1pub mod ext_bytecode;
5mod input;
6mod loop_control;
7mod return_data;
8mod runtime_flags;
9mod shared_memory;
10mod stack;
11
12pub use ext_bytecode::ExtBytecode;
14pub use input::InputsImpl;
15pub use return_data::ReturnDataImpl;
16pub use runtime_flags::RuntimeFlags;
17pub use shared_memory::{num_words, resize_memory, SharedMemory};
18pub use stack::{Stack, STACK_LIMIT};
19
20use crate::{
22 host::DummyHost, instruction_context::InstructionContext, interpreter_types::*, Gas, Host,
23 InstructionResult, InstructionTable, InterpreterAction,
24};
25use bytecode::Bytecode;
26use primitives::{hardfork::SpecId, Bytes};
27
28#[derive(Debug, Clone)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
31pub struct Interpreter<WIRE: InterpreterTypes = EthInterpreter> {
32 pub bytecode: WIRE::Bytecode,
34 pub gas: Gas,
36 pub stack: WIRE::Stack,
38 pub return_data: WIRE::ReturnData,
40 pub memory: WIRE::Memory,
42 pub input: WIRE::Input,
44 pub runtime_flag: WIRE::RuntimeFlag,
46 pub extend: WIRE::Extend,
48}
49
50impl<EXT: Default> Interpreter<EthInterpreter<EXT>> {
51 pub fn new(
53 memory: SharedMemory,
54 bytecode: ExtBytecode,
55 input: InputsImpl,
56 is_static: bool,
57 spec_id: SpecId,
58 gas_limit: u64,
59 ) -> Self {
60 Self::new_inner(
61 Stack::new(),
62 memory,
63 bytecode,
64 input,
65 is_static,
66 spec_id,
67 gas_limit,
68 )
69 }
70
71 pub fn default_ext() -> Self {
73 Self::do_default(Stack::new(), SharedMemory::new())
74 }
75
76 pub fn invalid() -> Self {
78 Self::do_default(Stack::invalid(), SharedMemory::invalid())
79 }
80
81 fn do_default(stack: Stack, memory: SharedMemory) -> Self {
82 Self::new_inner(
83 stack,
84 memory,
85 ExtBytecode::default(),
86 InputsImpl::default(),
87 false,
88 SpecId::default(),
89 u64::MAX,
90 )
91 }
92
93 #[allow(clippy::too_many_arguments)]
94 fn new_inner(
95 stack: Stack,
96 memory: SharedMemory,
97 bytecode: ExtBytecode,
98 input: InputsImpl,
99 is_static: bool,
100 spec_id: SpecId,
101 gas_limit: u64,
102 ) -> Self {
103 Self {
104 bytecode,
105 gas: Gas::new(gas_limit),
106 stack,
107 return_data: Default::default(),
108 memory,
109 input,
110 runtime_flag: RuntimeFlags { is_static, spec_id },
111 extend: Default::default(),
112 }
113 }
114
115 #[allow(clippy::too_many_arguments)]
117 pub fn clear(
118 &mut self,
119 memory: SharedMemory,
120 bytecode: ExtBytecode,
121 input: InputsImpl,
122 is_static: bool,
123 spec_id: SpecId,
124 gas_limit: u64,
125 ) {
126 let Self {
127 bytecode: bytecode_ref,
128 gas,
129 stack,
130 return_data,
131 memory: memory_ref,
132 input: input_ref,
133 runtime_flag,
134 extend,
135 } = self;
136 *bytecode_ref = bytecode;
137 *gas = Gas::new(gas_limit);
138 if stack.data().capacity() == 0 {
139 *stack = Stack::new();
140 } else {
141 stack.clear();
142 }
143 return_data.0.clear();
144 *memory_ref = memory;
145 *input_ref = input;
146 *runtime_flag = RuntimeFlags { spec_id, is_static };
147 *extend = EXT::default();
148 }
149
150 pub fn with_bytecode(mut self, bytecode: Bytecode) -> Self {
152 self.bytecode = ExtBytecode::new(bytecode);
153 self
154 }
155
156 pub fn set_spec_id(&mut self, spec_id: SpecId) {
158 self.runtime_flag.spec_id = spec_id;
159 }
160}
161
162impl Default for Interpreter<EthInterpreter> {
163 fn default() -> Self {
164 Self::default_ext()
165 }
166}
167
168#[derive(Debug)]
170pub struct EthInterpreter<EXT = (), MG = SharedMemory> {
171 _phantom: core::marker::PhantomData<fn() -> (EXT, MG)>,
172}
173
174impl<EXT> InterpreterTypes for EthInterpreter<EXT> {
175 type Stack = Stack;
176 type Memory = SharedMemory;
177 type Bytecode = ExtBytecode;
178 type ReturnData = ReturnDataImpl;
179 type Input = InputsImpl;
180 type RuntimeFlag = RuntimeFlags;
181 type Extend = EXT;
182 type Output = InterpreterAction;
183}
184
185impl<IW: InterpreterTypes> Interpreter<IW> {
186 #[inline]
188 #[must_use]
189 pub fn resize_memory(&mut self, offset: usize, len: usize) -> bool {
190 resize_memory(&mut self.gas, &mut self.memory, offset, len)
191 }
192
193 #[inline]
195 pub fn take_next_action(&mut self) -> InterpreterAction {
196 self.bytecode.reset_action();
197 let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action");
199 action
200 }
201
202 #[cold]
206 #[inline(never)]
207 pub fn halt(&mut self, result: InstructionResult) {
208 self.bytecode
209 .set_action(InterpreterAction::new_halt(result, self.gas));
210 }
211
212 #[cold]
216 #[inline(never)]
217 pub fn halt_fatal(&mut self) {
218 self.bytecode.set_action(InterpreterAction::new_halt(
219 InstructionResult::FatalExternalError,
220 self.gas,
221 ));
222 }
223
224 #[cold]
226 #[inline(never)]
227 pub fn halt_oog(&mut self) {
228 self.gas.spend_all();
229 self.halt(InstructionResult::OutOfGas);
230 }
231
232 #[cold]
234 #[inline(never)]
235 pub fn halt_memory_oog(&mut self) {
236 self.halt(InstructionResult::MemoryOOG);
237 }
238
239 #[cold]
241 #[inline(never)]
242 pub fn halt_memory_limit_oog(&mut self) {
243 self.halt(InstructionResult::MemoryLimitOOG);
244 }
245
246 #[cold]
248 #[inline(never)]
249 pub fn halt_overflow(&mut self) {
250 self.halt(InstructionResult::StackOverflow);
251 }
252
253 #[cold]
255 #[inline(never)]
256 pub fn halt_underflow(&mut self) {
257 self.halt(InstructionResult::StackUnderflow);
258 }
259
260 #[cold]
262 #[inline(never)]
263 pub fn halt_not_activated(&mut self) {
264 self.halt(InstructionResult::NotActivated);
265 }
266
267 pub fn return_with_output(&mut self, output: Bytes) {
271 self.bytecode.set_action(InterpreterAction::new_return(
272 InstructionResult::Return,
273 output,
274 self.gas,
275 ));
276 }
277
278 #[inline]
282 pub fn step<H: Host + ?Sized>(
283 &mut self,
284 instruction_table: &InstructionTable<IW, H>,
285 host: &mut H,
286 ) {
287 let opcode = self.bytecode.opcode();
289
290 self.bytecode.relative_jump(1);
294
295 let instruction = unsafe { instruction_table.get_unchecked(opcode as usize) };
296
297 if self.gas.record_cost_unsafe(instruction.static_gas()) {
298 return self.halt_oog();
299 }
300 let context = InstructionContext {
301 interpreter: self,
302 host,
303 };
304 instruction.execute(context);
305 }
306
307 #[inline]
313 pub fn step_dummy(&mut self, instruction_table: &InstructionTable<IW, DummyHost>) {
314 self.step(instruction_table, &mut DummyHost);
315 }
316
317 #[inline]
319 pub fn run_plain<H: Host + ?Sized>(
320 &mut self,
321 instruction_table: &InstructionTable<IW, H>,
322 host: &mut H,
323 ) -> InterpreterAction {
324 while self.bytecode.is_not_end() {
325 self.step(instruction_table, host);
326 }
327 self.take_next_action()
328 }
329}
330
331#[derive(Clone, Debug, PartialEq, Eq)]
351#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
352pub struct InterpreterResult {
353 pub result: InstructionResult,
355 pub output: Bytes,
357 pub gas: Gas,
359}
360
361impl InterpreterResult {
362 pub fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
364 Self {
365 result,
366 output,
367 gas,
368 }
369 }
370
371 #[inline]
373 pub const fn is_ok(&self) -> bool {
374 self.result.is_ok()
375 }
376
377 #[inline]
379 pub const fn is_revert(&self) -> bool {
380 self.result.is_revert()
381 }
382
383 #[inline]
385 pub const fn is_error(&self) -> bool {
386 self.result.is_error()
387 }
388}
389
390impl<IW: InterpreterTypes> Interpreter<IW>
392where
393 IW::Output: From<InterpreterAction>,
394{
395 #[inline]
397 pub fn take_next_action_as_output(&mut self) -> IW::Output {
398 From::from(self.take_next_action())
399 }
400
401 #[inline]
403 pub fn run_plain_as_output<H: Host + ?Sized>(
404 &mut self,
405 instruction_table: &InstructionTable<IW, H>,
406 host: &mut H,
407 ) -> IW::Output {
408 From::from(self.run_plain(instruction_table, host))
409 }
410}
411
412#[cfg(test)]
413mod tests {
414 #[test]
415 #[cfg(feature = "serde")]
416 fn test_interpreter_serde() {
417 use super::*;
418 use bytecode::Bytecode;
419 use primitives::Bytes;
420
421 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
422 let interpreter = Interpreter::<EthInterpreter>::new(
423 SharedMemory::new(),
424 ExtBytecode::new(bytecode),
425 InputsImpl::default(),
426 false,
427 SpecId::default(),
428 u64::MAX,
429 );
430
431 let serialized = serde_json::to_string_pretty(&interpreter).unwrap();
432 let deserialized: Interpreter<EthInterpreter> = serde_json::from_str(&serialized).unwrap();
433
434 assert_eq!(
435 interpreter.bytecode.pc(),
436 deserialized.bytecode.pc(),
437 "Program counter should be preserved"
438 );
439 }
440}
441
442#[test]
443fn test_mstore_big_offset_memory_oog() {
444 use super::*;
445 use crate::{host::DummyHost, instructions::instruction_table};
446 use bytecode::Bytecode;
447 use primitives::Bytes;
448
449 let code = Bytes::from(
450 &[
451 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
456 );
457 let bytecode = Bytecode::new_raw(code);
458
459 let mut interpreter = Interpreter::<EthInterpreter>::new(
460 SharedMemory::new(),
461 ExtBytecode::new(bytecode),
462 InputsImpl::default(),
463 false,
464 SpecId::default(),
465 1000,
466 );
467
468 let table = instruction_table::<EthInterpreter, DummyHost>();
469 let mut host = DummyHost;
470 let action = interpreter.run_plain(&table, &mut host);
471
472 assert!(action.is_return());
473 assert_eq!(
474 action.instruction_result(),
475 Some(InstructionResult::MemoryOOG)
476 );
477}
478
479#[test]
480#[cfg(feature = "memory_limit")]
481fn test_mstore_big_offset_memory_limit_oog() {
482 use super::*;
483 use crate::{host::DummyHost, instructions::instruction_table};
484 use bytecode::Bytecode;
485 use primitives::Bytes;
486
487 let code = Bytes::from(
488 &[
489 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
494 );
495 let bytecode = Bytecode::new_raw(code);
496
497 let mut interpreter = Interpreter::<EthInterpreter>::new(
498 SharedMemory::new_with_memory_limit(1000),
499 ExtBytecode::new(bytecode),
500 InputsImpl::default(),
501 false,
502 SpecId::default(),
503 100000,
504 );
505
506 let table = instruction_table::<EthInterpreter, DummyHost>();
507 let mut host = DummyHost;
508 let action = interpreter.run_plain(&table, &mut host);
509
510 assert!(action.is_return());
511 assert_eq!(
512 action.instruction_result(),
513 Some(InstructionResult::MemoryLimitOOG)
514 );
515}