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