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