reth_rpc_eth_api/helpers/
state.rs
1use super::{EthApiSpec, LoadPendingBlock, SpawnBlocking};
4use crate::{EthApiTypes, FromEthApiError, RpcNodeCore, RpcNodeCoreExt};
5use alloy_consensus::constants::KECCAK_EMPTY;
6use alloy_eips::BlockId;
7use alloy_primitives::{Address, Bytes, B256, U256};
8use alloy_rpc_types_eth::{Account, EIP1186AccountProofResponse};
9use alloy_serde::JsonStorageKey;
10use futures::Future;
11use reth_chainspec::{EthChainSpec, EthereumHardforks};
12use reth_errors::RethError;
13use reth_evm::{ConfigureEvm, EvmEnvFor};
14use reth_provider::{
15 BlockIdReader, BlockNumReader, ChainSpecProvider, StateProvider, StateProviderBox,
16 StateProviderFactory,
17};
18use reth_rpc_eth_types::{EthApiError, PendingBlockEnv, RpcInvalidTransactionError};
19use reth_transaction_pool::TransactionPool;
20
21pub trait EthState: LoadState + SpawnBlocking {
23 fn max_proof_window(&self) -> u64;
25
26 fn transaction_count(
31 &self,
32 address: Address,
33 block_id: Option<BlockId>,
34 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
35 LoadState::transaction_count(self, address, block_id)
36 }
37
38 fn get_code(
40 &self,
41 address: Address,
42 block_id: Option<BlockId>,
43 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
44 LoadState::get_code(self, address, block_id)
45 }
46
47 fn balance(
49 &self,
50 address: Address,
51 block_id: Option<BlockId>,
52 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
53 self.spawn_blocking_io(move |this| {
54 Ok(this
55 .state_at_block_id_or_latest(block_id)?
56 .account_balance(&address)
57 .map_err(Self::Error::from_eth_err)?
58 .unwrap_or_default())
59 })
60 }
61
62 fn storage_at(
64 &self,
65 address: Address,
66 index: JsonStorageKey,
67 block_id: Option<BlockId>,
68 ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
69 self.spawn_blocking_io(move |this| {
70 Ok(B256::new(
71 this.state_at_block_id_or_latest(block_id)?
72 .storage(address, index.as_b256())
73 .map_err(Self::Error::from_eth_err)?
74 .unwrap_or_default()
75 .to_be_bytes(),
76 ))
77 })
78 }
79
80 fn get_proof(
82 &self,
83 address: Address,
84 keys: Vec<JsonStorageKey>,
85 block_id: Option<BlockId>,
86 ) -> Result<
87 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
88 Self::Error,
89 >
90 where
91 Self: EthApiSpec,
92 {
93 Ok(async move {
94 let _permit = self
95 .acquire_owned()
96 .await
97 .map_err(RethError::other)
98 .map_err(EthApiError::Internal)?;
99
100 let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
101 let block_id = block_id.unwrap_or_default();
102
103 let block_number = self
105 .provider()
106 .block_number_for_id(block_id)
107 .map_err(Self::Error::from_eth_err)?
108 .ok_or(EthApiError::HeaderNotFound(block_id))?;
109 let max_window = self.max_proof_window();
110 if chain_info.best_number.saturating_sub(block_number) > max_window {
111 return Err(EthApiError::ExceedsMaxProofWindow.into())
112 }
113
114 self.spawn_blocking_io(move |this| {
115 let state = this.state_at_block_id(block_id)?;
116 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
117 let proof = state
118 .proof(Default::default(), address, &storage_keys)
119 .map_err(Self::Error::from_eth_err)?;
120 Ok(proof.into_eip1186_response(keys))
121 })
122 .await
123 })
124 }
125
126 fn get_account(
128 &self,
129 address: Address,
130 block_id: BlockId,
131 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send {
132 self.spawn_blocking_io(move |this| {
133 let state = this.state_at_block_id(block_id)?;
134 let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
135 let Some(account) = account else { return Ok(None) };
136
137 let chain_info = this.provider().chain_info().map_err(Self::Error::from_eth_err)?;
139 let block_number = this
140 .provider()
141 .block_number_for_id(block_id)
142 .map_err(Self::Error::from_eth_err)?
143 .ok_or(EthApiError::HeaderNotFound(block_id))?;
144 let max_window = this.max_proof_window();
145 if chain_info.best_number.saturating_sub(block_number) > max_window {
146 return Err(EthApiError::ExceedsMaxProofWindow.into())
147 }
148
149 let balance = account.balance;
150 let nonce = account.nonce;
151 let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
152
153 let storage_root = state
156 .storage_root(address, Default::default())
157 .map_err(Self::Error::from_eth_err)?;
158
159 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
160 })
161 }
162}
163
164pub trait LoadState:
168 EthApiTypes
169 + RpcNodeCoreExt<
170 Provider: StateProviderFactory
171 + ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>,
172 Pool: TransactionPool,
173 >
174{
175 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
177 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
178 }
179
180 fn state_at_block_id(&self, at: BlockId) -> Result<StateProviderBox, Self::Error> {
185 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
186 }
187
188 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
190 self.provider().latest().map_err(Self::Error::from_eth_err)
191 }
192
193 fn state_at_block_id_or_latest(
197 &self,
198 block_id: Option<BlockId>,
199 ) -> Result<StateProviderBox, Self::Error> {
200 if let Some(block_id) = block_id {
201 self.state_at_block_id(block_id)
202 } else {
203 Ok(self.latest_state()?)
204 }
205 }
206
207 fn evm_env_at(
214 &self,
215 at: BlockId,
216 ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
217 where
218 Self: LoadPendingBlock + SpawnBlocking,
219 {
220 async move {
221 if at.is_pending() {
222 let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
223 Ok((evm_env, origin.state_block_id()))
224 } else {
225 let block_hash = RpcNodeCore::provider(self)
227 .block_hash_for_id(at)
228 .map_err(Self::Error::from_eth_err)?
229 .ok_or(EthApiError::HeaderNotFound(at))?;
230
231 let header =
232 self.cache().get_header(block_hash).await.map_err(Self::Error::from_eth_err)?;
233 let evm_env = self.evm_config().evm_env(&header);
234
235 Ok((evm_env, block_hash.into()))
236 }
237 }
238 }
239
240 fn next_available_nonce(
244 &self,
245 address: Address,
246 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
247 where
248 Self: SpawnBlocking,
249 {
250 self.spawn_blocking_io(move |this| {
251 let on_chain_account_nonce = this
253 .latest_state()?
254 .account_nonce(&address)
255 .map_err(Self::Error::from_eth_err)?
256 .unwrap_or_default();
257
258 let mut next_nonce = on_chain_account_nonce;
259 if let Some(highest_tx) = this
261 .pool()
262 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
263 {
264 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
266 Self::Error::from(EthApiError::InvalidTransaction(
267 RpcInvalidTransactionError::NonceMaxValue,
268 ))
269 })?;
270 }
271
272 Ok(next_nonce)
273 })
274 }
275
276 fn transaction_count(
281 &self,
282 address: Address,
283 block_id: Option<BlockId>,
284 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
285 where
286 Self: SpawnBlocking,
287 {
288 self.spawn_blocking_io(move |this| {
289 let on_chain_account_nonce = this
291 .state_at_block_id_or_latest(block_id)?
292 .account_nonce(&address)
293 .map_err(Self::Error::from_eth_err)?
294 .unwrap_or_default();
295
296 if block_id == Some(BlockId::pending()) {
297 if let Some(highest_pool_tx) =
299 this.pool().get_highest_transaction_by_sender(address)
300 {
301 {
302 let next_tx_nonce =
305 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
306 Self::Error::from(EthApiError::InvalidTransaction(
307 RpcInvalidTransactionError::NonceMaxValue,
308 ))
309 })?;
310
311 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
313
314 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
315 return Ok(U256::from(tx_count));
316 }
317 }
318 }
319 Ok(U256::from(on_chain_account_nonce))
320 })
321 }
322
323 fn get_code(
325 &self,
326 address: Address,
327 block_id: Option<BlockId>,
328 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
329 where
330 Self: SpawnBlocking,
331 {
332 self.spawn_blocking_io(move |this| {
333 Ok(this
334 .state_at_block_id_or_latest(block_id)?
335 .account_code(&address)
336 .map_err(Self::Error::from_eth_err)?
337 .unwrap_or_default()
338 .original_bytes())
339 })
340 }
341}