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    // Get target types
111    let Some(types) = interpreter.bytecode.code_info(idx) else {
112        panic!("Invalid EOF in execution, expecting correct intermediate in callf")
113    };
114
115    // Check max stack height for target code section.
116    // Safe to subtract as max_stack_height is always more than inputs.
117    if interpreter.stack.len() + types.max_stack_increase as usize > 1024 {
118        interpreter
119            .control
120            .set_instruction_result(InstructionResult::StackOverflow);
121        return;
122    }
123
124    // Push current idx and PC to the callf stack.
125    // PC is incremented by 2 to point to the next instruction after callf.
126    if !(interpreter
127        .sub_routine
128        .push(interpreter.bytecode.pc() + 2, idx))
129    {
130        interpreter
131            .control
132            .set_instruction_result(InstructionResult::SubRoutineStackOverflow);
133        return;
134    };
135    let pc = interpreter
136        .bytecode
137        .code_section_pc(idx)
138        .expect("Invalid code section index");
139    interpreter.bytecode.absolute_jump(pc);
140}
141
142pub fn retf<WIRE: InterpreterTypes, H: Host + ?Sized>(
143    interpreter: &mut Interpreter<WIRE>,
144    _host: &mut H,
145) {
146    require_eof!(interpreter);
147    gas!(interpreter, gas::RETF_GAS);
148
149    let Some(jump) = interpreter.sub_routine.pop() else {
150        panic!("Expected function frame")
151    };
152
153    interpreter.bytecode.absolute_jump(jump);
154}
155
156pub fn jumpf<WIRE: InterpreterTypes, H: Host + ?Sized>(
157    interpreter: &mut Interpreter<WIRE>,
158    _host: &mut H,
159) {
160    require_eof!(interpreter);
161    gas!(interpreter, gas::LOW);
162
163    let idx = interpreter.bytecode.read_u16() as usize;
164
165    // Get target types
166    let types = interpreter
167        .bytecode
168        .code_info(idx)
169        .expect("Invalid code section index");
170
171    // Check max stack height for target code section.
172    if interpreter.stack.len() + types.max_stack_increase as usize > 1024 {
173        interpreter
174            .control
175            .set_instruction_result(InstructionResult::StackOverflow);
176        return;
177    }
178    interpreter.sub_routine.set_routine_idx(idx);
179    let pc = interpreter
180        .bytecode
181        .code_section_pc(idx)
182        .expect("Invalid code section index");
183    interpreter.bytecode.absolute_jump(pc);
184}
185
186pub fn pc<WIRE: InterpreterTypes, H: Host + ?Sized>(
187    interpreter: &mut Interpreter<WIRE>,
188    _host: &mut H,
189) {
190    gas!(interpreter, gas::BASE);
191    // - 1 because we have already advanced the instruction pointer in `Interpreter::step`
192    push!(interpreter, U256::from(interpreter.bytecode.pc() - 1));
193}
194
195#[inline]
196fn return_inner(
197    interpreter: &mut Interpreter<impl InterpreterTypes>,
198    instruction_result: InstructionResult,
199) {
200    // Zero gas cost
201    // gas!(interpreter, gas::ZERO)
202    popn!([offset, len], interpreter);
203    let len = as_usize_or_fail!(interpreter, len);
204    // Important: Offset must be ignored if len is zeros
205    let mut output = Bytes::default();
206    if len != 0 {
207        let offset = as_usize_or_fail!(interpreter, offset);
208        resize_memory!(interpreter, offset, len);
209        output = interpreter.memory.slice_len(offset, len).to_vec().into()
210    }
211
212    let gas = *interpreter.control.gas();
213    interpreter.control.set_next_action(
214        InterpreterAction::Return {
215            result: InterpreterResult {
216                output,
217                gas,
218                result: instruction_result,
219            },
220        },
221        instruction_result,
222    );
223}
224
225pub fn ret<WIRE: InterpreterTypes, H: Host + ?Sized>(
226    interpreter: &mut Interpreter<WIRE>,
227    _host: &mut H,
228) {
229    return_inner(interpreter, InstructionResult::Return);
230}
231
232/// EIP-140: REVERT instruction
233pub fn revert<WIRE: InterpreterTypes, H: Host + ?Sized>(
234    interpreter: &mut Interpreter<WIRE>,
235    _host: &mut H,
236) {
237    check!(interpreter, BYZANTIUM);
238    return_inner(interpreter, InstructionResult::Revert);
239}
240
241/// Stop opcode. This opcode halts the execution.
242pub fn stop<WIRE: InterpreterTypes, H: Host + ?Sized>(
243    interpreter: &mut Interpreter<WIRE>,
244    _host: &mut H,
245) {
246    interpreter
247        .control
248        .set_instruction_result(InstructionResult::Stop);
249}
250
251/// Invalid opcode. This opcode halts the execution.
252pub fn invalid<WIRE: InterpreterTypes, H: Host + ?Sized>(
253    interpreter: &mut Interpreter<WIRE>,
254    _host: &mut H,
255) {
256    interpreter
257        .control
258        .set_instruction_result(InstructionResult::InvalidFEOpcode);
259}
260
261/// Unknown opcode. This opcode halts the execution.
262pub fn unknown<WIRE: InterpreterTypes, H: Host + ?Sized>(
263    interpreter: &mut Interpreter<WIRE>,
264    _host: &mut H,
265) {
266    interpreter
267        .control
268        .set_instruction_result(InstructionResult::OpcodeNotFound);
269}
270
271#[cfg(test)]
272mod test {
273    use super::*;
274    use crate::interpreter::SubRoutineReturnFrame;
275    use crate::{host::DummyHost, instruction_table, interpreter::EthInterpreter};
276    use bytecode::opcode::{CALLF, JUMPF, NOP, RETF, RJUMP, RJUMPI, RJUMPV, STOP};
277    use bytecode::{
278        eof::{CodeInfo, Eof},
279        Bytecode,
280    };
281    use primitives::bytes;
282    use std::sync::Arc;
283
284    #[test]
285    fn rjump() {
286        let bytecode = Bytecode::new_raw(Bytes::from(&[RJUMP, 0x00, 0x02, STOP, STOP]));
287        let mut interpreter = Interpreter::<EthInterpreter>::default().with_bytecode(bytecode);
288
289        interpreter.runtime_flag.is_eof = true;
290        let table = instruction_table();
291        let mut host = DummyHost;
292
293        interpreter.step(&table, &mut host);
294        assert_eq!(interpreter.bytecode.pc(), 5)
295    }
296
297    #[test]
298    fn rjumpi() {
299        let bytecode = Bytecode::new_raw(Bytes::from(&[
300            RJUMPI, 0x00, 0x03, RJUMPI, 0x00, 0x01, STOP, STOP,
301        ]));
302        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
303
304        interpreter.runtime_flag.is_eof = true;
305        let table = instruction_table();
306        let mut host = DummyHost;
307
308        let _ = interpreter.stack.push(U256::from(1));
309        let _ = interpreter.stack.push(U256::from(0));
310
311        // Dont jump
312        interpreter.step(&table, &mut host);
313        assert_eq!(interpreter.bytecode.pc(), 3);
314        // Jumps to last opcode
315        interpreter.step(&table, &mut host);
316        assert_eq!(interpreter.bytecode.pc(), 7);
317    }
318
319    #[test]
320    fn rjumpv() {
321        let bytecode = Bytecode::new_raw(Bytes::from(&[
322            RJUMPV,
323            0x01, // max index, 0 and 1
324            0x00, // first x0001
325            0x01,
326            0x00, // second 0x0002
327            0x02,
328            NOP,
329            NOP,
330            NOP,
331            RJUMP,
332            0xFF,
333            (-12i8) as u8,
334            STOP,
335        ]));
336        let mut interpreter = Interpreter::default().with_bytecode(bytecode);
337
338        interpreter.runtime_flag.is_eof = true;
339        let table = instruction_table();
340        let mut host = DummyHost;
341
342        // More then max_index
343        let _ = interpreter.stack.push(U256::from(10));
344        interpreter.step(&table, &mut host);
345        assert_eq!(interpreter.bytecode.pc(), 6);
346
347        // Cleanup
348        interpreter.step(&table, &mut host);
349        interpreter.step(&table, &mut host);
350        interpreter.step(&table, &mut host);
351        interpreter.step(&table, &mut host);
352        assert_eq!(interpreter.bytecode.pc(), 0);
353
354        // Jump to first index of vtable
355        let _ = interpreter.stack.push(U256::from(0));
356        interpreter.step(&table, &mut host);
357        assert_eq!(interpreter.bytecode.pc(), 7);
358
359        // Cleanup
360        interpreter.step(&table, &mut host);
361        interpreter.step(&table, &mut host);
362        interpreter.step(&table, &mut host);
363        assert_eq!(interpreter.bytecode.pc(), 0);
364
365        // Jump to second index of vtable
366        let _ = interpreter.stack.push(U256::from(1));
367        interpreter.step(&table, &mut host);
368        assert_eq!(interpreter.bytecode.pc(), 8);
369    }
370
371    fn dummy_eof() -> Eof {
372        let bytes = bytes!("ef00010100040200010001ff00000000800000fe");
373        Eof::decode(bytes).unwrap()
374    }
375
376    fn eof_setup(bytes1: Bytes, bytes2: Bytes) -> Interpreter {
377        eof_setup_with_types(bytes1, bytes2, CodeInfo::default())
378    }
379
380    /// Two code section and types section is for last code.
381    fn eof_setup_with_types(bytes1: Bytes, bytes2: Bytes, types: CodeInfo) -> Interpreter {
382        let mut eof = dummy_eof();
383
384        eof.body.code_section.clear();
385        eof.body.code_info.clear();
386        eof.header.code_sizes.clear();
387
388        eof.header.code_sizes.push(bytes1.len() as u16);
389        eof.body.code_section.push(bytes1.len());
390        eof.body.code_info.push(CodeInfo::new(0, 0, 11));
391
392        eof.header.code_sizes.push(bytes2.len() as u16);
393        eof.body.code_section.push(bytes2.len() + bytes1.len());
394        eof.body.code_info.push(types);
395
396        // added two code infos that are 4 bytes each.
397        eof.header.types_size = 2 * 4;
398
399        eof.body.code = Bytes::from([bytes1, bytes2].concat());
400
401        // encoding EOF is done se we can generate a raw bytecode.
402        // raw bytecode is used to calculate program counter.
403        let encoded = eof.encode_slow();
404
405        let bytecode = Bytecode::Eof(Arc::new(Eof::decode(encoded).unwrap()));
406
407        Interpreter::default().with_bytecode(bytecode)
408    }
409
410    #[test]
411    fn callf_retf_stop() {
412        let table = instruction_table();
413        let mut host = DummyHost;
414
415        let bytes1 = Bytes::from([CALLF, 0x00, 0x01, STOP]);
416        let bytes2 = Bytes::from([RETF]);
417        let mut interpreter = eof_setup(bytes1, bytes2.clone());
418        interpreter.runtime_flag.is_eof = true;
419        let base_pc = interpreter.bytecode.pc();
420
421        // CALLF
422        interpreter.step(&table, &mut host);
423
424        assert_eq!(interpreter.sub_routine.current_code_idx, 1);
425        assert_eq!(
426            interpreter.sub_routine.return_stack[0],
427            SubRoutineReturnFrame::new(0, 3 + base_pc)
428        );
429        // points to second code section, at RETF opcode
430        assert_eq!(interpreter.bytecode.pc() - base_pc, 4);
431
432        // RETF
433        interpreter.step(&table, &mut host);
434
435        assert_eq!(interpreter.sub_routine.current_code_idx, 0);
436        assert_eq!(interpreter.sub_routine.return_stack, Vec::new());
437        // we have returned from the second code section and next opcode is STOP
438        assert_eq!(interpreter.bytecode.pc() - base_pc, 3);
439
440        // STOP
441        interpreter.step(&table, &mut host);
442        assert_eq!(
443            interpreter.control.instruction_result,
444            InstructionResult::Stop
445        );
446    }
447
448    #[test]
449    fn callf_stop() {
450        let table = instruction_table();
451        let mut host = DummyHost;
452
453        let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
454        let bytes2 = Bytes::from([STOP]);
455        let mut interpreter = eof_setup(bytes1, bytes2.clone());
456        interpreter.runtime_flag.is_eof = true;
457        let base_pc = interpreter.bytecode.pc();
458
459        // CALLF
460        interpreter.step(&table, &mut host);
461
462        assert_eq!(interpreter.sub_routine.current_code_idx, 1);
463        assert_eq!(
464            interpreter.sub_routine.return_stack[0],
465            SubRoutineReturnFrame::new(0, 3 + base_pc)
466        );
467        // program counter points to STOP of second code section.
468        assert_eq!(interpreter.bytecode.pc(), 3 + base_pc);
469
470        // STOP
471        interpreter.step(&table, &mut host);
472        assert_eq!(
473            interpreter.control.instruction_result,
474            InstructionResult::Stop
475        );
476    }
477
478    #[test]
479    fn callf_stack_overflow() {
480        let table = instruction_table();
481        let mut host = DummyHost;
482
483        let bytes1 = Bytes::from([CALLF, 0x00, 0x01]);
484        let bytes2 = Bytes::from([STOP]);
485        let mut interpreter =
486            eof_setup_with_types(bytes1, bytes2.clone(), CodeInfo::new(0, 0, 1023));
487        interpreter.runtime_flag.is_eof = true;
488
489        // push two items so we can overflow the CALLF call.
490        // overflow happens if max_stack_increase + stack.len is more than 1024
491        let _ = interpreter.stack.push(U256::from(0));
492        let _ = interpreter.stack.push(U256::from(0));
493
494        // CALLF
495        interpreter.step(&table, &mut host);
496
497        // Stack overflow
498        assert_eq!(
499            interpreter.control.instruction_result,
500            InstructionResult::StackOverflow
501        );
502    }
503
504    #[test]
505    fn jumpf_stop() {
506        let table = instruction_table();
507        let mut host = DummyHost;
508
509        let bytes1 = Bytes::from([JUMPF, 0x00, 0x01]);
510        let bytes2 = Bytes::from([STOP]);
511        let mut interpreter = eof_setup(bytes1, bytes2.clone());
512        interpreter.runtime_flag.is_eof = true;
513        let base_pc = interpreter.bytecode.pc();
514
515        // JUMPF
516        interpreter.step(&table, &mut host);
517
518        // fails after this line
519        assert_eq!(interpreter.sub_routine.current_code_idx, 1);
520        assert!(interpreter.sub_routine.return_stack.is_empty());
521        // program counter points to STOP of second code section.
522        assert_eq!(interpreter.bytecode.pc(), 3 + base_pc);
523
524        // STOP
525        interpreter.step(&table, &mut host);
526        assert_eq!(
527            interpreter.control.instruction_result,
528            InstructionResult::Stop
529        );
530    }
531
532    #[test]
533    fn jumpf_stack_overflow() {
534        let table = instruction_table();
535        let mut host = DummyHost;
536
537        let bytes1 = Bytes::from([JUMPF, 0x00, 0x01, STOP]);
538        let bytes2 = Bytes::from([STOP]);
539        let mut interpreter =
540            eof_setup_with_types(bytes1, bytes2.clone(), CodeInfo::new(0, 0, 1023));
541        interpreter.runtime_flag.is_eof = true;
542
543        // push two items so we can overflow the JUMPF call.
544        // overflow happens if max_stack_size + stack.len is more than 1024
545        let _ = interpreter.stack.push(U256::from(0));
546        let _ = interpreter.stack.push(U256::from(0));
547
548        // JUMPF
549        interpreter.step(&table, &mut host);
550
551        // Stack overflow
552        assert_eq!(
553            interpreter.control.instruction_result,
554            InstructionResult::StackOverflow
555        );
556    }
557}