reth_storage_api/
state.rs

1use super::{
2    AccountReader, BlockHashReader, BlockIdReader, StateProofProvider, StateRootProvider,
3    StorageRootProvider,
4};
5use alloy_consensus::constants::KECCAK_EMPTY;
6use alloy_eips::{BlockId, BlockNumberOrTag};
7use alloy_primitives::{Address, BlockHash, BlockNumber, StorageKey, B256, U256};
8use auto_impl::auto_impl;
9use reth_primitives::Bytecode;
10use reth_storage_errors::provider::ProviderResult;
11use reth_trie::HashedPostState;
12use reth_trie_db::StateCommitment;
13use revm::{db::states::BundleState, primitives::FlaggedStorage};
14
15/// Type alias of boxed [`StateProvider`].
16pub type StateProviderBox = Box<dyn StateProvider>;
17
18/// An abstraction for a type that provides state data.
19#[auto_impl(&, Arc, Box)]
20pub trait StateProvider:
21    BlockHashReader
22    + AccountReader
23    + StateRootProvider
24    + StorageRootProvider
25    + StateProofProvider
26    + HashedPostStateProvider
27    + Send
28    + Sync
29{
30    /// Get storage of given account.
31    fn storage(
32        &self,
33        account: Address,
34        storage_key: StorageKey,
35    ) -> ProviderResult<Option<FlaggedStorage>>;
36
37    /// Get account code by its hash
38    fn bytecode_by_hash(&self, code_hash: B256) -> ProviderResult<Option<Bytecode>>;
39
40    /// Get account code by its address.
41    ///
42    /// Returns `None` if the account doesn't exist or account is not a contract
43    fn account_code(&self, addr: Address) -> ProviderResult<Option<Bytecode>> {
44        // Get basic account information
45        // Returns None if acc doesn't exist
46        let acc = match self.basic_account(addr)? {
47            Some(acc) => acc,
48            None => return Ok(None),
49        };
50
51        if let Some(code_hash) = acc.bytecode_hash {
52            if code_hash == KECCAK_EMPTY {
53                return Ok(None)
54            }
55            // Get the code from the code hash
56            return self.bytecode_by_hash(code_hash)
57        }
58
59        // Return `None` if no code hash is set
60        Ok(None)
61    }
62
63    /// Get account balance by its address.
64    ///
65    /// Returns `None` if the account doesn't exist
66    fn account_balance(&self, addr: Address) -> ProviderResult<Option<U256>> {
67        // Get basic account information
68        // Returns None if acc doesn't exist
69        match self.basic_account(addr)? {
70            Some(acc) => Ok(Some(acc.balance)),
71            None => Ok(None),
72        }
73    }
74
75    /// Get account nonce by its address.
76    ///
77    /// Returns `None` if the account doesn't exist
78    fn account_nonce(&self, addr: Address) -> ProviderResult<Option<u64>> {
79        // Get basic account information
80        // Returns None if acc doesn't exist
81        match self.basic_account(addr)? {
82            Some(acc) => Ok(Some(acc.nonce)),
83            None => Ok(None),
84        }
85    }
86}
87
88/// Trait implemented for database providers that can provide the [`StateCommitment`] type.
89pub trait StateCommitmentProvider: Send + Sync {
90    /// The [`StateCommitment`] type that can be used to perform state commitment operations.
91    type StateCommitment: StateCommitment;
92}
93
94/// Trait that provides the hashed state from various sources.
95#[auto_impl(&, Arc, Box)]
96pub trait HashedPostStateProvider: Send + Sync {
97    /// Returns the `HashedPostState` of the provided [`BundleState`].
98    fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState;
99}
100
101/// Trait implemented for database providers that can be converted into a historical state provider.
102pub trait TryIntoHistoricalStateProvider {
103    /// Returns a historical [`StateProvider`] indexed by the given historic block number.
104    fn try_into_history_at_block(
105        self,
106        block_number: BlockNumber,
107    ) -> ProviderResult<StateProviderBox>;
108}
109
110/// Light wrapper that returns `StateProvider` implementations that correspond to the given
111/// `BlockNumber`, the latest state, or the pending state.
112///
113/// This type differentiates states into `historical`, `latest` and `pending`, where the `latest`
114/// block determines what is historical or pending: `[historical..latest..pending]`.
115///
116/// The `latest` state represents the state after the most recent block has been committed to the
117/// database, `historical` states are states that have been committed to the database before the
118/// `latest` state, and `pending` states are states that have not yet been committed to the
119/// database which may or may not become the `latest` state, depending on consensus.
120///
121/// Note: the `pending` block is considered the block that extends the canonical chain but one and
122/// has the `latest` block as its parent.
123///
124/// All states are _inclusive_, meaning they include _all_ all changes made (executed transactions)
125/// in their respective blocks. For example [StateProviderFactory::history_by_block_number] for
126/// block number `n` will return the state after block `n` was executed (transactions, withdrawals).
127/// In other words, all states point to the end of the state's respective block, which is equivalent
128/// to state at the beginning of the child block.
129///
130/// This affects tracing, or replaying blocks, which will need to be executed on top of the state of
131/// the parent block. For example, in order to trace block `n`, the state after block `n - 1` needs
132/// to be used, since block `n` was executed on its parent block's state.
133#[auto_impl(&, Arc, Box)]
134pub trait StateProviderFactory: BlockIdReader + Send + Sync {
135    /// Storage provider for latest block.
136    fn latest(&self) -> ProviderResult<StateProviderBox>;
137
138    /// Returns a [`StateProvider`] indexed by the given [`BlockId`].
139    ///
140    /// Note: if a number or hash is provided this will __only__ look at historical(canonical)
141    /// state.
142    fn state_by_block_id(&self, block_id: BlockId) -> ProviderResult<StateProviderBox> {
143        match block_id {
144            BlockId::Number(block_number) => self.state_by_block_number_or_tag(block_number),
145            BlockId::Hash(block_hash) => self.history_by_block_hash(block_hash.into()),
146        }
147    }
148
149    /// Returns a [StateProvider] indexed by the given block number or tag.
150    ///
151    /// Note: if a number is provided this will only look at historical(canonical) state.
152    fn state_by_block_number_or_tag(
153        &self,
154        number_or_tag: BlockNumberOrTag,
155    ) -> ProviderResult<StateProviderBox>;
156
157    /// Returns a historical [StateProvider] indexed by the given historic block number.
158    ///
159    ///
160    /// Note: this only looks at historical blocks, not pending blocks.
161    fn history_by_block_number(&self, block: BlockNumber) -> ProviderResult<StateProviderBox>;
162
163    /// Returns a historical [StateProvider] indexed by the given block hash.
164    ///
165    /// Note: this only looks at historical blocks, not pending blocks.
166    fn history_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
167
168    /// Returns _any_ [StateProvider] with matching block hash.
169    ///
170    /// This will return a [StateProvider] for either a historical or pending block.
171    fn state_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
172
173    /// Storage provider for pending state.
174    ///
175    /// Represents the state at the block that extends the canonical chain by one.
176    /// If there's no `pending` block, then this is equal to [StateProviderFactory::latest]
177    fn pending(&self) -> ProviderResult<StateProviderBox>;
178
179    /// Storage provider for pending state for the given block hash.
180    ///
181    /// Represents the state at the block that extends the canonical chain.
182    ///
183    /// If the block couldn't be found, returns `None`.
184    fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>>;
185}