reth_storage_api/
state.rs

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