diff --git a/crates/revm/src/builder.rs b/crates/revm/src/builder.rs index 5508fa9cf3..4b2a81ec4f 100644 --- a/crates/revm/src/builder.rs +++ b/crates/revm/src/builder.rs @@ -15,7 +15,7 @@ use std::boxed::Box; pub struct EvmBuilder<'a, BuilderStage, EXT, DB: Database> { context: Context, /// Handler that will be used by EVM. It contains handle registers - handler: Handler<'a, Evm<'a, EXT, DB>, EXT, DB>, + handler: Handler<'a, Context, EXT, DB>, /// Phantom data to mark the stage of the builder. phantom: PhantomData, } @@ -269,7 +269,7 @@ impl<'a, BuilderStage, EXT, DB: Database> EvmBuilder<'a, BuilderStage, EXT, DB> /// Creates the default handler. /// /// This is useful for adding optimism handle register. - fn handler(handler_cfg: HandlerCfg) -> Handler<'a, Evm<'a, EXT, DB>, EXT, DB> { + fn handler(handler_cfg: HandlerCfg) -> Handler<'a, Context, EXT, DB> { Handler::new(handler_cfg) } @@ -291,7 +291,7 @@ impl<'a, BuilderStage, EXT, DB: Database> EvmBuilder<'a, BuilderStage, EXT, DB> /// ``` pub fn with_handler( self, - handler: Handler<'a, Evm<'a, EXT, DB>, EXT, DB>, + handler: Handler<'a, Context, EXT, DB>, ) -> EvmBuilder<'a, BuilderStage, EXT, DB> { EvmBuilder { context: self.context, @@ -481,22 +481,18 @@ mod test { // we need to use a box to capture the custom context in the instruction let custom_instruction = Box::new( - move |_interp: &mut Interpreter, _host: &mut Evm<'_, (), InMemoryDB>| { + move |_interp: &mut Interpreter, _host: &mut Context<(), InMemoryDB>| { // modify the value let mut inner = custom_context.inner.borrow_mut(); *inner += 1; }, ); - // need to make esure the instruction table is a boxed instruction table so that we + // need to ensure the instruction table is a boxed instruction table so that we // can insert the custom instruction as a boxed instruction - let mut table = handler.take_instruction_table(); - table = table.map(|mut table| { - // now we can finally insert - table.insert_boxed(0xEF, custom_instruction); - table - }); - handler.instruction_table = table; + handler + .instruction_table + .insert_boxed(0xEF, custom_instruction); })) .build(); @@ -528,9 +524,7 @@ mod test { }) .modify_tx_env(|tx| tx.transact_to = TransactTo::Call(to_addr)) .append_handler_register(|handler| { - if let Some(ref mut table) = handler.instruction_table { - table.insert(0xEF, custom_instruction) - } + handler.instruction_table.insert(0xEF, custom_instruction) }) .build(); diff --git a/crates/revm/src/context.rs b/crates/revm/src/context.rs index aba8f27d53..343dfcf985 100644 --- a/crates/revm/src/context.rs +++ b/crates/revm/src/context.rs @@ -11,7 +11,8 @@ pub use inner_evm_context::InnerEvmContext; use crate::{ db::{Database, EmptyDB}, - primitives::HandlerCfg, + interpreter::{Host, LoadAccountResult, SStoreResult, SelfDestructResult}, + primitives::{Address, Bytecode, Env, HandlerCfg, Log, B256, U256}, }; use std::boxed::Box; @@ -94,3 +95,83 @@ where } } } + +impl Host for Context { + fn env(&self) -> &Env { + &self.evm.env + } + + fn env_mut(&mut self) -> &mut Env { + &mut self.evm.env + } + + fn block_hash(&mut self, number: U256) -> Option { + self.evm + .block_hash(number) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } + + fn load_account(&mut self, address: Address) -> Option { + self.evm + .load_account_exist(address) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } + + fn balance(&mut self, address: Address) -> Option<(U256, bool)> { + self.evm + .balance(address) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } + + fn code(&mut self, address: Address) -> Option<(Bytecode, bool)> { + self.evm + .code(address) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } + + fn code_hash(&mut self, address: Address) -> Option<(B256, bool)> { + self.evm + .code_hash(address) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } + + fn sload(&mut self, address: Address, index: U256) -> Option<(U256, bool)> { + self.evm + .sload(address, index) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } + + fn sstore(&mut self, address: Address, index: U256, value: U256) -> Option { + self.evm + .sstore(address, index, value) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } + + fn tload(&mut self, address: Address, index: U256) -> U256 { + self.evm.tload(address, index) + } + + fn tstore(&mut self, address: Address, index: U256, value: U256) { + self.evm.tstore(address, index, value) + } + + fn log(&mut self, log: Log) { + self.evm.journaled_state.log(log); + } + + fn selfdestruct(&mut self, address: Address, target: Address) -> Option { + self.evm + .inner + .journaled_state + .selfdestruct(address, target, &mut self.evm.inner.db) + .map_err(|e| self.evm.error = Err(e)) + .ok() + } +} diff --git a/crates/revm/src/context/inner_evm_context.rs b/crates/revm/src/context/inner_evm_context.rs index 63e1146721..109b16a7a6 100644 --- a/crates/revm/src/context/inner_evm_context.rs +++ b/crates/revm/src/context/inner_evm_context.rs @@ -114,6 +114,7 @@ impl InnerEvmContext { } /// Returns the error by replacing it with `Ok(())`, if any. + #[inline] pub fn take_error(&mut self) -> Result<(), EVMError> { core::mem::replace(&mut self.error, Ok(())) } diff --git a/crates/revm/src/evm.rs b/crates/revm/src/evm.rs index 25ff0d017c..2fcf932452 100644 --- a/crates/revm/src/evm.rs +++ b/crates/revm/src/evm.rs @@ -2,14 +2,10 @@ use crate::{ builder::{EvmBuilder, HandlerStage, SetGenericStage}, db::{Database, DatabaseCommit, EmptyDB}, handler::Handler, - interpreter::{ - opcode::InstructionTables, Host, Interpreter, InterpreterAction, LoadAccountResult, - SStoreResult, SelfDestructResult, SharedMemory, - }, + interpreter::{Host, InterpreterAction, SharedMemory}, primitives::{ - specification::SpecId, Address, BlockEnv, Bytecode, CfgEnv, EVMError, EVMResult, Env, - EnvWithHandlerCfg, ExecutionResult, HandlerCfg, Log, ResultAndState, TransactTo, TxEnv, - B256, U256, + specification::SpecId, BlockEnv, CfgEnv, EVMError, EVMResult, EnvWithHandlerCfg, + ExecutionResult, HandlerCfg, ResultAndState, TransactTo, TxEnv, }, Context, ContextWithHandlerCfg, Frame, FrameOrResult, FrameResult, }; @@ -27,7 +23,7 @@ pub struct Evm<'a, EXT, DB: Database> { pub context: Context, /// Handler is a component of the of EVM that contains all the logic. Handler contains specification id /// and it different depending on the specified fork. - pub handler: Handler<'a, Self, EXT, DB>, + pub handler: Handler<'a, Context, EXT, DB>, } impl fmt::Debug for Evm<'_, EXT, DB> @@ -63,7 +59,7 @@ impl<'a, EXT, DB: Database> Evm<'a, EXT, DB> { /// Create new EVM. pub fn new( mut context: Context, - handler: Handler<'a, Self, EXT, DB>, + handler: Handler<'a, Context, EXT, DB>, ) -> Evm<'a, EXT, DB> { context.evm.journaled_state.set_spec_id(handler.cfg.spec_id); Evm { context, handler } @@ -74,6 +70,102 @@ impl<'a, EXT, DB: Database> Evm<'a, EXT, DB> { pub fn modify(self) -> EvmBuilder<'a, HandlerStage, EXT, DB> { EvmBuilder::new(self) } + + /// Runs main call loop. + #[inline] + pub fn run_the_loop(&mut self, first_frame: Frame) -> Result> { + let mut call_stack: Vec = Vec::with_capacity(1025); + call_stack.push(first_frame); + + #[cfg(feature = "memory_limit")] + let mut shared_memory = + SharedMemory::new_with_memory_limit(self.context.evm.env.cfg.memory_limit); + #[cfg(not(feature = "memory_limit"))] + let mut shared_memory = SharedMemory::new(); + + shared_memory.new_context(); + + // Peek the last stack frame. + let mut stack_frame = call_stack.last_mut().unwrap(); + + loop { + // Execute the frame. + let next_action = + self.handler + .execute_frame(stack_frame, &mut shared_memory, &mut self.context)?; + + // Take error and break the loop, if any. + // This error can be set in the Interpreter when it interacts with the context. + self.context.evm.take_error()?; + + let exec = &mut self.handler.execution; + let frame_or_result = match next_action { + InterpreterAction::Call { inputs } => exec.call(&mut self.context, inputs)?, + InterpreterAction::Create { inputs } => exec.create(&mut self.context, inputs)?, + InterpreterAction::EOFCreate { inputs } => { + exec.eofcreate(&mut self.context, inputs)? + } + InterpreterAction::Return { result } => { + // free memory context. + shared_memory.free_context(); + + // pop last frame from the stack and consume it to create FrameResult. + let returned_frame = call_stack + .pop() + .expect("We just returned from Interpreter frame"); + + let ctx = &mut self.context; + FrameOrResult::Result(match returned_frame { + Frame::Call(frame) => { + // return_call + FrameResult::Call(exec.call_return(ctx, frame, result)?) + } + Frame::Create(frame) => { + // return_create + FrameResult::Create(exec.create_return(ctx, frame, result)?) + } + Frame::EOFCreate(frame) => { + // return_eofcreate + FrameResult::EOFCreate(exec.eofcreate_return(ctx, frame, result)?) + } + }) + } + InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"), + }; + + // handle result + match frame_or_result { + FrameOrResult::Frame(frame) => { + shared_memory.new_context(); + call_stack.push(frame); + stack_frame = call_stack.last_mut().unwrap(); + } + FrameOrResult::Result(result) => { + let Some(top_frame) = call_stack.last_mut() else { + // Break the loop if there are no more frames. + return Ok(result); + }; + stack_frame = top_frame; + let ctx = &mut self.context; + // Insert result to the top frame. + match result { + FrameResult::Call(outcome) => { + // return_call + exec.insert_call_outcome(ctx, stack_frame, &mut shared_memory, outcome)? + } + FrameResult::Create(outcome) => { + // return_create + exec.insert_create_outcome(ctx, stack_frame, outcome)? + } + FrameResult::EOFCreate(outcome) => { + // return_eofcreate + exec.insert_eofcreate_outcome(ctx, stack_frame, outcome)? + } + } + } + } + } + } } impl Evm<'_, EXT, DB> { @@ -156,7 +248,7 @@ impl Evm<'_, EXT, DB> { /// Returns the reference of Env configuration #[inline] pub fn cfg(&self) -> &CfgEnv { - &self.env().cfg + &self.context.env().cfg } /// Returns the mutable reference of Env configuration @@ -230,133 +322,6 @@ impl Evm<'_, EXT, DB> { ContextWithHandlerCfg::new(self.context, self.handler.cfg) } - /// Starts the main loop and returns outcome of the execution. - pub fn start_the_loop( - &mut self, - first_frame: Frame, - ) -> Result> { - // take instruction table - let table = self - .handler - .take_instruction_table() - .expect("Instruction table should be present"); - - // run main loop - let frame_result = match &table { - InstructionTables::Plain(table) => self.run_the_loop(table, first_frame), - InstructionTables::Boxed(table) => self.run_the_loop(table, first_frame), - }; - - // return back instruction table - self.handler.set_instruction_table(table); - - frame_result - } - - /// Runs main call loop. - #[inline] - pub fn run_the_loop( - &mut self, - instruction_table: &[FN; 256], - first_frame: Frame, - ) -> Result> - where - FN: Fn(&mut Interpreter, &mut Self), - { - let mut call_stack: Vec = Vec::with_capacity(1025); - call_stack.push(first_frame); - - #[cfg(feature = "memory_limit")] - let mut shared_memory = - SharedMemory::new_with_memory_limit(self.context.evm.env.cfg.memory_limit); - #[cfg(not(feature = "memory_limit"))] - let mut shared_memory = SharedMemory::new(); - - shared_memory.new_context(); - - // peek last stack frame. - let mut stack_frame = call_stack.last_mut().unwrap(); - - loop { - // run interpreter - let interpreter = &mut stack_frame.frame_data_mut().interpreter; - let next_action = interpreter.run(shared_memory, instruction_table, self); - - // take error and break the loop if there is any. - // This error is set From Interpreter when it's interacting with Host. - self.context.evm.take_error()?; - // take shared memory back. - shared_memory = interpreter.take_memory(); - - let exec = &mut self.handler.execution; - let frame_or_result = match next_action { - InterpreterAction::Call { inputs } => exec.call(&mut self.context, inputs)?, - InterpreterAction::Create { inputs } => exec.create(&mut self.context, inputs)?, - InterpreterAction::EOFCreate { inputs } => { - exec.eofcreate(&mut self.context, inputs)? - } - InterpreterAction::Return { result } => { - // free memory context. - shared_memory.free_context(); - - // pop last frame from the stack and consume it to create FrameResult. - let returned_frame = call_stack - .pop() - .expect("We just returned from Interpreter frame"); - - let ctx = &mut self.context; - FrameOrResult::Result(match returned_frame { - Frame::Call(frame) => { - // return_call - FrameResult::Call(exec.call_return(ctx, frame, result)?) - } - Frame::Create(frame) => { - // return_create - FrameResult::Create(exec.create_return(ctx, frame, result)?) - } - Frame::EOFCreate(frame) => { - // return_eofcreate - FrameResult::EOFCreate(exec.eofcreate_return(ctx, frame, result)?) - } - }) - } - InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"), - }; - - // handle result - match frame_or_result { - FrameOrResult::Frame(frame) => { - shared_memory.new_context(); - call_stack.push(frame); - stack_frame = call_stack.last_mut().unwrap(); - } - FrameOrResult::Result(result) => { - let Some(top_frame) = call_stack.last_mut() else { - // Break the look if there are no more frames. - return Ok(result); - }; - stack_frame = top_frame; - let ctx = &mut self.context; - // Insert result to the top frame. - match result { - FrameResult::Call(outcome) => { - // return_call - exec.insert_call_outcome(ctx, stack_frame, &mut shared_memory, outcome)? - } - FrameResult::Create(outcome) => { - // return_create - exec.insert_create_outcome(ctx, stack_frame, outcome)? - } - FrameResult::EOFCreate(outcome) => { - // return_eofcreate - exec.insert_eofcreate_outcome(ctx, stack_frame, outcome)? - } - } - } - } - } - } - /// Transact pre-verified transaction. fn transact_preverified_inner(&mut self, initial_gas_spend: u64) -> EVMResult { let ctx = &mut self.context; @@ -389,7 +354,7 @@ impl Evm<'_, EXT, DB> { // Starts the main running loop. let mut result = match first_frame_or_result { - FrameOrResult::Frame(first_frame) => self.start_the_loop(first_frame)?, + FrameOrResult::Frame(first_frame) => self.run_the_loop(first_frame)?, FrameOrResult::Result(result) => result, }; @@ -409,91 +374,3 @@ impl Evm<'_, EXT, DB> { post_exec.output(ctx, result) } } - -impl Host for Evm<'_, EXT, DB> { - fn env(&self) -> &Env { - &self.context.evm.env - } - - fn env_mut(&mut self) -> &mut Env { - &mut self.context.evm.env - } - - fn block_hash(&mut self, number: U256) -> Option { - self.context - .evm - .block_hash(number) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } - - fn load_account(&mut self, address: Address) -> Option { - self.context - .evm - .load_account_exist(address) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } - - fn balance(&mut self, address: Address) -> Option<(U256, bool)> { - self.context - .evm - .balance(address) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } - - fn code(&mut self, address: Address) -> Option<(Bytecode, bool)> { - self.context - .evm - .code(address) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } - - fn code_hash(&mut self, address: Address) -> Option<(B256, bool)> { - self.context - .evm - .code_hash(address) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } - - fn sload(&mut self, address: Address, index: U256) -> Option<(U256, bool)> { - self.context - .evm - .sload(address, index) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } - - fn sstore(&mut self, address: Address, index: U256, value: U256) -> Option { - self.context - .evm - .sstore(address, index, value) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } - - fn tload(&mut self, address: Address, index: U256) -> U256 { - self.context.evm.tload(address, index) - } - - fn tstore(&mut self, address: Address, index: U256, value: U256) { - self.context.evm.tstore(address, index, value) - } - - fn log(&mut self, log: Log) { - self.context.evm.journaled_state.log(log); - } - - fn selfdestruct(&mut self, address: Address, target: Address) -> Option { - self.context - .evm - .inner - .journaled_state - .selfdestruct(address, target, &mut self.context.evm.inner.db) - .map_err(|e| self.context.evm.error = Err(e)) - .ok() - } -} diff --git a/crates/revm/src/handler.rs b/crates/revm/src/handler.rs index a6dfde551e..fab20b1229 100644 --- a/crates/revm/src/handler.rs +++ b/crates/revm/src/handler.rs @@ -8,10 +8,11 @@ pub use handle_types::*; // Includes. use crate::{ - interpreter::{opcode::InstructionTables, Host}, - primitives::{db::Database, spec_to_generic, HandlerCfg, Spec, SpecId}, - Evm, + interpreter::{opcode::InstructionTables, Host, InterpreterAction, SharedMemory}, + primitives::{db::Database, spec_to_generic, EVMError, HandlerCfg, Spec, SpecId}, + Context, Frame, }; +use core::mem; use register::{EvmHandler, HandleRegisters}; use std::vec::Vec; @@ -24,7 +25,7 @@ pub struct Handler<'a, H: Host + 'a, EXT, DB: Database> { /// Handler configuration. pub cfg: HandlerCfg, /// Instruction table type. - pub instruction_table: Option>, + pub instruction_table: InstructionTables<'a, H>, /// Registers that will be called on initialization. pub registers: Vec>, /// Validity handles. @@ -60,7 +61,7 @@ impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> { pub fn mainnet() -> Self { Self { cfg: HandlerCfg::new(SPEC::SPEC_ID), - instruction_table: Some(InstructionTables::new_plain::()), + instruction_table: InstructionTables::new_plain::(), registers: Vec::new(), validation: ValidationHandler::new::(), pre_execution: PreExecutionHandler::new::(), @@ -102,14 +103,34 @@ impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> { self.cfg } + /// Returns specification ID. + pub fn spec_id(&self) -> SpecId { + self.cfg.spec_id + } + + /// Executes call frame. + pub fn execute_frame( + &self, + frame: &mut Frame, + shared_memory: &mut SharedMemory, + context: &mut Context, + ) -> Result> { + self.execution + .execute_frame(frame, shared_memory, &self.instruction_table, context) + } + /// Take instruction table. - pub fn take_instruction_table(&mut self) -> Option>> { - self.instruction_table.take() + pub fn take_instruction_table(&mut self) -> InstructionTables<'a, Context> { + let spec_id = self.spec_id(); + mem::replace( + &mut self.instruction_table, + spec_to_generic!(spec_id, InstructionTables::new_plain::()), + ) } /// Set instruction table. - pub fn set_instruction_table(&mut self, table: InstructionTables<'a, Evm<'a, EXT, DB>>) { - self.instruction_table = Some(table); + pub fn set_instruction_table(&mut self, table: InstructionTables<'a, Context>) { + self.instruction_table = table; } /// Returns reference to pre execution handler. diff --git a/crates/revm/src/handler/handle_types/execution.rs b/crates/revm/src/handler/handle_types/execution.rs index d13dd2057a..b69354a591 100644 --- a/crates/revm/src/handler/handle_types/execution.rs +++ b/crates/revm/src/handler/handle_types/execution.rs @@ -5,11 +5,11 @@ use crate::{ primitives::{db::Database, EVMError, Spec}, CallFrame, Context, CreateFrame, Frame, FrameOrResult, FrameResult, }; -use std::{boxed::Box, sync::Arc}; - use revm_interpreter::{ - CallOutcome, CreateOutcome, EOFCreateInput, EOFCreateOutcome, InterpreterResult, + opcode::InstructionTables, CallOutcome, CreateOutcome, EOFCreateInput, EOFCreateOutcome, + InterpreterAction, InterpreterResult, }; +use std::{boxed::Box, sync::Arc}; /// Handles first frame return handle. pub type LastFrameReturnHandle<'a, EXT, DB> = Arc< @@ -17,6 +17,17 @@ pub type LastFrameReturnHandle<'a, EXT, DB> = Arc< + 'a, >; +/// Executes a single frame. Errors can be returned in the EVM context. +pub type ExecuteFrameHandle<'a, EXT, DB> = Arc< + dyn Fn( + &mut Frame, + &mut SharedMemory, + &InstructionTables<'_, Context>, + &mut Context, + ) -> Result::Error>> + + 'a, +>; + /// Handle sub call. pub type FrameCallHandle<'a, EXT, DB> = Arc< dyn Fn( @@ -110,6 +121,8 @@ pub struct ExecutionHandler<'a, EXT, DB: Database> { /// Handles last frame return, modified gas for refund and /// sets tx gas limit. pub last_frame_return: LastFrameReturnHandle<'a, EXT, DB>, + /// Executes a single frame. + pub execute_frame: ExecuteFrameHandle<'a, EXT, DB>, /// Frame call pub call: FrameCallHandle<'a, EXT, DB>, /// Call return @@ -135,6 +148,7 @@ impl<'a, EXT: 'a, DB: Database + 'a> ExecutionHandler<'a, EXT, DB> { pub fn new() -> Self { Self { last_frame_return: Arc::new(mainnet::last_frame_return::), + execute_frame: Arc::new(mainnet::execute_frame::), call: Arc::new(mainnet::call::), call_return: Arc::new(mainnet::call_return::), insert_call_outcome: Arc::new(mainnet::insert_call_outcome), @@ -149,6 +163,18 @@ impl<'a, EXT: 'a, DB: Database + 'a> ExecutionHandler<'a, EXT, DB> { } impl<'a, EXT, DB: Database> ExecutionHandler<'a, EXT, DB> { + /// Executes single frame. + #[inline] + pub fn execute_frame( + &self, + frame: &mut Frame, + shared_memory: &mut SharedMemory, + instruction_tables: &InstructionTables<'_, Context>, + context: &mut Context, + ) -> Result> { + (self.execute_frame)(frame, shared_memory, instruction_tables, context) + } + /// Handle call return, depending on instruction result gas will be reimbursed or not. #[inline] pub fn last_frame_return( diff --git a/crates/revm/src/handler/mainnet.rs b/crates/revm/src/handler/mainnet.rs index 3bf7da305f..b02e96bfdf 100644 --- a/crates/revm/src/handler/mainnet.rs +++ b/crates/revm/src/handler/mainnet.rs @@ -6,7 +6,7 @@ mod pre_execution; mod validation; pub use execution::{ - call, call_return, create, create_return, eofcreate, eofcreate_return, + call, call_return, create, create_return, eofcreate, eofcreate_return, execute_frame, frame_return_with_refund_flag, insert_call_outcome, insert_create_outcome, insert_eofcreate_outcome, last_frame_return, }; diff --git a/crates/revm/src/handler/mainnet/execution.rs b/crates/revm/src/handler/mainnet/execution.rs index 852dab3721..9e1ff3ef54 100644 --- a/crates/revm/src/handler/mainnet/execution.rs +++ b/crates/revm/src/handler/mainnet/execution.rs @@ -8,9 +8,33 @@ use crate::{ primitives::{EVMError, Env, Spec, SpecId}, CallFrame, Context, CreateFrame, Frame, FrameOrResult, FrameResult, }; -use revm_interpreter::{CallOutcome, EOFCreateInput, EOFCreateOutcome, InterpreterResult}; +use core::mem; +use revm_interpreter::{ + opcode::InstructionTables, CallOutcome, EOFCreateInput, EOFCreateOutcome, InterpreterAction, + InterpreterResult, EMPTY_SHARED_MEMORY, +}; use std::boxed::Box; +/// Execute frame +#[inline] +pub fn execute_frame( + frame: &mut Frame, + shared_memory: &mut SharedMemory, + instruction_tables: &InstructionTables<'_, Context>, + context: &mut Context, +) -> Result> { + let interpreter = frame.interpreter_mut(); + let memory = mem::replace(shared_memory, EMPTY_SHARED_MEMORY); + let next_action = match instruction_tables { + InstructionTables::Plain(table) => interpreter.run(memory, table, context), + InstructionTables::Boxed(table) => interpreter.run(memory, table, context), + }; + // Take the shared memory back. + *shared_memory = interpreter.take_memory(); + + Ok(next_action) +} + /// Helper function called inside [`last_frame_return`] #[inline] pub fn frame_return_with_refund_flag( diff --git a/crates/revm/src/handler/register.rs b/crates/revm/src/handler/register.rs index 73c28439ee..4b9fa31377 100644 --- a/crates/revm/src/handler/register.rs +++ b/crates/revm/src/handler/register.rs @@ -1,8 +1,8 @@ -use crate::{db::Database, handler::Handler, Evm}; +use crate::{db::Database, handler::Handler, Context}; use std::boxed::Box; /// EVM Handler -pub type EvmHandler<'a, EXT, DB> = Handler<'a, Evm<'a, EXT, DB>, EXT, DB>; +pub type EvmHandler<'a, EXT, DB> = Handler<'a, Context, EXT, DB>; // Handle register pub type HandleRegister = for<'a> fn(&mut EvmHandler<'a, EXT, DB>); diff --git a/crates/revm/src/inspector/handler_register.rs b/crates/revm/src/inspector/handler_register.rs index 65a60daee9..01bc11c577 100644 --- a/crates/revm/src/inspector/handler_register.rs +++ b/crates/revm/src/inspector/handler_register.rs @@ -1,9 +1,12 @@ use crate::{ db::Database, handler::register::EvmHandler, - interpreter::{opcode, opcode::BoxedInstruction, InstructionResult, Interpreter}, + interpreter::{ + opcode::{self, BoxedInstruction}, + InstructionResult, Interpreter, + }, primitives::EVMError, - Evm, FrameOrResult, FrameResult, Inspector, JournalEntry, + Context, FrameOrResult, FrameResult, Inspector, JournalEntry, }; use core::cell::RefCell; use revm_interpreter::opcode::InstructionTables; @@ -34,13 +37,11 @@ impl> GetInspector for INSP { /// A few instructions handlers are wrapped twice once for `step` and `step_end` /// and in case of Logs and Selfdestruct wrapper is wrapped again for the /// `log` and `selfdestruct` calls. -pub fn inspector_handle_register<'a, DB: Database, EXT: GetInspector>( - handler: &mut EvmHandler<'a, EXT, DB>, +pub fn inspector_handle_register>( + handler: &mut EvmHandler<'_, EXT, DB>, ) { // Every instruction inside flat table that is going to be wrapped by inspector calls. - let table = handler - .take_instruction_table() - .expect("Handler must have instruction table"); + let table = handler.take_instruction_table(); let mut table = match table { InstructionTables::Plain(table) => table .into_iter() @@ -57,28 +58,18 @@ pub fn inspector_handle_register<'a, DB: Database, EXT: GetInspector>( if let Some(i) = table.get_mut(index as usize) { let old = core::mem::replace(i, Box::new(|_, _| ())); *i = Box::new( - move |interpreter: &mut Interpreter, host: &mut Evm<'a, EXT, DB>| { - let old_log_len = host.context.evm.journaled_state.logs.len(); + move |interpreter: &mut Interpreter, host: &mut Context| { + let old_log_len = host.evm.journaled_state.logs.len(); old(interpreter, host); // check if log was added. It is possible that revert happened // cause of gas or stack underflow. - if host.context.evm.journaled_state.logs.len() == old_log_len + 1 { + if host.evm.journaled_state.logs.len() == old_log_len + 1 { // clone log. // TODO decide if we should remove this and leave the comment // that log can be found as journaled_state. - let last_log = host - .context - .evm - .journaled_state - .logs - .last() - .unwrap() - .clone(); + let last_log = host.evm.journaled_state.logs.last().unwrap().clone(); // call Inspector - host.context - .external - .get_inspector() - .log(&mut host.context.evm, &last_log); + host.external.get_inspector().log(&mut host.evm, &last_log); } }, ) @@ -95,7 +86,7 @@ pub fn inspector_handle_register<'a, DB: Database, EXT: GetInspector>( if let Some(i) = table.get_mut(opcode::SELFDESTRUCT as usize) { let old = core::mem::replace(i, Box::new(|_, _| ())); *i = Box::new( - move |interpreter: &mut Interpreter, host: &mut Evm<'a, EXT, DB>| { + move |interpreter: &mut Interpreter, host: &mut Context| { // execute selfdestruct old(interpreter, host); // check if selfdestruct was successful and if journal entry is made. @@ -104,20 +95,11 @@ pub fn inspector_handle_register<'a, DB: Database, EXT: GetInspector>( target, had_balance, .. - }) = host - .context - .evm - .journaled_state - .journal - .last() - .unwrap() - .last() + }) = host.evm.journaled_state.journal.last().unwrap().last() { - host.context.external.get_inspector().selfdestruct( - *address, - *target, - *had_balance, - ); + host.external + .get_inspector() + .selfdestruct(*address, *target, *had_balance); } }, ) @@ -236,20 +218,19 @@ pub fn inspector_instruction< 'a, INSP: GetInspector, DB: Database, - Instruction: Fn(&mut Interpreter, &mut Evm<'a, INSP, DB>) + 'a, + Instruction: Fn(&mut Interpreter, &mut Context) + 'a, >( instruction: Instruction, -) -> BoxedInstruction<'a, Evm<'a, INSP, DB>> { +) -> BoxedInstruction<'a, Context> { Box::new( - move |interpreter: &mut Interpreter, host: &mut Evm<'a, INSP, DB>| { + move |interpreter: &mut Interpreter, host: &mut Context| { // SAFETY: as the PC was already incremented we need to subtract 1 to preserve the // old Inspector behavior. interpreter.instruction_pointer = unsafe { interpreter.instruction_pointer.sub(1) }; - host.context - .external + host.external .get_inspector() - .step(interpreter, &mut host.context.evm); + .step(interpreter, &mut host.evm); if interpreter.instruction_result != InstructionResult::Continue { return; } @@ -260,10 +241,9 @@ pub fn inspector_instruction< // execute instruction. instruction(interpreter, host); - host.context - .external + host.external .get_inspector() - .step_end(interpreter, &mut host.context.evm); + .step_end(interpreter, &mut host.evm); }, ) } @@ -276,16 +256,16 @@ mod tests { inspectors::NoOpInspector, interpreter::{opcode::*, CallInputs, CallOutcome, CreateInputs, CreateOutcome}, primitives::BerlinSpec, - EvmContext, + Evm, EvmContext, }; // Test that this pattern builds. #[test] fn test_make_boxed_instruction_table() { - type MyEvm<'a> = Evm<'a, NoOpInspector, EmptyDB>; - let table: InstructionTable> = make_instruction_table::, BerlinSpec>(); - let _boxed_table: BoxedInstructionTable<'_, MyEvm<'_>> = - make_boxed_instruction_table::<'_, MyEvm<'_>, BerlinSpec, _>( + type MyContext = Context; + let table: InstructionTable = make_instruction_table::(); + let _boxed_table: BoxedInstructionTable<'_, MyContext> = + make_boxed_instruction_table::<'_, MyContext, BerlinSpec, _>( table, inspector_instruction, );