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_rpc_server_types::constants::DEFAULT_MAX_STORAGE_VALUES_SLOTS;
20use reth_storage_api::{
21 BlockIdReader, BlockReaderIdExt, StateProvider, StateProviderBox, StateProviderFactory,
22};
23use reth_transaction_pool::TransactionPool;
24use std::collections::HashMap;
25
26pub trait EthState: LoadState + SpawnBlocking {
28 fn max_proof_window(&self) -> u64;
30
31 fn ensure_within_proof_window(&self, block_id: BlockId) -> Result<(), Self::Error>
36 where
37 Self: EthApiSpec,
38 {
39 let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
40 let block_number = self
41 .provider()
42 .block_number_for_id(block_id)
43 .map_err(Self::Error::from_eth_err)?
44 .ok_or(EthApiError::HeaderNotFound(block_id))?;
45 if chain_info.best_number.saturating_sub(block_number) > self.max_proof_window() {
46 return Err(EthApiError::ExceedsMaxProofWindow.into())
47 }
48 Ok(())
49 }
50
51 fn transaction_count(
56 &self,
57 address: Address,
58 block_id: Option<BlockId>,
59 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
60 LoadState::transaction_count(self, address, block_id)
61 }
62
63 fn get_code(
65 &self,
66 address: Address,
67 block_id: Option<BlockId>,
68 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
69 LoadState::get_code(self, address, block_id)
70 }
71
72 fn balance(
74 &self,
75 address: Address,
76 block_id: Option<BlockId>,
77 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
78 self.spawn_blocking_io_fut(async move |this| {
79 Ok(this
80 .state_at_block_id_or_latest(block_id)
81 .await?
82 .account_balance(&address)
83 .map_err(Self::Error::from_eth_err)?
84 .unwrap_or_default())
85 })
86 }
87
88 fn storage_at(
90 &self,
91 address: Address,
92 index: JsonStorageKey,
93 block_id: Option<BlockId>,
94 ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
95 self.spawn_blocking_io_fut(async move |this| {
96 Ok(B256::new(
97 this.state_at_block_id_or_latest(block_id)
98 .await?
99 .storage(address, index.as_b256())
100 .map_err(Self::Error::from_eth_err)?
101 .unwrap_or_default()
102 .to_be_bytes(),
103 ))
104 })
105 }
106
107 fn storage_values(
112 &self,
113 requests: HashMap<Address, Vec<JsonStorageKey>>,
114 block_id: Option<BlockId>,
115 ) -> impl Future<Output = Result<HashMap<Address, Vec<B256>>, Self::Error>> + Send {
116 async move {
117 let total_slots: usize = requests.values().map(|slots| slots.len()).sum();
118 if total_slots > DEFAULT_MAX_STORAGE_VALUES_SLOTS {
119 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(
120 format!(
121 "total slot count {total_slots} exceeds limit {DEFAULT_MAX_STORAGE_VALUES_SLOTS}",
122 ),
123 )));
124 }
125
126 self.spawn_blocking_io_fut(async move |this| {
127 let state = this.state_at_block_id_or_latest(block_id).await?;
128
129 let mut result = HashMap::with_capacity(requests.len());
130 for (address, slots) in requests {
131 let mut values = Vec::with_capacity(slots.len());
132 for slot in &slots {
133 let value = state
134 .storage(address, slot.as_b256())
135 .map_err(Self::Error::from_eth_err)?
136 .unwrap_or_default();
137 values.push(B256::new(value.to_be_bytes()));
138 }
139 result.insert(address, values);
140 }
141
142 Ok(result)
143 })
144 .await
145 }
146 }
147
148 fn get_proof(
150 &self,
151 address: Address,
152 keys: Vec<JsonStorageKey>,
153 block_id: Option<BlockId>,
154 ) -> Result<
155 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
156 Self::Error,
157 >
158 where
159 Self: EthApiSpec,
160 {
161 Ok(async move {
162 let _permit = self
163 .acquire_owned_tracing()
164 .await
165 .map_err(RethError::other)
166 .map_err(EthApiError::Internal)?;
167
168 let block_id = block_id.unwrap_or_default();
169 self.ensure_within_proof_window(block_id)?;
170
171 self.spawn_blocking_io_fut(async move |this| {
172 let state = this.state_at_block_id(block_id).await?;
173 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
174 let proof = state
175 .proof(Default::default(), address, &storage_keys)
176 .map_err(Self::Error::from_eth_err)?;
177 Ok(proof.into_eip1186_response(keys))
178 })
179 .await
180 })
181 }
182
183 fn get_account(
185 &self,
186 address: Address,
187 block_id: BlockId,
188 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send
189 where
190 Self: EthApiSpec,
191 {
192 async move {
193 self.ensure_within_proof_window(block_id)?;
194
195 self.spawn_blocking_io_fut(async move |this| {
196 let state = this.state_at_block_id(block_id).await?;
197 let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
198 let Some(account) = account else { return Ok(None) };
199
200 let balance = account.balance;
201 let nonce = account.nonce;
202 let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY);
203
204 let storage_root = state
207 .storage_root(address, Default::default())
208 .map_err(Self::Error::from_eth_err)?;
209
210 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
211 })
212 .await
213 }
214 }
215
216 fn get_account_info(
218 &self,
219 address: Address,
220 block_id: BlockId,
221 ) -> impl Future<Output = Result<AccountInfo, Self::Error>> + Send {
222 self.spawn_blocking_io_fut(async move |this| {
223 let state = this.state_at_block_id(block_id).await?;
224 let account = state
225 .basic_account(&address)
226 .map_err(Self::Error::from_eth_err)?
227 .unwrap_or_default();
228
229 let balance = account.balance;
230 let nonce = account.nonce;
231 let code = if account.get_bytecode_hash() == KECCAK_EMPTY {
232 Default::default()
233 } else {
234 state
235 .account_code(&address)
236 .map_err(Self::Error::from_eth_err)?
237 .unwrap_or_default()
238 .original_bytes()
239 };
240
241 Ok(AccountInfo { balance, nonce, code })
242 })
243 }
244}
245
246pub trait LoadState:
250 LoadPendingBlock
251 + EthApiTypes<
252 Error: FromEvmError<Self::Evm> + FromEthApiError,
253 RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
254 > + RpcNodeCoreExt
255{
256 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
258 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
259 }
260
261 fn state_at_block_id(
266 &self,
267 at: BlockId,
268 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
269 where
270 Self: SpawnBlocking,
271 {
272 async move {
273 if at.is_pending() &&
274 let Ok(Some(state)) = self.local_pending_state().await
275 {
276 return Ok(state)
277 }
278
279 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
280 }
281 }
282
283 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
285 self.provider().latest().map_err(Self::Error::from_eth_err)
286 }
287
288 fn state_at_block_id_or_latest(
292 &self,
293 block_id: Option<BlockId>,
294 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
295 where
296 Self: SpawnBlocking,
297 {
298 async move {
299 if let Some(block_id) = block_id {
300 self.state_at_block_id(block_id).await
301 } else {
302 Ok(self.latest_state()?)
303 }
304 }
305 }
306
307 fn evm_env_for_header(
309 &self,
310 header: &SealedHeaderFor<Self::Primitives>,
311 ) -> Result<EvmEnvFor<Self::Evm>, Self::Error> {
312 self.evm_config()
313 .evm_env(header)
314 .map_err(RethError::other)
315 .map_err(Self::Error::from_eth_err)
316 }
317
318 fn evm_env_at(
325 &self,
326 at: BlockId,
327 ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
328 where
329 Self: SpawnBlocking,
330 {
331 async move {
332 if at.is_pending() {
333 let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
334 Ok((evm_env, origin.state_block_id()))
335 } else {
336 let header = RpcNodeCore::provider(self)
340 .sealed_header_by_id(at)
341 .map_err(Self::Error::from_eth_err)?
342 .ok_or_else(|| EthApiError::HeaderNotFound(at))?;
343 let evm_env = self.evm_env_for_header(&header)?;
344
345 Ok((evm_env, header.hash().into()))
346 }
347 }
348 }
349
350 fn next_available_nonce(
354 &self,
355 address: Address,
356 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
357 where
358 Self: SpawnBlocking,
359 {
360 self.spawn_blocking_io(move |this| {
361 let mut next_nonce = this
363 .latest_state()?
364 .account_nonce(&address)
365 .map_err(Self::Error::from_eth_err)?
366 .unwrap_or_default();
367
368 if let Some(highest_tx) =
370 this.pool().get_highest_consecutive_transaction_by_sender(address, next_nonce)
371 {
372 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
374 Self::Error::from(EthApiError::InvalidTransaction(
375 RpcInvalidTransactionError::NonceMaxValue,
376 ))
377 })?;
378 }
379
380 Ok(next_nonce)
381 })
382 }
383
384 fn transaction_count(
389 &self,
390 address: Address,
391 block_id: Option<BlockId>,
392 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
393 where
394 Self: SpawnBlocking,
395 {
396 self.spawn_blocking_io_fut(async move |this| {
397 let on_chain_account_nonce = this
399 .state_at_block_id_or_latest(block_id)
400 .await?
401 .account_nonce(&address)
402 .map_err(Self::Error::from_eth_err)?
403 .unwrap_or_default();
404
405 if block_id == Some(BlockId::pending()) {
406 if let Some(highest_pool_tx) = this
408 .pool()
409 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
410 {
411 {
412 let next_tx_nonce =
415 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
416 Self::Error::from(EthApiError::InvalidTransaction(
417 RpcInvalidTransactionError::NonceMaxValue,
418 ))
419 })?;
420
421 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
423
424 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
425 return Ok(U256::from(tx_count));
426 }
427 }
428 }
429 Ok(U256::from(on_chain_account_nonce))
430 })
431 }
432
433 fn get_code(
435 &self,
436 address: Address,
437 block_id: Option<BlockId>,
438 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
439 where
440 Self: SpawnBlocking,
441 {
442 self.spawn_blocking_io_fut(async move |this| {
443 Ok(this
444 .state_at_block_id_or_latest(block_id)
445 .await?
446 .account_code(&address)
447 .map_err(Self::Error::from_eth_err)?
448 .unwrap_or_default()
449 .original_bytes())
450 })
451 }
452}