Skip to main content

ethrex_levm/
opcodes.rs

1use crate::{
2    errors::{OpcodeResult, VMError},
3    opcode_handlers::{
4        OpInvalidHandler, OpStopHandler, OpcodeHandler, arithmetic::*, bitwise_comparison::*,
5        block::*, dup::*, environment::*, exchange::*, keccak::*, logging::*, push::*,
6        stack_memory_storage_flow::*, system::*,
7    },
8    vm::VM,
9};
10use ethrex_common::types::Fork;
11use std::cell::OnceCell;
12use strum::EnumString;
13
14#[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, EnumString, Hash)]
15pub enum Opcode {
16    // Stop and Arithmetic Operations
17    STOP = 0x00,
18    ADD = 0x01,
19    MUL = 0x02,
20    SUB = 0x03,
21    DIV = 0x04,
22    SDIV = 0x05,
23    MOD = 0x06,
24    SMOD = 0x07,
25    ADDMOD = 0x08,
26    MULMOD = 0x09,
27    EXP = 0x0A,
28    SIGNEXTEND = 0x0B,
29
30    // Comparison & Bitwise Logic Operations
31    LT = 0x10,
32    GT = 0x11,
33    SLT = 0x12,
34    SGT = 0x13,
35    EQ = 0x14,
36    ISZERO = 0x15,
37    AND = 0x16,
38    OR = 0x17,
39    XOR = 0x18,
40    NOT = 0x19,
41    BYTE = 0x1A,
42    SHL = 0x1B,
43    SHR = 0x1C,
44    SAR = 0x1D,
45    CLZ = 0x1E,
46
47    // KECCAK256
48    KECCAK256 = 0x20,
49
50    // Environmental Information
51    ADDRESS = 0x30,
52    BALANCE = 0x31,
53    ORIGIN = 0x32,
54    CALLER = 0x33,
55    CALLVALUE = 0x34,
56    CALLDATALOAD = 0x35,
57    CALLDATASIZE = 0x36,
58    CALLDATACOPY = 0x37,
59    CODESIZE = 0x38,
60    CODECOPY = 0x39,
61    GASPRICE = 0x3A,
62    EXTCODESIZE = 0x3B,
63    EXTCODECOPY = 0x3C,
64    RETURNDATASIZE = 0x3D,
65    RETURNDATACOPY = 0x3E,
66    EXTCODEHASH = 0x3F,
67
68    // Block Information
69    BLOCKHASH = 0x40,
70    COINBASE = 0x41,
71    TIMESTAMP = 0x42,
72    NUMBER = 0x43,
73    PREVRANDAO = 0x44,
74    GASLIMIT = 0x45,
75    CHAINID = 0x46,
76    SELFBALANCE = 0x47,
77    BASEFEE = 0x48,
78    BLOBHASH = 0x49,
79    BLOBBASEFEE = 0x4A,
80    SLOTNUM = 0x4B,
81
82    // Stack, Memory, Storage, and Flow Operations
83    POP = 0x50,
84    MLOAD = 0x51,
85    MSTORE = 0x52,
86    MSTORE8 = 0x53,
87    SLOAD = 0x54,
88    SSTORE = 0x55,
89    JUMP = 0x56,
90    JUMPI = 0x57,
91    PC = 0x58,
92    MSIZE = 0x59,
93    GAS = 0x5A,
94    JUMPDEST = 0x5B,
95    TLOAD = 0x5C,
96    TSTORE = 0x5D,
97    MCOPY = 0x5E,
98
99    // Push Operations
100    PUSH0 = 0x5F,
101    PUSH1 = 0x60,
102    PUSH2 = 0x61,
103    PUSH3 = 0x62,
104    PUSH4 = 0x63,
105    PUSH5 = 0x64,
106    PUSH6 = 0x65,
107    PUSH7 = 0x66,
108    PUSH8 = 0x67,
109    PUSH9 = 0x68,
110    PUSH10 = 0x69,
111    PUSH11 = 0x6A,
112    PUSH12 = 0x6B,
113    PUSH13 = 0x6C,
114    PUSH14 = 0x6D,
115    PUSH15 = 0x6E,
116    PUSH16 = 0x6F,
117    PUSH17 = 0x70,
118    PUSH18 = 0x71,
119    PUSH19 = 0x72,
120    PUSH20 = 0x73,
121    PUSH21 = 0x74,
122    PUSH22 = 0x75,
123    PUSH23 = 0x76,
124    PUSH24 = 0x77,
125    PUSH25 = 0x78,
126    PUSH26 = 0x79,
127    PUSH27 = 0x7A,
128    PUSH28 = 0x7B,
129    PUSH29 = 0x7C,
130    PUSH30 = 0x7D,
131    PUSH31 = 0x7E,
132    PUSH32 = 0x7F,
133
134    // Duplication Operations
135    DUP1 = 0x80,
136    DUP2 = 0x81,
137    DUP3 = 0x82,
138    DUP4 = 0x83,
139    DUP5 = 0x84,
140    DUP6 = 0x85,
141    DUP7 = 0x86,
142    DUP8 = 0x87,
143    DUP9 = 0x88,
144    DUP10 = 0x89,
145    DUP11 = 0x8A,
146    DUP12 = 0x8B,
147    DUP13 = 0x8C,
148    DUP14 = 0x8D,
149    DUP15 = 0x8E,
150    DUP16 = 0x8F,
151
152    // Swap Operations
153    SWAP1 = 0x90,
154    SWAP2 = 0x91,
155    SWAP3 = 0x92,
156    SWAP4 = 0x93,
157    SWAP5 = 0x94,
158    SWAP6 = 0x95,
159    SWAP7 = 0x96,
160    SWAP8 = 0x97,
161    SWAP9 = 0x98,
162    SWAP10 = 0x99,
163    SWAP11 = 0x9A,
164    SWAP12 = 0x9B,
165    SWAP13 = 0x9C,
166    SWAP14 = 0x9D,
167    SWAP15 = 0x9E,
168    SWAP16 = 0x9F,
169    // Logging Operations
170    LOG0 = 0xA0,
171    LOG1 = 0xA1,
172    LOG2 = 0xA2,
173    LOG3 = 0xA3,
174    LOG4 = 0xA4,
175    // EIP-8024
176    DUPN = 0xE6,
177    SWAPN = 0xE7,
178    EXCHANGE = 0xE8,
179    // System Operations
180    CREATE = 0xF0,
181    CALL = 0xF1,
182    CALLCODE = 0xF2,
183    RETURN = 0xF3,
184    DELEGATECALL = 0xF4,
185    CREATE2 = 0xF5,
186    STATICCALL = 0xFA,
187    REVERT = 0xFD,
188    INVALID = 0xFE,
189    SELFDESTRUCT = 0xFF,
190}
191
192impl From<u8> for Opcode {
193    #[expect(clippy::as_conversions)]
194    fn from(byte: u8) -> Self {
195        // We use a manual lookup table instead of a match because it gives improved perfomance
196        // See https://godbolt.org/z/eG8M1jz3M
197        const OPCODE_TABLE: [Opcode; 256] = const {
198            let mut table = [Opcode::INVALID; 256];
199            table[0x00] = Opcode::STOP;
200            table[0x01] = Opcode::ADD;
201            table[0x16] = Opcode::AND;
202            table[0x17] = Opcode::OR;
203            table[0x18] = Opcode::XOR;
204            table[0x19] = Opcode::NOT;
205            table[0x1A] = Opcode::BYTE;
206            table[0x1B] = Opcode::SHL;
207            table[0x1C] = Opcode::SHR;
208            table[0x1D] = Opcode::SAR;
209            table[0x1E] = Opcode::CLZ;
210            table[0x02] = Opcode::MUL;
211            table[0x03] = Opcode::SUB;
212            table[0x04] = Opcode::DIV;
213            table[0x05] = Opcode::SDIV;
214            table[0x06] = Opcode::MOD;
215            table[0x07] = Opcode::SMOD;
216            table[0x08] = Opcode::ADDMOD;
217            table[0x09] = Opcode::MULMOD;
218            table[0x0A] = Opcode::EXP;
219            table[0x0B] = Opcode::SIGNEXTEND;
220            table[0x10] = Opcode::LT;
221            table[0x11] = Opcode::GT;
222            table[0x12] = Opcode::SLT;
223            table[0x13] = Opcode::SGT;
224            table[0x14] = Opcode::EQ;
225            table[0x15] = Opcode::ISZERO;
226            table[0x20] = Opcode::KECCAK256;
227            table[0x30] = Opcode::ADDRESS;
228            table[0x31] = Opcode::BALANCE;
229            table[0x32] = Opcode::ORIGIN;
230            table[0x33] = Opcode::CALLER;
231            table[0x34] = Opcode::CALLVALUE;
232            table[0x35] = Opcode::CALLDATALOAD;
233            table[0x36] = Opcode::CALLDATASIZE;
234            table[0x37] = Opcode::CALLDATACOPY;
235            table[0x38] = Opcode::CODESIZE;
236            table[0x39] = Opcode::CODECOPY;
237            table[0x3A] = Opcode::GASPRICE;
238            table[0x3B] = Opcode::EXTCODESIZE;
239            table[0x3C] = Opcode::EXTCODECOPY;
240            table[0x3D] = Opcode::RETURNDATASIZE;
241            table[0x3E] = Opcode::RETURNDATACOPY;
242            table[0x3F] = Opcode::EXTCODEHASH;
243            table[0x40] = Opcode::BLOCKHASH;
244            table[0x41] = Opcode::COINBASE;
245            table[0x42] = Opcode::TIMESTAMP;
246            table[0x43] = Opcode::NUMBER;
247            table[0x44] = Opcode::PREVRANDAO;
248            table[0x45] = Opcode::GASLIMIT;
249            table[0x46] = Opcode::CHAINID;
250            table[0x47] = Opcode::SELFBALANCE;
251            table[0x48] = Opcode::BASEFEE;
252            table[0x49] = Opcode::BLOBHASH;
253            table[0x4A] = Opcode::BLOBBASEFEE;
254            table[0x4B] = Opcode::SLOTNUM;
255            table[0x50] = Opcode::POP;
256            table[0x56] = Opcode::JUMP;
257            table[0x57] = Opcode::JUMPI;
258            table[0x58] = Opcode::PC;
259            table[0x5B] = Opcode::JUMPDEST;
260            table[0x5F] = Opcode::PUSH0;
261            table[0x60] = Opcode::PUSH1;
262            table[0x61] = Opcode::PUSH2;
263            table[0x62] = Opcode::PUSH3;
264            table[0x63] = Opcode::PUSH4;
265            table[0x64] = Opcode::PUSH5;
266            table[0x65] = Opcode::PUSH6;
267            table[0x66] = Opcode::PUSH7;
268            table[0x67] = Opcode::PUSH8;
269            table[0x68] = Opcode::PUSH9;
270            table[0x69] = Opcode::PUSH10;
271            table[0x6A] = Opcode::PUSH11;
272            table[0x6B] = Opcode::PUSH12;
273            table[0x6C] = Opcode::PUSH13;
274            table[0x6D] = Opcode::PUSH14;
275            table[0x6E] = Opcode::PUSH15;
276            table[0x6F] = Opcode::PUSH16;
277            table[0x70] = Opcode::PUSH17;
278            table[0x71] = Opcode::PUSH18;
279            table[0x72] = Opcode::PUSH19;
280            table[0x73] = Opcode::PUSH20;
281            table[0x74] = Opcode::PUSH21;
282            table[0x75] = Opcode::PUSH22;
283            table[0x76] = Opcode::PUSH23;
284            table[0x77] = Opcode::PUSH24;
285            table[0x78] = Opcode::PUSH25;
286            table[0x79] = Opcode::PUSH26;
287            table[0x7A] = Opcode::PUSH27;
288            table[0x7B] = Opcode::PUSH28;
289            table[0x7C] = Opcode::PUSH29;
290            table[0x7D] = Opcode::PUSH30;
291            table[0x7E] = Opcode::PUSH31;
292            table[0x7F] = Opcode::PUSH32;
293            table[0x80] = Opcode::DUP1;
294            table[0x81] = Opcode::DUP2;
295            table[0x82] = Opcode::DUP3;
296            table[0x83] = Opcode::DUP4;
297            table[0x84] = Opcode::DUP5;
298            table[0x85] = Opcode::DUP6;
299            table[0x86] = Opcode::DUP7;
300            table[0x87] = Opcode::DUP8;
301            table[0x88] = Opcode::DUP9;
302            table[0x89] = Opcode::DUP10;
303            table[0x8A] = Opcode::DUP11;
304            table[0x8B] = Opcode::DUP12;
305            table[0x8C] = Opcode::DUP13;
306            table[0x8D] = Opcode::DUP14;
307            table[0x8E] = Opcode::DUP15;
308            table[0x8F] = Opcode::DUP16;
309            table[0x90] = Opcode::SWAP1;
310            table[0x91] = Opcode::SWAP2;
311            table[0x92] = Opcode::SWAP3;
312            table[0x93] = Opcode::SWAP4;
313            table[0x94] = Opcode::SWAP5;
314            table[0x95] = Opcode::SWAP6;
315            table[0x96] = Opcode::SWAP7;
316            table[0x97] = Opcode::SWAP8;
317            table[0x98] = Opcode::SWAP9;
318            table[0x99] = Opcode::SWAP10;
319            table[0x9A] = Opcode::SWAP11;
320            table[0x9B] = Opcode::SWAP12;
321            table[0x9C] = Opcode::SWAP13;
322            table[0x9D] = Opcode::SWAP14;
323            table[0x9E] = Opcode::SWAP15;
324            table[0x9F] = Opcode::SWAP16;
325            table[0xA0] = Opcode::LOG0;
326            table[0xA1] = Opcode::LOG1;
327            table[0xA2] = Opcode::LOG2;
328            table[0xA3] = Opcode::LOG3;
329            table[0xA4] = Opcode::LOG4;
330            table[0x51] = Opcode::MLOAD;
331            table[0x52] = Opcode::MSTORE;
332            table[0x53] = Opcode::MSTORE8;
333            table[0x54] = Opcode::SLOAD;
334            table[0x55] = Opcode::SSTORE;
335            table[0x59] = Opcode::MSIZE;
336            table[0x5A] = Opcode::GAS;
337            table[0x5E] = Opcode::MCOPY;
338            table[0x5C] = Opcode::TLOAD;
339            table[0x5D] = Opcode::TSTORE;
340            table[0xE6] = Opcode::DUPN;
341            table[0xE7] = Opcode::SWAPN;
342            table[0xE8] = Opcode::EXCHANGE;
343            table[0xF0] = Opcode::CREATE;
344            table[0xF1] = Opcode::CALL;
345            table[0xF2] = Opcode::CALLCODE;
346            table[0xF3] = Opcode::RETURN;
347            table[0xF5] = Opcode::CREATE2;
348            table[0xF4] = Opcode::DELEGATECALL;
349            table[0xFA] = Opcode::STATICCALL;
350            table[0xFD] = Opcode::REVERT;
351            table[0xFF] = Opcode::SELFDESTRUCT;
352
353            table
354        };
355        #[expect(clippy::indexing_slicing)] // can never happen
356        OPCODE_TABLE[byte as usize]
357    }
358}
359
360impl From<Opcode> for u8 {
361    #[allow(clippy::as_conversions)]
362    fn from(opcode: Opcode) -> Self {
363        opcode as u8
364    }
365}
366
367impl From<Opcode> for usize {
368    #[allow(clippy::as_conversions)]
369    fn from(opcode: Opcode) -> Self {
370        opcode as usize
371    }
372}
373
374/// Represents an opcode function handler.
375#[derive(Debug, Clone, Copy)]
376pub(crate) struct OpCodeFn(fn(&mut VM<'_>, &mut OnceCell<VMError>) -> OpcodeResult);
377
378impl OpCodeFn {
379    pub const fn new<T>() -> Self
380    where
381        T: OpcodeHandler,
382    {
383        Self(Self::wrap::<T>)
384    }
385
386    /// Call the opcode handler.
387    #[inline(always)]
388    pub fn call(self, vm: &mut VM<'_>, error: &mut OnceCell<VMError>) -> OpcodeResult {
389        (self.0)(vm, error)
390    }
391
392    fn wrap<T>(vm: &mut VM<'_>, error: &mut OnceCell<VMError>) -> OpcodeResult
393    where
394        T: OpcodeHandler,
395    {
396        T::eval(vm).unwrap_or_else(|err| {
397            _ = error.set(err);
398            OpcodeResult::Halt
399        })
400    }
401}
402
403impl<'a> VM<'a> {
404    /// Returns the opcode lookup function-pointer table for the given fork.
405    ///
406    /// The per-fork tables are `const`-evaluated once into process statics (the builders below
407    /// are all `const fn`), so this is a branch returning a shared `&'static` reference — no
408    /// per-tx rebuild or 2 KB copy into the VM. `fork` is constant within a block, so every tx
409    /// in a block resolves to the same table. This is faster than a conventional match.
410    #[allow(clippy::as_conversions, clippy::indexing_slicing)]
411    pub(crate) fn build_opcode_table(fork: Fork) -> &'static [OpCodeFn; 256] {
412        // Built once at compile time; immutable, so sharing across all VMs is trivially safe.
413        // Instantiated with `'static` so the initializers don't reference the impl's `'a`.
414        static AMSTERDAM: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_amsterdam();
415        static OSAKA: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_osaka();
416        static PRE_OSAKA: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_pre_osaka();
417        static PRE_CANCUN: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_pre_cancun();
418        static PRE_SHANGHAI: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_pre_shanghai();
419
420        if fork >= Fork::Amsterdam {
421            &AMSTERDAM
422        } else if fork >= Fork::Osaka {
423            &OSAKA
424        } else if fork >= Fork::Cancun {
425            &PRE_OSAKA
426        } else if fork >= Fork::Shanghai {
427            &PRE_CANCUN
428        } else {
429            &PRE_SHANGHAI
430        }
431    }
432
433    #[allow(clippy::as_conversions, clippy::indexing_slicing)]
434    const fn build_opcode_table_pre_shanghai() -> [OpCodeFn; 256] {
435        let mut opcode_table: [OpCodeFn; 256] = [OpCodeFn::new::<OpInvalidHandler>(); 256];
436
437        opcode_table[Opcode::STOP as usize] = OpCodeFn::new::<OpStopHandler>();
438        opcode_table[Opcode::MLOAD as usize] = OpCodeFn::new::<OpMLoadHandler>();
439        opcode_table[Opcode::MSTORE as usize] = OpCodeFn::new::<OpMStoreHandler>();
440        opcode_table[Opcode::MSTORE8 as usize] = OpCodeFn::new::<OpMStore8Handler>();
441        opcode_table[Opcode::JUMP as usize] = OpCodeFn::new::<OpJumpHandler>();
442        opcode_table[Opcode::SLOAD as usize] = OpCodeFn::new::<OpSLoadHandler>();
443        opcode_table[Opcode::SSTORE as usize] = OpCodeFn::new::<OpSStoreHandler>();
444        opcode_table[Opcode::MSIZE as usize] = OpCodeFn::new::<OpMSizeHandler>();
445        opcode_table[Opcode::GAS as usize] = OpCodeFn::new::<OpGasHandler>();
446        opcode_table[Opcode::PUSH1 as usize] = OpCodeFn::new::<OpPushHandler<1>>();
447        opcode_table[Opcode::PUSH2 as usize] = OpCodeFn::new::<OpPushHandler<2>>();
448        opcode_table[Opcode::PUSH3 as usize] = OpCodeFn::new::<OpPushHandler<3>>();
449        opcode_table[Opcode::PUSH4 as usize] = OpCodeFn::new::<OpPushHandler<4>>();
450        opcode_table[Opcode::PUSH5 as usize] = OpCodeFn::new::<OpPushHandler<5>>();
451        opcode_table[Opcode::PUSH6 as usize] = OpCodeFn::new::<OpPushHandler<6>>();
452        opcode_table[Opcode::PUSH7 as usize] = OpCodeFn::new::<OpPushHandler<7>>();
453        opcode_table[Opcode::PUSH8 as usize] = OpCodeFn::new::<OpPushHandler<8>>();
454        opcode_table[Opcode::PUSH9 as usize] = OpCodeFn::new::<OpPushHandler<9>>();
455        opcode_table[Opcode::PUSH10 as usize] = OpCodeFn::new::<OpPushHandler<10>>();
456        opcode_table[Opcode::PUSH11 as usize] = OpCodeFn::new::<OpPushHandler<11>>();
457        opcode_table[Opcode::PUSH12 as usize] = OpCodeFn::new::<OpPushHandler<12>>();
458        opcode_table[Opcode::PUSH13 as usize] = OpCodeFn::new::<OpPushHandler<13>>();
459        opcode_table[Opcode::PUSH14 as usize] = OpCodeFn::new::<OpPushHandler<14>>();
460        opcode_table[Opcode::PUSH15 as usize] = OpCodeFn::new::<OpPushHandler<15>>();
461        opcode_table[Opcode::PUSH16 as usize] = OpCodeFn::new::<OpPushHandler<16>>();
462        opcode_table[Opcode::PUSH17 as usize] = OpCodeFn::new::<OpPushHandler<17>>();
463        opcode_table[Opcode::PUSH18 as usize] = OpCodeFn::new::<OpPushHandler<18>>();
464        opcode_table[Opcode::PUSH19 as usize] = OpCodeFn::new::<OpPushHandler<19>>();
465        opcode_table[Opcode::PUSH20 as usize] = OpCodeFn::new::<OpPushHandler<20>>();
466        opcode_table[Opcode::PUSH21 as usize] = OpCodeFn::new::<OpPushHandler<21>>();
467        opcode_table[Opcode::PUSH22 as usize] = OpCodeFn::new::<OpPushHandler<22>>();
468        opcode_table[Opcode::PUSH23 as usize] = OpCodeFn::new::<OpPushHandler<23>>();
469        opcode_table[Opcode::PUSH24 as usize] = OpCodeFn::new::<OpPushHandler<24>>();
470        opcode_table[Opcode::PUSH25 as usize] = OpCodeFn::new::<OpPushHandler<25>>();
471        opcode_table[Opcode::PUSH26 as usize] = OpCodeFn::new::<OpPushHandler<26>>();
472        opcode_table[Opcode::PUSH27 as usize] = OpCodeFn::new::<OpPushHandler<27>>();
473        opcode_table[Opcode::PUSH28 as usize] = OpCodeFn::new::<OpPushHandler<28>>();
474        opcode_table[Opcode::PUSH29 as usize] = OpCodeFn::new::<OpPushHandler<29>>();
475        opcode_table[Opcode::PUSH30 as usize] = OpCodeFn::new::<OpPushHandler<30>>();
476        opcode_table[Opcode::PUSH31 as usize] = OpCodeFn::new::<OpPushHandler<31>>();
477        opcode_table[Opcode::PUSH32 as usize] = OpCodeFn::new::<OpPushHandler<32>>();
478
479        opcode_table[Opcode::DUP1 as usize] = OpCodeFn::new::<OpDupHandler<0>>();
480        opcode_table[Opcode::DUP2 as usize] = OpCodeFn::new::<OpDupHandler<1>>();
481        opcode_table[Opcode::DUP3 as usize] = OpCodeFn::new::<OpDupHandler<2>>();
482        opcode_table[Opcode::DUP4 as usize] = OpCodeFn::new::<OpDupHandler<3>>();
483        opcode_table[Opcode::DUP5 as usize] = OpCodeFn::new::<OpDupHandler<4>>();
484        opcode_table[Opcode::DUP6 as usize] = OpCodeFn::new::<OpDupHandler<5>>();
485        opcode_table[Opcode::DUP7 as usize] = OpCodeFn::new::<OpDupHandler<6>>();
486        opcode_table[Opcode::DUP8 as usize] = OpCodeFn::new::<OpDupHandler<7>>();
487        opcode_table[Opcode::DUP9 as usize] = OpCodeFn::new::<OpDupHandler<8>>();
488        opcode_table[Opcode::DUP10 as usize] = OpCodeFn::new::<OpDupHandler<9>>();
489        opcode_table[Opcode::DUP11 as usize] = OpCodeFn::new::<OpDupHandler<10>>();
490        opcode_table[Opcode::DUP12 as usize] = OpCodeFn::new::<OpDupHandler<11>>();
491        opcode_table[Opcode::DUP13 as usize] = OpCodeFn::new::<OpDupHandler<12>>();
492        opcode_table[Opcode::DUP14 as usize] = OpCodeFn::new::<OpDupHandler<13>>();
493        opcode_table[Opcode::DUP15 as usize] = OpCodeFn::new::<OpDupHandler<14>>();
494        opcode_table[Opcode::DUP16 as usize] = OpCodeFn::new::<OpDupHandler<15>>();
495
496        opcode_table[Opcode::SWAP1 as usize] = OpCodeFn::new::<OpSwapHandler<1>>();
497        opcode_table[Opcode::SWAP2 as usize] = OpCodeFn::new::<OpSwapHandler<2>>();
498        opcode_table[Opcode::SWAP3 as usize] = OpCodeFn::new::<OpSwapHandler<3>>();
499        opcode_table[Opcode::SWAP4 as usize] = OpCodeFn::new::<OpSwapHandler<4>>();
500        opcode_table[Opcode::SWAP5 as usize] = OpCodeFn::new::<OpSwapHandler<5>>();
501        opcode_table[Opcode::SWAP6 as usize] = OpCodeFn::new::<OpSwapHandler<6>>();
502        opcode_table[Opcode::SWAP7 as usize] = OpCodeFn::new::<OpSwapHandler<7>>();
503        opcode_table[Opcode::SWAP8 as usize] = OpCodeFn::new::<OpSwapHandler<8>>();
504        opcode_table[Opcode::SWAP9 as usize] = OpCodeFn::new::<OpSwapHandler<9>>();
505        opcode_table[Opcode::SWAP10 as usize] = OpCodeFn::new::<OpSwapHandler<10>>();
506        opcode_table[Opcode::SWAP11 as usize] = OpCodeFn::new::<OpSwapHandler<11>>();
507        opcode_table[Opcode::SWAP12 as usize] = OpCodeFn::new::<OpSwapHandler<12>>();
508        opcode_table[Opcode::SWAP13 as usize] = OpCodeFn::new::<OpSwapHandler<13>>();
509        opcode_table[Opcode::SWAP14 as usize] = OpCodeFn::new::<OpSwapHandler<14>>();
510        opcode_table[Opcode::SWAP15 as usize] = OpCodeFn::new::<OpSwapHandler<15>>();
511        opcode_table[Opcode::SWAP16 as usize] = OpCodeFn::new::<OpSwapHandler<16>>();
512        opcode_table[Opcode::POP as usize] = OpCodeFn::new::<OpPopHandler>();
513        opcode_table[Opcode::ADD as usize] = OpCodeFn::new::<OpAddHandler>();
514        opcode_table[Opcode::MUL as usize] = OpCodeFn::new::<OpMulHandler>();
515        opcode_table[Opcode::SUB as usize] = OpCodeFn::new::<OpSubHandler>();
516        opcode_table[Opcode::DIV as usize] = OpCodeFn::new::<OpDivHandler>();
517        opcode_table[Opcode::SDIV as usize] = OpCodeFn::new::<OpSDivHandler>();
518        opcode_table[Opcode::MOD as usize] = OpCodeFn::new::<OpModHandler>();
519        opcode_table[Opcode::SMOD as usize] = OpCodeFn::new::<OpSModHandler>();
520        opcode_table[Opcode::ADDMOD as usize] = OpCodeFn::new::<OpAddModHandler>();
521        opcode_table[Opcode::MULMOD as usize] = OpCodeFn::new::<OpMulModHandler>();
522        opcode_table[Opcode::EXP as usize] = OpCodeFn::new::<OpExpHandler>();
523        opcode_table[Opcode::CALL as usize] = OpCodeFn::new::<OpCallHandler>();
524        opcode_table[Opcode::CALLCODE as usize] = OpCodeFn::new::<OpCallCodeHandler>();
525        opcode_table[Opcode::RETURN as usize] = OpCodeFn::new::<OpReturnHandler>();
526        opcode_table[Opcode::DELEGATECALL as usize] = OpCodeFn::new::<OpDelegateCallHandler>();
527        opcode_table[Opcode::STATICCALL as usize] = OpCodeFn::new::<OpStaticCallHandler>();
528        opcode_table[Opcode::CREATE as usize] = OpCodeFn::new::<OpCreateHandler>();
529        opcode_table[Opcode::CREATE2 as usize] = OpCodeFn::new::<OpCreate2Handler>();
530        opcode_table[Opcode::JUMPI as usize] = OpCodeFn::new::<OpJumpIHandler>();
531        opcode_table[Opcode::JUMPDEST as usize] = OpCodeFn::new::<OpJumpDestHandler>();
532        opcode_table[Opcode::ADDRESS as usize] = OpCodeFn::new::<OpAddressHandler>();
533        opcode_table[Opcode::ORIGIN as usize] = OpCodeFn::new::<OpOriginHandler>();
534        opcode_table[Opcode::BALANCE as usize] = OpCodeFn::new::<OpBalanceHandler>();
535        opcode_table[Opcode::CALLER as usize] = OpCodeFn::new::<OpCallerHandler>();
536        opcode_table[Opcode::CALLVALUE as usize] = OpCodeFn::new::<OpCallValueHandler>();
537        opcode_table[Opcode::CODECOPY as usize] = OpCodeFn::new::<OpCodeCopyHandler>();
538        opcode_table[Opcode::SIGNEXTEND as usize] = OpCodeFn::new::<OpSignExtendHandler>();
539        opcode_table[Opcode::LT as usize] = OpCodeFn::new::<OpLtHandler>();
540        opcode_table[Opcode::GT as usize] = OpCodeFn::new::<OpGtHandler>();
541        opcode_table[Opcode::SLT as usize] = OpCodeFn::new::<OpSLtHandler>();
542        opcode_table[Opcode::SGT as usize] = OpCodeFn::new::<OpSGtHandler>();
543        opcode_table[Opcode::EQ as usize] = OpCodeFn::new::<OpEqHandler>();
544        opcode_table[Opcode::ISZERO as usize] = OpCodeFn::new::<OpIsZeroHandler>();
545        opcode_table[Opcode::KECCAK256 as usize] = OpCodeFn::new::<OpKeccak256Handler>();
546        opcode_table[Opcode::CALLDATALOAD as usize] = OpCodeFn::new::<OpCallDataLoadHandler>();
547        opcode_table[Opcode::CALLDATASIZE as usize] = OpCodeFn::new::<OpCallDataSizeHandler>();
548        opcode_table[Opcode::CALLDATACOPY as usize] = OpCodeFn::new::<OpCallDataCopyHandler>();
549        opcode_table[Opcode::RETURNDATASIZE as usize] = OpCodeFn::new::<OpReturnDataSizeHandler>();
550        opcode_table[Opcode::RETURNDATACOPY as usize] = OpCodeFn::new::<OpReturnDataCopyHandler>();
551        opcode_table[Opcode::PC as usize] = OpCodeFn::new::<OpPcHandler>();
552        opcode_table[Opcode::BLOCKHASH as usize] = OpCodeFn::new::<OpBlockHashHandler>();
553        opcode_table[Opcode::COINBASE as usize] = OpCodeFn::new::<OpCoinbaseHandler>();
554        opcode_table[Opcode::TIMESTAMP as usize] = OpCodeFn::new::<OpTimestampHandler>();
555        opcode_table[Opcode::NUMBER as usize] = OpCodeFn::new::<OpNumberHandler>();
556        opcode_table[Opcode::PREVRANDAO as usize] = OpCodeFn::new::<OpPrevRandaoHandler>();
557        opcode_table[Opcode::GASLIMIT as usize] = OpCodeFn::new::<OpGasLimitHandler>();
558        opcode_table[Opcode::CHAINID as usize] = OpCodeFn::new::<OpChainIdHandler>();
559        opcode_table[Opcode::BASEFEE as usize] = OpCodeFn::new::<OpBaseFeeHandler>();
560        opcode_table[Opcode::AND as usize] = OpCodeFn::new::<OpAndHandler>();
561        opcode_table[Opcode::OR as usize] = OpCodeFn::new::<OpOrHandler>();
562        opcode_table[Opcode::XOR as usize] = OpCodeFn::new::<OpXorHandler>();
563        opcode_table[Opcode::NOT as usize] = OpCodeFn::new::<OpNotHandler>();
564        opcode_table[Opcode::BYTE as usize] = OpCodeFn::new::<OpByteHandler>();
565        opcode_table[Opcode::SHL as usize] = OpCodeFn::new::<OpShlHandler>();
566        opcode_table[Opcode::SHR as usize] = OpCodeFn::new::<OpShrHandler>();
567        opcode_table[Opcode::SAR as usize] = OpCodeFn::new::<OpSarHandler>();
568        opcode_table[Opcode::SELFBALANCE as usize] = OpCodeFn::new::<OpSelfBalanceHandler>();
569        opcode_table[Opcode::CODESIZE as usize] = OpCodeFn::new::<OpCodeSizeHandler>();
570        opcode_table[Opcode::GASPRICE as usize] = OpCodeFn::new::<OpGasPriceHandler>();
571        opcode_table[Opcode::EXTCODESIZE as usize] = OpCodeFn::new::<OpExtCodeSizeHandler>();
572        opcode_table[Opcode::EXTCODECOPY as usize] = OpCodeFn::new::<OpExtCodeCopyHandler>();
573        opcode_table[Opcode::EXTCODEHASH as usize] = OpCodeFn::new::<OpExtCodeHashHandler>();
574        opcode_table[Opcode::REVERT as usize] = OpCodeFn::new::<OpRevertHandler>();
575        opcode_table[Opcode::INVALID as usize] = OpCodeFn::new::<OpInvalidHandler>();
576        opcode_table[Opcode::SELFDESTRUCT as usize] = OpCodeFn::new::<OpSelfDestructHandler>();
577
578        opcode_table[Opcode::LOG0 as usize] = OpCodeFn::new::<OpLogHandler<0>>();
579        opcode_table[Opcode::LOG1 as usize] = OpCodeFn::new::<OpLogHandler<1>>();
580        opcode_table[Opcode::LOG2 as usize] = OpCodeFn::new::<OpLogHandler<2>>();
581        opcode_table[Opcode::LOG3 as usize] = OpCodeFn::new::<OpLogHandler<3>>();
582        opcode_table[Opcode::LOG4 as usize] = OpCodeFn::new::<OpLogHandler<4>>();
583
584        opcode_table
585    }
586
587    #[allow(clippy::as_conversions, clippy::indexing_slicing)]
588    const fn build_opcode_table_pre_cancun() -> [OpCodeFn; 256] {
589        let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_pre_shanghai();
590
591        // [EIP-3855] - PUSH0 is only available from SHANGHAI
592        opcode_table[Opcode::PUSH0 as usize] = OpCodeFn::new::<OpPush0Handler>();
593
594        opcode_table
595    }
596
597    #[allow(clippy::as_conversions, clippy::indexing_slicing)]
598    const fn build_opcode_table_pre_osaka() -> [OpCodeFn; 256] {
599        const {
600            let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_pre_cancun();
601
602            // [EIP-5656] - MCOPY is only available from CANCUN
603            opcode_table[Opcode::MCOPY as usize] = OpCodeFn::new::<OpMCopyHandler>();
604
605            // [EIP-1153] - TLOAD is only available from CANCUN
606            opcode_table[Opcode::TLOAD as usize] = OpCodeFn::new::<OpTLoadHandler>();
607            opcode_table[Opcode::TSTORE as usize] = OpCodeFn::new::<OpTStoreHandler>();
608
609            // [EIP-7516] - BLOBBASEFEE is only available from CANCUN
610            opcode_table[Opcode::BLOBBASEFEE as usize] = OpCodeFn::new::<OpBlobBaseFeeHandler>();
611            // [EIP-4844] - BLOBHASH is only available from CANCUN
612            opcode_table[Opcode::BLOBHASH as usize] = OpCodeFn::new::<OpBlobHashHandler>();
613
614            opcode_table
615        }
616    }
617
618    #[allow(clippy::as_conversions, clippy::indexing_slicing)]
619    const fn build_opcode_table_osaka() -> [OpCodeFn; 256] {
620        let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_pre_osaka();
621
622        opcode_table[Opcode::CLZ as usize] = OpCodeFn::new::<OpClzHandler>();
623
624        opcode_table
625    }
626
627    #[expect(clippy::as_conversions, clippy::indexing_slicing)]
628    const fn build_opcode_table_amsterdam() -> [OpCodeFn; 256] {
629        let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_osaka();
630
631        // EIP-8024 opcodes
632        opcode_table[Opcode::DUPN as usize] = OpCodeFn::new::<OpDupNHandler>();
633        opcode_table[Opcode::SWAPN as usize] = OpCodeFn::new::<OpSwapNHandler>();
634        opcode_table[Opcode::EXCHANGE as usize] = OpCodeFn::new::<OpExchangeHandler>();
635        // EIP-7843 opcode
636        opcode_table[Opcode::SLOTNUM as usize] = OpCodeFn::new::<OpSlotNumHandler>();
637        opcode_table
638    }
639}