reth_revm/
database.rs

1use crate::primitives::alloy_primitives::{BlockNumber, StorageKey, StorageValue};
2use alloy_primitives::{Address, B256, U256};
3use core::ops::{Deref, DerefMut};
4use reth_primitives_traits::Account;
5use reth_storage_api::{AccountReader, BlockHashReader, StateProvider};
6use reth_storage_errors::provider::{ProviderError, ProviderResult};
7use revm::{bytecode::Bytecode, state::AccountInfo, Database, DatabaseRef};
8
9/// A helper trait responsible for providing state necessary for EVM execution.
10///
11/// This serves as the data layer for [`Database`].
12pub trait EvmStateProvider: Send + Sync {
13    /// Get basic account information.
14    ///
15    /// Returns [`None`] if the account doesn't exist.
16    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>>;
17
18    /// Get the hash of the block with the given number. Returns [`None`] if no block with this
19    /// number exists.
20    fn block_hash(&self, number: BlockNumber) -> ProviderResult<Option<B256>>;
21
22    /// Get account code by hash.
23    fn bytecode_by_hash(
24        &self,
25        code_hash: &B256,
26    ) -> ProviderResult<Option<reth_primitives_traits::Bytecode>>;
27
28    /// Get storage of the given account.
29    fn storage(
30        &self,
31        account: Address,
32        storage_key: StorageKey,
33    ) -> ProviderResult<Option<StorageValue>>;
34}
35
36// Blanket implementation of EvmStateProvider for any type that implements StateProvider.
37impl<T: StateProvider> EvmStateProvider for T {
38    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
39        <T as AccountReader>::basic_account(self, address)
40    }
41
42    fn block_hash(&self, number: BlockNumber) -> ProviderResult<Option<B256>> {
43        <T as BlockHashReader>::block_hash(self, number)
44    }
45
46    fn bytecode_by_hash(
47        &self,
48        code_hash: &B256,
49    ) -> ProviderResult<Option<reth_primitives_traits::Bytecode>> {
50        <T as StateProvider>::bytecode_by_hash(self, code_hash)
51    }
52
53    fn storage(
54        &self,
55        account: Address,
56        storage_key: StorageKey,
57    ) -> ProviderResult<Option<StorageValue>> {
58        <T as StateProvider>::storage(self, account, storage_key)
59    }
60}
61
62/// A [Database] and [`DatabaseRef`] implementation that uses [`EvmStateProvider`] as the underlying
63/// data source.
64#[derive(Debug, Clone)]
65pub struct StateProviderDatabase<DB>(pub DB);
66
67impl<DB> StateProviderDatabase<DB> {
68    /// Create new State with generic `StateProvider`.
69    pub const fn new(db: DB) -> Self {
70        Self(db)
71    }
72
73    /// Consume State and return inner `StateProvider`.
74    pub fn into_inner(self) -> DB {
75        self.0
76    }
77}
78
79impl<DB> AsRef<DB> for StateProviderDatabase<DB> {
80    fn as_ref(&self) -> &DB {
81        self
82    }
83}
84
85impl<DB> Deref for StateProviderDatabase<DB> {
86    type Target = DB;
87
88    fn deref(&self) -> &Self::Target {
89        &self.0
90    }
91}
92
93impl<DB> DerefMut for StateProviderDatabase<DB> {
94    fn deref_mut(&mut self) -> &mut Self::Target {
95        &mut self.0
96    }
97}
98
99impl<DB: EvmStateProvider> Database for StateProviderDatabase<DB> {
100    type Error = ProviderError;
101
102    /// Retrieves basic account information for a given address.
103    ///
104    /// Returns `Ok` with `Some(AccountInfo)` if the account exists,
105    /// `None` if it doesn't, or an error if encountered.
106    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
107        self.basic_ref(address)
108    }
109
110    /// Retrieves the bytecode associated with a given code hash.
111    ///
112    /// Returns `Ok` with the bytecode if found, or the default bytecode otherwise.
113    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
114        self.code_by_hash_ref(code_hash)
115    }
116
117    /// Retrieves the storage value at a specific index for a given address.
118    ///
119    /// Returns `Ok` with the storage value, or the default value if not found.
120    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
121        self.storage_ref(address, index)
122    }
123
124    /// Retrieves the block hash for a given block number.
125    ///
126    /// Returns `Ok` with the block hash if found, or the default hash otherwise.
127    /// Note: It safely casts the `number` to `u64`.
128    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
129        self.block_hash_ref(number)
130    }
131}
132
133impl<DB: EvmStateProvider> DatabaseRef for StateProviderDatabase<DB> {
134    type Error = <Self as Database>::Error;
135
136    /// Retrieves basic account information for a given address.
137    ///
138    /// Returns `Ok` with `Some(AccountInfo)` if the account exists,
139    /// `None` if it doesn't, or an error if encountered.
140    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
141        Ok(self.basic_account(&address)?.map(Into::into))
142    }
143
144    /// Retrieves the bytecode associated with a given code hash.
145    ///
146    /// Returns `Ok` with the bytecode if found, or the default bytecode otherwise.
147    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
148        Ok(self.bytecode_by_hash(&code_hash)?.unwrap_or_default().0)
149    }
150
151    /// Retrieves the storage value at a specific index for a given address.
152    ///
153    /// Returns `Ok` with the storage value, or the default value if not found.
154    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
155        Ok(self.0.storage(address, B256::new(index.to_be_bytes()))?.unwrap_or_default())
156    }
157
158    /// Retrieves the block hash for a given block number.
159    ///
160    /// Returns `Ok` with the block hash if found, or the default hash otherwise.
161    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
162        // Get the block hash or default hash with an attempt to convert U256 block number to u64
163        Ok(self.0.block_hash(number)?.unwrap_or_default())
164    }
165}