revm_interpreter/
interpreter_types.rs

1use crate::{CallInput, Gas, InstructionResult, 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    #[inline]
10    fn read_i16(&self) -> i16 {
11        self.read_u16() as i16
12    }
13    fn read_u16(&self) -> u16;
14
15    #[inline]
16    fn read_i8(&self) -> i8 {
17        self.read_u8() as i8
18    }
19    fn read_u8(&self) -> u8;
20
21    #[inline]
22    fn read_offset_i16(&self, offset: isize) -> i16 {
23        self.read_offset_u16(offset) as i16
24    }
25    fn read_offset_u16(&self, offset: isize) -> u16;
26
27    fn read_slice(&self, len: usize) -> &[u8];
28}
29
30/// Trait for fetching inputs of the call.
31pub trait InputsTr {
32    /// Returns target address of the call.
33    fn target_address(&self) -> Address;
34    /// Returns bytecode address of the call. For DELEGATECALL this address will be different from target address.
35    /// And if initcode is called this address will be [`None`].
36    fn bytecode_address(&self) -> Option<&Address>;
37    /// Returns caller address of the call.
38    fn caller_address(&self) -> Address;
39    /// Returns input of the call.
40    fn input(&self) -> &CallInput;
41    /// Returns call value of the call.
42    fn call_value(&self) -> U256;
43}
44
45/// Trait needed for legacy bytecode.
46///
47/// Used in [`bytecode::opcode::CODECOPY`] and [`bytecode::opcode::CODESIZE`] opcodes.
48pub trait LegacyBytecode {
49    /// Returns current bytecode original length. Used in [`bytecode::opcode::CODESIZE`] opcode.
50    fn bytecode_len(&self) -> usize;
51    /// Returns current bytecode original slice. Used in [`bytecode::opcode::CODECOPY`] opcode.
52    fn bytecode_slice(&self) -> &[u8];
53}
54
55/// Trait for Interpreter to be able to jump
56pub trait Jumps {
57    /// Relative jumps does not require checking for overflow.
58    fn relative_jump(&mut self, offset: isize);
59    /// Absolute jumps require checking for overflow and if target is a jump destination
60    /// from jump table.
61    fn absolute_jump(&mut self, offset: usize);
62    /// Check legacy jump destination from jump table.
63    fn is_valid_legacy_jump(&mut self, offset: usize) -> bool;
64    /// Returns current program counter.
65    fn pc(&self) -> usize;
66    /// Returns instruction opcode.
67    fn opcode(&self) -> u8;
68}
69
70/// Trait for Interpreter memory operations.
71pub trait MemoryTr {
72    /// Sets memory data at given offset from data with a given data_offset and len.
73    ///
74    /// # Panics
75    ///
76    /// Panics if range is out of scope of allocated memory.
77    fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]);
78
79    /// Inner clone part of memory from global context to local context.
80    /// This is used to clone calldata to memory.
81    ///
82    /// # Panics
83    ///
84    /// Panics if range is out of scope of allocated memory.
85    fn set_data_from_global(
86        &mut self,
87        memory_offset: usize,
88        data_offset: usize,
89        len: usize,
90        data_range: Range<usize>,
91    );
92
93    /// Memory slice with global range. This range
94    ///
95    /// # Panics
96    ///
97    /// Panics if range is out of scope of allocated memory.
98    fn global_slice(&self, range: Range<usize>) -> Ref<'_, [u8]>;
99
100    /// Offset of local context of memory.
101    fn local_memory_offset(&self) -> usize;
102
103    /// Sets memory data at given offset.
104    ///
105    /// # Panics
106    ///
107    /// Panics if range is out of scope of allocated memory.
108    fn set(&mut self, memory_offset: usize, data: &[u8]);
109
110    /// Returns memory size.
111    fn size(&self) -> usize;
112
113    /// Copies memory data from source to destination.
114    ///
115    /// # Panics
116    /// Panics if range is out of scope of allocated memory.
117    fn copy(&mut self, destination: usize, source: usize, len: usize);
118
119    /// Memory slice with range
120    ///
121    /// # Panics
122    ///
123    /// Panics if range is out of scope of allocated memory.
124    fn slice(&self, range: Range<usize>) -> Ref<'_, [u8]>;
125
126    /// Memory slice len
127    ///
128    /// Uses [`slice`][MemoryTr::slice] internally.
129    fn slice_len(&self, offset: usize, len: usize) -> impl Deref<Target = [u8]> + '_ {
130        self.slice(offset..offset + len)
131    }
132
133    /// Resizes memory to new size
134    ///
135    /// # Note
136    ///
137    /// It checks memory limits.
138    fn resize(&mut self, new_size: usize) -> bool;
139}
140
141/// Returns EOF containers. Used by [`bytecode::opcode::RETURNCONTRACT`] and [`bytecode::opcode::EOFCREATE`] opcodes.
142pub trait EofContainer {
143    /// Returns EOF container at given index.
144    fn eof_container(&self, index: usize) -> Option<&Bytes>;
145}
146
147/// Handles EOF introduced sub routine calls.
148pub trait SubRoutineStack {
149    /// Returns sub routine stack length.
150    fn len(&self) -> usize;
151
152    /// Returns `true` if sub routine stack is empty.
153    fn is_empty(&self) -> bool {
154        self.len() == 0
155    }
156
157    /// Returns current sub routine index.
158    fn routine_idx(&self) -> usize;
159
160    /// Sets new code section without touching subroutine stack.
161    ///
162    /// This is used for [`bytecode::opcode::JUMPF`] opcode. Where
163    /// tail call is performed.
164    fn set_routine_idx(&mut self, idx: usize);
165
166    /// Pushes a new frame to the stack and new code index.
167    fn push(&mut self, old_program_counter: usize, new_idx: usize) -> bool;
168
169    /// Pops previous subroutine, sets previous code index and returns program counter.
170    fn pop(&mut self) -> Option<usize>;
171}
172
173/// Functions needed for Interpreter Stack operations.
174pub trait StackTr {
175    /// Returns stack length.
176    fn len(&self) -> usize;
177
178    /// Returns `true` if stack is empty.
179    fn is_empty(&self) -> bool {
180        self.len() == 0
181    }
182
183    /// Pushes values 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(&mut self, value: U256) -> 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::<0>().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    ///
232    /// Returns `true` if swap was successful, `false` if stack underflow.
233    #[must_use]
234    fn exchange(&mut self, n: usize, m: usize) -> bool;
235
236    /// Duplicates the `N`th value from the top of the stack.
237    ///
238    /// Index is based from the top of the stack.
239    ///
240    /// Returns `true` if duplicate was successful, `false` if stack underflow.
241    #[must_use]
242    fn dup(&mut self, n: usize) -> bool;
243}
244
245/// EOF data fetching.
246pub trait EofData {
247    /// Returns EOF data.
248    fn data(&self) -> &[u8];
249    /// Returns EOF data slice.
250    fn data_slice(&self, offset: usize, len: usize) -> &[u8];
251    /// Returns EOF data size.
252    fn data_size(&self) -> usize;
253}
254
255/// EOF code info.
256pub trait EofCodeInfo {
257    /// Returns code information containing stack information.
258    fn code_info(&self, idx: usize) -> Option<&CodeInfo>;
259
260    /// Returns program counter at the start of code section.
261    fn code_section_pc(&self, idx: usize) -> Option<usize>;
262}
263
264/// Returns return data.
265pub trait ReturnData {
266    /// Returns return data.
267    fn buffer(&self) -> &Bytes;
268
269    /// Sets return buffer.
270    fn set_buffer(&mut self, bytes: Bytes);
271
272    /// Clears return buffer.
273    fn clear(&mut self) {
274        self.set_buffer(Bytes::new());
275    }
276}
277
278pub trait LoopControl {
279    fn set_instruction_result(&mut self, result: InstructionResult);
280    fn set_next_action(&mut self, action: InterpreterAction, result: InstructionResult);
281    fn gas(&self) -> &Gas;
282    fn gas_mut(&mut self) -> &mut Gas;
283    fn instruction_result(&self) -> InstructionResult;
284    fn take_next_action(&mut self) -> InterpreterAction;
285}
286
287pub trait RuntimeFlag {
288    fn is_static(&self) -> bool;
289    fn is_eof(&self) -> bool;
290    fn is_eof_init(&self) -> bool;
291    fn spec_id(&self) -> SpecId;
292}
293
294pub trait Interp {
295    type Instruction;
296    type Action;
297
298    fn run(&mut self, instructions: &[Self::Instruction; 256]) -> Self::Action;
299}
300
301pub trait InterpreterTypes {
302    type Stack: StackTr;
303    type Memory: MemoryTr;
304    type Bytecode: Jumps + Immediates + LegacyBytecode + EofData + EofContainer + EofCodeInfo;
305    type ReturnData: ReturnData;
306    type Input: InputsTr;
307    type SubRoutineStack: SubRoutineStack;
308    type Control: LoopControl;
309    type RuntimeFlag: RuntimeFlag;
310    type Extend;
311    type Output;
312}