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}