1use super::{
5 pending_block::PendingStateSource, EthApiSpec, LoadBlock, LoadPendingBlock, SpawnBlocking,
6};
7use crate::{EthApiTypes, FromEthApiError, RpcNodeCore, RpcNodeCoreExt};
8use alloy_consensus::{constants::KECCAK_EMPTY, BlockHeader};
9use alloy_eips::BlockId;
10use alloy_primitives::{keccak256, Address, Bytes, B256, U256};
11use alloy_rpc_types_eth::{Account, AccountInfo, EIP1186AccountProofResponse};
12use alloy_serde::JsonStorageKey;
13use futures::Future;
14use reth_errors::RethError;
15use reth_evm::{ConfigureEvm, EvmEnvFor};
16use reth_primitives_traits::{BlockTy, RecoveredBlock, SealedHeaderFor};
17use reth_rpc_convert::{RpcConvert, RpcTxReq};
18use reth_rpc_eth_types::{
19 error::{FromEvmError, IntoEthApiError},
20 EthApiError, PendingBlockEnv, RpcInvalidTransactionError, SignError,
21};
22use reth_rpc_server_types::constants::{DEFAULT_MAX_PROOF_SLOTS, DEFAULT_MAX_STORAGE_VALUES_SLOTS};
23use reth_storage_api::{
24 BlockIdReader, BlockReaderIdExt, StateProvider, StateProviderBox, StateProviderFactory,
25};
26use reth_transaction_pool::TransactionPool;
27use reth_trie_common::{MultiProofTargetsV2, ProofV2Target};
28use std::{collections::HashMap, sync::Arc};
29
30pub trait EthState: LoadState + SpawnBlocking {
32 fn max_proof_window(&self) -> u64 {
34 self.eth_api_settings().eth_proof_window
35 }
36
37 fn ensure_within_proof_window(&self, block_id: BlockId) -> Result<(), Self::Error>
42 where
43 Self: EthApiSpec,
44 {
45 let chain_info = self.chain_info().map_err(Self::Error::from_eth_err)?;
46 let block_number = self
47 .provider()
48 .block_number_for_id(block_id)
49 .map_err(Self::Error::from_eth_err)?
50 .ok_or(EthApiError::HeaderNotFound(block_id))?;
51 if chain_info.best_number.saturating_sub(block_number) > self.max_proof_window() {
52 return Err(EthApiError::ExceedsMaxProofWindow.into())
53 }
54 Ok(())
55 }
56
57 fn transaction_count(
62 &self,
63 address: Address,
64 block_id: Option<BlockId>,
65 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
66 LoadState::transaction_count(self, address, block_id)
67 }
68
69 fn get_code(
71 &self,
72 address: Address,
73 block_id: Option<BlockId>,
74 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send {
75 LoadState::get_code(self, address, block_id)
76 }
77
78 fn balance(
80 &self,
81 address: Address,
82 block_id: Option<BlockId>,
83 ) -> impl Future<Output = Result<U256, Self::Error>> + Send {
84 self.spawn_blocking_io_with_state(block_id.unwrap_or_default(), move |_, state| {
85 Ok(state
86 .account_balance(&address)
87 .map_err(Self::Error::from_eth_err)?
88 .unwrap_or_default())
89 })
90 }
91
92 fn storage_at(
94 &self,
95 address: Address,
96 index: JsonStorageKey,
97 block_id: Option<BlockId>,
98 ) -> impl Future<Output = Result<B256, Self::Error>> + Send {
99 self.spawn_blocking_io_with_state(block_id.unwrap_or_default(), move |_, state| {
100 Ok(B256::from(
101 state
102 .storage(address, index.as_b256())
103 .map_err(Self::Error::from_eth_err)?
104 .unwrap_or_default(),
105 ))
106 })
107 }
108
109 fn storage_values(
114 &self,
115 requests: HashMap<Address, Vec<JsonStorageKey>>,
116 block_id: Option<BlockId>,
117 ) -> impl Future<Output = Result<HashMap<Address, Vec<B256>>, Self::Error>> + Send {
118 async move {
119 if requests.is_empty() {
120 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(
121 "empty request".to_string(),
122 )));
123 }
124 let total_slots: usize = requests.values().map(|slots| slots.len()).sum();
125 if total_slots > DEFAULT_MAX_STORAGE_VALUES_SLOTS {
126 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(
127 format!(
128 "total slot count {total_slots} exceeds limit {DEFAULT_MAX_STORAGE_VALUES_SLOTS}",
129 ),
130 )));
131 }
132
133 self.spawn_blocking_io_with_state(block_id.unwrap_or_default(), move |_, state| {
134 let mut result = HashMap::with_capacity(requests.len());
135 for (address, slots) in requests {
136 let mut values = Vec::with_capacity(slots.len());
137 for slot in &slots {
138 let value = state
139 .storage(address, slot.as_b256())
140 .map_err(Self::Error::from_eth_err)?
141 .unwrap_or_default();
142 values.push(B256::from(value));
143 }
144 result.insert(address, values);
145 }
146
147 Ok(result)
148 })
149 .await
150 }
151 }
152
153 fn get_proof(
158 &self,
159 address: Address,
160 keys: Vec<JsonStorageKey>,
161 block_id: Option<BlockId>,
162 ) -> Result<
163 impl Future<Output = Result<EIP1186AccountProofResponse, Self::Error>> + Send,
164 Self::Error,
165 >
166 where
167 Self: EthApiSpec,
168 {
169 if keys.len() > DEFAULT_MAX_PROOF_SLOTS {
170 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(format!(
171 "storage key count {} exceeds limit {DEFAULT_MAX_PROOF_SLOTS}",
172 keys.len(),
173 ))));
174 }
175
176 Ok(async move {
177 let permit = self
178 .acquire_owned_tracing()
179 .await
180 .map_err(RethError::other)
181 .map_err(EthApiError::Internal)?;
182
183 let block_id = block_id.unwrap_or_default();
184 self.ensure_within_proof_window(block_id)?;
185
186 self.spawn_blocking_io_with_state(block_id, move |_, state| {
187 let _permit = permit;
188 let storage_keys = keys.iter().map(|key| key.as_b256()).collect::<Vec<_>>();
189 let proof = state
190 .proof(Default::default(), address, &storage_keys)
191 .map_err(Self::Error::from_eth_err)?;
192 Ok(proof.into_eip1186_response_with(keys, true))
193 })
194 .await
195 })
196 }
197
198 fn get_multi_proof(
203 &self,
204 targets: Vec<(Address, Vec<B256>)>,
205 block_id: Option<BlockId>,
206 ) -> Result<
207 impl Future<Output = Result<Vec<EIP1186AccountProofResponse>, Self::Error>> + Send,
208 Self::Error,
209 >
210 where
211 Self: EthApiSpec,
212 {
213 if targets.len() > DEFAULT_MAX_PROOF_SLOTS {
214 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(format!(
215 "target count {} exceeds limit {DEFAULT_MAX_PROOF_SLOTS}",
216 targets.len(),
217 ))));
218 }
219 let total_slots: usize = targets.iter().map(|(_, slots)| slots.len()).sum();
220 if total_slots > DEFAULT_MAX_PROOF_SLOTS {
221 return Err(Self::Error::from_eth_err(EthApiError::InvalidParams(format!(
222 "total slot count {total_slots} exceeds limit {DEFAULT_MAX_PROOF_SLOTS}",
223 ))));
224 }
225
226 Ok(async move {
227 let permit = self
228 .acquire_owned_tracing()
229 .await
230 .map_err(RethError::other)
231 .map_err(EthApiError::Internal)?;
232
233 let block_id = block_id.unwrap_or_default();
234 self.ensure_within_proof_window(block_id)?;
235
236 self.spawn_blocking_io_with_state(block_id, move |_, state| {
237 let _permit = permit;
238 let mut proof_targets = MultiProofTargetsV2::default();
239 proof_targets.account_targets.reserve(targets.len());
240 proof_targets.storage_targets.reserve(targets.len());
241 for (address, slots) in &targets {
242 let hashed_address = keccak256(address);
243 proof_targets.account_targets.push(ProofV2Target::new(hashed_address));
244 if !slots.is_empty() {
245 proof_targets
246 .storage_targets
247 .entry(hashed_address)
248 .or_default()
249 .extend(slots.iter().map(|slot| ProofV2Target::new(keccak256(slot))));
250 }
251 }
252
253 let multiproof =
254 state.multiproof_v2(proof_targets, false).map_err(Self::Error::from_eth_err)?;
255
256 targets
257 .into_iter()
258 .map(|(address, slots)| {
259 let proof = multiproof
260 .account_proof(address, &slots)
261 .map_err(RethError::other)
262 .map_err(Self::Error::from_eth_err)?;
263 let storage_keys =
264 slots.into_iter().map(JsonStorageKey::from).collect::<Vec<_>>();
265 Ok(proof.into_eip1186_response_with(storage_keys, true))
266 })
267 .collect::<Result<Vec<_>, Self::Error>>()
268 })
269 .await
270 })
271 }
272
273 fn get_account(
275 &self,
276 address: Address,
277 block_id: BlockId,
278 ) -> impl Future<Output = Result<Option<Account>, Self::Error>> + Send
279 where
280 Self: EthApiSpec,
281 {
282 async move {
283 self.ensure_within_proof_window(block_id)?;
284
285 self.spawn_blocking_io_with_state(block_id, move |_, state| {
286 let account = state.basic_account(&address).map_err(Self::Error::from_eth_err)?;
287 let Some(account) = account else { return Ok(None) };
288
289 let storage_root = state
292 .storage_root(address, Default::default())
293 .map_err(Self::Error::from_eth_err)?;
294
295 Ok(Some(account.into_trie_account(storage_root)))
296 })
297 .await
298 }
299 }
300
301 #[allow(clippy::needless_update)]
303 fn get_account_info(
304 &self,
305 address: Address,
306 block_id: BlockId,
307 ) -> impl Future<Output = Result<AccountInfo, Self::Error>> + Send {
308 self.spawn_blocking_io_with_state(block_id, move |_, state| {
309 let account = state
310 .basic_account(&address)
311 .map_err(Self::Error::from_eth_err)?
312 .unwrap_or_default();
313
314 let balance = account.balance;
315 let nonce = account.nonce;
316 let code = if account.get_bytecode_hash() == KECCAK_EMPTY {
317 Default::default()
318 } else {
319 state
320 .account_code(&address)
321 .map_err(Self::Error::from_eth_err)?
322 .unwrap_or_default()
323 .original_bytes()
324 };
325
326 Ok(AccountInfo {
327 balance,
328 nonce,
329 code,
330 #[cfg(feature = "account-ext")]
331 extension: account.extension,
332 ..Default::default()
333 })
334 })
335 }
336}
337
338pub trait LoadState:
342 LoadPendingBlock
343 + EthApiTypes<
344 Error: FromEvmError<Self::Evm> + FromEthApiError,
345 RpcConvert: RpcConvert<Network = Self::NetworkTypes>,
346 > + RpcNodeCoreExt
347{
348 fn state_at_hash(&self, block_hash: B256) -> Result<StateProviderBox, Self::Error> {
350 self.provider().history_by_block_hash(block_hash).map_err(Self::Error::from_eth_err)
351 }
352
353 fn state_at_block_id(
363 &self,
364 at: BlockId,
365 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
366 where
367 Self: SpawnBlocking,
368 {
369 async move {
370 if at.is_pending() &&
371 let Ok(Some(state)) = self.local_pending_state().await
372 {
373 return Ok(state)
374 }
375
376 self.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)
377 }
378 }
379
380 fn latest_state(&self) -> Result<StateProviderBox, Self::Error> {
382 self.provider().latest().map_err(Self::Error::from_eth_err)
383 }
384
385 fn state_at_block_id_or_latest(
389 &self,
390 block_id: Option<BlockId>,
391 ) -> impl Future<Output = Result<StateProviderBox, Self::Error>> + Send
392 where
393 Self: SpawnBlocking,
394 {
395 async move {
396 if let Some(block_id) = block_id {
397 self.state_at_block_id(block_id).await
398 } else {
399 Ok(self.latest_state()?)
400 }
401 }
402 }
403
404 fn spawn_blocking_io_with_state<F, R>(
409 &self,
410 at: BlockId,
411 f: F,
412 ) -> impl Future<Output = Result<R, Self::Error>> + Send
413 where
414 Self: SpawnBlocking,
415 F: FnOnce(Self, StateProviderBox) -> Result<R, Self::Error> + Send + 'static,
416 R: Send + 'static,
417 {
418 async move {
419 let pending = if at.is_pending() {
420 self.local_pending_block_or_state().await.ok().flatten()
421 } else {
422 None
423 };
424
425 self.spawn_blocking_io(move |this| {
426 let state = match pending {
427 Some(PendingStateSource::Block(pending)) => this
428 .provider()
429 .state_with_block_appended(
430 pending.block().parent_hash(),
431 pending.executed_block,
432 )
433 .or_else(|_| this.provider().state_by_block_id(BlockId::pending()))
434 .map_err(Self::Error::from_eth_err)?,
435 Some(PendingStateSource::State(state)) => state,
436 None if at.is_latest() => this.latest_state()?,
437 None => {
438 this.provider().state_by_block_id(at).map_err(Self::Error::from_eth_err)?
439 }
440 };
441 f(this, state)
442 })
443 .await
444 }
445 }
446
447 fn evm_env_for_header(
449 &self,
450 header: &SealedHeaderFor<Self::Primitives>,
451 ) -> Result<EvmEnvFor<Self::Evm>, Self::Error> {
452 self.evm_config()
453 .evm_env(header)
454 .map_err(RethError::other)
455 .map_err(Self::Error::from_eth_err)
456 }
457
458 fn evm_env_at(
465 &self,
466 at: BlockId,
467 ) -> impl Future<Output = Result<(EvmEnvFor<Self::Evm>, BlockId), Self::Error>> + Send
468 where
469 Self: SpawnBlocking,
470 {
471 async move {
472 if at.is_pending() {
473 let PendingBlockEnv { evm_env, origin } = self.pending_block_env_and_cfg()?;
474 Ok((evm_env, origin.state_block_id()))
475 } else {
476 let header = RpcNodeCore::provider(self)
480 .sealed_header_by_id(at)
481 .map_err(Self::Error::from_eth_err)?
482 .ok_or_else(|| EthApiError::HeaderNotFound(at))?;
483 let evm_env = self.evm_env_for_header(&header)?;
484
485 Ok((evm_env, header.hash().into()))
486 }
487 }
488 }
489
490 #[expect(clippy::type_complexity)]
497 fn evm_env_and_recovered_block_at(
498 &self,
499 at: BlockId,
500 ) -> impl Future<
501 Output = Result<
502 (Arc<RecoveredBlock<BlockTy<Self::Primitives>>>, EvmEnvFor<Self::Evm>, BlockId),
503 Self::Error,
504 >,
505 > + Send
506 where
507 Self: LoadBlock,
508 {
509 async move {
510 if at.is_pending() {
511 let (evm_env, block_id) = self.evm_env_at(at).await?;
512 let block = self
513 .recovered_block(block_id)
514 .await?
515 .ok_or_else(|| EthApiError::HeaderNotFound(at))?;
516
517 Ok((block, evm_env, block_id))
518 } else {
519 let block = self
520 .recovered_block(at)
521 .await?
522 .ok_or_else(|| EthApiError::HeaderNotFound(at))?;
523 let evm_env = self.evm_env_for_header(block.sealed_block().sealed_header())?;
524 let block_id = block.hash().into();
525
526 Ok((block, evm_env, block_id))
527 }
528 }
529 }
530
531 fn next_available_nonce_for(
537 &self,
538 request: &RpcTxReq<Self::NetworkTypes>,
539 ) -> impl Future<Output = Result<u64, Self::Error>> + Send
540 where
541 Self: SpawnBlocking,
542 {
543 let address = request.as_ref().from;
544 self.spawn_blocking_io(move |this| {
545 let address = match address {
546 Some(address) => address,
547 None => return Err(SignError::NoAccount.into_eth_err()),
548 };
549
550 let mut next_nonce = this
552 .latest_state()?
553 .account_nonce(&address)
554 .map_err(Self::Error::from_eth_err)?
555 .unwrap_or_default();
556
557 if let Some(highest_tx) =
559 this.pool().get_highest_consecutive_transaction_by_sender(address, next_nonce)
560 {
561 next_nonce = highest_tx.nonce().checked_add(1).ok_or_else(|| {
563 Self::Error::from(EthApiError::InvalidTransaction(
564 RpcInvalidTransactionError::NonceMaxValue,
565 ))
566 })?;
567 }
568
569 Ok(next_nonce)
570 })
571 }
572
573 fn transaction_count(
578 &self,
579 address: Address,
580 block_id: Option<BlockId>,
581 ) -> impl Future<Output = Result<U256, Self::Error>> + Send
582 where
583 Self: SpawnBlocking,
584 {
585 let at = block_id.unwrap_or_default();
586 self.spawn_blocking_io_with_state(at, move |this, state| {
587 this.transaction_count_with_state(address, at, &state)
588 })
589 }
590
591 fn transaction_count_with_state(
597 &self,
598 address: Address,
599 at: BlockId,
600 state: &StateProviderBox,
601 ) -> Result<U256, Self::Error> {
602 let on_chain_account_nonce =
604 state.account_nonce(&address).map_err(Self::Error::from_eth_err)?.unwrap_or_default();
605
606 if at.is_pending() {
607 if let Some(highest_pool_tx) = self
609 .pool()
610 .get_highest_consecutive_transaction_by_sender(address, on_chain_account_nonce)
611 {
612 {
613 let next_tx_nonce =
616 highest_pool_tx.nonce().checked_add(1).ok_or_else(|| {
617 Self::Error::from(EthApiError::InvalidTransaction(
618 RpcInvalidTransactionError::NonceMaxValue,
619 ))
620 })?;
621
622 let next_tx_nonce = on_chain_account_nonce.max(next_tx_nonce);
624
625 let tx_count = on_chain_account_nonce.max(next_tx_nonce);
626 return Ok(U256::from(tx_count));
627 }
628 }
629 }
630 Ok(U256::from(on_chain_account_nonce))
631 }
632
633 fn get_code(
635 &self,
636 address: Address,
637 block_id: Option<BlockId>,
638 ) -> impl Future<Output = Result<Bytes, Self::Error>> + Send
639 where
640 Self: SpawnBlocking,
641 {
642 self.spawn_blocking_io_with_state(block_id.unwrap_or_default(), move |_, state| {
643 Ok(state
644 .account_code(&address)
645 .map_err(Self::Error::from_eth_err)?
646 .unwrap_or_default()
647 .original_bytes())
648 })
649 }
650}