1pub mod ext_bytecode;
5mod input;
6mod loop_control;
7mod return_data;
8mod runtime_flags;
9mod shared_memory;
10mod stack;
11
12use context_interface::cfg::GasParams;
13pub use ext_bytecode::ExtBytecode;
15pub use input::InputsImpl;
16pub use return_data::ReturnDataImpl;
17pub use runtime_flags::RuntimeFlags;
18pub use shared_memory::{num_words, resize_memory, SharedMemory};
19pub use stack::{Stack, STACK_LIMIT};
20
21use crate::{
23 host::DummyHost, instruction_context::InstructionContext, interpreter_types::*, Gas, Host,
24 InstructionResult, InstructionTable, InterpreterAction,
25};
26use bytecode::Bytecode;
27use primitives::{hardfork::SpecId, Bytes};
28
29#[derive(Debug, Clone)]
31#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
32pub struct Interpreter<WIRE: InterpreterTypes = EthInterpreter> {
33 pub bytecode: WIRE::Bytecode,
35 pub gas: Gas,
37 pub stack: WIRE::Stack,
39 pub return_data: WIRE::ReturnData,
41 pub memory: WIRE::Memory,
43 pub input: WIRE::Input,
45 pub runtime_flag: WIRE::RuntimeFlag,
47 pub extend: WIRE::Extend,
49}
50
51impl<EXT: Default> Interpreter<EthInterpreter<EXT>> {
52 pub fn new(
54 memory: SharedMemory,
55 bytecode: ExtBytecode,
56 input: InputsImpl,
57 is_static: bool,
58 spec_id: SpecId,
59 gas_limit: u64,
60 ) -> Self {
61 Self::new_inner(
62 Stack::new(),
63 memory,
64 bytecode,
65 input,
66 is_static,
67 spec_id,
68 gas_limit,
69 )
70 }
71
72 pub fn default_ext() -> Self {
74 Self::do_default(Stack::new(), SharedMemory::new())
75 }
76
77 pub fn invalid() -> Self {
79 Self::do_default(Stack::invalid(), SharedMemory::invalid())
80 }
81
82 fn do_default(stack: Stack, memory: SharedMemory) -> Self {
83 Self::new_inner(
84 stack,
85 memory,
86 ExtBytecode::default(),
87 InputsImpl::default(),
88 false,
89 SpecId::default(),
90 u64::MAX,
91 )
92 }
93
94 #[allow(clippy::too_many_arguments)]
95 fn new_inner(
96 stack: Stack,
97 memory: SharedMemory,
98 bytecode: ExtBytecode,
99 input: InputsImpl,
100 is_static: bool,
101 spec_id: SpecId,
102 gas_limit: u64,
103 ) -> Self {
104 Self {
105 bytecode,
106 gas: Gas::new(gas_limit),
107 stack,
108 return_data: Default::default(),
109 memory,
110 input,
111 runtime_flag: RuntimeFlags { is_static, spec_id },
112 extend: Default::default(),
113 }
114 }
115
116 #[allow(clippy::too_many_arguments)]
118 #[inline(always)]
119 pub fn clear(
120 &mut self,
121 memory: SharedMemory,
122 bytecode: ExtBytecode,
123 input: InputsImpl,
124 is_static: bool,
125 spec_id: SpecId,
126 gas_limit: u64,
127 reservoir_remaining_gas: u64,
128 ) {
129 let Self {
130 bytecode: bytecode_ref,
131 gas,
132 stack,
133 return_data,
134 memory: memory_ref,
135 input: input_ref,
136 runtime_flag,
137 extend,
138 } = self;
139 *bytecode_ref = bytecode;
140 *gas = Gas::new_with_regular_gas_and_reservoir(gas_limit, reservoir_remaining_gas);
141 if stack.data().capacity() == 0 {
142 *stack = Stack::new();
143 } else {
144 stack.clear();
145 }
146 return_data.0.clear();
147 *memory_ref = memory;
148 *input_ref = input;
149 *runtime_flag = RuntimeFlags { spec_id, is_static };
150 *extend = EXT::default();
151 }
152
153 pub fn with_bytecode(mut self, bytecode: Bytecode) -> Self {
155 self.bytecode = ExtBytecode::new(bytecode);
156 self
157 }
158}
159
160impl Default for Interpreter<EthInterpreter> {
161 fn default() -> Self {
162 Self::default_ext()
163 }
164}
165
166#[derive(Debug)]
168pub struct EthInterpreter<EXT = (), MG = SharedMemory> {
169 _phantom: core::marker::PhantomData<fn() -> (EXT, MG)>,
170}
171
172impl<EXT> InterpreterTypes for EthInterpreter<EXT> {
173 type Stack = Stack;
174 type Memory = SharedMemory;
175 type Bytecode = ExtBytecode;
176 type ReturnData = ReturnDataImpl;
177 type Input = InputsImpl;
178 type RuntimeFlag = RuntimeFlags;
179 type Extend = EXT;
180 type Output = InterpreterAction;
181}
182
183impl<IW: InterpreterTypes> Interpreter<IW> {
184 #[inline]
186 #[must_use]
187 pub fn resize_memory(&mut self, gas_params: &GasParams, offset: usize, len: usize) -> bool {
188 if let Err(result) = resize_memory(&mut self.gas, &mut self.memory, gas_params, offset, len)
189 {
190 self.halt(result);
191 return false;
192 }
193 true
194 }
195
196 #[inline]
198 pub fn take_next_action(&mut self) -> InterpreterAction {
199 self.bytecode.reset_action();
200 let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action");
202 action
203 }
204
205 #[cold]
209 #[inline(never)]
210 pub fn halt(&mut self, result: InstructionResult) {
211 self.bytecode
212 .set_action(InterpreterAction::new_halt(result, self.gas));
213 }
214
215 #[cold]
219 #[inline(never)]
220 pub fn halt_fatal(&mut self) {
221 self.bytecode.set_action(InterpreterAction::new_halt(
222 InstructionResult::FatalExternalError,
223 self.gas,
224 ));
225 }
226
227 #[cold]
229 #[inline(never)]
230 pub fn halt_oog(&mut self) {
231 self.gas.spend_all();
232 self.halt(InstructionResult::OutOfGas);
233 }
234
235 #[cold]
237 #[inline(never)]
238 pub fn halt_memory_oog(&mut self) {
239 self.halt(InstructionResult::MemoryOOG);
240 }
241
242 #[cold]
244 #[inline(never)]
245 pub fn halt_memory_limit_oog(&mut self) {
246 self.halt(InstructionResult::MemoryLimitOOG);
247 }
248
249 #[cold]
251 #[inline(never)]
252 pub fn halt_overflow(&mut self) {
253 self.halt(InstructionResult::StackOverflow);
254 }
255
256 #[cold]
258 #[inline(never)]
259 pub fn halt_underflow(&mut self) {
260 self.halt(InstructionResult::StackUnderflow);
261 }
262
263 #[cold]
265 #[inline(never)]
266 pub fn halt_not_activated(&mut self) {
267 self.halt(InstructionResult::NotActivated);
268 }
269
270 pub fn return_with_output(&mut self, output: Bytes) {
274 self.bytecode.set_action(InterpreterAction::new_return(
275 InstructionResult::Return,
276 output,
277 self.gas,
278 ));
279 }
280
281 #[inline]
285 pub fn step<H: Host + ?Sized>(
286 &mut self,
287 instruction_table: &InstructionTable<IW, H>,
288 host: &mut H,
289 ) {
290 let opcode = self.bytecode.opcode();
292
293 self.bytecode.relative_jump(1);
297
298 let instruction = unsafe { instruction_table.get_unchecked(opcode as usize) };
299
300 if self.gas.record_cost_unsafe(instruction.static_gas()) {
301 return self.halt_oog();
302 }
303 let context = InstructionContext {
304 interpreter: self,
305 host,
306 };
307 instruction.execute(context);
308 }
309
310 #[inline]
316 pub fn step_dummy(&mut self, instruction_table: &InstructionTable<IW, DummyHost>) {
317 self.step(instruction_table, &mut DummyHost::default());
318 }
319
320 #[inline]
322 pub fn run_plain<H: Host + ?Sized>(
323 &mut self,
324 instruction_table: &InstructionTable<IW, H>,
325 host: &mut H,
326 ) -> InterpreterAction {
327 while self.bytecode.is_not_end() {
328 self.step(instruction_table, host);
329 }
330 self.take_next_action()
331 }
332}
333
334#[derive(Clone, Debug, PartialEq, Eq)]
354#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
355pub struct InterpreterResult {
356 pub result: InstructionResult,
358 pub output: Bytes,
360 pub gas: Gas,
362}
363
364impl InterpreterResult {
365 pub fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
367 Self {
368 result,
369 output,
370 gas,
371 }
372 }
373
374 pub fn new_oog(gas_limit: u64) -> Self {
376 Self {
377 result: InstructionResult::OutOfGas,
378 output: Bytes::default(),
379 gas: Gas::new_spent(gas_limit),
380 }
381 }
382
383 #[inline]
385 pub const fn is_ok(&self) -> bool {
386 self.result.is_ok()
387 }
388
389 #[inline]
391 pub const fn is_revert(&self) -> bool {
392 self.result.is_revert()
393 }
394
395 #[inline]
397 pub const fn is_error(&self) -> bool {
398 self.result.is_error()
399 }
400}
401
402impl<IW: InterpreterTypes> Interpreter<IW>
404where
405 IW::Output: From<InterpreterAction>,
406{
407 #[inline]
409 pub fn take_next_action_as_output(&mut self) -> IW::Output {
410 From::from(self.take_next_action())
411 }
412
413 #[inline]
415 pub fn run_plain_as_output<H: Host + ?Sized>(
416 &mut self,
417 instruction_table: &InstructionTable<IW, H>,
418 host: &mut H,
419 ) -> IW::Output {
420 From::from(self.run_plain(instruction_table, host))
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 #[test]
427 #[cfg(feature = "serde")]
428 fn test_interpreter_serde() {
429 use super::*;
430 use bytecode::Bytecode;
431 use primitives::Bytes;
432
433 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
434 let interpreter = Interpreter::<EthInterpreter>::new(
435 SharedMemory::new(),
436 ExtBytecode::new(bytecode),
437 InputsImpl::default(),
438 false,
439 SpecId::default(),
440 u64::MAX,
441 );
442
443 let serialized = serde_json::to_string_pretty(&interpreter).unwrap();
444 let deserialized: Interpreter<EthInterpreter> = serde_json::from_str(&serialized).unwrap();
445
446 assert_eq!(
447 interpreter.bytecode.pc(),
448 deserialized.bytecode.pc(),
449 "Program counter should be preserved"
450 );
451 }
452}
453
454#[test]
455fn test_mstore_big_offset_memory_oog() {
456 use super::*;
457 use crate::{host::DummyHost, instructions::instruction_table};
458 use bytecode::Bytecode;
459 use primitives::Bytes;
460
461 let code = Bytes::from(
462 &[
463 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
468 );
469 let bytecode = Bytecode::new_raw(code);
470
471 let mut interpreter = Interpreter::<EthInterpreter>::new(
472 SharedMemory::new(),
473 ExtBytecode::new(bytecode),
474 InputsImpl::default(),
475 false,
476 SpecId::default(),
477 1000,
478 );
479
480 let table = instruction_table::<EthInterpreter, DummyHost>();
481 let mut host = DummyHost::default();
482 let action = interpreter.run_plain(&table, &mut host);
483
484 assert!(action.is_return());
485 assert_eq!(
486 action.instruction_result(),
487 Some(InstructionResult::MemoryOOG)
488 );
489}
490
491#[test]
492#[cfg(feature = "memory_limit")]
493fn test_mstore_big_offset_memory_limit_oog() {
494 use super::*;
495 use crate::{host::DummyHost, instructions::instruction_table};
496 use bytecode::Bytecode;
497 use primitives::Bytes;
498
499 let code = Bytes::from(
500 &[
501 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
506 );
507 let bytecode = Bytecode::new_raw(code);
508
509 let mut interpreter = Interpreter::<EthInterpreter>::new(
510 SharedMemory::new_with_memory_limit(1000),
511 ExtBytecode::new(bytecode),
512 InputsImpl::default(),
513 false,
514 SpecId::default(),
515 100000,
516 );
517
518 let table = instruction_table::<EthInterpreter, DummyHost>();
519 let mut host = DummyHost::default();
520 let action = interpreter.run_plain(&table, &mut host);
521
522 assert!(action.is_return());
523 assert_eq!(
524 action.instruction_result(),
525 Some(InstructionResult::MemoryLimitOOG)
526 );
527}