1use crate::{DBErrorMarker, Database, DatabaseRef};
3use core::future::Future;
4use primitives::{Address, StorageKey, StorageValue, B256};
5use state::{AccountInfo, Bytecode};
6use tokio::runtime::{Handle, Runtime};
7
8pub trait DatabaseAsync {
14 type Error: DBErrorMarker;
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 #[inline]
40 fn storage_by_account_id_async(
41 &mut self,
42 address: Address,
43 account_id: usize,
44 storage_key: StorageKey,
45 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send {
46 let _ = account_id;
47 self.storage_async(address, storage_key)
48 }
49
50 fn block_hash_async(
52 &mut self,
53 number: u64,
54 ) -> impl Future<Output = Result<B256, Self::Error>> + Send;
55}
56
57pub trait DatabaseAsyncRef {
63 type Error: DBErrorMarker;
65
66 fn basic_async_ref(
68 &self,
69 address: Address,
70 ) -> impl Future<Output = Result<Option<AccountInfo>, Self::Error>> + Send;
71
72 fn code_by_hash_async_ref(
74 &self,
75 code_hash: B256,
76 ) -> impl Future<Output = Result<Bytecode, Self::Error>> + Send;
77
78 fn storage_async_ref(
80 &self,
81 address: Address,
82 index: StorageKey,
83 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send;
84
85 #[inline]
89 fn storage_by_account_id_async_ref(
90 &self,
91 address: Address,
92 account_id: usize,
93 storage_key: StorageKey,
94 ) -> impl Future<Output = Result<StorageValue, Self::Error>> + Send {
95 let _ = account_id;
96 self.storage_async_ref(address, storage_key)
97 }
98
99 fn block_hash_async_ref(
101 &self,
102 number: u64,
103 ) -> impl Future<Output = Result<B256, Self::Error>> + Send;
104}
105
106#[derive(Debug)]
108pub struct WrapDatabaseAsync<T> {
109 db: T,
110 rt: HandleOrRuntime,
111}
112
113impl<T> WrapDatabaseAsync<T> {
114 pub fn new(db: T) -> Option<Self> {
118 let rt = match Handle::try_current() {
119 Ok(handle) => match handle.runtime_flavor() {
120 tokio::runtime::RuntimeFlavor::CurrentThread => return None,
121 _ => HandleOrRuntime::Handle(handle),
122 },
123 Err(_) => return None,
124 };
125 Some(Self { db, rt })
126 }
127
128 pub fn with_runtime(db: T, runtime: Runtime) -> Self {
134 let rt = HandleOrRuntime::Runtime(runtime);
135 Self { db, rt }
136 }
137
138 pub fn with_handle(db: T, handle: Handle) -> Self {
145 let rt = HandleOrRuntime::Handle(handle);
146 Self { db, rt }
147 }
148}
149
150impl<T: DatabaseAsync> Database for WrapDatabaseAsync<T> {
151 type Error = T::Error;
152
153 #[inline]
154 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
155 self.rt.block_on(self.db.basic_async(address))
156 }
157
158 #[inline]
159 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
160 self.rt.block_on(self.db.code_by_hash_async(code_hash))
161 }
162
163 #[inline]
164 fn storage(
165 &mut self,
166 address: Address,
167 index: StorageKey,
168 ) -> Result<StorageValue, Self::Error> {
169 self.rt.block_on(self.db.storage_async(address, index))
170 }
171
172 #[inline]
176 fn storage_by_account_id(
177 &mut self,
178 address: Address,
179 account_id: usize,
180 storage_key: StorageKey,
181 ) -> Result<StorageValue, Self::Error> {
182 self.rt.block_on(
183 self.db
184 .storage_by_account_id_async(address, account_id, storage_key),
185 )
186 }
187
188 #[inline]
189 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
190 self.rt.block_on(self.db.block_hash_async(number))
191 }
192}
193
194impl<T: DatabaseAsyncRef> DatabaseRef for WrapDatabaseAsync<T> {
195 type Error = T::Error;
196
197 #[inline]
198 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
199 self.rt.block_on(self.db.basic_async_ref(address))
200 }
201
202 #[inline]
203 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
204 self.rt.block_on(self.db.code_by_hash_async_ref(code_hash))
205 }
206
207 #[inline]
208 fn storage_ref(
209 &self,
210 address: Address,
211 index: StorageKey,
212 ) -> Result<StorageValue, Self::Error> {
213 self.rt.block_on(self.db.storage_async_ref(address, index))
214 }
215
216 #[inline]
217 fn storage_by_account_id_ref(
218 &self,
219 address: Address,
220 account_id: usize,
221 storage_key: StorageKey,
222 ) -> Result<StorageValue, Self::Error> {
223 self.rt.block_on(
224 self.db
225 .storage_by_account_id_async_ref(address, account_id, storage_key),
226 )
227 }
228
229 #[inline]
230 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
231 self.rt.block_on(self.db.block_hash_async_ref(number))
232 }
233}
234
235#[derive(Debug)]
237enum HandleOrRuntime {
238 Handle(Handle),
239 Runtime(Runtime),
240}
241
242impl HandleOrRuntime {
243 #[inline]
244 fn block_on<F>(&self, f: F) -> F::Output
245 where
246 F: Future + Send,
247 F::Output: Send,
248 {
249 match self {
250 Self::Handle(handle) => {
251 let should_use_block_in_place = Handle::try_current()
260 .ok()
261 .map(|current| {
262 !matches!(
265 current.runtime_flavor(),
266 tokio::runtime::RuntimeFlavor::CurrentThread
267 )
268 })
269 .unwrap_or(false);
270
271 if should_use_block_in_place {
272 tokio::task::block_in_place(move || handle.block_on(f))
278 } else {
279 handle.block_on(f)
283 }
284 }
285 Self::Runtime(rt) => rt.block_on(f),
286 }
287 }
288}