Skip to main content

revm_interpreter/
instructions.rs

1//! EVM opcode implementations.
2
3#[macro_use]
4pub mod macros;
5/// Arithmetic operations (ADD, SUB, MUL, DIV, etc.).
6pub mod arithmetic;
7/// Bitwise operations (AND, OR, XOR, NOT, etc.).
8pub mod bitwise;
9/// Block information instructions (COINBASE, TIMESTAMP, etc.).
10pub mod block_info;
11/// Contract operations (CALL, CREATE, DELEGATECALL, etc.).
12pub mod contract;
13/// Control flow instructions (JUMP, JUMPI, REVERT, etc.).
14pub mod control;
15/// Host environment interactions (SLOAD, SSTORE, LOG, etc.).
16pub mod host;
17/// Signed 256-bit integer operations.
18pub mod i256;
19/// Memory operations (MLOAD, MSTORE, MSIZE, etc.).
20pub mod memory;
21/// Stack operations (PUSH, POP, DUP, SWAP, etc.).
22pub mod stack;
23/// System information instructions (ADDRESS, CALLER, etc.).
24pub mod system;
25/// Transaction information instructions (ORIGIN, GASPRICE, etc.).
26pub mod tx_info;
27/// Utility functions and helpers for instruction implementation.
28pub mod utility;
29
30pub use context_interface::cfg::gas::{self, *};
31
32use crate::{interpreter_types::InterpreterTypes, Host, InstructionContext, InstructionExecResult};
33use primitives::hardfork::SpecId;
34
35/// EVM opcode function pointer.
36#[derive(Debug)]
37pub struct Instruction<W: InterpreterTypes, H: ?Sized> {
38    fn_: fn(InstructionContext<'_, H, W>) -> InstructionExecResult,
39}
40
41impl<W: InterpreterTypes, H: Host + ?Sized> Instruction<W, H> {
42    /// Creates a new instruction with the given function.
43    #[inline]
44    pub const fn new(fn_: fn(InstructionContext<'_, H, W>) -> InstructionExecResult) -> Self {
45        Self { fn_ }
46    }
47
48    /// Creates an unknown/invalid instruction.
49    #[inline]
50    pub const fn unknown() -> Self {
51        Self {
52            fn_: control::unknown,
53        }
54    }
55
56    /// Executes the instruction with the given context.
57    #[inline(always)]
58    pub fn execute(self, ctx: InstructionContext<'_, H, W>) -> InstructionExecResult {
59        (self.fn_)(ctx)
60    }
61}
62
63impl<W: InterpreterTypes, H: Host + ?Sized> Copy for Instruction<W, H> {}
64impl<W: InterpreterTypes, H: Host + ?Sized> Clone for Instruction<W, H> {
65    fn clone(&self) -> Self {
66        *self
67    }
68}
69
70/// Instruction table is list of instruction function pointers mapped to 256 EVM opcodes.
71pub type InstructionTable<W, H> = [Instruction<W, H>; 256];
72
73/// Static gas cost table mapped to 256 EVM opcodes.
74pub type GasTable = [u16; 256];
75
76/// Returns the default instruction table for the given interpreter types and host.
77#[inline]
78pub const fn instruction_table<WIRE: InterpreterTypes, H: Host>() -> InstructionTable<WIRE, H> {
79    const { instruction_table_impl::<WIRE, H>() }
80}
81
82/// Returns the default gas table.
83#[inline]
84pub const fn gas_table() -> GasTable {
85    const { gas_table_impl() }
86}
87
88/// Create a gas table with applied spec changes to static gas cost.
89#[inline]
90pub const fn gas_table_spec(spec: SpecId) -> GasTable {
91    use bytecode::opcode::*;
92    use SpecId::*;
93    let mut table = gas_table();
94
95    if spec.is_enabled_in(TANGERINE) {
96        // EIP-150: Gas cost changes for IO-heavy operations
97        table[SLOAD as usize] = 200;
98        table[BALANCE as usize] = 400;
99        table[EXTCODESIZE as usize] = 700;
100        table[EXTCODECOPY as usize] = 700;
101        table[CALL as usize] = 700;
102        table[CALLCODE as usize] = 700;
103        table[DELEGATECALL as usize] = 700;
104        table[STATICCALL as usize] = 700;
105        table[SELFDESTRUCT as usize] = 5000;
106    }
107
108    if spec.is_enabled_in(ISTANBUL) {
109        // EIP-1884: Repricing for trie-size-dependent opcodes
110        table[SLOAD as usize] = gas::ISTANBUL_SLOAD_GAS as u16;
111        table[BALANCE as usize] = 700;
112        table[EXTCODEHASH as usize] = 700;
113    }
114
115    if spec.is_enabled_in(BERLIN) {
116        // warm account cost is base gas that is spend. Additional gas depends if account is cold loaded.
117        table[SLOAD as usize] = gas::WARM_STORAGE_READ_COST as u16;
118        table[BALANCE as usize] = gas::WARM_STORAGE_READ_COST as u16;
119        table[EXTCODESIZE as usize] = gas::WARM_STORAGE_READ_COST as u16;
120        table[EXTCODEHASH as usize] = gas::WARM_STORAGE_READ_COST as u16;
121        table[EXTCODECOPY as usize] = gas::WARM_STORAGE_READ_COST as u16;
122        table[CALL as usize] = gas::WARM_STORAGE_READ_COST as u16;
123        table[CALLCODE as usize] = gas::WARM_STORAGE_READ_COST as u16;
124        table[DELEGATECALL as usize] = gas::WARM_STORAGE_READ_COST as u16;
125        table[STATICCALL as usize] = gas::WARM_STORAGE_READ_COST as u16;
126    }
127
128    if spec.is_enabled_in(AMSTERDAM) {
129        // EIP-8038 §"EXT* family update": EXTCODESIZE and EXTCODECOPY perform two
130        // database reads (load the account object, then read its code), so their
131        // per-access base is charged an extra WARM_ACCESS on top of the normal
132        // account access. WARM_ACCESS itself is unchanged by EIP-8038 (100), so
133        // every other access opcode keeps its Berlin warm base; only these two
134        // change. The dynamic cold premium is still added by `load_account`.
135        let warm = primitives::eip8038::WARM_ACCESS as u16;
136        table[EXTCODESIZE as usize] = warm + warm;
137        table[EXTCODECOPY as usize] = warm + warm;
138    }
139
140    table
141}
142
143const fn instruction_table_impl<WIRE: InterpreterTypes, H: Host>() -> InstructionTable<WIRE, H> {
144    use bytecode::opcode::*;
145    let mut table = [Instruction::unknown(); 256];
146
147    table[STOP as usize] = Instruction::new(control::stop);
148    table[ADD as usize] = Instruction::new(arithmetic::add);
149    table[MUL as usize] = Instruction::new(arithmetic::mul);
150    table[SUB as usize] = Instruction::new(arithmetic::sub);
151    table[DIV as usize] = Instruction::new(arithmetic::div);
152    table[SDIV as usize] = Instruction::new(arithmetic::sdiv);
153    table[MOD as usize] = Instruction::new(arithmetic::rem);
154    table[SMOD as usize] = Instruction::new(arithmetic::smod);
155    table[ADDMOD as usize] = Instruction::new(arithmetic::addmod);
156    table[MULMOD as usize] = Instruction::new(arithmetic::mulmod);
157    table[EXP as usize] = Instruction::new(arithmetic::exp);
158    table[SIGNEXTEND as usize] = Instruction::new(arithmetic::signextend);
159
160    table[LT as usize] = Instruction::new(bitwise::lt);
161    table[GT as usize] = Instruction::new(bitwise::gt);
162    table[SLT as usize] = Instruction::new(bitwise::slt);
163    table[SGT as usize] = Instruction::new(bitwise::sgt);
164    table[EQ as usize] = Instruction::new(bitwise::eq);
165    table[ISZERO as usize] = Instruction::new(bitwise::iszero);
166    table[AND as usize] = Instruction::new(bitwise::bitand);
167    table[OR as usize] = Instruction::new(bitwise::bitor);
168    table[XOR as usize] = Instruction::new(bitwise::bitxor);
169    table[NOT as usize] = Instruction::new(bitwise::not);
170    table[BYTE as usize] = Instruction::new(bitwise::byte);
171    table[SHL as usize] = Instruction::new(bitwise::shl);
172    table[SHR as usize] = Instruction::new(bitwise::shr);
173    table[SAR as usize] = Instruction::new(bitwise::sar);
174    table[CLZ as usize] = Instruction::new(bitwise::clz);
175
176    table[KECCAK256 as usize] = Instruction::new(system::keccak256);
177
178    table[ADDRESS as usize] = Instruction::new(system::address);
179    table[BALANCE as usize] = Instruction::new(host::balance);
180    table[ORIGIN as usize] = Instruction::new(tx_info::origin);
181    table[CALLER as usize] = Instruction::new(system::caller);
182    table[CALLVALUE as usize] = Instruction::new(system::callvalue);
183    table[CALLDATALOAD as usize] = Instruction::new(system::calldataload);
184    table[CALLDATASIZE as usize] = Instruction::new(system::calldatasize);
185    table[CALLDATACOPY as usize] = Instruction::new(system::calldatacopy);
186    table[CODESIZE as usize] = Instruction::new(system::codesize);
187    table[CODECOPY as usize] = Instruction::new(system::codecopy);
188
189    table[GASPRICE as usize] = Instruction::new(tx_info::gasprice);
190    table[EXTCODESIZE as usize] = Instruction::new(host::extcodesize);
191    table[EXTCODECOPY as usize] = Instruction::new(host::extcodecopy);
192    table[RETURNDATASIZE as usize] = Instruction::new(system::returndatasize);
193    table[RETURNDATACOPY as usize] = Instruction::new(system::returndatacopy);
194    table[EXTCODEHASH as usize] = Instruction::new(host::extcodehash);
195    table[BLOCKHASH as usize] = Instruction::new(host::blockhash);
196    table[COINBASE as usize] = Instruction::new(block_info::coinbase);
197    table[TIMESTAMP as usize] = Instruction::new(block_info::timestamp);
198    table[NUMBER as usize] = Instruction::new(block_info::block_number);
199    table[DIFFICULTY as usize] = Instruction::new(block_info::difficulty);
200    table[GASLIMIT as usize] = Instruction::new(block_info::gaslimit);
201    table[CHAINID as usize] = Instruction::new(block_info::chainid);
202    table[SELFBALANCE as usize] = Instruction::new(host::selfbalance);
203    table[BASEFEE as usize] = Instruction::new(block_info::basefee);
204    table[BLOBHASH as usize] = Instruction::new(tx_info::blob_hash);
205    table[BLOBBASEFEE as usize] = Instruction::new(block_info::blob_basefee);
206    table[SLOTNUM as usize] = Instruction::new(block_info::slot_num);
207
208    table[POP as usize] = Instruction::new(stack::pop);
209    table[MLOAD as usize] = Instruction::new(memory::mload);
210    table[MSTORE as usize] = Instruction::new(memory::mstore);
211    table[MSTORE8 as usize] = Instruction::new(memory::mstore8);
212    table[SLOAD as usize] = Instruction::new(host::sload);
213    table[SSTORE as usize] = Instruction::new(host::sstore);
214    table[JUMP as usize] = Instruction::new(control::jump);
215    table[JUMPI as usize] = Instruction::new(control::jumpi);
216    table[PC as usize] = Instruction::new(control::pc);
217    table[MSIZE as usize] = Instruction::new(memory::msize);
218    table[GAS as usize] = Instruction::new(system::gas);
219    table[JUMPDEST as usize] = Instruction::new(control::jumpdest);
220    table[TLOAD as usize] = Instruction::new(host::tload);
221    table[TSTORE as usize] = Instruction::new(host::tstore);
222    table[MCOPY as usize] = Instruction::new(memory::mcopy);
223
224    table[PUSH0 as usize] = Instruction::new(stack::push0);
225    table[PUSH1 as usize] = Instruction::new(stack::push::<1, _, _>);
226    table[PUSH2 as usize] = Instruction::new(stack::push::<2, _, _>);
227    table[PUSH3 as usize] = Instruction::new(stack::push::<3, _, _>);
228    table[PUSH4 as usize] = Instruction::new(stack::push::<4, _, _>);
229    table[PUSH5 as usize] = Instruction::new(stack::push::<5, _, _>);
230    table[PUSH6 as usize] = Instruction::new(stack::push::<6, _, _>);
231    table[PUSH7 as usize] = Instruction::new(stack::push::<7, _, _>);
232    table[PUSH8 as usize] = Instruction::new(stack::push::<8, _, _>);
233    table[PUSH9 as usize] = Instruction::new(stack::push::<9, _, _>);
234    table[PUSH10 as usize] = Instruction::new(stack::push::<10, _, _>);
235    table[PUSH11 as usize] = Instruction::new(stack::push::<11, _, _>);
236    table[PUSH12 as usize] = Instruction::new(stack::push::<12, _, _>);
237    table[PUSH13 as usize] = Instruction::new(stack::push::<13, _, _>);
238    table[PUSH14 as usize] = Instruction::new(stack::push::<14, _, _>);
239    table[PUSH15 as usize] = Instruction::new(stack::push::<15, _, _>);
240    table[PUSH16 as usize] = Instruction::new(stack::push::<16, _, _>);
241    table[PUSH17 as usize] = Instruction::new(stack::push::<17, _, _>);
242    table[PUSH18 as usize] = Instruction::new(stack::push::<18, _, _>);
243    table[PUSH19 as usize] = Instruction::new(stack::push::<19, _, _>);
244    table[PUSH20 as usize] = Instruction::new(stack::push::<20, _, _>);
245    table[PUSH21 as usize] = Instruction::new(stack::push::<21, _, _>);
246    table[PUSH22 as usize] = Instruction::new(stack::push::<22, _, _>);
247    table[PUSH23 as usize] = Instruction::new(stack::push::<23, _, _>);
248    table[PUSH24 as usize] = Instruction::new(stack::push::<24, _, _>);
249    table[PUSH25 as usize] = Instruction::new(stack::push::<25, _, _>);
250    table[PUSH26 as usize] = Instruction::new(stack::push::<26, _, _>);
251    table[PUSH27 as usize] = Instruction::new(stack::push::<27, _, _>);
252    table[PUSH28 as usize] = Instruction::new(stack::push::<28, _, _>);
253    table[PUSH29 as usize] = Instruction::new(stack::push::<29, _, _>);
254    table[PUSH30 as usize] = Instruction::new(stack::push::<30, _, _>);
255    table[PUSH31 as usize] = Instruction::new(stack::push::<31, _, _>);
256    table[PUSH32 as usize] = Instruction::new(stack::push::<32, _, _>);
257
258    table[DUP1 as usize] = Instruction::new(stack::dup::<1, _, _>);
259    table[DUP2 as usize] = Instruction::new(stack::dup::<2, _, _>);
260    table[DUP3 as usize] = Instruction::new(stack::dup::<3, _, _>);
261    table[DUP4 as usize] = Instruction::new(stack::dup::<4, _, _>);
262    table[DUP5 as usize] = Instruction::new(stack::dup::<5, _, _>);
263    table[DUP6 as usize] = Instruction::new(stack::dup::<6, _, _>);
264    table[DUP7 as usize] = Instruction::new(stack::dup::<7, _, _>);
265    table[DUP8 as usize] = Instruction::new(stack::dup::<8, _, _>);
266    table[DUP9 as usize] = Instruction::new(stack::dup::<9, _, _>);
267    table[DUP10 as usize] = Instruction::new(stack::dup::<10, _, _>);
268    table[DUP11 as usize] = Instruction::new(stack::dup::<11, _, _>);
269    table[DUP12 as usize] = Instruction::new(stack::dup::<12, _, _>);
270    table[DUP13 as usize] = Instruction::new(stack::dup::<13, _, _>);
271    table[DUP14 as usize] = Instruction::new(stack::dup::<14, _, _>);
272    table[DUP15 as usize] = Instruction::new(stack::dup::<15, _, _>);
273    table[DUP16 as usize] = Instruction::new(stack::dup::<16, _, _>);
274
275    table[SWAP1 as usize] = Instruction::new(stack::swap::<1, _, _>);
276    table[SWAP2 as usize] = Instruction::new(stack::swap::<2, _, _>);
277    table[SWAP3 as usize] = Instruction::new(stack::swap::<3, _, _>);
278    table[SWAP4 as usize] = Instruction::new(stack::swap::<4, _, _>);
279    table[SWAP5 as usize] = Instruction::new(stack::swap::<5, _, _>);
280    table[SWAP6 as usize] = Instruction::new(stack::swap::<6, _, _>);
281    table[SWAP7 as usize] = Instruction::new(stack::swap::<7, _, _>);
282    table[SWAP8 as usize] = Instruction::new(stack::swap::<8, _, _>);
283    table[SWAP9 as usize] = Instruction::new(stack::swap::<9, _, _>);
284    table[SWAP10 as usize] = Instruction::new(stack::swap::<10, _, _>);
285    table[SWAP11 as usize] = Instruction::new(stack::swap::<11, _, _>);
286    table[SWAP12 as usize] = Instruction::new(stack::swap::<12, _, _>);
287    table[SWAP13 as usize] = Instruction::new(stack::swap::<13, _, _>);
288    table[SWAP14 as usize] = Instruction::new(stack::swap::<14, _, _>);
289    table[SWAP15 as usize] = Instruction::new(stack::swap::<15, _, _>);
290    table[SWAP16 as usize] = Instruction::new(stack::swap::<16, _, _>);
291
292    table[DUPN as usize] = Instruction::new(stack::dupn);
293    table[SWAPN as usize] = Instruction::new(stack::swapn);
294    table[EXCHANGE as usize] = Instruction::new(stack::exchange);
295
296    table[LOG0 as usize] = Instruction::new(host::log::<0, _>);
297    table[LOG1 as usize] = Instruction::new(host::log::<1, _>);
298    table[LOG2 as usize] = Instruction::new(host::log::<2, _>);
299    table[LOG3 as usize] = Instruction::new(host::log::<3, _>);
300    table[LOG4 as usize] = Instruction::new(host::log::<4, _>);
301
302    table[CREATE as usize] = Instruction::new(contract::create::<false, _, _>);
303    table[CALL as usize] = Instruction::new(contract::call::<CALL, _, _>);
304    table[CALLCODE as usize] = Instruction::new(contract::call::<CALLCODE, _, _>);
305    table[RETURN as usize] = Instruction::new(control::ret);
306    table[DELEGATECALL as usize] = Instruction::new(contract::call::<DELEGATECALL, _, _>);
307    table[CREATE2 as usize] = Instruction::new(contract::create::<true, _, _>);
308
309    table[STATICCALL as usize] = Instruction::new(contract::call::<STATICCALL, _, _>);
310    table[REVERT as usize] = Instruction::new(control::revert);
311    table[INVALID as usize] = Instruction::new(control::invalid);
312    table[SELFDESTRUCT as usize] = Instruction::new(host::selfdestruct);
313    table
314}
315
316const fn gas_table_impl() -> GasTable {
317    use bytecode::opcode::*;
318    let mut table = [0u16; 256];
319
320    table[STOP as usize] = 0;
321    table[ADD as usize] = 3;
322    table[MUL as usize] = 5;
323    table[SUB as usize] = 3;
324    table[DIV as usize] = 5;
325    table[SDIV as usize] = 5;
326    table[MOD as usize] = 5;
327    table[SMOD as usize] = 5;
328    table[ADDMOD as usize] = 8;
329    table[MULMOD as usize] = 8;
330    table[EXP as usize] = gas::EXP as u16; // base
331    table[SIGNEXTEND as usize] = 5;
332
333    table[LT as usize] = 3;
334    table[GT as usize] = 3;
335    table[SLT as usize] = 3;
336    table[SGT as usize] = 3;
337    table[EQ as usize] = 3;
338    table[ISZERO as usize] = 3;
339    table[AND as usize] = 3;
340    table[OR as usize] = 3;
341    table[XOR as usize] = 3;
342    table[NOT as usize] = 3;
343    table[BYTE as usize] = 3;
344    table[SHL as usize] = 3;
345    table[SHR as usize] = 3;
346    table[SAR as usize] = 3;
347    table[CLZ as usize] = 5;
348
349    table[KECCAK256 as usize] = gas::KECCAK256 as u16;
350
351    table[ADDRESS as usize] = 2;
352    table[BALANCE as usize] = 20;
353    table[ORIGIN as usize] = 2;
354    table[CALLER as usize] = 2;
355    table[CALLVALUE as usize] = 2;
356    table[CALLDATALOAD as usize] = 3;
357    table[CALLDATASIZE as usize] = 2;
358    table[CALLDATACOPY as usize] = 3;
359    table[CODESIZE as usize] = 2;
360    table[CODECOPY as usize] = 3;
361
362    table[GASPRICE as usize] = 2;
363    table[EXTCODESIZE as usize] = 20;
364    table[EXTCODECOPY as usize] = 20;
365    table[RETURNDATASIZE as usize] = 2;
366    table[RETURNDATACOPY as usize] = 3;
367    table[EXTCODEHASH as usize] = 400;
368    table[BLOCKHASH as usize] = 20;
369    table[COINBASE as usize] = 2;
370    table[TIMESTAMP as usize] = 2;
371    table[NUMBER as usize] = 2;
372    table[DIFFICULTY as usize] = 2;
373    table[GASLIMIT as usize] = 2;
374    table[CHAINID as usize] = 2;
375    table[SELFBALANCE as usize] = 5;
376    table[BASEFEE as usize] = 2;
377    table[BLOBHASH as usize] = 3;
378    table[BLOBBASEFEE as usize] = 2;
379    table[SLOTNUM as usize] = 2;
380
381    table[POP as usize] = 2;
382    table[MLOAD as usize] = 3;
383    table[MSTORE as usize] = 3;
384    table[MSTORE8 as usize] = 3;
385    table[SLOAD as usize] = 50;
386    // SSTORE static gas can be found in GasParams as check for minimal stipend
387    // needs to be done before deduction of static gas.
388    table[SSTORE as usize] = 0;
389    table[JUMP as usize] = 8;
390    table[JUMPI as usize] = 10;
391    table[PC as usize] = 2;
392    table[MSIZE as usize] = 2;
393    table[GAS as usize] = 2;
394    table[JUMPDEST as usize] = 1;
395    table[TLOAD as usize] = 100;
396    table[TSTORE as usize] = 100;
397    table[MCOPY as usize] = 3; // static 2, mostly dynamic
398
399    table[PUSH0 as usize] = 2;
400    table[PUSH1 as usize] = 3;
401    table[PUSH2 as usize] = 3;
402    table[PUSH3 as usize] = 3;
403    table[PUSH4 as usize] = 3;
404    table[PUSH5 as usize] = 3;
405    table[PUSH6 as usize] = 3;
406    table[PUSH7 as usize] = 3;
407    table[PUSH8 as usize] = 3;
408    table[PUSH9 as usize] = 3;
409    table[PUSH10 as usize] = 3;
410    table[PUSH11 as usize] = 3;
411    table[PUSH12 as usize] = 3;
412    table[PUSH13 as usize] = 3;
413    table[PUSH14 as usize] = 3;
414    table[PUSH15 as usize] = 3;
415    table[PUSH16 as usize] = 3;
416    table[PUSH17 as usize] = 3;
417    table[PUSH18 as usize] = 3;
418    table[PUSH19 as usize] = 3;
419    table[PUSH20 as usize] = 3;
420    table[PUSH21 as usize] = 3;
421    table[PUSH22 as usize] = 3;
422    table[PUSH23 as usize] = 3;
423    table[PUSH24 as usize] = 3;
424    table[PUSH25 as usize] = 3;
425    table[PUSH26 as usize] = 3;
426    table[PUSH27 as usize] = 3;
427    table[PUSH28 as usize] = 3;
428    table[PUSH29 as usize] = 3;
429    table[PUSH30 as usize] = 3;
430    table[PUSH31 as usize] = 3;
431    table[PUSH32 as usize] = 3;
432
433    table[DUP1 as usize] = 3;
434    table[DUP2 as usize] = 3;
435    table[DUP3 as usize] = 3;
436    table[DUP4 as usize] = 3;
437    table[DUP5 as usize] = 3;
438    table[DUP6 as usize] = 3;
439    table[DUP7 as usize] = 3;
440    table[DUP8 as usize] = 3;
441    table[DUP9 as usize] = 3;
442    table[DUP10 as usize] = 3;
443    table[DUP11 as usize] = 3;
444    table[DUP12 as usize] = 3;
445    table[DUP13 as usize] = 3;
446    table[DUP14 as usize] = 3;
447    table[DUP15 as usize] = 3;
448    table[DUP16 as usize] = 3;
449
450    table[SWAP1 as usize] = 3;
451    table[SWAP2 as usize] = 3;
452    table[SWAP3 as usize] = 3;
453    table[SWAP4 as usize] = 3;
454    table[SWAP5 as usize] = 3;
455    table[SWAP6 as usize] = 3;
456    table[SWAP7 as usize] = 3;
457    table[SWAP8 as usize] = 3;
458    table[SWAP9 as usize] = 3;
459    table[SWAP10 as usize] = 3;
460    table[SWAP11 as usize] = 3;
461    table[SWAP12 as usize] = 3;
462    table[SWAP13 as usize] = 3;
463    table[SWAP14 as usize] = 3;
464    table[SWAP15 as usize] = 3;
465    table[SWAP16 as usize] = 3;
466
467    table[DUPN as usize] = 3;
468    table[SWAPN as usize] = 3;
469    table[EXCHANGE as usize] = 3;
470
471    table[LOG0 as usize] = gas::LOG as u16;
472    table[LOG1 as usize] = gas::LOG as u16;
473    table[LOG2 as usize] = gas::LOG as u16;
474    table[LOG3 as usize] = gas::LOG as u16;
475    table[LOG4 as usize] = gas::LOG as u16;
476
477    table[CREATE as usize] = 0;
478    table[CALL as usize] = 40;
479    table[CALLCODE as usize] = 40;
480    table[RETURN as usize] = 0;
481    table[DELEGATECALL as usize] = 40;
482    table[CREATE2 as usize] = 0;
483
484    table[STATICCALL as usize] = 40;
485    table[REVERT as usize] = 0;
486    table[INVALID as usize] = 0;
487    table[SELFDESTRUCT as usize] = 0;
488    table
489}
490
491#[cfg(test)]
492mod tests {
493    use super::instruction_table;
494    use crate::{host::DummyHost, interpreter::EthInterpreter};
495    use bytecode::opcode::*;
496
497    #[test]
498    fn all_instructions_and_opcodes_used() {
499        // known unknown instruction we compare it with other instructions from table.
500        let unknown_instruction = 0x0C_usize;
501        let instr_table = instruction_table::<EthInterpreter, DummyHost>();
502
503        let unknown_istr = instr_table[unknown_instruction];
504        for (i, instr) in instr_table.iter().enumerate() {
505            let is_opcode_unknown = OpCode::new(i as u8).is_none();
506            //
507            let is_instr_unknown = std::ptr::fn_addr_eq(instr.fn_, unknown_istr.fn_);
508            assert_eq!(
509                is_instr_unknown, is_opcode_unknown,
510                "Opcode 0x{i:X?} is not handled",
511            );
512        }
513    }
514
515    #[test]
516    fn amsterdam_eip8038_ext_family_second_read() {
517        use super::gas_table_spec;
518        use primitives::hardfork::SpecId;
519
520        let warm = primitives::eip8038::WARM_ACCESS as u16;
521        let table = gas_table_spec(SpecId::AMSTERDAM);
522        // EIP-8038 §"EXT* family update": EXTCODESIZE / EXTCODECOPY make a second
523        // database read, charged an extra WARM_ACCESS on the static base.
524        assert_eq!(table[EXTCODESIZE as usize], warm + warm);
525        assert_eq!(table[EXTCODECOPY as usize], warm + warm);
526        // Other account-access opcodes keep a single WARM_ACCESS base.
527        assert_eq!(table[EXTCODEHASH as usize], warm);
528        assert_eq!(table[BALANCE as usize], warm);
529        assert_eq!(table[SLOAD as usize], warm);
530        // The surcharge is Amsterdam-only: pre-Amsterdam EXTCODESIZE == EXTCODEHASH.
531        let prague = gas_table_spec(SpecId::PRAGUE);
532        assert_eq!(prague[EXTCODESIZE as usize], prague[EXTCODEHASH as usize]);
533    }
534}