reth_rpc_eth_api/helpers/
state.rs1use 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_primitives_traits::SealedHeaderFor;
15use reth_rpc_convert::RpcConvert;
16use reth_rpc_eth_types::{
17 error::FromEvmError, EthApiError, PendingBlockEnv, RpcInvalidTransactionError,
18};
19use reth_storage_api::{
20 BlockIdReader, BlockNumReader, BlockReaderIdExt, StateProvider, StateProviderBox,
21 StateProviderFactory,
22};
23use reth_transaction_pool::TransactionPool;
24
25pub trait EthState: LoadState + SpawnBlocking {
27 fn max_proof_window(&self) -> u64;
29
30 fn transaction_count(
35 &self,
36 address: Address,
37 block_id: Option<BlockId>,
38 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
39 LoadState::transaction_count(self, address, block_id)
40 }
41
42 fn get_code(
44 &self,
45 address: Address,
46 block_id: Option<BlockId>,
47 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
48 LoadState::get_code(self, address, block_id)
49 }
50
51 fn balance(
53 &self,
54 address: Address,
55 block_id: Option<BlockId>,
56 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
57 self.spawn_blocking_io_fut(move |this| async move {
58 Ok(this
59 .state_at_block_id_or_latest(block_id)
60 .await?
61 .account_balance(&address)
62 .map_err(Self::Error::from_eth_err)?
63 .unwrap_or_default())
64 })
65 }
66
67 fn storage_at(
69 &self,
70 address: Address,
71 index: JsonStorageKey,
72 block_id: Option<BlockId>,
73 ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
74 self.spawn_blocking_io_fut(move |this| async move {
75 Ok(B256::new(
76 this.state_at_block_id_or_latest(block_id)
77 .await?
78 .storage(address, index.as_b256())
79 .map_err(Self::Error::from_eth_err)?
80 .unwrap_or_default()
81 .to_be_bytes(),
82 ))
83 })
84 }
85
86 fn get_proof(
88 &self,
89 address: Address,
90 keys: Vec<JsonStorageKey>,
91 block_id: Option<BlockId>,
92 ) -> Result<
93 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
94 Self::Error,
95 >
96 where
97 Self: EthApiSpec,
98 {
99 Ok(async move {
100 let _permit = self
101 .acquire_owned_tracing()
102 .await
103 .map_err(RethError::other)
104 .map_err(EthApiError::Internal)?;
105
106 let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
107 let block_id = block_id.unwrap_or_default();
108
109 let block_number = self
111 .provider()
112 .block_number_for_id(block_id)
113 .map_err(Self::Error::from_eth_err)?
114 .ok_or(EthApiError::HeaderNotFound(block_id))?;
115 let max_window = self.max_proof_window();
116 if chain_info.best_number.saturating_sub(block_number) > max_window {
117 return Err(EthApiError::ExceedsMaxProofWindow.into())
118 }
119
120 self.spawn_blocking_io_fut(move |this| async move {
121 let state = this.state_at_block_id(block_id).await?;
122 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
123 let proof = state
124 .proof(Default::default(), address, &storage_keys)
125 .map_err(Self::Error::from_eth_err)?;
126 Ok(proof.into_eip1186_response(keys))
127 })
128 .await
129 })
130 }
131
132 fn get_account(
134 &self,
135 address: Address,
136 block_id: BlockId,
137 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send {
138 self.spawn_blocking_io_fut(move |this| async move {
139 let state = this.state_at_block_id(block_id).await?;
140 let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
141 let Some(account) = account else { return Ok(None) };
142
143 let chain_info = this.provider().chain_info().map_err(Self::Error::from_eth_err)?;
145 let block_number = this
146 .provider()
147 .block_number_for_id(block_id)
148 .map_err(Self::Error::from_eth_err)?
149 .ok_or(EthApiError::HeaderNotFound(block_id))?;
150 let max_window = this.max_proof_window();
151 if chain_info.best_number.saturating_sub(block_number) > max_window {
152 return Err(EthApiError::ExceedsMaxProofWindow.into())
153 }
154
155 let balance = account.balance;
156 let nonce = account.nonce;
157 let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
158
159 let storage_root = state
162 .storage_root(address, Default::default())
163 .map_err(Self::Error::from_eth_err)?;
164
165 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
166 })
167 }
168
169 fn get_account_info(
171 &self,
172 address: Address,
173 block_id: BlockId,
174 ) -> impl Future<Output = Result<AccountInfo, Self::Error>> + Send {
175 self.spawn_blocking_io_fut(move |this| async move {
176 let state = this.state_at_block_id(block_id).await?;
177 let account = state
178 .basic_account(&address)
179 .map_err(Self::Error::from_eth_err)?
180 .unwrap_or_default();
181
182 let balance = account.balance;
183 let nonce = account.nonce;
184 let code = if account.get_bytecode_hash() == KECCAK_EMPTY {
185 Default::default()
186 } else {
187 state
188 .account_code(&address)
189 .map_err(Self::Error::from_eth_err)?
190 .unwrap_or_default()
191 .original_bytes()
192 };
193
194 Ok(AccountInfo { balance, nonce, code })
195 })
196 }
197}
198
199pub trait LoadState:
203 LoadPendingBlock
204 + EthApiTypes<
205 Error: FromEvmError<Self::Evm> + FromEthApiError,
206 RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
207 > + RpcNodeCoreExt
208{
209 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
211 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
212 }
213
214 fn state_at_block_id(
219 &self,
220 at: BlockId,
221 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
222 where
223 Self: SpawnBlocking,
224 {
225 async move {
226 if at.is_pending() &&
227 let Ok(Some(state)) = self.local_pending_state().await
228 {
229 return Ok(state)
230 }
231
232 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
233 }
234 }
235
236 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
238 self.provider().latest().map_err(Self::Error::from_eth_err)
239 }
240
241 fn state_at_block_id_or_latest(
245 &self,
246 block_id: Option<BlockId>,
247 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
248 where
249 Self: SpawnBlocking,
250 {
251 async move {
252 if let Some(block_id) = block_id {
253 self.state_at_block_id(block_id).await
254 } else {
255 Ok(self.latest_state()?)
256 }
257 }
258 }
259
260 fn evm_env_for_header(
262 &self,
263 header: &SealedHeaderFor<Self::Primitives>,
264 ) -> Result<EvmEnvFor<Self::Evm>, Self::Error> {
265 self.evm_config()
266 .evm_env(header)
267 .map_err(RethError::other)
268 .map_err(Self::Error::from_eth_err)
269 }
270
271 fn evm_env_at(
278 &self,
279 at: BlockId,
280 ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
281 where
282 Self: SpawnBlocking,
283 {
284 async move {
285 if at.is_pending() {
286 let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
287 Ok((evm_env, origin.state_block_id()))
288 } else {
289 let header = RpcNodeCore::provider(self)
293 .sealed_header_by_id(at)
294 .map_err(Self::Error::from_eth_err)?
295 .ok_or_else(|| EthApiError::HeaderNotFound(at))?;
296 let evm_env = self.evm_env_for_header(&header)?;
297
298 Ok((evm_env, header.hash().into()))
299 }
300 }
301 }
302
303 fn next_available_nonce(
307 &self,
308 address: Address,
309 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
310 where
311 Self: SpawnBlocking,
312 {
313 self.spawn_blocking_io(move |this| {
314 let mut next_nonce = this
316 .latest_state()?
317 .account_nonce(&address)
318 .map_err(Self::Error::from_eth_err)?
319 .unwrap_or_default();
320
321 if let Some(highest_tx) =
323 this.pool().get_highest_consecutive_transaction_by_sender(address, next_nonce)
324 {
325 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
327 Self::Error::from(EthApiError::InvalidTransaction(
328 RpcInvalidTransactionError::NonceMaxValue,
329 ))
330 })?;
331 }
332
333 Ok(next_nonce)
334 })
335 }
336
337 fn transaction_count(
342 &self,
343 address: Address,
344 block_id: Option<BlockId>,
345 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
346 where
347 Self: SpawnBlocking,
348 {
349 self.spawn_blocking_io_fut(move |this| async move {
350 let on_chain_account_nonce = this
352 .state_at_block_id_or_latest(block_id)
353 .await?
354 .account_nonce(&address)
355 .map_err(Self::Error::from_eth_err)?
356 .unwrap_or_default();
357
358 if block_id == Some(BlockId::pending()) {
359 if let Some(highest_pool_tx) = this
361 .pool()
362 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
363 {
364 {
365 let next_tx_nonce =
368 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
369 Self::Error::from(EthApiError::InvalidTransaction(
370 RpcInvalidTransactionError::NonceMaxValue,
371 ))
372 })?;
373
374 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
376
377 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
378 return Ok(U256::from(tx_count));
379 }
380 }
381 }
382 Ok(U256::from(on_chain_account_nonce))
383 })
384 }
385
386 fn get_code(
388 &self,
389 address: Address,
390 block_id: Option<BlockId>,
391 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
392 where
393 Self: SpawnBlocking,
394 {
395 self.spawn_blocking_io_fut(move |this| async move {
396 Ok(this
397 .state_at_block_id_or_latest(block_id)
398 .await?
399 .account_code(&address)
400 .map_err(Self::Error::from_eth_err)?
401 .unwrap_or_default()
402 .original_bytes())
403 })
404 }
405}