1pub mod ext_bytecode;
5mod input;
6mod return_data;
7mod runtime_flags;
8mod shared_memory;
9mod stack;
10
11pub use ext_bytecode::ExtBytecode;
13pub use input::InputsImpl;
14pub use return_data::ReturnDataImpl;
15pub use runtime_flags::RuntimeFlags;
16pub use shared_memory::{num_words, resize_memory, SharedMemory};
17pub use stack::{Stack, STACK_LIMIT};
18
19use crate::{
21 instruction_context::InstructionContext, interpreter_types::*, Gas, GasTable, Host,
22 InstructionExecResult, InstructionResult, InstructionTable, InterpreterAction,
23};
24use bytecode::Bytecode;
25use context_interface::{cfg::GasParams, host::LoadError};
26use primitives::{hardfork::SpecId, hints_util::cold_path, 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 #[inline(always)]
118 pub fn clear(
119 &mut self,
120 memory: SharedMemory,
121 bytecode: ExtBytecode,
122 input: InputsImpl,
123 is_static: bool,
124 spec_id: SpecId,
125 gas_limit: u64,
126 reservoir_remaining_gas: u64,
127 ) {
128 let Self {
129 bytecode: bytecode_ref,
130 gas,
131 stack,
132 return_data,
133 memory: memory_ref,
134 input: input_ref,
135 runtime_flag,
136 extend,
137 } = self;
138 *bytecode_ref = bytecode;
139 *gas = Gas::new_with_regular_gas_and_reservoir(gas_limit, reservoir_remaining_gas);
140 if stack.data().capacity() == 0 {
141 *stack = Stack::new();
142 } else {
143 stack.clear();
144 }
145 return_data.0.clear();
146 *memory_ref = memory;
147 *input_ref = input;
148 *runtime_flag = RuntimeFlags { spec_id, is_static };
149 *extend = EXT::default();
150 }
151
152 pub fn with_bytecode(mut self, bytecode: Bytecode) -> Self {
154 self.bytecode = ExtBytecode::new(bytecode);
155 self
156 }
157}
158
159impl Default for Interpreter<EthInterpreter> {
160 fn default() -> Self {
161 Self::default_ext()
162 }
163}
164
165#[derive(Debug)]
167pub struct EthInterpreter<EXT = (), MG = SharedMemory> {
168 _phantom: core::marker::PhantomData<fn() -> (EXT, MG)>,
169}
170
171impl<EXT> InterpreterTypes for EthInterpreter<EXT> {
172 type Stack = Stack;
173 type Memory = SharedMemory;
174 type Bytecode = ExtBytecode;
175 type ReturnData = ReturnDataImpl;
176 type Input = InputsImpl;
177 type RuntimeFlag = RuntimeFlags;
178 type Extend = EXT;
179 type Output = InterpreterAction;
180}
181
182impl<IW: InterpreterTypes> Interpreter<IW> {
183 #[inline]
185 pub fn resize_memory(
186 &mut self,
187 gas_params: &GasParams,
188 offset: usize,
189 len: usize,
190 ) -> Result<(), InstructionResult> {
191 resize_memory(&mut self.gas, &mut self.memory, gas_params, offset, len)
192 }
193
194 #[inline]
196 pub fn take_next_action(&mut self) -> InterpreterAction {
197 self.bytecode.reset_action();
198 let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action");
200 action
201 }
202
203 #[cold]
207 #[inline(never)]
208 pub fn halt(&mut self, result: InstructionResult) {
209 if result == InstructionResult::OutOfGas {
210 self.gas.spend_all();
211 }
212 self.bytecode
213 .set_action(InterpreterAction::new_halt(result, self.gas));
214 }
215
216 #[cold]
220 #[inline(never)]
221 pub fn halt_fatal(&mut self) {
222 self.bytecode.set_action(InterpreterAction::new_halt(
223 InstructionResult::FatalExternalError,
224 self.gas,
225 ));
226 }
227
228 #[cold]
230 #[inline(never)]
231 pub fn halt_load_error(&mut self, err: LoadError) {
232 match err {
233 LoadError::ColdLoadSkipped => self.halt_oog(),
234 LoadError::DBError => self.halt_fatal(),
235 }
236 }
237
238 #[cold]
240 #[inline(never)]
241 pub fn halt_oog(&mut self) {
242 self.gas.spend_all();
243 self.halt(InstructionResult::OutOfGas);
244 }
245
246 #[cold]
248 #[inline(never)]
249 pub fn halt_memory_oog(&mut self) {
250 self.halt(InstructionResult::MemoryOOG);
251 }
252
253 #[cold]
255 #[inline(never)]
256 pub fn halt_memory_limit_oog(&mut self) {
257 self.halt(InstructionResult::MemoryLimitOOG);
258 }
259
260 #[cold]
262 #[inline(never)]
263 pub fn halt_overflow(&mut self) {
264 self.halt(InstructionResult::StackOverflow);
265 }
266
267 #[cold]
269 #[inline(never)]
270 pub fn halt_underflow(&mut self) {
271 self.halt(InstructionResult::StackUnderflow);
272 }
273
274 #[cold]
276 #[inline(never)]
277 pub fn halt_not_activated(&mut self) {
278 self.halt(InstructionResult::NotActivated);
279 }
280
281 pub fn return_with_output(&mut self, output: Bytes) {
285 self.bytecode.set_action(InterpreterAction::new_return(
286 InstructionResult::Return,
287 output,
288 self.gas,
289 ));
290 }
291
292 #[inline]
296 pub fn step<H: Host + ?Sized>(
297 &mut self,
298 instruction_table: &InstructionTable<IW, H>,
299 gas_table: &GasTable,
300 host: &mut H,
301 ) -> InstructionExecResult {
302 let opcode = self.bytecode.opcode();
304
305 self.bytecode.relative_jump(1);
309
310 let instruction = instruction_table[opcode as usize];
311 let static_gas = unsafe { *gas_table.get_unchecked(opcode as usize) };
312
313 if self.gas.record_cost_unsafe(static_gas as u64) {
314 cold_path();
315 return Err(InstructionResult::OutOfGas);
316 }
317
318 instruction.execute(InstructionContext {
319 interpreter: self,
320 host,
321 })
322 }
323
324 #[inline]
326 pub fn run_plain<H: Host + ?Sized>(
327 &mut self,
328 instruction_table: &InstructionTable<IW, H>,
329 gas_table: &GasTable,
330 host: &mut H,
331 ) -> InterpreterAction {
332 let e = loop {
333 if let Err(e) = self.step(instruction_table, gas_table, host) {
334 cold_path();
335 break e;
336 }
337 };
338 if self.bytecode.action().is_none() {
339 self.halt(e);
340 }
341 debug_assert!(self.bytecode.is_end());
342 self.take_next_action()
343 }
344}
345
346#[derive(Clone, Debug, PartialEq, Eq)]
361#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
362pub struct InterpreterResult {
363 pub result: InstructionResult,
365 pub output: Bytes,
367 pub gas: Gas,
369}
370
371impl InterpreterResult {
372 pub const fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
374 Self {
375 result,
376 output,
377 gas,
378 }
379 }
380
381 pub fn new_oog(gas_limit: u64, reservoir: u64) -> Self {
383 Self {
384 result: InstructionResult::OutOfGas,
385 output: Bytes::default(),
386 gas: Gas::new_spent_with_reservoir(gas_limit, reservoir),
387 }
388 }
389
390 #[inline]
392 pub const fn is_ok(&self) -> bool {
393 self.result.is_ok()
394 }
395
396 #[inline]
398 pub const fn is_revert(&self) -> bool {
399 self.result.is_revert()
400 }
401
402 #[inline]
404 pub const fn is_error(&self) -> bool {
405 self.result.is_error()
406 }
407}
408
409impl<IW: InterpreterTypes> Interpreter<IW>
411where
412 IW::Output: From<InterpreterAction>,
413{
414 #[inline]
416 pub fn take_next_action_as_output(&mut self) -> IW::Output {
417 From::from(self.take_next_action())
418 }
419
420 #[inline]
422 pub fn run_plain_as_output<H: Host + ?Sized>(
423 &mut self,
424 instruction_table: &InstructionTable<IW, H>,
425 gas_table: &GasTable,
426 host: &mut H,
427 ) -> IW::Output {
428 From::from(self.run_plain(instruction_table, gas_table, host))
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 #[test]
435 #[cfg(feature = "serde")]
436 fn test_interpreter_serde() {
437 use super::*;
438 use bytecode::Bytecode;
439 use primitives::Bytes;
440
441 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
442 let interpreter = Interpreter::<EthInterpreter>::new(
443 SharedMemory::new(),
444 ExtBytecode::new(bytecode),
445 InputsImpl::default(),
446 false,
447 SpecId::default(),
448 u64::MAX,
449 );
450
451 let serialized = serde_json::to_string_pretty(&interpreter).unwrap();
452 let deserialized: Interpreter<EthInterpreter> = serde_json::from_str(&serialized).unwrap();
453
454 assert_eq!(
455 interpreter.bytecode.pc(),
456 deserialized.bytecode.pc(),
457 "Program counter should be preserved"
458 );
459 }
460}
461
462#[test]
463fn test_mstore_big_offset_memory_oog() {
464 use super::*;
465 use crate::{
466 host::DummyHost,
467 instructions::{gas_table, instruction_table},
468 };
469 use bytecode::Bytecode;
470 use primitives::Bytes;
471
472 let code = Bytes::from(
473 &[
474 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
479 );
480 let bytecode = Bytecode::new_raw(code);
481
482 let mut interpreter = Interpreter::<EthInterpreter>::new(
483 SharedMemory::new(),
484 ExtBytecode::new(bytecode),
485 InputsImpl::default(),
486 false,
487 SpecId::default(),
488 1000,
489 );
490
491 let table = instruction_table::<EthInterpreter, DummyHost>();
492 let gas = gas_table();
493 let mut host = DummyHost::default();
494 let action = interpreter.run_plain(&table, &gas, &mut host);
495
496 assert!(action.is_return());
497 assert_eq!(
498 action.instruction_result(),
499 Some(InstructionResult::MemoryOOG)
500 );
501}
502
503#[test]
504#[cfg(feature = "memory_limit")]
505fn test_mstore_big_offset_memory_limit_oog() {
506 use super::*;
507 use crate::{
508 host::DummyHost,
509 instructions::{gas_table, instruction_table},
510 };
511 use bytecode::Bytecode;
512 use primitives::Bytes;
513
514 let code = Bytes::from(
515 &[
516 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
521 );
522 let bytecode = Bytecode::new_raw(code);
523
524 let mut interpreter = Interpreter::<EthInterpreter>::new(
525 SharedMemory::new_with_memory_limit(1000),
526 ExtBytecode::new(bytecode),
527 InputsImpl::default(),
528 false,
529 SpecId::default(),
530 100000,
531 );
532
533 let table = instruction_table::<EthInterpreter, DummyHost>();
534 let gas = gas_table();
535 let mut host = DummyHost::default();
536 let action = interpreter.run_plain(&table, &gas, &mut host);
537
538 assert!(action.is_return());
539 assert_eq!(
540 action.instruction_result(),
541 Some(InstructionResult::MemoryLimitOOG)
542 );
543}