Skip to main content

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