revm_interpreter/instructions/
control.rs

1use crate::{
2    gas,
3    interpreter::Interpreter,
4    interpreter_types::{
5        EofCodeInfo, Immediates, InterpreterTypes, Jumps, LoopControl, MemoryTr, RuntimeFlag,
6        StackTr, SubRoutineStack,
7    },
8    Host, InstructionResult, InterpreterAction, InterpreterResult,
9};
10use primitives::{Bytes, U256};
11
12pub fn rjump<WIRE: InterpreterTypes, H: ?Sized>(
13    interpreter: &mut Interpreter<WIRE>,
14    _host: &mut H,
15) {
16    require_eof!(interpreter);
17    gas!(interpreter, gas::BASE);
18    let offset = interpreter.bytecode.read_i16() as isize;
19    // In spec it is +3 but pointer is already incremented in
20    // `Interpreter::step` so for revm is +2.
21    interpreter.bytecode.relative_jump(offset + 2);
22}
23
24pub fn rjumpi<WIRE: InterpreterTypes, H: Host + ?Sized>(
25    interpreter: &mut Interpreter<WIRE>,
26    _host: &mut H,
27) {
28    require_eof!(interpreter);
29    gas!(interpreter, gas::CONDITION_JUMP_GAS);
30    popn!([condition], interpreter);
31    // In spec it is +3 but pointer is already incremented in
32    // `Interpreter::step` so for revm is +2.
33    let mut offset = 2;
34    if !condition.is_zero() {
35        offset += interpreter.bytecode.read_i16() as isize;
36    }
37
38    interpreter.bytecode.relative_jump(offset);
39}
40
41pub fn rjumpv<WIRE: InterpreterTypes, H: Host + ?Sized>(
42    interpreter: &mut Interpreter<WIRE>,
43    _host: &mut H,
44) {
45    require_eof!(interpreter);
46    gas!(interpreter, gas::CONDITION_JUMP_GAS);
47    popn!([case], interpreter);
48    let case = as_isize_saturated!(case);
49
50    let max_index = interpreter.bytecode.read_u8() as isize;
51    // For number of items we are adding 1 to max_index, multiply by 2 as each offset is 2 bytes
52    // and add 1 for max_index itself. Note that revm already incremented the instruction pointer
53    let mut offset = (max_index + 1) * 2 + 1;
54
55    if case <= max_index {
56        offset += interpreter.bytecode.read_offset_i16(1 + case * 2) as isize;
57    }
58    interpreter.bytecode.relative_jump(offset);
59}
60
61pub fn jump<WIRE: InterpreterTypes, H: Host + ?Sized>(
62    interpreter: &mut Interpreter<WIRE>,
63    _host: &mut H,
64) {
65    gas!(interpreter, gas::MID);
66    popn!([target], interpreter);
67    jump_inner(interpreter, target);
68}
69
70pub fn jumpi<WIRE: InterpreterTypes, H: Host + ?Sized>(
71    interpreter: &mut Interpreter<WIRE>,
72    _host: &mut H,
73) {
74    gas!(interpreter, gas::HIGH);
75    popn!([target, cond], interpreter);
76
77    if !cond.is_zero() {
78        jump_inner(interpreter, target);
79    }
80}
81
82#[inline]
83fn jump_inner<WIRE: InterpreterTypes>(interpreter: &mut Interpreter<WIRE>, target: U256) {
84    let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump);
85    if !interpreter.bytecode.is_valid_legacy_jump(target) {
86        interpreter
87            .control
88            .set_instruction_result(InstructionResult::InvalidJump);
89        return;
90    }
91    // SAFETY: `is_valid_jump` ensures that `dest` is in bounds.
92    interpreter.bytecode.absolute_jump(target);
93}
94
95pub fn jumpdest_or_nop<WIRE: InterpreterTypes, H: Host + ?Sized>(
96    interpreter: &mut Interpreter<WIRE>,
97    _host: &mut H,
98) {
99    gas!(interpreter, gas::JUMPDEST);
100}
101
102pub fn callf<WIRE: InterpreterTypes, H: Host + ?Sized>(
103    interpreter: &mut Interpreter<WIRE>,
104    _host: &mut H,
105) {
106    require_eof!(interpreter);
107    gas!(interpreter, gas::LOW);
108
109    let idx = interpreter.bytecode.read_u16() as usize;
110
111    // Get target types
112    let Some(types) = interpreter.bytecode.code_section_info(idx) else {
113        panic!("Invalid EOF in execution, expecting correct intermediate in callf")
114    };
115
116    // Check max stack height for target code section.
117    // Safe to subtract as max_stack_height is always more than inputs.
118    if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 {
119        interpreter
120            .control
121            .set_instruction_result(InstructionResult::StackOverflow);
122        return;
123    }
124
125    // Push current idx and PC to the callf stack.
126    // PC is incremented by 2 to point to the next instruction after callf.
127    if !(interpreter
128        .sub_routine
129        .push(interpreter.bytecode.pc() + 2, idx))
130    {
131        interpreter
132            .control
133            .set_instruction_result(InstructionResult::SubRoutineStackOverflow);
134        return;
135    };
136    let pc = interpreter
137        .bytecode
138        .code_section_pc(idx)
139        .expect("Invalid code section index");
140    interpreter.bytecode.absolute_jump(pc);
141}
142
143pub fn retf<WIRE: InterpreterTypes, H: Host + ?Sized>(
144    interpreter: &mut Interpreter<WIRE>,
145    _host: &mut H,
146) {
147    require_eof!(interpreter);
148    gas!(interpreter, gas::RETF_GAS);
149
150    let Some(jump) = interpreter.sub_routine.pop() else {
151        panic!("Expected function frame")
152    };
153
154    interpreter.bytecode.absolute_jump(jump);
155}
156
157pub fn jumpf<WIRE: InterpreterTypes, H: Host + ?Sized>(
158    interpreter: &mut Interpreter<WIRE>,
159    _host: &mut H,
160) {
161    require_eof!(interpreter);
162    gas!(interpreter, gas::LOW);
163
164    let idx = interpreter.bytecode.read_u16() as usize;
165
166    // Get target types
167    let types = interpreter
168        .bytecode
169        .code_section_info(idx)
170        .expect("Invalid code section index");
171
172    // Check max stack height for target code section.
173    // Safe to subtract as max_stack_height is always more than inputs.
174    if interpreter.stack.len() + (types.max_stack_size - types.inputs as u16) as usize > 1024 {
175        interpreter
176            .control
177            .set_instruction_result(InstructionResult::StackOverflow);
178        return;
179    }
180    interpreter.sub_routine.set_routine_idx(idx);
181    let pc = interpreter
182        .bytecode
183        .code_section_pc(idx)
184        .expect("Invalid code section index");
185    interpreter.bytecode.absolute_jump(pc);
186}
187
188pub fn pc<WIRE: InterpreterTypes, H: Host + ?Sized>(
189    interpreter: &mut Interpreter<WIRE>,
190    _host: &mut H,
191) {
192    gas!(interpreter, gas::BASE);
193    // - 1 because we have already advanced the instruction pointer in `Interpreter::step`
194    push!(interpreter, U256::from(interpreter.bytecode.pc() - 1));
195}
196
197#[inline]
198fn return_inner(
199    interpreter: &mut Interpreter<impl InterpreterTypes>,
200    instruction_result: InstructionResult,
201) {
202    // Zero gas cost
203    // gas!(interpreter, gas::ZERO)
204    popn!([offset, len], interpreter);
205    let len = as_usize_or_fail!(interpreter, len);
206    // Important: Offset must be ignored if len is zeros
207    let mut output = Bytes::default();
208    if len != 0 {
209        let offset = as_usize_or_fail!(interpreter, offset);
210        resize_memory!(interpreter, offset, len);
211        output = interpreter.memory.slice_len(offset, len).to_vec().into()
212    }
213
214    let gas = *interpreter.control.gas();
215    interpreter.control.set_next_action(
216        InterpreterAction::Return {
217            result: InterpreterResult {
218                output,
219                gas,
220                result: instruction_result,
221            },
222        },
223        instruction_result,
224    );
225}
226
227pub fn ret<WIRE: InterpreterTypes, H: Host + ?Sized>(
228    interpreter: &mut Interpreter<WIRE>,
229    _host: &mut H,
230) {
231    return_inner(interpreter, InstructionResult::Return);
232}
233
234/// EIP-140: REVERT instruction
235pub fn revert<WIRE: InterpreterTypes, H: Host + ?Sized>(
236    interpreter: &mut Interpreter<WIRE>,
237    _host: &mut H,
238) {
239    check!(interpreter, BYZANTIUM);
240    return_inner(interpreter, InstructionResult::Revert);
241}
242
243/// Stop opcode. This opcode halts the execution.
244pub fn stop<WIRE: InterpreterTypes, H: Host + ?Sized>(
245    interpreter: &mut Interpreter<WIRE>,
246    _host: &mut H,
247) {
248    interpreter
249        .control
250        .set_instruction_result(InstructionResult::Stop);
251}
252
253/// Invalid opcode. This opcode halts the execution.
254pub fn invalid<WIRE: InterpreterTypes, H: Host + ?Sized>(
255    interpreter: &mut Interpreter<WIRE>,
256    _host: &mut H,
257) {
258    interpreter
259        .control
260        .set_instruction_result(InstructionResult::InvalidFEOpcode);
261}
262
263/// Unknown opcode. This opcode halts the execution.
264pub fn unknown<WIRE: InterpreterTypes, H: Host + ?Sized>(
265    interpreter: &mut Interpreter<WIRE>,
266    _host: &mut H,
267) {
268    interpreter
269        .control
270        .set_instruction_result(InstructionResult::OpcodeNotFound);
271}
272
273// TODO : Test
274/*
275#[cfg(test)]
276mod test {
277    use super::*;
278    use crate::{table::make_instruction_table, DummyHost, Gas};
279    use bytecode::opcode::{CALLF, JUMPF, NOP, RETF, RJUMP, RJUMPI, RJUMPV, STOP};
280    use bytecode::{
281        eof::{Eof, TypesSection},
282        Bytecode,
283    };
284    use primitives::bytes;
285    use specification::hardfork::SpecId;
286    use std::sync::Arc;
287    use context_interface::DefaultEthereumWiring;
288
289    #[test]
290    fn rjump() {
291        let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
292        let mut host = DummyHost::default();
293        let mut interp =
294            Interpreter::new_bytecode(Bytecode::LegacyRaw([RJUMP, 0x00, 0x02, STOP, STOP].into()));
295        interp.is_eof = true;
296        interp.gas = Gas::new(10000);
297        interp.spec_id = SpecId::PRAGUE;
298
299        interp.step(&table, &mut host);
300        assert_eq!(interp.program_counter(), 5);
301    }
302
303    #[test]
304    fn rjumpi() {
305        let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
306        let mut host = DummyHost::default();
307        let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
308            [RJUMPI, 0x00, 0x03, RJUMPI, 0x00, 0x01, STOP, STOP].into(),
309        ));
310        interp.is_eof = true;
311        interp.stack.push(U256::from(1)).unwrap();
312        interp.stack.push(U256::from(0)).unwrap();
313        interp.gas = Gas::new(10000);
314        interp.spec_id = SpecId::PRAGUE;
315
316        // Dont jump
317        interp.step(&table, &mut host);
318        assert_eq!(interp.program_counter(), 3);
319        // Jumps to last opcode
320        interp.step(&table, &mut host);
321        assert_eq!(interp.program_counter(), 7);
322    }
323
324    #[test]
325    fn rjumpv() {
326        let table = make_instruction_table::<Interpreter, DummyHost<DefaultEthereumWiring>>();
327        let mut host = DummyHost::default();
328        let mut interp = Interpreter::new_bytecode(Bytecode::LegacyRaw(
329            [
330                RJUMPV,
331                0x01, // max index, 0 and 1
332                0x00, // first x0001
333                0x01,
334                0x00, // second 0x002
335                0x02,
336                NOP,
337                NOP,
338                NOP,
339                RJUMP,
340                0xFF,
341                (-12i8) as u8,
342                STOP,
343            ]
344            .into(),
345        ));
346        interp.is_eof = true;
347        interp.gas = Gas::new(1000);
348        interp.spec_id = SpecId::PRAGUE;
349
350        // More then max_index
351        interp.stack.push(U256::from(10)).unwrap();
352        interp.step(&table, &mut host);
353        assert_eq!(interp.program_counter(), 6);
354
355        // Cleanup
356        interp.step(&table, &mut host);
357        interp.step(&table, &mut host);
358        interp.step(&table, &mut host);
359        interp.step(&table, &mut host);
360        assert_eq!(interp.program_counter(), 0);
361
362        // Jump to first index of vtable
363        interp.stack.push(U256::from(0)).unwrap();
364        interp.step(&table, &mut host);
365        assert_eq!(interp.program_counter(), 7);
366
367        // Cleanup
368        interp.step(&table, &mut host);
369        interp.step(&table, &mut host);
370        interp.step(&table, &mut host);
371        assert_eq!(interp.program_counter(), 0);
372
373        // Jump to second index of vtable
374        interp.stack.push(U256::from(1)).unwrap();
375        interp.step(&table, &mut host);
376        assert_eq!(interp.program_counter(), 8);
377    }
378
379    fn dummy_eof() -> Eof {
380        let bytes = bytes!("ef000101000402000100010400000000800000fe");
381        Eof::decode(bytes).unwrap()
382    }
383
384    fn eof_setup(bytes1: Bytes, bytes2: Bytes) -> Interpreter {
385        eof_setup_with_types(bytes1, bytes2, TypesSection::default())
386    }
387
388    /// Two code section and types section is for last code.
389    fn eof_setup_with_types(bytes1: Bytes, bytes2: Bytes, types: TypesSection) -> Interpreter {
390        let mut eof = dummy_eof();
391
392        eof.body.code_section.clear();
393        eof.body.types_section.clear();
394        eof.header.code_sizes.clear();
395
396        eof.header.code_sizes.push(bytes1.len() as u16);
397        eof.body.code_section.push(bytes1.len());
398        eof.body.types_section.push(TypesSection::new(0, 0, 11));
399
400        eof.header.code_sizes.push(bytes2.len() as u16);
401        eof.body.code_section.push(bytes2.len() + bytes1.len());
402        eof.body.types_section.push(types);
403
404        eof.body.code = Bytes::from([bytes1, bytes2].concat());
405
406        let mut interp = Interpreter::new_bytecode(Bytecode::Eof(Arc::new(eof)));
407        interp.gas = Gas::new(10000);
408        interp.spec_id = SpecId::PRAGUE;
409        interp
410    }
411
412    #[test]
413    fn callf_retf_stop() {
414        let table = make_instruction_table::<Interpreter, _>();
415        let mut host = DummyHost::<DefaultEthereumWiring>::default();
416
417        let bytes1 = Bytes::from([CALLF, 0x00, 0x01, STOP]);
418        let bytes2 = Bytes::from([RETF]);
419        let mut interp = eof_setup(bytes1, bytes2.clone());
420
421        // CALLF
422        interp.step(&table, &mut host);
423
424        assert_eq!(interp.function_stack.current_code_idx, 1);
425        assert_eq!(
426            interp.function_stack.return_stack[0],
427            SubRoutineReturnFrame::new(0, 3)
428        );
429        assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
430
431        // RETF
432        interp.step(&table, &mut host);
433
434        assert_eq!(interp.function_stack.current_code_idx, 0);
435        assert_eq!(interp.function_stack.return_stack, Vec::new());
436        assert_eq!(interp.program_counter(), 3);
437
438        // STOP
439        interp.step(&table, &mut host);
440        assert_eq!(interp.instruction_result, InstructionResult::Stop);
441    }
442
443    #[test]
444    fn callf_stop() {
445        let table = make_instruction_table::<Interpreter, _>();
446        let mut host = DummyHost::<DefaultEthereumWiring>::default();
447
448        let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
449        let bytes2 = Bytes::from([STOP]);
450        let mut interp = eof_setup(bytes1, bytes2.clone());
451
452        // CALLF
453        interp.step(&table, &mut host);
454
455        assert_eq!(interp.function_stack.current_code_idx, 1);
456        assert_eq!(
457            interp.function_stack.return_stack[0],
458            SubRoutineReturnFrame::new(0, 3)
459        );
460        assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
461
462        // STOP
463        interp.step(&table, &mut host);
464        assert_eq!(interp.instruction_result, InstructionResult::Stop);
465    }
466
467    #[test]
468    fn callf_stack_overflow() {
469        let table = make_instruction_table::<Interpreter, _>();
470        let mut host = DummyHost::<DefaultEthereumWiring>::default();
471
472        let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
473        let bytes2 = Bytes::from([STOP]);
474        let mut interp =
475            eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025));
476
477        // CALLF
478        interp.step(&table, &mut host);
479
480        // Stack overflow
481        assert_eq!(interp.instruction_result, InstructionResult::StackOverflow);
482    }
483
484    #[test]
485    fn jumpf_stop() {
486        let table = make_instruction_table::<Interpreter, _>();
487        let mut host = DummyHost::<DefaultEthereumWiring>::default();
488
489        let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
490        let bytes2 = Bytes::from([STOP]);
491        let mut interp = eof_setup(bytes1, bytes2.clone());
492
493        // JUMPF
494        interp.step(&table, &mut host);
495
496        assert_eq!(interp.function_stack.current_code_idx, 1);
497        assert!(interp.function_stack.return_stack.is_empty());
498        assert_eq!(interp.instruction_pointer, bytes2.as_ptr());
499
500        // STOP
501        interp.step(&table, &mut host);
502        assert_eq!(interp.instruction_result, InstructionResult::Stop);
503    }
504
505    #[test]
506    fn jumpf_stack_overflow() {
507        let table = make_instruction_table::<Interpreter, _>();
508        let mut host = DummyHost::<DefaultEthereumWiring>::default();
509
510        let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
511        let bytes2 = Bytes::from([STOP]);
512        let mut interp =
513            eof_setup_with_types(bytes1, bytes2.clone(), TypesSection::new(0, 0, 1025));
514
515        // JUMPF
516        interp.step(&table, &mut host);
517
518        // Stack overflow
519        assert_eq!(interp.instruction_result, InstructionResult::StackOverflow);
520    }
521}
522*/