diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 3cfe860376..e14a223ed9 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -114,6 +114,11 @@ name = "generate_block_traces" path = "../../examples/generate_block_traces.rs" required-features = ["std", "serde-json", "ethersdb"] +[[example]] +name = "db_by_ref" +path = "../../examples/db_by_ref.rs" +required-features = ["std", "serde-json"] + [[bench]] name = "bench" path = "benches/bench.rs" diff --git a/crates/revm/src/builder.rs b/crates/revm/src/builder.rs index 20a8fd37a0..cc177e1b96 100644 --- a/crates/revm/src/builder.rs +++ b/crates/revm/src/builder.rs @@ -284,8 +284,8 @@ impl<'a, BuilderStage, EXT, DB: Database> EvmBuilder<'a, BuilderStage, EXT, DB> /// When called, EvmBuilder will transition from SetGenericStage to HandlerStage. pub fn append_handler_register( mut self, - handle_register: register::HandleRegister<'a, EXT, DB>, - ) -> EvmBuilder<'_, HandlerStage, EXT, DB> { + handle_register: register::HandleRegister, + ) -> EvmBuilder<'a, HandlerStage, EXT, DB> { self.handler .append_handler_register(register::HandleRegisters::Plain(handle_register)); EvmBuilder { @@ -302,8 +302,8 @@ impl<'a, BuilderStage, EXT, DB: Database> EvmBuilder<'a, BuilderStage, EXT, DB> /// When called, EvmBuilder will transition from SetGenericStage to HandlerStage. pub fn append_handler_register_box( mut self, - handle_register: register::HandleRegisterBox<'a, EXT, DB>, - ) -> EvmBuilder<'_, HandlerStage, EXT, DB> { + handle_register: register::HandleRegisterBox, + ) -> EvmBuilder<'a, HandlerStage, EXT, DB> { self.handler .append_handler_register(register::HandleRegisters::Box(handle_register)); EvmBuilder { diff --git a/crates/revm/src/handler.rs b/crates/revm/src/handler.rs index bba5192543..35ad55af99 100644 --- a/crates/revm/src/handler.rs +++ b/crates/revm/src/handler.rs @@ -29,7 +29,7 @@ pub struct Handler<'a, H: Host + 'a, EXT, DB: Database> { /// Instruction table type. pub instruction_table: Option>, /// Registers that will be called on initialization. - pub registers: Vec>, + pub registers: Vec>, /// Validity handles. pub validation: ValidationHandler<'a, EXT, DB>, /// Pre execution handle @@ -138,25 +138,25 @@ impl<'a, EXT, DB: Database> EvmHandler<'a, EXT, DB> { } /// Append handle register. - pub fn append_handler_register(&mut self, register: HandleRegisters<'a, EXT, DB>) { + pub fn append_handler_register(&mut self, register: HandleRegisters) { register.register(self); self.registers.push(register); } /// Append plain handle register. - pub fn append_handler_register_plain(&mut self, register: HandleRegister<'a, EXT, DB>) { + pub fn append_handler_register_plain(&mut self, register: HandleRegister) { register(self); self.registers.push(HandleRegisters::Plain(register)); } /// Append boxed handle register. - pub fn append_handler_register_box(&mut self, register: HandleRegisterBox<'a, EXT, DB>) { + pub fn append_handler_register_box(&mut self, register: HandleRegisterBox) { register(self); self.registers.push(HandleRegisters::Box(register)); } /// Pop last handle register and reapply all registers that are left. - pub fn pop_handle_register(&mut self) -> Option> { + pub fn pop_handle_register(&mut self) -> Option> { let out = self.registers.pop(); if out.is_some() { let registers = core::mem::take(&mut self.registers); @@ -211,7 +211,7 @@ mod test { #[test] fn test_handler_register_pop() { - let register = |inner: &Rc>| -> HandleRegisterBox<'_, (), EmptyDB> { + let register = |inner: &Rc>| -> HandleRegisterBox<(), EmptyDB> { let inner = inner.clone(); Box::new(move |h| { *inner.borrow_mut() += 1; diff --git a/crates/revm/src/handler/register.rs b/crates/revm/src/handler/register.rs index 835b80e2c8..ba7980f06e 100644 --- a/crates/revm/src/handler/register.rs +++ b/crates/revm/src/handler/register.rs @@ -8,21 +8,21 @@ pub type EvmHandler<'a, EXT, DB> = Handler<'a, Evm<'a, EXT, DB>, EXT, DB>; pub type EvmInstructionTables<'a, EXT, DB> = InstructionTables<'a, Evm<'a, EXT, DB>>; // Handle register -pub type HandleRegister<'a, EXT, DB> = fn(&mut EvmHandler<'a, EXT, DB>); +pub type HandleRegister = for<'a> fn(&mut EvmHandler<'a, EXT, DB>); // Boxed handle register -pub type HandleRegisterBox<'a, EXT, DB> = Box)>; +pub type HandleRegisterBox = Box Fn(&mut EvmHandler<'a, EXT, DB>)>; -pub enum HandleRegisters<'a, EXT, DB: Database> { +pub enum HandleRegisters { /// Plain function register - Plain(HandleRegister<'a, EXT, DB>), + Plain(HandleRegister), /// Boxed function register. - Box(HandleRegisterBox<'a, EXT, DB>), + Box(HandleRegisterBox), } -impl<'a, EXT, DB: Database> HandleRegisters<'a, EXT, DB> { +impl HandleRegisters { /// Call register function to modify EvmHandler. - pub fn register(&self, handler: &mut EvmHandler<'a, EXT, DB>) { + pub fn register(&self, handler: &mut EvmHandler<'_, EXT, DB>) { match self { HandleRegisters::Plain(f) => f(handler), HandleRegisters::Box(f) => f(handler), diff --git a/examples/db_by_ref.rs b/examples/db_by_ref.rs new file mode 100644 index 0000000000..01f51faec3 --- /dev/null +++ b/examples/db_by_ref.rs @@ -0,0 +1,81 @@ +use revm::{ + db::{CacheDB, EmptyDB, WrapDatabaseRef}, + handler::register::HandleRegister, + inspector_handle_register, + inspectors::{NoOpInspector, TracerEip3155}, + primitives::ResultAndState, + DatabaseCommit, DatabaseRef, Evm, +}; +use std::error::Error; + +trait DatabaseRefDebugError: DatabaseRef { + type DBError: std::fmt::Debug + Error + Send + Sync + 'static; +} + +impl DatabaseRefDebugError for DB +where + DB: DatabaseRef, + DBError: std::fmt::Debug + Error + Send + Sync + 'static, +{ + type DBError = DBError; +} + +fn run_transaction( + db: DB, + ext: EXT, + register_handles_fn: HandleRegister>, +) -> anyhow::Result<(ResultAndState, DB)> { + let mut evm = Evm::builder() + .with_ref_db(db) + .with_external_context(ext) + .append_handler_register(register_handles_fn) + .build(); + + let result = evm.transact()?; + Ok((result, evm.into_context().evm.db.0)) +} + +fn run_transaction_and_commit_with_ext( + db: DB, + ext: EXT, + register_handles_fn: HandleRegister>, +) -> anyhow::Result<()> { + // To circumvent borrow checker issues, we need to move the database into the + // transaction and return it after the transaction is done. + let (ResultAndState { state: changes, .. }, mut db) = + { run_transaction(db, ext, register_handles_fn)? }; + + db.commit(changes); + + Ok(()) +} + +fn run_transaction_and_commit(db: &mut CacheDB) -> anyhow::Result<()> { + let ResultAndState { state: changes, .. } = { + let rdb = &*db; + + let mut evm = Evm::builder() + .with_ref_db(rdb) + .with_external_context(NoOpInspector) + .append_handler_register(inspector_handle_register) + .build(); + + evm.transact()? + }; + + // No compiler error because there is no lifetime parameter for the `HandleRegister` function + db.commit(changes); + + Ok(()) +} + +fn main() -> anyhow::Result<()> { + let mut cache_db = CacheDB::new(EmptyDB::default()); + + let mut tracer = TracerEip3155::new(Box::new(std::io::stdout()), true, true); + + run_transaction_and_commit_with_ext(&mut cache_db, &mut tracer, inspector_handle_register)?; + run_transaction_and_commit(&mut cache_db)?; + + Ok(()) +}