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}