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