diff --git a/Cargo.lock b/Cargo.lock index 26844a7d1d..f85875c7d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3408,7 +3408,6 @@ dependencies = [ "revm-primitives", "revm-specification", "serde", - "serde_json", "walkdir", ] diff --git a/crates/handler/src/frame.rs b/crates/handler/src/frame.rs index 53814cbced..7a01a19102 100644 --- a/crates/handler/src/frame.rs +++ b/crates/handler/src/frame.rs @@ -78,7 +78,6 @@ where Instructions: InstructionProvider< Context = EVM::Context, InterpreterTypes = EthInterpreter, - Output = InterpreterAction, >, >, ERROR: From> + From, @@ -519,7 +518,6 @@ where Instructions: InstructionProvider< Context = EVM::Context, InterpreterTypes = EthInterpreter, - Output = InterpreterAction, >, >, ERROR: From> + From, @@ -629,7 +627,7 @@ where let interpreter = &mut self.interpreter; let mem_length = outcome.memory_length(); let mem_start = outcome.memory_start(); - *interpreter.return_data.buffer_mut() = outcome.result.output; + interpreter.return_data.set_buffer(outcome.result.output); let target_len = min(mem_length, returned_len); @@ -675,13 +673,14 @@ where let instruction_result = *outcome.instruction_result(); let interpreter = &mut self.interpreter; - let buffer = interpreter.return_data.buffer_mut(); if instruction_result == InstructionResult::Revert { // Save data to return data buffer if the create reverted - *buffer = outcome.output().to_owned() + interpreter + .return_data + .set_buffer(outcome.output().to_owned()); } else { // Otherwise clear it. Note that RETURN opcode should abort. - buffer.clear(); + interpreter.return_data.clear(); }; assert_ne!( @@ -710,10 +709,12 @@ where let interpreter = &mut self.interpreter; if instruction_result == InstructionResult::Revert { // Save data to return data buffer if the create reverted - *interpreter.return_data.buffer_mut() = outcome.output().to_owned() + interpreter + .return_data + .set_buffer(outcome.output().to_owned()); } else { // Otherwise clear it. Note that RETURN opcode should abort. - interpreter.return_data.buffer_mut().clear(); + interpreter.return_data.clear() }; assert_ne!( diff --git a/crates/handler/src/handler.rs b/crates/handler/src/handler.rs index f8fcfec605..afd0f15835 100644 --- a/crates/handler/src/handler.rs +++ b/crates/handler/src/handler.rs @@ -10,7 +10,9 @@ use context_interface::{ Cfg, Database, Journal, Transaction, }; use core::mem; -use interpreter::{FrameInput, Host, InitialAndFloorGas, Interpreter, InterpreterAction}; +use interpreter::{ + FrameInput, Host, InitialAndFloorGas, Interpreter, InterpreterAction, InterpreterTypes, +}; use precompile::PrecompileError; use primitives::Log; use state::EvmState; @@ -37,7 +39,10 @@ impl< impl EvmTr for Evm where CTX: ContextTr + Host, - I: InstructionProvider, + I: InstructionProvider< + Context = CTX, + InterpreterTypes: InterpreterTypes, + >, { type Context = CTX; type Instructions = I; @@ -49,7 +54,8 @@ where interpreter: &mut Interpreter< ::InterpreterTypes, >, - ) -> ::Output { + ) -> <::InterpreterTypes as InterpreterTypes>::Output + { let context = &mut self.data.ctx; let instructions = &mut self.instruction; interpreter.run_plain(instructions.instruction_table(), context) @@ -86,7 +92,7 @@ pub trait EvmTr { interpreter: &mut Interpreter< ::InterpreterTypes, >, - ) -> ::Output; + ) -> <::InterpreterTypes as InterpreterTypes>::Output; fn ctx(&mut self) -> &mut Self::Context; diff --git a/crates/handler/src/instructions.rs b/crates/handler/src/instructions.rs index bc58e905de..eceae21c10 100644 --- a/crates/handler/src/instructions.rs +++ b/crates/handler/src/instructions.rs @@ -1,23 +1,25 @@ use auto_impl::auto_impl; -use context_interface::ContextTr; use interpreter::{ - table::{make_instruction_table, InstructionTable}, - Host, Interpreter, InterpreterAction, InterpreterTypes, + instructions::{instruction_table, InstructionTable}, + Host, Instruction, InterpreterTypes, }; -use std::rc::Rc; +use std::boxed::Box; /// Stores instructions for EVM. #[auto_impl(&, Arc, Rc)] pub trait InstructionProvider { + /// Context type. type Context; + /// Interpreter types. type InterpreterTypes: InterpreterTypes; - type Output; + /// Returns the instruction table that is used by EvmTr to execute instructions. fn instruction_table(&self) -> &InstructionTable; } +/// Ethereum instruction contains list of mainnet instructions that is used for Interpreter execution. pub struct EthInstructions { - pub instruction_table: Rc>, + pub instruction_table: Box>, } impl Clone for EthInstructions @@ -36,26 +38,22 @@ where WIRE: InterpreterTypes, HOST: Host, { + /// Returns `EthInstructions` with mainnet spec. pub fn new_mainnet() -> Self { - Self::new(make_instruction_table::()) + Self::new(instruction_table::()) } + /// Rerurns new `EthInstructions` with custom instruction table. pub fn new(base_table: InstructionTable) -> Self { Self { - instruction_table: Rc::new(base_table), + instruction_table: Box::new(base_table), } } -} - -pub trait ContextInspectRun { - type InterpreterTypes: InterpreterTypes; - type Context: ContextTr + Host; - fn run_context( - &mut self, - interpretere: Interpreter, - instructions: &InstructionTable, - ); + /// Inserts a new instruction into the instruction table.s + pub fn insert_instruction(&mut self, opcode: u8, instruction: Instruction) { + self.instruction_table[opcode as usize] = instruction; + } } impl InstructionProvider for EthInstructions @@ -65,9 +63,6 @@ where { type InterpreterTypes = IT; type Context = CTX; - /// TODO Interpreter action could be tied to InterpreterTypes so we can - /// set custom actions from instructions. - type Output = InterpreterAction; fn instruction_table(&self) -> &InstructionTable { &self.instruction_table diff --git a/crates/inspector/src/inspector.rs b/crates/inspector/src/inspector.rs index 1043ccf10c..db40cad519 100644 --- a/crates/inspector/src/inspector.rs +++ b/crates/inspector/src/inspector.rs @@ -7,9 +7,9 @@ use handler::{ execution, EvmTr, Frame, FrameInitOrResult, FrameOrResult, FrameResult, Handler, ItemOrResult, }; use interpreter::{ + instructions::InstructionTable, interpreter::EthInterpreter, interpreter_types::{Jumps, LoopControl}, - table::InstructionTable, CallInputs, CallOutcome, CreateInputs, CreateOutcome, EOFCreateInputs, FrameInput, Host, InitialAndFloorGas, InstructionResult, Interpreter, InterpreterAction, InterpreterTypes, }; @@ -17,7 +17,7 @@ use primitives::{Address, Log, U256}; use state::EvmState; use std::{vec, vec::Vec}; -/// EVM [Interpreter] callbacks. +/// EVM hooks into execution. #[auto_impl(&mut, Box)] pub trait Inspector { /// Called before the interpreter is initialized. diff --git a/crates/inspector/src/traits.rs b/crates/inspector/src/traits.rs index 78d7997c9b..3bdb5abcb2 100644 --- a/crates/inspector/src/traits.rs +++ b/crates/inspector/src/traits.rs @@ -23,13 +23,16 @@ pub trait InspectorEvmTr: EvmTr { interpreter: &mut Interpreter< ::InterpreterTypes, >, - ) -> ::Output; + ) -> <::InterpreterTypes as InterpreterTypes>::Output; } impl InspectorEvmTr for Evm where CTX: ContextTr + ContextSetters, - I: InstructionProvider, + I: InstructionProvider< + Context = CTX, + InterpreterTypes: InterpreterTypes, + >, INSP: Inspector, { type Inspector = INSP; @@ -47,7 +50,8 @@ where interpreter: &mut Interpreter< ::InterpreterTypes, >, - ) -> ::Output { + ) -> <::InterpreterTypes as InterpreterTypes>::Output + { let context = &mut self.data.ctx; let instructions = &mut self.instruction; let inspector = &mut self.data.inspector; @@ -80,7 +84,6 @@ where Instructions: InstructionProvider< Context = EVM::Context, InterpreterTypes = EthInterpreter, - Output = InterpreterAction, >, > + InspectorEvmTr, ERROR: From> + From, diff --git a/crates/interpreter/Cargo.toml b/crates/interpreter/Cargo.toml index 76650e3411..bf3ab5f118 100644 --- a/crates/interpreter/Cargo.toml +++ b/crates/interpreter/Cargo.toml @@ -34,7 +34,6 @@ serde = { workspace = true, features = ["derive", "rc"], optional = true } [dev-dependencies] database-interface.workspace = true walkdir.workspace = true -serde_json.workspace = true bincode.workspace = true [features] diff --git a/crates/interpreter/src/host.rs b/crates/interpreter/src/host.rs index 28953a9df6..2d4ee59348 100644 --- a/crates/interpreter/src/host.rs +++ b/crates/interpreter/src/host.rs @@ -264,3 +264,109 @@ impl Host for CTX { .ok() } } + +/// Dummy host that implements [`Host`] trait and returns all default values. +pub struct DummyHost; + +impl Host for DummyHost { + fn basefee(&self) -> U256 { + U256::ZERO + } + + fn blob_gasprice(&self) -> U256 { + U256::ZERO + } + + fn gas_limit(&self) -> U256 { + U256::ZERO + } + + fn difficulty(&self) -> U256 { + U256::ZERO + } + + fn prevrandao(&self) -> Option { + None + } + + fn block_number(&self) -> u64 { + 0 + } + + fn timestamp(&self) -> U256 { + U256::ZERO + } + + fn beneficiary(&self) -> Address { + Address::ZERO + } + + fn chain_id(&self) -> U256 { + U256::ZERO + } + + fn effective_gas_price(&self) -> U256 { + U256::ZERO + } + + fn caller(&self) -> Address { + Address::ZERO + } + + fn blob_hash(&self, _number: usize) -> Option { + None + } + + fn max_initcode_size(&self) -> usize { + 0 + } + + fn block_hash(&mut self, _number: u64) -> Option { + None + } + + fn selfdestruct( + &mut self, + _address: Address, + _target: Address, + ) -> Option> { + None + } + + fn log(&mut self, _log: Log) {} + + fn sstore( + &mut self, + _address: Address, + _key: U256, + _value: U256, + ) -> Option> { + None + } + + fn sload(&mut self, _address: Address, _key: U256) -> Option> { + None + } + + fn tstore(&mut self, _address: Address, _key: U256, _value: U256) {} + + fn tload(&mut self, _address: Address, _key: U256) -> U256 { + U256::ZERO + } + + fn balance(&mut self, _address: Address) -> Option> { + None + } + + fn load_account_delegated(&mut self, _address: Address) -> Option> { + None + } + + fn load_account_code(&mut self, _address: Address) -> Option> { + None + } + + fn load_account_code_hash(&mut self, _address: Address) -> Option> { + None + } +} diff --git a/crates/interpreter/src/instructions.rs b/crates/interpreter/src/instructions.rs index 9830df9586..1d1fff3cd5 100644 --- a/crates/interpreter/src/instructions.rs +++ b/crates/interpreter/src/instructions.rs @@ -16,20 +16,19 @@ pub mod system; pub mod tx_info; pub mod utility; -use crate::{interpreter_types::InterpreterTypes, Host}; - -/// Returns the instruction function for the given opcode and spec. -pub const fn instruction( - opcode: u8, -) -> crate::table::Instruction { - let table = instruction_table::(); - table[opcode as usize] -} +use crate::{interpreter_types::InterpreterTypes, Host, Interpreter}; + +/// EVM opcode function signature. +pub type Instruction = for<'a> fn(&'a mut Interpreter, &'a mut H); + +/// Instruction table is list of instruction function pointers mapped to 256 EVM opcodes. +pub type InstructionTable = [Instruction; 256]; +/// Returns the instruction table for the given spec. pub const fn instruction_table( -) -> [crate::table::Instruction; 256] { +) -> [Instruction; 256] { use bytecode::opcode::*; - let mut table = [control::unknown as crate::table::Instruction; 256]; + let mut table = [control::unknown as Instruction; 256]; table[STOP as usize] = control::stop; table[ADD as usize] = arithmetic::add; @@ -219,25 +218,26 @@ pub const fn instruction_table( #[cfg(test)] mod tests { - // use super::*; - // use crate::DummyHost; - // use bytecode::opcode::*; - - // #[test] - // fn all_instructions_and_opcodes_used() { - // // known unknown instruction we compare it with other instructions from table. - // let unknown_instruction = 0x0C_usize; - // let instr_table = instruction_table::>(); - - // let unknown_istr = instr_table[unknown_instruction]; - // for (i, instr) in instr_table.iter().enumerate() { - // let is_opcode_unknown = OpCode::new(i as u8).is_none(); - // let is_instr_unknown = *instr == unknown_istr; - // assert_eq!( - // is_instr_unknown, is_opcode_unknown, - // "Opcode 0x{:X?} is not handled", - // i - // ); - // } - // } + use super::instruction_table; + use crate::{host::DummyHost, interpreter::EthInterpreter}; + use bytecode::opcode::*; + + #[test] + fn all_instructions_and_opcodes_used() { + // known unknown instruction we compare it with other instructions from table. + let unknown_instruction = 0x0C_usize; + let instr_table = instruction_table::(); + + let unknown_istr = instr_table[unknown_instruction]; + for (i, instr) in instr_table.iter().enumerate() { + let is_opcode_unknown = OpCode::new(i as u8).is_none(); + // + let is_instr_unknown = std::ptr::fn_addr_eq(*instr, unknown_istr); + assert_eq!( + is_instr_unknown, is_opcode_unknown, + "Opcode 0x{:X?} is not handled", + i + ); + } + } } diff --git a/crates/interpreter/src/instructions/contract.rs b/crates/interpreter/src/instructions/contract.rs index ea4c762759..13199db8b0 100644 --- a/crates/interpreter/src/instructions/contract.rs +++ b/crates/interpreter/src/instructions/contract.rs @@ -214,7 +214,7 @@ pub fn extcall_gas_calc( // Push 1 to stack to indicate that call light failed. // It is safe to ignore stack overflow error as we already popped multiple values from stack. let _ = interpreter.stack.push(U256::from(1)); - interpreter.return_data.buffer_mut().clear(); + interpreter.return_data.clear(); // Return none to continue execution. return None; } diff --git a/crates/interpreter/src/interpreter.rs b/crates/interpreter/src/interpreter.rs index 62a95c284e..de9b49197a 100644 --- a/crates/interpreter/src/interpreter.rs +++ b/crates/interpreter/src/interpreter.rs @@ -8,9 +8,8 @@ mod stack; mod subroutine_stack; use crate::{ - interpreter_types::*, - table::{CustomInstruction, InstructionTable}, - Gas, Host, Instruction, InstructionResult, InterpreterAction, + interpreter_types::*, Gas, Host, Instruction, InstructionResult, InstructionTable, + InterpreterAction, }; use core::cell::RefCell; pub use ext_bytecode::ExtBytecode; @@ -25,6 +24,7 @@ pub use stack::{Stack, STACK_LIMIT}; use std::rc::Rc; use subroutine_stack::SubRoutineImpl; +/// Main interpreter structure that contains all components defines in [`InterpreterTypes`].s #[derive(Debug, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct Interpreter { @@ -71,6 +71,7 @@ impl Interpreter> { } } +/// Default types for Ethereum interpreter. pub struct EthInterpreter { _phantom: core::marker::PhantomData (EXT, MG)>, } @@ -85,23 +86,10 @@ impl InterpreterTypes for EthInterpreter { type Control = LoopControlImpl; type RuntimeFlag = RuntimeFlags; type Extend = EXT; + type Output = InterpreterAction; } -impl CustomInstruction for Instruction { - type Wire = IW; - type Host = H; - - #[inline] - fn exec(&self, interpreter: &mut Interpreter, host: &mut Self::Host) { - (self)(interpreter, host); - } - - #[inline] - fn from_base(instruction: Instruction) -> Self { - instruction - } -} - +// TODO InterpreterAction should be replaces with InterpreterTypes::Output. impl Interpreter { /// Executes the instruction at the current instruction pointer. /// @@ -121,15 +109,18 @@ impl Interpreter { self.bytecode.relative_jump(1); // Execute instruction. - instruction_table[opcode as usize].exec(self, host) + instruction_table[opcode as usize](self, host) } + /// Resets the control to the initial state. so that we can run the interpreter again. #[inline] pub fn reset_control(&mut self) { self.control .set_next_action(InterpreterAction::None, InstructionResult::Continue); } + /// Takes the next action from the control and returns it. + #[inline] pub fn take_next_action(&mut self) -> InterpreterAction { // Return next action if it is some. let action = self.control.take_next_action(); @@ -148,6 +139,7 @@ impl Interpreter { } /// Executes the interpreter until it returns or stops. + #[inline] pub fn run_plain( &mut self, instruction_table: &InstructionTable, @@ -207,13 +199,13 @@ impl InterpreterResult { #[cfg(test)] mod tests { - use super::*; - use bytecode::Bytecode; - use primitives::{Address, Bytes, U256}; - #[test] #[cfg(feature = "serde")] fn test_interpreter_serde() { + use super::*; + use bytecode::Bytecode; + use primitives::{Address, Bytes, U256}; + let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..])); let interpreter = Interpreter::::new( Rc::new(RefCell::new(SharedMemory::new())), diff --git a/crates/interpreter/src/interpreter/return_data.rs b/crates/interpreter/src/interpreter/return_data.rs index 8940ea78aa..9bfd44aaff 100644 --- a/crates/interpreter/src/interpreter/return_data.rs +++ b/crates/interpreter/src/interpreter/return_data.rs @@ -12,7 +12,7 @@ impl ReturnData for ReturnDataImpl { self.0.as_ref() } - fn buffer_mut(&mut self) -> &mut Bytes { - &mut self.0 + fn set_buffer(&mut self, bytes: Bytes) { + self.0 = bytes; } } diff --git a/crates/interpreter/src/interpreter_types.rs b/crates/interpreter/src/interpreter_types.rs index 5c0cde7e42..a2e4f33a61 100644 --- a/crates/interpreter/src/interpreter_types.rs +++ b/crates/interpreter/src/interpreter_types.rs @@ -19,6 +19,7 @@ pub trait Immediates { fn read_slice(&self, len: usize) -> &[u8]; } +/// Trait for fetching inputs of the call. pub trait InputsTr { fn target_address(&self) -> Address; fn caller_address(&self) -> Address; @@ -26,12 +27,17 @@ pub trait InputsTr { fn call_value(&self) -> U256; } +/// Trait needed for legacy bytecode. +/// +/// Used in [`bytecode::opcode::CODECOPY`] and [`bytecode::opcode::CODESIZE`] opcodes. pub trait LegacyBytecode { + /// Returns current bytecode original length. Used in [`bytecode::opcode::CODESIZE`] opcode. fn bytecode_len(&self) -> usize; + /// Returns current bytecode original slice. Used in [`bytecode::opcode::CODECOPY`] opcode. fn bytecode_slice(&self) -> &[u8]; } -/// Trait for interpreter to be able to jump +/// Trait for Interpreter to be able to jump pub trait Jumps { /// Relative jumps does not require checking for overflow. fn relative_jump(&mut self, offset: isize); @@ -46,16 +52,34 @@ pub trait Jumps { fn opcode(&self) -> u8; } +/// Trait for Interpreter memory operations. pub trait MemoryTr { + /// Sets memory data at given offset from data with a given data_offset and len. + /// + /// # Panics + /// + /// Panics if range is out of scope of allocated memory. fn set_data(&mut self, memory_offset: usize, data_offset: usize, len: usize, data: &[u8]); + /// Sets memory data at given offset. + /// + /// # Panics + /// + /// Panics if range is out of scope of allocated memory. fn set(&mut self, memory_offset: usize, data: &[u8]); + /// Returns memory size. fn size(&self) -> usize; + + /// Copies memory data from source to destination. + /// + /// # Panics + /// Panics if range is out of scope of allocated memory. fn copy(&mut self, destination: usize, source: usize, len: usize); /// Memory slice with range /// /// # Panics + /// /// Panics if range is out of scope of allocated memory. fn slice(&self, range: Range) -> impl Deref + '_; @@ -69,24 +93,34 @@ pub trait MemoryTr { /// Resizes memory to new size /// /// # Note + /// /// It checks memory limits. fn resize(&mut self, new_size: usize) -> bool; } +/// Returns EOF containers. Used by [`bytecode::opcode::RETURNCONTRACT`] and [`bytecode::opcode::EOFCREATE`] opcodes. pub trait EofContainer { + /// Returns EOF container at given index. fn eof_container(&self, index: usize) -> Option<&Bytes>; } +/// Handles EOF introduced sub routine calls. pub trait SubRoutineStack { + /// Returns sub routine stack length. fn len(&self) -> usize; + /// Returns `true` if sub routine stack is empty. fn is_empty(&self) -> bool { self.len() == 0 } + /// Returns current sub routine index. fn routine_idx(&self) -> usize; /// Sets new code section without touching subroutine stack. + /// + /// This is used for [`bytecode::opcode::JUMPF`] opcode. Where + /// tail call is performed. fn set_routine_idx(&mut self, idx: usize); /// Pushes a new frame to the stack and new code index. @@ -94,11 +128,9 @@ pub trait SubRoutineStack { /// Pops previous subroutine, sets previous code index and returns program counter. fn pop(&mut self) -> Option; - - // /// Returns code info from EOF body. - // fn eof_code_info(&self, idx: usize) -> Option<&CodeInfo>; } +/// Functions needed for Interpreter Stack operations. pub trait StackTr { /// Returns stack length. fn len(&self) -> usize; @@ -117,6 +149,9 @@ pub trait StackTr { #[must_use] fn push(&mut self, value: U256) -> bool; + /// Pushes B256 value to the stack. + /// + /// Internally converts B256 to U256 and then calls [`StackTr::push`]. #[must_use] fn push_b256(&mut self, value: B256) -> bool { self.push(value.into()) @@ -142,6 +177,9 @@ pub trait StackTr { self.popn::<1>().map(|[value]| value) } + /// Pops address from the stack. + /// + /// Internally call [`StackTr::pop`] and converts [`U256`] into [`Address`]. #[must_use] fn pop_address(&mut self) -> Option
{ self.pop().map(|value| Address::from(value.to_be_bytes())) @@ -164,12 +202,17 @@ pub trait StackTr { fn dup(&mut self, n: usize) -> bool; } +/// EOF data fetching. pub trait EofData { + /// Returns EOF data. fn data(&self) -> &[u8]; + /// Returns EOF data slice. fn data_slice(&self, offset: usize, len: usize) -> &[u8]; + /// Returns EOF data size. fn data_size(&self) -> usize; } +/// EOF code info. pub trait EofCodeInfo { /// Returns code information containing stack information. fn code_info(&self, idx: usize) -> Option<&CodeInfo>; @@ -178,9 +221,18 @@ pub trait EofCodeInfo { fn code_section_pc(&self, idx: usize) -> Option; } +/// Returns return data. pub trait ReturnData { + /// Returns return data. fn buffer(&self) -> &[u8]; - fn buffer_mut(&mut self) -> &mut Bytes; + + /// Sets return buffer. + fn set_buffer(&mut self, bytes: Bytes); + + /// Clears return buffer. + fn clear(&mut self) { + self.set_buffer(Bytes::new()); + } } pub trait LoopControl { @@ -216,4 +268,5 @@ pub trait InterpreterTypes { type Control: LoopControl; type RuntimeFlag: RuntimeFlag; type Extend; + type Output; } diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index 541ffdfe90..f4d3faeb80 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -1,6 +1,6 @@ //! # revm-interpreter //! -//! REVM Interpreter. +//! Interpreter is part of the project that executes EVM instructions. #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(not(feature = "std"), no_std)] @@ -10,13 +10,6 @@ extern crate alloc as std; #[macro_use] mod macros; -// silence lint -#[cfg(test)] -use serde_json as _; - -#[cfg(test)] -use walkdir as _; - pub mod gas; pub mod host; mod instruction_result; @@ -24,7 +17,6 @@ pub mod instructions; pub mod interpreter; pub mod interpreter_action; pub mod interpreter_types; -pub mod table; // Reexport primary types. pub use context_interface::{ @@ -34,6 +26,7 @@ pub use context_interface::{ pub use gas::{Gas, InitialAndFloorGas}; pub use host::Host; pub use instruction_result::*; +pub use instructions::{instruction_table, Instruction, InstructionTable}; pub use interpreter::{ num_words, InputsImpl, Interpreter, InterpreterResult, MemoryGetter, SharedMemory, Stack, EMPTY_SHARED_MEMORY, STACK_LIMIT, @@ -44,4 +37,3 @@ pub use interpreter_action::{ }; pub use interpreter_types::InterpreterTypes; pub use specification::{constants::MAX_INITCODE_SIZE, eip170::MAX_CODE_SIZE}; -pub use table::Instruction; diff --git a/crates/interpreter/src/macros.rs b/crates/interpreter/src/macros.rs index d0c1c6c080..8c25523092 100644 --- a/crates/interpreter/src/macros.rs +++ b/crates/interpreter/src/macros.rs @@ -1,3 +1,4 @@ +#[macro_export] macro_rules! debug_unreachable { ($($t:tt)*) => { if cfg!(debug_assertions) { @@ -8,6 +9,7 @@ macro_rules! debug_unreachable { }; } +#[macro_export] macro_rules! assume { ($e:expr $(,)?) => { if !$e { diff --git a/crates/interpreter/src/table.rs b/crates/interpreter/src/table.rs deleted file mode 100644 index 2723f72429..0000000000 --- a/crates/interpreter/src/table.rs +++ /dev/null @@ -1,152 +0,0 @@ -#![allow(clippy::wrong_self_convention)] - -use crate::{ - instructions::{control, instruction}, - interpreter::Interpreter, - interpreter_types::InterpreterTypes, - Host, -}; -use std::boxed::Box; - -/// EVM opcode function signature. -pub type Instruction = for<'a> fn(&'a mut Interpreter, &'a mut H); - -/// Instruction table is list of instruction function pointers mapped to 256 EVM opcodes. -pub type InstructionTable = [Instruction; 256]; - -/// A table of boxed instructions. -pub type CustomInstructionTable = [IT; 256]; - -pub trait CustomInstruction { - type Wire: InterpreterTypes; - type Host: ?Sized; - - fn exec(&self, interpreter: &mut Interpreter, host: &mut Self::Host); - - fn from_base(instruction: Instruction) -> Self; -} - -/// Either a plain, static instruction table, or a boxed, dynamic instruction table. -/// -/// Note that `Plain` variant is about 10-20% faster in Interpreter execution. -pub enum InstructionTables< - W: InterpreterTypes, - H: ?Sized, - CI: CustomInstruction, -> { - Plain(Box>), - Custom(Box>), -} - -impl InstructionTables -where - WIRE: InterpreterTypes, - H: Host + ?Sized, - CI: CustomInstruction, -{ - /// Inserts the instruction into the table with the specified index. - #[inline] - pub fn insert(&mut self, opcode: u8, instruction: Instruction) { - match self { - Self::Plain(table) => table[opcode as usize] = instruction, - Self::Custom(table) => table[opcode as usize] = CI::from_base(instruction), - } - } - - /// Converts the current instruction table to a boxed variant if it is not already, and returns - /// a mutable reference to the boxed table. - #[inline] - pub fn to_custom(&mut self) -> &mut CustomInstructionTable { - self.to_custom_with(|i| CI::from_base(i)) - } - - /// Converts the current instruction table to a boxed variant if it is not already with `f`, - /// and returns a mutable reference to the boxed table. - #[inline] - pub fn to_custom_with(&mut self, f: F) -> &mut CustomInstructionTable - where - F: FnMut(Instruction) -> CI, - { - match self { - Self::Plain(_) => self.to_custom_with_slow(f), - Self::Custom(boxed) => boxed, - } - } - - #[cold] - fn to_custom_with_slow(&mut self, f: F) -> &mut CustomInstructionTable - where - F: FnMut(Instruction) -> CI, - { - let Self::Plain(table) = self else { - unreachable!() - }; - *self = Self::Custom(Box::new(make_custom_instruction_table(table, f))); - let Self::Custom(boxed) = self else { - unreachable!() - }; - boxed - } - - /// Returns a mutable reference to the boxed instruction at the specified index. - #[inline] - pub fn get_custom(&mut self, opcode: u8) -> &mut CI { - &mut self.to_custom()[opcode as usize] - } - - /// Inserts a boxed instruction into the table at the specified index. - #[inline] - pub fn insert_custom(&mut self, opcode: u8, instruction: CI) { - *self.get_custom(opcode) = instruction; - } - - /// Replaces a boxed instruction into the table at the specified index, returning the previous - /// instruction. - #[inline] - pub fn replace_boxed(&mut self, opcode: u8, instruction: CI) -> CI { - core::mem::replace(self.get_custom(opcode), instruction) - } -} - -/// Make instruction table. -#[inline] -pub const fn make_instruction_table( -) -> InstructionTable { - let mut table: InstructionTable = [control::unknown; 256]; - let mut i = 0; - while i < 256 { - table[i] = instruction::(i as u8); - i += 1; - } - table -} - -/// Make boxed instruction table that calls `f` closure for every instruction. -#[inline] -pub fn make_custom_instruction_table>( - table: &InstructionTable, - mut f: FN, -) -> CustomInstructionTable -where - W: InterpreterTypes, - H: Host + ?Sized, - FN: FnMut(Instruction) -> CI, -{ - core::array::from_fn(|i| f(table[i])) -} - -// TODO -// /// Updates a boxed instruction with a new one. -// #[inline] -// pub fn update_custom_instruction( -// instruction: &mut impl CustomInstruction, -// f: F, -// ) where -// W: InterpreterTypes, -// H: Host + ?Sized, -// F: Fn(&DynInstruction, &mut W, &mut H), -// { -// // Note: This first allocation gets elided by the compiler. -// let prev = core::mem::replace(instruction, Box::new(|_, _| {})); -// *instruction = Box::new(move |i, h| f(&prev, i, h)); -// } diff --git a/crates/optimism/src/evm.rs b/crates/optimism/src/evm.rs index 4bd96520f5..ce49085c98 100644 --- a/crates/optimism/src/evm.rs +++ b/crates/optimism/src/evm.rs @@ -5,7 +5,9 @@ use revm::{ handler::EvmTr, instructions::{EthInstructions, InstructionProvider}, }, - interpreter::{interpreter::EthInterpreter, Host, Interpreter, InterpreterAction}, + interpreter::{ + interpreter::EthInterpreter, Host, Interpreter, InterpreterAction, InterpreterTypes, + }, }; use crate::handler::precompiles::OpPrecompileProvider; @@ -42,7 +44,10 @@ impl ContextSetters for OpEvm impl EvmTr for OpEvm where CTX: ContextTr, - I: InstructionProvider, + I: InstructionProvider< + Context = CTX, + InterpreterTypes: InterpreterTypes, + >, { type Context = CTX; type Instructions = I; @@ -53,7 +58,8 @@ where interpreter: &mut Interpreter< ::InterpreterTypes, >, - ) -> ::Output { + ) -> <::InterpreterTypes as InterpreterTypes>::Output + { let context = &mut self.0.data.ctx; let instructions = &mut self.0.instruction; interpreter.run_plain(instructions.instruction_table(), context) diff --git a/crates/state/src/account_info.rs b/crates/state/src/account_info.rs index 224c84e177..b2fb853b01 100644 --- a/crates/state/src/account_info.rs +++ b/crates/state/src/account_info.rs @@ -2,7 +2,9 @@ use bytecode::Bytecode; use core::hash::{Hash, Hasher}; use primitives::{B256, KECCAK_EMPTY, U256}; -/// AccountInfo account information +/// Account information that contains balance, nonce, code hash and code +/// +/// Code is set as optional. #[derive(Clone, Debug, Eq, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct AccountInfo { diff --git a/crates/statetest-types/src/test_authorization.rs b/crates/statetest-types/src/test_authorization.rs index f09c0ed900..b8ad20c875 100644 --- a/crates/statetest-types/src/test_authorization.rs +++ b/crates/statetest-types/src/test_authorization.rs @@ -52,7 +52,8 @@ mod tests { "signer": "0x6389e7f33ce3b1e94e4325ef02829cd12297ef71" }"#; - let _: TestAuthorization = serde_json::from_str(auth).unwrap(); + let auth: TestAuthorization = serde_json::from_str(auth).unwrap(); + println!("{:?}", auth); } #[test] diff --git a/examples/custom_opcodes/src/lib.rs b/examples/custom_opcodes/src/lib.rs index f50828688a..ac316849d0 100644 --- a/examples/custom_opcodes/src/lib.rs +++ b/examples/custom_opcodes/src/lib.rs @@ -219,19 +219,6 @@ macro_rules! custom_opcode_spec_to_generic { }}; } -// impl EvmHandler<'_, CustomOpcodeEvmWiring, EXT, DB> { -// pub fn custom_opcode_with_spec(spec_id: CustomOpcodeSpecId) -> Self { -// let mut handler = Self::mainnet_with_spec(spec_id); - -// custom_opcode_spec_to_generic!(spec_id, { -// let table = make_custom_instruction_table::<_, SPEC>(); -// handler.set_instruction_table(InstructionTables::Plain(table)); -// }); - -// handler -// } -// } - pub fn make_custom_instruction_table< EvmWiringT: EvmWiring, H: Host + ?Sized, diff --git a/examples/erc20_gas/src/exec.rs b/examples/erc20_gas/src/exec.rs index 3fad55d34a..d2371815fe 100644 --- a/examples/erc20_gas/src/exec.rs +++ b/examples/erc20_gas/src/exec.rs @@ -9,7 +9,7 @@ use revm::{ instructions::InstructionProvider, ContextTrDbError, EthFrame, EvmTr, Handler, PrecompileProvider, }, - interpreter::{interpreter::EthInterpreter, InterpreterAction, InterpreterResult}, + interpreter::{interpreter::EthInterpreter, InterpreterResult}, primitives::Log, state::EvmState, }; @@ -24,7 +24,6 @@ where Instructions: InstructionProvider< Context = EVM::Context, InterpreterTypes = EthInterpreter, - Output = InterpreterAction, >, >, { @@ -44,7 +43,6 @@ where Instructions: InstructionProvider< Context = EVM::Context, InterpreterTypes = EthInterpreter, - Output = InterpreterAction, >, >, {