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 gas::params::GasParams, host::DummyHost, instruction_context::InstructionContext,
23 interpreter_types::*, Gas, Host, 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 gas_params: GasParams,
34 pub bytecode: WIRE::Bytecode,
36 pub gas: Gas,
38 pub stack: WIRE::Stack,
40 pub return_data: WIRE::ReturnData,
42 pub memory: WIRE::Memory,
44 pub input: WIRE::Input,
46 pub runtime_flag: WIRE::RuntimeFlag,
48 pub extend: WIRE::Extend,
50}
51
52impl<EXT: Default> Interpreter<EthInterpreter<EXT>> {
53 pub fn new(
55 memory: SharedMemory,
56 bytecode: ExtBytecode,
57 input: InputsImpl,
58 is_static: bool,
59 spec_id: SpecId,
60 gas_limit: u64,
61 gas_params: GasParams,
62 ) -> Self {
63 Self::new_inner(
64 Stack::new(),
65 memory,
66 bytecode,
67 input,
68 is_static,
69 spec_id,
70 gas_limit,
71 gas_params,
72 )
73 }
74
75 pub fn default_ext() -> Self {
77 Self::do_default(Stack::new(), SharedMemory::new())
78 }
79
80 pub fn invalid() -> Self {
82 Self::do_default(Stack::invalid(), SharedMemory::invalid())
83 }
84
85 fn do_default(stack: Stack, memory: SharedMemory) -> Self {
86 Self::new_inner(
87 stack,
88 memory,
89 ExtBytecode::default(),
90 InputsImpl::default(),
91 false,
92 SpecId::default(),
93 u64::MAX,
94 GasParams::default(),
95 )
96 }
97
98 #[allow(clippy::too_many_arguments)]
99 fn new_inner(
100 stack: Stack,
101 memory: SharedMemory,
102 bytecode: ExtBytecode,
103 input: InputsImpl,
104 is_static: bool,
105 spec_id: SpecId,
106 gas_limit: u64,
107 gas_params: GasParams,
108 ) -> Self {
109 Self {
110 bytecode,
111 gas: Gas::new(gas_limit),
112 gas_params,
113 stack,
114 return_data: Default::default(),
115 memory,
116 input,
117 runtime_flag: RuntimeFlags { is_static, spec_id },
118 extend: Default::default(),
119 }
120 }
121
122 #[allow(clippy::too_many_arguments)]
124 #[inline(always)]
125 pub fn clear(
126 &mut self,
127 memory: SharedMemory,
128 bytecode: ExtBytecode,
129 input: InputsImpl,
130 is_static: bool,
131 spec_id: SpecId,
132 gas_limit: u64,
133 gas_params: GasParams,
134 ) {
135 let Self {
136 bytecode: bytecode_ref,
137 gas,
138 gas_params: gas_params_ref,
139 stack,
140 return_data,
141 memory: memory_ref,
142 input: input_ref,
143 runtime_flag,
144 extend,
145 } = self;
146 *bytecode_ref = bytecode;
147 *gas = Gas::new(gas_limit);
148 if stack.data().capacity() == 0 {
149 *stack = Stack::new();
150 } else {
151 stack.clear();
152 }
153 return_data.0.clear();
154 *memory_ref = memory;
155 *input_ref = input;
156 *runtime_flag = RuntimeFlags { spec_id, is_static };
157 *gas_params_ref = gas_params;
158 *extend = EXT::default();
159 }
160
161 pub fn with_bytecode(mut self, bytecode: Bytecode) -> Self {
163 self.bytecode = ExtBytecode::new(bytecode);
164 self
165 }
166
167 pub fn set_spec_id(&mut self, spec_id: SpecId) {
169 self.gas_params = GasParams::new_spec(spec_id);
170 self.runtime_flag.spec_id = spec_id;
171 }
172}
173
174impl Default for Interpreter<EthInterpreter> {
175 fn default() -> Self {
176 Self::default_ext()
177 }
178}
179
180#[derive(Debug)]
182pub struct EthInterpreter<EXT = (), MG = SharedMemory> {
183 _phantom: core::marker::PhantomData<fn() -> (EXT, MG)>,
184}
185
186impl<EXT> InterpreterTypes for EthInterpreter<EXT> {
187 type Stack = Stack;
188 type Memory = SharedMemory;
189 type Bytecode = ExtBytecode;
190 type ReturnData = ReturnDataImpl;
191 type Input = InputsImpl;
192 type RuntimeFlag = RuntimeFlags;
193 type Extend = EXT;
194 type Output = InterpreterAction;
195}
196
197impl<IW: InterpreterTypes> Interpreter<IW> {
198 #[inline]
200 #[must_use]
201 pub fn resize_memory(&mut self, offset: usize, len: usize) -> bool {
202 if let Err(result) = resize_memory(
203 &mut self.gas,
204 &mut self.memory,
205 &self.gas_params,
206 offset,
207 len,
208 ) {
209 self.halt(result);
210 return false;
211 }
212 true
213 }
214
215 #[inline]
217 pub fn take_next_action(&mut self) -> InterpreterAction {
218 self.bytecode.reset_action();
219 let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action");
221 action
222 }
223
224 #[cold]
228 #[inline(never)]
229 pub fn halt(&mut self, result: InstructionResult) {
230 self.bytecode
231 .set_action(InterpreterAction::new_halt(result, self.gas));
232 }
233
234 #[cold]
238 #[inline(never)]
239 pub fn halt_fatal(&mut self) {
240 self.bytecode.set_action(InterpreterAction::new_halt(
241 InstructionResult::FatalExternalError,
242 self.gas,
243 ));
244 }
245
246 #[cold]
248 #[inline(never)]
249 pub fn halt_oog(&mut self) {
250 self.gas.spend_all();
251 self.halt(InstructionResult::OutOfGas);
252 }
253
254 #[cold]
256 #[inline(never)]
257 pub fn halt_memory_oog(&mut self) {
258 self.halt(InstructionResult::MemoryOOG);
259 }
260
261 #[cold]
263 #[inline(never)]
264 pub fn halt_memory_limit_oog(&mut self) {
265 self.halt(InstructionResult::MemoryLimitOOG);
266 }
267
268 #[cold]
270 #[inline(never)]
271 pub fn halt_overflow(&mut self) {
272 self.halt(InstructionResult::StackOverflow);
273 }
274
275 #[cold]
277 #[inline(never)]
278 pub fn halt_underflow(&mut self) {
279 self.halt(InstructionResult::StackUnderflow);
280 }
281
282 #[cold]
284 #[inline(never)]
285 pub fn halt_not_activated(&mut self) {
286 self.halt(InstructionResult::NotActivated);
287 }
288
289 pub fn return_with_output(&mut self, output: Bytes) {
293 self.bytecode.set_action(InterpreterAction::new_return(
294 InstructionResult::Return,
295 output,
296 self.gas,
297 ));
298 }
299
300 #[inline]
304 pub fn step<H: Host + ?Sized>(
305 &mut self,
306 instruction_table: &InstructionTable<IW, H>,
307 host: &mut H,
308 ) {
309 let opcode = self.bytecode.opcode();
311
312 self.bytecode.relative_jump(1);
316
317 let instruction = unsafe { instruction_table.get_unchecked(opcode as usize) };
318
319 if self.gas.record_cost_unsafe(instruction.static_gas()) {
320 return self.halt_oog();
321 }
322 let context = InstructionContext {
323 interpreter: self,
324 host,
325 };
326 instruction.execute(context);
327 }
328
329 #[inline]
335 pub fn step_dummy(&mut self, instruction_table: &InstructionTable<IW, DummyHost>) {
336 self.step(instruction_table, &mut DummyHost);
337 }
338
339 #[inline]
341 pub fn run_plain<H: Host + ?Sized>(
342 &mut self,
343 instruction_table: &InstructionTable<IW, H>,
344 host: &mut H,
345 ) -> InterpreterAction {
346 while self.bytecode.is_not_end() {
347 self.step(instruction_table, host);
348 }
349 self.take_next_action()
350 }
351}
352
353#[derive(Clone, Debug, PartialEq, Eq)]
373#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
374pub struct InterpreterResult {
375 pub result: InstructionResult,
377 pub output: Bytes,
379 pub gas: Gas,
381}
382
383impl InterpreterResult {
384 pub fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
386 Self {
387 result,
388 output,
389 gas,
390 }
391 }
392
393 #[inline]
395 pub const fn is_ok(&self) -> bool {
396 self.result.is_ok()
397 }
398
399 #[inline]
401 pub const fn is_revert(&self) -> bool {
402 self.result.is_revert()
403 }
404
405 #[inline]
407 pub const fn is_error(&self) -> bool {
408 self.result.is_error()
409 }
410}
411
412impl<IW: InterpreterTypes> Interpreter<IW>
414where
415 IW::Output: From<InterpreterAction>,
416{
417 #[inline]
419 pub fn take_next_action_as_output(&mut self) -> IW::Output {
420 From::from(self.take_next_action())
421 }
422
423 #[inline]
425 pub fn run_plain_as_output<H: Host + ?Sized>(
426 &mut self,
427 instruction_table: &InstructionTable<IW, H>,
428 host: &mut H,
429 ) -> IW::Output {
430 From::from(self.run_plain(instruction_table, host))
431 }
432}
433
434#[cfg(test)]
435mod tests {
436 #[test]
437 #[cfg(feature = "serde")]
438 fn test_interpreter_serde() {
439 use super::*;
440 use bytecode::Bytecode;
441 use primitives::Bytes;
442
443 let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
444 let interpreter = Interpreter::<EthInterpreter>::new(
445 SharedMemory::new(),
446 ExtBytecode::new(bytecode),
447 InputsImpl::default(),
448 false,
449 SpecId::default(),
450 u64::MAX,
451 GasParams::default(),
452 );
453
454 let serialized = serde_json::to_string_pretty(&interpreter).unwrap();
455 let deserialized: Interpreter<EthInterpreter> = serde_json::from_str(&serialized).unwrap();
456
457 assert_eq!(
458 interpreter.bytecode.pc(),
459 deserialized.bytecode.pc(),
460 "Program counter should be preserved"
461 );
462 }
463}
464
465#[test]
466fn test_mstore_big_offset_memory_oog() {
467 use super::*;
468 use crate::{host::DummyHost, instructions::instruction_table};
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 GasParams::default(),
490 );
491
492 let table = instruction_table::<EthInterpreter, DummyHost>();
493 let mut host = DummyHost;
494 let action = interpreter.run_plain(&table, &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::{host::DummyHost, instructions::instruction_table};
508 use bytecode::Bytecode;
509 use primitives::Bytes;
510
511 let code = Bytes::from(
512 &[
513 0x60, 0x00, 0x61, 0x27, 0x10, 0x52, 0x00, ][..],
518 );
519 let bytecode = Bytecode::new_raw(code);
520
521 let mut interpreter = Interpreter::<EthInterpreter>::new(
522 SharedMemory::new_with_memory_limit(1000),
523 ExtBytecode::new(bytecode),
524 InputsImpl::default(),
525 false,
526 SpecId::default(),
527 100000,
528 GasParams::default(),
529 );
530
531 let table = instruction_table::<EthInterpreter, DummyHost>();
532 let mut host = DummyHost;
533 let action = interpreter.run_plain(&table, &mut host);
534
535 assert!(action.is_return());
536 assert_eq!(
537 action.instruction_result(),
538 Some(InstructionResult::MemoryLimitOOG)
539 );
540}