From 00adb4ba464912ab105640ff926b5c7360222c1a Mon Sep 17 00:00:00 2001 From: lazymio Date: Sat, 29 Jun 2024 00:14:22 +0800 Subject: [PATCH 1/6] Use HandleOrRuntime to allow alloydb/ethersdb to hold a custom runtime --- crates/revm/src/db.rs | 3 +++ crates/revm/src/db/alloydb.rs | 29 ++++++++++++++++++++------- crates/revm/src/db/ethersdb.rs | 36 ++++++++++++++++++++++++++++------ crates/revm/src/db/utils.rs | 21 ++++++++++++++++++++ 4 files changed, 76 insertions(+), 13 deletions(-) create mode 100644 crates/revm/src/db/utils.rs diff --git a/crates/revm/src/db.rs b/crates/revm/src/db.rs index f7c4904ab4..febad10c08 100644 --- a/crates/revm/src/db.rs +++ b/crates/revm/src/db.rs @@ -1,5 +1,8 @@ //! [Database] implementations. +#[cfg(any(feature = "alloydb", feature = "ethersdb"))] +mod utils; + #[cfg(feature = "alloydb")] mod alloydb; pub mod emptydb; diff --git a/crates/revm/src/db/alloydb.rs b/crates/revm/src/db/alloydb.rs index aa6d09fcaf..f9100d2232 100644 --- a/crates/revm/src/db/alloydb.rs +++ b/crates/revm/src/db/alloydb.rs @@ -6,7 +6,8 @@ use alloy_eips::BlockId; use alloy_provider::{Network, Provider}; use alloy_transport::{Transport, TransportError}; use std::future::IntoFuture; -use tokio::runtime::Handle; + +use super::utils::HandleOrRuntime; /// An alloy-powered REVM [Database]. /// @@ -18,30 +19,44 @@ pub struct AlloyDB> { /// The block number on which the queries will be based on. block_number: BlockId, /// handle to the tokio runtime - handle: Handle, + rt: HandleOrRuntime, _marker: std::marker::PhantomData (T, N)>, } impl> AlloyDB { - /// Create a new AlloyDB instance, with a [Provider] and a block (Use None for latest). + /// Create a new AlloyDB instance, with a [Provider] and a block. /// /// Returns `None` if no tokio runtime is available or if the current runtime is a current-thread runtime. pub fn new(provider: P, block_number: BlockId) -> Option { - let handle = match Handle::try_current() { + let rt = match Handle::try_current() { Ok(handle) => match handle.runtime_flavor() { tokio::runtime::RuntimeFlavor::CurrentThread => return None, - _ => handle, + _ => HandleOrRuntime::Handle(handle), }, Err(_) => return None, }; Some(Self { provider, block_number, - handle, + rt, _marker: std::marker::PhantomData, }) } + // Create a new AlloyDB instance, with a provider and a block and a runtime. + // + // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. + // If you are already using something like [tokio::main], call AlloyDB::new instead. + pub fn with_runtime(provider: P, block_number: BlockId, runtime: Runtime) -> Self { + let rt = HandleOrRuntime::Runtime(runtime); + Self { + provider, + block_number, + rt, + _marker: std::marker::PhantomData, + } + } + /// Internal utility function that allows us to block on a future regardless of the runtime flavor. #[inline] fn block_on(&self, f: F) -> F::Output @@ -49,7 +64,7 @@ impl> AlloyDB { F: std::future::Future + Send, F::Output: Send, { - tokio::task::block_in_place(move || self.handle.block_on(f)) + self.rt.block_on(f) } /// Set the block number on which the queries will be based on. diff --git a/crates/revm/src/db/ethersdb.rs b/crates/revm/src/db/ethersdb.rs index a93affea92..c63706540c 100644 --- a/crates/revm/src/db/ethersdb.rs +++ b/crates/revm/src/db/ethersdb.rs @@ -7,11 +7,13 @@ use tokio::runtime::Handle; use crate::primitives::{AccountInfo, Address, Bytecode, B256, U256}; use crate::{Database, DatabaseRef}; +use super::utils::HandleOrRuntime; + #[derive(Debug, Clone)] pub struct EthersDB { client: Arc, block_number: Option, - handle: Handle, + rt: HandleOrRuntime, } impl EthersDB { @@ -19,10 +21,10 @@ impl EthersDB { /// /// Returns `None` if no tokio runtime is available or if the current runtime is a current-thread runtime. pub fn new(client: Arc, block_number: Option) -> Option { - let handle = match Handle::try_current() { + let rt = match Handle::try_current() { Ok(handle) => match handle.runtime_flavor() { tokio::runtime::RuntimeFlavor::CurrentThread => return None, - _ => handle, + _ => HandleOrRuntime::Handle(handle), }, Err(_) => return None, }; @@ -31,13 +33,13 @@ impl EthersDB { Some(Self { client, block_number, - handle, + rt, }) } else { let mut instance = Self { client: client.clone(), block_number: None, - handle, + rt, }; instance.block_number = Some(BlockId::from( instance.block_on(client.get_block_number()).ok()?, @@ -46,6 +48,28 @@ impl EthersDB { } } + // Create a new AlloyDB instance, with a provider and a block and a runtime. + // + // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. + // If you are already using something like [tokio::main], call AlloyDB::new instead. + pub fn with_runtime( + client: Arc, + block_number: Option, + runtime: Runtime, + ) -> Option { + let rt = HandleOrRuntime::Runtime(runtime); + let mut instance = Self { + client, + block_number, + rt, + }; + + instance.block_number = Some(BlockId::from( + instance.block_on(client.get_block_number()).ok()?, + )); + Some(instance) + } + /// Internal utility function to call tokio feature and wait for output #[inline] fn block_on(&self, f: F) -> F::Output @@ -53,7 +77,7 @@ impl EthersDB { F: core::future::Future + Send, F::Output: Send, { - tokio::task::block_in_place(move || self.handle.block_on(f)) + self.rt.block_on(f) } /// set block number on which upcoming queries will be based diff --git a/crates/revm/src/db/utils.rs b/crates/revm/src/db/utils.rs new file mode 100644 index 0000000000..aec5b94ae4 --- /dev/null +++ b/crates/revm/src/db/utils.rs @@ -0,0 +1,21 @@ +use tokio::runtime::{Handle, Runtime}; + +// Hold a tokio runtime handle or full runtime +pub(crate) enum HandleOrRuntime { + Handle(Handle), + Runtime(Runtime), +} + +impl HandleOrRuntime { + #[inline] + pub fn block_on(&self, f: F) -> F::Output + where + F: std::future::Future + Send, + F::Output: Send, + { + match self { + Self::Handle(handle) => tokio::task::block_in_place(move || handle.block_on(f)), + Self::Runtime(rt) => rt.block_on(f), + } + } +} From fda89eddd3626799801ac124655002b95a632d90 Mon Sep 17 00:00:00 2001 From: lazymio Date: Sat, 29 Jun 2024 00:17:18 +0800 Subject: [PATCH 2/6] Minor fix and clippy --- crates/revm/src/db/alloydb.rs | 3 ++- crates/revm/src/db/ethersdb.rs | 14 +++++++------- crates/revm/src/db/utils.rs | 3 ++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/crates/revm/src/db/alloydb.rs b/crates/revm/src/db/alloydb.rs index f9100d2232..4568baba26 100644 --- a/crates/revm/src/db/alloydb.rs +++ b/crates/revm/src/db/alloydb.rs @@ -6,13 +6,14 @@ use alloy_eips::BlockId; use alloy_provider::{Network, Provider}; use alloy_transport::{Transport, TransportError}; use std::future::IntoFuture; +use tokio::runtime::{Handle, Runtime}; use super::utils::HandleOrRuntime; /// An alloy-powered REVM [Database]. /// /// When accessing the database, it'll use the given provider to fetch the corresponding account's data. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct AlloyDB> { /// The provider to fetch the data from. provider: P, diff --git a/crates/revm/src/db/ethersdb.rs b/crates/revm/src/db/ethersdb.rs index c63706540c..4129046780 100644 --- a/crates/revm/src/db/ethersdb.rs +++ b/crates/revm/src/db/ethersdb.rs @@ -2,14 +2,14 @@ use std::sync::Arc; use ethers_core::types::{Block, BlockId, TxHash, H160 as eH160, H256, U64 as eU64}; use ethers_providers::Middleware; -use tokio::runtime::Handle; +use tokio::runtime::{Handle, Runtime}; use crate::primitives::{AccountInfo, Address, Bytecode, B256, U256}; use crate::{Database, DatabaseRef}; use super::utils::HandleOrRuntime; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct EthersDB { client: Arc, block_number: Option, @@ -37,21 +37,21 @@ impl EthersDB { }) } else { let mut instance = Self { - client: client.clone(), + client: client, block_number: None, rt, }; instance.block_number = Some(BlockId::from( - instance.block_on(client.get_block_number()).ok()?, + instance.block_on(instance.client.get_block_number()).ok()?, )); Some(instance) } } - // Create a new AlloyDB instance, with a provider and a block and a runtime. + // Create a new EthersDB instance, with a provider and a block (None for latest) and a runtime. // // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. - // If you are already using something like [tokio::main], call AlloyDB::new instead. + // If you are already using something like [tokio::main], call EthersDB::new instead. pub fn with_runtime( client: Arc, block_number: Option, @@ -65,7 +65,7 @@ impl EthersDB { }; instance.block_number = Some(BlockId::from( - instance.block_on(client.get_block_number()).ok()?, + instance.block_on(instance.client.get_block_number()).ok()?, )); Some(instance) } diff --git a/crates/revm/src/db/utils.rs b/crates/revm/src/db/utils.rs index aec5b94ae4..bf06940612 100644 --- a/crates/revm/src/db/utils.rs +++ b/crates/revm/src/db/utils.rs @@ -1,6 +1,7 @@ use tokio::runtime::{Handle, Runtime}; // Hold a tokio runtime handle or full runtime +#[derive(Debug)] pub(crate) enum HandleOrRuntime { Handle(Handle), Runtime(Runtime), @@ -8,7 +9,7 @@ pub(crate) enum HandleOrRuntime { impl HandleOrRuntime { #[inline] - pub fn block_on(&self, f: F) -> F::Output + pub(crate) fn block_on(&self, f: F) -> F::Output where F: std::future::Future + Send, F::Output: Send, From f94b1b78cb73dea85945dcbb4ff643289c8f27a5 Mon Sep 17 00:00:00 2001 From: lazymio Date: Sat, 29 Jun 2024 00:23:13 +0800 Subject: [PATCH 3/6] Clippy --- crates/revm/src/db/ethersdb.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/revm/src/db/ethersdb.rs b/crates/revm/src/db/ethersdb.rs index 4129046780..7813ff2fdd 100644 --- a/crates/revm/src/db/ethersdb.rs +++ b/crates/revm/src/db/ethersdb.rs @@ -37,7 +37,7 @@ impl EthersDB { }) } else { let mut instance = Self { - client: client, + client, block_number: None, rt, }; From ba20812f40be1db4a41cde0bbf8a611186eb5cdb Mon Sep 17 00:00:00 2001 From: lazymio Date: Sat, 29 Jun 2024 21:59:59 +0800 Subject: [PATCH 4/6] allow users to provide a runtime handle --- crates/revm/src/db/alloydb.rs | 16 +++++++++++++++- crates/revm/src/db/ethersdb.rs | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/revm/src/db/alloydb.rs b/crates/revm/src/db/alloydb.rs index 4568baba26..211fea2770 100644 --- a/crates/revm/src/db/alloydb.rs +++ b/crates/revm/src/db/alloydb.rs @@ -46,7 +46,7 @@ impl> AlloyDB { // Create a new AlloyDB instance, with a provider and a block and a runtime. // - // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. + // Refer to [tokio::runtime::Builder] on how to create a runtime if you are in synchronous world. // If you are already using something like [tokio::main], call AlloyDB::new instead. pub fn with_runtime(provider: P, block_number: BlockId, runtime: Runtime) -> Self { let rt = HandleOrRuntime::Runtime(runtime); @@ -58,6 +58,20 @@ impl> AlloyDB { } } + // Create a new AlloyDB instance, with a provider and a block and a runtime handle. + // + // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. + // If you are already using something like [tokio::main], call AlloyDB::new instead. + pub fn with_handle(provider: P, block_number: BlockId, handle: Handle) -> Self { + let rt = HandleOrRuntime::Handle(handle); + Self { + provider, + block_number, + rt, + _marker: std::marker::PhantomData, + } + } + /// Internal utility function that allows us to block on a future regardless of the runtime flavor. #[inline] fn block_on(&self, f: F) -> F::Output diff --git a/crates/revm/src/db/ethersdb.rs b/crates/revm/src/db/ethersdb.rs index 7813ff2fdd..6296dc84f0 100644 --- a/crates/revm/src/db/ethersdb.rs +++ b/crates/revm/src/db/ethersdb.rs @@ -70,6 +70,28 @@ impl EthersDB { Some(instance) } + // Create a new EthersDB instance, with a provider and a block (None for latest) and a handle. + // + // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. + // If you are already using something like [tokio::main], call EthersDB::new instead. + pub fn with_handle( + client: Arc, + block_number: Option, + handle: Handle, + ) -> Option { + let rt = HandleOrRuntime::Handle(handle); + let mut instance = Self { + client, + block_number, + rt, + }; + + instance.block_number = Some(BlockId::from( + instance.block_on(instance.client.get_block_number()).ok()?, + )); + Some(instance) + } + /// Internal utility function to call tokio feature and wait for output #[inline] fn block_on(&self, f: F) -> F::Output From e6c8a57c65ab7dd0ffaeb02ae15cc76c9240cdf8 Mon Sep 17 00:00:00 2001 From: lazymio Date: Sat, 29 Jun 2024 22:35:10 +0800 Subject: [PATCH 5/6] Update docs --- crates/revm/src/db/alloydb.rs | 4 ++-- crates/revm/src/db/ethersdb.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/revm/src/db/alloydb.rs b/crates/revm/src/db/alloydb.rs index 211fea2770..a70cd2a1ef 100644 --- a/crates/revm/src/db/alloydb.rs +++ b/crates/revm/src/db/alloydb.rs @@ -60,8 +60,8 @@ impl> AlloyDB { // Create a new AlloyDB instance, with a provider and a block and a runtime handle. // - // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. - // If you are already using something like [tokio::main], call AlloyDB::new instead. + // This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how + // to obtain a handle. If you are already in asynchronous world, like [tokio::main], use AlloyDB::new instead. pub fn with_handle(provider: P, block_number: BlockId, handle: Handle) -> Self { let rt = HandleOrRuntime::Handle(handle); Self { diff --git a/crates/revm/src/db/ethersdb.rs b/crates/revm/src/db/ethersdb.rs index 6296dc84f0..7b8ef6c34a 100644 --- a/crates/revm/src/db/ethersdb.rs +++ b/crates/revm/src/db/ethersdb.rs @@ -72,8 +72,8 @@ impl EthersDB { // Create a new EthersDB instance, with a provider and a block (None for latest) and a handle. // - // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. - // If you are already using something like [tokio::main], call EthersDB::new instead. + // This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how + // to obtain a handle. If you are already in asynchronous world, like [tokio::main], use EthersDB::new instead. pub fn with_handle( client: Arc, block_number: Option, From 01899bb41f3d835e6d16f726626deadb72727423 Mon Sep 17 00:00:00 2001 From: lazymio Date: Sun, 30 Jun 2024 00:40:00 +0800 Subject: [PATCH 6/6] Fix slashes --- crates/revm/src/db/alloydb.rs | 16 ++++++++-------- crates/revm/src/db/ethersdb.rs | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/crates/revm/src/db/alloydb.rs b/crates/revm/src/db/alloydb.rs index a70cd2a1ef..1caf4151be 100644 --- a/crates/revm/src/db/alloydb.rs +++ b/crates/revm/src/db/alloydb.rs @@ -44,10 +44,10 @@ impl> AlloyDB { }) } - // Create a new AlloyDB instance, with a provider and a block and a runtime. - // - // Refer to [tokio::runtime::Builder] on how to create a runtime if you are in synchronous world. - // If you are already using something like [tokio::main], call AlloyDB::new instead. + /// Create a new AlloyDB instance, with a provider and a block and a runtime. + /// + /// Refer to [tokio::runtime::Builder] on how to create a runtime if you are in synchronous world. + /// If you are already using something like [tokio::main], call AlloyDB::new instead. pub fn with_runtime(provider: P, block_number: BlockId, runtime: Runtime) -> Self { let rt = HandleOrRuntime::Runtime(runtime); Self { @@ -58,10 +58,10 @@ impl> AlloyDB { } } - // Create a new AlloyDB instance, with a provider and a block and a runtime handle. - // - // This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how - // to obtain a handle. If you are already in asynchronous world, like [tokio::main], use AlloyDB::new instead. + /// Create a new AlloyDB instance, with a provider and a block and a runtime handle. + /// + /// This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how + /// to obtain a handle. If you are already in asynchronous world, like [tokio::main], use AlloyDB::new instead. pub fn with_handle(provider: P, block_number: BlockId, handle: Handle) -> Self { let rt = HandleOrRuntime::Handle(handle); Self { diff --git a/crates/revm/src/db/ethersdb.rs b/crates/revm/src/db/ethersdb.rs index 7b8ef6c34a..6e4f813a1b 100644 --- a/crates/revm/src/db/ethersdb.rs +++ b/crates/revm/src/db/ethersdb.rs @@ -48,10 +48,10 @@ impl EthersDB { } } - // Create a new EthersDB instance, with a provider and a block (None for latest) and a runtime. - // - // Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. - // If you are already using something like [tokio::main], call EthersDB::new instead. + /// Create a new EthersDB instance, with a provider and a block (None for latest) and a runtime. + /// + /// Refer to [tokio::runtime::Builder] how to create a runtime if you are in synchronous world. + /// If you are already using something like [tokio::main], call EthersDB::new instead. pub fn with_runtime( client: Arc, block_number: Option, @@ -70,10 +70,10 @@ impl EthersDB { Some(instance) } - // Create a new EthersDB instance, with a provider and a block (None for latest) and a handle. - // - // This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how - // to obtain a handle. If you are already in asynchronous world, like [tokio::main], use EthersDB::new instead. + /// Create a new EthersDB instance, with a provider and a block (None for latest) and a handle. + /// + /// This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how + /// to obtain a handle. If you are already in asynchronous world, like [tokio::main], use EthersDB::new instead. pub fn with_handle( client: Arc, block_number: Option,