reth_rpc_eth_api/helpers/
state.rs

1//! Loads a pending block from database. Helper trait for `eth_` block, transaction, call and trace
2//! RPC methods.
3
4use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking};
5use crate::{EthApiTypes, FromEthApiError, RpcNodeCore, RpcNodeCoreExt};
6use alloy_consensus::constants::KECCAK_EMPTY;
7use alloy_eips::BlockId;
8use alloy_primitives::{Address, Bytes, B256, U256};
9use alloy_rpc_types_eth::{Account, AccountInfo, EIP1186AccountProofResponse};
10use alloy_serde::JsonStorageKey;
11use futures::Future;
12use reth_errors::RethError;
13use reth_evm::{ConfigureEvm, EvmEnvFor};
14use reth_rpc_convert::RpcConvert;
15use reth_rpc_eth_types::{
16    error::FromEvmError, EthApiError, PendingBlockEnv, RpcInvalidTransactionError,
17};
18use reth_storage_api::{
19    BlockIdReader, BlockNumReader, StateProvider, StateProviderBox, StateProviderFactory,
20};
21use reth_transaction_pool::TransactionPool;
22
23/// Helper methods for `eth_` methods relating to state (accounts).
24pub trait EthState: LoadState + SpawnBlocking {
25    /// Returns the maximum number of blocks into the past for generating state proofs.
26    fn max_proof_window(&self) -> u64;
27
28    /// Returns the number of transactions sent from an address at the given block identifier.
29    ///
30    /// If this is [`BlockNumberOrTag::Pending`](alloy_eips::BlockNumberOrTag) then this will
31    /// look up the highest transaction in pool and return the next nonce (highest + 1).
32    fn transaction_count(
33        &self,
34        address: Address,
35        block_id: Option<BlockId>,
36    ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
37        LoadState::transaction_count(self, address, block_id)
38    }
39
40    /// Returns code of given account, at given blocknumber.
41    fn get_code(
42        &self,
43        address: Address,
44        block_id: Option<BlockId>,
45    ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
46        LoadState::get_code(self, address, block_id)
47    }
48
49    /// Returns balance of given account, at given blocknumber.
50    fn balance(
51        &self,
52        address: Address,
53        block_id: Option<BlockId>,
54    ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
55        self.spawn_blocking_io_fut(move |this| async move {
56            Ok(this
57                .state_at_block_id_or_latest(block_id)
58                .await?
59                .account_balance(&address)
60                .map_err(Self::Error::from_eth_err)?
61                .unwrap_or_default())
62        })
63    }
64
65    /// Returns values stored of given account, at given blocknumber.
66    fn storage_at(
67        &self,
68        address: Address,
69        index: JsonStorageKey,
70        block_id: Option<BlockId>,
71    ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
72        self.spawn_blocking_io_fut(move |this| async move {
73            Ok(B256::new(
74                this.state_at_block_id_or_latest(block_id)
75                    .await?
76                    .storage(address, index.as_b256())
77                    .map_err(Self::Error::from_eth_err)?
78                    .unwrap_or_default()
79                    .to_be_bytes(),
80            ))
81        })
82    }
83
84    /// Returns values stored of given account, with Merkle-proof, at given blocknumber.
85    fn get_proof(
86        &self,
87        address: Address,
88        keys: Vec<JsonStorageKey>,
89        block_id: Option<BlockId>,
90    ) -> Result<
91        impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
92        Self::Error,
93    >
94    where
95        Self: EthApiSpec,
96    {
97        Ok(async move {
98            let _permit = self
99                .acquire_owned()
100                .await
101                .map_err(RethError::other)
102                .map_err(EthApiError::Internal)?;
103
104            let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
105            let block_id = block_id.unwrap_or_default();
106
107            // Check whether the distance to the block exceeds the maximum configured window.
108            let block_number = self
109                .provider()
110                .block_number_for_id(block_id)
111                .map_err(Self::Error::from_eth_err)?
112                .ok_or(EthApiError::HeaderNotFound(block_id))?;
113            let max_window = self.max_proof_window();
114            if chain_info.best_number.saturating_sub(block_number) > max_window {
115                return Err(EthApiError::ExceedsMaxProofWindow.into())
116            }
117
118            self.spawn_blocking_io_fut(move |this| async move {
119                let state = this.state_at_block_id(block_id).await?;
120                let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
121                let proof = state
122                    .proof(Default::default(), address, &storage_keys)
123                    .map_err(Self::Error::from_eth_err)?;
124                Ok(proof.into_eip1186_response(keys))
125            })
126            .await
127        })
128    }
129
130    /// Returns the account at the given address for the provided block identifier.
131    fn get_account(
132        &self,
133        address: Address,
134        block_id: BlockId,
135    ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send {
136        self.spawn_blocking_io_fut(move |this| async move {
137            let state = this.state_at_block_id(block_id).await?;
138            let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
139            let Some(account) = account else { return Ok(None) };
140
141            // Check whether the distance to the block exceeds the maximum configured proof window.
142            let chain_info = this.provider().chain_info().map_err(Self::Error::from_eth_err)?;
143            let block_number = this
144                .provider()
145                .block_number_for_id(block_id)
146                .map_err(Self::Error::from_eth_err)?
147                .ok_or(EthApiError::HeaderNotFound(block_id))?;
148            let max_window = this.max_proof_window();
149            if chain_info.best_number.saturating_sub(block_number) > max_window {
150                return Err(EthApiError::ExceedsMaxProofWindow.into())
151            }
152
153            let balance = account.balance;
154            let nonce = account.nonce;
155            let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
156
157            // Provide a default `HashedStorage` value in order to
158            // get the storage root hash of the current state.
159            let storage_root = state
160                .storage_root(address, Default::default())
161                .map_err(Self::Error::from_eth_err)?;
162
163            Ok(Some(Account { balance, nonce, code_hash, storage_root }))
164        })
165    }
166
167    /// Retrieves the account's balance, nonce, and code for a given address.
168    fn get_account_info(
169        &self,
170        address: Address,
171        block_id: BlockId,
172    ) -> impl Future<Output = Result<AccountInfo, Self::Error>> + Send {
173        self.spawn_blocking_io_fut(move |this| async move {
174            let state = this.state_at_block_id(block_id).await?;
175            let account = state
176                .basic_account(&address)
177                .map_err(Self::Error::from_eth_err)?
178                .unwrap_or_default();
179
180            let balance = account.balance;
181            let nonce = account.nonce;
182            let code = if account.get_bytecode_hash() == KECCAK_EMPTY {
183                Default::default()
184            } else {
185                state
186                    .account_code(&address)
187                    .map_err(Self::Error::from_eth_err)?
188                    .unwrap_or_default()
189                    .original_bytes()
190            };
191
192            Ok(AccountInfo { balance, nonce, code })
193        })
194    }
195}
196
197/// Loads state from database.
198///
199/// Behaviour shared by several `eth_` RPC methods, not exclusive to `eth_` state RPC methods.
200pub trait LoadState:
201    LoadPendingBlock
202    + EthApiTypes<
203        Error: FromEvmError<Self::Evm> + FromEthApiError,
204        RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
205    > + RpcNodeCoreExt
206{
207    /// Returns the state at the given block number
208    fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
209        self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
210    }
211
212    /// Returns the state at the given [`BlockId`] enum.
213    ///
214    /// Note: if not [`BlockNumberOrTag::Pending`](alloy_eips::BlockNumberOrTag) then this
215    /// will only return canonical state. See also <https://github.com/paradigmxyz/reth/issues/4515>
216    fn state_at_block_id(
217        &self,
218        at: BlockId,
219    ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
220    where
221        Self: SpawnBlocking,
222    {
223        async move {
224            if at.is_pending() {
225                if let Ok(Some(state)) = self.local_pending_state().await {
226                    return Ok(state)
227                }
228            }
229
230            self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
231        }
232    }
233
234    /// Returns the _latest_ state
235    fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
236        self.provider().latest().map_err(Self::Error::from_eth_err)
237    }
238
239    /// Returns the state at the given [`BlockId`] enum or the latest.
240    ///
241    /// Convenience function to interprets `None` as `BlockId::Number(BlockNumberOrTag::Latest)`
242    fn state_at_block_id_or_latest(
243        &self,
244        block_id: Option<BlockId>,
245    ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
246    where
247        Self: SpawnBlocking,
248    {
249        async move {
250            if let Some(block_id) = block_id {
251                self.state_at_block_id(block_id).await
252            } else {
253                Ok(self.latest_state()?)
254            }
255        }
256    }
257
258    /// Returns the revm evm env for the requested [`BlockId`]
259    ///
260    /// If the [`BlockId`] this will return the [`BlockId`] of the block the env was configured
261    /// for.
262    /// If the [`BlockId`] is pending, this will return the "Pending" tag, otherwise this returns
263    /// the hash of the exact block.
264    fn evm_env_at(
265        &self,
266        at: BlockId,
267    ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
268    where
269        Self: SpawnBlocking,
270    {
271        async move {
272            if at.is_pending() {
273                let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
274                Ok((evm_env, origin.state_block_id()))
275            } else {
276                // Use cached values if there is no pending block
277                let block_hash = RpcNodeCore::provider(self)
278                    .block_hash_for_id(at)
279                    .map_err(Self::Error::from_eth_err)?
280                    .ok_or(EthApiError::HeaderNotFound(at))?;
281
282                let header =
283                    self.cache().get_header(block_hash).await.map_err(Self::Error::from_eth_err)?;
284                let evm_env = self.evm_config().evm_env(&header);
285
286                Ok((evm_env, block_hash.into()))
287            }
288        }
289    }
290
291    /// Returns the next available nonce without gaps for the given address
292    /// Next available nonce is either the on chain nonce of the account or the highest consecutive
293    /// nonce in the pool + 1
294    fn next_available_nonce(
295        &self,
296        address: Address,
297    ) -> impl Future<Output = Result<u64, Self::Error>> + Send
298    where
299        Self: SpawnBlocking,
300    {
301        self.spawn_blocking_io(move |this| {
302            // first fetch the on chain nonce of the account
303            let mut next_nonce = this
304                .latest_state()?
305                .account_nonce(&address)
306                .map_err(Self::Error::from_eth_err)?
307                .unwrap_or_default();
308
309            // Retrieve the highest consecutive transaction for the sender from the transaction pool
310            if let Some(highest_tx) =
311                this.pool().get_highest_consecutive_transaction_by_sender(address, next_nonce)
312            {
313                // Return the nonce of the highest consecutive transaction + 1
314                next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
315                    Self::Error::from(EthApiError::InvalidTransaction(
316                        RpcInvalidTransactionError::NonceMaxValue,
317                    ))
318                })?;
319            }
320
321            Ok(next_nonce)
322        })
323    }
324
325    /// Returns the number of transactions sent from an address at the given block identifier.
326    ///
327    /// If this is [`BlockNumberOrTag::Pending`](alloy_eips::BlockNumberOrTag) then this will
328    /// look up the highest transaction in pool and return the next nonce (highest + 1).
329    fn transaction_count(
330        &self,
331        address: Address,
332        block_id: Option<BlockId>,
333    ) -> impl Future<Output = Result<U256, Self::Error>> + Send
334    where
335        Self: SpawnBlocking,
336    {
337        self.spawn_blocking_io_fut(move |this| async move {
338            // first fetch the on chain nonce of the account
339            let on_chain_account_nonce = this
340                .state_at_block_id_or_latest(block_id)
341                .await?
342                .account_nonce(&address)
343                .map_err(Self::Error::from_eth_err)?
344                .unwrap_or_default();
345
346            if block_id == Some(BlockId::pending()) {
347                // for pending tag we need to find the highest nonce of txn in the pending state.
348                if let Some(highest_pool_tx) = this
349                    .pool()
350                    .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
351                {
352                    {
353                        // and the corresponding txcount is nonce + 1 of the highest tx in the pool
354                        // (on chain nonce is increased after tx)
355                        let next_tx_nonce =
356                            highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
357                                Self::Error::from(EthApiError::InvalidTransaction(
358                                    RpcInvalidTransactionError::NonceMaxValue,
359                                ))
360                            })?;
361
362                        // guard against drifts in the pool
363                        let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
364
365                        let tx_count = on_chain_account_nonce.max(next_tx_nonce);
366                        return Ok(U256::from(tx_count));
367                    }
368                }
369            }
370            Ok(U256::from(on_chain_account_nonce))
371        })
372    }
373
374    /// Returns code of given account, at the given identifier.
375    fn get_code(
376        &self,
377        address: Address,
378        block_id: Option<BlockId>,
379    ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
380    where
381        Self: SpawnBlocking,
382    {
383        self.spawn_blocking_io_fut(move |this| async move {
384            Ok(this
385                .state_at_block_id_or_latest(block_id)
386                .await?
387                .account_code(&address)
388                .map_err(Self::Error::from_eth_err)?
389                .unwrap_or_default()
390                .original_bytes())
391        })
392    }
393}