revm_interpreter/
interpreter_types.rs

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