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