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}