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_primitives_traits::Bytecode;
11use reth_storage_errors::provider::ProviderResult;
12use reth_trie_common::HashedPostState;
13use revm_database::BundleState;
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<StorageValue>>;
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 [`reth_trie_db::StateCommitment`]
89/// type.
90#[cfg(feature = "db-api")]
91pub trait StateCommitmentProvider: Send + Sync {
92 /// The [`reth_trie_db::StateCommitment`] type that can be used to perform state commitment
93 /// operations.
94 type StateCommitment: reth_trie_db::StateCommitment;
95}
96
97/// Trait that provides the hashed state from various sources.
98#[auto_impl(&, Arc, Box)]
99pub trait HashedPostStateProvider: Send + Sync {
100 /// Returns the `HashedPostState` of the provided [`BundleState`].
101 fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState;
102}
103
104/// Trait implemented for database providers that can be converted into a historical state provider.
105pub trait TryIntoHistoricalStateProvider {
106 /// Returns a historical [`StateProvider`] indexed by the given historic block number.
107 fn try_into_history_at_block(
108 self,
109 block_number: BlockNumber,
110 ) -> ProviderResult<StateProviderBox>;
111}
112
113/// Light wrapper that returns `StateProvider` implementations that correspond to the given
114/// `BlockNumber`, the latest state, or the pending state.
115///
116/// This type differentiates states into `historical`, `latest` and `pending`, where the `latest`
117/// block determines what is historical or pending: `[historical..latest..pending]`.
118///
119/// The `latest` state represents the state after the most recent block has been committed to the
120/// database, `historical` states are states that have been committed to the database before the
121/// `latest` state, and `pending` states are states that have not yet been committed to the
122/// database which may or may not become the `latest` state, depending on consensus.
123///
124/// Note: the `pending` block is considered the block that extends the canonical chain but one and
125/// has the `latest` block as its parent.
126///
127/// All states are _inclusive_, meaning they include _all_ all changes made (executed transactions)
128/// in their respective blocks. For example [StateProviderFactory::history_by_block_number] for
129/// block number `n` will return the state after block `n` was executed (transactions, withdrawals).
130/// In other words, all states point to the end of the state's respective block, which is equivalent
131/// to state at the beginning of the child block.
132///
133/// This affects tracing, or replaying blocks, which will need to be executed on top of the state of
134/// the parent block. For example, in order to trace block `n`, the state after block `n - 1` needs
135/// to be used, since block `n` was executed on its parent block's state.
136#[auto_impl(&, Arc, Box)]
137pub trait StateProviderFactory: BlockIdReader + Send + Sync {
138 /// Storage provider for latest block.
139 fn latest(&self) -> ProviderResult<StateProviderBox>;
140
141 /// Returns a [`StateProvider`] indexed by the given [`BlockId`].
142 ///
143 /// Note: if a number or hash is provided this will __only__ look at historical(canonical)
144 /// state.
145 fn state_by_block_id(&self, block_id: BlockId) -> ProviderResult<StateProviderBox> {
146 match block_id {
147 BlockId::Number(block_number) => self.state_by_block_number_or_tag(block_number),
148 BlockId::Hash(block_hash) => self.history_by_block_hash(block_hash.into()),
149 }
150 }
151
152 /// Returns a [StateProvider] indexed by the given block number or tag.
153 ///
154 /// Note: if a number is provided this will only look at historical(canonical) state.
155 fn state_by_block_number_or_tag(
156 &self,
157 number_or_tag: BlockNumberOrTag,
158 ) -> ProviderResult<StateProviderBox>;
159
160 /// Returns a historical [StateProvider] indexed by the given historic block number.
161 ///
162 ///
163 /// Note: this only looks at historical blocks, not pending blocks.
164 fn history_by_block_number(&self, block: BlockNumber) -> ProviderResult<StateProviderBox>;
165
166 /// Returns a historical [StateProvider] indexed by the given block hash.
167 ///
168 /// Note: this only looks at historical blocks, not pending blocks.
169 fn history_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
170
171 /// Returns _any_ [StateProvider] with matching block hash.
172 ///
173 /// This will return a [StateProvider] for either a historical or pending block.
174 fn state_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
175
176 /// Storage provider for pending state.
177 ///
178 /// Represents the state at the block that extends the canonical chain by one.
179 /// If there's no `pending` block, then this is equal to [StateProviderFactory::latest]
180 fn pending(&self) -> ProviderResult<StateProviderBox>;
181
182 /// Storage provider for pending state for the given block hash.
183 ///
184 /// Represents the state at the block that extends the canonical chain.
185 ///
186 /// If the block couldn't be found, returns `None`.
187 fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>>;
188}