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_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
23pub trait EthState: LoadState + SpawnBlocking {
25 fn max_proof_window(&self) -> u64;
27
28 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 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 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 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 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 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 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 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 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 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
197pub trait LoadState:
201 LoadPendingBlock
202 + EthApiTypes<
203 Error: FromEvmError<Self::Evm> + FromEthApiError,
204 RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
205 > + RpcNodeCoreExt
206{
207 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 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 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
236 self.provider().latest().map_err(Self::Error::from_eth_err)
237 }
238
239 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 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 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 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 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 if let Some(highest_tx) =
311 this.pool().get_highest_consecutive_transaction_by_sender(address, next_nonce)
312 {
313 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 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 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 if let Some(highest_pool_tx) = this
349 .pool()
350 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
351 {
352 {
353 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 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 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}