Skip to main content

revm_interpreter/
interpreter_types.rs

1use crate::{CallInput, InstructionResult, InterpreterAction};
2use core::{
3    cell::Ref,
4    ops::{Deref, Range},
5};
6use primitives::{hardfork::SpecId, Address, Bytes, B256, U256};
7
8/// Helper function to read immediates data from the bytecode
9pub trait Immediates {
10    /// Reads next 16 bits as signed integer from the bytecode.
11    #[inline]
12    fn read_i16(&self) -> i16 {
13        self.read_u16() as i16
14    }
15    /// Reads next 16 bits as unsigned integer from the bytecode.
16    fn read_u16(&self) -> u16;
17
18    /// Reads next 8 bits as signed integer from the bytecode.
19    #[inline]
20    fn read_i8(&self) -> i8 {
21        self.read_u8() as i8
22    }
23
24    /// Reads next 8 bits as unsigned integer from the bytecode.
25    fn read_u8(&self) -> u8;
26
27    /// Reads next 16 bits as signed integer from the bytecode at given offset.
28    #[inline]
29    fn read_offset_i16(&self, offset: isize) -> i16 {
30        self.read_offset_u16(offset) as i16
31    }
32
33    /// Reads next 16 bits as unsigned integer from the bytecode at given offset.
34    fn read_offset_u16(&self, offset: isize) -> u16;
35
36    /// Reads next `len` bytes from the bytecode.
37    ///
38    /// Used by PUSH opcode.
39    fn read_slice(&self, len: usize) -> &[u8];
40}
41
42/// Trait for fetching inputs of the call.
43pub trait InputsTr {
44    /// Returns target address of the call.
45    fn target_address(&self) -> Address;
46    /// Returns bytecode address of the call. For DELEGATECALL this address will be different from target address.
47    /// And if initcode is called this address will be [`None`].
48    fn bytecode_address(&self) -> Option<&Address>;
49    /// Returns caller address of the call.
50    fn caller_address(&self) -> Address;
51    /// Returns input of the call.
52    fn input(&self) -> &CallInput;
53    /// Returns call value of the call.
54    fn call_value(&self) -> U256;
55}
56
57/// Trait needed for legacy bytecode.
58///
59/// Used in [`bytecode::opcode::CODECOPY`] and [`bytecode::opcode::CODESIZE`] opcodes.
60pub trait LegacyBytecode {
61    /// Returns current bytecode original length. Used in [`bytecode::opcode::CODESIZE`] opcode.
62    fn bytecode_len(&self) -> usize;
63    /// Returns current bytecode original slice. Used in [`bytecode::opcode::CODECOPY`] opcode.
64    fn bytecode_slice(&self) -> &[u8];
65}
66
67/// Trait for Interpreter to be able to jump
68pub trait Jumps {
69    /// Relative jumps does not require checking for overflow.
70    fn relative_jump(&mut self, offset: isize);
71    /// Absolute jumps require checking for overflow and if target is a jump destination
72    /// from jump table.
73    fn absolute_jump(&mut self, offset: usize);
74    /// Check legacy jump destination from jump table.
75    fn is_valid_legacy_jump(&mut self, offset: usize) -> bool;
76    /// Returns current program counter.
77    fn pc(&self) -> usize;
78    /// Returns instruction opcode.
79    fn opcode(&self) -> u8;
80}
81
82/// Trait for Interpreter memory operations.
83pub trait MemoryTr {
84    /// Sets memory data at given offset from data with a given data_offset and len.
85    ///
86    /// # Panics
87    ///
88    /// Panics if range is out of scope of allocated memory.
89    fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]);
90
91    /// Inner clone part of memory from global context to local context.
92    /// This is used to clone calldata to memory.
93    ///
94    /// # Panics
95    ///
96    /// Panics if range is out of scope of allocated memory.
97    fn set_data_from_global(
98        &mut self,
99        memory_offset: usize,
100        data_offset: usize,
101        len: usize,
102        data_range: Range<usize>,
103    );
104
105    /// Memory slice with global range. This range
106    ///
107    /// # Panics
108    ///
109    /// Panics if range is out of scope of allocated memory.
110    fn global_slice(&self, range: Range<usize>) -> Ref<'_, [u8]>;
111
112    /// Offset of local context of memory.
113    fn local_memory_offset(&self) -> usize;
114
115    /// Sets memory data at given offset.
116    ///
117    /// # Panics
118    ///
119    /// Panics if range is out of scope of allocated memory.
120    fn set(&mut self, memory_offset: usize, data: &[u8]);
121
122    /// Returns memory size.
123    fn size(&self) -> usize;
124
125    /// Copies memory data from source to destination.
126    ///
127    /// # Panics
128    /// Panics if range is out of scope of allocated memory.
129    fn copy(&mut self, destination: usize, source: usize, len: usize);
130
131    /// Memory slice with range
132    ///
133    /// # Panics
134    ///
135    /// Panics if range is out of scope of allocated memory.
136    fn slice(&self, range: Range<usize>) -> Ref<'_, [u8]>;
137
138    /// Memory slice len
139    ///
140    /// Uses [`slice`][MemoryTr::slice] internally.
141    fn slice_len(&self, offset: usize, len: usize) -> impl Deref<Target = [u8]> + '_ {
142        self.slice(offset..offset + len)
143    }
144
145    /// Resizes memory to new size
146    ///
147    /// # Note
148    ///
149    /// It checks if the memory allocation fits under gas cap.
150    fn resize(&mut self, new_size: usize) -> bool;
151
152    /// Returns `true` if the `new_words` for the current context memory will
153    /// make the shared buffer length exceed the `memory_limit`.
154    #[cfg(feature = "memory_limit")]
155    fn limit_reached(&self, new_words: usize) -> bool;
156}
157
158/// Functions needed for Interpreter Stack operations.
159pub trait StackTr {
160    /// Returns stack length.
161    fn len(&self) -> usize;
162
163    /// Returns stack content.
164    fn data(&self) -> &[U256];
165
166    /// Returns `true` if stack is empty.
167    fn is_empty(&self) -> bool {
168        self.len() == 0
169    }
170
171    /// Clears the stack.
172    fn clear(&mut self);
173
174    /// Pushes values to the stack.
175    ///
176    /// Returns `true` if push was successful, `false` if stack overflow.
177    ///
178    /// # Note
179    /// Error is internally set in interpreter.
180    #[must_use]
181    fn push(&mut self, value: U256) -> bool;
182
183    /// Pushes slice to the stack.
184    ///
185    /// Returns `true` if push was successful, `false` if stack overflow.
186    ///
187    /// # Note
188    /// Error is internally set in interpreter.
189    #[must_use]
190    fn push_slice(&mut self, slice: &[u8]) -> bool;
191
192    /// Pushes B256 value to the stack.
193    ///
194    /// Internally converts B256 to U256 and then calls [`StackTr::push`].
195    #[must_use]
196    fn push_b256(&mut self, value: B256) -> bool {
197        self.push(value.into())
198    }
199
200    /// Pops value from the stack.
201    #[must_use]
202    fn popn<const N: usize>(&mut self) -> Option<[U256; N]>;
203
204    /// Pop N values from the stack and return top value.
205    #[must_use]
206    fn popn_top<const POPN: usize>(&mut self) -> Option<([U256; POPN], &mut U256)>;
207
208    /// Returns top value from the stack.
209    #[must_use]
210    fn top(&mut self) -> Option<&mut U256> {
211        self.popn_top().map(|([], top)| top)
212    }
213
214    /// Pops one value from the stack.
215    #[must_use]
216    fn pop(&mut self) -> Option<U256> {
217        self.popn::<1>().map(|[value]| value)
218    }
219
220    /// Pops address from the stack.
221    ///
222    /// Internally call [`StackTr::pop`] and converts [`U256`] into [`Address`].
223    #[must_use]
224    fn pop_address(&mut self) -> Option<Address> {
225        self.pop().map(|value| Address::from(value.to_be_bytes()))
226    }
227
228    /// Exchanges two values on the stack.
229    ///
230    /// Indexes are based from the top of the stack.
231    /// `n` is the first index, and the second index is calculated as `n + m`.
232    ///
233    /// Returns `true` if swap was successful, `false` if stack underflow.
234    #[must_use]
235    fn exchange(&mut self, n: usize, m: usize) -> bool;
236
237    /// Duplicates the `N`th value from the top of the stack.
238    ///
239    /// Index is based from the top of the stack.
240    ///
241    /// Returns `true` if duplicate was successful, `false` if stack underflow.
242    #[must_use]
243    fn dup(&mut self, n: usize) -> bool;
244}
245
246/// Returns return data.
247pub trait ReturnData {
248    /// Returns return data.
249    fn buffer(&self) -> &Bytes;
250
251    /// Sets return buffer.
252    fn set_buffer(&mut self, bytes: Bytes);
253
254    /// Clears return buffer.
255    fn clear(&mut self) {
256        self.set_buffer(Bytes::new());
257    }
258}
259
260/// Trait controls execution of the loop.
261pub trait LoopControl {
262    /// Returns `true` if the loop should continue.
263    fn is_not_end(&self) -> bool;
264    /// Is end of the loop.
265    #[inline]
266    fn is_end(&self) -> bool {
267        !self.is_not_end()
268    }
269    /// Sets the `end` flag internally. Action should be taken after.
270    fn reset_action(&mut self);
271    /// Set return action.
272    fn set_action(&mut self, action: InterpreterAction);
273    /// Returns the current action.
274    fn action(&mut self) -> &mut Option<InterpreterAction>;
275    /// Returns instruction result
276    #[inline]
277    fn instruction_result(&mut self) -> Option<InstructionResult> {
278        self.action()
279            .as_ref()
280            .and_then(|action| action.instruction_result())
281    }
282}
283
284/// Runtime flags that control interpreter execution behavior.
285pub trait RuntimeFlag {
286    /// Returns true if the current execution context is static (read-only).
287    fn is_static(&self) -> bool;
288    /// Returns the current EVM specification ID.
289    fn spec_id(&self) -> SpecId;
290}
291
292/// Trait for interpreter execution.
293pub trait Interp {
294    /// The instruction type.
295    type Instruction;
296    /// The action type returned after execution.
297    type Action;
298
299    /// Runs the interpreter with the given instruction table.
300    fn run(&mut self, instructions: &[Self::Instruction; 256]) -> Self::Action;
301}
302
303/// Trait defining the component types used by an interpreter implementation.
304pub trait InterpreterTypes {
305    /// Stack implementation type.
306    type Stack: StackTr;
307    /// Memory implementation type.
308    type Memory: MemoryTr;
309    /// Bytecode implementation type.
310    type Bytecode: Jumps + Immediates + LoopControl + LegacyBytecode;
311    /// Return data implementation type.
312    type ReturnData: ReturnData;
313    /// Input data implementation type.
314    type Input: InputsTr;
315    /// Runtime flags implementation type.
316    type RuntimeFlag: RuntimeFlag;
317    /// Extended functionality type.
318    type Extend;
319    /// Output type for execution results.
320    type Output;
321}