1use alloy_consensus::{transaction::TxHashRef, BlockHeader};
2use alloy_eip7928::BlockAccessList;
3use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
4use alloy_evm::env::BlockEnvironment;
5use alloy_genesis::ChainConfig;
6use alloy_primitives::{hex::decode, uint, Address, Bytes, B256, U64};
7use alloy_rlp::{Decodable, Encodable};
8use alloy_rpc_types::BlockTransactionsKind;
9use alloy_rpc_types_debug::ExecutionWitness;
10use alloy_rpc_types_eth::{state::EvmOverrides, BlockError, Bundle, StateContext};
11use alloy_rpc_types_trace::geth::{
12 BlockTraceResult, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult,
13};
14use async_trait::async_trait;
15use futures::Stream;
16use jsonrpsee::core::RpcResult;
17use parking_lot::RwLock;
18use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
19use reth_engine_primitives::ConsensusEngineEvent;
20use reth_errors::RethError;
21use reth_evm::{execute::Executor, ConfigureEvm, EvmEnvFor};
22use reth_primitives_traits::{
23 Block as BlockTrait, BlockBody, BlockTy, ReceiptWithBloom, RecoveredBlock,
24};
25use reth_revm::{db::State, witness::ExecutionWitnessRecord};
26use reth_rpc_api::DebugApiServer;
27use reth_rpc_convert::RpcTxReq;
28use reth_rpc_eth_api::{
29 helpers::{EthTransactions, TraceExt},
30 FromEthApiError, RpcConvert, RpcNodeCore,
31};
32use reth_rpc_eth_types::EthApiError;
33use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
34use reth_storage_api::{
35 BlockIdReader, BlockReaderIdExt, HeaderProvider, ProviderBlock, ReceiptProviderIdExt,
36 StateProofProvider, StateProviderFactory, StateRootProvider, TransactionVariant,
37};
38use reth_tasks::{pool::BlockingTaskGuard, Runtime};
39use reth_trie_common::{updates::TrieUpdates, HashedPostState};
40use revm::DatabaseCommit;
41use revm_inspectors::tracing::{DebugInspector, TransactionContext};
42use serde::{Deserialize, Serialize};
43use std::{collections::VecDeque, sync::Arc};
44use tokio::sync::{AcquireError, OwnedSemaphorePermit};
45use tokio_stream::StreamExt;
46
47pub struct DebugApi<Eth: RpcNodeCore> {
51 inner: Arc<DebugApiInner<Eth>>,
52}
53
54impl<Eth> DebugApi<Eth>
55where
56 Eth: RpcNodeCore,
57{
58 pub fn new(
60 eth_api: Eth,
61 blocking_task_guard: BlockingTaskGuard,
62 executor: &Runtime,
63 mut stream: impl Stream<Item = ConsensusEngineEvent<Eth::Primitives>> + Send + Unpin + 'static,
64 ) -> Self {
65 let bad_block_store = BadBlockStore::default();
66 let inner = Arc::new(DebugApiInner {
67 eth_api,
68 blocking_task_guard,
69 bad_block_store: bad_block_store.clone(),
70 });
71
72 executor.spawn_task(async move {
74 while let Some(event) = stream.next().await {
75 if let ConsensusEngineEvent::InvalidBlock(block) = event &&
76 let Ok(recovered) =
77 RecoveredBlock::try_recover_sealed(block.as_ref().clone())
78 {
79 bad_block_store.insert(recovered);
80 }
81 }
82 });
83
84 Self { inner }
85 }
86
87 pub fn eth_api(&self) -> &Eth {
89 &self.inner.eth_api
90 }
91
92 pub fn provider(&self) -> &Eth::Provider {
94 self.inner.eth_api.provider()
95 }
96}
97
98impl<Eth> DebugApi<Eth>
101where
102 Eth: TraceExt,
103{
104 async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
106 self.inner.blocking_task_guard.clone().acquire_owned().await
107 }
108
109 async fn trace_block(
111 &self,
112 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
113 evm_env: EvmEnvFor<Eth::Evm>,
114 opts: GethDebugTracingOptions,
115 ) -> Result<Vec<TraceResult>, Eth::Error> {
116 self.eth_api()
117 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
118 let mut results = Vec::with_capacity(block.body().transactions().len());
119
120 eth_api.apply_pre_execution_changes(&block, &mut db)?;
121
122 let mut transactions = block.transactions_recovered().enumerate().peekable();
123 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
124 while let Some((index, tx)) = transactions.next() {
125 let tx_hash = *tx.tx_hash();
126 let tx_env = eth_api.evm_config().tx_env(tx);
127
128 let res = eth_api.inspect(
129 &mut db,
130 evm_env.clone(),
131 tx_env.clone(),
132 &mut inspector,
133 )?;
134 let result = inspector
135 .get_result(
136 Some(TransactionContext {
137 block_hash: Some(block.hash()),
138 tx_hash: Some(tx_hash),
139 tx_index: Some(index),
140 }),
141 &tx_env,
142 &evm_env.block_env,
143 &res,
144 &mut db,
145 )
146 .map_err(Eth::Error::from_eth_err)?;
147
148 results.push(TraceResult::Success { result, tx_hash: Some(tx_hash) });
149 if transactions.peek().is_some() {
150 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
151 db.commit(res.state)
154 }
155 }
156
157 Ok(results)
158 })
159 .await
160 }
161
162 pub async fn debug_trace_raw_block(
168 &self,
169 rlp_block: Bytes,
170 opts: GethDebugTracingOptions,
171 ) -> Result<Vec<TraceResult>, Eth::Error> {
172 let block: ProviderBlock<Eth::Provider> = Decodable::decode(&mut rlp_block.as_ref())
173 .map_err(BlockError::RlpDecodeRawBlock)
174 .map_err(Eth::Error::from_eth_err)?;
175
176 let evm_env = self
177 .eth_api()
178 .evm_config()
179 .evm_env(block.header())
180 .map_err(RethError::other)
181 .map_err(Eth::Error::from_eth_err)?;
182
183 let senders =
185 if self.provider().chain_spec().is_homestead_active_at_block(block.header().number()) {
186 block.body().recover_signers()
187 } else {
188 block.body().recover_signers_unchecked()
189 }
190 .map_err(Eth::Error::from_eth_err)?;
191
192 self.trace_block(Arc::new(block.into_recovered_with_signers(senders)), evm_env, opts).await
193 }
194
195 pub async fn debug_trace_block(
197 &self,
198 block_id: BlockId,
199 opts: GethDebugTracingOptions,
200 ) -> Result<Vec<TraceResult>, Eth::Error> {
201 let block_hash = self
202 .provider()
203 .block_hash_for_id(block_id)
204 .map_err(Eth::Error::from_eth_err)?
205 .ok_or(EthApiError::HeaderNotFound(block_id))?;
206
207 let block = self
208 .eth_api()
209 .recovered_block(block_hash.into())
210 .await?
211 .ok_or(EthApiError::HeaderNotFound(block_id))?;
212 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
213
214 self.trace_block(block, evm_env, opts).await
215 }
216
217 pub async fn debug_trace_transaction(
221 &self,
222 tx_hash: B256,
223 opts: GethDebugTracingOptions,
224 ) -> Result<GethTrace, Eth::Error> {
225 let (transaction, block) = match self.eth_api().transaction_and_block(tx_hash).await? {
226 None => return Err(EthApiError::TransactionNotFound.into()),
227 Some(res) => res,
228 };
229 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
230
231 let state_at: BlockId = block.parent_hash().into();
234 let block_hash = block.hash();
235
236 self.eth_api()
237 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
238 let block_txs = block.transactions_recovered();
239
240 let tx = transaction.into_recovered();
242
243 eth_api.apply_pre_execution_changes(&block, &mut db)?;
244
245 let index = eth_api.replay_transactions_until(
247 &mut db,
248 evm_env.clone(),
249 block_txs,
250 *tx.tx_hash(),
251 )?;
252
253 let tx_env = eth_api.evm_config().tx_env(&tx);
254
255 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
256 let res =
257 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
258 let trace = inspector
259 .get_result(
260 Some(TransactionContext {
261 block_hash: Some(block_hash),
262 tx_index: Some(index),
263 tx_hash: Some(*tx.tx_hash()),
264 }),
265 &tx_env,
266 &evm_env.block_env,
267 &res,
268 &mut db,
269 )
270 .map_err(Eth::Error::from_eth_err)?;
271
272 Ok(trace)
273 })
274 .await
275 }
276
277 pub async fn debug_trace_call(
287 &self,
288 call: RpcTxReq<Eth::NetworkTypes>,
289 block_id: Option<BlockId>,
290 opts: GethDebugTracingCallOptions,
291 ) -> Result<GethTrace, Eth::Error> {
292 let at = block_id.unwrap_or_default();
293 let GethDebugTracingCallOptions {
294 tracing_options,
295 state_overrides,
296 block_overrides,
297 tx_index,
298 } = opts;
299 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
300
301 if let Some(tx_idx) = tx_index {
303 return self
304 .debug_trace_call_at_tx_index(call, at, tx_idx as usize, tracing_options, overrides)
305 .await;
306 }
307
308 let this = self.clone();
309 self.eth_api()
310 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
311 let mut inspector =
312 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
313 let res = this.eth_api().inspect(
314 &mut *db,
315 evm_env.clone(),
316 tx_env.clone(),
317 &mut inspector,
318 )?;
319 let trace = inspector
320 .get_result(None, &tx_env, &evm_env.block_env, &res, db)
321 .map_err(Eth::Error::from_eth_err)?;
322 Ok(trace)
323 })
324 .await
325 }
326
327 async fn debug_trace_call_at_tx_index(
331 &self,
332 call: RpcTxReq<Eth::NetworkTypes>,
333 block_id: BlockId,
334 tx_index: usize,
335 tracing_options: GethDebugTracingOptions,
336 overrides: EvmOverrides,
337 ) -> Result<GethTrace, Eth::Error> {
338 let block = self
340 .eth_api()
341 .recovered_block(block_id)
342 .await?
343 .ok_or(EthApiError::HeaderNotFound(block_id))?;
344
345 if tx_index >= block.transaction_count() {
346 return Err(EthApiError::InvalidParams(format!(
348 "tx_index {} out of bounds for block with {} transactions",
349 tx_index,
350 block.transaction_count()
351 ))
352 .into())
353 }
354
355 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
356
357 let state_at = block.parent_hash();
359
360 self.eth_api()
361 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
362 eth_api.apply_pre_execution_changes(&block, &mut db)?;
364
365 eth_api.replay_transactions_until(
367 &mut db,
368 evm_env.clone(),
369 block.transactions_recovered(),
370 *block.body().transactions()[tx_index].tx_hash(),
371 )?;
372
373 let (evm_env, tx_env) =
375 eth_api.prepare_call_env(evm_env, call, &mut db, overrides)?;
376
377 let mut inspector =
378 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
379 let res =
380 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
381 let trace = inspector
382 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
383 .map_err(Eth::Error::from_eth_err)?;
384
385 Ok(trace)
386 })
387 .await
388 }
389
390 pub async fn debug_trace_call_many(
394 &self,
395 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
396 state_context: Option<StateContext>,
397 opts: Option<GethDebugTracingCallOptions>,
398 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
399 if bundles.is_empty() {
400 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
401 }
402
403 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
404 let transaction_index = transaction_index.unwrap_or_default();
405
406 let target_block = block_number.unwrap_or_default();
407 let block = self
408 .eth_api()
409 .recovered_block(target_block)
410 .await?
411 .ok_or(EthApiError::HeaderNotFound(target_block))?;
412 let mut evm_env =
413 self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
414
415 let opts = opts.unwrap_or_default();
416 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
417
418 let mut at = block.parent_hash();
421 let mut replay_block_txs = true;
422
423 let num_txs =
425 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
426 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
430 at = block.hash();
431 replay_block_txs = false;
432 }
433
434 self.eth_api()
435 .spawn_with_state_at_block(at, move |eth_api, mut db| {
436 let mut all_bundles = Vec::with_capacity(bundles.len());
438
439 if replay_block_txs {
440 eth_api.apply_pre_execution_changes(&block, &mut db)?;
443
444 let transactions = block.transactions_recovered().take(num_txs);
445
446 for tx in transactions {
448 let tx_env = eth_api.evm_config().tx_env(tx);
449 let res = eth_api.transact(&mut db, evm_env.clone(), tx_env)?;
450 db.commit(res.state);
451 }
452 }
453
454 let mut bundles = bundles.into_iter().peekable();
456 let mut inspector = DebugInspector::new(tracing_options.clone())
457 .map_err(Eth::Error::from_eth_err)?;
458 while let Some(bundle) = bundles.next() {
459 let mut results = Vec::with_capacity(bundle.transactions.len());
460 let Bundle { transactions, block_override } = bundle;
461
462 let block_overrides = block_override.map(Box::new);
463
464 let mut transactions = transactions.into_iter().peekable();
465 while let Some(tx) = transactions.next() {
466 let state_overrides = state_overrides.take();
468 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
469
470 let (evm_env, tx_env) =
471 eth_api.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
472
473 let res = eth_api.inspect(
474 &mut db,
475 evm_env.clone(),
476 tx_env.clone(),
477 &mut inspector,
478 )?;
479 let trace = inspector
480 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
481 .map_err(Eth::Error::from_eth_err)?;
482
483 if transactions.peek().is_some() || bundles.peek().is_some() {
486 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
487 db.commit(res.state);
488 }
489 results.push(trace);
490 }
491 evm_env.block_env.inner_mut().number += uint!(1_U256);
493 evm_env.block_env.inner_mut().timestamp += uint!(12_U256);
494
495 all_bundles.push(results);
496 }
497 Ok(all_bundles)
498 })
499 .await
500 }
501
502 pub async fn debug_execution_witness_by_block_hash(
505 &self,
506 hash: B256,
507 ) -> Result<ExecutionWitness, Eth::Error> {
508 let this = self.clone();
509 let block = this
510 .eth_api()
511 .recovered_block(hash.into())
512 .await?
513 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
514
515 self.debug_execution_witness_for_block(block).await
516 }
517
518 pub async fn debug_execution_witness(
523 &self,
524 block_id: BlockNumberOrTag,
525 ) -> Result<ExecutionWitness, Eth::Error> {
526 let this = self.clone();
527 let block = this
528 .eth_api()
529 .recovered_block(block_id.into())
530 .await?
531 .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;
532
533 self.debug_execution_witness_for_block(block).await
534 }
535
536 pub async fn debug_execution_witness_for_block(
538 &self,
539 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
540 ) -> Result<ExecutionWitness, Eth::Error> {
541 let block_number = block.header().number();
542
543 let (mut exec_witness, lowest_block_number) = self
544 .eth_api()
545 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
546 let block_executor = eth_api.evm_config().executor(&mut db);
547
548 let mut witness_record = ExecutionWitnessRecord::default();
549
550 let _ = block_executor
551 .execute_with_state_closure(&block, |statedb: &State<_>| {
552 witness_record.record_executed_state(statedb);
553 })
554 .map_err(|err| EthApiError::Internal(err.into()))?;
555
556 let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number } =
557 witness_record;
558
559 let state = db
560 .database
561 .0
562 .witness(Default::default(), hashed_state)
563 .map_err(EthApiError::from)?;
564 Ok((
565 ExecutionWitness { state, codes, keys, ..Default::default() },
566 lowest_block_number,
567 ))
568 })
569 .await?;
570
571 let smallest = match lowest_block_number {
572 Some(smallest) => smallest,
573 None => {
574 block_number.saturating_sub(1)
577 }
578 };
579
580 let range = smallest..block_number;
581 exec_witness.headers = self
582 .provider()
583 .headers_range(range)
584 .map_err(EthApiError::from)?
585 .into_iter()
586 .map(|header| {
587 let mut serialized_header = Vec::new();
588 header.encode(&mut serialized_header);
589 serialized_header.into()
590 })
591 .collect();
592
593 Ok(exec_witness)
594 }
595
596 pub async fn debug_code_by_hash(
599 &self,
600 hash: B256,
601 block_id: Option<BlockId>,
602 ) -> Result<Option<Bytes>, Eth::Error> {
603 Ok(self
604 .provider()
605 .state_by_block_id(block_id.unwrap_or_default())
606 .map_err(Eth::Error::from_eth_err)?
607 .bytecode_by_hash(&hash)
608 .map_err(Eth::Error::from_eth_err)?
609 .map(|b| b.original_bytes()))
610 }
611
612 async fn debug_state_root_with_updates(
615 &self,
616 hashed_state: HashedPostState,
617 block_id: Option<BlockId>,
618 ) -> Result<(B256, TrieUpdates), Eth::Error> {
619 self.inner
620 .eth_api
621 .spawn_blocking_io(move |this| {
622 let state = this
623 .provider()
624 .state_by_block_id(block_id.unwrap_or_default())
625 .map_err(Eth::Error::from_eth_err)?;
626 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
627 })
628 .await
629 }
630}
631
632#[async_trait]
633impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
634where
635 Eth: EthTransactions + TraceExt,
636{
637 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
639 let header = match block_id {
640 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
641 BlockId::Number(number_or_tag) => {
642 let number = self
643 .provider()
644 .convert_block_number(number_or_tag)
645 .to_rpc_result()?
646 .ok_or_else(|| {
647 internal_rpc_err("Pending block not supported".to_string())
648 })?;
649 self.provider().header_by_number(number).to_rpc_result()?
650 }
651 };
652
653 let mut res = Vec::new();
654 if let Some(header) = header {
655 header.encode(&mut res);
656 }
657
658 Ok(res.into())
659 }
660
661 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
663 let block = self
664 .provider()
665 .block_by_id(block_id)
666 .to_rpc_result()?
667 .ok_or(EthApiError::HeaderNotFound(block_id))?;
668 let mut res = Vec::new();
669 block.encode(&mut res);
670 Ok(res.into())
671 }
672
673 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
679 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
680 }
681
682 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
685 let block: RecoveredBlock<BlockTy<Eth::Primitives>> = self
686 .provider()
687 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
688 .to_rpc_result()?
689 .unwrap_or_default();
690 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
691 }
692
693 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
695 Ok(self
696 .provider()
697 .receipts_by_block_id(block_id)
698 .to_rpc_result()?
699 .unwrap_or_default()
700 .into_iter()
701 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
702 .collect())
703 }
704
705 async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>> {
707 let blocks = self.inner.bad_block_store.all();
708 let mut bad_blocks = Vec::with_capacity(blocks.len());
709
710 #[derive(Serialize, Deserialize)]
711 struct BadBlockSerde<T> {
712 block: T,
713 hash: B256,
714 rlp: Bytes,
715 }
716
717 for block in blocks {
718 let rlp = alloy_rlp::encode(block.sealed_block()).into();
719 let hash = block.hash();
720
721 let block = block
722 .clone_into_rpc_block(
723 BlockTransactionsKind::Full,
724 |tx, tx_info| self.eth_api().converter().fill(tx, tx_info),
725 |header, size| self.eth_api().converter().convert_header(header, size),
726 )
727 .map_err(|err| Eth::Error::from(err).into())?;
728
729 let bad_block = serde_json::to_value(BadBlockSerde { block, hash, rlp })
730 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
731
732 bad_blocks.push(bad_block);
733 }
734
735 Ok(bad_blocks)
736 }
737
738 async fn debug_trace_chain(
740 &self,
741 _start_exclusive: BlockNumberOrTag,
742 _end_inclusive: BlockNumberOrTag,
743 ) -> RpcResult<Vec<BlockTraceResult>> {
744 Err(internal_rpc_err("unimplemented"))
745 }
746
747 async fn debug_trace_block(
749 &self,
750 rlp_block: Bytes,
751 opts: Option<GethDebugTracingOptions>,
752 ) -> RpcResult<Vec<TraceResult>> {
753 let _permit = self.acquire_trace_permit().await;
754 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
755 .await
756 .map_err(Into::into)
757 }
758
759 async fn debug_trace_block_by_hash(
761 &self,
762 block: B256,
763 opts: Option<GethDebugTracingOptions>,
764 ) -> RpcResult<Vec<TraceResult>> {
765 let _permit = self.acquire_trace_permit().await;
766 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
767 .await
768 .map_err(Into::into)
769 }
770
771 async fn debug_trace_block_by_number(
773 &self,
774 block: BlockNumberOrTag,
775 opts: Option<GethDebugTracingOptions>,
776 ) -> RpcResult<Vec<TraceResult>> {
777 let _permit = self.acquire_trace_permit().await;
778 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
779 .await
780 .map_err(Into::into)
781 }
782
783 async fn debug_trace_transaction(
785 &self,
786 tx_hash: B256,
787 opts: Option<GethDebugTracingOptions>,
788 ) -> RpcResult<GethTrace> {
789 let _permit = self.acquire_trace_permit().await;
790 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
791 .await
792 .map_err(Into::into)
793 }
794
795 async fn debug_trace_call(
797 &self,
798 request: RpcTxReq<Eth::NetworkTypes>,
799 block_id: Option<BlockId>,
800 opts: Option<GethDebugTracingCallOptions>,
801 ) -> RpcResult<GethTrace> {
802 let _permit = self.acquire_trace_permit().await;
803 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
804 .await
805 .map_err(Into::into)
806 }
807
808 async fn debug_trace_call_many(
809 &self,
810 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
811 state_context: Option<StateContext>,
812 opts: Option<GethDebugTracingCallOptions>,
813 ) -> RpcResult<Vec<Vec<GethTrace>>> {
814 let _permit = self.acquire_trace_permit().await;
815 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
816 }
817
818 async fn debug_execution_witness(
820 &self,
821 block: BlockNumberOrTag,
822 ) -> RpcResult<ExecutionWitness> {
823 let _permit = self.acquire_trace_permit().await;
824 Self::debug_execution_witness(self, block).await.map_err(Into::into)
825 }
826
827 async fn debug_execution_witness_by_block_hash(
829 &self,
830 hash: B256,
831 ) -> RpcResult<ExecutionWitness> {
832 let _permit = self.acquire_trace_permit().await;
833 Self::debug_execution_witness_by_block_hash(self, hash).await.map_err(Into::into)
834 }
835
836 async fn debug_get_block_access_list(&self, _block_id: BlockId) -> RpcResult<BlockAccessList> {
837 Err(internal_rpc_err("unimplemented"))
838 }
839
840 async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> {
841 Ok(())
842 }
843
844 async fn debug_account_range(
845 &self,
846 _block_number: BlockNumberOrTag,
847 _start: Bytes,
848 _max_results: u64,
849 _nocode: bool,
850 _nostorage: bool,
851 _incompletes: bool,
852 ) -> RpcResult<()> {
853 Ok(())
854 }
855
856 async fn debug_block_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
857 Ok(())
858 }
859
860 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
861 Ok(())
862 }
863
864 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
865 Ok(self.provider().chain_spec().genesis().config.clone())
866 }
867
868 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
869 Ok(())
870 }
871
872 async fn debug_code_by_hash(
873 &self,
874 hash: B256,
875 block_id: Option<BlockId>,
876 ) -> RpcResult<Option<Bytes>> {
877 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
878 }
879
880 async fn debug_cpu_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
881 Ok(())
882 }
883
884 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
885 Ok(())
886 }
887
888 async fn debug_db_ancients(&self) -> RpcResult<()> {
889 Ok(())
890 }
891
892 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
903 let key_bytes = if key.starts_with("0x") {
904 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
905 } else {
906 key.into_bytes()
907 };
908
909 if key_bytes.len() != 33 {
910 return Err(EthApiError::InvalidParams(format!(
911 "Key must be 33 bytes, got {}",
912 key_bytes.len()
913 ))
914 .into());
915 }
916 if key_bytes[0] != 0x63 {
917 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
918 }
919
920 let code_hash = B256::from_slice(&key_bytes[1..33]);
921
922 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
924 }
925
926 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
927 Ok(())
928 }
929
930 async fn debug_free_os_memory(&self) -> RpcResult<()> {
931 Ok(())
932 }
933
934 async fn debug_freeze_client(&self, _node: String) -> RpcResult<()> {
935 Ok(())
936 }
937
938 async fn debug_gc_stats(&self) -> RpcResult<()> {
939 Ok(())
940 }
941
942 async fn debug_get_accessible_state(
943 &self,
944 _from: BlockNumberOrTag,
945 _to: BlockNumberOrTag,
946 ) -> RpcResult<()> {
947 Ok(())
948 }
949
950 async fn debug_get_modified_accounts_by_hash(
951 &self,
952 _start_hash: B256,
953 _end_hash: B256,
954 ) -> RpcResult<()> {
955 Ok(())
956 }
957
958 async fn debug_get_modified_accounts_by_number(
959 &self,
960 _start_number: u64,
961 _end_number: u64,
962 ) -> RpcResult<()> {
963 Ok(())
964 }
965
966 async fn debug_go_trace(&self, _file: String, _seconds: u64) -> RpcResult<()> {
967 Ok(())
968 }
969
970 async fn debug_intermediate_roots(
971 &self,
972 _block_hash: B256,
973 _opts: Option<GethDebugTracingCallOptions>,
974 ) -> RpcResult<()> {
975 Ok(())
976 }
977
978 async fn debug_mem_stats(&self) -> RpcResult<()> {
979 Ok(())
980 }
981
982 async fn debug_mutex_profile(&self, _file: String, _nsec: u64) -> RpcResult<()> {
983 Ok(())
984 }
985
986 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
987 Ok(())
988 }
989
990 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
991 Ok(())
992 }
993
994 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
995 Ok(Default::default())
996 }
997
998 async fn debug_set_block_profile_rate(&self, _rate: u64) -> RpcResult<()> {
999 Ok(())
1000 }
1001
1002 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
1003 Ok(())
1004 }
1005
1006 async fn debug_set_head(&self, _number: U64) -> RpcResult<()> {
1007 Ok(())
1008 }
1009
1010 async fn debug_set_mutex_profile_fraction(&self, _rate: i32) -> RpcResult<()> {
1011 Ok(())
1012 }
1013
1014 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1015 Ok(())
1016 }
1017
1018 async fn debug_stacks(&self) -> RpcResult<()> {
1019 Ok(())
1020 }
1021
1022 async fn debug_standard_trace_bad_block_to_file(
1023 &self,
1024 _block: BlockNumberOrTag,
1025 _opts: Option<GethDebugTracingCallOptions>,
1026 ) -> RpcResult<()> {
1027 Ok(())
1028 }
1029
1030 async fn debug_standard_trace_block_to_file(
1031 &self,
1032 _block: BlockNumberOrTag,
1033 _opts: Option<GethDebugTracingCallOptions>,
1034 ) -> RpcResult<()> {
1035 Ok(())
1036 }
1037
1038 async fn debug_start_cpu_profile(&self, _file: String) -> RpcResult<()> {
1039 Ok(())
1040 }
1041
1042 async fn debug_start_go_trace(&self, _file: String) -> RpcResult<()> {
1043 Ok(())
1044 }
1045
1046 async fn debug_state_root_with_updates(
1047 &self,
1048 hashed_state: HashedPostState,
1049 block_id: Option<BlockId>,
1050 ) -> RpcResult<(B256, TrieUpdates)> {
1051 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1052 }
1053
1054 async fn debug_stop_cpu_profile(&self) -> RpcResult<()> {
1055 Ok(())
1056 }
1057
1058 async fn debug_stop_go_trace(&self) -> RpcResult<()> {
1059 Ok(())
1060 }
1061
1062 async fn debug_storage_range_at(
1063 &self,
1064 _block_hash: B256,
1065 _tx_idx: usize,
1066 _contract_address: Address,
1067 _key_start: B256,
1068 _max_result: u64,
1069 ) -> RpcResult<()> {
1070 Ok(())
1071 }
1072
1073 async fn debug_trace_bad_block(
1074 &self,
1075 block_hash: B256,
1076 opts: Option<GethDebugTracingCallOptions>,
1077 ) -> RpcResult<Vec<TraceResult>> {
1078 let _permit = self.acquire_trace_permit().await;
1079 let block = self
1080 .inner
1081 .bad_block_store
1082 .get(block_hash)
1083 .ok_or_else(|| internal_rpc_err("bad block not found in cache"))?;
1084
1085 let evm_env = self
1086 .eth_api()
1087 .evm_config()
1088 .evm_env(block.header())
1089 .map_err(RethError::other)
1090 .to_rpc_result()?;
1091
1092 let opts = opts.map(|o| o.tracing_options).unwrap_or_default();
1093 self.trace_block(block, evm_env, opts).await.map_err(Into::into)
1094 }
1095
1096 async fn debug_verbosity(&self, level: usize) -> RpcResult<()> {
1097 reth_tracing::set_log_verbosity(level).map_err(internal_rpc_err)
1098 }
1099
1100 async fn debug_vmodule(&self, pattern: String) -> RpcResult<()> {
1101 reth_tracing::set_log_vmodule(&pattern).map_err(internal_rpc_err)
1102 }
1103
1104 async fn debug_write_block_profile(&self, _file: String) -> RpcResult<()> {
1105 Ok(())
1106 }
1107
1108 async fn debug_write_mem_profile(&self, _file: String) -> RpcResult<()> {
1109 Ok(())
1110 }
1111
1112 async fn debug_write_mutex_profile(&self, _file: String) -> RpcResult<()> {
1113 Ok(())
1114 }
1115}
1116
1117impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1119 f.debug_struct("DebugApi").finish_non_exhaustive()
1120 }
1121}
1122
1123impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1124 fn clone(&self) -> Self {
1125 Self { inner: Arc::clone(&self.inner) }
1126 }
1127}
1128
1129struct DebugApiInner<Eth: RpcNodeCore> {
1130 eth_api: Eth,
1132 blocking_task_guard: BlockingTaskGuard,
1134 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1136}
1137
1138#[derive(Clone, Debug)]
1140struct BadBlockStore<B: BlockTrait> {
1141 inner: Arc<RwLock<VecDeque<Arc<RecoveredBlock<B>>>>>,
1142 limit: usize,
1143}
1144
1145impl<B: BlockTrait> BadBlockStore<B> {
1146 fn new(limit: usize) -> Self {
1148 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1149 }
1150
1151 fn insert(&self, block: RecoveredBlock<B>) {
1154 let hash = block.hash();
1155 let mut guard = self.inner.write();
1156
1157 if guard.iter().any(|b| b.hash() == hash) {
1159 return;
1160 }
1161 guard.push_back(Arc::new(block));
1162
1163 while guard.len() > self.limit {
1164 guard.pop_front();
1165 }
1166 }
1167
1168 fn all(&self) -> Vec<Arc<RecoveredBlock<B>>> {
1170 let guard = self.inner.read();
1171 guard.iter().rev().cloned().collect()
1172 }
1173
1174 fn get(&self, hash: B256) -> Option<Arc<RecoveredBlock<B>>> {
1176 let guard = self.inner.read();
1177 guard.iter().find(|b| b.hash() == hash).cloned()
1178 }
1179}
1180
1181impl<B: BlockTrait> Default for BadBlockStore<B> {
1182 fn default() -> Self {
1183 Self::new(64)
1184 }
1185}