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) = RecoveredBlock::try_recover_sealed(*block)
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 = self
202 .eth_api()
203 .recovered_block(block_id)
204 .await?
205 .ok_or(EthApiError::HeaderNotFound(block_id))?;
206 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
207
208 self.trace_block(block, evm_env, opts).await
209 }
210
211 pub async fn debug_trace_transaction(
215 &self,
216 tx_hash: B256,
217 opts: GethDebugTracingOptions,
218 ) -> Result<GethTrace, Eth::Error> {
219 let (transaction, block) = match self.eth_api().transaction_and_block(tx_hash).await? {
220 None => return Err(EthApiError::TransactionNotFound.into()),
221 Some(res) => res,
222 };
223 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
224
225 let state_at: BlockId = block.parent_hash().into();
228 let block_hash = block.hash();
229
230 self.eth_api()
231 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
232 let block_txs = block.transactions_recovered();
233
234 let tx = transaction.into_recovered();
236
237 eth_api.apply_pre_execution_changes(&block, &mut db)?;
238
239 let index = eth_api.replay_transactions_until(
241 &mut db,
242 evm_env.clone(),
243 block_txs,
244 *tx.tx_hash(),
245 )?;
246
247 let tx_env = eth_api.evm_config().tx_env(&tx);
248
249 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
250 let res =
251 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
252 let trace = inspector
253 .get_result(
254 Some(TransactionContext {
255 block_hash: Some(block_hash),
256 tx_index: Some(index),
257 tx_hash: Some(*tx.tx_hash()),
258 }),
259 &tx_env,
260 &evm_env.block_env,
261 &res,
262 &mut db,
263 )
264 .map_err(Eth::Error::from_eth_err)?;
265
266 Ok(trace)
267 })
268 .await
269 }
270
271 pub async fn debug_trace_call(
281 &self,
282 call: RpcTxReq<Eth::NetworkTypes>,
283 block_id: Option<BlockId>,
284 opts: GethDebugTracingCallOptions,
285 ) -> Result<GethTrace, Eth::Error> {
286 let at = block_id.unwrap_or_default();
287 let GethDebugTracingCallOptions {
288 tracing_options,
289 state_overrides,
290 block_overrides,
291 tx_index,
292 } = opts;
293 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
294
295 if let Some(tx_idx) = tx_index {
297 return self
298 .debug_trace_call_at_tx_index(call, at, tx_idx as usize, tracing_options, overrides)
299 .await;
300 }
301
302 let this = self.clone();
303 self.eth_api()
304 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
305 let mut inspector =
306 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
307 let res = this.eth_api().inspect(
308 &mut *db,
309 evm_env.clone(),
310 tx_env.clone(),
311 &mut inspector,
312 )?;
313 let trace = inspector
314 .get_result(None, &tx_env, &evm_env.block_env, &res, db)
315 .map_err(Eth::Error::from_eth_err)?;
316 Ok(trace)
317 })
318 .await
319 }
320
321 async fn debug_trace_call_at_tx_index(
325 &self,
326 call: RpcTxReq<Eth::NetworkTypes>,
327 block_id: BlockId,
328 tx_index: usize,
329 tracing_options: GethDebugTracingOptions,
330 overrides: EvmOverrides,
331 ) -> Result<GethTrace, Eth::Error> {
332 let block = self
334 .eth_api()
335 .recovered_block(block_id)
336 .await?
337 .ok_or(EthApiError::HeaderNotFound(block_id))?;
338
339 if tx_index >= block.transaction_count() {
340 return Err(EthApiError::InvalidParams(format!(
342 "tx_index {} out of bounds for block with {} transactions",
343 tx_index,
344 block.transaction_count()
345 ))
346 .into())
347 }
348
349 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
350
351 let state_at = block.parent_hash();
353
354 self.eth_api()
355 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
356 eth_api.apply_pre_execution_changes(&block, &mut db)?;
358
359 eth_api.replay_transactions_until(
361 &mut db,
362 evm_env.clone(),
363 block.transactions_recovered(),
364 *block.body().transactions()[tx_index].tx_hash(),
365 )?;
366
367 let (evm_env, tx_env) =
369 eth_api.prepare_call_env(evm_env, call, &mut db, overrides)?;
370
371 let mut inspector =
372 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
373 let res =
374 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
375 let trace = inspector
376 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
377 .map_err(Eth::Error::from_eth_err)?;
378
379 Ok(trace)
380 })
381 .await
382 }
383
384 pub async fn debug_trace_call_many(
388 &self,
389 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
390 state_context: Option<StateContext>,
391 opts: Option<GethDebugTracingCallOptions>,
392 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
393 if bundles.is_empty() {
394 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
395 }
396
397 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
398 let transaction_index = transaction_index.unwrap_or_default();
399
400 let target_block = block_number.unwrap_or_default();
401 let block = self
402 .eth_api()
403 .recovered_block(target_block)
404 .await?
405 .ok_or(EthApiError::HeaderNotFound(target_block))?;
406 let mut evm_env =
407 self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
408
409 let opts = opts.unwrap_or_default();
410 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
411
412 let mut at = block.parent_hash();
415 let mut replay_block_txs = true;
416
417 let num_txs =
419 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
420 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
424 at = block.hash();
425 replay_block_txs = false;
426 }
427
428 self.eth_api()
429 .spawn_with_state_at_block(at, move |eth_api, mut db| {
430 let mut all_bundles = Vec::with_capacity(bundles.len());
432
433 if replay_block_txs {
434 eth_api.apply_pre_execution_changes(&block, &mut db)?;
437
438 let transactions = block.transactions_recovered().take(num_txs);
439
440 for tx in transactions {
442 let tx_env = eth_api.evm_config().tx_env(tx);
443 let res = eth_api.transact(&mut db, evm_env.clone(), tx_env)?;
444 db.commit(res.state);
445 }
446 }
447
448 let mut bundles = bundles.into_iter().peekable();
450 let mut inspector = DebugInspector::new(tracing_options.clone())
451 .map_err(Eth::Error::from_eth_err)?;
452 while let Some(bundle) = bundles.next() {
453 let mut results = Vec::with_capacity(bundle.transactions.len());
454 let Bundle { transactions, block_override } = bundle;
455
456 let block_overrides = block_override.map(Box::new);
457
458 let mut transactions = transactions.into_iter().peekable();
459 while let Some(tx) = transactions.next() {
460 let state_overrides = state_overrides.take();
462 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
463
464 let (evm_env, tx_env) =
465 eth_api.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
466
467 let res = eth_api.inspect(
468 &mut db,
469 evm_env.clone(),
470 tx_env.clone(),
471 &mut inspector,
472 )?;
473 let trace = inspector
474 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
475 .map_err(Eth::Error::from_eth_err)?;
476
477 if transactions.peek().is_some() || bundles.peek().is_some() {
480 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
481 db.commit(res.state);
482 }
483 results.push(trace);
484 }
485 evm_env.block_env.inner_mut().number += uint!(1_U256);
487 evm_env.block_env.inner_mut().timestamp += uint!(12_U256);
488
489 all_bundles.push(results);
490 }
491 Ok(all_bundles)
492 })
493 .await
494 }
495
496 pub async fn debug_execution_witness_by_block_hash(
499 &self,
500 hash: B256,
501 ) -> Result<ExecutionWitness, Eth::Error> {
502 let this = self.clone();
503 let block = this
504 .eth_api()
505 .recovered_block(hash.into())
506 .await?
507 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
508
509 self.debug_execution_witness_for_block(block).await
510 }
511
512 pub async fn debug_execution_witness(
517 &self,
518 block_id: BlockNumberOrTag,
519 ) -> Result<ExecutionWitness, Eth::Error> {
520 let this = self.clone();
521 let block = this
522 .eth_api()
523 .recovered_block(block_id.into())
524 .await?
525 .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;
526
527 self.debug_execution_witness_for_block(block).await
528 }
529
530 pub async fn debug_execution_witness_for_block(
532 &self,
533 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
534 ) -> Result<ExecutionWitness, Eth::Error> {
535 let block_number = block.header().number();
536
537 let (mut exec_witness, lowest_block_number) = self
538 .eth_api()
539 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
540 let block_executor = eth_api.evm_config().executor(&mut db);
541
542 let mut witness_record = ExecutionWitnessRecord::default();
543
544 let _ = block_executor
545 .execute_with_state_closure(&block, |statedb: &State<_>| {
546 witness_record.record_executed_state(statedb);
547 })
548 .map_err(|err| EthApiError::Internal(err.into()))?;
549
550 let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number } =
551 witness_record;
552
553 let state = db
554 .database
555 .0
556 .witness(Default::default(), hashed_state)
557 .map_err(EthApiError::from)?;
558 Ok((
559 ExecutionWitness { state, codes, keys, ..Default::default() },
560 lowest_block_number,
561 ))
562 })
563 .await?;
564
565 let smallest = match lowest_block_number {
566 Some(smallest) => smallest,
567 None => {
568 block_number.saturating_sub(1)
571 }
572 };
573
574 let range = smallest..block_number;
575 exec_witness.headers = self
576 .provider()
577 .headers_range(range)
578 .map_err(EthApiError::from)?
579 .into_iter()
580 .map(|header| {
581 let mut serialized_header = Vec::new();
582 header.encode(&mut serialized_header);
583 serialized_header.into()
584 })
585 .collect();
586
587 Ok(exec_witness)
588 }
589
590 pub async fn debug_code_by_hash(
593 &self,
594 hash: B256,
595 block_id: Option<BlockId>,
596 ) -> Result<Option<Bytes>, Eth::Error> {
597 Ok(self
598 .provider()
599 .state_by_block_id(block_id.unwrap_or_default())
600 .map_err(Eth::Error::from_eth_err)?
601 .bytecode_by_hash(&hash)
602 .map_err(Eth::Error::from_eth_err)?
603 .map(|b| b.original_bytes()))
604 }
605
606 async fn debug_state_root_with_updates(
609 &self,
610 hashed_state: HashedPostState,
611 block_id: Option<BlockId>,
612 ) -> Result<(B256, TrieUpdates), Eth::Error> {
613 self.inner
614 .eth_api
615 .spawn_blocking_io(move |this| {
616 let state = this
617 .provider()
618 .state_by_block_id(block_id.unwrap_or_default())
619 .map_err(Eth::Error::from_eth_err)?;
620 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
621 })
622 .await
623 }
624
625 pub async fn intermediate_roots(&self, block_hash: B256) -> Result<Vec<B256>, Eth::Error> {
627 let block = self
628 .eth_api()
629 .recovered_block(block_hash.into())
630 .await?
631 .ok_or(EthApiError::HeaderNotFound(block_hash.into()))?;
632 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
633
634 self.eth_api()
635 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
636 db.transition_state = Some(Default::default());
638
639 eth_api.apply_pre_execution_changes(&block, &mut db)?;
640
641 let mut roots = Vec::with_capacity(block.body().transactions().len());
642 for tx in block.transactions_recovered() {
643 let tx_env = eth_api.evm_config().tx_env(tx);
644 {
645 let mut evm = eth_api.evm_config().evm_with_env(&mut db, evm_env.clone());
646 evm.transact_commit(tx_env).map_err(Eth::Error::from_evm_err)?;
647 }
648 db.merge_transitions(BundleRetention::PlainState);
650 let hashed_state = db.database.hashed_post_state(&db.bundle_state);
652 let root =
653 db.database.state_root(hashed_state).map_err(Eth::Error::from_eth_err)?;
654 roots.push(root);
655 }
656
657 Ok(roots)
658 })
659 .await
660 }
661}
662
663#[async_trait]
664impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
665where
666 Eth: EthTransactions + TraceExt,
667{
668 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
670 let header = match block_id {
671 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
672 BlockId::Number(number_or_tag) => {
673 let number = self
674 .provider()
675 .convert_block_number(number_or_tag)
676 .to_rpc_result()?
677 .ok_or(EthApiError::HeaderNotFound(block_id))?;
678 self.provider().header_by_number(number).to_rpc_result()?
679 }
680 }
681 .ok_or(EthApiError::HeaderNotFound(block_id))?;
682
683 let mut res = Vec::new();
684 header.encode(&mut res);
685 Ok(res.into())
686 }
687
688 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
690 let block = self
691 .provider()
692 .block_by_id(block_id)
693 .to_rpc_result()?
694 .ok_or(EthApiError::HeaderNotFound(block_id))?;
695 let mut res = Vec::new();
696 block.encode(&mut res);
697 Ok(res.into())
698 }
699
700 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
706 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
707 }
708
709 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
712 let block: RecoveredBlock<BlockTy<Eth::Primitives>> = self
713 .provider()
714 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
715 .to_rpc_result()?
716 .unwrap_or_default();
717 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
718 }
719
720 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
722 Ok(self
723 .provider()
724 .receipts_by_block_id(block_id)
725 .to_rpc_result()?
726 .ok_or(EthApiError::HeaderNotFound(block_id))?
727 .into_iter()
728 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
729 .collect())
730 }
731
732 async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>> {
734 let blocks = self.inner.bad_block_store.all();
735 let mut bad_blocks = Vec::with_capacity(blocks.len());
736
737 #[derive(Serialize, Deserialize)]
738 struct BadBlockSerde<T> {
739 block: T,
740 hash: B256,
741 rlp: Bytes,
742 }
743
744 for block in blocks {
745 let rlp = alloy_rlp::encode(block.sealed_block()).into();
746 let hash = block.hash();
747
748 let block = block
749 .clone_into_rpc_block(
750 BlockTransactionsKind::Full,
751 |tx, tx_info| self.eth_api().converter().fill(tx, tx_info),
752 |header, size| self.eth_api().converter().convert_header(header, size),
753 )
754 .map_err(|err| Eth::Error::from(err).into())?;
755
756 let bad_block = serde_json::to_value(BadBlockSerde { block, hash, rlp })
757 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
758
759 bad_blocks.push(bad_block);
760 }
761
762 Ok(bad_blocks)
763 }
764
765 async fn debug_trace_chain(
767 &self,
768 _start_exclusive: BlockNumberOrTag,
769 _end_inclusive: BlockNumberOrTag,
770 ) -> RpcResult<Vec<BlockTraceResult>> {
771 Err(internal_rpc_err("unimplemented"))
772 }
773
774 async fn debug_trace_block(
776 &self,
777 rlp_block: Bytes,
778 opts: Option<GethDebugTracingOptions>,
779 ) -> RpcResult<Vec<TraceResult>> {
780 let _permit = self.acquire_trace_permit().await;
781 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
782 .await
783 .map_err(Into::into)
784 }
785
786 async fn debug_trace_block_by_hash(
788 &self,
789 block: B256,
790 opts: Option<GethDebugTracingOptions>,
791 ) -> RpcResult<Vec<TraceResult>> {
792 let _permit = self.acquire_trace_permit().await;
793 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
794 .await
795 .map_err(Into::into)
796 }
797
798 async fn debug_trace_block_by_number(
800 &self,
801 block: BlockNumberOrTag,
802 opts: Option<GethDebugTracingOptions>,
803 ) -> RpcResult<Vec<TraceResult>> {
804 let _permit = self.acquire_trace_permit().await;
805 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
806 .await
807 .map_err(Into::into)
808 }
809
810 async fn debug_trace_transaction(
812 &self,
813 tx_hash: B256,
814 opts: Option<GethDebugTracingOptions>,
815 ) -> RpcResult<GethTrace> {
816 let _permit = self.acquire_trace_permit().await;
817 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
818 .await
819 .map_err(Into::into)
820 }
821
822 async fn debug_trace_call(
824 &self,
825 request: RpcTxReq<Eth::NetworkTypes>,
826 block_id: Option<BlockId>,
827 opts: Option<GethDebugTracingCallOptions>,
828 ) -> RpcResult<GethTrace> {
829 let _permit = self.acquire_trace_permit().await;
830 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
831 .await
832 .map_err(Into::into)
833 }
834
835 async fn debug_trace_call_many(
836 &self,
837 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
838 state_context: Option<StateContext>,
839 opts: Option<GethDebugTracingCallOptions>,
840 ) -> RpcResult<Vec<Vec<GethTrace>>> {
841 let _permit = self.acquire_trace_permit().await;
842 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
843 }
844
845 async fn debug_execution_witness(
847 &self,
848 block: BlockNumberOrTag,
849 ) -> RpcResult<ExecutionWitness> {
850 let _permit = self.acquire_trace_permit().await;
851 Self::debug_execution_witness(self, block).await.map_err(Into::into)
852 }
853
854 async fn debug_execution_witness_by_block_hash(
856 &self,
857 hash: B256,
858 ) -> RpcResult<ExecutionWitness> {
859 let _permit = self.acquire_trace_permit().await;
860 Self::debug_execution_witness_by_block_hash(self, hash).await.map_err(Into::into)
861 }
862
863 async fn debug_get_block_access_list(&self, _block_id: BlockId) -> RpcResult<BlockAccessList> {
864 Err(internal_rpc_err("unimplemented"))
865 }
866
867 async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> {
868 Ok(())
869 }
870
871 async fn debug_account_range(
872 &self,
873 _block_number: BlockNumberOrTag,
874 _start: Bytes,
875 _max_results: u64,
876 _nocode: bool,
877 _nostorage: bool,
878 _incompletes: bool,
879 ) -> RpcResult<()> {
880 Ok(())
881 }
882
883 async fn debug_block_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
884 Ok(())
885 }
886
887 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
888 Ok(())
889 }
890
891 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
892 Ok(self.provider().chain_spec().genesis().config.clone())
893 }
894
895 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
896 Ok(())
897 }
898
899 async fn debug_code_by_hash(
900 &self,
901 hash: B256,
902 block_id: Option<BlockId>,
903 ) -> RpcResult<Option<Bytes>> {
904 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
905 }
906
907 async fn debug_cpu_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
908 Ok(())
909 }
910
911 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
912 Ok(())
913 }
914
915 async fn debug_db_ancients(&self) -> RpcResult<()> {
916 Ok(())
917 }
918
919 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
930 let key_bytes = if key.starts_with("0x") {
931 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
932 } else {
933 key.into_bytes()
934 };
935
936 if key_bytes.len() != 33 {
937 return Err(EthApiError::InvalidParams(format!(
938 "Key must be 33 bytes, got {}",
939 key_bytes.len()
940 ))
941 .into());
942 }
943 if key_bytes[0] != 0x63 {
944 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
945 }
946
947 let code_hash = B256::from_slice(&key_bytes[1..33]);
948
949 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
951 }
952
953 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
954 Ok(())
955 }
956
957 async fn debug_free_os_memory(&self) -> RpcResult<()> {
958 Ok(())
959 }
960
961 async fn debug_freeze_client(&self, _node: String) -> RpcResult<()> {
962 Ok(())
963 }
964
965 async fn debug_gc_stats(&self) -> RpcResult<()> {
966 Ok(())
967 }
968
969 async fn debug_get_accessible_state(
970 &self,
971 _from: BlockNumberOrTag,
972 _to: BlockNumberOrTag,
973 ) -> RpcResult<()> {
974 Ok(())
975 }
976
977 async fn debug_get_modified_accounts_by_hash(
978 &self,
979 _start_hash: B256,
980 _end_hash: B256,
981 ) -> RpcResult<()> {
982 Ok(())
983 }
984
985 async fn debug_get_modified_accounts_by_number(
986 &self,
987 _start_number: u64,
988 _end_number: u64,
989 ) -> RpcResult<()> {
990 Ok(())
991 }
992
993 async fn debug_go_trace(&self, _file: String, _seconds: u64) -> RpcResult<()> {
994 Ok(())
995 }
996
997 async fn debug_intermediate_roots(
998 &self,
999 block_hash: B256,
1000 _opts: Option<GethDebugTracingCallOptions>,
1001 ) -> RpcResult<Vec<B256>> {
1002 let _permit = self.acquire_trace_permit().await;
1003 self.intermediate_roots(block_hash).await.map_err(Into::into)
1004 }
1005
1006 async fn debug_mem_stats(&self) -> RpcResult<()> {
1007 Ok(())
1008 }
1009
1010 async fn debug_mutex_profile(&self, _file: String, _nsec: u64) -> RpcResult<()> {
1011 Ok(())
1012 }
1013
1014 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
1015 Ok(())
1016 }
1017
1018 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
1019 Ok(())
1020 }
1021
1022 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
1023 Ok(Default::default())
1024 }
1025
1026 async fn debug_set_block_profile_rate(&self, _rate: u64) -> RpcResult<()> {
1027 Ok(())
1028 }
1029
1030 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
1031 Ok(())
1032 }
1033
1034 async fn debug_set_head(&self, _number: U64) -> RpcResult<()> {
1035 Ok(())
1036 }
1037
1038 async fn debug_set_mutex_profile_fraction(&self, _rate: i32) -> RpcResult<()> {
1039 Ok(())
1040 }
1041
1042 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1043 Ok(())
1044 }
1045
1046 async fn debug_stacks(&self) -> RpcResult<()> {
1047 Ok(())
1048 }
1049
1050 async fn debug_standard_trace_bad_block_to_file(
1051 &self,
1052 _block: BlockNumberOrTag,
1053 _opts: Option<GethDebugTracingCallOptions>,
1054 ) -> RpcResult<()> {
1055 Ok(())
1056 }
1057
1058 async fn debug_standard_trace_block_to_file(
1059 &self,
1060 _block: BlockNumberOrTag,
1061 _opts: Option<GethDebugTracingCallOptions>,
1062 ) -> RpcResult<()> {
1063 Ok(())
1064 }
1065
1066 async fn debug_start_cpu_profile(&self, _file: String) -> RpcResult<()> {
1067 Ok(())
1068 }
1069
1070 async fn debug_start_go_trace(&self, _file: String) -> RpcResult<()> {
1071 Ok(())
1072 }
1073
1074 async fn debug_state_root_with_updates(
1075 &self,
1076 hashed_state: HashedPostState,
1077 block_id: Option<BlockId>,
1078 ) -> RpcResult<(B256, TrieUpdates)> {
1079 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1080 }
1081
1082 async fn debug_stop_cpu_profile(&self) -> RpcResult<()> {
1083 Ok(())
1084 }
1085
1086 async fn debug_stop_go_trace(&self) -> RpcResult<()> {
1087 Ok(())
1088 }
1089
1090 async fn debug_storage_range_at(
1091 &self,
1092 _block_hash: B256,
1093 _tx_idx: usize,
1094 _contract_address: Address,
1095 _key_start: B256,
1096 _max_result: u64,
1097 ) -> RpcResult<()> {
1098 Ok(())
1099 }
1100
1101 async fn debug_trace_bad_block(
1102 &self,
1103 block_hash: B256,
1104 opts: Option<GethDebugTracingCallOptions>,
1105 ) -> RpcResult<Vec<TraceResult>> {
1106 let _permit = self.acquire_trace_permit().await;
1107 let block = self
1108 .inner
1109 .bad_block_store
1110 .get(block_hash)
1111 .ok_or_else(|| internal_rpc_err("bad block not found in cache"))?;
1112
1113 let evm_env = self
1114 .eth_api()
1115 .evm_config()
1116 .evm_env(block.header())
1117 .map_err(RethError::other)
1118 .to_rpc_result()?;
1119
1120 let opts = opts.map(|o| o.tracing_options).unwrap_or_default();
1121 self.trace_block(block, evm_env, opts).await.map_err(Into::into)
1122 }
1123
1124 async fn debug_verbosity(&self, level: usize) -> RpcResult<()> {
1125 reth_tracing::set_log_verbosity(level).map_err(internal_rpc_err)
1126 }
1127
1128 async fn debug_vmodule(&self, pattern: String) -> RpcResult<()> {
1129 reth_tracing::set_log_vmodule(&pattern).map_err(internal_rpc_err)
1130 }
1131
1132 async fn debug_write_block_profile(&self, _file: String) -> RpcResult<()> {
1133 Ok(())
1134 }
1135
1136 async fn debug_write_mem_profile(&self, _file: String) -> RpcResult<()> {
1137 Ok(())
1138 }
1139
1140 async fn debug_write_mutex_profile(&self, _file: String) -> RpcResult<()> {
1141 Ok(())
1142 }
1143}
1144
1145impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1146 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1147 f.debug_struct("DebugApi").finish_non_exhaustive()
1148 }
1149}
1150
1151impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1152 fn clone(&self) -> Self {
1153 Self { inner: Arc::clone(&self.inner) }
1154 }
1155}
1156
1157struct DebugApiInner<Eth: RpcNodeCore> {
1158 eth_api: Eth,
1160 blocking_task_guard: BlockingTaskGuard,
1162 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1164}
1165
1166#[derive(Clone, Debug)]
1168struct BadBlockStore<B: BlockTrait> {
1169 inner: Arc<RwLock<VecDeque<Arc<RecoveredBlock<B>>>>>,
1170 limit: usize,
1171}
1172
1173impl<B: BlockTrait> BadBlockStore<B> {
1174 fn new(limit: usize) -> Self {
1176 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1177 }
1178
1179 fn insert(&self, block: RecoveredBlock<B>) {
1182 let hash = block.hash();
1183 let mut guard = self.inner.write();
1184
1185 if guard.iter().any(|b| b.hash() == hash) {
1187 return;
1188 }
1189 guard.push_back(Arc::new(block));
1190
1191 while guard.len() > self.limit {
1192 guard.pop_front();
1193 }
1194 }
1195
1196 fn all(&self) -> Vec<Arc<RecoveredBlock<B>>> {
1198 let guard = self.inner.read();
1199 guard.iter().rev().cloned().collect()
1200 }
1201
1202 fn get(&self, hash: B256) -> Option<Arc<RecoveredBlock<B>>> {
1204 let guard = self.inner.read();
1205 guard.iter().find(|b| b.hash() == hash).cloned()
1206 }
1207}
1208
1209impl<B: BlockTrait> Default for BadBlockStore<B> {
1210 fn default() -> Self {
1211 Self::new(64)
1212 }
1213}