casper_wasm_utils/
rules.rs

1use crate::std::collections::BTreeMap as Map;
2
3use crate::std::{num::NonZeroU32, str::FromStr};
4use casper_wasm::elements::Instruction;
5
6pub struct UnknownInstruction;
7
8/// An interface that describes instruction costs.
9pub trait Rules {
10    /// Returns the cost for the passed `instruction`.
11    ///
12    /// Returning `None` makes the gas instrumention end with an error. This is meant
13    /// as a way to have a partial rule set where any instruction that is not specifed
14    /// is considered as forbidden.
15    fn instruction_cost(&self, instruction: &Instruction) -> Option<u32>;
16
17    /// Returns the costs for growing the memory using the `memory.grow` instruction.
18    ///
19    /// Please note that these costs are in addition to the costs specified by `instruction_cost`
20    /// for the `memory.grow` instruction. Specifying `None` leads to no additional charge.
21    /// Those are meant as dynamic costs which take the amount of pages that the memory is
22    /// grown by into consideration. This is not possible using `instruction_cost` because
23    /// those costs depend on the stack and must be injected as code into the function calling
24    /// `memory.grow`. Therefore returning `Some` comes with a performance cost.
25    fn memory_grow_cost(&self) -> Option<MemoryGrowCost>;
26}
27
28/// Dynamic costs for memory growth.
29#[derive(Debug, PartialEq, Eq, Copy, Clone)]
30pub enum MemoryGrowCost {
31    /// Charge the specified amount for each page that the memory is grown by.
32    Linear(NonZeroU32),
33}
34
35#[derive(Debug, PartialEq, Eq, Copy, Clone)]
36pub enum Metering {
37    Regular,
38    Forbidden,
39    Fixed(u32),
40}
41
42#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
43pub enum InstructionType {
44    Bit,
45    Add,
46    Mul,
47    Div,
48    Load,
49    Store,
50    Const,
51    FloatConst,
52    Local,
53    Global,
54    ControlFlow,
55    IntegerComparison,
56    FloatComparison,
57    Float,
58    Conversion,
59    FloatConversion,
60    Reinterpretation,
61    Unreachable,
62    Nop,
63    CurrentMemory,
64    GrowMemory,
65
66    #[cfg(feature = "sign_ext")]
67    SignExt,
68}
69
70impl FromStr for InstructionType {
71    type Err = UnknownInstruction;
72
73    fn from_str(s: &str) -> Result<Self, Self::Err> {
74        match s {
75            "bit" => Ok(InstructionType::Bit),
76            "add" => Ok(InstructionType::Add),
77            "mul" => Ok(InstructionType::Mul),
78            "div" => Ok(InstructionType::Div),
79            "load" => Ok(InstructionType::Load),
80            "store" => Ok(InstructionType::Store),
81            "const" => Ok(InstructionType::Const),
82            "local" => Ok(InstructionType::Local),
83            "global" => Ok(InstructionType::Global),
84            "flow" => Ok(InstructionType::ControlFlow),
85            "integer_comp" => Ok(InstructionType::IntegerComparison),
86            "float_comp" => Ok(InstructionType::FloatComparison),
87            "float" => Ok(InstructionType::Float),
88            "conversion" => Ok(InstructionType::Conversion),
89            "float_conversion" => Ok(InstructionType::FloatConversion),
90            "reinterpret" => Ok(InstructionType::Reinterpretation),
91            "unreachable" => Ok(InstructionType::Unreachable),
92            "nop" => Ok(InstructionType::Nop),
93            "current_mem" => Ok(InstructionType::CurrentMemory),
94            "grow_mem" => Ok(InstructionType::GrowMemory),
95
96            #[cfg(feature = "sign_ext")]
97            "sign_ext" => Ok(InstructionType::SignExt),
98
99            _ => Err(UnknownInstruction),
100        }
101    }
102}
103
104impl InstructionType {
105    pub fn op(instruction: &Instruction) -> Self {
106        use Instruction::*;
107
108        match *instruction {
109            Unreachable => InstructionType::Unreachable,
110            Nop => InstructionType::Nop,
111            Block(_) => InstructionType::ControlFlow,
112            Loop(_) => InstructionType::ControlFlow,
113            If(_) => InstructionType::ControlFlow,
114            Else => InstructionType::ControlFlow,
115            End => InstructionType::ControlFlow,
116            Br(_) => InstructionType::ControlFlow,
117            BrIf(_) => InstructionType::ControlFlow,
118            BrTable(_) => InstructionType::ControlFlow,
119            Return => InstructionType::ControlFlow,
120            Call(_) => InstructionType::ControlFlow,
121            CallIndirect(_, _) => InstructionType::ControlFlow,
122            Drop => InstructionType::ControlFlow,
123            Select => InstructionType::ControlFlow,
124
125            GetLocal(_) => InstructionType::Local,
126            SetLocal(_) => InstructionType::Local,
127            TeeLocal(_) => InstructionType::Local,
128            GetGlobal(_) => InstructionType::Global,
129            SetGlobal(_) => InstructionType::Global,
130
131            I32Load(_, _) => InstructionType::Load,
132            I64Load(_, _) => InstructionType::Load,
133            F32Load(_, _) => InstructionType::Load,
134            F64Load(_, _) => InstructionType::Load,
135            I32Load8S(_, _) => InstructionType::Load,
136            I32Load8U(_, _) => InstructionType::Load,
137            I32Load16S(_, _) => InstructionType::Load,
138            I32Load16U(_, _) => InstructionType::Load,
139            I64Load8S(_, _) => InstructionType::Load,
140            I64Load8U(_, _) => InstructionType::Load,
141            I64Load16S(_, _) => InstructionType::Load,
142            I64Load16U(_, _) => InstructionType::Load,
143            I64Load32S(_, _) => InstructionType::Load,
144            I64Load32U(_, _) => InstructionType::Load,
145
146            I32Store(_, _) => InstructionType::Store,
147            I64Store(_, _) => InstructionType::Store,
148            F32Store(_, _) => InstructionType::Store,
149            F64Store(_, _) => InstructionType::Store,
150            I32Store8(_, _) => InstructionType::Store,
151            I32Store16(_, _) => InstructionType::Store,
152            I64Store8(_, _) => InstructionType::Store,
153            I64Store16(_, _) => InstructionType::Store,
154            I64Store32(_, _) => InstructionType::Store,
155
156            CurrentMemory(_) => InstructionType::CurrentMemory,
157            GrowMemory(_) => InstructionType::GrowMemory,
158
159            I32Const(_) => InstructionType::Const,
160            I64Const(_) => InstructionType::Const,
161
162            F32Const(_) => InstructionType::FloatConst,
163            F64Const(_) => InstructionType::FloatConst,
164
165            I32Eqz => InstructionType::IntegerComparison,
166            I32Eq => InstructionType::IntegerComparison,
167            I32Ne => InstructionType::IntegerComparison,
168            I32LtS => InstructionType::IntegerComparison,
169            I32LtU => InstructionType::IntegerComparison,
170            I32GtS => InstructionType::IntegerComparison,
171            I32GtU => InstructionType::IntegerComparison,
172            I32LeS => InstructionType::IntegerComparison,
173            I32LeU => InstructionType::IntegerComparison,
174            I32GeS => InstructionType::IntegerComparison,
175            I32GeU => InstructionType::IntegerComparison,
176
177            I64Eqz => InstructionType::IntegerComparison,
178            I64Eq => InstructionType::IntegerComparison,
179            I64Ne => InstructionType::IntegerComparison,
180            I64LtS => InstructionType::IntegerComparison,
181            I64LtU => InstructionType::IntegerComparison,
182            I64GtS => InstructionType::IntegerComparison,
183            I64GtU => InstructionType::IntegerComparison,
184            I64LeS => InstructionType::IntegerComparison,
185            I64LeU => InstructionType::IntegerComparison,
186            I64GeS => InstructionType::IntegerComparison,
187            I64GeU => InstructionType::IntegerComparison,
188
189            F32Eq => InstructionType::FloatComparison,
190            F32Ne => InstructionType::FloatComparison,
191            F32Lt => InstructionType::FloatComparison,
192            F32Gt => InstructionType::FloatComparison,
193            F32Le => InstructionType::FloatComparison,
194            F32Ge => InstructionType::FloatComparison,
195
196            F64Eq => InstructionType::FloatComparison,
197            F64Ne => InstructionType::FloatComparison,
198            F64Lt => InstructionType::FloatComparison,
199            F64Gt => InstructionType::FloatComparison,
200            F64Le => InstructionType::FloatComparison,
201            F64Ge => InstructionType::FloatComparison,
202
203            I32Clz => InstructionType::Bit,
204            I32Ctz => InstructionType::Bit,
205            I32Popcnt => InstructionType::Bit,
206            I32Add => InstructionType::Add,
207            I32Sub => InstructionType::Add,
208            I32Mul => InstructionType::Mul,
209            I32DivS => InstructionType::Div,
210            I32DivU => InstructionType::Div,
211            I32RemS => InstructionType::Div,
212            I32RemU => InstructionType::Div,
213            I32And => InstructionType::Bit,
214            I32Or => InstructionType::Bit,
215            I32Xor => InstructionType::Bit,
216            I32Shl => InstructionType::Bit,
217            I32ShrS => InstructionType::Bit,
218            I32ShrU => InstructionType::Bit,
219            I32Rotl => InstructionType::Bit,
220            I32Rotr => InstructionType::Bit,
221
222            I64Clz => InstructionType::Bit,
223            I64Ctz => InstructionType::Bit,
224            I64Popcnt => InstructionType::Bit,
225            I64Add => InstructionType::Add,
226            I64Sub => InstructionType::Add,
227            I64Mul => InstructionType::Mul,
228            I64DivS => InstructionType::Div,
229            I64DivU => InstructionType::Div,
230            I64RemS => InstructionType::Div,
231            I64RemU => InstructionType::Div,
232            I64And => InstructionType::Bit,
233            I64Or => InstructionType::Bit,
234            I64Xor => InstructionType::Bit,
235            I64Shl => InstructionType::Bit,
236            I64ShrS => InstructionType::Bit,
237            I64ShrU => InstructionType::Bit,
238            I64Rotl => InstructionType::Bit,
239            I64Rotr => InstructionType::Bit,
240
241            F32Abs => InstructionType::Float,
242            F32Neg => InstructionType::Float,
243            F32Ceil => InstructionType::Float,
244            F32Floor => InstructionType::Float,
245            F32Trunc => InstructionType::Float,
246            F32Nearest => InstructionType::Float,
247            F32Sqrt => InstructionType::Float,
248            F32Add => InstructionType::Float,
249            F32Sub => InstructionType::Float,
250            F32Mul => InstructionType::Float,
251            F32Div => InstructionType::Float,
252            F32Min => InstructionType::Float,
253            F32Max => InstructionType::Float,
254            F32Copysign => InstructionType::Float,
255            F64Abs => InstructionType::Float,
256            F64Neg => InstructionType::Float,
257            F64Ceil => InstructionType::Float,
258            F64Floor => InstructionType::Float,
259            F64Trunc => InstructionType::Float,
260            F64Nearest => InstructionType::Float,
261            F64Sqrt => InstructionType::Float,
262            F64Add => InstructionType::Float,
263            F64Sub => InstructionType::Float,
264            F64Mul => InstructionType::Float,
265            F64Div => InstructionType::Float,
266            F64Min => InstructionType::Float,
267            F64Max => InstructionType::Float,
268            F64Copysign => InstructionType::Float,
269
270            I32WrapI64 => InstructionType::Conversion,
271            I64ExtendSI32 => InstructionType::Conversion,
272            I64ExtendUI32 => InstructionType::Conversion,
273
274            I32TruncSF32 => InstructionType::FloatConversion,
275            I32TruncUF32 => InstructionType::FloatConversion,
276            I32TruncSF64 => InstructionType::FloatConversion,
277            I32TruncUF64 => InstructionType::FloatConversion,
278            I64TruncSF32 => InstructionType::FloatConversion,
279            I64TruncUF32 => InstructionType::FloatConversion,
280            I64TruncSF64 => InstructionType::FloatConversion,
281            I64TruncUF64 => InstructionType::FloatConversion,
282            F32ConvertSI32 => InstructionType::FloatConversion,
283            F32ConvertUI32 => InstructionType::FloatConversion,
284            F32ConvertSI64 => InstructionType::FloatConversion,
285            F32ConvertUI64 => InstructionType::FloatConversion,
286            F32DemoteF64 => InstructionType::FloatConversion,
287            F64ConvertSI32 => InstructionType::FloatConversion,
288            F64ConvertUI32 => InstructionType::FloatConversion,
289            F64ConvertSI64 => InstructionType::FloatConversion,
290            F64ConvertUI64 => InstructionType::FloatConversion,
291            F64PromoteF32 => InstructionType::FloatConversion,
292
293            I32ReinterpretF32 => InstructionType::Reinterpretation,
294            I64ReinterpretF64 => InstructionType::Reinterpretation,
295            F32ReinterpretI32 => InstructionType::Reinterpretation,
296            F64ReinterpretI64 => InstructionType::Reinterpretation,
297
298            #[cfg(feature = "sign_ext")]
299            SignExt(_) => InstructionType::SignExt,
300        }
301    }
302}
303
304#[derive(Debug)]
305pub struct Set {
306    regular: u32,
307    entries: Map<InstructionType, Metering>,
308    grow: u32,
309}
310
311impl Default for Set {
312    fn default() -> Self {
313        Set {
314            regular: 1,
315            entries: Map::new(),
316            grow: 0,
317        }
318    }
319}
320
321impl Set {
322    pub fn new(regular: u32, entries: Map<InstructionType, Metering>) -> Self {
323        Set {
324            regular,
325            entries,
326            grow: 0,
327        }
328    }
329
330    pub fn grow_cost(&self) -> u32 {
331        self.grow
332    }
333
334    pub fn with_grow_cost(mut self, val: u32) -> Self {
335        self.grow = val;
336        self
337    }
338
339    pub fn with_forbidden_floats(mut self) -> Self {
340        self.entries
341            .insert(InstructionType::Float, Metering::Forbidden);
342        self.entries
343            .insert(InstructionType::FloatComparison, Metering::Forbidden);
344        self.entries
345            .insert(InstructionType::FloatConst, Metering::Forbidden);
346        self.entries
347            .insert(InstructionType::FloatConversion, Metering::Forbidden);
348        self
349    }
350}
351
352impl Rules for Set {
353    fn instruction_cost(&self, instruction: &Instruction) -> Option<u32> {
354        match self.entries.get(&InstructionType::op(instruction)) {
355            None | Some(Metering::Regular) => Some(self.regular),
356            Some(Metering::Fixed(val)) => Some(*val),
357            Some(Metering::Forbidden) => None,
358        }
359    }
360
361    fn memory_grow_cost(&self) -> Option<MemoryGrowCost> {
362        NonZeroU32::new(self.grow).map(MemoryGrowCost::Linear)
363    }
364}