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 return_data;
7mod runtime_flags;
8mod shared_memory;
9mod stack;
10
11// re-exports
12pub use ext_bytecode::ExtBytecode;
13pub use input::InputsImpl;
14pub use return_data::ReturnDataImpl;
15pub use runtime_flags::RuntimeFlags;
16pub use shared_memory::{num_words, resize_memory, SharedMemory};
17pub use stack::{Stack, STACK_LIMIT};
18
19// imports
20use crate::{
21    instruction_context::InstructionContext, interpreter_types::*, Gas, GasTable, Host,
22    InstructionExecResult, InstructionResult, InstructionTable, InterpreterAction,
23};
24use bytecode::Bytecode;
25use context_interface::{cfg::GasParams, host::LoadError};
26use primitives::{hardfork::SpecId, hints_util::cold_path, 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    #[inline(always)]
118    pub fn clear(
119        &mut self,
120        memory: SharedMemory,
121        bytecode: ExtBytecode,
122        input: InputsImpl,
123        is_static: bool,
124        spec_id: SpecId,
125        gas_limit: u64,
126        reservoir_remaining_gas: 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_with_regular_gas_and_reservoir(gas_limit, reservoir_remaining_gas);
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    pub fn resize_memory(
186        &mut self,
187        gas_params: &GasParams,
188        offset: usize,
189        len: usize,
190    ) -> Result<(), InstructionResult> {
191        resize_memory(&mut self.gas, &mut self.memory, gas_params, offset, len)
192    }
193
194    /// Takes the next action from the control and returns it.
195    #[inline]
196    pub fn take_next_action(&mut self) -> InterpreterAction {
197        self.bytecode.reset_action();
198        // Return next action if it is some.
199        let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action");
200        action
201    }
202
203    /// Halt the interpreter with the given result.
204    ///
205    /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas.
206    #[cold]
207    #[inline(never)]
208    pub fn halt(&mut self, result: InstructionResult) {
209        if result == InstructionResult::OutOfGas {
210            self.gas.spend_all();
211        }
212        self.bytecode
213            .set_action(InterpreterAction::new_halt(result, self.gas));
214    }
215
216    /// Halt the interpreter with the given result.
217    ///
218    /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas.
219    #[cold]
220    #[inline(never)]
221    pub fn halt_fatal(&mut self) {
222        self.bytecode.set_action(InterpreterAction::new_halt(
223            InstructionResult::FatalExternalError,
224            self.gas,
225        ));
226    }
227
228    /// Halt the interpreter due to a [`LoadError`].
229    #[cold]
230    #[inline(never)]
231    pub fn halt_load_error(&mut self, err: LoadError) {
232        match err {
233            LoadError::ColdLoadSkipped => self.halt_oog(),
234            LoadError::DBError => self.halt_fatal(),
235        }
236    }
237
238    /// Halt the interpreter with an out-of-gas error.
239    #[cold]
240    #[inline(never)]
241    pub fn halt_oog(&mut self) {
242        self.gas.spend_all();
243        self.halt(InstructionResult::OutOfGas);
244    }
245
246    /// Halt the interpreter with an out-of-gas error.
247    #[cold]
248    #[inline(never)]
249    pub fn halt_memory_oog(&mut self) {
250        self.halt(InstructionResult::MemoryOOG);
251    }
252
253    /// Halt the interpreter with an out-of-gas error.
254    #[cold]
255    #[inline(never)]
256    pub fn halt_memory_limit_oog(&mut self) {
257        self.halt(InstructionResult::MemoryLimitOOG);
258    }
259
260    /// Halt the interpreter with and overflow error.
261    #[cold]
262    #[inline(never)]
263    pub fn halt_overflow(&mut self) {
264        self.halt(InstructionResult::StackOverflow);
265    }
266
267    /// Halt the interpreter with and underflow error.
268    #[cold]
269    #[inline(never)]
270    pub fn halt_underflow(&mut self) {
271        self.halt(InstructionResult::StackUnderflow);
272    }
273
274    /// Halt the interpreter with and not activated error.
275    #[cold]
276    #[inline(never)]
277    pub fn halt_not_activated(&mut self) {
278        self.halt(InstructionResult::NotActivated);
279    }
280
281    /// Return with the given output.
282    ///
283    /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas.
284    pub fn return_with_output(&mut self, output: Bytes) {
285        self.bytecode.set_action(InterpreterAction::new_return(
286            InstructionResult::Return,
287            output,
288            self.gas,
289        ));
290    }
291
292    /// Executes the instruction at the current instruction pointer.
293    ///
294    /// Internally it will increment instruction pointer by one.
295    #[inline]
296    pub fn step<H: Host + ?Sized>(
297        &mut self,
298        instruction_table: &InstructionTable<IW, H>,
299        gas_table: &GasTable,
300        host: &mut H,
301    ) -> InstructionExecResult {
302        // Get current opcode.
303        let opcode = self.bytecode.opcode();
304
305        // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last
306        // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction
307        // it will do noop and just stop execution of this contract
308        self.bytecode.relative_jump(1);
309
310        let instruction = instruction_table[opcode as usize];
311        let static_gas = unsafe { *gas_table.get_unchecked(opcode as usize) };
312
313        if self.gas.record_cost_unsafe(static_gas as u64) {
314            cold_path();
315            return Err(InstructionResult::OutOfGas);
316        }
317
318        instruction.execute(InstructionContext {
319            interpreter: self,
320            host,
321        })
322    }
323
324    /// Executes the interpreter until it returns or stops.
325    #[inline]
326    pub fn run_plain<H: Host + ?Sized>(
327        &mut self,
328        instruction_table: &InstructionTable<IW, H>,
329        gas_table: &GasTable,
330        host: &mut H,
331    ) -> InterpreterAction {
332        let e = loop {
333            if let Err(e) = self.step(instruction_table, gas_table, host) {
334                cold_path();
335                break e;
336            }
337        };
338        if self.bytecode.action().is_none() {
339            self.halt(e);
340        }
341        debug_assert!(self.bytecode.is_end());
342        self.take_next_action()
343    }
344}
345
346/*
347#[doc(hidden)]
348#[unsafe(no_mangle)]
349pub fn asm_run(
350    interpreter: &mut Interpreter<EthInterpreter>,
351    host: &mut context_interface::DummyHost,
352) {
353    let table = crate::instruction_table();
354    let gas_table = crate::gas_table();
355    interpreter.run_plain(&table, &gas_table, host);
356}
357*/
358
359/// The result of an interpreter operation.
360#[derive(Clone, Debug, PartialEq, Eq)]
361#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
362pub struct InterpreterResult {
363    /// The result of the instruction execution.
364    pub result: InstructionResult,
365    /// The output of the instruction execution.
366    pub output: Bytes,
367    /// The gas usage information.
368    pub gas: Gas,
369}
370
371impl InterpreterResult {
372    /// Returns a new `InterpreterResult` with the given values.
373    pub const fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
374        Self {
375            result,
376            output,
377            gas,
378        }
379    }
380
381    /// Returns a new `InterpreterResult` for an out-of-gas error with the given gas limit.
382    pub fn new_oog(gas_limit: u64, reservoir: u64) -> Self {
383        Self {
384            result: InstructionResult::OutOfGas,
385            output: Bytes::default(),
386            gas: Gas::new_spent_with_reservoir(gas_limit, reservoir),
387        }
388    }
389
390    /// Returns whether the instruction result is a success.
391    #[inline]
392    pub const fn is_ok(&self) -> bool {
393        self.result.is_ok()
394    }
395
396    /// Returns whether the instruction result is a revert.
397    #[inline]
398    pub const fn is_revert(&self) -> bool {
399        self.result.is_revert()
400    }
401
402    /// Returns whether the instruction result is an error.
403    #[inline]
404    pub const fn is_error(&self) -> bool {
405        self.result.is_error()
406    }
407}
408
409// Special implementation for types where Output can be created from InterpreterAction
410impl<IW: InterpreterTypes> Interpreter<IW>
411where
412    IW::Output: From<InterpreterAction>,
413{
414    /// Takes the next action from the control and returns it as the specific Output type.
415    #[inline]
416    pub fn take_next_action_as_output(&mut self) -> IW::Output {
417        From::from(self.take_next_action())
418    }
419
420    /// Executes the interpreter until it returns or stops, returning the specific Output type.
421    #[inline]
422    pub fn run_plain_as_output<H: Host + ?Sized>(
423        &mut self,
424        instruction_table: &InstructionTable<IW, H>,
425        gas_table: &GasTable,
426        host: &mut H,
427    ) -> IW::Output {
428        From::from(self.run_plain(instruction_table, gas_table, host))
429    }
430}
431
432#[cfg(test)]
433mod tests {
434    #[test]
435    #[cfg(feature = "serde")]
436    fn test_interpreter_serde() {
437        use super::*;
438        use bytecode::Bytecode;
439        use primitives::Bytes;
440
441        let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
442        let interpreter = Interpreter::<EthInterpreter>::new(
443            SharedMemory::new(),
444            ExtBytecode::new(bytecode),
445            InputsImpl::default(),
446            false,
447            SpecId::default(),
448            u64::MAX,
449        );
450
451        let serialized = serde_json::to_string_pretty(&interpreter).unwrap();
452        let deserialized: Interpreter<EthInterpreter> = serde_json::from_str(&serialized).unwrap();
453
454        assert_eq!(
455            interpreter.bytecode.pc(),
456            deserialized.bytecode.pc(),
457            "Program counter should be preserved"
458        );
459    }
460}
461
462#[test]
463fn test_mstore_big_offset_memory_oog() {
464    use super::*;
465    use crate::{
466        host::DummyHost,
467        instructions::{gas_table, instruction_table},
468    };
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    );
490
491    let table = instruction_table::<EthInterpreter, DummyHost>();
492    let gas = gas_table();
493    let mut host = DummyHost::default();
494    let action = interpreter.run_plain(&table, &gas, &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::{
508        host::DummyHost,
509        instructions::{gas_table, instruction_table},
510    };
511    use bytecode::Bytecode;
512    use primitives::Bytes;
513
514    let code = Bytes::from(
515        &[
516            0x60, 0x00, // PUSH1 0x00
517            0x61, 0x27, 0x10, // PUSH2 0x2710  (10,000)
518            0x52, // MSTORE
519            0x00, // STOP
520        ][..],
521    );
522    let bytecode = Bytecode::new_raw(code);
523
524    let mut interpreter = Interpreter::<EthInterpreter>::new(
525        SharedMemory::new_with_memory_limit(1000),
526        ExtBytecode::new(bytecode),
527        InputsImpl::default(),
528        false,
529        SpecId::default(),
530        100000,
531    );
532
533    let table = instruction_table::<EthInterpreter, DummyHost>();
534    let gas = gas_table();
535    let mut host = DummyHost::default();
536    let action = interpreter.run_plain(&table, &gas, &mut host);
537
538    assert!(action.is_return());
539    assert_eq!(
540        action.instruction_result(),
541        Some(InstructionResult::MemoryLimitOOG)
542    );
543}