reth_revm/database.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
use crate::primitives::alloy_primitives::{BlockNumber, StorageKey, StorageValue};
use alloy_primitives::{Address, B256, U256};
use core::ops::{Deref, DerefMut};
use reth_primitives::Account;
use reth_storage_errors::provider::{ProviderError, ProviderResult};
use revm::{
db::DatabaseRef,
primitives::{AccountInfo, Bytecode},
Database,
};
/// A helper trait responsible for providing state necessary for EVM execution.
///
/// This serves 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<Option<Account>>;
/// 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<Option<B256>>;
/// Get account code by hash.
fn bytecode_by_hash(
&self,
code_hash: B256,
) -> ProviderResult<Option<reth_primitives::Bytecode>>;
/// Get storage of the given account.
fn storage(
&self,
account: Address,
storage_key: StorageKey,
) -> ProviderResult<Option<StorageValue>>;
}
// Blanket implementation of EvmStateProvider for any type that implements StateProvider.
impl<T: reth_storage_api::StateProvider> EvmStateProvider for T {
fn basic_account(&self, address: Address) -> ProviderResult<Option<Account>> {
<T as reth_storage_api::AccountReader>::basic_account(self, address)
}
fn block_hash(&self, number: BlockNumber) -> ProviderResult<Option<B256>> {
<T as reth_storage_api::BlockHashReader>::block_hash(self, number)
}
fn bytecode_by_hash(
&self,
code_hash: B256,
) -> ProviderResult<Option<reth_primitives::Bytecode>> {
<T as reth_storage_api::StateProvider>::bytecode_by_hash(self, code_hash)
}
fn storage(
&self,
account: Address,
storage_key: StorageKey,
) -> ProviderResult<Option<StorageValue>> {
<T as reth_storage_api::StateProvider>::storage(self, account, storage_key)
}
}
/// A [Database] and [`DatabaseRef`] implementation that uses [`EvmStateProvider`] as the underlying
/// data source.
#[derive(Debug, Clone)]
pub struct StateProviderDatabase<DB>(pub DB);
impl<DB> StateProviderDatabase<DB> {
/// 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<DB> AsRef<DB> for StateProviderDatabase<DB> {
fn as_ref(&self) -> &DB {
self
}
}
impl<DB> Deref for StateProviderDatabase<DB> {
type Target = DB;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<DB> DerefMut for StateProviderDatabase<DB> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<DB: EvmStateProvider> Database for StateProviderDatabase<DB> {
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<Option<AccountInfo>, Self::Error> {
self.basic_ref(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<Bytecode, Self::Error> {
self.code_by_hash_ref(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<U256, Self::Error> {
self.storage_ref(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<B256, Self::Error> {
self.block_hash_ref(number)
}
}
impl<DB: EvmStateProvider> DatabaseRef for StateProviderDatabase<DB> {
type Error = <Self as Database>::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<Option<AccountInfo>, 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<Bytecode, Self::Error> {
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<U256, Self::Error> {
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<B256, Self::Error> {
// 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())
}
}