revm_trace/
wrap_db.rs

1//! # MyWrapDatabaseAsync
2//!
3//! This module provides a fork of REVM's `WrapDatabaseAsync`,
4//! with an additional `get_db_mut` method for advanced control.
5//!
6//! ## Key Features
7//!
8//! - Wraps any `DatabaseAsync` or `DatabaseAsyncRef` to provide a synchronous `Database`/`DatabaseRef` interface.
9//! - Adds `get_db_mut`, allowing direct mutable access to the underlying async database.
10//!   This is especially useful for operations such as resetting the block number or other configuration/state changes
11//!   that are not covered by the standard trait interfaces.
12//! - Maintains compatibility with both async and sync REVM database traits.
13//!
14//! ## Usage Example
15//!
16//! ```rust,ignore
17//! let mut wrapped_db = MyWrapDatabaseAsync::new(alloy_db)?;
18//! let inner_db = wrapped_db.get_db_mut();
19//! inner_db.set_block_number(new_block_id);
20//! ```
21//!
22//! This extension is essential for scenarios where you need to update the underlying database state
23//! (e.g., switching block context) without reconstructing the entire wrapper.
24
25use revm::{
26    database::{Database, DatabaseRef},
27    database_interface::async_db::{DatabaseAsync, DatabaseAsyncRef},
28    primitives::{Address, StorageKey, StorageValue, B256},
29    state::{AccountInfo, Bytecode},
30};
31
32use core::future::Future;
33use tokio::runtime::{Handle, Runtime};
34
35/// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] to provide a [`Database`] implementation.
36#[derive(Debug)]
37pub struct MyWrapDatabaseAsync<T> {
38    db: T,
39    rt: HandleOrRuntime,
40}
41
42impl<T> MyWrapDatabaseAsync<T> {
43    /// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] instance.
44    ///
45    /// Returns `None` if no tokio runtime is available or if the current runtime is a current-thread runtime.
46    pub fn new(db: T) -> Option<Self> {
47        let rt = match Handle::try_current() {
48            Ok(handle) => match handle.runtime_flavor() {
49                tokio::runtime::RuntimeFlavor::CurrentThread => return None,
50                _ => HandleOrRuntime::Handle(handle),
51            },
52            Err(_) => return None,
53        };
54        Some(Self { db, rt })
55    }
56
57    /// Gets a mutable reference to the inner database
58    ///
59    /// This allows direct access to the wrapped database instance for operations
60    /// that are not covered by the standard Database/DatabaseRef interfaces,
61    /// such as configuration changes or state updates.
62    ///
63    /// # Example
64    /// ```rust,ignore
65    /// let mut wrapped_db = MyWrapDatabaseAsync::new(alloy_db)?;
66    /// let inner_db = wrapped_db.get_db_mut();
67    /// inner_db.set_block_number(new_block_id);
68    /// ```
69    pub fn get_db_mut(&mut self) -> &mut T {
70        &mut self.db
71    }
72
73    /// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] instance, with a runtime.
74    ///
75    /// Refer to [tokio::runtime::Builder] on how to create a runtime if you are in synchronous world.
76    ///
77    /// If you are already using something like [tokio::main], call [`WrapDatabaseAsync::new`] instead.
78    pub fn with_runtime(db: T, runtime: Runtime) -> Self {
79        let rt = HandleOrRuntime::Runtime(runtime);
80        Self { db, rt }
81    }
82
83    /// Wraps a [DatabaseAsync] or [DatabaseAsyncRef] instance, with a runtime handle.
84    ///
85    /// This generally allows you to pass any valid runtime handle, refer to [tokio::runtime::Handle] on how
86    /// to obtain a handle.
87    ///
88    /// If you are already in asynchronous world, like [tokio::main], use [`WrapDatabaseAsync::new`] instead.
89    pub fn with_handle(db: T, handle: Handle) -> Self {
90        let rt = HandleOrRuntime::Handle(handle);
91        Self { db, rt }
92    }
93}
94
95impl<T: DatabaseAsync> Database for MyWrapDatabaseAsync<T> {
96    type Error = T::Error;
97
98    #[inline]
99    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
100        self.rt.block_on(self.db.basic_async(address))
101    }
102
103    #[inline]
104    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
105        self.rt.block_on(self.db.code_by_hash_async(code_hash))
106    }
107
108    #[inline]
109    fn storage(
110        &mut self,
111        address: Address,
112        index: StorageKey,
113    ) -> Result<StorageValue, Self::Error> {
114        self.rt.block_on(self.db.storage_async(address, index))
115    }
116
117    #[inline]
118    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
119        self.rt.block_on(self.db.block_hash_async(number))
120    }
121}
122
123impl<T: DatabaseAsyncRef> DatabaseRef for MyWrapDatabaseAsync<T> {
124    type Error = T::Error;
125
126    #[inline]
127    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
128        self.rt.block_on(self.db.basic_async_ref(address))
129    }
130
131    #[inline]
132    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
133        self.rt.block_on(self.db.code_by_hash_async_ref(code_hash))
134    }
135
136    #[inline]
137    fn storage_ref(
138        &self,
139        address: Address,
140        index: StorageKey,
141    ) -> Result<StorageValue, Self::Error> {
142        self.rt.block_on(self.db.storage_async_ref(address, index))
143    }
144
145    #[inline]
146    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
147        self.rt.block_on(self.db.block_hash_async_ref(number))
148    }
149}
150
151// Hold a tokio runtime handle or full runtime
152#[derive(Debug)]
153enum HandleOrRuntime {
154    Handle(Handle),
155    Runtime(Runtime),
156}
157
158impl HandleOrRuntime {
159    #[inline]
160    fn block_on<F>(&self, f: F) -> F::Output
161    where
162        F: Future + Send,
163        F::Output: Send,
164    {
165        match self {
166            Self::Handle(handle) => tokio::task::block_in_place(move || handle.block_on(f)),
167            Self::Runtime(rt) => rt.block_on(f),
168        }
169    }
170}