1use crate::{
2 errors::{OpcodeResult, VMError},
3 opcode_handlers::{
4 OpInvalidHandler, OpStopHandler, OpcodeHandler, arithmetic::*, bitwise_comparison::*,
5 block::*, dup::*, environment::*, exchange::*, frame_tx::*, 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 = 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 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 = 0x20,
49
50 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 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 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 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 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 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 LOG0 = 0xA0,
171 LOG1 = 0xA1,
172 LOG2 = 0xA2,
173 LOG3 = 0xA3,
174 LOG4 = 0xA4,
175 APPROVE = 0xAA,
177 TXPARAM = 0xB0,
178 FRAMEDATALOAD = 0xB1,
179 FRAMEDATACOPY = 0xB2,
180 FRAMEPARAM = 0xB3,
181 SIGPARAM = 0xB4,
182 DUPN = 0xE6,
184 SWAPN = 0xE7,
185 EXCHANGE = 0xE8,
186 CREATE = 0xF0,
188 CALL = 0xF1,
189 CALLCODE = 0xF2,
190 RETURN = 0xF3,
191 DELEGATECALL = 0xF4,
192 CREATE2 = 0xF5,
193 STATICCALL = 0xFA,
194 REVERT = 0xFD,
195 INVALID = 0xFE,
196 SELFDESTRUCT = 0xFF,
197}
198
199impl From<u8> for Opcode {
200 #[expect(clippy::as_conversions)]
201 fn from(byte: u8) -> Self {
202 const OPCODE_TABLE: [Opcode; 256] = const {
205 let mut table = [Opcode::INVALID; 256];
206 table[0x00] = Opcode::STOP;
207 table[0x01] = Opcode::ADD;
208 table[0x16] = Opcode::AND;
209 table[0x17] = Opcode::OR;
210 table[0x18] = Opcode::XOR;
211 table[0x19] = Opcode::NOT;
212 table[0x1A] = Opcode::BYTE;
213 table[0x1B] = Opcode::SHL;
214 table[0x1C] = Opcode::SHR;
215 table[0x1D] = Opcode::SAR;
216 table[0x1E] = Opcode::CLZ;
217 table[0x02] = Opcode::MUL;
218 table[0x03] = Opcode::SUB;
219 table[0x04] = Opcode::DIV;
220 table[0x05] = Opcode::SDIV;
221 table[0x06] = Opcode::MOD;
222 table[0x07] = Opcode::SMOD;
223 table[0x08] = Opcode::ADDMOD;
224 table[0x09] = Opcode::MULMOD;
225 table[0x0A] = Opcode::EXP;
226 table[0x0B] = Opcode::SIGNEXTEND;
227 table[0x10] = Opcode::LT;
228 table[0x11] = Opcode::GT;
229 table[0x12] = Opcode::SLT;
230 table[0x13] = Opcode::SGT;
231 table[0x14] = Opcode::EQ;
232 table[0x15] = Opcode::ISZERO;
233 table[0x20] = Opcode::KECCAK256;
234 table[0x30] = Opcode::ADDRESS;
235 table[0x31] = Opcode::BALANCE;
236 table[0x32] = Opcode::ORIGIN;
237 table[0x33] = Opcode::CALLER;
238 table[0x34] = Opcode::CALLVALUE;
239 table[0x35] = Opcode::CALLDATALOAD;
240 table[0x36] = Opcode::CALLDATASIZE;
241 table[0x37] = Opcode::CALLDATACOPY;
242 table[0x38] = Opcode::CODESIZE;
243 table[0x39] = Opcode::CODECOPY;
244 table[0x3A] = Opcode::GASPRICE;
245 table[0x3B] = Opcode::EXTCODESIZE;
246 table[0x3C] = Opcode::EXTCODECOPY;
247 table[0x3D] = Opcode::RETURNDATASIZE;
248 table[0x3E] = Opcode::RETURNDATACOPY;
249 table[0x3F] = Opcode::EXTCODEHASH;
250 table[0x40] = Opcode::BLOCKHASH;
251 table[0x41] = Opcode::COINBASE;
252 table[0x42] = Opcode::TIMESTAMP;
253 table[0x43] = Opcode::NUMBER;
254 table[0x44] = Opcode::PREVRANDAO;
255 table[0x45] = Opcode::GASLIMIT;
256 table[0x46] = Opcode::CHAINID;
257 table[0x47] = Opcode::SELFBALANCE;
258 table[0x48] = Opcode::BASEFEE;
259 table[0x49] = Opcode::BLOBHASH;
260 table[0x4A] = Opcode::BLOBBASEFEE;
261 table[0x4B] = Opcode::SLOTNUM;
262 table[0x50] = Opcode::POP;
263 table[0x56] = Opcode::JUMP;
264 table[0x57] = Opcode::JUMPI;
265 table[0x58] = Opcode::PC;
266 table[0x5B] = Opcode::JUMPDEST;
267 table[0x5F] = Opcode::PUSH0;
268 table[0x60] = Opcode::PUSH1;
269 table[0x61] = Opcode::PUSH2;
270 table[0x62] = Opcode::PUSH3;
271 table[0x63] = Opcode::PUSH4;
272 table[0x64] = Opcode::PUSH5;
273 table[0x65] = Opcode::PUSH6;
274 table[0x66] = Opcode::PUSH7;
275 table[0x67] = Opcode::PUSH8;
276 table[0x68] = Opcode::PUSH9;
277 table[0x69] = Opcode::PUSH10;
278 table[0x6A] = Opcode::PUSH11;
279 table[0x6B] = Opcode::PUSH12;
280 table[0x6C] = Opcode::PUSH13;
281 table[0x6D] = Opcode::PUSH14;
282 table[0x6E] = Opcode::PUSH15;
283 table[0x6F] = Opcode::PUSH16;
284 table[0x70] = Opcode::PUSH17;
285 table[0x71] = Opcode::PUSH18;
286 table[0x72] = Opcode::PUSH19;
287 table[0x73] = Opcode::PUSH20;
288 table[0x74] = Opcode::PUSH21;
289 table[0x75] = Opcode::PUSH22;
290 table[0x76] = Opcode::PUSH23;
291 table[0x77] = Opcode::PUSH24;
292 table[0x78] = Opcode::PUSH25;
293 table[0x79] = Opcode::PUSH26;
294 table[0x7A] = Opcode::PUSH27;
295 table[0x7B] = Opcode::PUSH28;
296 table[0x7C] = Opcode::PUSH29;
297 table[0x7D] = Opcode::PUSH30;
298 table[0x7E] = Opcode::PUSH31;
299 table[0x7F] = Opcode::PUSH32;
300 table[0x80] = Opcode::DUP1;
301 table[0x81] = Opcode::DUP2;
302 table[0x82] = Opcode::DUP3;
303 table[0x83] = Opcode::DUP4;
304 table[0x84] = Opcode::DUP5;
305 table[0x85] = Opcode::DUP6;
306 table[0x86] = Opcode::DUP7;
307 table[0x87] = Opcode::DUP8;
308 table[0x88] = Opcode::DUP9;
309 table[0x89] = Opcode::DUP10;
310 table[0x8A] = Opcode::DUP11;
311 table[0x8B] = Opcode::DUP12;
312 table[0x8C] = Opcode::DUP13;
313 table[0x8D] = Opcode::DUP14;
314 table[0x8E] = Opcode::DUP15;
315 table[0x8F] = Opcode::DUP16;
316 table[0x90] = Opcode::SWAP1;
317 table[0x91] = Opcode::SWAP2;
318 table[0x92] = Opcode::SWAP3;
319 table[0x93] = Opcode::SWAP4;
320 table[0x94] = Opcode::SWAP5;
321 table[0x95] = Opcode::SWAP6;
322 table[0x96] = Opcode::SWAP7;
323 table[0x97] = Opcode::SWAP8;
324 table[0x98] = Opcode::SWAP9;
325 table[0x99] = Opcode::SWAP10;
326 table[0x9A] = Opcode::SWAP11;
327 table[0x9B] = Opcode::SWAP12;
328 table[0x9C] = Opcode::SWAP13;
329 table[0x9D] = Opcode::SWAP14;
330 table[0x9E] = Opcode::SWAP15;
331 table[0x9F] = Opcode::SWAP16;
332 table[0xA0] = Opcode::LOG0;
333 table[0xA1] = Opcode::LOG1;
334 table[0xA2] = Opcode::LOG2;
335 table[0xA3] = Opcode::LOG3;
336 table[0xA4] = Opcode::LOG4;
337 table[0xAA] = Opcode::APPROVE;
338 table[0xB0] = Opcode::TXPARAM;
339 table[0xB1] = Opcode::FRAMEDATALOAD;
340 table[0xB2] = Opcode::FRAMEDATACOPY;
341 table[0xB3] = Opcode::FRAMEPARAM;
342 table[0xB4] = Opcode::SIGPARAM;
343 table[0x51] = Opcode::MLOAD;
344 table[0x52] = Opcode::MSTORE;
345 table[0x53] = Opcode::MSTORE8;
346 table[0x54] = Opcode::SLOAD;
347 table[0x55] = Opcode::SSTORE;
348 table[0x59] = Opcode::MSIZE;
349 table[0x5A] = Opcode::GAS;
350 table[0x5E] = Opcode::MCOPY;
351 table[0x5C] = Opcode::TLOAD;
352 table[0x5D] = Opcode::TSTORE;
353 table[0xE6] = Opcode::DUPN;
354 table[0xE7] = Opcode::SWAPN;
355 table[0xE8] = Opcode::EXCHANGE;
356 table[0xF0] = Opcode::CREATE;
357 table[0xF1] = Opcode::CALL;
358 table[0xF2] = Opcode::CALLCODE;
359 table[0xF3] = Opcode::RETURN;
360 table[0xF5] = Opcode::CREATE2;
361 table[0xF4] = Opcode::DELEGATECALL;
362 table[0xFA] = Opcode::STATICCALL;
363 table[0xFD] = Opcode::REVERT;
364 table[0xFF] = Opcode::SELFDESTRUCT;
365
366 table
367 };
368 #[expect(clippy::indexing_slicing)] OPCODE_TABLE[byte as usize]
370 }
371}
372
373impl From<Opcode> for u8 {
374 #[allow(clippy::as_conversions)]
375 fn from(opcode: Opcode) -> Self {
376 opcode as u8
377 }
378}
379
380impl From<Opcode> for usize {
381 #[allow(clippy::as_conversions)]
382 fn from(opcode: Opcode) -> Self {
383 opcode as usize
384 }
385}
386
387#[derive(Debug, Clone, Copy)]
389pub(crate) struct OpCodeFn(fn(&mut VM<'_>, &mut OnceCell<VMError>) -> OpcodeResult);
390
391impl OpCodeFn {
392 pub const fn new<T>() -> Self
393 where
394 T: OpcodeHandler,
395 {
396 Self(Self::wrap::<T>)
397 }
398
399 #[inline(always)]
401 pub fn call(self, vm: &mut VM<'_>, error: &mut OnceCell<VMError>) -> OpcodeResult {
402 (self.0)(vm, error)
403 }
404
405 fn wrap<T>(vm: &mut VM<'_>, error: &mut OnceCell<VMError>) -> OpcodeResult
406 where
407 T: OpcodeHandler,
408 {
409 T::eval(vm).unwrap_or_else(|err| {
410 _ = error.set(err);
411 OpcodeResult::Halt
412 })
413 }
414}
415
416impl<'a> VM<'a> {
417 #[allow(clippy::as_conversions, clippy::indexing_slicing)]
424 pub(crate) fn build_opcode_table(fork: Fork) -> &'static [OpCodeFn; 256] {
425 static HEGOTA: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_hegota();
428 static AMSTERDAM: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_amsterdam();
429 static OSAKA: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_osaka();
430 static PRE_OSAKA: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_pre_osaka();
431 static PRE_CANCUN: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_pre_cancun();
432 static PRE_SHANGHAI: [OpCodeFn; 256] = VM::<'static>::build_opcode_table_pre_shanghai();
433
434 if fork >= Fork::Hegota {
435 &HEGOTA
436 } else if fork >= Fork::Amsterdam {
437 &AMSTERDAM
438 } else if fork >= Fork::Osaka {
439 &OSAKA
440 } else if fork >= Fork::Cancun {
441 &PRE_OSAKA
442 } else if fork >= Fork::Shanghai {
443 &PRE_CANCUN
444 } else {
445 &PRE_SHANGHAI
446 }
447 }
448
449 #[allow(clippy::as_conversions, clippy::indexing_slicing)]
450 const fn build_opcode_table_pre_shanghai() -> [OpCodeFn; 256] {
451 let mut opcode_table: [OpCodeFn; 256] = [OpCodeFn::new::<OpInvalidHandler>(); 256];
452
453 opcode_table[Opcode::STOP as usize] = OpCodeFn::new::<OpStopHandler>();
454 opcode_table[Opcode::MLOAD as usize] = OpCodeFn::new::<OpMLoadHandler>();
455 opcode_table[Opcode::MSTORE as usize] = OpCodeFn::new::<OpMStoreHandler>();
456 opcode_table[Opcode::MSTORE8 as usize] = OpCodeFn::new::<OpMStore8Handler>();
457 opcode_table[Opcode::JUMP as usize] = OpCodeFn::new::<OpJumpHandler>();
458 opcode_table[Opcode::SLOAD as usize] = OpCodeFn::new::<OpSLoadHandler>();
459 opcode_table[Opcode::SSTORE as usize] = OpCodeFn::new::<OpSStoreHandler>();
460 opcode_table[Opcode::MSIZE as usize] = OpCodeFn::new::<OpMSizeHandler>();
461 opcode_table[Opcode::GAS as usize] = OpCodeFn::new::<OpGasHandler>();
462 opcode_table[Opcode::PUSH1 as usize] = OpCodeFn::new::<OpPushHandler<1>>();
463 opcode_table[Opcode::PUSH2 as usize] = OpCodeFn::new::<OpPushHandler<2>>();
464 opcode_table[Opcode::PUSH3 as usize] = OpCodeFn::new::<OpPushHandler<3>>();
465 opcode_table[Opcode::PUSH4 as usize] = OpCodeFn::new::<OpPushHandler<4>>();
466 opcode_table[Opcode::PUSH5 as usize] = OpCodeFn::new::<OpPushHandler<5>>();
467 opcode_table[Opcode::PUSH6 as usize] = OpCodeFn::new::<OpPushHandler<6>>();
468 opcode_table[Opcode::PUSH7 as usize] = OpCodeFn::new::<OpPushHandler<7>>();
469 opcode_table[Opcode::PUSH8 as usize] = OpCodeFn::new::<OpPushHandler<8>>();
470 opcode_table[Opcode::PUSH9 as usize] = OpCodeFn::new::<OpPushHandler<9>>();
471 opcode_table[Opcode::PUSH10 as usize] = OpCodeFn::new::<OpPushHandler<10>>();
472 opcode_table[Opcode::PUSH11 as usize] = OpCodeFn::new::<OpPushHandler<11>>();
473 opcode_table[Opcode::PUSH12 as usize] = OpCodeFn::new::<OpPushHandler<12>>();
474 opcode_table[Opcode::PUSH13 as usize] = OpCodeFn::new::<OpPushHandler<13>>();
475 opcode_table[Opcode::PUSH14 as usize] = OpCodeFn::new::<OpPushHandler<14>>();
476 opcode_table[Opcode::PUSH15 as usize] = OpCodeFn::new::<OpPushHandler<15>>();
477 opcode_table[Opcode::PUSH16 as usize] = OpCodeFn::new::<OpPushHandler<16>>();
478 opcode_table[Opcode::PUSH17 as usize] = OpCodeFn::new::<OpPushHandler<17>>();
479 opcode_table[Opcode::PUSH18 as usize] = OpCodeFn::new::<OpPushHandler<18>>();
480 opcode_table[Opcode::PUSH19 as usize] = OpCodeFn::new::<OpPushHandler<19>>();
481 opcode_table[Opcode::PUSH20 as usize] = OpCodeFn::new::<OpPushHandler<20>>();
482 opcode_table[Opcode::PUSH21 as usize] = OpCodeFn::new::<OpPushHandler<21>>();
483 opcode_table[Opcode::PUSH22 as usize] = OpCodeFn::new::<OpPushHandler<22>>();
484 opcode_table[Opcode::PUSH23 as usize] = OpCodeFn::new::<OpPushHandler<23>>();
485 opcode_table[Opcode::PUSH24 as usize] = OpCodeFn::new::<OpPushHandler<24>>();
486 opcode_table[Opcode::PUSH25 as usize] = OpCodeFn::new::<OpPushHandler<25>>();
487 opcode_table[Opcode::PUSH26 as usize] = OpCodeFn::new::<OpPushHandler<26>>();
488 opcode_table[Opcode::PUSH27 as usize] = OpCodeFn::new::<OpPushHandler<27>>();
489 opcode_table[Opcode::PUSH28 as usize] = OpCodeFn::new::<OpPushHandler<28>>();
490 opcode_table[Opcode::PUSH29 as usize] = OpCodeFn::new::<OpPushHandler<29>>();
491 opcode_table[Opcode::PUSH30 as usize] = OpCodeFn::new::<OpPushHandler<30>>();
492 opcode_table[Opcode::PUSH31 as usize] = OpCodeFn::new::<OpPushHandler<31>>();
493 opcode_table[Opcode::PUSH32 as usize] = OpCodeFn::new::<OpPushHandler<32>>();
494
495 opcode_table[Opcode::DUP1 as usize] = OpCodeFn::new::<OpDupHandler<0>>();
496 opcode_table[Opcode::DUP2 as usize] = OpCodeFn::new::<OpDupHandler<1>>();
497 opcode_table[Opcode::DUP3 as usize] = OpCodeFn::new::<OpDupHandler<2>>();
498 opcode_table[Opcode::DUP4 as usize] = OpCodeFn::new::<OpDupHandler<3>>();
499 opcode_table[Opcode::DUP5 as usize] = OpCodeFn::new::<OpDupHandler<4>>();
500 opcode_table[Opcode::DUP6 as usize] = OpCodeFn::new::<OpDupHandler<5>>();
501 opcode_table[Opcode::DUP7 as usize] = OpCodeFn::new::<OpDupHandler<6>>();
502 opcode_table[Opcode::DUP8 as usize] = OpCodeFn::new::<OpDupHandler<7>>();
503 opcode_table[Opcode::DUP9 as usize] = OpCodeFn::new::<OpDupHandler<8>>();
504 opcode_table[Opcode::DUP10 as usize] = OpCodeFn::new::<OpDupHandler<9>>();
505 opcode_table[Opcode::DUP11 as usize] = OpCodeFn::new::<OpDupHandler<10>>();
506 opcode_table[Opcode::DUP12 as usize] = OpCodeFn::new::<OpDupHandler<11>>();
507 opcode_table[Opcode::DUP13 as usize] = OpCodeFn::new::<OpDupHandler<12>>();
508 opcode_table[Opcode::DUP14 as usize] = OpCodeFn::new::<OpDupHandler<13>>();
509 opcode_table[Opcode::DUP15 as usize] = OpCodeFn::new::<OpDupHandler<14>>();
510 opcode_table[Opcode::DUP16 as usize] = OpCodeFn::new::<OpDupHandler<15>>();
511
512 opcode_table[Opcode::SWAP1 as usize] = OpCodeFn::new::<OpSwapHandler<1>>();
513 opcode_table[Opcode::SWAP2 as usize] = OpCodeFn::new::<OpSwapHandler<2>>();
514 opcode_table[Opcode::SWAP3 as usize] = OpCodeFn::new::<OpSwapHandler<3>>();
515 opcode_table[Opcode::SWAP4 as usize] = OpCodeFn::new::<OpSwapHandler<4>>();
516 opcode_table[Opcode::SWAP5 as usize] = OpCodeFn::new::<OpSwapHandler<5>>();
517 opcode_table[Opcode::SWAP6 as usize] = OpCodeFn::new::<OpSwapHandler<6>>();
518 opcode_table[Opcode::SWAP7 as usize] = OpCodeFn::new::<OpSwapHandler<7>>();
519 opcode_table[Opcode::SWAP8 as usize] = OpCodeFn::new::<OpSwapHandler<8>>();
520 opcode_table[Opcode::SWAP9 as usize] = OpCodeFn::new::<OpSwapHandler<9>>();
521 opcode_table[Opcode::SWAP10 as usize] = OpCodeFn::new::<OpSwapHandler<10>>();
522 opcode_table[Opcode::SWAP11 as usize] = OpCodeFn::new::<OpSwapHandler<11>>();
523 opcode_table[Opcode::SWAP12 as usize] = OpCodeFn::new::<OpSwapHandler<12>>();
524 opcode_table[Opcode::SWAP13 as usize] = OpCodeFn::new::<OpSwapHandler<13>>();
525 opcode_table[Opcode::SWAP14 as usize] = OpCodeFn::new::<OpSwapHandler<14>>();
526 opcode_table[Opcode::SWAP15 as usize] = OpCodeFn::new::<OpSwapHandler<15>>();
527 opcode_table[Opcode::SWAP16 as usize] = OpCodeFn::new::<OpSwapHandler<16>>();
528 opcode_table[Opcode::POP as usize] = OpCodeFn::new::<OpPopHandler>();
529 opcode_table[Opcode::ADD as usize] = OpCodeFn::new::<OpAddHandler>();
530 opcode_table[Opcode::MUL as usize] = OpCodeFn::new::<OpMulHandler>();
531 opcode_table[Opcode::SUB as usize] = OpCodeFn::new::<OpSubHandler>();
532 opcode_table[Opcode::DIV as usize] = OpCodeFn::new::<OpDivHandler>();
533 opcode_table[Opcode::SDIV as usize] = OpCodeFn::new::<OpSDivHandler>();
534 opcode_table[Opcode::MOD as usize] = OpCodeFn::new::<OpModHandler>();
535 opcode_table[Opcode::SMOD as usize] = OpCodeFn::new::<OpSModHandler>();
536 opcode_table[Opcode::ADDMOD as usize] = OpCodeFn::new::<OpAddModHandler>();
537 opcode_table[Opcode::MULMOD as usize] = OpCodeFn::new::<OpMulModHandler>();
538 opcode_table[Opcode::EXP as usize] = OpCodeFn::new::<OpExpHandler>();
539 opcode_table[Opcode::CALL as usize] = OpCodeFn::new::<OpCallHandler>();
540 opcode_table[Opcode::CALLCODE as usize] = OpCodeFn::new::<OpCallCodeHandler>();
541 opcode_table[Opcode::RETURN as usize] = OpCodeFn::new::<OpReturnHandler>();
542 opcode_table[Opcode::DELEGATECALL as usize] = OpCodeFn::new::<OpDelegateCallHandler>();
543 opcode_table[Opcode::STATICCALL as usize] = OpCodeFn::new::<OpStaticCallHandler>();
544 opcode_table[Opcode::CREATE as usize] = OpCodeFn::new::<OpCreateHandler>();
545 opcode_table[Opcode::CREATE2 as usize] = OpCodeFn::new::<OpCreate2Handler>();
546 opcode_table[Opcode::JUMPI as usize] = OpCodeFn::new::<OpJumpIHandler>();
547 opcode_table[Opcode::JUMPDEST as usize] = OpCodeFn::new::<OpJumpDestHandler>();
548 opcode_table[Opcode::ADDRESS as usize] = OpCodeFn::new::<OpAddressHandler>();
549 opcode_table[Opcode::ORIGIN as usize] = OpCodeFn::new::<OpOriginHandler>();
550 opcode_table[Opcode::BALANCE as usize] = OpCodeFn::new::<OpBalanceHandler>();
551 opcode_table[Opcode::CALLER as usize] = OpCodeFn::new::<OpCallerHandler>();
552 opcode_table[Opcode::CALLVALUE as usize] = OpCodeFn::new::<OpCallValueHandler>();
553 opcode_table[Opcode::CODECOPY as usize] = OpCodeFn::new::<OpCodeCopyHandler>();
554 opcode_table[Opcode::SIGNEXTEND as usize] = OpCodeFn::new::<OpSignExtendHandler>();
555 opcode_table[Opcode::LT as usize] = OpCodeFn::new::<OpLtHandler>();
556 opcode_table[Opcode::GT as usize] = OpCodeFn::new::<OpGtHandler>();
557 opcode_table[Opcode::SLT as usize] = OpCodeFn::new::<OpSLtHandler>();
558 opcode_table[Opcode::SGT as usize] = OpCodeFn::new::<OpSGtHandler>();
559 opcode_table[Opcode::EQ as usize] = OpCodeFn::new::<OpEqHandler>();
560 opcode_table[Opcode::ISZERO as usize] = OpCodeFn::new::<OpIsZeroHandler>();
561 opcode_table[Opcode::KECCAK256 as usize] = OpCodeFn::new::<OpKeccak256Handler>();
562 opcode_table[Opcode::CALLDATALOAD as usize] = OpCodeFn::new::<OpCallDataLoadHandler>();
563 opcode_table[Opcode::CALLDATASIZE as usize] = OpCodeFn::new::<OpCallDataSizeHandler>();
564 opcode_table[Opcode::CALLDATACOPY as usize] = OpCodeFn::new::<OpCallDataCopyHandler>();
565 opcode_table[Opcode::RETURNDATASIZE as usize] = OpCodeFn::new::<OpReturnDataSizeHandler>();
566 opcode_table[Opcode::RETURNDATACOPY as usize] = OpCodeFn::new::<OpReturnDataCopyHandler>();
567 opcode_table[Opcode::PC as usize] = OpCodeFn::new::<OpPcHandler>();
568 opcode_table[Opcode::BLOCKHASH as usize] = OpCodeFn::new::<OpBlockHashHandler>();
569 opcode_table[Opcode::COINBASE as usize] = OpCodeFn::new::<OpCoinbaseHandler>();
570 opcode_table[Opcode::TIMESTAMP as usize] = OpCodeFn::new::<OpTimestampHandler>();
571 opcode_table[Opcode::NUMBER as usize] = OpCodeFn::new::<OpNumberHandler>();
572 opcode_table[Opcode::PREVRANDAO as usize] = OpCodeFn::new::<OpPrevRandaoHandler>();
573 opcode_table[Opcode::GASLIMIT as usize] = OpCodeFn::new::<OpGasLimitHandler>();
574 opcode_table[Opcode::CHAINID as usize] = OpCodeFn::new::<OpChainIdHandler>();
575 opcode_table[Opcode::BASEFEE as usize] = OpCodeFn::new::<OpBaseFeeHandler>();
576 opcode_table[Opcode::AND as usize] = OpCodeFn::new::<OpAndHandler>();
577 opcode_table[Opcode::OR as usize] = OpCodeFn::new::<OpOrHandler>();
578 opcode_table[Opcode::XOR as usize] = OpCodeFn::new::<OpXorHandler>();
579 opcode_table[Opcode::NOT as usize] = OpCodeFn::new::<OpNotHandler>();
580 opcode_table[Opcode::BYTE as usize] = OpCodeFn::new::<OpByteHandler>();
581 opcode_table[Opcode::SHL as usize] = OpCodeFn::new::<OpShlHandler>();
582 opcode_table[Opcode::SHR as usize] = OpCodeFn::new::<OpShrHandler>();
583 opcode_table[Opcode::SAR as usize] = OpCodeFn::new::<OpSarHandler>();
584 opcode_table[Opcode::SELFBALANCE as usize] = OpCodeFn::new::<OpSelfBalanceHandler>();
585 opcode_table[Opcode::CODESIZE as usize] = OpCodeFn::new::<OpCodeSizeHandler>();
586 opcode_table[Opcode::GASPRICE as usize] = OpCodeFn::new::<OpGasPriceHandler>();
587 opcode_table[Opcode::EXTCODESIZE as usize] = OpCodeFn::new::<OpExtCodeSizeHandler>();
588 opcode_table[Opcode::EXTCODECOPY as usize] = OpCodeFn::new::<OpExtCodeCopyHandler>();
589 opcode_table[Opcode::EXTCODEHASH as usize] = OpCodeFn::new::<OpExtCodeHashHandler>();
590 opcode_table[Opcode::REVERT as usize] = OpCodeFn::new::<OpRevertHandler>();
591 opcode_table[Opcode::INVALID as usize] = OpCodeFn::new::<OpInvalidHandler>();
592 opcode_table[Opcode::SELFDESTRUCT as usize] = OpCodeFn::new::<OpSelfDestructHandler>();
593
594 opcode_table[Opcode::LOG0 as usize] = OpCodeFn::new::<OpLogHandler<0>>();
595 opcode_table[Opcode::LOG1 as usize] = OpCodeFn::new::<OpLogHandler<1>>();
596 opcode_table[Opcode::LOG2 as usize] = OpCodeFn::new::<OpLogHandler<2>>();
597 opcode_table[Opcode::LOG3 as usize] = OpCodeFn::new::<OpLogHandler<3>>();
598 opcode_table[Opcode::LOG4 as usize] = OpCodeFn::new::<OpLogHandler<4>>();
599
600 opcode_table
601 }
602
603 #[allow(clippy::as_conversions, clippy::indexing_slicing)]
604 const fn build_opcode_table_pre_cancun() -> [OpCodeFn; 256] {
605 let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_pre_shanghai();
606
607 opcode_table[Opcode::PUSH0 as usize] = OpCodeFn::new::<OpPush0Handler>();
609
610 opcode_table
611 }
612
613 #[allow(clippy::as_conversions, clippy::indexing_slicing)]
614 const fn build_opcode_table_pre_osaka() -> [OpCodeFn; 256] {
615 const {
616 let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_pre_cancun();
617
618 opcode_table[Opcode::MCOPY as usize] = OpCodeFn::new::<OpMCopyHandler>();
620
621 opcode_table[Opcode::TLOAD as usize] = OpCodeFn::new::<OpTLoadHandler>();
623 opcode_table[Opcode::TSTORE as usize] = OpCodeFn::new::<OpTStoreHandler>();
624
625 opcode_table[Opcode::BLOBBASEFEE as usize] = OpCodeFn::new::<OpBlobBaseFeeHandler>();
627 opcode_table[Opcode::BLOBHASH as usize] = OpCodeFn::new::<OpBlobHashHandler>();
629
630 opcode_table
631 }
632 }
633
634 #[allow(clippy::as_conversions, clippy::indexing_slicing)]
635 const fn build_opcode_table_osaka() -> [OpCodeFn; 256] {
636 let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_pre_osaka();
637
638 opcode_table[Opcode::CLZ as usize] = OpCodeFn::new::<OpClzHandler>();
639
640 opcode_table
641 }
642
643 #[expect(clippy::as_conversions, clippy::indexing_slicing)]
644 const fn build_opcode_table_amsterdam() -> [OpCodeFn; 256] {
645 let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_osaka();
646
647 opcode_table[Opcode::DUPN as usize] = OpCodeFn::new::<OpDupNHandler>();
649 opcode_table[Opcode::SWAPN as usize] = OpCodeFn::new::<OpSwapNHandler>();
650 opcode_table[Opcode::EXCHANGE as usize] = OpCodeFn::new::<OpExchangeHandler>();
651 opcode_table[Opcode::SLOTNUM as usize] = OpCodeFn::new::<OpSlotNumHandler>();
653 opcode_table
654 }
655
656 #[expect(clippy::as_conversions, clippy::indexing_slicing)]
657 const fn build_opcode_table_hegota() -> [OpCodeFn; 256] {
658 let mut opcode_table: [OpCodeFn; 256] = Self::build_opcode_table_amsterdam();
659
660 opcode_table[Opcode::APPROVE as usize] = OpCodeFn::new::<OpApproveHandler>();
662 opcode_table[Opcode::TXPARAM as usize] = OpCodeFn::new::<OpTxParamHandler>();
663 opcode_table[Opcode::FRAMEDATALOAD as usize] = OpCodeFn::new::<OpFrameDataLoadHandler>();
664 opcode_table[Opcode::FRAMEDATACOPY as usize] = OpCodeFn::new::<OpFrameDataCopyHandler>();
665 opcode_table[Opcode::FRAMEPARAM as usize] = OpCodeFn::new::<OpFrameParamHandler>();
666 opcode_table[Opcode::SIGPARAM as usize] = OpCodeFn::new::<OpSigParamHandler>();
667
668 opcode_table
669 }
670}
671
672#[cfg(test)]
673mod tests {
674 use super::*;
675
676 #[test]
677 #[allow(
678 clippy::indexing_slicing,
679 reason = "fixed 256-entry table indexed by u8"
680 )]
681 fn frame_opcodes_not_installed_before_hegota() {
682 fn same_handler(a: OpCodeFn, b: OpCodeFn) -> bool {
683 std::ptr::fn_addr_eq(a.0, b.0)
686 }
687 for fork in [Fork::Osaka, Fork::Amsterdam] {
689 let table = VM::build_opcode_table(fork);
690 for byte in [0xAAusize, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4] {
691 assert!(
692 same_handler(table[byte], table[0xEF]),
693 "frame opcode {byte:#x} must be invalid at {fork:?}"
694 );
695 }
696 }
697 let hegota = VM::build_opcode_table(Fork::Hegota);
698 assert!(!same_handler(hegota[0xAA], hegota[0xEF]));
699 }
700}