From 0e13a8d6587cbb49c86817e50264c91e97e4dd1e Mon Sep 17 00:00:00 2001 From: Wodann Date: Sat, 2 Mar 2024 05:25:39 +0000 Subject: [PATCH 1/5] issue: cannot use databases by reference when using handlers --- crates/revm/Cargo.toml | 5 ++ crates/revm/src/handler/register.rs | 2 +- examples/db_by_ref.rs | 74 +++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 examples/db_by_ref.rs 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/handler/register.rs b/crates/revm/src/handler/register.rs index 835b80e2c8..3e2a8aefa3 100644 --- a/crates/revm/src/handler/register.rs +++ b/crates/revm/src/handler/register.rs @@ -8,7 +8,7 @@ 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<'a, EXT, DB> = for<'evm> fn(&'evm mut EvmHandler<'a, EXT, DB>); // Boxed handle register pub type HandleRegisterBox<'a, EXT, DB> = Box)>; diff --git a/examples/db_by_ref.rs b/examples/db_by_ref.rs new file mode 100644 index 0000000000..4896017a95 --- /dev/null +++ b/examples/db_by_ref.rs @@ -0,0 +1,74 @@ +use revm::{ + db::{CacheDB, EmptyDB, WrapDatabaseRef}, + handler::register::HandleRegister, + inspector_handle_register, + inspectors::TracerEip3155, + primitives::ResultAndState, + Database, DatabaseCommit, Evm, +}; + +struct DebugContext<'evm, EXT, DB: Database> { + ext: EXT, + register_handles_fn: HandleRegister<'evm, EXT, DB>, +} + +fn run_transaction<'db, 'evm, EXT>( + db: &'db CacheDB, + ext: EXT, + register_handles_fn: HandleRegister<'evm, EXT, WrapDatabaseRef<&'evm CacheDB>>, +) -> anyhow::Result +where + 'db: 'evm, +{ + 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) +} + +fn run_transaction_and_commit_with_ext<'db, 'evm, EXT>( + db: &'db mut CacheDB, + ext: EXT, + register_handles_fn: HandleRegister<'evm, EXT, WrapDatabaseRef<&'evm CacheDB>>, +) -> anyhow::Result<()> +where + 'db: 'evm, +{ + let ResultAndState { state: changes, .. } = { + let db: &'evm _ = &*db; + run_transaction(db, ext, register_handles_fn)? + }; + + // Compile error: error[E0502]: cannot borrow `*db` as mutable because it is also borrowed as immutable + // The lifetime of `'evm` is extended beyond this function's scope because it is used in the `HandleRegister` function + db.commit(changes); + + Ok(()) +} + +fn run_transaction_and_commit<'db>(db: &mut CacheDB) -> anyhow::Result<()> { + let mut evm = Evm::builder().with_ref_db(db).build(); + + let ResultAndState { state: changes, .. } = 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(()) +} From 3d4d59ca05d03a27d31d7a01931ff66ad17ae964 Mon Sep 17 00:00:00 2001 From: rakita Date: Sat, 2 Mar 2024 20:13:57 +0100 Subject: [PATCH 2/5] Make db_by_ref generic --- crates/primitives/src/db.rs | 2 +- crates/revm/src/builder.rs | 8 ++--- crates/revm/src/handler.rs | 12 +++---- crates/revm/src/handler/register.rs | 15 ++++----- examples/db_by_ref.rs | 49 +++++++++++++++-------------- 5 files changed, 45 insertions(+), 41 deletions(-) diff --git a/crates/primitives/src/db.rs b/crates/primitives/src/db.rs index 0456b03432..5e60e1eb6f 100644 --- a/crates/primitives/src/db.rs +++ b/crates/primitives/src/db.rs @@ -57,7 +57,7 @@ pub trait DatabaseRef { } /// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation. -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WrapDatabaseRef(pub T); impl From for WrapDatabaseRef { 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 3e2a8aefa3..c4e954462d 100644 --- a/crates/revm/src/handler/register.rs +++ b/crates/revm/src/handler/register.rs @@ -8,21 +8,22 @@ 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> = for<'evm> fn(&'evm 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 index 4896017a95..7addc0aa44 100644 --- a/examples/db_by_ref.rs +++ b/examples/db_by_ref.rs @@ -1,24 +1,26 @@ +use std::{convert::Infallible, error::Error}; + use revm::{ db::{CacheDB, EmptyDB, WrapDatabaseRef}, handler::register::HandleRegister, inspector_handle_register, - inspectors::TracerEip3155, + inspectors::{NoOpInspector, TracerEip3155}, primitives::ResultAndState, - Database, DatabaseCommit, Evm, + DatabaseCommit, DatabaseRef, Evm, }; -struct DebugContext<'evm, EXT, DB: Database> { +struct DebugContext { ext: EXT, - register_handles_fn: HandleRegister<'evm, EXT, DB>, + register_handles_fn: HandleRegister>, } -fn run_transaction<'db, 'evm, EXT>( - db: &'db CacheDB, +fn run_transaction<'a, 'w, EXT, DB: DatabaseRef>( + db: DB, ext: EXT, - register_handles_fn: HandleRegister<'evm, EXT, WrapDatabaseRef<&'evm CacheDB>>, -) -> anyhow::Result + register_handles_fn: HandleRegister>, +) -> anyhow::Result<(ResultAndState, DB)> where - 'db: 'evm, + ::Error: std::fmt::Debug + Error + Send + Sync + 'static, { let mut evm = Evm::builder() .with_ref_db(db) @@ -27,35 +29,35 @@ where .build(); let result = evm.transact()?; - - Ok(result) + Ok((result, evm.into_context().evm.db.0)) } -fn run_transaction_and_commit_with_ext<'db, 'evm, EXT>( - db: &'db mut CacheDB, +fn run_transaction_and_commit_with_ext<'a, EXT, DB: DatabaseRef + DatabaseCommit>( + db: DB, ext: EXT, - register_handles_fn: HandleRegister<'evm, EXT, WrapDatabaseRef<&'evm CacheDB>>, + register_handles_fn: HandleRegister>, ) -> anyhow::Result<()> where - 'db: 'evm, + ::Error: std::fmt::Debug + Error + Send + Sync + 'static, { - let ResultAndState { state: changes, .. } = { - let db: &'evm _ = &*db; - run_transaction(db, ext, register_handles_fn)? - }; + let (ResultAndState { state: changes, .. }, mut db) = + { run_transaction(db, ext, register_handles_fn)? }; - // Compile error: error[E0502]: cannot borrow `*db` as mutable because it is also borrowed as immutable - // The lifetime of `'evm` is extended beyond this function's scope because it is used in the `HandleRegister` function db.commit(changes); Ok(()) } fn run_transaction_and_commit<'db>(db: &mut CacheDB) -> anyhow::Result<()> { - let mut evm = Evm::builder().with_ref_db(db).build(); + let rdb = &*db; + let mut evm = Evm::builder() + .with_ref_db(rdb) + .with_external_context(NoOpInspector) + .append_handler_register(inspector_handle_register) + .build(); let ResultAndState { state: changes, .. } = evm.transact()?; - + drop(evm); // No compiler error because there is no lifetime parameter for the `HandleRegister` function db.commit(changes); @@ -67,6 +69,7 @@ fn main() -> anyhow::Result<()> { let mut tracer = TracerEip3155::new(Box::new(std::io::stdout()), true, true); + //let db = WrapDatabaseRef(&cache_db); run_transaction_and_commit_with_ext(&mut cache_db, &mut tracer, inspector_handle_register)?; run_transaction_and_commit(&mut cache_db)?; From 04e32b78330fa01b1a3ca4c423126f1b7cf8ba6a Mon Sep 17 00:00:00 2001 From: rakita Date: Sat, 2 Mar 2024 20:38:22 +0100 Subject: [PATCH 3/5] Cleanup and cleaner debug error trait --- crates/primitives/src/db.rs | 2 +- crates/revm/src/handler/register.rs | 1 - examples/db_by_ref.rs | 33 ++++++++++++++--------------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/crates/primitives/src/db.rs b/crates/primitives/src/db.rs index 5e60e1eb6f..38f286f30b 100644 --- a/crates/primitives/src/db.rs +++ b/crates/primitives/src/db.rs @@ -57,7 +57,7 @@ pub trait DatabaseRef { } /// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation. -#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WrapDatabaseRef(pub T); impl From for WrapDatabaseRef { diff --git a/crates/revm/src/handler/register.rs b/crates/revm/src/handler/register.rs index c4e954462d..ba7980f06e 100644 --- a/crates/revm/src/handler/register.rs +++ b/crates/revm/src/handler/register.rs @@ -10,7 +10,6 @@ pub type EvmInstructionTables<'a, EXT, DB> = InstructionTables<'a, Evm<'a, EXT, // Handle register pub type HandleRegister = for<'a> fn(&mut EvmHandler<'a, EXT, DB>); - // Boxed handle register pub type HandleRegisterBox = Box Fn(&mut EvmHandler<'a, EXT, DB>)>; diff --git a/examples/db_by_ref.rs b/examples/db_by_ref.rs index 7addc0aa44..bb8c29b294 100644 --- a/examples/db_by_ref.rs +++ b/examples/db_by_ref.rs @@ -1,5 +1,3 @@ -use std::{convert::Infallible, error::Error}; - use revm::{ db::{CacheDB, EmptyDB, WrapDatabaseRef}, handler::register::HandleRegister, @@ -8,20 +6,25 @@ use revm::{ primitives::ResultAndState, DatabaseCommit, DatabaseRef, Evm, }; +use std::error::Error; -struct DebugContext { - ext: EXT, - register_handles_fn: HandleRegister>, +trait DatabaseRefDebugError: DatabaseRef { + type DBError: std::fmt::Debug + Error + Send + Sync + 'static; } -fn run_transaction<'a, 'w, EXT, DB: DatabaseRef>( +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)> -where - ::Error: std::fmt::Debug + Error + Send + Sync + 'static, -{ +) -> anyhow::Result<(ResultAndState, DB)> { let mut evm = Evm::builder() .with_ref_db(db) .with_external_context(ext) @@ -32,14 +35,11 @@ where Ok((result, evm.into_context().evm.db.0)) } -fn run_transaction_and_commit_with_ext<'a, EXT, DB: DatabaseRef + DatabaseCommit>( +fn run_transaction_and_commit_with_ext( db: DB, ext: EXT, register_handles_fn: HandleRegister>, -) -> anyhow::Result<()> -where - ::Error: std::fmt::Debug + Error + Send + Sync + 'static, -{ +) -> anyhow::Result<()> { let (ResultAndState { state: changes, .. }, mut db) = { run_transaction(db, ext, register_handles_fn)? }; @@ -48,7 +48,7 @@ where Ok(()) } -fn run_transaction_and_commit<'db>(db: &mut CacheDB) -> anyhow::Result<()> { +fn run_transaction_and_commit(db: &mut CacheDB) -> anyhow::Result<()> { let rdb = &*db; let mut evm = Evm::builder() .with_ref_db(rdb) @@ -69,7 +69,6 @@ fn main() -> anyhow::Result<()> { let mut tracer = TracerEip3155::new(Box::new(std::io::stdout()), true, true); - //let db = WrapDatabaseRef(&cache_db); run_transaction_and_commit_with_ext(&mut cache_db, &mut tracer, inspector_handle_register)?; run_transaction_and_commit(&mut cache_db)?; From 651db86fc5179064ca8b75a6e319a49b822bb397 Mon Sep 17 00:00:00 2001 From: Wodann Date: Mon, 4 Mar 2024 18:40:35 +0000 Subject: [PATCH 4/5] misc: minimise changes --- crates/primitives/src/db.rs | 2 +- examples/db_by_ref.rs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/crates/primitives/src/db.rs b/crates/primitives/src/db.rs index 38f286f30b..0456b03432 100644 --- a/crates/primitives/src/db.rs +++ b/crates/primitives/src/db.rs @@ -57,7 +57,7 @@ pub trait DatabaseRef { } /// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation. -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct WrapDatabaseRef(pub T); impl From for WrapDatabaseRef { diff --git a/examples/db_by_ref.rs b/examples/db_by_ref.rs index bb8c29b294..c016a71bee 100644 --- a/examples/db_by_ref.rs +++ b/examples/db_by_ref.rs @@ -49,15 +49,18 @@ fn run_transaction_and_commit_with_ext) -> anyhow::Result<()> { - let rdb = &*db; - let mut evm = Evm::builder() - .with_ref_db(rdb) - .with_external_context(NoOpInspector) - .append_handler_register(inspector_handle_register) - .build(); + 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()? + }; - let ResultAndState { state: changes, .. } = evm.transact()?; - drop(evm); // No compiler error because there is no lifetime parameter for the `HandleRegister` function db.commit(changes); From b4e30070aad599fe0e3dd1f5f79b7a206abeec4a Mon Sep 17 00:00:00 2001 From: Wodann Date: Mon, 4 Mar 2024 18:42:47 +0000 Subject: [PATCH 5/5] doc: add explanatory comment --- examples/db_by_ref.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/db_by_ref.rs b/examples/db_by_ref.rs index c016a71bee..01f51faec3 100644 --- a/examples/db_by_ref.rs +++ b/examples/db_by_ref.rs @@ -40,6 +40,8 @@ fn run_transaction_and_commit_with_ext>, ) -> 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)? };