use crate::primitives::alloy_primitives::{BlockNumber, StorageKey, StorageValue};
use core::ops::{Deref, DerefMut};
use reth_primitives::{Account, Address, B256, U256};
use reth_storage_errors::provider::{ProviderError, ProviderResult};
use revm::{
db::DatabaseRef,
primitives::{AccountInfo, Bytecode},
Database,
};
/// A helper trait responsible for providing that necessary state for the EVM execution.
///
/// This servers as the data layer for [Database].
pub trait EvmStateProvider: Send + Sync {
/// Get basic account information.
///
/// Returns `None` if the account doesn't exist.
fn basic_account(&self, address: Address) -> ProviderResult>;
/// Get the hash of the block with the given number. Returns `None` if no block with this number
/// exists.
fn block_hash(&self, number: BlockNumber) -> ProviderResult >;
/// Get account code by its hash
fn bytecode_by_hash(
&self,
code_hash: B256,
) -> ProviderResult >;
/// Get storage of given account.
fn storage(
&self,
account: Address,
storage_key: StorageKey,
) -> ProviderResult >;
}
// Blanket implementation of EvmStateProvider for any type that implements StateProvider.
impl EvmStateProvider for T {
fn basic_account(&self, address: Address) -> ProviderResult> {
::basic_account(self, address)
}
fn block_hash(&self, number: BlockNumber) -> ProviderResult> {
::block_hash(self, number)
}
fn bytecode_by_hash(
&self,
code_hash: B256,
) -> ProviderResult> {
::bytecode_by_hash(self, code_hash)
}
fn storage(
&self,
account: Address,
storage_key: StorageKey,
) -> ProviderResult> {
::storage(self, account, storage_key)
}
}
/// A [Database] and [`DatabaseRef`] implementation that uses [`EvmStateProvider`] as the underlying
/// data source.
#[derive(Debug, Clone)]
pub struct StateProviderDatabase(pub DB);
impl StateProviderDatabase {
/// Create new State with generic `StateProvider`.
pub const fn new(db: DB) -> Self {
Self(db)
}
/// Consume State and return inner `StateProvider`.
pub fn into_inner(self) -> DB {
self.0
}
}
impl Deref for StateProviderDatabase {
type Target = DB;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for StateProviderDatabase {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Database for StateProviderDatabase {
type Error = ProviderError;
/// Retrieves basic account information for a given address.
///
/// Returns `Ok` with `Some(AccountInfo)` if the account exists,
/// `None` if it doesn't, or an error if encountered.
fn basic(&mut self, address: Address) -> Result, Self::Error> {
DatabaseRef::basic_ref(self, address)
}
/// Retrieves the bytecode associated with a given code hash.
///
/// Returns `Ok` with the bytecode if found, or the default bytecode otherwise.
fn code_by_hash(&mut self, code_hash: B256) -> Result {
DatabaseRef::code_by_hash_ref(self, code_hash)
}
/// Retrieves the storage value at a specific index for a given address.
///
/// Returns `Ok` with the storage value, or the default value if not found.
fn storage(&mut self, address: Address, index: U256) -> Result {
DatabaseRef::storage_ref(self, address, index)
}
/// Retrieves the block hash for a given block number.
///
/// Returns `Ok` with the block hash if found, or the default hash otherwise.
/// Note: It safely casts the `number` to `u64`.
fn block_hash(&mut self, number: u64) -> Result {
DatabaseRef::block_hash_ref(self, number)
}
}
impl DatabaseRef for StateProviderDatabase {
type Error = ::Error;
/// Retrieves basic account information for a given address.
///
/// Returns `Ok` with `Some(AccountInfo)` if the account exists,
/// `None` if it doesn't, or an error if encountered.
fn basic_ref(&self, address: Address) -> Result, Self::Error> {
Ok(self.basic_account(address)?.map(Into::into))
}
/// Retrieves the bytecode associated with a given code hash.
///
/// Returns `Ok` with the bytecode if found, or the default bytecode otherwise.
fn code_by_hash_ref(&self, code_hash: B256) -> Result {
Ok(self.bytecode_by_hash(code_hash)?.unwrap_or_default().0)
}
/// Retrieves the storage value at a specific index for a given address.
///
/// Returns `Ok` with the storage value, or the default value if not found.
fn storage_ref(&self, address: Address, index: U256) -> Result {
Ok(self.0.storage(address, B256::new(index.to_be_bytes()))?.unwrap_or_default())
}
/// Retrieves the block hash for a given block number.
///
/// Returns `Ok` with the block hash if found, or the default hash otherwise.
fn block_hash_ref(&self, number: u64) -> Result {
// Get the block hash or default hash with an attempt to convert U256 block number to u64
Ok(self.0.block_hash(number)?.unwrap_or_default())
}
}