revm_database_interface/
async_db.rsuse core::future::Future;
use primitives::{Address, B256, U256};
use state::{AccountInfo, Bytecode};
use tokio::runtime::{Handle, Runtime};
use crate::{DBErrorMarker, Database, DatabaseRef};
pub trait DatabaseAsync {
type Error: Send + DBErrorMarker;
fn basic_async(
&mut self,
address: Address,
) -> impl Future<Output = Result<Option<AccountInfo>, Self::Error>> + Send;
fn code_by_hash_async(
&mut self,
code_hash: B256,
) -> impl Future<Output = Result<Bytecode, Self::Error>> + Send;
fn storage_async(
&mut self,
address: Address,
index: U256,
) -> impl Future<Output = Result<U256, Self::Error>> + Send;
fn block_hash_async(
&mut self,
number: u64,
) -> impl Future<Output = Result<B256, Self::Error>> + Send;
}
pub trait DatabaseAsyncRef {
type Error: Send + DBErrorMarker;
fn basic_async_ref(
&self,
address: Address,
) -> impl Future<Output = Result<Option<AccountInfo>, Self::Error>> + Send;
fn code_by_hash_async_ref(
&self,
code_hash: B256,
) -> impl Future<Output = Result<Bytecode, Self::Error>> + Send;
fn storage_async_ref(
&self,
address: Address,
index: U256,
) -> impl Future<Output = Result<U256, Self::Error>> + Send;
fn block_hash_async_ref(
&self,
number: u64,
) -> impl Future<Output = Result<B256, Self::Error>> + Send;
}
#[derive(Debug)]
pub struct WrapDatabaseAsync<T> {
db: T,
rt: HandleOrRuntime,
}
impl<T> WrapDatabaseAsync<T> {
pub fn new(db: T) -> Option<Self> {
let rt = match Handle::try_current() {
Ok(handle) => match handle.runtime_flavor() {
tokio::runtime::RuntimeFlavor::CurrentThread => return None,
_ => HandleOrRuntime::Handle(handle),
},
Err(_) => return None,
};
Some(Self { db, rt })
}
pub fn with_runtime(db: T, runtime: Runtime) -> Self {
let rt = HandleOrRuntime::Runtime(runtime);
Self { db, rt }
}
pub fn with_handle(db: T, handle: Handle) -> Self {
let rt = HandleOrRuntime::Handle(handle);
Self { db, rt }
}
}
impl<T: DatabaseAsync> Database for WrapDatabaseAsync<T> {
type Error = T::Error;
#[inline]
fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
self.rt.block_on(self.db.basic_async(address))
}
#[inline]
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.rt.block_on(self.db.code_by_hash_async(code_hash))
}
#[inline]
fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
self.rt.block_on(self.db.storage_async(address, index))
}
#[inline]
fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
self.rt.block_on(self.db.block_hash_async(number))
}
}
impl<T: DatabaseAsyncRef> DatabaseRef for WrapDatabaseAsync<T> {
type Error = T::Error;
#[inline]
fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
self.rt.block_on(self.db.basic_async_ref(address))
}
#[inline]
fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
self.rt.block_on(self.db.code_by_hash_async_ref(code_hash))
}
#[inline]
fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
self.rt.block_on(self.db.storage_async_ref(address, index))
}
#[inline]
fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
self.rt.block_on(self.db.block_hash_async_ref(number))
}
}
#[derive(Debug)]
enum HandleOrRuntime {
Handle(Handle),
Runtime(Runtime),
}
impl HandleOrRuntime {
#[inline]
fn block_on<F>(&self, f: F) -> F::Output
where
F: 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),
}
}
}