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