cfx_vm_interpreter/
instructions.rs

1// Copyright 2015-2018 Parity Technologies (UK) Ltd.
2// This file is part of Parity.
3
4// Parity is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
16
17// Copyright 2019 Conflux Foundation. All rights reserved.
18// Conflux is free software and distributed under GNU General Public License.
19// See http://www.gnu.org/licenses/
20
21//! VM Instructions list and utility functions
22
23pub use self::Instruction::*;
24
25use cfx_vm_types::Spec;
26
27macro_rules! enum_with_from_u8 {
28	(
29		$( #[$enum_attr:meta] )*
30		pub enum $name:ident {
31			$( $( #[$variant_attr:meta] )* $variant:ident = $discriminator:expr ),+,
32		}
33	) => {
34		$( #[$enum_attr] )*
35		pub enum $name {
36			$( $( #[$variant_attr] )* $variant = $discriminator ),+,
37		}
38
39		impl $name {
40			#[doc = "Convert from u8 to the given enum"]
41			pub fn from_u8(value: u8) -> Option<Self> {
42				match value {
43					$( $discriminator => Some($variant) ),+,
44					_ => None,
45				}
46			}
47		}
48	};
49}
50
51enum_with_from_u8! {
52    #[doc = "Virtual machine bytecode instruction."]
53    #[repr(u8)]
54    #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug, Hash)]
55    pub enum Instruction {
56        #[doc = "halts execution"]
57        STOP = 0x00,
58        #[doc = "addition operation"]
59        ADD = 0x01,
60        #[doc = "multiplication operation"]
61        MUL = 0x02,
62        #[doc = "subtraction operation"]
63        SUB = 0x03,
64        #[doc = "integer division operation"]
65        DIV = 0x04,
66        #[doc = "signed integer division operation"]
67        SDIV = 0x05,
68        #[doc = "modulo remainder operation"]
69        MOD = 0x06,
70        #[doc = "signed modulo remainder operation"]
71        SMOD = 0x07,
72        #[doc = "unsigned modular addition"]
73        ADDMOD = 0x08,
74        #[doc = "unsigned modular multiplication"]
75        MULMOD = 0x09,
76        #[doc = "exponential operation"]
77        EXP = 0x0a,
78        #[doc = "extend length of signed integer"]
79        SIGNEXTEND = 0x0b,
80
81        #[doc = "less-than comparison"]
82        LT = 0x10,
83        #[doc = "greater-than comparison"]
84        GT = 0x11,
85        #[doc = "signed less-than comparison"]
86        SLT = 0x12,
87        #[doc = "signed greater-than comparison"]
88        SGT = 0x13,
89        #[doc = "equality comparison"]
90        EQ = 0x14,
91        #[doc = "simple not operator"]
92        ISZERO = 0x15,
93        #[doc = "bitwise AND operation"]
94        AND = 0x16,
95        #[doc = "bitwise OR operation"]
96        OR = 0x17,
97        #[doc = "bitwise XOR operation"]
98        XOR = 0x18,
99        #[doc = "bitwise NOT operation"]
100        NOT = 0x19,
101        #[doc = "retrieve single byte from word"]
102        BYTE = 0x1a,
103        #[doc = "shift left operation"]
104        SHL = 0x1b,
105        #[doc = "logical shift right operation"]
106        SHR = 0x1c,
107        #[doc = "arithmetic shift right operation"]
108        SAR = 0x1d,
109        #[doc = "count leading zeros"]
110        CLZ = 0x1e,
111
112        #[doc = "compute SHA3-256 hash"]
113        SHA3 = 0x20,
114
115        #[doc = "get address of currently executing account"]
116        ADDRESS = 0x30,
117        #[doc = "get balance of the given account"]
118        BALANCE = 0x31,
119        #[doc = "get execution origination address"]
120        ORIGIN = 0x32,
121        #[doc = "get caller address"]
122        CALLER = 0x33,
123        #[doc = "get deposited value by the instruction/transaction responsible for this execution"]
124        CALLVALUE = 0x34,
125        #[doc = "get input data of current environment"]
126        CALLDATALOAD = 0x35,
127        #[doc = "get size of input data in current environment"]
128        CALLDATASIZE = 0x36,
129        #[doc = "copy input data in current environment to memory"]
130        CALLDATACOPY = 0x37,
131        #[doc = "get size of code running in current environment"]
132        CODESIZE = 0x38,
133        #[doc = "copy code running in current environment to memory"]
134        CODECOPY = 0x39,
135        #[doc = "get price of gas in current environment"]
136        GASPRICE = 0x3a,
137        #[doc = "get external code size (from another contract)"]
138        EXTCODESIZE = 0x3b,
139        #[doc = "copy external code (from another contract)"]
140        EXTCODECOPY = 0x3c,
141        #[doc = "get the size of the return data buffer for the last call"]
142        RETURNDATASIZE = 0x3d,
143        #[doc = "copy return data buffer to memory"]
144        RETURNDATACOPY = 0x3e,
145        #[doc = "return the keccak256 hash of contract code"]
146        EXTCODEHASH = 0x3f,
147
148        #[doc = "get hash of most recent complete block"]
149        BLOCKHASH = 0x40,
150        #[doc = "get the block's coinbase address"]
151        COINBASE = 0x41,
152        #[doc = "get the block's timestamp"]
153        TIMESTAMP = 0x42,
154        #[doc = "get the block's number"]
155        NUMBER = 0x43,
156        #[doc = "get the block's difficulty"]
157        DIFFICULTY = 0x44,
158        #[doc = "get the block's gas limit"]
159        GASLIMIT = 0x45,
160        #[doc = "get chain ID"]
161        CHAINID = 0x46,
162        #[doc = "get balance of own account"]
163        SELFBALANCE = 0x47,
164        #[doc = "base fee for EIP-1559 (EIP-3198)"]
165        BASEFEE = 0x48,
166        #[doc = "blob hash for EIP-4844 (dummy)"]
167        BLOBHASH=0x49,
168        #[doc = "blob base fee for EIP-4844 (dummy)"]
169        BLOBBASEFEE=0x4a,
170
171        #[doc = "remove item from stack"]
172        POP = 0x50,
173        #[doc = "load word from memory"]
174        MLOAD = 0x51,
175        #[doc = "save word to memory"]
176        MSTORE = 0x52,
177        #[doc = "save byte to memory"]
178        MSTORE8 = 0x53,
179        #[doc = "load word from storage"]
180        SLOAD = 0x54,
181        #[doc = "save word to storage"]
182        SSTORE = 0x55,
183        #[doc = "alter the program counter"]
184        JUMP = 0x56,
185        #[doc = "conditionally alter the program counter"]
186        JUMPI = 0x57,
187        #[doc = "get the program counter"]
188        PC = 0x58,
189        #[doc = "get the size of active memory"]
190        MSIZE = 0x59,
191        #[doc = "get the amount of available gas"]
192        GAS = 0x5a,
193        #[doc = "set a potential jump destination"]
194        JUMPDEST = 0x5b,
195        #[doc = "Marks the entry point to a subroutine (pre cip-142). load word from transient storage (after cip-142)"]
196        #[allow(non_camel_case_types)]
197        BEGINSUB_TLOAD = 0x5c,
198        #[doc = "Returns from a subroutine (pre cip-142). store word from transient storage (after cip-142)"]
199        #[allow(non_camel_case_types)]
200        RETURNSUB_TSTORE = 0x5d,
201        #[doc = "Jumps to a defined BEGINSUB subroutine (pre cip-143). copy data from one memory range to another (after cip-143)"]
202        #[allow(non_camel_case_types)]
203        JUMPSUB_MCOPY = 0x5e,
204
205        #[doc = "place zero item on stack (EIP-3855/CIP-119)"]
206        PUSH0 = 0x5f,
207        #[doc = "place 1 byte item on stack"]
208        PUSH1 = 0x60,
209        #[doc = "place 2 byte item on stack"]
210        PUSH2 = 0x61,
211        #[doc = "place 3 byte item on stack"]
212        PUSH3 = 0x62,
213        #[doc = "place 4 byte item on stack"]
214        PUSH4 = 0x63,
215        #[doc = "place 5 byte item on stack"]
216        PUSH5 = 0x64,
217        #[doc = "place 6 byte item on stack"]
218        PUSH6 = 0x65,
219        #[doc = "place 7 byte item on stack"]
220        PUSH7 = 0x66,
221        #[doc = "place 8 byte item on stack"]
222        PUSH8 = 0x67,
223        #[doc = "place 9 byte item on stack"]
224        PUSH9 = 0x68,
225        #[doc = "place 10 byte item on stack"]
226        PUSH10 = 0x69,
227        #[doc = "place 11 byte item on stack"]
228        PUSH11 = 0x6a,
229        #[doc = "place 12 byte item on stack"]
230        PUSH12 = 0x6b,
231        #[doc = "place 13 byte item on stack"]
232        PUSH13 = 0x6c,
233        #[doc = "place 14 byte item on stack"]
234        PUSH14 = 0x6d,
235        #[doc = "place 15 byte item on stack"]
236        PUSH15 = 0x6e,
237        #[doc = "place 16 byte item on stack"]
238        PUSH16 = 0x6f,
239        #[doc = "place 17 byte item on stack"]
240        PUSH17 = 0x70,
241        #[doc = "place 18 byte item on stack"]
242        PUSH18 = 0x71,
243        #[doc = "place 19 byte item on stack"]
244        PUSH19 = 0x72,
245        #[doc = "place 20 byte item on stack"]
246        PUSH20 = 0x73,
247        #[doc = "place 21 byte item on stack"]
248        PUSH21 = 0x74,
249        #[doc = "place 22 byte item on stack"]
250        PUSH22 = 0x75,
251        #[doc = "place 23 byte item on stack"]
252        PUSH23 = 0x76,
253        #[doc = "place 24 byte item on stack"]
254        PUSH24 = 0x77,
255        #[doc = "place 25 byte item on stack"]
256        PUSH25 = 0x78,
257        #[doc = "place 26 byte item on stack"]
258        PUSH26 = 0x79,
259        #[doc = "place 27 byte item on stack"]
260        PUSH27 = 0x7a,
261        #[doc = "place 28 byte item on stack"]
262        PUSH28 = 0x7b,
263        #[doc = "place 29 byte item on stack"]
264        PUSH29 = 0x7c,
265        #[doc = "place 30 byte item on stack"]
266        PUSH30 = 0x7d,
267        #[doc = "place 31 byte item on stack"]
268        PUSH31 = 0x7e,
269        #[doc = "place 32 byte item on stack"]
270        PUSH32 = 0x7f,
271
272        #[doc = "copies the highest item in the stack to the top of the stack"]
273        DUP1 = 0x80,
274        #[doc = "copies the second highest item in the stack to the top of the stack"]
275        DUP2 = 0x81,
276        #[doc = "copies the third highest item in the stack to the top of the stack"]
277        DUP3 = 0x82,
278        #[doc = "copies the 4th highest item in the stack to the top of the stack"]
279        DUP4 = 0x83,
280        #[doc = "copies the 5th highest item in the stack to the top of the stack"]
281        DUP5 = 0x84,
282        #[doc = "copies the 6th highest item in the stack to the top of the stack"]
283        DUP6 = 0x85,
284        #[doc = "copies the 7th highest item in the stack to the top of the stack"]
285        DUP7 = 0x86,
286        #[doc = "copies the 8th highest item in the stack to the top of the stack"]
287        DUP8 = 0x87,
288        #[doc = "copies the 9th highest item in the stack to the top of the stack"]
289        DUP9 = 0x88,
290        #[doc = "copies the 10th highest item in the stack to the top of the stack"]
291        DUP10 = 0x89,
292        #[doc = "copies the 11th highest item in the stack to the top of the stack"]
293        DUP11 = 0x8a,
294        #[doc = "copies the 12th highest item in the stack to the top of the stack"]
295        DUP12 = 0x8b,
296        #[doc = "copies the 13th highest item in the stack to the top of the stack"]
297        DUP13 = 0x8c,
298        #[doc = "copies the 14th highest item in the stack to the top of the stack"]
299        DUP14 = 0x8d,
300        #[doc = "copies the 15th highest item in the stack to the top of the stack"]
301        DUP15 = 0x8e,
302        #[doc = "copies the 16th highest item in the stack to the top of the stack"]
303        DUP16 = 0x8f,
304
305        #[doc = "swaps the highest and second highest value on the stack"]
306        SWAP1 = 0x90,
307        #[doc = "swaps the highest and third highest value on the stack"]
308        SWAP2 = 0x91,
309        #[doc = "swaps the highest and 4th highest value on the stack"]
310        SWAP3 = 0x92,
311        #[doc = "swaps the highest and 5th highest value on the stack"]
312        SWAP4 = 0x93,
313        #[doc = "swaps the highest and 6th highest value on the stack"]
314        SWAP5 = 0x94,
315        #[doc = "swaps the highest and 7th highest value on the stack"]
316        SWAP6 = 0x95,
317        #[doc = "swaps the highest and 8th highest value on the stack"]
318        SWAP7 = 0x96,
319        #[doc = "swaps the highest and 9th highest value on the stack"]
320        SWAP8 = 0x97,
321        #[doc = "swaps the highest and 10th highest value on the stack"]
322        SWAP9 = 0x98,
323        #[doc = "swaps the highest and 11th highest value on the stack"]
324        SWAP10 = 0x99,
325        #[doc = "swaps the highest and 12th highest value on the stack"]
326        SWAP11 = 0x9a,
327        #[doc = "swaps the highest and 13th highest value on the stack"]
328        SWAP12 = 0x9b,
329        #[doc = "swaps the highest and 14th highest value on the stack"]
330        SWAP13 = 0x9c,
331        #[doc = "swaps the highest and 15th highest value on the stack"]
332        SWAP14 = 0x9d,
333        #[doc = "swaps the highest and 16th highest value on the stack"]
334        SWAP15 = 0x9e,
335        #[doc = "swaps the highest and 17th highest value on the stack"]
336        SWAP16 = 0x9f,
337
338        #[doc = "Makes a log entry, no topics."]
339        LOG0 = 0xa0,
340        #[doc = "Makes a log entry, 1 topic."]
341        LOG1 = 0xa1,
342        #[doc = "Makes a log entry, 2 topics."]
343        LOG2 = 0xa2,
344        #[doc = "Makes a log entry, 3 topics."]
345        LOG3 = 0xa3,
346        #[doc = "Makes a log entry, 4 topics."]
347        LOG4 = 0xa4,
348
349        #[doc = "create a new account with associated code"]
350        CREATE = 0xf0,
351        #[doc = "message-call into an account"]
352        CALL = 0xf1,
353        #[doc = "message-call with another account's code only"]
354        CALLCODE = 0xf2,
355        #[doc = "halt execution returning output data"]
356        RETURN = 0xf3,
357        #[doc = "like CALLCODE but keeps caller's value and sender"]
358        DELEGATECALL = 0xf4,
359        #[doc = "create a new account and set creation address to sha3(sender + sha3(init code)) % 2**160"]
360        CREATE2 = 0xf5,
361        #[doc = "like CALL but it does not take value, nor modify the state"]
362        STATICCALL = 0xfa,
363        #[doc = "stop execution and revert state changes. Return output data."]
364        REVERT = 0xfd,
365
366        // INVALID = 0xfe
367
368        #[doc = "halt execution and register account for later deletion"]
369        SUICIDE = 0xff,
370    }
371}
372
373impl Instruction {
374    /// Returns true if given instruction is `PUSHN` instruction.
375    pub fn is_push(&self) -> bool { *self >= PUSH1 && *self <= PUSH32 }
376
377    pub fn from_u8_versioned(value: u8, spec: &Spec) -> Option<Self> {
378        let mut instruction = Instruction::from_u8(value);
379        if instruction == Some(PUSH0) && !spec.cip119 {
380            instruction = None;
381        }
382        if instruction == Some(BASEFEE) && !spec.cip1559 {
383            instruction = None;
384        }
385        if instruction == Some(CLZ) && !spec.eip7939 {
386            instruction = None;
387        }
388        return instruction;
389    }
390
391    pub fn u8(self) -> u8 { self as u8 }
392
393    /// Returns number of bytes to read for `PUSHN` instruction
394    /// PUSH1 -> 1
395    pub fn push_bytes(&self) -> Option<usize> {
396        if self.is_push() {
397            Some(((*self as u8) - (PUSH1 as u8) + 1) as usize)
398        } else {
399            None
400        }
401    }
402
403    /// Returns stack position of item to duplicate
404    /// DUP1 -> 0
405    pub fn dup_position(&self) -> Option<usize> {
406        if *self >= DUP1 && *self <= DUP16 {
407            Some(((*self as u8) - (DUP1 as u8)) as usize)
408        } else {
409            None
410        }
411    }
412
413    /// Returns stack position of item to SWAP top with
414    /// SWAP1 -> 1
415    pub fn swap_position(&self) -> Option<usize> {
416        if *self >= SWAP1 && *self <= SWAP16 {
417            Some(((*self as u8) - (SWAP1 as u8) + 1) as usize)
418        } else {
419            None
420        }
421    }
422
423    /// Returns number of topics to take from stack
424    /// LOG0 -> 0
425    pub fn log_topics(&self) -> Option<usize> {
426        if *self >= LOG0 && *self <= LOG4 {
427            Some(((*self as u8) - (LOG0 as u8)) as usize)
428        } else {
429            None
430        }
431    }
432
433    /// Returns the instruction info.
434    pub fn info<const CANCUN: bool>(
435        &self, cip645: bool, eip7939: bool,
436    ) -> &InstructionInfo {
437        let instrs = if !CANCUN {
438            &*INSTRUCTIONS
439        } else if !cip645 {
440            &*INSTRUCTIONS_CANCUN
441        } else if !eip7939 {
442            &*INSTRUCTIONS_CIP645
443        } else {
444            &*INSTRUCTIONS_EIP7939
445        };
446
447        instrs[*self as usize].as_ref().expect("A instruction is defined in Instruction enum, but it is not found in InstructionInfo struct; this indicates a logic failure in the code.")
448    }
449}
450
451#[derive(PartialEq, Clone, Copy)]
452pub enum GasPriceTier {
453    /// 0 Zero
454    Zero,
455    /// 2 Quick
456    Base,
457    /// 3 Fastest
458    VeryLow,
459    /// 5 Fast
460    Low,
461    /// 8 Mid
462    Mid,
463    /// 10 Slow
464    High,
465    /// 20 Ext
466    Ext,
467    /// Multiparam or otherwise special
468    Special,
469}
470
471impl GasPriceTier {
472    /// Returns the index in schedule for specific `GasPriceTier`
473    pub const fn idx(&self) -> usize {
474        match self {
475            &GasPriceTier::Zero => 0,
476            &GasPriceTier::Base => 1,
477            &GasPriceTier::VeryLow => 2,
478            &GasPriceTier::Low => 3,
479            &GasPriceTier::Mid => 4,
480            &GasPriceTier::High => 5,
481            &GasPriceTier::Ext => 6,
482            &GasPriceTier::Special => 7,
483        }
484    }
485}
486
487/// EVM instruction information.
488#[derive(Copy, Clone)]
489pub struct InstructionInfo {
490    /// Mnemonic name.
491    pub name: &'static str,
492    /// Number of stack arguments.
493    pub args: usize,
494    /// Number of returned stack items.
495    pub ret: usize,
496    /// Gas price tier.
497    pub tier: GasPriceTier,
498}
499
500impl InstructionInfo {
501    /// Create new instruction info.
502    pub fn new(
503        name: &'static str, args: usize, ret: usize, tier: GasPriceTier,
504    ) -> Self {
505        InstructionInfo {
506            name,
507            args,
508            ret,
509            tier,
510        }
511    }
512}
513
514lazy_static! {
515    /// Static instruction table.
516    pub static ref INSTRUCTIONS: [Option<InstructionInfo>; 0x100] = {
517        let mut arr = [None; 0x100];
518        arr[STOP as usize] = Some(InstructionInfo::new("STOP", 0, 0, GasPriceTier::Zero));
519        arr[ADD as usize] = Some(InstructionInfo::new("ADD", 2, 1, GasPriceTier::VeryLow));
520        arr[SUB as usize] = Some(InstructionInfo::new("SUB", 2, 1, GasPriceTier::VeryLow));
521        arr[MUL as usize] = Some(InstructionInfo::new("MUL", 2, 1, GasPriceTier::Low));
522        arr[DIV as usize] = Some(InstructionInfo::new("DIV", 2, 1, GasPriceTier::Low));
523        arr[SDIV as usize] = Some(InstructionInfo::new("SDIV", 2, 1, GasPriceTier::Low));
524        arr[MOD as usize] = Some(InstructionInfo::new("MOD", 2, 1, GasPriceTier::Low));
525        arr[SMOD as usize] = Some(InstructionInfo::new("SMOD", 2, 1, GasPriceTier::Low));
526        arr[EXP as usize] = Some(InstructionInfo::new("EXP", 2, 1, GasPriceTier::Special));
527        arr[NOT as usize] = Some(InstructionInfo::new("NOT", 1, 1, GasPriceTier::VeryLow));
528        arr[LT as usize] = Some(InstructionInfo::new("LT", 2, 1, GasPriceTier::VeryLow));
529        arr[GT as usize] = Some(InstructionInfo::new("GT", 2, 1, GasPriceTier::VeryLow));
530        arr[SLT as usize] = Some(InstructionInfo::new("SLT", 2, 1, GasPriceTier::VeryLow));
531        arr[SGT as usize] = Some(InstructionInfo::new("SGT", 2, 1, GasPriceTier::VeryLow));
532        arr[EQ as usize] = Some(InstructionInfo::new("EQ", 2, 1, GasPriceTier::VeryLow));
533        arr[ISZERO as usize] = Some(InstructionInfo::new("ISZERO", 1, 1, GasPriceTier::VeryLow));
534        arr[AND as usize] = Some(InstructionInfo::new("AND", 2, 1, GasPriceTier::VeryLow));
535        arr[OR as usize] = Some(InstructionInfo::new("OR", 2, 1, GasPriceTier::VeryLow));
536        arr[XOR as usize] = Some(InstructionInfo::new("XOR", 2, 1, GasPriceTier::VeryLow));
537        arr[BYTE as usize] = Some(InstructionInfo::new("BYTE", 2, 1, GasPriceTier::VeryLow));
538        arr[SHL as usize] = Some(InstructionInfo::new("SHL", 2, 1, GasPriceTier::VeryLow));
539        arr[SHR as usize] = Some(InstructionInfo::new("SHR", 2, 1, GasPriceTier::VeryLow));
540        arr[SAR as usize] = Some(InstructionInfo::new("SAR", 2, 1, GasPriceTier::VeryLow));
541        arr[ADDMOD as usize] = Some(InstructionInfo::new("ADDMOD", 3, 1, GasPriceTier::Mid));
542        arr[MULMOD as usize] = Some(InstructionInfo::new("MULMOD", 3, 1, GasPriceTier::Mid));
543        arr[SIGNEXTEND as usize] = Some(InstructionInfo::new("SIGNEXTEND", 2, 1, GasPriceTier::Low));
544        arr[RETURNDATASIZE as usize] = Some(InstructionInfo::new("RETURNDATASIZE", 0, 1, GasPriceTier::Base));
545        arr[RETURNDATACOPY as usize] = Some(InstructionInfo::new("RETURNDATACOPY", 3, 0, GasPriceTier::VeryLow));
546        arr[SHA3 as usize] = Some(InstructionInfo::new("SHA3", 2, 1, GasPriceTier::Special));
547        arr[ADDRESS as usize] = Some(InstructionInfo::new("ADDRESS", 0, 1, GasPriceTier::Base));
548        arr[BALANCE as usize] = Some(InstructionInfo::new("BALANCE", 1, 1, GasPriceTier::Special));
549        arr[ORIGIN as usize] = Some(InstructionInfo::new("ORIGIN", 0, 1, GasPriceTier::Base));
550        arr[CALLER as usize] = Some(InstructionInfo::new("CALLER", 0, 1, GasPriceTier::Base));
551        arr[CALLVALUE as usize] = Some(InstructionInfo::new("CALLVALUE", 0, 1, GasPriceTier::Base));
552        arr[CALLDATALOAD as usize] = Some(InstructionInfo::new("CALLDATALOAD", 1, 1, GasPriceTier::VeryLow));
553        arr[CALLDATASIZE as usize] = Some(InstructionInfo::new("CALLDATASIZE", 0, 1, GasPriceTier::Base));
554        arr[CALLDATACOPY as usize] = Some(InstructionInfo::new("CALLDATACOPY", 3, 0, GasPriceTier::VeryLow));
555        arr[EXTCODEHASH as usize] = Some(InstructionInfo::new("EXTCODEHASH", 1, 1, GasPriceTier::Special));
556        arr[CODESIZE as usize] = Some(InstructionInfo::new("CODESIZE", 0, 1, GasPriceTier::Base));
557        arr[CODECOPY as usize] = Some(InstructionInfo::new("CODECOPY", 3, 0, GasPriceTier::VeryLow));
558        arr[GASPRICE as usize] = Some(InstructionInfo::new("GASPRICE", 0, 1, GasPriceTier::Base));
559        arr[EXTCODESIZE as usize] = Some(InstructionInfo::new("EXTCODESIZE", 1, 1, GasPriceTier::Special));
560        arr[EXTCODECOPY as usize] = Some(InstructionInfo::new("EXTCODECOPY", 4, 0, GasPriceTier::Special));
561        arr[BLOCKHASH as usize] = Some(InstructionInfo::new("BLOCKHASH", 1, 1, GasPriceTier::Ext));
562        arr[COINBASE as usize] = Some(InstructionInfo::new("COINBASE", 0, 1, GasPriceTier::Base));
563        arr[TIMESTAMP as usize] = Some(InstructionInfo::new("TIMESTAMP", 0, 1, GasPriceTier::Base));
564        arr[NUMBER as usize] = Some(InstructionInfo::new("NUMBER", 0, 1, GasPriceTier::Base));
565        arr[DIFFICULTY as usize] = Some(InstructionInfo::new("DIFFICULTY", 0, 1, GasPriceTier::Base));
566        arr[GASLIMIT as usize] = Some(InstructionInfo::new("GASLIMIT", 0, 1, GasPriceTier::Base));
567        arr[CHAINID as usize] = Some(InstructionInfo::new("CHAINID", 0, 1, GasPriceTier::Base));
568        arr[SELFBALANCE as usize] = Some(InstructionInfo::new("SELFBALANCE", 0, 1, GasPriceTier::Low));
569        arr[BASEFEE as usize] = Some(InstructionInfo::new("BASEFEE", 0, 1, GasPriceTier::VeryLow));
570        arr[POP as usize] = Some(InstructionInfo::new("POP", 1, 0, GasPriceTier::Base));
571        arr[MLOAD as usize] = Some(InstructionInfo::new("MLOAD", 1, 1, GasPriceTier::VeryLow));
572        arr[MSTORE as usize] = Some(InstructionInfo::new("MSTORE", 2, 0, GasPriceTier::VeryLow));
573        arr[MSTORE8 as usize] = Some(InstructionInfo::new("MSTORE8", 2, 0, GasPriceTier::VeryLow));
574        arr[SLOAD as usize] = Some(InstructionInfo::new("SLOAD", 1, 1, GasPriceTier::Special));
575        arr[SSTORE as usize] = Some(InstructionInfo::new("SSTORE", 2, 0, GasPriceTier::Special));
576        arr[JUMP as usize] = Some(InstructionInfo::new("JUMP", 1, 0, GasPriceTier::Mid));
577        arr[JUMPI as usize] = Some(InstructionInfo::new("JUMPI", 2, 0, GasPriceTier::High));
578        arr[PC as usize] = Some(InstructionInfo::new("PC", 0, 1, GasPriceTier::Base));
579        arr[MSIZE as usize] = Some(InstructionInfo::new("MSIZE", 0, 1, GasPriceTier::Base));
580        arr[GAS as usize] = Some(InstructionInfo::new("GAS", 0, 1, GasPriceTier::Base));
581        arr[JUMPDEST as usize] = Some(InstructionInfo::new("JUMPDEST", 0, 0, GasPriceTier::Special));
582        arr[PUSH0 as usize] = Some(InstructionInfo::new("PUSH0", 0, 1, GasPriceTier::Base));
583        arr[PUSH1 as usize] = Some(InstructionInfo::new("PUSH1", 0, 1, GasPriceTier::VeryLow));
584        arr[PUSH2 as usize] = Some(InstructionInfo::new("PUSH2", 0, 1, GasPriceTier::VeryLow));
585        arr[PUSH3 as usize] = Some(InstructionInfo::new("PUSH3", 0, 1, GasPriceTier::VeryLow));
586        arr[PUSH4 as usize] = Some(InstructionInfo::new("PUSH4", 0, 1, GasPriceTier::VeryLow));
587        arr[PUSH5 as usize] = Some(InstructionInfo::new("PUSH5", 0, 1, GasPriceTier::VeryLow));
588        arr[PUSH6 as usize] = Some(InstructionInfo::new("PUSH6", 0, 1, GasPriceTier::VeryLow));
589        arr[PUSH7 as usize] = Some(InstructionInfo::new("PUSH7", 0, 1, GasPriceTier::VeryLow));
590        arr[PUSH8 as usize] = Some(InstructionInfo::new("PUSH8", 0, 1, GasPriceTier::VeryLow));
591        arr[PUSH9 as usize] = Some(InstructionInfo::new("PUSH9", 0, 1, GasPriceTier::VeryLow));
592        arr[PUSH10 as usize] = Some(InstructionInfo::new("PUSH10", 0, 1, GasPriceTier::VeryLow));
593        arr[PUSH11 as usize] = Some(InstructionInfo::new("PUSH11", 0, 1, GasPriceTier::VeryLow));
594        arr[PUSH12 as usize] = Some(InstructionInfo::new("PUSH12", 0, 1, GasPriceTier::VeryLow));
595        arr[PUSH13 as usize] = Some(InstructionInfo::new("PUSH13", 0, 1, GasPriceTier::VeryLow));
596        arr[PUSH14 as usize] = Some(InstructionInfo::new("PUSH14", 0, 1, GasPriceTier::VeryLow));
597        arr[PUSH15 as usize] = Some(InstructionInfo::new("PUSH15", 0, 1, GasPriceTier::VeryLow));
598        arr[PUSH16 as usize] = Some(InstructionInfo::new("PUSH16", 0, 1, GasPriceTier::VeryLow));
599        arr[PUSH17 as usize] = Some(InstructionInfo::new("PUSH17", 0, 1, GasPriceTier::VeryLow));
600        arr[PUSH18 as usize] = Some(InstructionInfo::new("PUSH18", 0, 1, GasPriceTier::VeryLow));
601        arr[PUSH19 as usize] = Some(InstructionInfo::new("PUSH19", 0, 1, GasPriceTier::VeryLow));
602        arr[PUSH20 as usize] = Some(InstructionInfo::new("PUSH20", 0, 1, GasPriceTier::VeryLow));
603        arr[PUSH21 as usize] = Some(InstructionInfo::new("PUSH21", 0, 1, GasPriceTier::VeryLow));
604        arr[PUSH22 as usize] = Some(InstructionInfo::new("PUSH22", 0, 1, GasPriceTier::VeryLow));
605        arr[PUSH23 as usize] = Some(InstructionInfo::new("PUSH23", 0, 1, GasPriceTier::VeryLow));
606        arr[PUSH24 as usize] = Some(InstructionInfo::new("PUSH24", 0, 1, GasPriceTier::VeryLow));
607        arr[PUSH25 as usize] = Some(InstructionInfo::new("PUSH25", 0, 1, GasPriceTier::VeryLow));
608        arr[PUSH26 as usize] = Some(InstructionInfo::new("PUSH26", 0, 1, GasPriceTier::VeryLow));
609        arr[PUSH27 as usize] = Some(InstructionInfo::new("PUSH27", 0, 1, GasPriceTier::VeryLow));
610        arr[PUSH28 as usize] = Some(InstructionInfo::new("PUSH28", 0, 1, GasPriceTier::VeryLow));
611        arr[PUSH29 as usize] = Some(InstructionInfo::new("PUSH29", 0, 1, GasPriceTier::VeryLow));
612        arr[PUSH30 as usize] = Some(InstructionInfo::new("PUSH30", 0, 1, GasPriceTier::VeryLow));
613        arr[PUSH31 as usize] = Some(InstructionInfo::new("PUSH31", 0, 1, GasPriceTier::VeryLow));
614        arr[PUSH32 as usize] = Some(InstructionInfo::new("PUSH32", 0, 1, GasPriceTier::VeryLow));
615        arr[DUP1 as usize] = Some(InstructionInfo::new("DUP1", 1, 2, GasPriceTier::VeryLow));
616        arr[DUP2 as usize] = Some(InstructionInfo::new("DUP2", 2, 3, GasPriceTier::VeryLow));
617        arr[DUP3 as usize] = Some(InstructionInfo::new("DUP3", 3, 4, GasPriceTier::VeryLow));
618        arr[DUP4 as usize] = Some(InstructionInfo::new("DUP4", 4, 5, GasPriceTier::VeryLow));
619        arr[DUP5 as usize] = Some(InstructionInfo::new("DUP5", 5, 6, GasPriceTier::VeryLow));
620        arr[DUP6 as usize] = Some(InstructionInfo::new("DUP6", 6, 7, GasPriceTier::VeryLow));
621        arr[DUP7 as usize] = Some(InstructionInfo::new("DUP7", 7, 8, GasPriceTier::VeryLow));
622        arr[DUP8 as usize] = Some(InstructionInfo::new("DUP8", 8, 9, GasPriceTier::VeryLow));
623        arr[DUP9 as usize] = Some(InstructionInfo::new("DUP9", 9, 10, GasPriceTier::VeryLow));
624        arr[DUP10 as usize] = Some(InstructionInfo::new("DUP10", 10, 11, GasPriceTier::VeryLow));
625        arr[DUP11 as usize] = Some(InstructionInfo::new("DUP11", 11, 12, GasPriceTier::VeryLow));
626        arr[DUP12 as usize] = Some(InstructionInfo::new("DUP12", 12, 13, GasPriceTier::VeryLow));
627        arr[DUP13 as usize] = Some(InstructionInfo::new("DUP13", 13, 14, GasPriceTier::VeryLow));
628        arr[DUP14 as usize] = Some(InstructionInfo::new("DUP14", 14, 15, GasPriceTier::VeryLow));
629        arr[DUP15 as usize] = Some(InstructionInfo::new("DUP15", 15, 16, GasPriceTier::VeryLow));
630        arr[DUP16 as usize] = Some(InstructionInfo::new("DUP16", 16, 17, GasPriceTier::VeryLow));
631        arr[SWAP1 as usize] = Some(InstructionInfo::new("SWAP1", 2, 2, GasPriceTier::VeryLow));
632        arr[SWAP2 as usize] = Some(InstructionInfo::new("SWAP2", 3, 3, GasPriceTier::VeryLow));
633        arr[SWAP3 as usize] = Some(InstructionInfo::new("SWAP3", 4, 4, GasPriceTier::VeryLow));
634        arr[SWAP4 as usize] = Some(InstructionInfo::new("SWAP4", 5, 5, GasPriceTier::VeryLow));
635        arr[SWAP5 as usize] = Some(InstructionInfo::new("SWAP5", 6, 6, GasPriceTier::VeryLow));
636        arr[SWAP6 as usize] = Some(InstructionInfo::new("SWAP6", 7, 7, GasPriceTier::VeryLow));
637        arr[SWAP7 as usize] = Some(InstructionInfo::new("SWAP7", 8, 8, GasPriceTier::VeryLow));
638        arr[SWAP8 as usize] = Some(InstructionInfo::new("SWAP8", 9, 9, GasPriceTier::VeryLow));
639        arr[SWAP9 as usize] = Some(InstructionInfo::new("SWAP9", 10, 10, GasPriceTier::VeryLow));
640        arr[SWAP10 as usize] = Some(InstructionInfo::new("SWAP10", 11, 11, GasPriceTier::VeryLow));
641        arr[SWAP11 as usize] = Some(InstructionInfo::new("SWAP11", 12, 12, GasPriceTier::VeryLow));
642        arr[SWAP12 as usize] = Some(InstructionInfo::new("SWAP12", 13, 13, GasPriceTier::VeryLow));
643        arr[SWAP13 as usize] = Some(InstructionInfo::new("SWAP13", 14, 14, GasPriceTier::VeryLow));
644        arr[SWAP14 as usize] = Some(InstructionInfo::new("SWAP14", 15, 15, GasPriceTier::VeryLow));
645        arr[SWAP15 as usize] = Some(InstructionInfo::new("SWAP15", 16, 16, GasPriceTier::VeryLow));
646        arr[SWAP16 as usize] = Some(InstructionInfo::new("SWAP16", 17, 17, GasPriceTier::VeryLow));
647        arr[LOG0 as usize] = Some(InstructionInfo::new("LOG0", 2, 0, GasPriceTier::Special));
648        arr[LOG1 as usize] = Some(InstructionInfo::new("LOG1", 3, 0, GasPriceTier::Special));
649        arr[LOG2 as usize] = Some(InstructionInfo::new("LOG2", 4, 0, GasPriceTier::Special));
650        arr[LOG3 as usize] = Some(InstructionInfo::new("LOG3", 5, 0, GasPriceTier::Special));
651        arr[LOG4 as usize] = Some(InstructionInfo::new("LOG4", 6, 0, GasPriceTier::Special));
652        arr[BEGINSUB_TLOAD as usize] = Some(InstructionInfo::new("BEGINSUB", 0, 0, GasPriceTier::Base));
653        arr[JUMPSUB_MCOPY as usize] = Some(InstructionInfo::new("JUMPSUB", 1, 0, GasPriceTier::High));
654        arr[RETURNSUB_TSTORE as usize] = Some(InstructionInfo::new("RETURNSUB", 0, 0, GasPriceTier::Low));
655        arr[CREATE as usize] = Some(InstructionInfo::new("CREATE", 3, 1, GasPriceTier::Special));
656        arr[CALL as usize] = Some(InstructionInfo::new("CALL", 7, 1, GasPriceTier::Special));
657        arr[CALLCODE as usize] = Some(InstructionInfo::new("CALLCODE", 7, 1, GasPriceTier::Special));
658        arr[RETURN as usize] = Some(InstructionInfo::new("RETURN", 2, 0, GasPriceTier::Zero));
659        arr[DELEGATECALL as usize] = Some(InstructionInfo::new("DELEGATECALL", 6, 1, GasPriceTier::Special));
660        arr[STATICCALL as usize] = Some(InstructionInfo::new("STATICCALL", 6, 1, GasPriceTier::Special));
661        arr[SUICIDE as usize] = Some(InstructionInfo::new("SUICIDE", 1, 0, GasPriceTier::Special));
662        arr[CREATE2 as usize] = Some(InstructionInfo::new("CREATE2", 4, 1, GasPriceTier::Special));
663        arr[REVERT as usize] = Some(InstructionInfo::new("REVERT", 2, 0, GasPriceTier::Zero));
664        arr
665    };
666
667    pub static ref INSTRUCTIONS_CANCUN: [Option<InstructionInfo>; 0x100] = {
668        let mut arr = *INSTRUCTIONS;
669        arr[BEGINSUB_TLOAD as usize] = Some(InstructionInfo::new("TLOAD", 1, 1, GasPriceTier::Special));
670        arr[JUMPSUB_MCOPY as usize] = Some(InstructionInfo::new("MCOPY", 3, 0, GasPriceTier::Special));
671        arr[RETURNSUB_TSTORE as usize] = Some(InstructionInfo::new("TSTORE", 2, 0, GasPriceTier::Special));
672        arr
673    };
674
675    pub static ref INSTRUCTIONS_CIP645: [Option<InstructionInfo>; 0x100] = {
676        let mut arr = *INSTRUCTIONS_CANCUN;
677        arr[BASEFEE as usize] = Some(InstructionInfo::new("BASEFEE", 0, 1, GasPriceTier::Base));
678        arr[BLOBHASH as usize] = Some(InstructionInfo::new("BLOBHASH", 1, 1, GasPriceTier::VeryLow));
679        arr[BLOBBASEFEE as usize] = Some(InstructionInfo::new("BLOBBASEFEE", 0, 1, GasPriceTier::Base));
680        arr[JUMPSUB_MCOPY as usize] = Some(InstructionInfo::new("MCOPY", 3, 0, GasPriceTier::VeryLow));
681
682        arr
683    };
684
685    pub static ref INSTRUCTIONS_EIP7939: [Option<InstructionInfo>; 0x100] = {
686        let mut arr = *INSTRUCTIONS_CIP645;
687        arr[CLZ as usize] = Some(InstructionInfo::new("CLZ", 1, 1, GasPriceTier::Low));
688
689        arr
690    };
691}
692
693/// Maximal number of topics for log instructions
694pub const MAX_NO_OF_TOPICS: usize = 4;
695
696#[cfg(test)]
697mod tests {
698    use super::*;
699
700    #[test]
701    fn test_is_push() {
702        assert!(PUSH1.is_push());
703        assert!(PUSH32.is_push());
704        assert!(!DUP1.is_push());
705    }
706
707    #[test]
708    fn test_get_push_bytes() {
709        assert_eq!(PUSH1.push_bytes(), Some(1));
710        assert_eq!(PUSH3.push_bytes(), Some(3));
711        assert_eq!(PUSH32.push_bytes(), Some(32));
712    }
713
714    #[test]
715    fn test_get_dup_position() {
716        assert_eq!(DUP1.dup_position(), Some(0));
717        assert_eq!(DUP5.dup_position(), Some(4));
718        assert_eq!(DUP10.dup_position(), Some(9));
719    }
720
721    #[test]
722    fn test_get_swap_position() {
723        assert_eq!(SWAP1.swap_position(), Some(1));
724        assert_eq!(SWAP5.swap_position(), Some(5));
725        assert_eq!(SWAP10.swap_position(), Some(10));
726    }
727
728    #[test]
729    fn test_get_log_topics() {
730        assert_eq!(LOG0.log_topics(), Some(0));
731        assert_eq!(LOG2.log_topics(), Some(2));
732        assert_eq!(LOG4.log_topics(), Some(4));
733    }
734}