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