revm_database_interface/
async_db.rs1use crate::{DBErrorMarker, Database, DatabaseRef};
3use core::{error::Error, future::Future};
4use primitives::{Address, StorageKey, StorageValue, B256};
5use state::{AccountInfo, Bytecode};
6use tokio::runtime::{Handle, Runtime};
7
8pub trait DatabaseAsync {
14 type Error: Send + DBErrorMarker + Error;
16
17 fn basic_async(
19 &mut self,
20 address: Address,
21 ) -> impl Future<Output = Result<Option<AccountInfo>, Self::Error>> + Send;
22
23 fn code_by_hash_async(
25 &mut self,
26 code_hash: B256,
27 ) -> impl Future<Output = Result<Bytecode, Self::Error>> + Send;
28
29 fn storage_async(
31 &mut self,
32 address: Address,
33 index: StorageKey,
34 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send;
35
36 fn block_hash_async(
38 &mut self,
39 number: u64,
40 ) -> impl Future<Output = Result<B256, Self::Error>> + Send;
41}
42
43pub trait DatabaseAsyncRef {
49 type Error: Send + DBErrorMarker + Error;
51
52 fn basic_async_ref(
54 &self,
55 address: Address,
56 ) -> impl Future<Output = Result<Option<AccountInfo>, Self::Error>> + Send;
57
58 fn code_by_hash_async_ref(
60 &self,
61 code_hash: B256,
62 ) -> impl Future<Output = Result<Bytecode, Self::Error>> + Send;
63
64 fn storage_async_ref(
66 &self,
67 address: Address,
68 index: StorageKey,
69 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send;
70
71 fn block_hash_async_ref(
73 &self,
74 number: u64,
75 ) -> impl Future<Output = Result<B256, Self::Error>> + Send;
76}
77
78#[derive(Debug)]
80pub struct WrapDatabaseAsync<T> {
81 db: T,
82 rt: HandleOrRuntime,
83}
84
85impl<T> WrapDatabaseAsync<T> {
86 pub fn new(db: T) -> Option<Self> {
90 let rt = match Handle::try_current() {
91 Ok(handle) => match handle.runtime_flavor() {
92 tokio::runtime::RuntimeFlavor::CurrentThread => return None,
93 _ => HandleOrRuntime::Handle(handle),
94 },
95 Err(_) => return None,
96 };
97 Some(Self { db, rt })
98 }
99
100 pub fn with_runtime(db: T, runtime: Runtime) -> Self {
106 let rt = HandleOrRuntime::Runtime(runtime);
107 Self { db, rt }
108 }
109
110 pub fn with_handle(db: T, handle: Handle) -> Self {
117 let rt = HandleOrRuntime::Handle(handle);
118 Self { db, rt }
119 }
120}
121
122impl<T: DatabaseAsync> Database for WrapDatabaseAsync<T> {
123 type Error = T::Error;
124
125 #[inline]
126 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
127 self.rt.block_on(self.db.basic_async(address))
128 }
129
130 #[inline]
131 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
132 self.rt.block_on(self.db.code_by_hash_async(code_hash))
133 }
134
135 #[inline]
136 fn storage(
137 &mut self,
138 address: Address,
139 index: StorageKey,
140 ) -> Result<StorageValue, Self::Error> {
141 self.rt.block_on(self.db.storage_async(address, index))
142 }
143
144 #[inline]
145 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
146 self.rt.block_on(self.db.block_hash_async(number))
147 }
148}
149
150impl<T: DatabaseAsyncRef> DatabaseRef for WrapDatabaseAsync<T> {
151 type Error = T::Error;
152
153 #[inline]
154 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
155 self.rt.block_on(self.db.basic_async_ref(address))
156 }
157
158 #[inline]
159 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
160 self.rt.block_on(self.db.code_by_hash_async_ref(code_hash))
161 }
162
163 #[inline]
164 fn storage_ref(
165 &self,
166 address: Address,
167 index: StorageKey,
168 ) -> Result<StorageValue, Self::Error> {
169 self.rt.block_on(self.db.storage_async_ref(address, index))
170 }
171
172 #[inline]
173 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
174 self.rt.block_on(self.db.block_hash_async_ref(number))
175 }
176}
177
178#[derive(Debug)]
180enum HandleOrRuntime {
181 Handle(Handle),
182 Runtime(Runtime),
183}
184
185impl HandleOrRuntime {
186 #[inline]
187 fn block_on<F>(&self, f: F) -> F::Output
188 where
189 F: Future + Send,
190 F::Output: Send,
191 {
192 match self {
193 Self::Handle(handle) => tokio::task::block_in_place(move || handle.block_on(f)),
194 Self::Runtime(rt) => rt.block_on(f),
195 }
196 }
197}