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