1pub mod analysis;
2mod contract;
3#[cfg(feature = "serde")]
4pub mod serde;
5mod shared_memory;
6mod stack;
7
8pub use contract::Contract;
9pub use shared_memory::{num_words, SharedMemory, EMPTY_SHARED_MEMORY};
10pub use stack::{Stack, STACK_LIMIT};
11
12use crate::{
13 gas, primitives::Bytes, push, push_b256, return_ok, return_revert, CallOutcome, CreateOutcome,
14 FunctionStack, Gas, Host, InstructionResult, InterpreterAction,
15};
16use core::cmp::min;
17use revm_primitives::{Bytecode, Eof, U256};
18use std::borrow::ToOwned;
19use std::sync::Arc;
20
21#[derive(Debug)]
23pub struct Interpreter {
24 pub instruction_pointer: *const u8,
26 pub gas: Gas,
28 pub contract: Contract,
30 pub instruction_result: InstructionResult,
33 pub bytecode: Bytes,
36 pub is_eof: bool,
39 pub is_eof_init: bool,
41 pub shared_memory: SharedMemory,
46 pub stack: Stack,
48 pub function_stack: FunctionStack,
50 pub return_data_buffer: Bytes,
56 pub is_static: bool,
58 pub next_action: InterpreterAction,
63}
64
65impl Default for Interpreter {
66 fn default() -> Self {
67 Self::new(Contract::default(), u64::MAX, false)
68 }
69}
70
71impl Interpreter {
72 pub fn new(contract: Contract, gas_limit: u64, is_static: bool) -> Self {
74 if !contract.bytecode.is_execution_ready() {
75 panic!("Contract is not execution ready {:?}", contract.bytecode);
76 }
77 let is_eof = contract.bytecode.is_eof();
78 let bytecode = contract.bytecode.bytecode().clone();
79 Self {
80 instruction_pointer: bytecode.as_ptr(),
81 bytecode,
82 contract,
83 gas: Gas::new(gas_limit),
84 instruction_result: InstructionResult::Continue,
85 function_stack: FunctionStack::default(),
86 is_static,
87 is_eof,
88 is_eof_init: false,
89 return_data_buffer: Bytes::new(),
90 shared_memory: EMPTY_SHARED_MEMORY,
91 stack: Stack::new(),
92 next_action: InterpreterAction::None,
93 }
94 }
95
96 #[inline]
98 pub fn set_is_eof_init(&mut self) {
99 self.is_eof_init = true;
100 }
101
102 #[inline]
103 pub fn eof(&self) -> Option<&Arc<Eof>> {
104 self.contract.bytecode.eof()
105 }
106
107 #[cfg(test)]
109 pub fn new_bytecode(bytecode: Bytecode) -> Self {
110 Self::new(
111 Contract::new(
112 Bytes::new(),
113 bytecode,
114 None,
115 crate::primitives::Address::default(),
116 None,
117 crate::primitives::Address::default(),
118 U256::ZERO,
119 ),
120 0,
121 false,
122 )
123 }
124
125 pub(crate) fn load_eof_code(&mut self, idx: usize, pc: usize) {
127 let Bytecode::Eof(eof) = &self.contract.bytecode else {
129 panic!("Expected EOF code section")
130 };
131 let Some(code) = eof.body.code(idx) else {
132 panic!("Code not found")
133 };
134 self.bytecode = code.clone();
135 self.instruction_pointer = unsafe { self.bytecode.as_ptr().add(pc) };
136 }
137
138 pub fn insert_create_outcome(&mut self, create_outcome: CreateOutcome) {
164 self.instruction_result = InstructionResult::Continue;
165
166 let instruction_result = create_outcome.instruction_result();
167 self.return_data_buffer = if instruction_result.is_revert() {
168 create_outcome.output().to_owned()
170 } else {
171 Bytes::new()
173 };
174
175 match instruction_result {
176 return_ok!() => {
177 let address = create_outcome.address;
178 push_b256!(self, address.unwrap_or_default().into_word());
179 self.gas.erase_cost(create_outcome.gas().remaining());
180 self.gas.record_refund(create_outcome.gas().refunded());
181 }
182 return_revert!() => {
183 push!(self, U256::ZERO);
184 self.gas.erase_cost(create_outcome.gas().remaining());
185 }
186 InstructionResult::FatalExternalError => {
187 panic!("Fatal external error in insert_create_outcome");
188 }
189 _ => {
190 push!(self, U256::ZERO);
191 }
192 }
193 }
194
195 pub fn insert_eofcreate_outcome(&mut self, create_outcome: CreateOutcome) {
196 self.instruction_result = InstructionResult::Continue;
197 let instruction_result = create_outcome.instruction_result();
198
199 self.return_data_buffer = if *instruction_result == InstructionResult::Revert {
200 create_outcome.output().to_owned()
202 } else {
203 Bytes::new()
205 };
206
207 match instruction_result {
208 InstructionResult::ReturnContract => {
209 push_b256!(
210 self,
211 create_outcome.address.expect("EOF Address").into_word()
212 );
213 self.gas.erase_cost(create_outcome.gas().remaining());
214 self.gas.record_refund(create_outcome.gas().refunded());
215 }
216 return_revert!() => {
217 push!(self, U256::ZERO);
218 self.gas.erase_cost(create_outcome.gas().remaining());
219 }
220 InstructionResult::FatalExternalError => {
221 panic!("Fatal external error in insert_eofcreate_outcome");
222 }
223 _ => {
224 push!(self, U256::ZERO);
225 }
226 }
227 }
228
229 pub fn insert_call_outcome(
252 &mut self,
253 shared_memory: &mut SharedMemory,
254 call_outcome: CallOutcome,
255 ) {
256 self.instruction_result = InstructionResult::Continue;
257
258 let out_offset = call_outcome.memory_start();
259 let out_len = call_outcome.memory_length();
260 let out_ins_result = *call_outcome.instruction_result();
261 let out_gas = call_outcome.gas();
262 self.return_data_buffer = call_outcome.result.output;
263
264 let target_len = min(out_len, self.return_data_buffer.len());
265 match out_ins_result {
266 return_ok!() => {
267 self.gas.erase_cost(out_gas.remaining());
269 self.gas.record_refund(out_gas.refunded());
270 shared_memory.set(out_offset, &self.return_data_buffer[..target_len]);
271 push!(
272 self,
273 if self.is_eof {
274 U256::ZERO
275 } else {
276 U256::from(1)
277 }
278 );
279 }
280 return_revert!() => {
281 self.gas.erase_cost(out_gas.remaining());
282 shared_memory.set(out_offset, &self.return_data_buffer[..target_len]);
283 push!(
284 self,
285 if self.is_eof {
286 U256::from(1)
287 } else {
288 U256::ZERO
289 }
290 );
291 }
292 InstructionResult::FatalExternalError => {
293 panic!("Fatal external error in insert_call_outcome");
294 }
295 _ => {
296 push!(
297 self,
298 if self.is_eof {
299 U256::from(2)
300 } else {
301 U256::ZERO
302 }
303 );
304 }
305 }
306 }
307
308 #[inline]
310 pub fn current_opcode(&self) -> u8 {
311 unsafe { *self.instruction_pointer }
312 }
313
314 #[inline]
316 pub fn contract(&self) -> &Contract {
317 &self.contract
318 }
319
320 #[inline]
322 pub fn gas(&self) -> &Gas {
323 &self.gas
324 }
325
326 #[inline]
328 pub fn stack(&self) -> &Stack {
329 &self.stack
330 }
331
332 #[inline]
334 pub fn stack_mut(&mut self) -> &mut Stack {
335 &mut self.stack
336 }
337
338 #[inline]
340 pub fn program_counter(&self) -> usize {
341 unsafe { self.instruction_pointer.offset_from(self.bytecode.as_ptr()) as usize }
344 }
345
346 #[inline]
350 pub(crate) fn step<FN, H: Host + ?Sized>(&mut self, instruction_table: &[FN; 256], host: &mut H)
351 where
352 FN: Fn(&mut Interpreter, &mut H),
353 {
354 let opcode = unsafe { *self.instruction_pointer };
356
357 self.instruction_pointer = unsafe { self.instruction_pointer.offset(1) };
361
362 (instruction_table[opcode as usize])(self, host)
364 }
365
366 pub fn take_memory(&mut self) -> SharedMemory {
368 core::mem::replace(&mut self.shared_memory, EMPTY_SHARED_MEMORY)
369 }
370
371 pub fn run<FN, H: Host + ?Sized>(
373 &mut self,
374 shared_memory: SharedMemory,
375 instruction_table: &[FN; 256],
376 host: &mut H,
377 ) -> InterpreterAction
378 where
379 FN: Fn(&mut Interpreter, &mut H),
380 {
381 self.next_action = InterpreterAction::None;
382 self.shared_memory = shared_memory;
383 while self.instruction_result == InstructionResult::Continue {
385 self.step(instruction_table, host);
386 }
387
388 if self.next_action.is_some() {
390 return core::mem::take(&mut self.next_action);
391 }
392 InterpreterAction::Return {
394 result: InterpreterResult {
395 result: self.instruction_result,
396 output: Bytes::new(),
398 gas: self.gas,
399 },
400 }
401 }
402
403 #[inline]
405 #[must_use]
406 pub fn resize_memory(&mut self, new_size: usize) -> bool {
407 resize_memory(&mut self.shared_memory, &mut self.gas, new_size)
408 }
409}
410
411#[derive(Clone, Debug, PartialEq, Eq)]
413#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
414pub struct InterpreterResult {
415 pub result: InstructionResult,
417 pub output: Bytes,
419 pub gas: Gas,
421}
422
423impl InterpreterResult {
424 pub fn new(result: InstructionResult, output: Bytes, gas: Gas) -> Self {
426 Self {
427 result,
428 output,
429 gas,
430 }
431 }
432
433 #[inline]
435 pub const fn is_ok(&self) -> bool {
436 self.result.is_ok()
437 }
438
439 #[inline]
441 pub const fn is_revert(&self) -> bool {
442 self.result.is_revert()
443 }
444
445 #[inline]
447 pub const fn is_error(&self) -> bool {
448 self.result.is_error()
449 }
450}
451
452#[inline(never)]
454#[cold]
455#[must_use]
456pub fn resize_memory(memory: &mut SharedMemory, gas: &mut Gas, new_size: usize) -> bool {
457 let new_words = num_words(new_size as u64);
458 let new_cost = gas::memory_gas(new_words);
459 let current_cost = memory.current_expansion_cost();
460 let cost = new_cost - current_cost;
461 let success = gas.record_cost(cost);
462 if success {
463 memory.resize((new_words as usize) * 32);
464 }
465 success
466}
467
468#[cfg(test)]
469mod tests {
470 use super::*;
471 use crate::{opcode::InstructionTable, DummyHost};
472 use revm_primitives::CancunSpec;
473
474 #[test]
475 fn object_safety() {
476 let mut interp = Interpreter::new(Contract::default(), u64::MAX, false);
477
478 let mut host = crate::DummyHost::default();
479 let table: &InstructionTable<DummyHost> =
480 &crate::opcode::make_instruction_table::<DummyHost, CancunSpec>();
481 let _ = interp.run(EMPTY_SHARED_MEMORY, table, &mut host);
482
483 let host: &mut dyn Host = &mut host as &mut dyn Host;
484 let table: &InstructionTable<dyn Host> =
485 &crate::opcode::make_instruction_table::<dyn Host, CancunSpec>();
486 let _ = interp.run(EMPTY_SHARED_MEMORY, table, host);
487 }
488}