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