Skip to main content

reth_storage_api/
state.rs

1use super::{
2    AccountReader, BlockHashReader, BlockIdReader, EvmStateProviderAdapter, StateProofProvider,
3    StateRootProvider, 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;
10#[cfg(feature = "chain-state")]
11use reth_chain_state::ExecutedBlock;
12use reth_execution_types::ExecutionOutcome;
13use reth_primitives_traits::{Bytecode, NodePrimitives};
14use reth_storage_errors::provider::ProviderResult;
15use reth_trie_common::{bundle_state::BundleState, HashedPostState};
16
17/// This just receives state, or [`ExecutionOutcome`], from the provider
18#[auto_impl::auto_impl(&, Arc, Box)]
19pub trait StateReader: Send {
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 + Send + 'static>;
32
33/// An abstraction for a type that provides state data.
34#[auto_impl(&, Arc, Box)]
35pub trait StateProvider:
36    BlockHashReader
37    + AccountReader
38    + BytecodeReader
39    + StateRootProvider
40    + StorageRootProvider
41    + StateProofProvider
42    + HashedPostStateProvider
43{
44    /// Get storage of given account.
45    fn storage(
46        &self,
47        account: Address,
48        storage_key: StorageKey,
49    ) -> ProviderResult<Option<StorageValue>>;
50
51    /// Get account code by its address.
52    ///
53    /// Returns `None` if the account doesn't exist or account is not a contract
54    fn account_code(&self, addr: &Address) -> ProviderResult<Option<Bytecode>> {
55        // Get basic account information
56        // Returns None if acc doesn't exist
57        let acc = match self.basic_account(addr)? {
58            Some(acc) => acc,
59            None => return Ok(None),
60        };
61
62        if let Some(code_hash) = acc.bytecode_hash {
63            if code_hash == KECCAK_EMPTY {
64                return Ok(None)
65            }
66            // Get the code from the code hash
67            return self.bytecode_by_hash(&code_hash)
68        }
69
70        // Return `None` if no code hash is set
71        Ok(None)
72    }
73
74    /// Get account balance by its address.
75    ///
76    /// Returns `None` if the account doesn't exist
77    fn account_balance(&self, addr: &Address) -> ProviderResult<Option<U256>> {
78        // Get basic account information
79        // Returns None if acc doesn't exist
80
81        self.basic_account(addr)?.map_or_else(|| Ok(None), |acc| Ok(Some(acc.balance)))
82    }
83
84    /// Get account nonce by its address.
85    ///
86    /// Returns `None` if the account doesn't exist
87    fn account_nonce(&self, addr: &Address) -> ProviderResult<Option<u64>> {
88        // Get basic account information
89        // Returns None if acc doesn't exist
90        self.basic_account(addr)?.map_or_else(|| Ok(None), |acc| Ok(Some(acc.nonce)))
91    }
92
93    /// Wraps this provider for EVM execution without allocating or cloning it.
94    ///
95    /// Call this on a reference to borrow the provider, or on a box to retain ownership.
96    #[auto_impl(keep_default_for(&, Arc, Box))]
97    fn into_evm_state_provider(self) -> EvmStateProviderAdapter<Self>
98    where
99        Self: Sized,
100    {
101        EvmStateProviderAdapter(self)
102    }
103}
104
105/// Minimal requirements to read a full account, for example, to validate its new transactions
106pub trait AccountInfoReader: AccountReader + BytecodeReader {}
107impl<T: AccountReader + BytecodeReader> AccountInfoReader for T {}
108
109/// Trait that provides the hashed state from various sources.
110#[auto_impl(&, Arc, Box)]
111pub trait HashedPostStateProvider {
112    /// Returns the [`HashedPostState`] of the provided [`BundleState`], materializing zero-valued
113    /// updates for parent storage of accounts that were destroyed but remain in the post-state.
114    ///
115    /// Providers backed by an exact parent-state view also materialize terminally destroyed
116    /// accounts with explicit zero-valued storage updates.
117    fn hashed_post_state(&self, bundle_state: &BundleState) -> ProviderResult<HashedPostState>;
118}
119
120/// Trait for reading bytecode associated with a given code hash.
121#[auto_impl(&, Arc, Box)]
122pub trait BytecodeReader {
123    /// Get account code by its hash
124    fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>>;
125}
126
127/// Light wrapper that returns `StateProvider` implementations that correspond to the given
128/// `BlockNumber`, the latest state, or the pending state.
129///
130/// This type differentiates states into `historical`, `latest` and `pending`, where the `latest`
131/// block determines what is historical or pending: `[historical..latest..pending]`.
132///
133/// The `latest` state represents the state after the most recent block has been committed to the
134/// database, `historical` states are states that have been committed to the database before the
135/// `latest` state, and `pending` states are states that have not yet been committed to the
136/// database which may or may not become the `latest` state, depending on consensus.
137///
138/// Note: the `pending` block is considered the block that extends the canonical chain but one and
139/// has the `latest` block as its parent.
140///
141/// All states are _inclusive_, meaning they include _all_ changes made (executed transactions)
142/// in their respective blocks. For example [`StateProviderFactory::history_by_block_number`] for
143/// block number `n` will return the state after block `n` was executed (transactions, withdrawals).
144/// In other words, all states point to the end of the state's respective block, which is equivalent
145/// to state at the beginning of the child block.
146///
147/// This affects tracing, or replaying blocks, which will need to be executed on top of the state of
148/// the parent block. For example, in order to trace block `n`, the state after block `n - 1` needs
149/// to be used, since block `n` was executed on its parent block's state.
150#[auto_impl(&, Box, Arc)]
151pub trait StateProviderFactory: BlockIdReader {
152    /// The node primitive types.
153    type Primitives: NodePrimitives;
154
155    /// Storage provider for latest block.
156    fn latest(&self) -> ProviderResult<StateProviderBox>;
157
158    /// Returns a state provider after applying `block` to `parent_hash`.
159    #[cfg(feature = "chain-state")]
160    fn state_with_block_appended(
161        &self,
162        parent_hash: BlockHash,
163        block: ExecutedBlock<Self::Primitives>,
164    ) -> ProviderResult<StateProviderBox>;
165
166    /// Returns a [`StateProvider`] indexed by the given [`BlockId`].
167    ///
168    /// Note: if a number or hash is provided this will __only__ look at historical(canonical)
169    /// state.
170    fn state_by_block_id(&self, block_id: BlockId) -> ProviderResult<StateProviderBox> {
171        match block_id {
172            BlockId::Number(block_number) => self.state_by_block_number_or_tag(block_number),
173            BlockId::Hash(block_hash) => self.history_by_block_hash(block_hash.into()),
174        }
175    }
176
177    /// Returns a [`StateProvider`] indexed by the given block number or tag.
178    ///
179    /// Note: if a number is provided this will only look at historical(canonical) state.
180    fn state_by_block_number_or_tag(
181        &self,
182        number_or_tag: BlockNumberOrTag,
183    ) -> ProviderResult<StateProviderBox>;
184
185    /// Returns a historical [`StateProvider`] indexed by the given historic block number.
186    ///
187    ///
188    /// Note: this only looks at historical blocks, not pending blocks.
189    fn history_by_block_number(&self, block: BlockNumber) -> ProviderResult<StateProviderBox>;
190
191    /// Returns a historical [`StateProvider`] indexed by the given block hash.
192    ///
193    /// Note: this only looks at historical blocks, not pending blocks.
194    fn history_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
195
196    /// Returns _any_ [`StateProvider`] with matching block hash.
197    ///
198    /// This will return a [`StateProvider`] for either a historical or pending block.
199    fn state_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
200
201    /// Storage provider for pending state.
202    ///
203    /// Represents the state at the block that extends the canonical chain by one.
204    /// If there's no `pending` block, then this is equal to [`StateProviderFactory::latest`]
205    fn pending(&self) -> ProviderResult<StateProviderBox>;
206
207    /// Storage provider for pending state for the given block hash.
208    ///
209    /// Represents the state at the block that extends the canonical chain.
210    ///
211    /// If the block couldn't be found, returns `None`.
212    fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>>;
213
214    /// Returns a pending [`StateProvider`] if it exists.
215    ///
216    /// This will return `None` if there's no pending state.
217    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>>;
218}