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