1use alloy_consensus::{constants::KECCAK_EMPTY, transaction::TxHashRef, BlockHeader};
2use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
3use alloy_evm::{env::BlockEnvironment, Evm};
4use alloy_genesis::ChainConfig;
5use alloy_primitives::{hex::decode, uint, Address, Bytes, B256, U256, U64};
6use alloy_rlp::{Decodable, Encodable};
7use alloy_rpc_types::BlockTransactionsKind;
8use alloy_rpc_types_debug::ExecutionWitness;
9use alloy_rpc_types_eth::{
10 state::EvmOverrides, Account, AccountInfo, BlockError, Bundle, Index, StateContext,
11};
12use alloy_rpc_types_trace::geth::{
13 ChainBlockTraceResult, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace,
14 TraceResult,
15};
16use async_trait::async_trait;
17use futures::Stream;
18use jsonrpsee::{core::RpcResult, PendingSubscriptionSink, SubscriptionMessage};
19use parking_lot::RwLock;
20use reth_chainspec::{ChainSpecProvider, EthereumHardforks};
21use reth_engine_primitives::ConsensusEngineEvent;
22use reth_errors::RethError;
23use reth_evm::{block::BlockExecutor, execute::Executor, ConfigureEvm, EvmEnvFor};
24use reth_primitives_traits::{
25 Block as BlockTrait, BlockBody, BlockTy, ReceiptWithBloom, RecoveredBlock,
26};
27use reth_revm::{db::State, witness::ExecutionWitnessRecord};
28use reth_rpc_api::DebugApiServer;
29use reth_rpc_convert::RpcTxReq;
30use reth_rpc_eth_api::{
31 helpers::{EthTransactions, TraceExt},
32 AsEthApiError, FromEthApiError, FromEvmError, RpcConvert, RpcNodeCore,
33};
34use reth_rpc_eth_types::{EthApiError, StateCacheDb};
35use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
36use reth_storage_api::{
37 BlockIdReader, BlockReaderIdExt, HashedPostStateProvider, HeaderProvider, ProviderBlock,
38 ReceiptProviderIdExt, StateProviderBox, StateProviderFactory, StateRootProvider,
39 StorageRootProvider, TransactionVariant,
40};
41use reth_tasks::{cancel::is_cancelled, pool::BlockingTaskGuard, Runtime};
42use reth_transaction_pool::TransactionPool;
43use reth_trie_common::{
44 root::storage_root_unsorted, updates::TrieUpdates, ExecutionWitnessMode, HashedPostState,
45 HashedStorage,
46};
47use revm::{database::states::bundle_state::BundleRetention, Database, DatabaseCommit};
48use revm_inspectors::tracing::{DebugInspector, TransactionContext};
49use serde::{Deserialize, Serialize};
50use std::{collections::VecDeque, sync::Arc};
51use tokio::sync::{AcquireError, OwnedSemaphorePermit};
52use tokio_stream::StreamExt;
53
54pub struct DebugApi<Eth: RpcNodeCore> {
58 inner: Arc<DebugApiInner<Eth>>,
59}
60
61impl<Eth> DebugApi<Eth>
62where
63 Eth: RpcNodeCore,
64{
65 pub fn new(
67 eth_api: Eth,
68 blocking_task_guard: BlockingTaskGuard,
69 executor: &Runtime,
70 mut stream: impl Stream<Item = ConsensusEngineEvent<Eth::Primitives>> + Send + Unpin + 'static,
71 ) -> Self {
72 let bad_block_store = BadBlockStore::default();
73 let inner = Arc::new(DebugApiInner {
74 eth_api,
75 blocking_task_guard,
76 task_spawner: executor.clone(),
77 bad_block_store: bad_block_store.clone(),
78 });
79
80 executor.spawn_task(async move {
82 while let Some(event) = stream.next().await {
83 if let ConsensusEngineEvent::InvalidBlock { block, error } = event &&
84 let Ok(recovered) = RecoveredBlock::try_recover_sealed(*block)
85 {
86 bad_block_store.insert(recovered, error);
87 }
88 }
89 });
90
91 Self { inner }
92 }
93
94 pub fn eth_api(&self) -> &Eth {
96 &self.inner.eth_api
97 }
98
99 pub fn provider(&self) -> &Eth::Provider {
101 self.inner.eth_api.provider()
102 }
103}
104
105impl<Eth> DebugApi<Eth>
108where
109 Eth: TraceExt,
110{
111 async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
113 self.inner.blocking_task_guard.clone().acquire_owned().await
114 }
115
116 async fn trace_block(
118 &self,
119 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
120 evm_env: EvmEnvFor<Eth::Evm>,
121 opts: GethDebugTracingOptions,
122 ) -> Result<Vec<TraceResult>, Eth::Error> {
123 self.eth_api()
124 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
125 let mut results = Vec::with_capacity(block.body().transactions().len());
126
127 eth_api.apply_pre_execution_changes(&block, &mut db)?;
128
129 let block_env = evm_env.block_env.clone();
130
131 let mut transactions = block.transactions_recovered().enumerate().peekable();
132 let inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
133 let mut evm =
134 eth_api.evm_config().evm_with_env_and_inspector(&mut db, evm_env, inspector);
135 while let Some((index, tx)) = transactions.next() {
136 if is_cancelled() {
137 return Err(EthApiError::InternalEthError.into())
138 }
139 let tx_env = eth_api.evm_config().tx_env(tx);
140
141 let res = evm.transact(tx_env.clone()).map_err(Eth::Error::from_evm_err)?;
142
143 let (db, inspector, _) = evm.components_mut();
144 let result = inspector
145 .get_result(
146 Some(TransactionContext {
147 block_hash: Some(block.hash()),
148 tx_hash: Some(*tx.tx_hash()),
149 tx_index: Some(index),
150 }),
151 &tx_env,
152 &block_env,
153 &res,
154 db,
155 )
156 .map_err(Eth::Error::from_eth_err)?;
157
158 results.push(TraceResult::Success { result, tx_hash: Some(*tx.tx_hash()) });
159 if transactions.peek().is_some() {
160 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
161 db.commit(res.state)
164 }
165 }
166
167 Ok(results)
168 })
169 .await
170 }
171
172 async fn trace_chain_block(
175 &self,
176 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
177 opts: GethDebugTracingOptions,
178 ) -> Result<Vec<Option<TraceResult>>, Eth::Error> {
179 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
180
181 self.eth_api()
182 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
183 let tx_count = block.body().transactions().len();
184 let mut results = Vec::with_capacity(tx_count);
185
186 eth_api.apply_pre_execution_changes(&block, &mut db)?;
187
188 let block_env = evm_env.block_env.clone();
189 let mut transactions = block.transactions_recovered().enumerate().peekable();
190 let inspector = match DebugInspector::new(opts) {
191 Ok(inspector) => inspector,
192 Err(err) => {
193 if let Some((_, tx)) = transactions.peek() {
194 results.push(Some(TraceResult::Error {
195 error: err.to_string(),
196 tx_hash: Some(*tx.tx_hash()),
197 }));
198 }
199 results.resize(tx_count, None);
200 return Ok(results)
201 }
202 };
203 let mut evm =
204 eth_api.evm_config().evm_with_env_and_inspector(&mut db, evm_env, inspector);
205
206 while let Some((index, tx)) = transactions.next() {
207 let tx_hash = *tx.tx_hash();
208 let tx_env = eth_api.evm_config().tx_env(tx);
209 let res = match evm.transact(tx_env.clone()) {
210 Ok(res) => res,
211 Err(err) => {
212 results.push(Some(TraceResult::Error {
213 error: err.to_string(),
214 tx_hash: Some(tx_hash),
215 }));
216 break
217 }
218 };
219
220 let (db, inspector, _) = evm.components_mut();
221 let result = match inspector.get_result(
222 Some(TransactionContext {
223 block_hash: Some(block.hash()),
224 tx_hash: Some(tx_hash),
225 tx_index: Some(index),
226 }),
227 &tx_env,
228 &block_env,
229 &res,
230 db,
231 ) {
232 Ok(result) => result,
233 Err(err) => {
234 results.push(Some(TraceResult::Error {
235 error: err.to_string(),
236 tx_hash: Some(tx_hash),
237 }));
238 break
239 }
240 };
241
242 results.push(Some(TraceResult::Success { result, tx_hash: Some(tx_hash) }));
243 if let Some((_, next_tx)) = transactions.peek() {
244 if let Err(err) = inspector.fuse() {
245 results.push(Some(TraceResult::Error {
246 error: err.to_string(),
247 tx_hash: Some(*next_tx.tx_hash()),
248 }));
249 break
250 }
251 db.commit(res.state);
252 }
253 }
254
255 results.resize(tx_count, None);
256 Ok(results)
257 })
258 .await
259 }
260
261 pub async fn debug_trace_raw_block(
267 &self,
268 rlp_block: Bytes,
269 opts: GethDebugTracingOptions,
270 ) -> Result<Vec<TraceResult>, Eth::Error> {
271 let block: ProviderBlock<Eth::Provider> = Decodable::decode(&mut rlp_block.as_ref())
272 .map_err(BlockError::RlpDecodeRawBlock)
273 .map_err(Eth::Error::from_eth_err)?;
274
275 let evm_env = self
276 .eth_api()
277 .evm_config()
278 .evm_env(block.header())
279 .map_err(RethError::other)
280 .map_err(Eth::Error::from_eth_err)?;
281
282 let senders =
284 if self.provider().chain_spec().is_homestead_active_at_block(block.header().number()) {
285 block.body().recover_signers()
286 } else {
287 block.body().recover_signers_unchecked()
288 }
289 .map_err(Eth::Error::from_eth_err)?;
290
291 self.trace_block(Arc::new(block.into_recovered_with_signers(senders)), evm_env, opts).await
292 }
293
294 pub async fn debug_trace_block(
296 &self,
297 block_id: BlockId,
298 opts: GethDebugTracingOptions,
299 ) -> Result<Vec<TraceResult>, Eth::Error> {
300 let block = self
301 .eth_api()
302 .recovered_block(block_id)
303 .await?
304 .ok_or(EthApiError::TracingBlockNotFound(block_id))?;
305 if block.number() == 0 {
307 return Err(EthApiError::GenesisNotTraceable.into())
308 }
309 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
310
311 self.trace_block(block, evm_env, opts).await
312 }
313
314 pub async fn debug_trace_transaction(
318 &self,
319 tx_hash: B256,
320 opts: GethDebugTracingOptions,
321 ) -> Result<GethTrace, Eth::Error> {
322 let (transaction, block, bal) =
323 match self.eth_api().transaction_and_block_and_maybe_bal(tx_hash).await? {
324 None => return Err(EthApiError::TracingTransactionNotFound.into()),
325 Some(res) => res,
326 };
327
328 self.eth_api()
329 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
330 let (tx, tx_info) = transaction.split();
332
333 let index =
336 tx_info.index.expect("transaction_and_block only returns block transactions")
337 as usize;
338
339 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
340 let tx_env = eth_api.evm_config().tx_env(&tx);
341 let (res, evm_env) = eth_api.inspect_transaction_in_block(
342 &block,
343 &mut db,
344 &mut inspector,
345 index,
346 tx_env.clone(),
347 bal.as_deref(),
348 )?;
349
350 let trace = inspector
351 .get_result(
352 Some(TransactionContext {
353 block_hash: Some(block.hash()),
354 tx_index: Some(index),
355 tx_hash: Some(*tx.tx_hash()),
356 }),
357 &tx_env,
358 &evm_env.block_env,
359 &res,
360 &mut db,
361 )
362 .map_err(Eth::Error::from_eth_err)?;
363
364 Ok(trace)
365 })
366 .await
367 }
368
369 pub async fn debug_trace_call(
379 &self,
380 call: RpcTxReq<Eth::NetworkTypes>,
381 block_id: Option<BlockId>,
382 opts: GethDebugTracingCallOptions,
383 ) -> Result<GethTrace, Eth::Error> {
384 let at = block_id.unwrap_or_default();
385 let GethDebugTracingCallOptions {
386 tracing_options,
387 state_overrides,
388 block_overrides,
389 tx_index,
390 } = opts;
391 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
392
393 if let Some(tx_idx) = tx_index {
395 return self
396 .debug_trace_call_at_tx_index(call, at, tx_idx as usize, tracing_options, overrides)
397 .await;
398 }
399
400 let this = self.clone();
401 self.eth_api()
402 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
403 let mut inspector =
404 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
405 let res = this.eth_api().inspect(
406 &mut *db,
407 evm_env.clone(),
408 tx_env.clone(),
409 &mut inspector,
410 )?;
411 let trace = inspector
412 .get_result(None, &tx_env, &evm_env.block_env, &res, db)
413 .map_err(Eth::Error::from_eth_err)?;
414 Ok(trace)
415 })
416 .await
417 .map_err(|err| match err.as_err() {
418 Some(EthApiError::HeaderNotFound(id)) if *id == at => {
419 EthApiError::TracingBlockNotFound(at).into()
421 }
422 _ => err,
423 })
424 }
425
426 async fn debug_trace_call_at_tx_index(
430 &self,
431 call: RpcTxReq<Eth::NetworkTypes>,
432 block_id: BlockId,
433 tx_index: usize,
434 tracing_options: GethDebugTracingOptions,
435 overrides: EvmOverrides,
436 ) -> Result<GethTrace, Eth::Error> {
437 let (block, bal) = self
439 .eth_api()
440 .recovered_block_and_maybe_bal(block_id)
441 .await?
442 .ok_or(EthApiError::TracingBlockNotFound(block_id))?;
443
444 if tx_index >= block.transaction_count() {
445 return Err(EthApiError::InvalidParams(format!(
447 "tx_index {} out of bounds for block with {} transactions",
448 tx_index,
449 block.transaction_count()
450 ))
451 .into())
452 }
453
454 let bal = bal.filter(|_| !overrides.has_state());
457
458 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
459
460 self.eth_api()
461 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
462 eth_api.replay_block_until(&mut db, &block, tx_index, bal.as_deref())?;
464
465 let (evm_env, tx_env) =
467 eth_api.prepare_call_env(evm_env, call, &mut db, overrides)?;
468
469 let mut inspector =
470 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
471 let res =
472 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
473 let trace = inspector
474 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
475 .map_err(Eth::Error::from_eth_err)?;
476
477 Ok(trace)
478 })
479 .await
480 }
481
482 pub async fn debug_trace_call_many(
486 &self,
487 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
488 state_context: Option<StateContext>,
489 opts: Option<GethDebugTracingCallOptions>,
490 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
491 if bundles.is_empty() {
492 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
493 }
494
495 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
496 let transaction_index = transaction_index.unwrap_or_default();
497
498 let target_block = block_number.unwrap_or_default();
499 let block = self
500 .eth_api()
501 .recovered_block(target_block)
502 .await?
503 .ok_or(EthApiError::HeaderNotFound(target_block))?;
504 let mut evm_env =
505 self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
506
507 let opts = opts.unwrap_or_default();
508 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
509
510 let mut at = block.parent_hash();
513 let mut replay_block_txs = true;
514
515 let num_txs =
517 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
518 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
522 at = block.hash();
523 replay_block_txs = false;
524 }
525
526 self.eth_api()
527 .spawn_with_state_at_block(at, move |eth_api, mut db| {
528 let mut all_bundles = Vec::with_capacity(bundles.len());
530
531 if replay_block_txs {
532 eth_api.replay_block_until(&mut db, &block, num_txs, None)?;
538 }
539
540 let mut bundles = bundles.into_iter().peekable();
542 let mut inspector = DebugInspector::new(tracing_options.clone())
543 .map_err(Eth::Error::from_eth_err)?;
544 while let Some(bundle) = bundles.next() {
545 let mut results = Vec::with_capacity(bundle.transactions.len());
546 let Bundle { transactions, block_override } = bundle;
547
548 let block_overrides = block_override.map(Box::new);
549
550 let mut transactions = transactions.into_iter().peekable();
551 while let Some(tx) = transactions.next() {
552 if is_cancelled() {
553 return Err(EthApiError::InternalEthError.into())
554 }
555 let state_overrides = state_overrides.take();
557 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
558
559 let (evm_env, tx_env) =
560 eth_api.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
561
562 let res = eth_api.inspect(
563 &mut db,
564 evm_env.clone(),
565 tx_env.clone(),
566 &mut inspector,
567 )?;
568 let trace = inspector
569 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
570 .map_err(Eth::Error::from_eth_err)?;
571
572 if transactions.peek().is_some() || bundles.peek().is_some() {
575 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
576 db.commit(res.state);
577 }
578 results.push(trace);
579 }
580 evm_env.block_env.inner_mut().number += uint!(1_U256);
582 evm_env.block_env.inner_mut().timestamp += uint!(12_U256);
583
584 all_bundles.push(results);
585 }
586 Ok(all_bundles)
587 })
588 .await
589 }
590
591 pub async fn debug_execution_witness_by_block_hash(
594 &self,
595 hash: B256,
596 mode: Option<ExecutionWitnessMode>,
597 ) -> Result<ExecutionWitness, Eth::Error> {
598 let this = self.clone();
599 let block = this
600 .eth_api()
601 .recovered_block(hash.into())
602 .await?
603 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
604
605 self.debug_execution_witness_for_block(block, mode.unwrap_or_default()).await
606 }
607
608 pub async fn debug_execution_witness(
613 &self,
614 block_id: BlockId,
615 mode: Option<ExecutionWitnessMode>,
616 ) -> Result<ExecutionWitness, Eth::Error> {
617 let this = self.clone();
618 let block = this
619 .eth_api()
620 .recovered_block(block_id)
621 .await?
622 .ok_or(EthApiError::HeaderNotFound(block_id))?;
623
624 self.debug_execution_witness_for_block(block, mode.unwrap_or_default()).await
625 }
626
627 pub async fn debug_execution_witness_for_block(
629 &self,
630 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
631 mode: ExecutionWitnessMode,
632 ) -> Result<ExecutionWitness, Eth::Error> {
633 let block_number = block.header().number();
634 self.eth_api()
635 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
636 let block_executor = eth_api.evm_config().executor(&mut db);
637
638 let mut witness = None;
639 let _ = block_executor
640 .execute_with_state_closure(&block, |statedb: &State<_>| {
641 witness = Some(
642 ExecutionWitnessRecord::new(statedb)
643 .into_execution_witness::<StateProviderBox, _>(
644 &statedb.database.database,
645 eth_api.provider(),
646 block_number,
647 mode,
648 ),
649 );
650 })
651 .map_err(|err| EthApiError::Internal(err.into()))?;
652
653 Ok(witness
654 .expect("state closure is called after successful execution")
655 .map_err(EthApiError::from)?)
656 })
657 .await
658 }
659
660 pub async fn debug_account_at(
663 &self,
664 block_id: BlockId,
665 tx_index: Index,
666 address: Address,
667 ) -> Result<Option<Account>, Eth::Error> {
668 self.replay_block_until(block_id, tx_index, move |db| Self::account(db, address))
669 .await
670 .map(Option::flatten)
671 }
672
673 pub async fn debug_account_info_at(
676 &self,
677 block_id: BlockId,
678 tx_index: Index,
679 address: Address,
680 ) -> Result<Option<AccountInfo>, Eth::Error> {
681 self.replay_block_until(block_id, tx_index, move |db| Self::account_info(db, address)).await
682 }
683
684 async fn replay_block_until<F, R>(
687 &self,
688 block_id: BlockId,
689 tx_index: Index,
690 f: F,
691 ) -> Result<Option<R>, Eth::Error>
692 where
693 F: FnOnce(&mut StateCacheDb) -> Result<R, Eth::Error> + Send + 'static,
694 R: Send + 'static,
695 {
696 let block = self
697 .eth_api()
698 .recovered_block(block_id)
699 .await?
700 .ok_or(EthApiError::HeaderNotFound(block_id))?;
701 let tx_index = usize::from(tx_index);
702 let transaction_count = block.transaction_count();
703 if tx_index >= transaction_count {
704 return Err(EthApiError::InvalidParams(format!(
705 "tx_index {tx_index} out of bounds for block with {transaction_count} transactions"
706 ))
707 .into())
708 }
709
710 self.eth_api()
711 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
712 let mut executor = eth_api
713 .evm_config()
714 .executor_for_block(&mut db, block.sealed_block())
715 .map_err(RethError::other)
716 .map_err(Eth::Error::from_eth_err)?;
717 executor.apply_pre_execution_changes().map_err(Eth::Error::from_eth_err)?;
718
719 for tx in block.transactions_recovered().take(tx_index + 1) {
720 if is_cancelled() {
721 return Err(EthApiError::InternalEthError.into())
722 }
723 executor.execute_transaction(tx).map_err(Eth::Error::from_eth_err)?;
724 }
725 drop(executor);
726
727 f(&mut db)
728 })
729 .await
730 .map(Some)
731 }
732
733 fn account(db: &mut StateCacheDb, address: Address) -> Result<Option<Account>, Eth::Error> {
735 let account = db.basic(address).map_err(Eth::Error::from_eth_err)?;
736 let Some(account) = account else { return Ok(None) };
737
738 let (hashed_storage, status) = db
739 .cache
740 .accounts
741 .get(&address)
742 .and_then(|account| {
743 account.account.as_ref().map(|plain_account| {
744 (HashedStorage::from_plain_storage(&plain_account.storage), account.status)
745 })
746 })
747 .unwrap_or_default();
748 let storage_root = if status.was_destroyed() {
749 storage_root_unsorted(
752 hashed_storage.storage.into_iter().filter(|(_, value)| !value.is_zero()),
753 )
754 } else {
755 db.database.storage_root(address, hashed_storage).map_err(Eth::Error::from_eth_err)?
756 };
757
758 Ok(Some(reth_primitives_traits::Account::from(account).into_trie_account(storage_root)))
759 }
760
761 #[allow(clippy::needless_update)]
763 fn account_info<DB>(db: &mut DB, address: Address) -> Result<AccountInfo, Eth::Error>
764 where
765 DB: Database,
766 EthApiError: From<DB::Error>,
767 {
768 let account = db.basic(address).map_err(Eth::Error::from_eth_err)?.unwrap_or_default();
769 let code = if account.code_hash == KECCAK_EMPTY {
770 Default::default()
771 } else if let Some(code) = account.code {
772 code.original_bytes()
773 } else {
774 db.code_by_hash(account.code_hash).map_err(Eth::Error::from_eth_err)?.original_bytes()
775 };
776
777 Ok(AccountInfo {
778 balance: account.balance,
779 nonce: account.nonce,
780 code,
781 #[cfg(feature = "account-ext")]
782 extension: reth_primitives_traits::AccountExtension::from_shared(
783 account.extension.into_shared(),
784 ),
785 ..Default::default()
786 })
787 }
788
789 pub async fn debug_code_by_hash(
792 &self,
793 hash: B256,
794 block_id: Option<BlockId>,
795 ) -> Result<Option<Bytes>, Eth::Error> {
796 Ok(self
797 .provider()
798 .state_by_block_id(block_id.unwrap_or_default())
799 .map_err(Eth::Error::from_eth_err)?
800 .bytecode_by_hash(&hash)
801 .map_err(Eth::Error::from_eth_err)?
802 .map(|b| b.original_bytes()))
803 }
804
805 async fn debug_state_root_with_updates(
808 &self,
809 hashed_state: HashedPostState,
810 block_id: Option<BlockId>,
811 ) -> Result<(B256, TrieUpdates), Eth::Error> {
812 self.inner
813 .eth_api
814 .spawn_blocking_io(move |this| {
815 let state = this
816 .provider()
817 .state_by_block_id(block_id.unwrap_or_default())
818 .map_err(Eth::Error::from_eth_err)?;
819 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
820 })
821 .await
822 }
823
824 pub async fn intermediate_roots(&self, block_hash: B256) -> Result<Vec<B256>, Eth::Error> {
826 let block = self
827 .eth_api()
828 .recovered_block(block_hash.into())
829 .await?
830 .ok_or(EthApiError::HeaderNotFound(block_hash.into()))?;
831 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
832
833 self.eth_api()
834 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
835 db.transition_state = Some(Default::default());
837
838 eth_api.apply_pre_execution_changes(&block, &mut db)?;
839
840 let mut roots = Vec::with_capacity(block.body().transactions().len());
841 let mut evm = eth_api.evm_config().evm_with_env(&mut db, evm_env);
842 for tx in block.transactions_recovered() {
843 if is_cancelled() {
844 return Err(EthApiError::InternalEthError.into())
845 }
846 let tx_env = eth_api.evm_config().tx_env(tx);
847 evm.transact_commit(tx_env).map_err(Eth::Error::from_evm_err)?;
848
849 let state = evm.db_mut();
850 state.merge_transitions(BundleRetention::PlainState);
852 let hashed_state = state
854 .database
855 .hashed_post_state(&state.bundle_state)
856 .map_err(Eth::Error::from_eth_err)?;
857 let root = state
858 .database
859 .state_root(hashed_state)
860 .map_err(Eth::Error::from_eth_err)?;
861 roots.push(root);
862 }
863
864 Ok(roots)
865 })
866 .await
867 }
868}
869
870#[async_trait]
871impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
872where
873 Eth: EthTransactions + TraceExt,
874{
875 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
877 let header = match block_id {
878 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
879 BlockId::Number(number_or_tag) => {
880 let number = self
881 .provider()
882 .convert_block_number(number_or_tag)
883 .to_rpc_result()?
884 .ok_or(EthApiError::HeaderNotFound(block_id))?;
885 self.provider().header_by_number(number).to_rpc_result()?
886 }
887 }
888 .ok_or(EthApiError::HeaderNotFound(block_id))?;
889
890 let mut res = Vec::new();
891 header.encode(&mut res);
892 Ok(res.into())
893 }
894
895 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
897 let block = self
898 .provider()
899 .block_by_id(block_id)
900 .to_rpc_result()?
901 .ok_or(EthApiError::HeaderNotFound(block_id))?;
902 let mut res = Vec::new();
903 block.encode(&mut res);
904 Ok(res.into())
905 }
906
907 async fn raw_block_access_list(&self, block_id: BlockId) -> RpcResult<Bytes> {
909 self.eth_api()
910 .get_raw_block_access_list(block_id)
911 .await
912 .map_err(Into::into)?
913 .ok_or_else(|| EthApiError::HeaderNotFound(block_id).into())
914 }
915
916 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
922 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
923 }
924
925 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
928 let block: RecoveredBlock<BlockTy<Eth::Primitives>> = self
929 .provider()
930 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
931 .to_rpc_result()?
932 .unwrap_or_default();
933 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
934 }
935
936 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
938 Ok(self
939 .provider()
940 .receipts_by_block_id(block_id)
941 .to_rpc_result()?
942 .ok_or(EthApiError::HeaderNotFound(block_id))?
943 .into_iter()
944 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
945 .collect())
946 }
947
948 async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>> {
950 let entries = self.inner.bad_block_store.all();
951 let mut bad_blocks = Vec::with_capacity(entries.len());
952
953 #[derive(Serialize, Deserialize)]
954 struct BadBlockSerde<T> {
955 block: T,
956 hash: B256,
957 rlp: Bytes,
958 reason: String,
959 }
960
961 for entry in entries {
962 let rlp = Bytes::from(alloy_rlp::encode(entry.block.sealed_block()));
963 let hash = entry.block.hash();
964
965 let block = entry
966 .block
967 .clone_into_rpc_block(
968 BlockTransactionsKind::Full,
969 |tx, tx_info| self.eth_api().converter().fill(tx, tx_info),
970 |header, block_size| {
971 self.eth_api().converter().convert_header(header, Some(block_size))
972 },
973 )
974 .map_err(|err| Eth::Error::from(err).into())?;
975
976 let bad_block =
977 serde_json::to_value(BadBlockSerde { block, hash, rlp, reason: entry.reason })
978 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
979
980 bad_blocks.push(bad_block);
981 }
982
983 Ok(bad_blocks)
984 }
985
986 async fn debug_clear_txpool(&self) -> RpcResult<()> {
988 let pool = self.eth_api().pool();
989 let all_hashes = pool.all_transaction_hashes();
990 let _ = pool.remove_transactions(all_hashes);
991 Ok(())
992 }
993
994 async fn debug_subscribe(
996 &self,
997 pending: PendingSubscriptionSink,
998 subscription: String,
999 start_exclusive: BlockNumberOrTag,
1000 end_inclusive: BlockNumberOrTag,
1001 opts: Option<GethDebugTracingOptions>,
1002 ) -> jsonrpsee::core::SubscriptionResult {
1003 if subscription != "traceChain" {
1004 pending
1005 .reject(EthApiError::InvalidParams(format!(
1006 "unsupported debug subscription: {subscription}"
1007 )))
1008 .await;
1009 return Ok(())
1010 }
1011
1012 let start_id = BlockId::Number(start_exclusive);
1013 let start = match self.eth_api().recovered_block(start_id).await {
1014 Ok(Some(block)) => block,
1015 Ok(None) => {
1016 pending.reject(EthApiError::TracingBlockNotFound(start_id)).await;
1017 return Ok(())
1018 }
1019 Err(err) => {
1020 pending.reject(err).await;
1021 return Ok(())
1022 }
1023 };
1024 let end_id = BlockId::Number(end_inclusive);
1025 let end = match self.eth_api().recovered_block(end_id).await {
1026 Ok(Some(block)) => block,
1027 Ok(None) => {
1028 pending.reject(EthApiError::TracingBlockNotFound(end_id)).await;
1029 return Ok(())
1030 }
1031 Err(err) => {
1032 pending.reject(err).await;
1033 return Ok(())
1034 }
1035 };
1036
1037 if start.number() >= end.number() {
1038 pending
1039 .reject(EthApiError::InvalidParams(format!(
1040 "end block (#{}) needs to come after start block (#{})",
1041 end.number(),
1042 start.number()
1043 )))
1044 .await;
1045 return Ok(())
1046 }
1047
1048 let sink = pending.accept().await?;
1049 let this = self.clone();
1050 let task_spawner = self.inner.task_spawner.clone();
1051 task_spawner.spawn_task(async move {
1052 let end_number = end.number();
1053 let opts = opts.unwrap_or_default();
1054
1055 for number in (start.number() + 1)..=end_number {
1056 if sink.is_closed() {
1057 break
1058 }
1059
1060 let block_id = BlockId::Number(number.into());
1061 let block = match this.eth_api().recovered_block(block_id).await {
1062 Ok(Some(block)) => block,
1063 Ok(None) => {
1064 tracing::warn!(target: "rpc::debug", %number, "Chain tracing block not found");
1065 break
1066 }
1067 Err(err) => {
1068 tracing::warn!(target: "rpc::debug", %number, %err, "Failed to load chain tracing block");
1069 break
1070 }
1071 };
1072 let permit = tokio::select! {
1073 _ = sink.closed() => break,
1074 permit = this.acquire_trace_permit() => match permit {
1075 Ok(permit) => permit,
1076 Err(err) => {
1077 tracing::debug!(target: "rpc::debug", %err, "Failed to acquire trace permit");
1078 break
1079 }
1080 }
1081 };
1082 if sink.is_closed() {
1083 break
1084 }
1085 let traces = match this.trace_chain_block(block.clone(), opts.clone()).await {
1086 Ok(traces) => traces,
1087 Err(err) => {
1088 tracing::warn!(target: "rpc::debug", %number, %err, "Failed to trace chain block");
1089 break
1090 }
1091 };
1092 drop(permit);
1093
1094 if traces.is_empty() && number != end_number {
1095 continue
1096 }
1097 let result = ChainBlockTraceResult {
1098 block: U256::from(number),
1099 hash: block.hash(),
1100 traces,
1101 };
1102 let message = match SubscriptionMessage::new(
1103 sink.method_name(),
1104 sink.subscription_id(),
1105 &result,
1106 ) {
1107 Ok(message) => message,
1108 Err(err) => {
1109 tracing::warn!(target: "rpc::debug", %number, %err, "Failed to serialize chain trace");
1110 break
1111 }
1112 };
1113 if sink.send(message).await.is_err() {
1114 break
1115 }
1116 }
1117
1118 sink.closed().await;
1122 });
1123
1124 Ok(())
1125 }
1126
1127 async fn debug_trace_block(
1129 &self,
1130 rlp_block: Bytes,
1131 opts: Option<GethDebugTracingOptions>,
1132 ) -> RpcResult<Vec<TraceResult>> {
1133 let _permit = self.acquire_trace_permit().await;
1134 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
1135 .await
1136 .map_err(Into::into)
1137 }
1138
1139 async fn debug_trace_block_by_hash(
1141 &self,
1142 block: B256,
1143 opts: Option<GethDebugTracingOptions>,
1144 ) -> RpcResult<Vec<TraceResult>> {
1145 let _permit = self.acquire_trace_permit().await;
1146 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
1147 .await
1148 .map_err(Into::into)
1149 }
1150
1151 async fn debug_trace_block_by_number(
1153 &self,
1154 block: BlockNumberOrTag,
1155 opts: Option<GethDebugTracingOptions>,
1156 ) -> RpcResult<Vec<TraceResult>> {
1157 let _permit = self.acquire_trace_permit().await;
1158 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
1159 .await
1160 .map_err(Into::into)
1161 }
1162
1163 async fn debug_trace_transaction(
1165 &self,
1166 tx_hash: B256,
1167 opts: Option<GethDebugTracingOptions>,
1168 ) -> RpcResult<GethTrace> {
1169 let _permit = self.acquire_trace_permit().await;
1170 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
1171 .await
1172 .map_err(Into::into)
1173 }
1174
1175 async fn debug_trace_call(
1177 &self,
1178 request: RpcTxReq<Eth::NetworkTypes>,
1179 block_id: Option<BlockId>,
1180 opts: Option<GethDebugTracingCallOptions>,
1181 ) -> RpcResult<GethTrace> {
1182 let _permit = self.acquire_trace_permit().await;
1183 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
1184 .await
1185 .map_err(Into::into)
1186 }
1187
1188 async fn debug_trace_call_many(
1189 &self,
1190 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
1191 state_context: Option<StateContext>,
1192 opts: Option<GethDebugTracingCallOptions>,
1193 ) -> RpcResult<Vec<Vec<GethTrace>>> {
1194 let _permit = self.acquire_trace_permit().await;
1195 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
1196 }
1197
1198 async fn debug_execution_witness(
1200 &self,
1201 block: BlockId,
1202 mode: Option<ExecutionWitnessMode>,
1203 ) -> RpcResult<ExecutionWitness> {
1204 let _permit = self.acquire_trace_permit().await;
1205 Self::debug_execution_witness(self, block, mode).await.map_err(Into::into)
1206 }
1207
1208 async fn debug_execution_witness_by_block_hash(
1210 &self,
1211 hash: B256,
1212 mode: Option<ExecutionWitnessMode>,
1213 ) -> RpcResult<ExecutionWitness> {
1214 let _permit = self.acquire_trace_permit().await;
1215 Self::debug_execution_witness_by_block_hash(self, hash, mode).await.map_err(Into::into)
1216 }
1217
1218 async fn debug_account_at(
1220 &self,
1221 block_id: BlockId,
1222 tx_index: Index,
1223 address: Address,
1224 ) -> RpcResult<Option<Account>> {
1225 let _permit = self.acquire_trace_permit().await;
1226 Self::debug_account_at(self, block_id, tx_index, address).await.map_err(Into::into)
1227 }
1228
1229 async fn debug_account_info_at(
1231 &self,
1232 block_id: BlockId,
1233 tx_index: Index,
1234 address: Address,
1235 ) -> RpcResult<Option<AccountInfo>> {
1236 let _permit = self.acquire_trace_permit().await;
1237 Self::debug_account_info_at(self, block_id, tx_index, address).await.map_err(Into::into)
1238 }
1239
1240 async fn debug_account_range(
1241 &self,
1242 _block_number: BlockNumberOrTag,
1243 _start: Bytes,
1244 _max_results: u64,
1245 _nocode: bool,
1246 _nostorage: bool,
1247 _incompletes: bool,
1248 ) -> RpcResult<()> {
1249 Ok(())
1250 }
1251
1252 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
1253 Ok(())
1254 }
1255
1256 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
1257 Ok(crate::chain_config::chain_config(&*self.provider().chain_spec()))
1258 }
1259
1260 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
1261 Ok(())
1262 }
1263
1264 async fn debug_code_by_hash(
1265 &self,
1266 hash: B256,
1267 block_id: Option<BlockId>,
1268 ) -> RpcResult<Option<Bytes>> {
1269 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
1270 }
1271
1272 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
1273 Ok(())
1274 }
1275
1276 async fn debug_db_ancients(&self) -> RpcResult<()> {
1277 Ok(())
1278 }
1279
1280 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
1291 let key_bytes = if key.starts_with("0x") {
1292 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
1293 } else {
1294 key.into_bytes()
1295 };
1296
1297 if key_bytes.len() != 33 {
1298 return Err(EthApiError::InvalidParams(format!(
1299 "Key must be 33 bytes, got {}",
1300 key_bytes.len()
1301 ))
1302 .into());
1303 }
1304 if key_bytes[0] != 0x63 {
1305 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
1306 }
1307
1308 let code_hash = B256::from_slice(&key_bytes[1..33]);
1309
1310 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
1312 }
1313
1314 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
1315 Ok(())
1316 }
1317
1318 async fn debug_free_os_memory(&self) -> RpcResult<()> {
1319 Ok(())
1320 }
1321
1322 async fn debug_gc_stats(&self) -> RpcResult<()> {
1323 Ok(())
1324 }
1325
1326 async fn debug_get_accessible_state(
1327 &self,
1328 _from: BlockNumberOrTag,
1329 _to: BlockNumberOrTag,
1330 ) -> RpcResult<()> {
1331 Ok(())
1332 }
1333
1334 async fn debug_get_modified_accounts_by_hash(
1335 &self,
1336 _start_hash: B256,
1337 _end_hash: B256,
1338 ) -> RpcResult<()> {
1339 Ok(())
1340 }
1341
1342 async fn debug_get_modified_accounts_by_number(
1343 &self,
1344 _start_number: u64,
1345 _end_number: u64,
1346 ) -> RpcResult<()> {
1347 Ok(())
1348 }
1349
1350 async fn debug_intermediate_roots(
1351 &self,
1352 block_hash: B256,
1353 _opts: Option<GethDebugTracingCallOptions>,
1354 ) -> RpcResult<Vec<B256>> {
1355 let _permit = self.acquire_trace_permit().await;
1356 self.intermediate_roots(block_hash).await.map_err(Into::into)
1357 }
1358
1359 async fn debug_mem_stats(&self) -> RpcResult<()> {
1360 Ok(())
1361 }
1362
1363 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
1364 Ok(())
1365 }
1366
1367 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
1368 Ok(())
1369 }
1370
1371 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
1372 Ok(Default::default())
1373 }
1374
1375 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
1376 Ok(())
1377 }
1378
1379 async fn debug_set_head(&self, _number: U64) -> RpcResult<()> {
1380 Ok(())
1381 }
1382
1383 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1384 Ok(())
1385 }
1386
1387 async fn debug_standard_trace_bad_block_to_file(
1388 &self,
1389 _block: BlockNumberOrTag,
1390 _opts: Option<GethDebugTracingCallOptions>,
1391 ) -> RpcResult<()> {
1392 Ok(())
1393 }
1394
1395 async fn debug_standard_trace_block_to_file(
1396 &self,
1397 _block: BlockNumberOrTag,
1398 _opts: Option<GethDebugTracingCallOptions>,
1399 ) -> RpcResult<()> {
1400 Ok(())
1401 }
1402
1403 async fn debug_state_root_with_updates(
1404 &self,
1405 hashed_state: HashedPostState,
1406 block_id: Option<BlockId>,
1407 ) -> RpcResult<(B256, TrieUpdates)> {
1408 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1409 }
1410
1411 async fn debug_storage_range_at(
1412 &self,
1413 _block_hash: B256,
1414 _tx_idx: usize,
1415 _contract_address: Address,
1416 _key_start: B256,
1417 _max_result: u64,
1418 ) -> RpcResult<()> {
1419 Ok(())
1420 }
1421
1422 async fn debug_trace_bad_block(
1423 &self,
1424 block_hash: B256,
1425 opts: Option<GethDebugTracingCallOptions>,
1426 ) -> RpcResult<Vec<TraceResult>> {
1427 let _permit = self.acquire_trace_permit().await;
1428 let entry = self
1429 .inner
1430 .bad_block_store
1431 .get(block_hash)
1432 .ok_or_else(|| internal_rpc_err("bad block not found in cache"))?;
1433
1434 let evm_env = self
1435 .eth_api()
1436 .evm_config()
1437 .evm_env(entry.block.header())
1438 .map_err(RethError::other)
1439 .to_rpc_result()?;
1440
1441 let opts = opts.map(|o| o.tracing_options).unwrap_or_default();
1442 self.trace_block(entry.block.clone(), evm_env, opts).await.map_err(Into::into)
1443 }
1444}
1445
1446impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1447 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1448 f.debug_struct("DebugApi").finish_non_exhaustive()
1449 }
1450}
1451
1452impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1453 fn clone(&self) -> Self {
1454 Self { inner: Arc::clone(&self.inner) }
1455 }
1456}
1457
1458struct DebugApiInner<Eth: RpcNodeCore> {
1459 eth_api: Eth,
1461 blocking_task_guard: BlockingTaskGuard,
1463 task_spawner: Runtime,
1465 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1467}
1468
1469#[derive(Clone, Debug)]
1471struct BadBlockStore<B: BlockTrait> {
1472 inner: Arc<RwLock<VecDeque<BadBlockEntry<B>>>>,
1473 limit: usize,
1474}
1475
1476#[derive(Clone, Debug)]
1478struct BadBlockEntry<B: BlockTrait> {
1479 block: Arc<RecoveredBlock<B>>,
1480 reason: String,
1481}
1482
1483impl<B: BlockTrait> BadBlockStore<B> {
1484 fn new(limit: usize) -> Self {
1486 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1487 }
1488
1489 fn insert(&self, block: RecoveredBlock<B>, reason: String) {
1492 let hash = block.hash();
1493 let mut guard = self.inner.write();
1494
1495 if guard.iter().any(|entry| entry.block.hash() == hash) {
1497 return;
1498 }
1499 guard.push_back(BadBlockEntry { block: Arc::new(block), reason });
1500
1501 while guard.len() > self.limit {
1502 guard.pop_front();
1503 }
1504 }
1505
1506 fn all(&self) -> Vec<BadBlockEntry<B>> {
1508 let guard = self.inner.read();
1509 guard.iter().rev().cloned().collect()
1510 }
1511
1512 fn get(&self, hash: B256) -> Option<BadBlockEntry<B>> {
1514 let guard = self.inner.read();
1515 guard.iter().find(|entry| entry.block.hash() == hash).cloned()
1516 }
1517}
1518
1519impl<B: BlockTrait> Default for BadBlockStore<B> {
1520 fn default() -> Self {
1521 Self::new(64)
1522 }
1523}
1524
1525#[cfg(test)]
1526mod tests {
1527 use super::*;
1528 use crate::{eth::helpers::types::EthRpcConverter, EthApi};
1529 use alloy_primitives::{keccak256, U256};
1530 use reth_chainspec::ChainSpec;
1531 use reth_db_api::{tables, transaction::DbTxMut};
1532 use reth_evm_ethereum::EthEvmConfig;
1533 use reth_network_api::noop::NoopNetwork;
1534 use reth_primitives_traits::StorageEntry;
1535 use reth_provider::test_utils::{create_test_provider_factory, NoopProvider};
1536 use reth_rpc_eth_api::EthApiServer;
1537 use reth_transaction_pool::test_utils::testing_pool;
1538 use revm::{
1539 database::{states::StorageSlot, AccountStatus, BundleAccount, BundleState},
1540 state::AccountInfo as RevmAccountInfo,
1541 };
1542
1543 #[tokio::test]
1544 async fn trace_call_out_of_range_block_error() {
1545 let eth_api = EthApi::<_, EthRpcConverter<ChainSpec>>::builder(
1546 NoopProvider::default(),
1547 testing_pool(),
1548 NoopNetwork::default(),
1549 EthEvmConfig::mainnet(),
1550 )
1551 .build();
1552 let debug_api = DebugApi::new(
1553 eth_api.clone(),
1554 BlockingTaskGuard::new(1),
1555 &Runtime::test(),
1556 futures::stream::empty(),
1557 );
1558 let block_id = BlockId::number(0xfffffffff);
1559 for tx_index in [None, Some(0)] {
1560 let mut opts: GethDebugTracingCallOptions =
1561 serde_json::from_value(serde_json::json!({ "tracer": "callTracer" })).unwrap();
1562 opts.tx_index = tx_index;
1563 let err = DebugApiServer::debug_trace_call(
1564 &debug_api,
1565 Default::default(),
1566 Some(block_id),
1567 Some(opts),
1568 )
1569 .await
1570 .unwrap_err();
1571 assert_eq!(err.code(), -32000);
1572 assert!(err.message().contains("not found"));
1573 }
1574
1575 let err = EthApiServer::call(ð_api, Default::default(), Some(block_id), None, None)
1576 .await
1577 .unwrap_err();
1578 assert_eq!(err.code(), -32001);
1579 }
1580
1581 #[test]
1582 fn hashed_post_state_zeroes_destroyed_account_parent_storage() {
1583 let factory = create_test_provider_factory();
1584 let address = Address::with_last_byte(1);
1585 let old_slot = U256::from(1);
1586 let new_slot = U256::from(2);
1587 let old_value = U256::from(10);
1588 let new_value = U256::from(20);
1589 let hashed_address = keccak256(address);
1590 let hashed_old_slot = keccak256(B256::from(old_slot));
1591 let hashed_new_slot = keccak256(B256::from(new_slot));
1592
1593 let provider_rw = factory.provider_rw().unwrap();
1594 provider_rw
1595 .tx_ref()
1596 .put::<tables::HashedStorages>(
1597 hashed_address,
1598 StorageEntry { key: hashed_old_slot, value: old_value },
1599 )
1600 .unwrap();
1601 provider_rw.commit().unwrap();
1602
1603 let mut bundle_state = BundleState::default();
1604 bundle_state.state.insert(
1605 address,
1606 BundleAccount::new(
1607 Some(RevmAccountInfo::default()),
1608 Some(RevmAccountInfo::default()),
1609 std::iter::once((new_slot, StorageSlot::new_changed(U256::ZERO, new_value)))
1610 .collect(),
1611 AccountStatus::DestroyedChanged,
1612 ),
1613 );
1614
1615 let provider = factory.latest().unwrap();
1616 let hashed_state = provider.hashed_post_state(&bundle_state).unwrap();
1617 let storage = &hashed_state.storages[&hashed_address];
1618
1619 assert_eq!(storage.storage[&hashed_old_slot], U256::ZERO);
1620 assert_eq!(storage.storage[&hashed_new_slot], new_value);
1621 }
1622}