reth_rpc_eth_api/helpers/
state.rs1use 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, AccountInfo, EIP1186AccountProofResponse};
9use alloy_serde::JsonStorageKey;
10use futures::Future;
11use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
12use reth_errors::RethError;
13use reth_evm::{ConfigureEvm, EvmEnvFor};
14use reth_rpc_eth_types::{EthApiError, PendingBlockEnv, RpcInvalidTransactionError};
15use reth_storage_api::{
16 BlockIdReader, BlockNumReader, StateProvider, StateProviderBox, StateProviderFactory,
17};
18use reth_transaction_pool::TransactionPool;
19
20pub trait EthState: LoadState + SpawnBlocking {
22 fn max_proof_window(&self) -> u64;
24
25 fn transaction_count(
30 &self,
31 address: Address,
32 block_id: Option<BlockId>,
33 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
34 LoadState::transaction_count(self, address, block_id)
35 }
36
37 fn get_code(
39 &self,
40 address: Address,
41 block_id: Option<BlockId>,
42 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
43 LoadState::get_code(self, address, block_id)
44 }
45
46 fn balance(
48 &self,
49 address: Address,
50 block_id: Option<BlockId>,
51 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
52 self.spawn_blocking_io(move |this| {
53 Ok(this
54 .state_at_block_id_or_latest(block_id)?
55 .account_balance(&address)
56 .map_err(Self::Error::from_eth_err)?
57 .unwrap_or_default())
58 })
59 }
60
61 fn storage_at(
63 &self,
64 address: Address,
65 index: JsonStorageKey,
66 block_id: Option<BlockId>,
67 ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
68 self.spawn_blocking_io(move |this| {
69 let storage_value = this
70 .state_at_block_id_or_latest(block_id)?
71 .storage(address, index.as_b256())
72 .map_err(Self::Error::from_eth_err)?
73 .unwrap_or_default();
74 match storage_value.is_public() {
75 true => Ok(B256::new(storage_value.value.to_be_bytes())),
76 false => Ok(B256::ZERO),
77 }
78 })
79 }
80
81 fn get_proof(
83 &self,
84 address: Address,
85 keys: Vec<JsonStorageKey>,
86 block_id: Option<BlockId>,
87 ) -> Result<
88 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
89 Self::Error,
90 >
91 where
92 Self: EthApiSpec,
93 {
94 Ok(async move {
95 let _permit = self
96 .acquire_owned()
97 .await
98 .map_err(RethError::other)
99 .map_err(EthApiError::Internal)?;
100
101 let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
102 let block_id = block_id.unwrap_or_default();
103
104 let block_number = self
106 .provider()
107 .block_number_for_id(block_id)
108 .map_err(Self::Error::from_eth_err)?
109 .ok_or(EthApiError::HeaderNotFound(block_id))?;
110 let max_window = self.max_proof_window();
111 if chain_info.best_number.saturating_sub(block_number) > max_window {
112 return Err(EthApiError::ExceedsMaxProofWindow.into())
113 }
114
115 self.spawn_blocking_io(move |this| {
116 let state = this.state_at_block_id(block_id)?;
117 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
118 let proof = state
119 .proof(Default::default(), address, &storage_keys)
120 .map_err(Self::Error::from_eth_err)?;
121 Ok(proof.into_eip1186_response(keys))
122 })
123 .await
124 })
125 }
126
127 fn get_account(
129 &self,
130 address: Address,
131 block_id: BlockId,
132 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send {
133 self.spawn_blocking_io(move |this| {
134 let state = this.state_at_block_id(block_id)?;
135 let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
136 let Some(account) = account else { return Ok(None) };
137
138 let chain_info = this.provider().chain_info().map_err(Self::Error::from_eth_err)?;
140 let block_number = this
141 .provider()
142 .block_number_for_id(block_id)
143 .map_err(Self::Error::from_eth_err)?
144 .ok_or(EthApiError::HeaderNotFound(block_id))?;
145 let max_window = this.max_proof_window();
146 if chain_info.best_number.saturating_sub(block_number) > max_window {
147 return Err(EthApiError::ExceedsMaxProofWindow.into())
148 }
149
150 let balance = account.balance;
151 let nonce = account.nonce;
152 let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
153
154 let storage_root = state
157 .storage_root(address, Default::default())
158 .map_err(Self::Error::from_eth_err)?;
159
160 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
161 })
162 }
163
164 fn get_account_info(
166 &self,
167 address: Address,
168 block_id: BlockId,
169 ) -> impl Future<Output = Result<AccountInfo, Self::Error>> + Send {
170 self.spawn_blocking_io(move |this| {
171 let state = this.state_at_block_id(block_id)?;
172 let account = state
173 .basic_account(&address)
174 .map_err(Self::Error::from_eth_err)?
175 .unwrap_or_default();
176
177 let balance = account.balance;
178 let nonce = account.nonce;
179 let code = if account.get_bytecode_hash() == KECCAK_EMPTY {
180 Default::default()
181 } else {
182 state
183 .account_code(&address)
184 .map_err(Self::Error::from_eth_err)?
185 .unwrap_or_default()
186 .original_bytes()
187 };
188
189 Ok(AccountInfo { balance, nonce, code })
190 })
191 }
192}
193
194pub trait LoadState:
198 EthApiTypes
199 + RpcNodeCoreExt<
200 Provider: StateProviderFactory
201 + ChainSpecProvider<ChainSpec: EthChainSpec + EthereumHardforks>,
202 Pool: TransactionPool,
203 >
204{
205 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
207 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
208 }
209
210 fn state_at_block_id(&self, at: BlockId) -> Result<StateProviderBox, Self::Error> {
215 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
216 }
217
218 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
220 self.provider().latest().map_err(Self::Error::from_eth_err)
221 }
222
223 fn state_at_block_id_or_latest(
227 &self,
228 block_id: Option<BlockId>,
229 ) -> Result<StateProviderBox, Self::Error> {
230 if let Some(block_id) = block_id {
231 self.state_at_block_id(block_id)
232 } else {
233 Ok(self.latest_state()?)
234 }
235 }
236
237 fn evm_env_at(
244 &self,
245 at: BlockId,
246 ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
247 where
248 Self: LoadPendingBlock + SpawnBlocking,
249 {
250 async move {
251 if at.is_pending() {
252 let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
253 Ok((evm_env, origin.state_block_id()))
254 } else {
255 let block_hash = RpcNodeCore::provider(self)
257 .block_hash_for_id(at)
258 .map_err(Self::Error::from_eth_err)?
259 .ok_or(EthApiError::HeaderNotFound(at))?;
260
261 let header =
262 self.cache().get_header(block_hash).await.map_err(Self::Error::from_eth_err)?;
263 let evm_env = self.evm_config().evm_env(&header);
264
265 Ok((evm_env, block_hash.into()))
266 }
267 }
268 }
269
270 fn next_available_nonce(
274 &self,
275 address: Address,
276 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
277 where
278 Self: SpawnBlocking,
279 {
280 self.spawn_blocking_io(move |this| {
281 let on_chain_account_nonce = this
283 .latest_state()?
284 .account_nonce(&address)
285 .map_err(Self::Error::from_eth_err)?
286 .unwrap_or_default();
287
288 let mut next_nonce = on_chain_account_nonce;
289 if let Some(highest_tx) = this
291 .pool()
292 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
293 {
294 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
296 Self::Error::from(EthApiError::InvalidTransaction(
297 RpcInvalidTransactionError::NonceMaxValue,
298 ))
299 })?;
300 }
301
302 Ok(next_nonce)
303 })
304 }
305
306 fn transaction_count(
311 &self,
312 address: Address,
313 block_id: Option<BlockId>,
314 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
315 where
316 Self: SpawnBlocking,
317 {
318 self.spawn_blocking_io(move |this| {
319 let on_chain_account_nonce = this
321 .state_at_block_id_or_latest(block_id)?
322 .account_nonce(&address)
323 .map_err(Self::Error::from_eth_err)?
324 .unwrap_or_default();
325
326 if block_id == Some(BlockId::pending()) {
327 if let Some(highest_pool_tx) = this
329 .pool()
330 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
331 {
332 {
333 let next_tx_nonce =
336 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
337 Self::Error::from(EthApiError::InvalidTransaction(
338 RpcInvalidTransactionError::NonceMaxValue,
339 ))
340 })?;
341
342 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
344
345 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
346 return Ok(U256::from(tx_count));
347 }
348 }
349 }
350 Ok(U256::from(on_chain_account_nonce))
351 })
352 }
353
354 fn get_code(
356 &self,
357 address: Address,
358 block_id: Option<BlockId>,
359 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
360 where
361 Self: SpawnBlocking,
362 {
363 self.spawn_blocking_io(move |this| {
364 Ok(this
365 .state_at_block_id_or_latest(block_id)?
366 .account_code(&address)
367 .map_err(Self::Error::from_eth_err)?
368 .unwrap_or_default()
369 .original_bytes())
370 })
371 }
372}