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 ) {
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(gas_limit);
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 #[must_use]
186 pub fn resize_memory(&mut self, gas_params: &GasParams, offset: usize, len: usize) -> bool {
187 if let Err(result) = resize_memory(&mut self.gas, &mut self.memory, gas_params, offset, len)
188 {
189 self.halt(result);
190 return false;
191 }
192 true
193 }
194
195 #[inline]
197 pub fn take_next_action(&mut self) -> InterpreterAction {
198 self.bytecode.reset_action();
199 let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action");
201 action
202 }
203
204 #[cold]
208 #[inline(never)]
209 pub fn halt(&mut self, result: InstructionResult) {
210 self.bytecode
211 .set_action(InterpreterAction::new_halt(result, self.gas));
212 }
213
214 #[cold]
218 #[inline(never)]
219 pub fn halt_fatal(&mut self) {
220 self.bytecode.set_action(InterpreterAction::new_halt(
221 InstructionResult::FatalExternalError,
222 self.gas,
223 ));
224 }
225
226 #[cold]
228 #[inline(never)]
229 pub fn halt_oog(&mut self) {
230 self.gas.spend_all();
231 self.halt(InstructionResult::OutOfGas);
232 }
233
234 #[cold]
236 #[inline(never)]
237 pub fn halt_memory_oog(&mut self) {
238 self.halt(InstructionResult::MemoryOOG);
239 }
240
241 #[cold]
243 #[inline(never)]
244 pub fn halt_memory_limit_oog(&mut self) {
245 self.halt(InstructionResult::MemoryLimitOOG);
246 }
247
248 #[cold]
250 #[inline(never)]
251 pub fn halt_overflow(&mut self) {
252 self.halt(InstructionResult::StackOverflow);
253 }
254
255 #[cold]
257 #[inline(never)]
258 pub fn halt_underflow(&mut self) {
259 self.halt(InstructionResult::StackUnderflow);
260 }
261
262 #[cold]
264 #[inline(never)]
265 pub fn halt_not_activated(&mut self) {
266 self.halt(InstructionResult::NotActivated);
267 }
268
269 pub fn return_with_output(&mut self, output: Bytes) {
273 self.bytecode.set_action(InterpreterAction::new_return(
274 InstructionResult::Return,
275 output,
276 self.gas,
277 ));
278 }
279
280 #[inline]
284 pub fn step<H: Host + ?Sized>(
285 &mut self,
286 instruction_table: &InstructionTable<IW, H>,
287 host: &mut H,
288 ) {
289 let opcode = self.bytecode.opcode();
291
292 self.bytecode.relative_jump(1);
296
297 let instruction = unsafe { instruction_table.get_unchecked(opcode as usize) };
298
299 if self.gas.record_cost_unsafe(instruction.static_gas()) {
300 return self.halt_oog();
301 }
302 let context = InstructionContext {
303 interpreter: self,
304 host,
305 };
306 instruction.execute(context);
307 }
308
309 #[inline]
315 pub fn step_dummy(&mut self, instruction_table: &InstructionTable<IW, DummyHost>) {
316 self.step(instruction_table, &mut DummyHost::default());
317 }
318
319 #[inline]
321 pub fn run_plain<H: Host + ?Sized>(
322 &mut self,
323 instruction_table: &InstructionTable<IW, H>,
324 host: &mut H,
325 ) -> InterpreterAction {
326 while self.bytecode.is_not_end() {
327 self.step(instruction_table, host);
328 }
329 self.take_next_action()
330 }
331}
332
333#[derive(Clone, Debug, PartialEq, Eq)]
353#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
354pub struct InterpreterResult {
355 pub result: InstructionResult,
357 pub output: Bytes,
359 pub gas: Gas,
361}
362
363impl InterpreterResult {
364 pub fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
366 Self {
367 result,
368 output,
369 gas,
370 }
371 }
372
373 pub fn new_oog(gas_limit: u64) -> Self {
375 Self {
376 result: InstructionResult::OutOfGas,
377 output: Bytes::default(),
378 gas: Gas::new_spent(gas_limit),
379 }
380 }
381
382 #[inline]
384 pub const fn is_ok(&self) -> bool {
385 self.result.is_ok()
386 }
387
388 #[inline]
390 pub const fn is_revert(&self) -> bool {
391 self.result.is_revert()
392 }
393
394 #[inline]
396 pub const fn is_error(&self) -> bool {
397 self.result.is_error()
398 }
399}
400
401impl<IW: InterpreterTypes> Interpreter<IW>
403where
404 IW::Output: From<InterpreterAction>,
405{
406 #[inline]
408 pub fn take_next_action_as_output(&mut self) -> IW::Output {
409 From::from(self.take_next_action())
410 }
411
412 #[inline]
414 pub fn run_plain_as_output<H: Host + ?Sized>(
415 &mut self,
416 instruction_table: &InstructionTable<IW, H>,
417 host: &mut H,
418 ) -> IW::Output {
419 From::from(self.run_plain(instruction_table, host))
420 }
421}
422
423#[cfg(test)]
424mod tests {
425 #[test]
426 #[cfg(feature = "serde")]
427 fn test_interpreter_serde() {
428 use super::*;
429 use bytecode::Bytecode;
430 use primitives::Bytes;
431
432 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
433 let interpreter = Interpreter::<EthInterpreter>::new(
434 SharedMemory::new(),
435 ExtBytecode::new(bytecode),
436 InputsImpl::default(),
437 false,
438 SpecId::default(),
439 u64::MAX,
440 );
441
442 let serialized = serde_json::to_string_pretty(&interpreter).unwrap();
443 let deserialized: Interpreter<EthInterpreter> = serde_json::from_str(&serialized).unwrap();
444
445 assert_eq!(
446 interpreter.bytecode.pc(),
447 deserialized.bytecode.pc(),
448 "Program counter should be preserved"
449 );
450 }
451}
452
453#[test]
454fn test_mstore_big_offset_memory_oog() {
455 use super::*;
456 use crate::{host::DummyHost, instructions::instruction_table};
457 use bytecode::Bytecode;
458 use primitives::Bytes;
459
460 let code = Bytes::from(
461 &[
462 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
467 );
468 let bytecode = Bytecode::new_raw(code);
469
470 let mut interpreter = Interpreter::<EthInterpreter>::new(
471 SharedMemory::new(),
472 ExtBytecode::new(bytecode),
473 InputsImpl::default(),
474 false,
475 SpecId::default(),
476 1000,
477 );
478
479 let table = instruction_table::<EthInterpreter, DummyHost>();
480 let mut host = DummyHost::default();
481 let action = interpreter.run_plain(&table, &mut host);
482
483 assert!(action.is_return());
484 assert_eq!(
485 action.instruction_result(),
486 Some(InstructionResult::MemoryOOG)
487 );
488}
489
490#[test]
491#[cfg(feature = "memory_limit")]
492fn test_mstore_big_offset_memory_limit_oog() {
493 use super::*;
494 use crate::{host::DummyHost, instructions::instruction_table};
495 use bytecode::Bytecode;
496 use primitives::Bytes;
497
498 let code = Bytes::from(
499 &[
500 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
505 );
506 let bytecode = Bytecode::new_raw(code);
507
508 let mut interpreter = Interpreter::<EthInterpreter>::new(
509 SharedMemory::new_with_memory_limit(1000),
510 ExtBytecode::new(bytecode),
511 InputsImpl::default(),
512 false,
513 SpecId::default(),
514 100000,
515 );
516
517 let table = instruction_table::<EthInterpreter, DummyHost>();
518 let mut host = DummyHost::default();
519 let action = interpreter.run_plain(&table, &mut host);
520
521 assert!(action.is_return());
522 assert_eq!(
523 action.instruction_result(),
524 Some(InstructionResult::MemoryLimitOOG)
525 );
526}