revm_interpreter/instructions/
control.rs

1use crate::{
2    gas,
3    interpreter::Interpreter,
4    interpreter_types::{InterpreterTypes, Jumps, LoopControl, MemoryTr, RuntimeFlag, StackTr},
5    InstructionResult, InterpreterAction,
6};
7use primitives::{Bytes, U256};
8
9use crate::InstructionContext;
10
11/// Implements the JUMP instruction.
12///
13/// Unconditional jump to a valid destination.
14pub fn jump<ITy: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, ITy>) {
15    gas!(context.interpreter, gas::MID);
16    popn!([target], context.interpreter);
17    jump_inner(context.interpreter, target);
18}
19
20/// Implements the JUMPI instruction.
21///
22/// Conditional jump to a valid destination if condition is true.
23pub fn jumpi<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
24    gas!(context.interpreter, gas::HIGH);
25    popn!([target, cond], context.interpreter);
26
27    if !cond.is_zero() {
28        jump_inner(context.interpreter, target);
29    }
30}
31
32#[inline(always)]
33/// Internal helper function for jump operations.
34///
35/// Validates jump target and performs the actual jump.
36fn jump_inner<WIRE: InterpreterTypes>(interpreter: &mut Interpreter<WIRE>, target: U256) {
37    let target = as_usize_or_fail!(interpreter, target, InstructionResult::InvalidJump);
38    if !interpreter.bytecode.is_valid_legacy_jump(target) {
39        interpreter.halt(InstructionResult::InvalidJump);
40        return;
41    }
42    // SAFETY: `is_valid_jump` ensures that `dest` is in bounds.
43    interpreter.bytecode.absolute_jump(target);
44}
45
46/// Implements the JUMPDEST instruction.
47///
48/// Marks a valid destination for jump operations.
49pub fn jumpdest<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
50    gas!(context.interpreter, gas::JUMPDEST);
51}
52
53/// Implements the PC instruction.
54///
55/// Pushes the current program counter onto the stack.
56pub fn pc<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
57    gas!(context.interpreter, gas::BASE);
58    // - 1 because we have already advanced the instruction pointer in `Interpreter::step`
59    push!(
60        context.interpreter,
61        U256::from(context.interpreter.bytecode.pc() - 1)
62    );
63}
64
65#[inline]
66/// Internal helper function for return operations.
67///
68/// Handles memory data retrieval and sets the return action.
69fn return_inner(
70    interpreter: &mut Interpreter<impl InterpreterTypes>,
71    instruction_result: InstructionResult,
72) {
73    // Zero gas cost
74    // gas!(interpreter, gas::ZERO)
75    popn!([offset, len], interpreter);
76    let len = as_usize_or_fail!(interpreter, len);
77    // Important: Offset must be ignored if len is zeros
78    let mut output = Bytes::default();
79    if len != 0 {
80        let offset = as_usize_or_fail!(interpreter, offset);
81        resize_memory!(interpreter, offset, len);
82        output = interpreter.memory.slice_len(offset, len).to_vec().into()
83    }
84
85    interpreter
86        .bytecode
87        .set_action(InterpreterAction::new_return(
88            instruction_result,
89            output,
90            interpreter.gas,
91        ));
92}
93
94/// Implements the RETURN instruction.
95///
96/// Halts execution and returns data from memory.
97pub fn ret<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
98    return_inner(context.interpreter, InstructionResult::Return);
99}
100
101/// EIP-140: REVERT instruction
102pub fn revert<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
103    check!(context.interpreter, BYZANTIUM);
104    return_inner(context.interpreter, InstructionResult::Revert);
105}
106
107/// Stop opcode. This opcode halts the execution.
108pub fn stop<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
109    context.interpreter.halt(InstructionResult::Stop);
110}
111
112/// Invalid opcode. This opcode halts the execution.
113pub fn invalid<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
114    context.interpreter.halt(InstructionResult::InvalidFEOpcode);
115}
116
117/// Unknown opcode. This opcode halts the execution.
118pub fn unknown<WIRE: InterpreterTypes, H: ?Sized>(context: InstructionContext<'_, H, WIRE>) {
119    context.interpreter.halt(InstructionResult::OpcodeNotFound);
120}