Skip to main content

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