Skip to main content

revmc_codegen/tests/
mod.rs

1#![allow(
2    clippy::needless_update,
3    unreachable_pub,
4    dead_code,
5    missing_docs,
6    missing_debug_implementations
7)]
8
9use crate::*;
10use revm_bytecode::opcode as op;
11use revm_context_interface as context_interface;
12use revm_interpreter as interpreter;
13use revm_interpreter::{
14    CreateInputs, FrameInput, Gas, InstructionResult, InterpreterAction, InterpreterResult,
15};
16use revm_primitives::{
17    Address, B256, Bytes, KECCAK_EMPTY, Log, LogData, hardfork::SpecId, hex, keccak256,
18};
19use revmc_builtins::gas;
20
21/// `KECCAK256` opcode gas cost (base + dynamic).
22const fn keccak256_cost(len: u64) -> Option<u64> {
23    let words = len.div_ceil(32);
24    match words.checked_mul(gas::KECCAK256WORD) {
25        Some(dyn_cost) => Some(gas::KECCAK256.saturating_add(dyn_cost)),
26        None => None,
27    }
28}
29
30/// `LOG` opcode gas cost (base + topics + dynamic).
31const fn log_cost(n_topics: u8, len: u64) -> Option<u64> {
32    match gas::LOGDATA.checked_mul(len) {
33        Some(dyn_cost) => {
34            Some((gas::LOG + gas::LOGTOPIC * n_topics as u64).saturating_add(dyn_cost))
35        }
36        None => None,
37    }
38}
39
40/// `CALLDATACOPY`, `CODECOPY`, `RETURNDATACOPY` opcode gas cost (base + dynamic).
41const fn verylowcopy_cost(len: u64) -> Option<u64> {
42    let words = len.div_ceil(32);
43    match words.checked_mul(gas::COPY) {
44        Some(dyn_cost) => Some(gas::VERYLOW.saturating_add(dyn_cost)),
45        None => None,
46    }
47}
48
49#[macro_use]
50mod macros;
51
52mod meta;
53
54mod fibonacci;
55mod resume;
56mod resume_at_call;
57
58mod runner;
59pub use runner::*;
60
61#[cfg(feature = "llvm")]
62pub fn with_jit_compiler<R>(
63    opt_level: revmc_backend::OptimizationLevel,
64    f: fn(&mut EvmCompiler<revmc_llvm::EvmLlvmBackend>) -> R,
65) -> R {
66    init_tracing();
67    let mut compiler = EvmCompiler::new_llvm(false).unwrap();
68    compiler.set_opt_level(opt_level);
69    compiler.set_profiling_support(false);
70    compiler.set_simple_perf(false);
71    compiler.single_error(false);
72    f(&mut compiler)
73}
74
75const I256_MIN: U256 = U256::from_limbs([
76    0x0000000000000000,
77    0x0000000000000000,
78    0x0000000000000000,
79    0x8000000000000000,
80]);
81
82const I256_MAX: U256 = U256::from_limbs([
83    0xFFFFFFFFFFFFFFFF,
84    0xFFFFFFFFFFFFFFFF,
85    0xFFFFFFFFFFFFFFFF,
86    0x7FFFFFFFFFFFFFFF,
87]);
88
89tests! {
90    ret {
91        empty(@raw {}),
92        no_stop(@raw {
93            bytecode: &[op::PUSH0],
94            expected_stack: &[U256::ZERO],
95            expected_gas: 2,
96        }),
97        stop(@raw {
98            bytecode: &[op::STOP],
99            expected_gas: 0,
100        }),
101        invalid(@raw {
102            bytecode: &[op::INVALID],
103            expected_return: InstructionResult::InvalidFEOpcode,
104            expected_gas: 0,
105        }),
106        unknown(@raw {
107            bytecode: &[0x21],
108            expected_return: InstructionResult::OpcodeNotFound,
109            expected_gas: 0,
110        }),
111        underflow1(@raw {
112            bytecode: &[op::ADD],
113            expected_return: InstructionResult::StackUnderflow,
114            expected_gas: 3,
115        }),
116        underflow2(@raw {
117            bytecode: &[op::PUSH0, op::ADD],
118            expected_return: InstructionResult::StackUnderflow,
119            expected_stack: &[U256::ZERO],
120            expected_gas: 5,
121        }),
122        underflow3(@raw {
123            bytecode: &[op::PUSH0, op::POP, op::ADD],
124            expected_return: InstructionResult::StackUnderflow,
125            expected_gas: 7,
126        }),
127        underflow4(@raw {
128            bytecode: &[op::PUSH0, op::ADD, op::POP],
129            expected_return: InstructionResult::StackUnderflow,
130            expected_stack: &[U256::ZERO],
131            expected_gas: 5,
132        }),
133        overflow_not0(@raw {
134            bytecode: &[op::PUSH0; 1023],
135            expected_return: InstructionResult::Stop,
136            expected_stack: &[0_U256; 1023],
137            expected_gas: 2 * 1023,
138        }),
139        overflow_not1(@raw {
140            bytecode: &[op::PUSH0; 1024],
141            expected_return: InstructionResult::Stop,
142            expected_stack: &[0_U256; 1024],
143            expected_gas: 2 * 1024,
144        }),
145        overflow0(@raw {
146            bytecode: &[op::PUSH0; 1025],
147            expected_return: InstructionResult::StackOverflow,
148            expected_stack: &[0_U256; 1024],
149            expected_gas: 2 * 1025,
150        }),
151        overflow1(@raw {
152            bytecode: &[op::PUSH0; 1026],
153            expected_return: InstructionResult::StackOverflow,
154            expected_stack: &[0_U256; 1024],
155            expected_gas: 2 * 1025,
156        }),
157    }
158
159    spec_id {
160        push0_merge(@raw {
161            bytecode: &[op::PUSH0],
162            spec_id: SpecId::MERGE,
163            expected_return: InstructionResult::NotActivated,
164            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
165        }),
166        push0_shanghai(@raw {
167            bytecode: &[op::PUSH0],
168            spec_id: SpecId::SHANGHAI,
169            expected_stack: &[U256::ZERO],
170            expected_gas: 2,
171        }),
172        push0_cancun(@raw {
173            bytecode: &[op::PUSH0],
174            spec_id: SpecId::CANCUN,
175            expected_stack: &[U256::ZERO],
176            expected_gas: 2,
177        }),
178        clz_cancun(@raw {
179            bytecode: &[op::MSIZE, op::CLZ],
180            spec_id: SpecId::CANCUN,
181            expected_return: InstructionResult::NotActivated,
182            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
183            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
184        }),
185        clz_arrow_glacier(@raw {
186            bytecode: &[op::MSIZE, op::CLZ],
187            spec_id: SpecId::LONDON,
188            expected_return: InstructionResult::NotActivated,
189            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
190            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
191        }),
192
193        dupn_cancun(@raw {
194            bytecode: &[op::PUSH0, op::DUPN, 0x00],
195            spec_id: SpecId::CANCUN,
196            expected_return: InstructionResult::NotActivated,
197            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
198            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
199        }),
200        swapn_cancun(@raw {
201            bytecode: &[op::PUSH0, op::SWAPN, 0x00],
202            spec_id: SpecId::CANCUN,
203            expected_return: InstructionResult::NotActivated,
204            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
205            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
206        }),
207        exchange_cancun(@raw {
208            bytecode: &[op::PUSH0, op::EXCHANGE, 0x01],
209            spec_id: SpecId::CANCUN,
210            expected_return: InstructionResult::NotActivated,
211            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
212            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
213        }),
214        slotnum_cancun(@raw {
215            bytecode: &[op::SLOTNUM],
216            spec_id: SpecId::CANCUN,
217            expected_return: InstructionResult::NotActivated,
218            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
219            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
220        }),
221
222        // EXP gas: pre-SPURIOUS_DRAGON exp_byte_gas=10, post=50.
223        // power=0 → dynamic=0 for all specs.
224        exp_zero_frontier(@raw {
225            bytecode: &bytecode_binop(op::EXP, 2_U256, 0_U256),
226            spec_id: SpecId::FRONTIER,
227            expected_stack: &[1_U256],
228            expected_gas: 6 + 10,
229        }),
230        // power=1 → 1 byte, dynamic=10*1=10 pre-spurious, total=20.
231        exp_one_frontier(@raw {
232            bytecode: &bytecode_binop(op::EXP, 2_U256, 1_U256),
233            spec_id: SpecId::FRONTIER,
234            expected_stack: &[2_U256],
235            expected_gas: 6 + 10 + 10,
236        }),
237        // power=256 → log2floor=8, bytes=2, dynamic=10*2=20 pre-spurious, total=30.
238        exp_multi_byte_frontier(@raw {
239            bytecode: &bytecode_binop(op::EXP, 2_U256, 256_U256),
240            spec_id: SpecId::FRONTIER,
241            expected_stack: &[0_U256],
242            expected_gas: 6 + 10 + 20,
243        }),
244        // Same with ISTANBUL (post-spurious, exp_byte_gas=50).
245        exp_zero_istanbul(@raw {
246            bytecode: &bytecode_binop(op::EXP, 2_U256, 0_U256),
247            spec_id: SpecId::ISTANBUL,
248            expected_stack: &[1_U256],
249            expected_gas: 6 + 10,
250        }),
251        exp_one_istanbul(@raw {
252            bytecode: &bytecode_binop(op::EXP, 2_U256, 1_U256),
253            spec_id: SpecId::ISTANBUL,
254            expected_stack: &[2_U256],
255            expected_gas: 6 + 10 + 50,
256        }),
257        exp_multi_byte_istanbul(@raw {
258            bytecode: &bytecode_binop(op::EXP, 2_U256, 256_U256),
259            spec_id: SpecId::ISTANBUL,
260            expected_stack: &[0_U256],
261            expected_gas: 6 + 10 + 100,
262        }),
263    }
264
265    stack {
266        pop(@raw {
267            bytecode: &[op::PUSH1, 1, op::POP],
268            expected_gas: 3 + 2,
269        }),
270        dup(@raw {
271            bytecode: &[op::PUSH1, 1, op::DUP1],
272            expected_stack: &[1_U256, 1_U256],
273            expected_gas: 3 + 3,
274        }),
275
276        swap(@raw {
277            bytecode: &[op::PUSH1, 1, op::PUSH1, 2, op::SWAP1],
278            expected_stack: &[2_U256, 1_U256],
279            expected_gas: 3 + 3 + 3,
280        }),
281        swap2(@raw {
282            bytecode: &[op::PUSH1, 1, op::PUSH1, 2, op::PUSH1, 3, op::SWAP2],
283            expected_stack: &[3_U256, 2_U256, 1_U256],
284            expected_gas: 3 + 3 + 3 + 3,
285        }),
286        swap3(@raw {
287            bytecode: &[op::PUSH1, 1, op::PUSH1, 2, op::PUSH1, 3, op::PUSH1, 4, op::SWAP3],
288            expected_stack: &[4_U256, 2_U256, 3_U256, 1_U256],
289            expected_gas: 3 + 3 + 3 + 3 + 3,
290        }),
291
292        // DUPN 0x80: decode_single(0x80) = 17, duplicates 17th stack item.
293        dupn(@raw {
294            bytecode: &{
295                let mut code = [0u8; 21];
296                code[0] = op::PUSH1; code[1] = 1;   // bottom = 1
297                // 16 zeros on top
298                let mut i = 2;
299                while i < 18 {
300                    code[i] = op::PUSH0;
301                    i += 1;
302                }
303                code[18] = op::DUPN;
304                code[19] = 0x80; // n=17
305                code
306            },
307            spec_id: SpecId::AMSTERDAM,
308            expected_stack: &{
309                let mut s = [U256::ZERO; 18];
310                s[0] = 1_U256;  // duplicated from bottom
311                // s[1..17] = ZERO (the 16 pushed zeros)
312                s[17] = 1_U256; // original bottom
313                s
314            },
315            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
316        }),
317
318        // SWAPN 0x80: decode_single(0x80) = 17, swaps top with 17th item.
319        swapn(@raw {
320            bytecode: &{
321                let mut code = [0u8; 23];
322                code[0] = op::PUSH1; code[1] = 1;   // bottom = 1
323                // 16 zeros on top
324                let mut i = 2;
325                while i < 18 {
326                    code[i] = op::PUSH0;
327                    i += 1;
328                }
329                code[18] = op::PUSH1; code[19] = 2; // top = 2
330                code[20] = op::SWAPN;
331                code[21] = 0x80; // n=17
332                code
333            },
334            spec_id: SpecId::AMSTERDAM,
335            expected_stack: &{
336                let mut s = [U256::ZERO; 18];
337                s[0] = 2_U256;  // swapped from top
338                // s[1..17] = ZERO
339                s[17] = 1_U256; // swapped from bottom
340                s
341            },
342            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
343        }),
344
345        // EXCHANGE 0x8E: decode_pair(0x8E) = (1, 2), swaps 2nd and 3rd from top.
346        exchange_basic(@raw {
347            bytecode: &[op::PUSH1, 1, op::PUSH1, 2, op::PUSH1, 3, op::EXCHANGE, 0x8E],
348            spec_id: SpecId::AMSTERDAM,
349            // stack before: [1, 2, 3] (3 on top)
350            // exchange(1, 2): swaps items at depth 1 and 2 (0-indexed from top)
351            // → swaps 2 and 1 → [2, 1, 3]
352            expected_stack: &[2_U256, 1_U256, 3_U256],
353            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
354        }),
355
356        // SLOTNUM: pushes the slot number from the host.
357        slotnum(@raw {
358            bytecode: &[op::SLOTNUM],
359            spec_id: SpecId::AMSTERDAM,
360            expected_stack: &[U256::ZERO],
361            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
362        }),
363
364        // Insufficient stack depth: DUPN 0x80 decodes to depth 17, but only 1 item on stack.
365        dupn_underflow(@raw {
366            bytecode: &[op::PUSH0, op::DUPN, 0x80],
367            spec_id: SpecId::AMSTERDAM,
368            expected_return: InstructionResult::StackOverflow,
369            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
370            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
371        }),
372        // Insufficient stack depth: SWAPN 0x80 decodes to depth 17, but only 1 item on stack.
373        swapn_underflow(@raw {
374            bytecode: &[op::PUSH0, op::SWAPN, 0x80],
375            spec_id: SpecId::AMSTERDAM,
376            expected_return: InstructionResult::StackUnderflow,
377            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
378            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
379        }),
380        // Insufficient stack depth: EXCHANGE 0x8E decodes to (1,2), but only 2 items on stack.
381        exchange_underflow(@raw {
382            bytecode: &[op::PUSH0, op::PUSH0, op::EXCHANGE, 0x8E],
383            spec_id: SpecId::AMSTERDAM,
384            expected_return: InstructionResult::StackUnderflow,
385            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
386            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
387        }),
388        swap16_dup10_selfdestruct_underflow(@raw {
389            bytecode: &[op::SWAP16, op::DUP10, op::SELFDESTRUCT],
390            spec_id: SpecId::OSAKA,
391            expected_return: InstructionResult::StackUnderflow,
392            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
393            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
394        }),
395
396        // Invalid immediate: 0x5B (91) is in the invalid range [91, 127] for decode_single.
397        dupn_invalid_imm(@raw {
398            bytecode: &[op::PUSH0, op::DUPN, 0x5B],
399            spec_id: SpecId::AMSTERDAM,
400            expected_return: InstructionResult::InvalidImmediateEncoding,
401            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
402            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
403        }),
404        swapn_invalid_imm(@raw {
405            bytecode: &[op::PUSH0, op::SWAPN, 0x5B],
406            spec_id: SpecId::AMSTERDAM,
407            expected_return: InstructionResult::InvalidImmediateEncoding,
408            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
409            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
410        }),
411        // Invalid immediate: 82 is in the invalid range [82, 127] for decode_pair.
412        exchange_invalid_imm(@raw {
413            bytecode: &[op::PUSH0, op::PUSH0, op::PUSH0, op::EXCHANGE, 82],
414            spec_id: SpecId::AMSTERDAM,
415            expected_return: InstructionResult::InvalidImmediateEncoding,
416            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
417            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
418        }),
419
420        // Truncated trailing DUPN at EOF: immediate byte missing, zero-padded to 0x00.
421        // decode_single(0) = 145, so this is DUPN(145) with only 17 items on stack → overflow.
422        dupn_truncated_eof(@raw {
423            bytecode: &{
424                let mut code = [0u8; 18];
425                let mut i = 0;
426                while i < 17 {
427                    code[i] = op::PUSH0;
428                    i += 1;
429                }
430                code[17] = op::DUPN; // no immediate byte
431                code
432            },
433            spec_id: SpecId::AMSTERDAM,
434            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
435            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
436            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
437        }),
438        // Truncated trailing SWAPN at EOF: immediate byte missing, zero-padded to 0x00.
439        // decode_single(0) = 145, so this is SWAPN(145) with only 18 items on stack → overflow.
440        swapn_truncated_eof(@raw {
441            bytecode: &{
442                let mut code = [0u8; 19];
443                let mut i = 0;
444                while i < 18 {
445                    code[i] = op::PUSH0;
446                    i += 1;
447                }
448                code[18] = op::SWAPN; // no immediate byte
449                code
450            },
451            spec_id: SpecId::AMSTERDAM,
452            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
453            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
454            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
455        }),
456
457        // JUMP into the 0x5b immediate byte of DUPN. Per EIP-8024, JUMPDEST analysis is
458        // unchanged by these opcodes, so 0x5b in the immediate position is a valid target.
459        jump_into_dupn_immediate(@raw {
460            bytecode: &[
461                op::PUSH1, 4, op::JUMP,
462                op::DUPN, op::JUMPDEST, // 0x5b immediate is a reachable JUMPDEST
463                op::PUSH1, 0x42, op::PUSH0, op::MSTORE,
464                op::PUSH1, 0x20, op::PUSH0, op::RETURN,
465            ],
466            spec_id: SpecId::AMSTERDAM,
467            expected_return: InstructionResult::Return,
468            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
469            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
470        }),
471        // Same as above but with SWAPN.
472        jump_into_swapn_immediate(@raw {
473            bytecode: &[
474                op::PUSH1, 4, op::JUMP,
475                op::SWAPN, op::JUMPDEST,
476                op::PUSH1, 0x42, op::PUSH0, op::MSTORE,
477                op::PUSH1, 0x20, op::PUSH0, op::RETURN,
478            ],
479            spec_id: SpecId::AMSTERDAM,
480            expected_return: InstructionResult::Return,
481            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
482            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
483        }),
484        // Same as above but with EXCHANGE.
485        jump_into_exchange_immediate(@raw {
486            bytecode: &[
487                op::PUSH1, 4, op::JUMP,
488                op::EXCHANGE, op::JUMPDEST,
489                op::PUSH1, 0x42, op::PUSH0, op::MSTORE,
490                op::PUSH1, 0x20, op::PUSH0, op::RETURN,
491            ],
492            spec_id: SpecId::AMSTERDAM,
493            expected_return: InstructionResult::Return,
494            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
495            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
496        }),
497
498        // Truncated PUSH2 at EOF: only 1 of 2 immediate bytes present.
499        // EVM spec right-pads with zeros: PUSH2 0x42 → 0x4200.
500        push2_truncated_eof(@raw {
501            bytecode: &[op::PUSH2, 0x42],
502            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
503            expected_stack: &[U256::from(0x4200u64)],
504            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
505        }),
506        // Truncated PUSH3 at EOF: only 2 of 3 immediate bytes present.
507        push3_truncated_eof(@raw {
508            bytecode: &[op::PUSH3, 0xAB, 0xCD],
509            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
510            expected_stack: &[U256::from(0xABCD00u64)],
511            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
512        }),
513        // PUSH1 with no immediate bytes at all.
514        push1_no_imm_eof(@raw {
515            bytecode: &[op::PUSH1],
516            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
517            expected_stack: &[U256::ZERO],
518            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
519        }),
520
521        overflow_analysis_edge_case(@raw {
522            bytecode: &[&[op::JUMPDEST][..], &[op::PUSH0; 1025][..], &[op::JUMPI][..]].concat(),
523            expected_return: InstructionResult::StackOverflow,
524        }),
525    }
526
527    control_flow {
528        basic_jump(@raw {
529            bytecode: &[op::PUSH1, 3, op::JUMP, op::JUMPDEST, op::PUSH1, 69],
530            expected_stack: &[69_U256],
531            expected_gas: 3 + 8 + 1 + 3,
532        }),
533        unmodified_stack_after_push_jump(@raw {
534            bytecode: &[op::PUSH1, 3, op::JUMP, op::JUMPDEST, op::PUSH0, op::ADD],
535            expected_return: InstructionResult::StackUnderflow,
536            expected_stack: &[U256::ZERO],
537            expected_gas: 3 + 8 + 1 + 2 + 3,
538        }),
539        bad_jump(@raw {
540            bytecode: &[op::JUMP],
541            expected_return: InstructionResult::StackUnderflow,
542            expected_gas: 8,
543        }),
544        bad_jumpi1(@raw {
545            bytecode: &[op::JUMPI],
546            expected_return: InstructionResult::StackUnderflow,
547            expected_gas: 10,
548        }),
549        bad_jumpi2(@raw {
550            bytecode: &[op::PUSH0, op::JUMPI],
551            expected_return: InstructionResult::StackUnderflow,
552            expected_stack: &[0_U256],
553            expected_gas: 2 + 10,
554        }),
555        bad_jumpi3(@raw {
556            bytecode: &[op::JUMPDEST, op::PUSH0, op::JUMPI],
557            expected_return: InstructionResult::StackUnderflow,
558            expected_stack: &[0_U256],
559            expected_gas: 1 + 2 + 10,
560        }),
561
562        basic_jumpi1(@raw {
563            bytecode: &[op::JUMPDEST, op::PUSH0, op::PUSH0, op::JUMPI, op::PUSH1, 69],
564            expected_stack: &[69_U256],
565            expected_gas: 1 + 2 + 2 + 10 + 3,
566        }),
567        basic_jumpi1_lazy_invalid_target(@raw {
568            bytecode: &[op::PUSH0, op::PUSH0, op::JUMPI, op::PUSH1, 69],
569            expected_stack: &[69_U256],
570            expected_gas: 2 + 2 + 10 + 3,
571        }),
572        basic_jumpi2(@raw {
573            bytecode: &[op::PUSH1, 1, op::PUSH1, 5, op::JUMPI, op::JUMPDEST, op::PUSH1, 69],
574            expected_stack: &[69_U256],
575            expected_gas: 3 + 3 + 10 + 1 + 3,
576        }),
577        basic_jumpi2_lazy_invalid_target(@raw {
578            bytecode: &[op::PUSH1, 1, op::PUSH0, op::JUMPI, op::PUSH1, 69],
579            expected_return: InstructionResult::InvalidJump,
580            expected_gas: 3 + 2 + 10,
581        }),
582        unmodified_stack_after_push_jumpi(@raw {
583            bytecode: &[op::PUSH1, 1, op::PUSH1, 5, op::JUMPI, op::JUMPDEST, op::PUSH0, op::ADD],
584            expected_return: InstructionResult::StackUnderflow,
585            expected_stack: &[U256::ZERO],
586            expected_gas: 3 + 3 + 10 + 1 + 2 + 3,
587        }),
588
589        basic_loop(@raw {
590            bytecode: &[
591                op::PUSH1, 3,  // i=3
592                op::JUMPDEST,  // i
593                op::PUSH1, 1,  // 1, i
594                op::SWAP1,     // i, 1
595                op::SUB,       // i-1
596                op::DUP1,      // i-1, i-1
597                op::PUSH1, 2,  // dst, i-1, i-1
598                op::JUMPI,     // i=i-1
599                op::POP,       //
600                op::PUSH1, 69, // 69
601            ],
602            expected_stack: &[69_U256],
603            expected_gas: 3 + (1 + 3 + 3 + 3 + 3 + 3 + 10) * 3 + 2 + 3,
604        }),
605
606        pc(@raw {
607            bytecode: &[op::PC, op::PC, op::PUSH1, 69, op::PC, op::PUSH0, op::PC],
608            expected_stack: &[0_U256, 1_U256, 69_U256, 4_U256, 0_U256, 6_U256],
609            expected_gas: 2 + 2 + 3 + 2 + 2 + 2,
610        }),
611
612    }
613
614    arith {
615        add1(op::ADD, 0_U256, 0_U256 => 0_U256),
616        add2(op::ADD, 1_U256, 2_U256 => 3_U256),
617        add3(op::ADD, 255_U256, 255_U256 => 510_U256),
618        add4(op::ADD, U256::MAX, 1_U256 => 0_U256),
619        add5(op::ADD, U256::MAX, 2_U256 => 1_U256),
620
621        sub1(op::SUB, 3_U256, 2_U256 => 1_U256),
622        sub2(op::SUB, 1_U256, 2_U256 => -1_U256),
623        sub3(op::SUB, 1_U256, 3_U256 => (-1_U256).wrapping_sub(1_U256)),
624        sub4(op::SUB, 255_U256, 255_U256 => 0_U256),
625
626        mul1(op::MUL, 1_U256, 2_U256 => 2_U256),
627        mul2(op::MUL, 32_U256, 32_U256 => 1024_U256),
628        mul3(op::MUL, U256::MAX, 2_U256 => U256::MAX.wrapping_sub(1_U256)),
629
630        div1(op::DIV, 32_U256, 32_U256 => 1_U256),
631        div2(op::DIV, 1_U256, 2_U256 => 0_U256),
632        div3(op::DIV, 2_U256, 2_U256 => 1_U256),
633        div4(op::DIV, 3_U256, 2_U256 => 1_U256),
634        div5(op::DIV, 4_U256, 2_U256 => 2_U256),
635        div_by_one(op::DIV, 42_U256, 1_U256 => 42_U256),
636        div_pow2_4(op::DIV, 100_U256, 4_U256 => 25_U256),
637        div_pow2_256(op::DIV, 512_U256, 256_U256 => 2_U256),
638        div_zero_dividend(op::DIV, 0_U256, 42_U256 => 0_U256),
639        div_by_zero1(op::DIV, 0_U256, 0_U256 => 0_U256),
640        div_by_zero2(op::DIV, 32_U256, 0_U256 => 0_U256),
641
642        rem1(op::MOD, 32_U256, 32_U256 => 0_U256),
643        rem2(op::MOD, 1_U256, 2_U256 => 1_U256),
644        rem3(op::MOD, 2_U256, 2_U256 => 0_U256),
645        rem4(op::MOD, 3_U256, 2_U256 => 1_U256),
646        rem5(op::MOD, 4_U256, 2_U256 => 0_U256),
647        rem_by_one(op::MOD, 42_U256, 1_U256 => 0_U256),
648        rem_pow2_4(op::MOD, 100_U256, 4_U256 => 0_U256),
649        rem_pow2_256(op::MOD, 513_U256, 256_U256 => 1_U256),
650        rem_zero_dividend(op::MOD, 0_U256, 42_U256 => 0_U256),
651        rem_by_zero1(op::MOD, 0_U256, 0_U256 => 0_U256),
652        rem_by_zero2(op::MOD, 32_U256, 0_U256 => 0_U256),
653
654        sdiv1(op::SDIV, 32_U256, 32_U256 => 1_U256),
655        sdiv2(op::SDIV, 1_U256, 2_U256 => 0_U256),
656        sdiv3(op::SDIV, 2_U256, 2_U256 => 1_U256),
657        sdiv4(op::SDIV, 3_U256, 2_U256 => 1_U256),
658        sdiv5(op::SDIV, 4_U256, 2_U256 => 2_U256),
659        sdiv_by_zero1(op::SDIV, 0_U256, 0_U256 => 0_U256),
660        sdiv_by_zero2(op::SDIV, 32_U256, 0_U256 => 0_U256),
661        sdiv_min_by_1(op::SDIV, I256_MIN, 1_U256 => -I256_MIN),
662        sdiv_min_by_minus_1(op::SDIV, I256_MIN, -1_U256 => I256_MIN),
663        sdiv_max1(op::SDIV, I256_MAX, 1_U256 => I256_MAX),
664        sdiv_max2(op::SDIV, I256_MAX, -1_U256 => -I256_MAX),
665        sdiv_by_int_min(op::SDIV, I256_MIN, I256_MIN => 1_U256),
666        sdiv_nonmin_by_int_min(op::SDIV, 42_U256, I256_MIN => 0_U256),
667        sdiv_zero_dividend(op::SDIV, 0_U256, 42_U256 => 0_U256),
668
669        srem1(op::SMOD, 32_U256, 32_U256 => 0_U256),
670        srem2(op::SMOD, 1_U256, 2_U256 => 1_U256),
671        srem3(op::SMOD, 2_U256, 2_U256 => 0_U256),
672        srem4(op::SMOD, 3_U256, 2_U256 => 1_U256),
673        srem5(op::SMOD, 4_U256, 2_U256 => 0_U256),
674        srem_by_one(op::SMOD, 42_U256, 1_U256 => 0_U256),
675        srem_by_minus_one(op::SMOD, 42_U256, -1_U256 => 0_U256),
676        srem_zero_dividend(op::SMOD, 0_U256, 42_U256 => 0_U256),
677        srem_by_zero1(op::SMOD, 0_U256, 0_U256 => 0_U256),
678        srem_by_zero2(op::SMOD, 32_U256, 0_U256 => 0_U256),
679
680        addmod_mod_zero(op::ADDMOD, 1_U256, 2_U256, 0_U256 => 0_U256),
681        addmod_mod_one(op::ADDMOD, 5_U256, 3_U256, 1_U256 => 0_U256),
682        addmod_both_zero(op::ADDMOD, 0_U256, 0_U256, 42_U256 => 0_U256),
683        addmod1(op::ADDMOD, 1_U256, 2_U256, 3_U256 => 0_U256),
684        addmod2(op::ADDMOD, 1_U256, 2_U256, 4_U256 => 3_U256),
685        addmod3(op::ADDMOD, 1_U256, 2_U256, 2_U256 => 1_U256),
686        addmod4(op::ADDMOD, 32_U256, 32_U256, 69_U256 => 64_U256),
687
688        mulmod_mod_zero(op::MULMOD, 3_U256, 4_U256, 0_U256 => 0_U256),
689        mulmod1(op::MULMOD, 0_U256, 0_U256, 1_U256 => 0_U256),
690        mulmod2(op::MULMOD, 69_U256, 0_U256, 1_U256 => 0_U256),
691        mulmod3(op::MULMOD, 0_U256, 1_U256, 2_U256 => 0_U256),
692        mulmod_a_zero(op::MULMOD, 0_U256, 5_U256, 7_U256 => 0_U256),
693        mulmod_b_zero(op::MULMOD, 5_U256, 0_U256, 7_U256 => 0_U256),
694        mulmod4(op::MULMOD, 69_U256, 1_U256, 2_U256 => 1_U256),
695        mulmod5(op::MULMOD, 69_U256, 1_U256, 30_U256 => 9_U256),
696        mulmod6(op::MULMOD, 69_U256, 2_U256, 100_U256 => 38_U256),
697
698        exp1(op::EXP, 0_U256, 0_U256 => 1_U256; op_gas(10)),
699        exp2(op::EXP, 2_U256, 0_U256 => 1_U256; op_gas(10)),
700        exp3(op::EXP, 2_U256, 1_U256 => 2_U256; op_gas(60)),
701        exp4(op::EXP, 2_U256, 2_U256 => 4_U256; op_gas(60)),
702        exp5(op::EXP, 2_U256, 3_U256 => 8_U256; op_gas(60)),
703        exp6(op::EXP, 2_U256, 4_U256 => 16_U256; op_gas(60)),
704        exp_zero_base_zero_exp(op::EXP, 0_U256, 0_U256 => 1_U256; op_gas(10)),
705        exp_zero_base_nonzero_exp(op::EXP, 0_U256, 5_U256 => 0_U256; op_gas(60)),
706        exp_one_base_large_exp(op::EXP, 1_U256, U256::MAX => 1_U256; op_gas(1610)),
707        exp_minus_one_base_even_exp(op::EXP, -1_U256, 4_U256 => 1_U256; op_gas(60)),
708        exp_minus_one_base_odd_exp(op::EXP, -1_U256, 5_U256 => -1_U256; op_gas(60)),
709        exp_pow4_base_in_range(op::EXP, 4_U256, 63_U256 => 1_U256 << 126; op_gas(60)),
710        exp_pow4_base_overflow(op::EXP, 4_U256, 128_U256 => 0_U256; op_gas(60)),
711        exp_non_pow2_base(op::EXP, 3_U256, 5_U256 => 243_U256; op_gas(60)),
712        exp_overflow(op::EXP, 2_U256, 256_U256 => 0_U256; op_gas(110)),
713        // Large exponent spanning multiple bytes.
714        exp_large(op::EXP, 2_U256, 0xFFFF_U256 => 2_U256.pow(0xFFFF_U256); op_gas(110)),
715        // Max exponent (32 bytes), dynamic = 50 * 32 = 1600, total = 10 + 1600 = 1610.
716        exp_max_exponent(op::EXP, 2_U256, U256::MAX => 0_U256; op_gas(1610)),
717
718        signextend1(op::SIGNEXTEND, 0_U256, 0_U256 => 0_U256),
719        signextend2(op::SIGNEXTEND, 1_U256, 0_U256 => 0_U256),
720        signextend3(op::SIGNEXTEND, 0_U256, -1_U256 => -1_U256),
721        signextend4(op::SIGNEXTEND, 1_U256, -1_U256 => -1_U256),
722        signextend5(op::SIGNEXTEND, 0_U256, 0x7f_U256 => 0x7f_U256),
723        signextend6(op::SIGNEXTEND, 0_U256, 0x80_U256 => -0x80_U256),
724        signextend7(op::SIGNEXTEND, 0_U256, 0xff_U256 => U256::MAX),
725        signextend8(op::SIGNEXTEND, 1_U256, 0x7fff_U256 => 0x7fff_U256),
726        signextend8_extra(op::SIGNEXTEND, 1_U256, 0xff7fff_U256 => 0x7fff_U256),
727        signextend9(op::SIGNEXTEND, 1_U256, 0x8000_U256 => -0x8000_U256),
728        signextend9_extra(op::SIGNEXTEND, 1_U256, 0x118000_U256 => -0x8000_U256),
729        signextend10(op::SIGNEXTEND, 1_U256, 0xffff_U256 => U256::MAX),
730        signextend_noop_31(op::SIGNEXTEND, 31_U256, 0x42_U256 => 0x42_U256),
731        signextend_noop_32(op::SIGNEXTEND, 32_U256, 0x42_U256 => 0x42_U256),
732        signextend_noop_max(op::SIGNEXTEND, U256::MAX, 0x42_U256 => 0x42_U256),
733    }
734
735    cmp {
736        lt1(op::LT, 1_U256, 2_U256 => 1_U256),
737        lt2(op::LT, 2_U256, 1_U256 => 0_U256),
738        lt3(op::LT, 1_U256, 1_U256 => 0_U256),
739        lt4(op::LT, -1_U256, 1_U256 => 0_U256),
740
741        gt1(op::GT, 1_U256, 2_U256 => 0_U256),
742        gt2(op::GT, 2_U256, 1_U256 => 1_U256),
743        gt3(op::GT, 1_U256, 1_U256 => 0_U256),
744        gt4(op::GT, -1_U256, 1_U256 => 1_U256),
745
746        slt1(op::SLT, 1_U256, 2_U256 => 1_U256),
747        slt2(op::SLT, 2_U256, 1_U256 => 0_U256),
748        slt3(op::SLT, 1_U256, 1_U256 => 0_U256),
749        slt4(op::SLT, -1_U256, 1_U256 => 1_U256),
750
751        sgt1(op::SGT, 1_U256, 2_U256 => 0_U256),
752        sgt2(op::SGT, 2_U256, 1_U256 => 1_U256),
753        sgt3(op::SGT, 1_U256, 1_U256 => 0_U256),
754        sgt4(op::SGT, -1_U256, 1_U256 => 0_U256),
755
756        eq1(op::EQ, 1_U256, 2_U256 => 0_U256),
757        eq2(op::EQ, 2_U256, 1_U256 => 0_U256),
758        eq3(op::EQ, 1_U256, 1_U256 => 1_U256),
759
760        iszero1(op::ISZERO, 0_U256 => 1_U256),
761        iszero2(op::ISZERO, 1_U256 => 0_U256),
762        iszero3(op::ISZERO, 2_U256 => 0_U256),
763    }
764
765    bitwise {
766        and1(op::AND, 0_U256, 0_U256 => 0_U256),
767        and2(op::AND, 1_U256, 1_U256 => 1_U256),
768        and3(op::AND, 1_U256, 2_U256 => 0_U256),
769        and4(op::AND, 255_U256, 255_U256 => 255_U256),
770
771        or1(op::OR, 0_U256, 0_U256 => 0_U256),
772        or2(op::OR, 1_U256, 2_U256 => 3_U256),
773        or3(op::OR, 1_U256, 3_U256 => 3_U256),
774        or4(op::OR, 2_U256, 2_U256 => 2_U256),
775
776        xor1(op::XOR, 0_U256, 0_U256 => 0_U256),
777        xor2(op::XOR, 1_U256, 2_U256 => 3_U256),
778        xor3(op::XOR, 1_U256, 3_U256 => 2_U256),
779        xor4(op::XOR, 2_U256, 2_U256 => 0_U256),
780
781        not1(op::NOT, 0_U256 => U256::MAX),
782        not2(op::NOT, U256::MAX => 0_U256),
783        not3(op::NOT, 1_U256 => U256::MAX.wrapping_sub(1_U256)),
784
785        byte1(op::BYTE, 0_U256, 0x1122334400000000000000000000000000000000000000000000000000000000_U256 => 0x11_U256),
786        byte2(op::BYTE, 1_U256, 0x1122334400000000000000000000000000000000000000000000000000000000_U256 => 0x22_U256),
787        byte3(op::BYTE, 2_U256, 0x1122334400000000000000000000000000000000000000000000000000000000_U256 => 0x33_U256),
788        byte4(op::BYTE, 3_U256, 0x1122334400000000000000000000000000000000000000000000000000000000_U256 => 0x44_U256),
789        byte5(op::BYTE, 4_U256, 0x1122334400000000000000000000000000000000000000000000000000000000_U256 => 0x00_U256),
790        byte_oob0(op::BYTE, 31_U256, U256::MAX => 0xFF_U256),
791        byte_oob1(op::BYTE, 32_U256, U256::MAX => 0_U256),
792        byte_oob2(op::BYTE, 33_U256, U256::MAX => 0_U256),
793
794        // shift operand order is reversed for some reason:
795        // shift, x
796        shl1(op::SHL, 0_U256, 1_U256 => 1_U256),
797        shl2(op::SHL, 1_U256, 1_U256 => 2_U256),
798        shl3(op::SHL, 2_U256, 1_U256 => 4_U256),
799        shl4(op::SHL, 255_U256, -1_U256 => -1_U256 << 255),
800        shl5(op::SHL, 256_U256, -1_U256 => 0_U256),
801
802        shr1(op::SHR, 0_U256, 1_U256 => 1_U256),
803        shr2(op::SHR, 1_U256, 2_U256 => 1_U256),
804        shr3(op::SHR, 2_U256, 4_U256 => 1_U256),
805        shr4(op::SHR, 255_U256, -1_U256 => 1_U256),
806        shr5(op::SHR, 256_U256, -1_U256 => 0_U256),
807
808        sar1(op::SAR, 0_U256, 1_U256 => 1_U256),
809        sar2(op::SAR, 1_U256, 2_U256 => 1_U256),
810        sar3(op::SAR, 2_U256, 4_U256 => 1_U256),
811        sar4(op::SAR, 1_U256, -1_U256 => -1_U256),
812        sar5(op::SAR, 2_U256, -1_U256 => -1_U256),
813        sar6(op::SAR, 255_U256, -1_U256 => -1_U256),
814        sar7(op::SAR, 256_U256, -1_U256 => -1_U256),
815    }
816
817    system {
818        gas0(@raw {
819            bytecode: &[op::GAS, op::GAS, op::JUMPDEST, op::GAS],
820            expected_stack: &[DEF_GAS_LIMIT_U256 - 2_U256, DEF_GAS_LIMIT_U256 - 4_U256, DEF_GAS_LIMIT_U256 - 7_U256],
821            expected_gas: 2 + 2 + 1 + 2,
822        }),
823        keccak256_empty1(@raw {
824            bytecode: &[op::PUSH0, op::PUSH0, op::KECCAK256],
825            expected_stack: &[KECCAK_EMPTY.into()],
826            expected_gas: 2 + 2 + gas::KECCAK256,
827        }),
828        keccak256_empty2(@raw {
829            bytecode: &[op::PUSH0, op::PUSH1, 32, op::KECCAK256],
830            expected_stack: &[KECCAK_EMPTY.into()],
831            expected_gas: 2 + 3 + gas::KECCAK256,
832        }),
833        keccak256_empty_dynamic_offset(@raw {
834            bytecode: &[op::PUSH0, op::ADDRESS, op::KECCAK256],
835            expected_stack: &[KECCAK_EMPTY.into()],
836            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
837        }),
838        keccak256_1(@raw {
839            bytecode: &[op::PUSH1, 32, op::PUSH0, op::KECCAK256],
840            expected_stack: &[keccak256([0; 32]).into()],
841            expected_memory: &[0; 32],
842            expected_gas: 3 + 2 + (keccak256_cost(32).unwrap() + 3),
843        }),
844        keccak256_2(@raw {
845            bytecode: &[op::PUSH2, 0x69, 0x42, op::PUSH0, op::MSTORE, op::PUSH1, 0x20, op::PUSH0, op::KECCAK256],
846            expected_stack: &[keccak256(0x6942_U256.to_be_bytes::<32>()).into()],
847            expected_memory: &0x6942_U256.to_be_bytes::<32>(),
848            expected_gas: 3 + 2 + (3 + 3) + 3 + 2 + keccak256_cost(32).unwrap(),
849        }),
850
851        address(@raw {
852            bytecode: &[op::ADDRESS, op::ADDRESS],
853            expected_stack: &[DEF_ADDR.into_word().into(), DEF_ADDR.into_word().into()],
854            expected_gas: 4,
855        }),
856        origin(@raw {
857            bytecode: &[op::ORIGIN, op::ORIGIN],
858            expected_stack: &[def_env().tx.caller.into_word().into(), def_env().tx.caller.into_word().into()],
859            expected_gas: 4,
860        }),
861        caller(@raw {
862            bytecode: &[op::CALLER, op::CALLER],
863            expected_stack: &[DEF_CALLER.into_word().into(), DEF_CALLER.into_word().into()],
864            expected_gas: 4,
865        }),
866        callvalue(@raw {
867            bytecode: &[op::CALLVALUE, op::CALLVALUE],
868            expected_stack: &[DEF_VALUE, DEF_VALUE],
869            expected_gas: 4,
870        }),
871    }
872
873    calldata {
874        calldataload1(@raw {
875            bytecode: &[op::PUSH0, op::CALLDATALOAD],
876            expected_stack: &[U256::from_be_slice(&DEF_CD[..32])],
877            expected_gas: 2 + 3,
878        }),
879        calldataload2(@raw {
880            bytecode: &[op::PUSH1, 63, op::CALLDATALOAD],
881            expected_stack: &[0xaa00000000000000000000000000000000000000000000000000000000000000_U256],
882            expected_gas: 3 + 3,
883        }),
884        calldatasize(@raw {
885            bytecode: &[op::CALLDATASIZE, op::CALLDATASIZE],
886            expected_stack: &[U256::from(DEF_CD.len()), U256::from(DEF_CD.len())],
887            expected_gas: 2 + 2,
888        }),
889        calldatacopy(@raw {
890            bytecode: &[op::PUSH1, 32, op::PUSH0, op::PUSH0, op::CALLDATACOPY],
891            expected_memory: &DEF_CD[..32],
892            expected_gas: 3 + 2 + 2 + (verylowcopy_cost(32).unwrap() + 3),
893        }),
894    }
895
896    code {
897        codesize(@raw {
898            bytecode: &[op::CODESIZE, op::CODESIZE],
899            expected_stack: &[2_U256, 2_U256],
900            expected_gas: 2 + 2,
901        }),
902        codecopy(@raw {
903            bytecode: &[op::PUSH1, 5, op::PUSH0, op::PUSH0, op::CODECOPY],
904            expected_memory: &hex!("60055f5f39000000000000000000000000000000000000000000000000000000"),
905            expected_gas: 3 + 2 + 2 + (verylowcopy_cost(32).unwrap() + memory_gas_cost(1)),
906        }),
907    }
908
909    returndata {
910        returndatasize(@raw {
911            // No return data exists in this test context
912            bytecode: &[op::RETURNDATASIZE, op::RETURNDATASIZE],
913            expected_stack: &[0_U256, 0_U256],
914            expected_gas: 2 + 2,
915        }),
916        returndatacopy(@raw {
917            // No return data exists, so copying 32 bytes from offset 0 fails with OutOfOffset
918            bytecode: &[op::PUSH1, 32, op::PUSH0, op::PUSH0, op::RETURNDATACOPY],
919            expected_return: InstructionResult::OutOfOffset,
920            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
921        }),
922    }
923
924    extcode {
925        extcodesize1(op::EXTCODESIZE, DEF_ADDR.into_word().into() => 0_U256;
926            op_gas(100)),
927        extcodesize2(op::EXTCODESIZE, OTHER_ADDR.into_word().into() => U256::from(def_codemap()[&OTHER_ADDR].len());
928            op_gas(100)),
929        extcodecopy1(@raw {
930            bytecode: &[op::PUSH0, op::PUSH0, op::PUSH0, op::PUSH0, op::EXTCODECOPY],
931            expected_memory: &[],
932            expected_gas: 2 + 2 + 2 + 2 + 100,
933        }),
934        extcodecopy2(@raw {
935            // bytecode: &[op::PUSH1, 64, op::PUSH0, op::PUSH0, op::PUSH20, OTHER_ADDR, op::EXTCODECOPY],
936            bytecode: &hex!("6040 5f 5f 736969696969696969696969696969696969696969 3c"),
937            expected_memory: &{
938                let mut mem = [0; 64];
939                let code = def_codemap()[&OTHER_ADDR].original_bytes();
940                mem[..code.len()].copy_from_slice(&code);
941                mem
942            },
943            expected_gas: 3 + 2 + 2 + 3 + (100 + 12),
944        }),
945        extcodehash1(op::EXTCODEHASH, DEF_ADDR.into_word().into() => KECCAK_EMPTY.into();
946            op_gas(100)),
947        extcodehash2(op::EXTCODEHASH, OTHER_ADDR.into_word().into() => def_codemap()[&OTHER_ADDR].hash_slow().into();
948            op_gas(100)),
949    }
950
951    env {
952        gas_price(@raw {
953            bytecode: &[op::GASPRICE],
954            expected_stack: &[def_env().effective_gas_price()],
955            expected_gas: 2,
956        }),
957        // Host determines blockhash - EVM semantics:
958        // - Current block returns 0
959        // - Blocks 1-256 ago return valid hash
960        // - Blocks more than 256 ago return 0
961        blockhash0(op::BLOCKHASH, DEF_BN - 0_U256 => 0_U256),  // current block -> 0
962        blockhash1(op::BLOCKHASH, DEF_BN - 1_U256 => DEF_BN - 1_U256),  // 1 block ago -> valid
963        blockhash2(op::BLOCKHASH, DEF_BN - 255_U256 => DEF_BN - 255_U256),  // 255 blocks ago -> valid
964        blockhash3(op::BLOCKHASH, DEF_BN - 256_U256 => DEF_BN - 256_U256),  // 256 blocks ago -> valid
965        blockhash4(op::BLOCKHASH, DEF_BN - 257_U256 => 0_U256),  // 257 blocks ago -> 0 (too old)
966        coinbase(@raw {
967            bytecode: &[op::COINBASE, op::COINBASE],
968            expected_stack: &[def_env().block.coinbase.into_word().into(), def_env().block.coinbase.into_word().into()],
969            expected_gas: 4,
970        }),
971        timestamp(@raw {
972            bytecode: &[op::TIMESTAMP, op::TIMESTAMP],
973            expected_stack: &[def_env().block.timestamp, def_env().block.timestamp],
974            expected_gas: 4,
975        }),
976        number(@raw {
977            bytecode: &[op::NUMBER, op::NUMBER],
978            expected_stack: &[def_env().block.number, def_env().block.number],
979            expected_gas: 4,
980        }),
981        difficulty(@raw {
982            bytecode: &[op::DIFFICULTY, op::DIFFICULTY],
983            spec_id: SpecId::LONDON,
984            expected_stack: &[def_env().block.difficulty, def_env().block.difficulty],
985            expected_gas: 4,
986        }),
987        difficulty_prevrandao(@raw {
988            bytecode: &[op::DIFFICULTY, op::DIFFICULTY],
989            spec_id: SpecId::MERGE,
990            expected_stack: &[def_env().block.prevrandao.unwrap().into(), def_env().block.prevrandao.unwrap().into()],
991            expected_gas: 4,
992        }),
993        gaslimit(@raw {
994            bytecode: &[op::GASLIMIT, op::GASLIMIT],
995            expected_stack: &[def_env().block.gas_limit, def_env().block.gas_limit],
996            expected_gas: 4,
997        }),
998        chainid(@raw {
999            bytecode: &[op::CHAINID, op::CHAINID],
1000            expected_stack: &[U256::from(def_env().cfg.chain_id), U256::from(def_env().cfg.chain_id)],
1001            expected_gas: 4,
1002        }),
1003        selfbalance(@raw {
1004            bytecode: &[op::SELFBALANCE, op::SELFBALANCE],
1005            expected_stack: &[0xba_U256, 0xba_U256],
1006            expected_gas: 10,
1007        }),
1008        basefee(@raw {
1009            bytecode: &[op::BASEFEE, op::BASEFEE],
1010            expected_stack: &[def_env().block.basefee, def_env().block.basefee],
1011            expected_gas: 4,
1012        }),
1013        blobhash0(@raw {
1014            bytecode: &[op::PUSH0, op::BLOBHASH],
1015            expected_stack: &[def_env().tx.blob_hashes[0].into()],
1016            expected_gas: 2 + 3,
1017        }),
1018        blobhash1(@raw {
1019            bytecode: &[op::PUSH1, 1, op::BLOBHASH],
1020            expected_stack: &[def_env().tx.blob_hashes[1].into()],
1021            expected_gas: 3 + 3,
1022        }),
1023        blobhash2(@raw {
1024            bytecode: &[op::PUSH1, 2, op::BLOBHASH],
1025            expected_stack: &[0_U256],
1026            expected_gas: 3 + 3,
1027        }),
1028        blobbasefee(@raw {
1029            bytecode: &[op::BLOBBASEFEE, op::BLOBBASEFEE],
1030            expected_stack: &[U256::from(def_env().block.get_blob_gasprice().unwrap()), U256::from(def_env().block.get_blob_gasprice().unwrap())],
1031            expected_gas: 4,
1032        }),
1033    }
1034
1035    memory {
1036        mload1(@raw {
1037            bytecode: &[op::PUSH0, op::MLOAD],
1038            expected_stack: &[0_U256],
1039            expected_memory: &[0; 32],
1040            expected_gas: 2 + (3 + memory_gas_cost(1)),
1041        }),
1042        mload2(@raw {
1043            bytecode: &[op::PUSH1, 1, op::MLOAD],
1044            expected_stack: &[0_U256],
1045            expected_memory: &[0; 64],
1046            expected_gas: 3 + (3 + memory_gas_cost(2)),
1047        }),
1048        mload3(@raw {
1049            bytecode: &[op::PUSH1, 32, op::MLOAD],
1050            expected_stack: &[0_U256],
1051            expected_memory: &[0; 64],
1052            expected_gas: 3 + (3 + memory_gas_cost(2)),
1053        }),
1054        mload4(@raw {
1055            bytecode: &[op::PUSH1, 33, op::MLOAD],
1056            expected_stack: &[0_U256],
1057            expected_memory: &[0; 96],
1058            expected_gas: 3 + (3 + memory_gas_cost(3)),
1059        }),
1060        mload_overflow1(@raw {
1061            bytecode: &[op::PUSH8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, op::MLOAD],
1062            expected_return: InstructionResult::MemoryOOG,
1063            expected_stack: &[U256::from(u64::MAX)],
1064            expected_gas: 3 + 3,
1065        }),
1066        mload_overflow2(@raw {
1067            bytecode: &[op::PUSH8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - 1, op::MLOAD],
1068            expected_return: InstructionResult::MemoryOOG,
1069            expected_stack: &[U256::from(u64::MAX - 1)],
1070            expected_gas: 3 + 3,
1071        }),
1072        mload_overflow3(@raw {
1073            bytecode: &[op::PUSH8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - 31, op::MLOAD],
1074            expected_return: InstructionResult::MemoryOOG,
1075            expected_stack: &[U256::from(u64::MAX - 31)],
1076            expected_gas: 3 + 3,
1077        }),
1078        mload_overflow4(@raw {
1079            bytecode: &[op::PUSH8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - 32, op::MLOAD],
1080            expected_return: InstructionResult::MemoryOOG,
1081            expected_stack: &[U256::from(u64::MAX - 32)],
1082            expected_gas: 3 + 3,
1083        }),
1084        mload_overflow5(@raw {
1085            bytecode: &[op::PUSH8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - 33, op::MLOAD],
1086            expected_return: InstructionResult::MemoryOOG,
1087            expected_stack: &[U256::from(u64::MAX - 33)],
1088            expected_gas: 3 + 3,
1089        }),
1090        mload_overflow6(@raw {
1091            bytecode: &[op::ADDRESS, op::MLOAD],
1092            expected_return: InstructionResult::InvalidOperandOOG,
1093            expected_stack: &[DEF_ADDR.into_word().into()],
1094            expected_gas: 5,
1095        }),
1096        mload_const_offset_too_large(@raw {
1097            bytecode: &{
1098                let mut code = Vec::new();
1099                code.push(op::PUSH9);
1100                code.extend_from_slice(&0x1_0000_0000_0000_0000_U256.to_be_bytes::<32>()[23..]);
1101                code.push(op::MLOAD);
1102                code
1103            },
1104            expected_return: InstructionResult::InvalidOperandOOG,
1105            expected_stack: &[0x1_0000_0000_0000_0000_U256],
1106            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1107        }),
1108        mstore1(@raw {
1109            bytecode: &[op::PUSH0, op::PUSH0, op::MSTORE],
1110            expected_memory: &[0; 32],
1111            expected_gas: 2 + 2 + (3 + memory_gas_cost(1)),
1112        }),
1113        mstore_const_offset_dyn_value(@raw {
1114            bytecode: &bytecode_binop_mixed(op::MSTORE, 0_U256, 0x69_U256, true, false),
1115            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1116            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1117        }),
1118        mstore_dyn_offset_const_value(@raw {
1119            bytecode: &bytecode_binop_mixed(op::MSTORE, 0_U256, 0x69_U256, false, true),
1120            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1121            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1122        }),
1123        mstore_dyn_offset_dyn_value(@raw {
1124            bytecode: &bytecode_binop_mixed(op::MSTORE, 0_U256, 0x69_U256, false, false),
1125            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1126            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1127        }),
1128        mstore8_1(@raw {
1129            bytecode: &[op::PUSH0, op::PUSH0, op::MSTORE8],
1130            expected_memory: &[0; 32],
1131            expected_gas: 2 + 2 + (3 + memory_gas_cost(1)),
1132        }),
1133        mstore8_2(@raw {
1134            bytecode: &[op::PUSH2, 0x69, 0x69, op::PUSH0, op::MSTORE8],
1135            expected_memory: &{
1136                let mut mem = [0; 32];
1137                mem[0] = 0x69;
1138                mem
1139            },
1140            expected_gas: 3 + 2 + (3 + memory_gas_cost(1)),
1141        }),
1142        msize1(@raw {
1143            bytecode: &[op::MSIZE, op::MSIZE],
1144            expected_stack: &[0_U256, 0_U256],
1145            expected_gas: 2 + 2,
1146        }),
1147        msize2(@raw {
1148            bytecode: &[op::MSIZE, op::PUSH0, op::MLOAD, op::POP, op::MSIZE, op::PUSH1, 1, op::MLOAD, op::POP, op::MSIZE],
1149            expected_stack: &[0_U256, 32_U256, 64_U256],
1150            expected_memory: &[0; 64],
1151            expected_gas: 2 + 2 + (3 + memory_gas_cost(1)) + 2 + 2 + 3 + (3 + (memory_gas_cost(2) - memory_gas_cost(1))) + 2 + 2,
1152        }),
1153        mcopy1(@raw {
1154            bytecode: &[op::PUSH1, 32, op::PUSH0, op::PUSH1, 32, op::MCOPY],
1155            expected_memory: &[0; 64],
1156            expected_gas: 3 + 2 + 3 + (verylowcopy_cost(32).unwrap() + memory_gas_cost(2)),
1157        }),
1158        mcopy2(@raw {
1159            bytecode: &[op::PUSH2, 0x42, 0x69, op::PUSH0, op::MSTORE,
1160                        op::PUSH1, 2, op::PUSH1, 30, op::PUSH1, 1, op::MCOPY],
1161            expected_memory: &{
1162                let mut mem = [0; 32];
1163                mem[30] = 0x42;
1164                mem[31] = 0x69;
1165                mem[1] = 0x42;
1166                mem[2] = 0x69;
1167                mem
1168            },
1169            expected_gas: 3 + 2 + (3 + memory_gas_cost(1)) +
1170                          3 + 3 + 3 + verylowcopy_cost(2).unwrap(),
1171        }),
1172    }
1173
1174    host {
1175        balance(op::BALANCE, 0_U256 => 0_U256; op_gas(100)),
1176        sload1(@raw {
1177            bytecode: &[op::PUSH1, 69, op::SLOAD],
1178            expected_stack: &[42_U256],
1179            expected_gas: 3 + 100,
1180        }),
1181        sload2(@raw {
1182            bytecode: &[op::PUSH1, 70, op::SLOAD],
1183            expected_stack: &[0_U256],
1184            expected_gas: 3 + 100, // TestHost always returns is_cold=false (warm)
1185        }),
1186        sload3(@raw {
1187            bytecode: &[op::PUSH1, 0xff, op::SLOAD],
1188            expected_stack: &[0_U256],
1189            expected_gas: 3 + 100, // TestHost always returns is_cold=false (warm)
1190        }),
1191        sstore1(@raw {
1192            bytecode: &[op::PUSH1, 200, op::SLOAD, op::PUSH1, 100, op::PUSH1, 200, op::SSTORE, op::PUSH1, 200, op::SLOAD],
1193            expected_stack: &[0_U256, 100_U256],
1194            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1195            assert_host: Some(|host| {
1196                assert_eq!(host.storage.get(&200_U256), Some(&100_U256));
1197            }),
1198        }),
1199        sstore_const_inputs(@raw {
1200            bytecode: &[op::PUSH1, 42, op::PUSH0, op::SSTORE],
1201            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1202            assert_host: Some(|host| {
1203                assert_eq!(host.storage.get(&U256::ZERO), Some(&42_U256));
1204            }),
1205        }),
1206        tstore_const_inputs(@raw {
1207            bytecode: &[op::PUSH1, 42, op::PUSH1, 69, op::TSTORE],
1208            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1209            assert_host: Some(|host| {
1210                assert_eq!(host.transient_storage.get(&69_U256), Some(&42_U256));
1211            }),
1212        }),
1213        sstore_constantinople(@raw {
1214            bytecode: &[op::PC, op::PC, op::SSTORE, op::PC, op::COINBASE],
1215            spec_id: SpecId::PETERSBURG,
1216            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
1217            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1218        }),
1219        tload(@raw {
1220            bytecode: &[op::PUSH1, 69, op::TLOAD],
1221            expected_stack: &[0_U256],
1222            expected_gas: 3 + 100,
1223            assert_host: Some(|host| {
1224                assert!(host.transient_storage.is_empty());
1225            }),
1226        }),
1227        tstore(@raw {
1228            bytecode: &[op::PUSH1, 69, op::TLOAD, op::PUSH1, 42, op::PUSH1, 69, op::TSTORE, op::PUSH1, 69, op::TLOAD],
1229            expected_stack: &[0_U256, 42_U256],
1230            expected_gas: 3 + 100 + 3 + 3 + 100 + 3 + 100,
1231            assert_host: Some(|host| {
1232                assert_eq!(host.transient_storage.get(&69_U256), Some(&42_U256));
1233            }),
1234        }),
1235        log0(@raw {
1236            bytecode: &[op::PUSH0, op::PUSH0, op::LOG0],
1237            expected_gas: 2 + 2 + log_cost(0, 0).unwrap(),
1238            assert_host: Some(|host| {
1239                assert_eq!(host.logs, [Log {
1240                    address: DEF_ADDR,
1241                    data: LogData::new(vec![], Bytes::new()).unwrap(),
1242                }]);
1243            }),
1244        }),
1245        log0_data(@raw {
1246            bytecode: &[op::PUSH2, 0x69, 0x42, op::PUSH0, op::MSTORE, op::PUSH1, 32, op::PUSH0, op::LOG0],
1247            expected_memory: &0x6942_U256.to_be_bytes::<32>(),
1248            expected_gas: 3 + 2 + (3 + memory_gas_cost(1)) + 3 + 2 + log_cost(0, 32).unwrap(),
1249            assert_host: Some(|host| {
1250                assert_eq!(host.logs, [Log {
1251                    address: DEF_ADDR,
1252                    data: LogData::new(vec![], Bytes::copy_from_slice(&0x6942_U256.to_be_bytes::<32>())).unwrap(),
1253                }]);
1254            }),
1255        }),
1256        log1_1(@raw {
1257            bytecode: &[op::PUSH0, op::PUSH0, op::PUSH0, op::LOG1],
1258            expected_gas: 2 + 2 + 2 + log_cost(1, 0).unwrap(),
1259            assert_host: Some(|host| {
1260                assert_eq!(host.logs, [Log {
1261                    address: DEF_ADDR,
1262                    data: LogData::new(vec![B256::ZERO], Bytes::new()).unwrap(),
1263                }]);
1264            }),
1265        }),
1266        log1_2(@raw {
1267            bytecode: &hex!(
1268                "7f000000000000000000000000ffffffffffffffffffffffffffffffffffffffff"
1269                "7f0000000000000000000000000000000000000000000000000000000000000032" // 50
1270                "59"
1271                "a1"
1272            ),
1273            expected_memory: &[0; 64],
1274            expected_gas: 3 + 3 + 2 + (log_cost(1, 50).unwrap() + memory_gas_cost(2)),
1275            assert_host: Some(|host| {
1276                assert_eq!(host.logs, [Log {
1277                    address: DEF_ADDR,
1278                    data: LogData::new(
1279                        vec![0xffffffffffffffffffffffffffffffffffffffff_U256.into()],
1280                        Bytes::copy_from_slice(&[0; 50]),
1281                    ).unwrap(),
1282                }]);
1283            }),
1284        }),
1285        log3_topic_does_not_resize_memory(@raw {
1286            bytecode: &[
1287                op::PUSH2, 0x08, 0x00, op::PUSH0, op::PUSH0, op::PUSH0, op::PUSH0, op::LOG3,
1288                op::PUSH0, op::PUSH0, op::MSTORE,
1289            ],
1290            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1291            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1292        }),
1293        create(@raw {
1294            bytecode: &[op::PUSH1, 0x69, op::PUSH0, op::MSTORE, op::PUSH1, 32, op::PUSH0, op::PUSH1, 0x42, op::CREATE],
1295            expected_return: InstructionResult::Stop,
1296            // NOTE: The address is pushed by the caller.
1297            expected_stack: &[],
1298            expected_memory: &0x69_U256.to_be_bytes::<32>(),
1299            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1300            expected_next_action: InterpreterAction::NewFrame(FrameInput::Create(Box::new(CreateInputs::new(
1301                DEF_ADDR,
1302                context_interface::CreateScheme::Create,
1303                0x42_U256,
1304                Bytes::copy_from_slice(&0x69_U256.to_be_bytes::<32>()),
1305                66917,
1306                0,
1307            )))),
1308        }),
1309        create2(@raw {
1310            bytecode: &[op::PUSH1, 0x69, op::PUSH0, op::MSTORE, op::PUSH1, 100, op::PUSH1, 32, op::PUSH0, op::PUSH1, 0x42, op::CREATE2],
1311            expected_return: InstructionResult::Stop,
1312            // NOTE: The address is pushed by the caller.
1313            expected_stack: &[],
1314            expected_memory: &0x69_U256.to_be_bytes::<32>(),
1315            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1316            expected_next_action: InterpreterAction::NewFrame(FrameInput::Create(Box::new(CreateInputs::new(
1317                DEF_ADDR,
1318                context_interface::CreateScheme::Create2 { salt: 100_U256 },
1319                0x42_U256,
1320                Bytes::copy_from_slice(&0x69_U256.to_be_bytes::<32>()),
1321                66908,
1322                0,
1323            )))),
1324        }),
1325        call(@raw {
1326            bytecode: &[
1327                op::PUSH1, 1, // ret length
1328                op::PUSH1, 2, // ret offset
1329                op::PUSH1, 3, // args length
1330                op::PUSH1, 4, // args offset
1331                op::PUSH1, 5, // value
1332                op::PUSH1, 6, // address
1333                op::PUSH1, 7, // gas
1334                op::CALL,
1335            ],
1336            expected_return: InstructionResult::Stop,
1337            // NOTE: The return is pushed by the caller.
1338            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1339            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1340            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1341        }),
1342        callcode(@raw {
1343            bytecode: &[
1344                op::PUSH1, 1, // ret length
1345                op::PUSH1, 2, // ret offset
1346                op::PUSH1, 3, // args length
1347                op::PUSH1, 4, // args offset
1348                op::PUSH1, 5, // value
1349                op::PUSH1, 6, // address
1350                op::PUSH1, 7, // gas
1351                op::CALLCODE,
1352            ],
1353            expected_return: InstructionResult::Stop,
1354            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1355            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1356            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1357        }),
1358        delegatecall(@raw {
1359            bytecode: &[
1360                op::PUSH1, 1, // ret length
1361                op::PUSH1, 2, // ret offset
1362                op::PUSH1, 3, // args length
1363                op::PUSH1, 4, // args offset
1364                op::PUSH1, 5, // address
1365                op::PUSH1, 6, // gas
1366                op::DELEGATECALL,
1367            ],
1368            expected_return: InstructionResult::Stop,
1369            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1370            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1371            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1372        }),
1373        staticcall(@raw {
1374            bytecode: &[
1375                op::PUSH1, 1, // ret length
1376                op::PUSH1, 2, // ret offset
1377                op::PUSH1, 3, // args length
1378                op::PUSH1, 4, // args offset
1379                op::PUSH1, 5, // address
1380                op::PUSH1, 6, // gas
1381                op::STATICCALL,
1382            ],
1383            expected_return: InstructionResult::Stop,
1384            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1385            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1386            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1387        }),
1388        ret_empty_dynamic_offset(@raw {
1389            bytecode: &[op::PUSH0, op::ADDRESS, op::RETURN],
1390            expected_return: InstructionResult::Return,
1391            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1392        }),
1393        ret(@raw {
1394            bytecode: &[op::PUSH1, 0x69, op::PUSH0, op::MSTORE, op::PUSH1, 32, op::PUSH0, op::RETURN],
1395            expected_return: InstructionResult::Return,
1396            expected_memory: &0x69_U256.to_be_bytes::<32>(),
1397            expected_gas: 3 + 2 + (3 + memory_gas_cost(1)) + 3 + 2,
1398            expected_next_action: InterpreterAction::Return(
1399                InterpreterResult {
1400                    result: InstructionResult::Return,
1401                    output: Bytes::copy_from_slice(&0x69_U256.to_be_bytes::<32>()),
1402                    gas: {
1403                        let mut gas = Gas::new(DEF_GAS_LIMIT);
1404                        assert!(gas.record_regular_cost(3 + 2 + (3 + memory_gas_cost(1)) + 3 + 2));
1405                        gas
1406                    },
1407                }
1408            ),
1409        }),
1410        revert(@raw {
1411            bytecode: &[op::PUSH1, 0x69, op::PUSH0, op::MSTORE, op::PUSH1, 32, op::PUSH0, op::REVERT],
1412            expected_return: InstructionResult::Revert,
1413            expected_memory: &0x69_U256.to_be_bytes::<32>(),
1414            expected_gas: 3 + 2 + (3 + memory_gas_cost(1)) + 3 + 2,
1415            expected_next_action: InterpreterAction::Return(
1416                InterpreterResult {
1417                    result: InstructionResult::Revert,
1418                    output: Bytes::copy_from_slice(&0x69_U256.to_be_bytes::<32>()),
1419                    gas: {
1420                        let mut gas = Gas::new(DEF_GAS_LIMIT);
1421                        assert!(gas.record_regular_cost(3 + 2 + (3 + memory_gas_cost(1)) + 3 + 2));
1422                        gas
1423                    },
1424                }
1425            ),
1426        }),
1427        selfdestruct(@raw {
1428            bytecode: &[op::PUSH1, 0x69, op::SELFDESTRUCT, op::INVALID],
1429            expected_return: InstructionResult::SelfDestruct,
1430            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1431            assert_host: Some(|host| {
1432                assert_eq!(host.selfdestructs, [(DEF_ADDR, Address::with_last_byte(0x69))]);
1433            }),
1434        }),
1435        selfdestruct_preserves_remaining_stack(@raw {
1436            bytecode: &[op::NUMBER, op::NUMBER, op::SELFDESTRUCT],
1437            spec_id: SpecId::BERLIN,
1438            expected_return: InstructionResult::SelfDestruct,
1439            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
1440            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1441        }),
1442        // Static-context SELFDESTRUCT: gas < 5000 → OOG before static-call check.
1443        selfdestruct_static_oog(@raw {
1444            bytecode: &[op::PUSH1, 0x01, op::SELFDESTRUCT],
1445            is_static: true,
1446            gas_limit: 4000,
1447            expected_return: InstructionResult::OutOfGas,
1448            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1449        }),
1450        // Static-context SELFDESTRUCT: gas >= 5000 → charges 5000, then StateChangeDuringStaticCall.
1451        selfdestruct_static_enough_gas(@raw {
1452            bytecode: &[op::PUSH1, 0x01, op::SELFDESTRUCT],
1453            is_static: true,
1454            expected_return: InstructionResult::StateChangeDuringStaticCall,
1455            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1456        }),
1457    }
1458
1459    // Tests for CALL gas accounting fix.
1460    // JIT CALL gas must match interpreter across specs and value-transfer scenarios.
1461    call_gas {
1462        call_value_cancun(@raw {
1463            bytecode: &[
1464                op::PUSH1, 1,   // ret length
1465                op::PUSH1, 2,   // ret offset
1466                op::PUSH1, 3,   // args length
1467                op::PUSH1, 4,   // args offset
1468                op::PUSH1, 5,   // value (non-zero → triggers value transfer gas)
1469                op::PUSH1, 6,   // address
1470                op::PUSH1, 7,   // gas
1471                op::CALL,
1472            ],
1473            spec_id: SpecId::CANCUN,
1474            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1475            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1476            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1477            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1478        }),
1479        call_no_value_cancun(@raw {
1480            bytecode: &[
1481                op::PUSH1, 1,   // ret length
1482                op::PUSH1, 2,   // ret offset
1483                op::PUSH1, 3,   // args length
1484                op::PUSH1, 4,   // args offset
1485                op::PUSH0,      // value = 0 (no transfer)
1486                op::PUSH1, 6,   // address
1487                op::PUSH1, 7,   // gas
1488                op::CALL,
1489            ],
1490            spec_id: SpecId::CANCUN,
1491            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1492            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1493            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1494            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1495        }),
1496        staticcall_cancun(@raw {
1497            bytecode: &[
1498                op::PUSH1, 1,   // ret length
1499                op::PUSH1, 2,   // ret offset
1500                op::PUSH1, 3,   // args length
1501                op::PUSH1, 4,   // args offset
1502                op::PUSH1, 5,   // address
1503                op::PUSH1, 6,   // gas
1504                op::STATICCALL,
1505            ],
1506            spec_id: SpecId::CANCUN,
1507            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1508            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1509            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1510            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1511        }),
1512        delegatecall_cancun(@raw {
1513            bytecode: &[
1514                op::PUSH1, 1,   // ret length
1515                op::PUSH1, 2,   // ret offset
1516                op::PUSH1, 3,   // args length
1517                op::PUSH1, 4,   // args offset
1518                op::PUSH1, 5,   // address
1519                op::PUSH1, 6,   // gas
1520                op::DELEGATECALL,
1521            ],
1522            spec_id: SpecId::CANCUN,
1523            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1524            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1525            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1526            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1527        }),
1528
1529        // Pre-Berlin specs: different static gas costs for CALL (700 vs 100).
1530        call_value_petersburg(@raw {
1531            bytecode: &[
1532                op::PUSH1, 1,   // ret length
1533                op::PUSH1, 2,   // ret offset
1534                op::PUSH1, 3,   // args length
1535                op::PUSH1, 4,   // args offset
1536                op::PUSH1, 5,   // value (non-zero)
1537                op::PUSH1, 6,   // address
1538                op::PUSH1, 7,   // gas
1539                op::CALL,
1540            ],
1541            spec_id: SpecId::PETERSBURG,
1542            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1543            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1544            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1545            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1546        }),
1547        call_no_value_petersburg(@raw {
1548            bytecode: &[
1549                op::PUSH1, 1,   // ret length
1550                op::PUSH1, 2,   // ret offset
1551                op::PUSH1, 3,   // args length
1552                op::PUSH1, 4,   // args offset
1553                op::PUSH1, 0,   // value = 0
1554                op::PUSH1, 6,   // address
1555                op::PUSH1, 7,   // gas
1556                op::CALL,
1557            ],
1558            spec_id: SpecId::PETERSBURG,
1559            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1560            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1561            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1562            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1563        }),
1564        staticcall_petersburg(@raw {
1565            bytecode: &[
1566                op::PUSH1, 1,   // ret length
1567                op::PUSH1, 2,   // ret offset
1568                op::PUSH1, 3,   // args length
1569                op::PUSH1, 4,   // args offset
1570                op::PUSH1, 5,   // address
1571                op::PUSH1, 6,   // gas
1572                op::STATICCALL,
1573            ],
1574            spec_id: SpecId::PETERSBURG,
1575            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1576            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1577            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1578            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1579        }),
1580        call_value_istanbul(@raw {
1581            bytecode: &[
1582                op::PUSH1, 1,   // ret length
1583                op::PUSH1, 2,   // ret offset
1584                op::PUSH1, 3,   // args length
1585                op::PUSH1, 4,   // args offset
1586                op::PUSH1, 5,   // value (non-zero)
1587                op::PUSH1, 6,   // address
1588                op::PUSH1, 7,   // gas
1589                op::CALL,
1590            ],
1591            spec_id: SpecId::ISTANBUL,
1592            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1593            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1594            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1595            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1596        }),
1597        call_no_value_istanbul(@raw {
1598            bytecode: &[
1599                op::PUSH1, 1,   // ret length
1600                op::PUSH1, 2,   // ret offset
1601                op::PUSH1, 3,   // args length
1602                op::PUSH1, 4,   // args offset
1603                op::PUSH1, 0,   // value = 0
1604                op::PUSH1, 6,   // address
1605                op::PUSH1, 7,   // gas
1606                op::CALL,
1607            ],
1608            spec_id: SpecId::ISTANBUL,
1609            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1610            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1611            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1612            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1613        }),
1614        staticcall_istanbul(@raw {
1615            bytecode: &[
1616                op::PUSH1, 1,   // ret length
1617                op::PUSH1, 2,   // ret offset
1618                op::PUSH1, 3,   // args length
1619                op::PUSH1, 4,   // args offset
1620                op::PUSH1, 5,   // address
1621                op::PUSH1, 6,   // gas
1622                op::STATICCALL,
1623            ],
1624            spec_id: SpecId::ISTANBUL,
1625            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1626            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1627            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1628            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1629        }),
1630        call_value_byzantium(@raw {
1631            bytecode: &[
1632                op::PUSH1, 1,   // ret length
1633                op::PUSH1, 2,   // ret offset
1634                op::PUSH1, 3,   // args length
1635                op::PUSH1, 4,   // args offset
1636                op::PUSH1, 5,   // value (non-zero)
1637                op::PUSH1, 6,   // address
1638                op::PUSH1, 7,   // gas
1639                op::CALL,
1640            ],
1641            spec_id: SpecId::BYZANTIUM,
1642            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1643            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1644            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1645            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1646        }),
1647        call_high_gas_value_istanbul(@raw {
1648            bytecode: &[
1649                op::PUSH1, 32,       // ret length
1650                op::PUSH1, 0,        // ret offset
1651                op::PUSH1, 64,       // args length
1652                op::PUSH1, 0,        // args offset
1653                op::PUSH1, 100,      // value = 100
1654                op::PUSH1, 0x69,     // address
1655                op::PUSH2, 0xFF, 0xFF, // gas = 65535
1656                op::CALL,
1657            ],
1658            spec_id: SpecId::ISTANBUL,
1659            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1660            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1661            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1662            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1663        }),
1664        // Muir Glacier uses ISTANBUL gas table.
1665        call_value_muir_glacier(@raw {
1666            bytecode: &[
1667                op::PUSH1, 1,   // ret length
1668                op::PUSH1, 2,   // ret offset
1669                op::PUSH1, 3,   // args length
1670                op::PUSH1, 4,   // args offset
1671                op::PUSH1, 5,   // value (non-zero)
1672                op::PUSH1, 6,   // address
1673                op::PUSH1, 7,   // gas
1674                op::CALL,
1675            ],
1676            spec_id: SpecId::ISTANBUL,
1677            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1678            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1679            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1680            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1681        }),
1682        call_high_gas_value(@raw {
1683            bytecode: &[
1684                op::PUSH1, 32,       // ret length
1685                op::PUSH0,           // ret offset
1686                op::PUSH1, 64,       // args length
1687                op::PUSH0,           // args offset
1688                op::PUSH1, 100,      // value = 100
1689                op::PUSH1, 0x69,     // address
1690                op::PUSH2, 0xFF, 0xFF, // gas = 65535
1691                op::CALL,
1692            ],
1693            spec_id: SpecId::CANCUN,
1694            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1695            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1696            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1697            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1698        }),
1699        call_known_bytecode(@raw {
1700            bytecode: &[
1701                op::PUSH1, 0,    // ret length
1702                op::PUSH1, 0,    // ret offset
1703                op::PUSH1, 0,    // args length
1704                op::PUSH1, 0,    // args offset
1705                op::PUSH1, 0,    // value
1706                op::PUSH1, 0x69, // address (OTHER_ADDR = 0x69..69, has code in TestHost)
1707                op::PUSH1, 7,    // gas
1708                op::CALL,
1709            ],
1710            spec_id: SpecId::CANCUN,
1711            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1712            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1713            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1714            expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
1715            assert_ecx: Some(|ecx| {
1716                if let Some(InterpreterAction::NewFrame(FrameInput::Call(call_inputs))) =
1717                    ecx.next_action.as_ref()
1718                {
1719                    let (code_hash, _) = &call_inputs.known_bytecode;
1720                    assert!(
1721                        !code_hash.is_zero(),
1722                        "CALL must populate known_bytecode via load_account_delegated; \
1723                         got zero code hash (old code path that skips delegation resolution)"
1724                    );
1725                }
1726            }),
1727        }),
1728    }
1729
1730    // Tests for i256 correctness under LLVM optimization (a09436d1).
1731    // These exercise full 256-bit (4 x i64 lane) arithmetic that LLVM may miscompile
1732    // if i256 load/store alignment or alias attributes are incorrect.
1733    i256_lanes {
1734        // ADD of two large 256-bit values that use all 4 i64 lanes.
1735        add_full_width(op::ADD,
1736            0xDEADBEEF_12345678_ABCDEF01_23456789_FEDCBA98_76543210_01234567_89ABCDEF_U256,
1737            0x11111111_22222222_33333333_44444444_55555555_66666666_77777777_88888888_U256
1738            => 0xDEADBEEF_12345678_ABCDEF01_23456789_FEDCBA98_76543210_01234567_89ABCDEF_U256
1739             + 0x11111111_22222222_33333333_44444444_55555555_66666666_77777777_88888888_U256
1740        ),
1741        // MUL of two values producing a result spanning all lanes.
1742        mul_full_width(op::MUL,
1743            0x00000000_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_U256,
1744            0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000002_U256
1745            => 0x00000000_00000000_00000000_00000001_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFE_U256
1746        ),
1747        // SUB across lane boundaries (borrow propagation through all 4 lanes).
1748        sub_cross_lane(op::SUB,
1749            0x00000000_00000000_00000000_00000001_00000000_00000000_00000000_00000000_U256,
1750            0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001_U256
1751            => 0x00000000_00000000_00000000_00000000_FFFFFFFF_FFFFFFFF_FFFFFFFF_FFFFFFFF_U256
1752        ),
1753        // Bitwise OR: each lane has different bit patterns.
1754        or_all_lanes(op::OR,
1755            0xFF000000_00000000_00FF0000_00000000_0000FF00_00000000_000000FF_00000000_U256,
1756            0x00000000_FF000000_00000000_00FF0000_00000000_0000FF00_00000000_000000FF_U256
1757            => 0xFF000000_FF000000_00FF0000_00FF0000_0000FF00_0000FF00_000000FF_000000FF_U256
1758        ),
1759        // SHL: shift left across lane boundaries (operand order: shift, value).
1760        shl_cross_lane(op::SHL,
1761            64_U256,
1762            0x00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000001_U256
1763            => 0x00000000_00000000_00000000_00000000_00000000_00000001_00000000_00000000_U256
1764        ),
1765        // SHR: shift right across lane boundaries (operand order: shift, value).
1766        shr_cross_lane(op::SHR,
1767            64_U256,
1768            0x00000000_00000001_00000000_00000000_00000000_00000000_00000000_00000000_U256
1769            => 0x00000000_00000000_00000000_00000001_00000000_00000000_00000000_00000000_U256
1770        ),
1771    }
1772
1773    // Tests for CODECOPY correctness.
1774    // CODECOPY must read bytecode from EvmContext at runtime, not from embedded compile-time
1775    // pointers, so that AOT-cached code works after deserialization.
1776    codecopy_fix {
1777        codecopy_exact(@raw {
1778            bytecode: &[op::PUSH1, 5, op::PUSH0, op::PUSH0, op::CODECOPY],
1779            expected_memory: &hex!("60055f5f39000000000000000000000000000000000000000000000000000000"),
1780            expected_gas: 3 + 2 + 2 + (verylowcopy_cost(32).unwrap() + memory_gas_cost(1)),
1781        }),
1782        codecopy_offset(@raw {
1783            bytecode: &[op::PUSH1, 3, op::PUSH1, 2, op::PUSH0, op::CODECOPY],
1784            expected_memory: &hex!("60025f0000000000000000000000000000000000000000000000000000000000"),
1785            expected_gas: 3 + 3 + 2 + (verylowcopy_cost(32).unwrap() + memory_gas_cost(1)),
1786        }),
1787        codecopy_beyond(@raw {
1788            bytecode: &[op::PUSH1, 10, op::PUSH0, op::PUSH0, op::CODECOPY],
1789            expected_memory: &hex!("600a5f5f39000000000000000000000000000000000000000000000000000000"),
1790            expected_gas: 3 + 2 + 2 + (verylowcopy_cost(32).unwrap() + memory_gas_cost(1)),
1791        }),
1792        codecopy_longer(@raw {
1793            bytecode: &[
1794                op::PUSH1, 42,  // dummy: push 42
1795                op::POP,        // pop it
1796                op::PUSH1, 99,  // another dummy
1797                op::POP,        // pop it
1798                op::PUSH1, 12,  // length = 12 (exact bytecode length)
1799                op::PUSH0,      // source offset = 0
1800                op::PUSH0,      // dest offset = 0
1801                op::CODECOPY,   // copy
1802            ],
1803            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
1804            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1805        }),
1806        // Red-green test: CODECOPY must read bytecode from EvmContext at runtime.
1807        // We swap bytecode ptr to fake data via modify_ecx. With the fix, CODECOPY reads the
1808        // fake data; without it, it would still read the original bytecode.
1809        codecopy_runtime_ptr(@raw {
1810            bytecode: &[op::PUSH1, 5, op::PUSH0, op::PUSH0, op::CODECOPY],
1811            modify_ecx: Some(|ecx| {
1812                static FAKE_CODE: [u8; 5] = [0xAA, 0xBB, 0xCC, 0xDD, 0xEE];
1813                ecx.bytecode = &FAKE_CODE as *const [u8];
1814            }),
1815            expected_return: InstructionResult::Stop,
1816            expected_memory: &hex!("AABBCCDDEE000000000000000000000000000000000000000000000000000000"),
1817            expected_gas: 3 + 2 + 2 + (verylowcopy_cost(32).unwrap() + memory_gas_cost(1)),
1818        }),
1819    }
1820
1821    dedup {
1822        // Transitive redirect chains in dedup caused MULTI_JUMP case PCs to resolve to
1823        // stale dead entry blocks, producing InvalidJump on valid bytecode.
1824        //
1825        // t0/t1/t2 are byte-identical trampolines (JUMPDEST JUMP) that get deduped into
1826        // a chain t2->t1->t0. `fn` dispatches to t0/t1/t2 via multi-jump. Without
1827        // transitive compression, t2's inst_entry points at the dead t1 block.
1828        //
1829        // Path taken at runtime: entry -> path1 -> path2 -> fn -> t2 -> u1 -> STOP
1830        transitive_redirect_multi_jump(@raw {
1831            bytecode: &asm("
1832                ; entry: dispatch on CALLDATASIZE (nonzero -> path1)
1833                CALLDATASIZE
1834                PUSH %path1
1835                JUMPI
1836                ; not taken: u0 via t0
1837                PUSH %u0
1838                PUSH %t0
1839                JUMP
1840
1841            path1:
1842                JUMPDEST
1843                CALLVALUE
1844                PUSH %path2
1845                JUMPI
1846                ; not taken: u1 via t1 via fn
1847                PUSH %u1
1848                PUSH %t1
1849                PUSH %fn
1850                JUMP
1851
1852            path2:
1853                JUMPDEST
1854                ; u1 via t2 via fn
1855                PUSH %u1
1856                PUSH %t2
1857                PUSH %fn
1858                JUMP
1859
1860            dead0: INVALID
1861            dead1: INVALID
1862            dead2: INVALID
1863
1864            ; three byte-identical trampolines that get deduped (t2->t1->t0)
1865            t0: JUMPDEST  JUMP
1866            t1: JUMPDEST  JUMP
1867            t2: JUMPDEST  JUMP
1868
1869            u0: JUMPDEST  STOP
1870            u1: JUMPDEST  STOP
1871
1872            fn: JUMPDEST  JUMP
1873            "),
1874            spec_id: SpecId::CANCUN,
1875            expected_return: RETURN_WHAT_INTERPRETER_SAYS,
1876            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
1877            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1878        }),
1879
1880        // Dedup merges two byte-identical MULTI_JUMP dispatcher blocks after their
1881        // target blocks are deduped, but only the canonical dispatcher's case PCs
1882        // were emitted in the switch. DEF_CD has nonzero words, so the bytecode takes the
1883        // path through the second dispatcher (the one that gets deduped away).
1884        //
1885        // Each path pushes (stop_pc, dispatcher_pc) then JUMPs to the dispatcher.
1886        // fn1 and fn2 are byte-identical dispatchers (JUMPDEST JUMP) that get deduped.
1887        dedup_multi_jump_dispatcher(@raw {
1888            bytecode: &asm("
1889                ; dispatch on first calldata word
1890                PUSH0
1891                CALLDATALOAD
1892                PUSH %d1
1893                JUMPI
1894
1895                ; dispatch on second calldata word
1896                PUSH 0x20
1897                CALLDATALOAD
1898                PUSH %d0
1899                JUMPI
1900
1901                ; neither taken: stop0 via fn1
1902                PUSH %stop0
1903                PUSH %fn1
1904                JUMP
1905
1906            d0:
1907                JUMPDEST
1908                PUSH %stop1
1909                PUSH %fn1
1910                JUMP
1911
1912            d1:
1913                JUMPDEST
1914                PUSH 0x20
1915                CALLDATALOAD
1916                PUSH %d1_taken
1917                JUMPI
1918                ; not taken: stop2 via fn2
1919                PUSH %stop2
1920                PUSH %fn2
1921                JUMP
1922
1923            d1_taken:
1924                JUMPDEST
1925                PUSH %stop3
1926                PUSH %fn2
1927                JUMP
1928
1929            stop0: JUMPDEST  STOP
1930            stop1: JUMPDEST  STOP
1931            stop2: JUMPDEST  STOP
1932            stop3: JUMPDEST  STOP
1933
1934            ; two byte-identical dispatchers that get deduped
1935            fn1: JUMPDEST  JUMP
1936            fn2: JUMPDEST  JUMP
1937            "),
1938            expected_return: InstructionResult::Stop,
1939            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1940        }),
1941    }
1942
1943    regressions {
1944        // Dedup must not poison DSE via lost leader marks.
1945        //
1946        // When a JUMPI's fall-through block gets deduped, the leader mark on the first dead
1947        // instruction must propagate to the next alive instruction. Without this, the JUMPI
1948        // block absorbs the next alive instruction (e.g. INVALID) as its terminator, which
1949        // causes DSE to treat all exit stack positions as dead, incorrectly NOOP-ing live PUSHes.
1950        //
1951        // inspect_stack must be off so DSE's diverging-terminator optimisation is active.
1952        dedup_leader_propagation(@raw {
1953            bytecode: &asm("
1954            entry:
1955                JUMPDEST
1956                PUSH 0x00       ; cond = 0
1957                PUSH %jumpi2
1958                JUMPI           ; not taken
1959                ; canonical fall-through
1960                PUSH %jumpi2
1961                JUMP
1962
1963            jumpi2:
1964                JUMPDEST
1965                PUSH 0x2a       ; live-out value DSE must preserve
1966                CALLDATASIZE    ; condition (nonzero)
1967                PUSH %dest
1968                JUMPI           ; taken
1969                ; duplicate fall-through (same bytes as canonical -> deduped)
1970                PUSH %jumpi2
1971                JUMP
1972
1973                INVALID         ; alive after dead deduped block
1974
1975            dest:
1976                JUMPDEST
1977                PUSH 0x00
1978                MSTORE          ; mem[0] = 0x2a
1979                PUSH 0x20
1980                PUSH 0x00
1981                RETURN
1982            "),
1983            inspect_stack: Some(false),
1984            expected_return: InstructionResult::Return,
1985            expected_memory: &U256::from(0x2a).to_be_bytes::<32>(),
1986            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
1987            expected_next_action: InterpreterAction::Return(
1988                InterpreterResult {
1989                    result: InstructionResult::Return,
1990                    output: Bytes::copy_from_slice(&U256::from(0x2a).to_be_bytes::<32>()),
1991                    gas: Gas::new(GAS_WHAT_INTERPRETER_SAYS),
1992                }
1993            ),
1994        }),
1995
1996        // Same class of bug but triggered by a deduped reachable JUMPDEST block rather than
1997        // a JUMPI fall-through.
1998        //
1999        // Real-world trigger: tx 0x3a0ab5...31856 (block 5330710).
2000        dedup_jumpdest_leader(@raw {
2001            bytecode: &asm("
2002            entry:
2003                JUMPDEST
2004                PUSH 0x00
2005                CALLDATASIZE
2006                PUSH %alt_entry
2007                JUMPI
2008                ; not-taken -> dup_ret (makes it reachable for analysis)
2009                PUSH %dup_ret
2010                JUMP
2011
2012            canonical_ret:
2013                JUMPDEST
2014                PUSH %dest
2015                JUMP
2016
2017            alt_entry:
2018                JUMPDEST
2019                DUP1
2020                POP
2021                POP
2022                PUSH 0x2a       ; <- DSE must NOT kill
2023
2024            dup_ret:
2025                ; byte-identical to canonical_ret -> deduped
2026                JUMPDEST
2027                PUSH %dest
2028                JUMP
2029
2030                INVALID         ; alive after dead dup_ret
2031
2032            dest:
2033                JUMPDEST
2034                PUSH 0x00
2035                MSTORE
2036                PUSH 0x20
2037                PUSH 0x00
2038                RETURN
2039            "),
2040            inspect_stack: Some(false),
2041            expected_return: InstructionResult::Return,
2042            expected_memory: &U256::from(0x2a).to_be_bytes::<32>(),
2043            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
2044            expected_next_action: InterpreterAction::Return(
2045                InterpreterResult {
2046                    result: InstructionResult::Return,
2047                    output: Bytes::copy_from_slice(&U256::from(0x2a).to_be_bytes::<32>()),
2048                    gas: Gas::new(GAS_WHAT_INTERPRETER_SAYS),
2049                }
2050            ),
2051        }),
2052
2053        dedup_false_jumpi_non_jumpdest_fallthrough(@raw {
2054            bytecode: &asm("
2055                CALLDATASIZE
2056                PUSH %path2
2057                JUMPI
2058
2059                PUSH0
2060                PUSH %done
2061                JUMPI
2062                PUSH0
2063                PUSH0
2064                REVERT
2065
2066            path2:
2067                JUMPDEST
2068                PUSH0
2069                PUSH %done
2070                JUMPI
2071                PUSH0
2072                PUSH0
2073                REVERT
2074
2075            done:
2076                JUMPDEST
2077                STOP
2078            "),
2079            expected_return: InstructionResult::Revert,
2080            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
2081        }),
2082
2083        dedup_fallthrough_jump_tail_charges_jump_gas(@raw {
2084            bytecode: &asm("
2085                PUSH %done
2086                CALLER
2087                PUSH %path2
2088                JUMPI
2089                JUMP
2090
2091            path2:
2092                JUMPDEST
2093                PUSH0
2094                PUSH %other
2095                JUMPI
2096                JUMP
2097
2098            other:
2099                JUMPDEST
2100                STOP
2101
2102            done:
2103                JUMPDEST
2104                STOP
2105            "),
2106            expected_return: InstructionResult::Stop,
2107            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
2108        }),
2109
2110        dedup_fallthrough_redirect_materializes_stack(@raw {
2111            bytecode: &asm("
2112                CALLVALUE
2113                PUSH 123456789
2114                SUB
2115                PUSH %join_a
2116                JUMPI
2117                CALLVALUE
2118                PUSH 123456789
2119                SUB
2120                PUSH %join_b
2121                JUMPI
2122
2123                CALLDATASIZE
2124                PUSH %case_b_entry
2125                JUMPI
2126
2127                PUSH0
2128                PUSH0
2129                PUSH %case_a
2130                JUMP
2131
2132            case_a:
2133                JUMPDEST
2134                PUSH 0xaa
2135                SWAP2
2136                POP
2137            join_a:
2138                JUMPDEST
2139                PUSH %done
2140                JUMP
2141
2142            case_b_entry:
2143                JUMPDEST
2144                PUSH0
2145                PUSH0
2146                PUSH %case_b
2147                JUMP
2148
2149            case_b:
2150                JUMPDEST
2151                PUSH 0xbb
2152                SWAP2
2153                POP
2154            join_b:
2155                JUMPDEST
2156                PUSH %done
2157                JUMP
2158
2159            done:
2160                JUMPDEST
2161                POP
2162                ISZERO
2163                PUSH %bad
2164                JUMPI
2165                STOP
2166
2167            bad:
2168                JUMPDEST
2169                PUSH0
2170                PUSH0
2171                REVERT
2172            "),
2173            inspect_stack: Some(false),
2174            expected_return: InstructionResult::Stop,
2175            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
2176        }),
2177
2178        // Disabled opcodes must not poison stack sections.
2179        //
2180        // When a disabled opcode (e.g. TSTORE before Cancun) follows executable instructions
2181        // in the same section, its stack I/O requirements must not be folded into the
2182        // section-head underflow check.
2183        //
2184        // CALLDATASIZE(0->1) ; TSTORE(2->0, disabled before Cancun).
2185        // The interpreter executes CALLDATASIZE then halts at TSTORE with NotActivated.
2186        calldatasize_tstore_shanghai(@raw {
2187            bytecode: &[op::CALLDATASIZE, op::TSTORE],
2188            spec_id: SpecId::SHANGHAI,
2189            expected_return: InstructionResult::NotActivated,
2190            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
2191        }),
2192
2193        // PUSH0(0->1) ; TLOAD(1->1, disabled before Cancun).
2194        push0_tload_shanghai(@raw {
2195            bytecode: &[op::PUSH0, op::TLOAD],
2196            spec_id: SpecId::SHANGHAI,
2197            expected_return: InstructionResult::NotActivated,
2198            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
2199        }),
2200
2201        // Mismatched costs in < BERLIN.
2202        // GeneralStateTests/stSolidityTest/TestKeywords.json
2203        st_solidity_keywords(@raw {
2204            bytecode: &hex!("7c01000000000000000000000000000000000000000000000000000000006000350463380e439681146037578063c040622614604757005b603d6084565b8060005260206000f35b604d6057565b8060005260206000f35b6000605f6084565b600060006101000a81548160ff0219169083021790555060ff60016000540416905090565b6000808160011560cd575b600a82121560a157600190910190608f565b81600a1460ac5760c9565b50600a5b60008160ff16111560c85760019182900391900360b0565b5b60d5565b6000925060ed565b8160001460e05760e8565b6001925060ed565b600092505b50509056"),
2205            spec_id: SpecId::ISTANBUL,
2206            modify_ecx: Some(|ecx| {
2207                ecx.input.call_value = 1_U256;
2208                ecx.input.input = interpreter::CallInput::Bytes(Bytes::from(&hex!("c0406226")));
2209            }),
2210            // Note: Cannot use RETURN_WHAT_INTERPRETER_SAYS here because modify_ecx
2211            // only modifies the JIT context, not the interpreter's input. The interpreter
2212            // runs with default call data which doesn't match the function selector.
2213            expected_return: InstructionResult::Return,
2214            expected_stack: STACK_WHAT_INTERPRETER_SAYS,
2215            expected_gas: GAS_WHAT_INTERPRETER_SAYS,
2216            expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
2217            expected_next_action: InterpreterAction::Return(
2218                InterpreterResult {
2219                    result: InstructionResult::Return,
2220                    output: Bytes::copy_from_slice(&1_U256.to_be_bytes::<32>()),
2221                    gas: Gas::new(GAS_WHAT_INTERPRETER_SAYS),
2222                }
2223            ),
2224            assert_host: Some(|host| {
2225                assert_eq!(host.storage.get(&0_U256), Some(&1_U256));
2226            }),
2227        }),
2228    }
2229}
2230
2231fn bytecode_unop(op: u8, a: U256) -> [u8; 34] {
2232    let mut code = [0; 34];
2233    let mut i = 0;
2234    build_push32!(code[i], a);
2235    code[i] = op;
2236    code
2237}
2238
2239fn bytecode_binop(op: u8, a: U256, b: U256) -> [u8; 67] {
2240    let mut code = [0; 67];
2241    let mut i = 0;
2242    build_push32!(code[i], b);
2243    build_push32!(code[i], a);
2244    code[i] = op;
2245    code
2246}
2247
2248fn bytecode_ternop(op: u8, a: U256, b: U256, c: U256) -> [u8; 100] {
2249    let mut code = [0; 100];
2250    let mut i = 0;
2251    build_push32!(code[i], c);
2252    build_push32!(code[i], b);
2253    build_push32!(code[i], a);
2254    code[i] = op;
2255    code
2256}
2257
2258/// Build opaque unop bytecode: MSTORE(a, 0), MLOAD(0), `<op>`.
2259fn bytecode_unop_opaque(opcode: u8, a: U256) -> Vec<u8> {
2260    let mut code = Vec::with_capacity(64);
2261    code.push(op::PUSH32);
2262    code.extend_from_slice(&a.to_be_bytes::<32>());
2263    code.push(op::PUSH1);
2264    code.push(0x00);
2265    code.push(op::MSTORE);
2266    code.push(op::PUSH1);
2267    code.push(0x00);
2268    code.push(op::MLOAD);
2269    code.push(opcode);
2270    code
2271}
2272
2273fn push_const_or_load(code: &mut Vec<u8>, value: U256, is_const: bool, offset: u8) {
2274    if is_const {
2275        code.push(op::PUSH32);
2276        code.extend_from_slice(&value.to_be_bytes::<32>());
2277    } else {
2278        code.push(op::PUSH1);
2279        code.push(offset);
2280        code.push(op::MLOAD);
2281    }
2282}
2283
2284fn store_dynamic_operands(code: &mut Vec<u8>, operands: &[(U256, bool, u8)]) {
2285    for &(value, is_const, offset) in operands {
2286        if !is_const {
2287            code.push(op::PUSH32);
2288            code.extend_from_slice(&value.to_be_bytes::<32>());
2289            code.push(op::PUSH1);
2290            code.push(offset);
2291            code.push(op::MSTORE);
2292        }
2293    }
2294}
2295
2296fn bytecode_binop_mixed(opcode: u8, a: U256, b: U256, a_const: bool, b_const: bool) -> Vec<u8> {
2297    let mut code = Vec::with_capacity(128);
2298    store_dynamic_operands(&mut code, &[(a, a_const, 0x00), (b, b_const, 0x20)]);
2299    push_const_or_load(&mut code, b, b_const, 0x20);
2300    push_const_or_load(&mut code, a, a_const, 0x00);
2301    code.push(opcode);
2302    code
2303}
2304
2305fn bytecode_ternop_mixed(
2306    opcode: u8,
2307    a: U256,
2308    b: U256,
2309    c: U256,
2310    a_const: bool,
2311    b_const: bool,
2312    c_const: bool,
2313) -> Vec<u8> {
2314    let mut code = Vec::with_capacity(192);
2315    store_dynamic_operands(
2316        &mut code,
2317        &[(a, a_const, 0x00), (b, b_const, 0x20), (c, c_const, 0x40)],
2318    );
2319    push_const_or_load(&mut code, c, c_const, 0x40);
2320    push_const_or_load(&mut code, b, b_const, 0x20);
2321    push_const_or_load(&mut code, a, a_const, 0x00);
2322    code.push(opcode);
2323    code
2324}
2325
2326fn asm(s: &str) -> Vec<u8> {
2327    crate::parse_asm(s).unwrap()
2328}