revm_interpreter/
interpreter.rs

1//! Core interpreter implementation and components.
2
3/// Extended bytecode functionality.
4pub mod ext_bytecode;
5mod input;
6mod loop_control;
7mod return_data;
8mod runtime_flags;
9mod shared_memory;
10mod stack;
11
12// re-exports
13pub use ext_bytecode::ExtBytecode;
14pub use input::InputsImpl;
15pub use return_data::ReturnDataImpl;
16pub use runtime_flags::RuntimeFlags;
17pub use shared_memory::{num_words, resize_memory, SharedMemory};
18pub use stack::{Stack, STACK_LIMIT};
19
20// imports
21use crate::{
22    host::DummyHost, instruction_context::InstructionContext, interpreter_types::*, Gas, Host,
23    InstructionResult, InstructionTable, InterpreterAction,
24};
25use bytecode::Bytecode;
26use primitives::{hardfork::SpecId, Bytes};
27
28/// Main interpreter structure that contains all components defined in [`InterpreterTypes`].
29#[derive(Debug, Clone)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct Interpreter<WIRE: InterpreterTypes = EthInterpreter> {
32    /// Bytecode being executed.
33    pub bytecode: WIRE::Bytecode,
34    /// Gas tracking for execution costs.
35    pub gas: Gas,
36    /// EVM stack for computation.
37    pub stack: WIRE::Stack,
38    /// Buffer for return data from calls.
39    pub return_data: WIRE::ReturnData,
40    /// EVM memory for data storage.
41    pub memory: WIRE::Memory,
42    /// Input data for current execution context.
43    pub input: WIRE::Input,
44    /// Runtime flags controlling execution behavior.
45    pub runtime_flag: WIRE::RuntimeFlag,
46    /// Extended functionality and customizations.
47    pub extend: WIRE::Extend,
48}
49
50impl<EXT: Default> Interpreter<EthInterpreter<EXT>> {
51    /// Create new interpreter
52    pub fn new(
53        memory: SharedMemory,
54        bytecode: ExtBytecode,
55        input: InputsImpl,
56        is_static: bool,
57        spec_id: SpecId,
58        gas_limit: u64,
59    ) -> Self {
60        Self::new_inner(
61            Stack::new(),
62            memory,
63            bytecode,
64            input,
65            is_static,
66            spec_id,
67            gas_limit,
68        )
69    }
70
71    /// Create a new interpreter with default extended functionality.
72    pub fn default_ext() -> Self {
73        Self::do_default(Stack::new(), SharedMemory::new())
74    }
75
76    /// Create a new invalid interpreter.
77    pub fn invalid() -> Self {
78        Self::do_default(Stack::invalid(), SharedMemory::invalid())
79    }
80
81    fn do_default(stack: Stack, memory: SharedMemory) -> Self {
82        Self::new_inner(
83            stack,
84            memory,
85            ExtBytecode::default(),
86            InputsImpl::default(),
87            false,
88            SpecId::default(),
89            u64::MAX,
90        )
91    }
92
93    #[allow(clippy::too_many_arguments)]
94    fn new_inner(
95        stack: Stack,
96        memory: SharedMemory,
97        bytecode: ExtBytecode,
98        input: InputsImpl,
99        is_static: bool,
100        spec_id: SpecId,
101        gas_limit: u64,
102    ) -> Self {
103        Self {
104            bytecode,
105            gas: Gas::new(gas_limit),
106            stack,
107            return_data: Default::default(),
108            memory,
109            input,
110            runtime_flag: RuntimeFlags { is_static, spec_id },
111            extend: Default::default(),
112        }
113    }
114
115    /// Clears and reinitializes the interpreter with new parameters.
116    #[allow(clippy::too_many_arguments)]
117    pub fn clear(
118        &mut self,
119        memory: SharedMemory,
120        bytecode: ExtBytecode,
121        input: InputsImpl,
122        is_static: bool,
123        spec_id: SpecId,
124        gas_limit: u64,
125    ) {
126        let Self {
127            bytecode: bytecode_ref,
128            gas,
129            stack,
130            return_data,
131            memory: memory_ref,
132            input: input_ref,
133            runtime_flag,
134            extend,
135        } = self;
136        *bytecode_ref = bytecode;
137        *gas = Gas::new(gas_limit);
138        if stack.data().capacity() == 0 {
139            *stack = Stack::new();
140        } else {
141            stack.clear();
142        }
143        return_data.0.clear();
144        *memory_ref = memory;
145        *input_ref = input;
146        *runtime_flag = RuntimeFlags { spec_id, is_static };
147        *extend = EXT::default();
148    }
149
150    /// Sets the bytecode that is going to be executed
151    pub fn with_bytecode(mut self, bytecode: Bytecode) -> Self {
152        self.bytecode = ExtBytecode::new(bytecode);
153        self
154    }
155
156    /// Sets the specid for the interpreter.
157    pub fn set_spec_id(&mut self, spec_id: SpecId) {
158        self.runtime_flag.spec_id = spec_id;
159    }
160}
161
162impl Default for Interpreter<EthInterpreter> {
163    fn default() -> Self {
164        Self::default_ext()
165    }
166}
167
168/// Default types for Ethereum interpreter.
169#[derive(Debug)]
170pub struct EthInterpreter<EXT = (), MG = SharedMemory> {
171    _phantom: core::marker::PhantomData<fn() -> (EXT, MG)>,
172}
173
174impl<EXT> InterpreterTypes for EthInterpreter<EXT> {
175    type Stack = Stack;
176    type Memory = SharedMemory;
177    type Bytecode = ExtBytecode;
178    type ReturnData = ReturnDataImpl;
179    type Input = InputsImpl;
180    type RuntimeFlag = RuntimeFlags;
181    type Extend = EXT;
182    type Output = InterpreterAction;
183}
184
185impl<IW: InterpreterTypes> Interpreter<IW> {
186    /// Performs EVM memory resize.
187    #[inline]
188    #[must_use]
189    pub fn resize_memory(&mut self, offset: usize, len: usize) -> bool {
190        resize_memory(&mut self.gas, &mut self.memory, offset, len)
191    }
192
193    /// Takes the next action from the control and returns it.
194    #[inline]
195    pub fn take_next_action(&mut self) -> InterpreterAction {
196        self.bytecode.reset_action();
197        // Return next action if it is some.
198        let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action");
199        action
200    }
201
202    /// Halt the interpreter with the given result.
203    ///
204    /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas.
205    #[cold]
206    #[inline(never)]
207    pub fn halt(&mut self, result: InstructionResult) {
208        self.bytecode
209            .set_action(InterpreterAction::new_halt(result, self.gas));
210    }
211
212    /// Halt the interpreter with the given result.
213    ///
214    /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas.
215    #[cold]
216    #[inline(never)]
217    pub fn halt_fatal(&mut self) {
218        self.bytecode.set_action(InterpreterAction::new_halt(
219            InstructionResult::FatalExternalError,
220            self.gas,
221        ));
222    }
223
224    /// Halt the interpreter with an out-of-gas error.
225    #[cold]
226    #[inline(never)]
227    pub fn halt_oog(&mut self) {
228        self.gas.spend_all();
229        self.halt(InstructionResult::OutOfGas);
230    }
231
232    /// Halt the interpreter with an out-of-gas error.
233    #[cold]
234    #[inline(never)]
235    pub fn halt_memory_oog(&mut self) {
236        self.halt(InstructionResult::MemoryOOG);
237    }
238
239    /// Halt the interpreter with an out-of-gas error.
240    #[cold]
241    #[inline(never)]
242    pub fn halt_memory_limit_oog(&mut self) {
243        self.halt(InstructionResult::MemoryLimitOOG);
244    }
245
246    /// Halt the interpreter with and overflow error.
247    #[cold]
248    #[inline(never)]
249    pub fn halt_overflow(&mut self) {
250        self.halt(InstructionResult::StackOverflow);
251    }
252
253    /// Halt the interpreter with and underflow error.
254    #[cold]
255    #[inline(never)]
256    pub fn halt_underflow(&mut self) {
257        self.halt(InstructionResult::StackUnderflow);
258    }
259
260    /// Halt the interpreter with and not activated error.
261    #[cold]
262    #[inline(never)]
263    pub fn halt_not_activated(&mut self) {
264        self.halt(InstructionResult::NotActivated);
265    }
266
267    /// Return with the given output.
268    ///
269    /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas.
270    pub fn return_with_output(&mut self, output: Bytes) {
271        self.bytecode.set_action(InterpreterAction::new_return(
272            InstructionResult::Return,
273            output,
274            self.gas,
275        ));
276    }
277
278    /// Executes the instruction at the current instruction pointer.
279    ///
280    /// Internally it will increment instruction pointer by one.
281    #[inline]
282    pub fn step<H: Host + ?Sized>(
283        &mut self,
284        instruction_table: &InstructionTable<IW, H>,
285        host: &mut H,
286    ) {
287        // Get current opcode.
288        let opcode = self.bytecode.opcode();
289
290        // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last
291        // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction
292        // it will do noop and just stop execution of this contract
293        self.bytecode.relative_jump(1);
294
295        let instruction = unsafe { instruction_table.get_unchecked(opcode as usize) };
296
297        if self.gas.record_cost_unsafe(instruction.static_gas()) {
298            return self.halt_oog();
299        }
300        let context = InstructionContext {
301            interpreter: self,
302            host,
303        };
304        instruction.execute(context);
305    }
306
307    /// Executes the instruction at the current instruction pointer.
308    ///
309    /// Internally it will increment instruction pointer by one.
310    ///
311    /// This uses dummy Host.
312    #[inline]
313    pub fn step_dummy(&mut self, instruction_table: &InstructionTable<IW, DummyHost>) {
314        self.step(instruction_table, &mut DummyHost);
315    }
316
317    /// Executes the interpreter until it returns or stops.
318    #[inline]
319    pub fn run_plain<H: Host + ?Sized>(
320        &mut self,
321        instruction_table: &InstructionTable<IW, H>,
322        host: &mut H,
323    ) -> InterpreterAction {
324        while self.bytecode.is_not_end() {
325            self.step(instruction_table, host);
326        }
327        self.take_next_action()
328    }
329}
330
331/* used for cargo asm
332pub fn asm_step(
333    interpreter: &mut Interpreter<EthInterpreter>,
334    instruction_table: &InstructionTable<EthInterpreter, DummyHost>,
335    host: &mut DummyHost,
336) {
337    interpreter.step(instruction_table, host);
338}
339
340pub fn asm_run(
341    interpreter: &mut Interpreter<EthInterpreter>,
342    instruction_table: &InstructionTable<EthInterpreter, DummyHost>,
343    host: &mut DummyHost,
344) {
345    interpreter.run_plain(instruction_table, host);
346}
347*/
348
349/// The result of an interpreter operation.
350#[derive(Clone, Debug, PartialEq, Eq)]
351#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
352pub struct InterpreterResult {
353    /// The result of the instruction execution.
354    pub result: InstructionResult,
355    /// The output of the instruction execution.
356    pub output: Bytes,
357    /// The gas usage information.
358    pub gas: Gas,
359}
360
361impl InterpreterResult {
362    /// Returns a new `InterpreterResult` with the given values.
363    pub fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
364        Self {
365            result,
366            output,
367            gas,
368        }
369    }
370
371    /// Returns whether the instruction result is a success.
372    #[inline]
373    pub const fn is_ok(&self) -> bool {
374        self.result.is_ok()
375    }
376
377    /// Returns whether the instruction result is a revert.
378    #[inline]
379    pub const fn is_revert(&self) -> bool {
380        self.result.is_revert()
381    }
382
383    /// Returns whether the instruction result is an error.
384    #[inline]
385    pub const fn is_error(&self) -> bool {
386        self.result.is_error()
387    }
388}
389
390// Special implementation for types where Output can be created from InterpreterAction
391impl<IW: InterpreterTypes> Interpreter<IW>
392where
393    IW::Output: From<InterpreterAction>,
394{
395    /// Takes the next action from the control and returns it as the specific Output type.
396    #[inline]
397    pub fn take_next_action_as_output(&mut self) -> IW::Output {
398        From::from(self.take_next_action())
399    }
400
401    /// Executes the interpreter until it returns or stops, returning the specific Output type.
402    #[inline]
403    pub fn run_plain_as_output<H: Host + ?Sized>(
404        &mut self,
405        instruction_table: &InstructionTable<IW, H>,
406        host: &mut H,
407    ) -> IW::Output {
408        From::from(self.run_plain(instruction_table, host))
409    }
410}
411
412#[cfg(test)]
413mod tests {
414    #[test]
415    #[cfg(feature = "serde")]
416    fn test_interpreter_serde() {
417        use super::*;
418        use bytecode::Bytecode;
419        use primitives::Bytes;
420
421        let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
422        let interpreter = Interpreter::<EthInterpreter>::new(
423            SharedMemory::new(),
424            ExtBytecode::new(bytecode),
425            InputsImpl::default(),
426            false,
427            SpecId::default(),
428            u64::MAX,
429        );
430
431        let serialized = serde_json::to_string_pretty(&interpreter).unwrap();
432        let deserialized: Interpreter<EthInterpreter> = serde_json::from_str(&serialized).unwrap();
433
434        assert_eq!(
435            interpreter.bytecode.pc(),
436            deserialized.bytecode.pc(),
437            "Program counter should be preserved"
438        );
439    }
440}
441
442#[test]
443fn test_mstore_big_offset_memory_oog() {
444    use super::*;
445    use crate::{host::DummyHost, instructions::instruction_table};
446    use bytecode::Bytecode;
447    use primitives::Bytes;
448
449    let code = Bytes::from(
450        &[
451            0x60, 0x00, // PUSH1 0x00
452            0x61, 0x27, 0x10, // PUSH2 0x2710  (10,000)
453            0x52, // MSTORE
454            0x00, // STOP
455        ][..],
456    );
457    let bytecode = Bytecode::new_raw(code);
458
459    let mut interpreter = Interpreter::<EthInterpreter>::new(
460        SharedMemory::new(),
461        ExtBytecode::new(bytecode),
462        InputsImpl::default(),
463        false,
464        SpecId::default(),
465        1000,
466    );
467
468    let table = instruction_table::<EthInterpreter, DummyHost>();
469    let mut host = DummyHost;
470    let action = interpreter.run_plain(&table, &mut host);
471
472    assert!(action.is_return());
473    assert_eq!(
474        action.instruction_result(),
475        Some(InstructionResult::MemoryOOG)
476    );
477}
478
479#[test]
480#[cfg(feature = "memory_limit")]
481fn test_mstore_big_offset_memory_limit_oog() {
482    use super::*;
483    use crate::{host::DummyHost, instructions::instruction_table};
484    use bytecode::Bytecode;
485    use primitives::Bytes;
486
487    let code = Bytes::from(
488        &[
489            0x60, 0x00, // PUSH1 0x00
490            0x61, 0x27, 0x10, // PUSH2 0x2710  (10,000)
491            0x52, // MSTORE
492            0x00, // STOP
493        ][..],
494    );
495    let bytecode = Bytecode::new_raw(code);
496
497    let mut interpreter = Interpreter::<EthInterpreter>::new(
498        SharedMemory::new_with_memory_limit(1000),
499        ExtBytecode::new(bytecode),
500        InputsImpl::default(),
501        false,
502        SpecId::default(),
503        100000,
504    );
505
506    let table = instruction_table::<EthInterpreter, DummyHost>();
507    let mut host = DummyHost;
508    let action = interpreter.run_plain(&table, &mut host);
509
510    assert!(action.is_return());
511    assert_eq!(
512        action.instruction_result(),
513        Some(InstructionResult::MemoryLimitOOG)
514    );
515}