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, TaskSpawner};
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: impl TaskSpawner,
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(Box::pin(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, &evm_env)?;
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 ((evm_env, _), block) = futures::try_join!(
208 self.eth_api().evm_env_at(block_hash.into()),
209 self.eth_api().recovered_block(block_hash.into()),
210 )?;
211
212 let block = block.ok_or(EthApiError::HeaderNotFound(block_id))?;
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_at(block.hash().into()).await?;
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, &evm_env)?;
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_at(block.hash().into()).await?;
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, &evm_env)?;
364
365 for tx in block.transactions_recovered().take(tx_index) {
367 let tx_env = eth_api.evm_config().tx_env(tx);
368 let res = eth_api.transact(&mut db, evm_env.clone(), tx_env)?;
369 db.commit(res.state);
370 }
371
372 let (evm_env, tx_env) =
374 eth_api.prepare_call_env(evm_env, call, &mut db, overrides)?;
375
376 let mut inspector =
377 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
378 let res =
379 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
380 let trace = inspector
381 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
382 .map_err(Eth::Error::from_eth_err)?;
383
384 Ok(trace)
385 })
386 .await
387 }
388
389 pub async fn debug_trace_call_many(
393 &self,
394 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
395 state_context: Option<StateContext>,
396 opts: Option<GethDebugTracingCallOptions>,
397 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
398 if bundles.is_empty() {
399 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
400 }
401
402 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
403 let transaction_index = transaction_index.unwrap_or_default();
404
405 let target_block = block_number.unwrap_or_default();
406 let ((mut evm_env, _), block) = futures::try_join!(
407 self.eth_api().evm_env_at(target_block),
408 self.eth_api().recovered_block(target_block),
409 )?;
410
411 let opts = opts.unwrap_or_default();
412 let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
413 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
414
415 let mut at = block.parent_hash();
418 let mut replay_block_txs = true;
419
420 let num_txs =
422 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
423 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
427 at = block.hash();
428 replay_block_txs = false;
429 }
430
431 self.eth_api()
432 .spawn_with_state_at_block(at, move |eth_api, mut db| {
433 let mut all_bundles = Vec::with_capacity(bundles.len());
435
436 if replay_block_txs {
437 let transactions = block.transactions_recovered().take(num_txs);
440
441 for tx in transactions {
443 let tx_env = eth_api.evm_config().tx_env(tx);
444 let res = eth_api.transact(&mut db, evm_env.clone(), tx_env)?;
445 db.commit(res.state);
446 }
447 }
448
449 let mut bundles = bundles.into_iter().peekable();
451 let mut inspector = DebugInspector::new(tracing_options.clone())
452 .map_err(Eth::Error::from_eth_err)?;
453 while let Some(bundle) = bundles.next() {
454 let mut results = Vec::with_capacity(bundle.transactions.len());
455 let Bundle { transactions, block_override } = bundle;
456
457 let block_overrides = block_override.map(Box::new);
458
459 let mut transactions = transactions.into_iter().peekable();
460 while let Some(tx) = transactions.next() {
461 let state_overrides = state_overrides.take();
463 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
464
465 let (evm_env, tx_env) =
466 eth_api.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
467
468 let res = eth_api.inspect(
469 &mut db,
470 evm_env.clone(),
471 tx_env.clone(),
472 &mut inspector,
473 )?;
474 let trace = inspector
475 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
476 .map_err(Eth::Error::from_eth_err)?;
477
478 if transactions.peek().is_some() || bundles.peek().is_some() {
481 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
482 db.commit(res.state);
483 }
484 results.push(trace);
485 }
486 evm_env.block_env.inner_mut().number += uint!(1_U256);
488 evm_env.block_env.inner_mut().timestamp += uint!(12_U256);
489
490 all_bundles.push(results);
491 }
492 Ok(all_bundles)
493 })
494 .await
495 }
496
497 pub async fn debug_execution_witness_by_block_hash(
500 &self,
501 hash: B256,
502 ) -> Result<ExecutionWitness, Eth::Error> {
503 let this = self.clone();
504 let block = this
505 .eth_api()
506 .recovered_block(hash.into())
507 .await?
508 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
509
510 self.debug_execution_witness_for_block(block).await
511 }
512
513 pub async fn debug_execution_witness(
518 &self,
519 block_id: BlockNumberOrTag,
520 ) -> Result<ExecutionWitness, Eth::Error> {
521 let this = self.clone();
522 let block = this
523 .eth_api()
524 .recovered_block(block_id.into())
525 .await?
526 .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;
527
528 self.debug_execution_witness_for_block(block).await
529 }
530
531 pub async fn debug_execution_witness_for_block(
533 &self,
534 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
535 ) -> Result<ExecutionWitness, Eth::Error> {
536 let block_number = block.header().number();
537
538 let (mut exec_witness, lowest_block_number) = self
539 .eth_api()
540 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
541 let block_executor = eth_api.evm_config().executor(&mut db);
542
543 let mut witness_record = ExecutionWitnessRecord::default();
544
545 let _ = block_executor
546 .execute_with_state_closure(&block, |statedb: &State<_>| {
547 witness_record.record_executed_state(statedb);
548 })
549 .map_err(|err| EthApiError::Internal(err.into()))?;
550
551 let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number } =
552 witness_record;
553
554 let state = db
555 .database
556 .0
557 .witness(Default::default(), hashed_state)
558 .map_err(EthApiError::from)?;
559 Ok((
560 ExecutionWitness { state, codes, keys, ..Default::default() },
561 lowest_block_number,
562 ))
563 })
564 .await?;
565
566 let smallest = match lowest_block_number {
567 Some(smallest) => smallest,
568 None => {
569 block_number.saturating_sub(1)
572 }
573 };
574
575 let range = smallest..block_number;
576 exec_witness.headers = self
577 .provider()
578 .headers_range(range)
579 .map_err(EthApiError::from)?
580 .into_iter()
581 .map(|header| {
582 let mut serialized_header = Vec::new();
583 header.encode(&mut serialized_header);
584 serialized_header.into()
585 })
586 .collect();
587
588 Ok(exec_witness)
589 }
590
591 pub async fn debug_code_by_hash(
594 &self,
595 hash: B256,
596 block_id: Option<BlockId>,
597 ) -> Result<Option<Bytes>, Eth::Error> {
598 Ok(self
599 .provider()
600 .state_by_block_id(block_id.unwrap_or_default())
601 .map_err(Eth::Error::from_eth_err)?
602 .bytecode_by_hash(&hash)
603 .map_err(Eth::Error::from_eth_err)?
604 .map(|b| b.original_bytes()))
605 }
606
607 async fn debug_state_root_with_updates(
610 &self,
611 hashed_state: HashedPostState,
612 block_id: Option<BlockId>,
613 ) -> Result<(B256, TrieUpdates), Eth::Error> {
614 self.inner
615 .eth_api
616 .spawn_blocking_io(move |this| {
617 let state = this
618 .provider()
619 .state_by_block_id(block_id.unwrap_or_default())
620 .map_err(Eth::Error::from_eth_err)?;
621 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
622 })
623 .await
624 }
625}
626
627#[async_trait]
628impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
629where
630 Eth: EthTransactions + TraceExt,
631{
632 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
634 let header = match block_id {
635 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
636 BlockId::Number(number_or_tag) => {
637 let number = self
638 .provider()
639 .convert_block_number(number_or_tag)
640 .to_rpc_result()?
641 .ok_or_else(|| {
642 internal_rpc_err("Pending block not supported".to_string())
643 })?;
644 self.provider().header_by_number(number).to_rpc_result()?
645 }
646 };
647
648 let mut res = Vec::new();
649 if let Some(header) = header {
650 header.encode(&mut res);
651 }
652
653 Ok(res.into())
654 }
655
656 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
658 let block = self
659 .provider()
660 .block_by_id(block_id)
661 .to_rpc_result()?
662 .ok_or(EthApiError::HeaderNotFound(block_id))?;
663 let mut res = Vec::new();
664 block.encode(&mut res);
665 Ok(res.into())
666 }
667
668 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
674 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
675 }
676
677 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
680 let block: RecoveredBlock<BlockTy<Eth::Primitives>> = self
681 .provider()
682 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
683 .to_rpc_result()?
684 .unwrap_or_default();
685 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
686 }
687
688 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
690 Ok(self
691 .provider()
692 .receipts_by_block_id(block_id)
693 .to_rpc_result()?
694 .unwrap_or_default()
695 .into_iter()
696 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
697 .collect())
698 }
699
700 async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>> {
702 let blocks = self.inner.bad_block_store.all();
703 let mut bad_blocks = Vec::with_capacity(blocks.len());
704
705 #[derive(Serialize, Deserialize)]
706 struct BadBlockSerde<T> {
707 block: T,
708 hash: B256,
709 rlp: Bytes,
710 }
711
712 for block in blocks {
713 let rlp = alloy_rlp::encode(block.sealed_block()).into();
714 let hash = block.hash();
715
716 let block = block
717 .clone_into_rpc_block(
718 BlockTransactionsKind::Full,
719 |tx, tx_info| self.eth_api().converter().fill(tx, tx_info),
720 |header, size| self.eth_api().converter().convert_header(header, size),
721 )
722 .map_err(|err| Eth::Error::from(err).into())?;
723
724 let bad_block = serde_json::to_value(BadBlockSerde { block, hash, rlp })
725 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
726
727 bad_blocks.push(bad_block);
728 }
729
730 Ok(bad_blocks)
731 }
732
733 async fn debug_trace_chain(
735 &self,
736 _start_exclusive: BlockNumberOrTag,
737 _end_inclusive: BlockNumberOrTag,
738 ) -> RpcResult<Vec<BlockTraceResult>> {
739 Err(internal_rpc_err("unimplemented"))
740 }
741
742 async fn debug_trace_block(
744 &self,
745 rlp_block: Bytes,
746 opts: Option<GethDebugTracingOptions>,
747 ) -> RpcResult<Vec<TraceResult>> {
748 let _permit = self.acquire_trace_permit().await;
749 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
750 .await
751 .map_err(Into::into)
752 }
753
754 async fn debug_trace_block_by_hash(
756 &self,
757 block: B256,
758 opts: Option<GethDebugTracingOptions>,
759 ) -> RpcResult<Vec<TraceResult>> {
760 let _permit = self.acquire_trace_permit().await;
761 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
762 .await
763 .map_err(Into::into)
764 }
765
766 async fn debug_trace_block_by_number(
768 &self,
769 block: BlockNumberOrTag,
770 opts: Option<GethDebugTracingOptions>,
771 ) -> RpcResult<Vec<TraceResult>> {
772 let _permit = self.acquire_trace_permit().await;
773 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
774 .await
775 .map_err(Into::into)
776 }
777
778 async fn debug_trace_transaction(
780 &self,
781 tx_hash: B256,
782 opts: Option<GethDebugTracingOptions>,
783 ) -> RpcResult<GethTrace> {
784 let _permit = self.acquire_trace_permit().await;
785 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
786 .await
787 .map_err(Into::into)
788 }
789
790 async fn debug_trace_call(
792 &self,
793 request: RpcTxReq<Eth::NetworkTypes>,
794 block_id: Option<BlockId>,
795 opts: Option<GethDebugTracingCallOptions>,
796 ) -> RpcResult<GethTrace> {
797 let _permit = self.acquire_trace_permit().await;
798 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
799 .await
800 .map_err(Into::into)
801 }
802
803 async fn debug_trace_call_many(
804 &self,
805 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
806 state_context: Option<StateContext>,
807 opts: Option<GethDebugTracingCallOptions>,
808 ) -> RpcResult<Vec<Vec<GethTrace>>> {
809 let _permit = self.acquire_trace_permit().await;
810 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
811 }
812
813 async fn debug_execution_witness(
815 &self,
816 block: BlockNumberOrTag,
817 ) -> RpcResult<ExecutionWitness> {
818 let _permit = self.acquire_trace_permit().await;
819 Self::debug_execution_witness(self, block).await.map_err(Into::into)
820 }
821
822 async fn debug_execution_witness_by_block_hash(
824 &self,
825 hash: B256,
826 ) -> RpcResult<ExecutionWitness> {
827 let _permit = self.acquire_trace_permit().await;
828 Self::debug_execution_witness_by_block_hash(self, hash).await.map_err(Into::into)
829 }
830
831 async fn debug_get_block_access_list(&self, _block_id: BlockId) -> RpcResult<BlockAccessList> {
832 Err(internal_rpc_err("unimplemented"))
833 }
834
835 async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> {
836 Ok(())
837 }
838
839 async fn debug_account_range(
840 &self,
841 _block_number: BlockNumberOrTag,
842 _start: Bytes,
843 _max_results: u64,
844 _nocode: bool,
845 _nostorage: bool,
846 _incompletes: bool,
847 ) -> RpcResult<()> {
848 Ok(())
849 }
850
851 async fn debug_block_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
852 Ok(())
853 }
854
855 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
856 Ok(())
857 }
858
859 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
860 Ok(self.provider().chain_spec().genesis().config.clone())
861 }
862
863 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
864 Ok(())
865 }
866
867 async fn debug_code_by_hash(
868 &self,
869 hash: B256,
870 block_id: Option<BlockId>,
871 ) -> RpcResult<Option<Bytes>> {
872 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
873 }
874
875 async fn debug_cpu_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
876 Ok(())
877 }
878
879 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
880 Ok(())
881 }
882
883 async fn debug_db_ancients(&self) -> RpcResult<()> {
884 Ok(())
885 }
886
887 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
898 let key_bytes = if key.starts_with("0x") {
899 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
900 } else {
901 key.into_bytes()
902 };
903
904 if key_bytes.len() != 33 {
905 return Err(EthApiError::InvalidParams(format!(
906 "Key must be 33 bytes, got {}",
907 key_bytes.len()
908 ))
909 .into());
910 }
911 if key_bytes[0] != 0x63 {
912 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
913 }
914
915 let code_hash = B256::from_slice(&key_bytes[1..33]);
916
917 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
919 }
920
921 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
922 Ok(())
923 }
924
925 async fn debug_free_os_memory(&self) -> RpcResult<()> {
926 Ok(())
927 }
928
929 async fn debug_freeze_client(&self, _node: String) -> RpcResult<()> {
930 Ok(())
931 }
932
933 async fn debug_gc_stats(&self) -> RpcResult<()> {
934 Ok(())
935 }
936
937 async fn debug_get_accessible_state(
938 &self,
939 _from: BlockNumberOrTag,
940 _to: BlockNumberOrTag,
941 ) -> RpcResult<()> {
942 Ok(())
943 }
944
945 async fn debug_get_modified_accounts_by_hash(
946 &self,
947 _start_hash: B256,
948 _end_hash: B256,
949 ) -> RpcResult<()> {
950 Ok(())
951 }
952
953 async fn debug_get_modified_accounts_by_number(
954 &self,
955 _start_number: u64,
956 _end_number: u64,
957 ) -> RpcResult<()> {
958 Ok(())
959 }
960
961 async fn debug_go_trace(&self, _file: String, _seconds: u64) -> RpcResult<()> {
962 Ok(())
963 }
964
965 async fn debug_intermediate_roots(
966 &self,
967 _block_hash: B256,
968 _opts: Option<GethDebugTracingCallOptions>,
969 ) -> RpcResult<()> {
970 Ok(())
971 }
972
973 async fn debug_mem_stats(&self) -> RpcResult<()> {
974 Ok(())
975 }
976
977 async fn debug_mutex_profile(&self, _file: String, _nsec: u64) -> RpcResult<()> {
978 Ok(())
979 }
980
981 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
982 Ok(())
983 }
984
985 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
986 Ok(())
987 }
988
989 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
990 Ok(Default::default())
991 }
992
993 async fn debug_set_block_profile_rate(&self, _rate: u64) -> RpcResult<()> {
994 Ok(())
995 }
996
997 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
998 Ok(())
999 }
1000
1001 async fn debug_set_head(&self, _number: U64) -> RpcResult<()> {
1002 Ok(())
1003 }
1004
1005 async fn debug_set_mutex_profile_fraction(&self, _rate: i32) -> RpcResult<()> {
1006 Ok(())
1007 }
1008
1009 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1010 Ok(())
1011 }
1012
1013 async fn debug_stacks(&self) -> RpcResult<()> {
1014 Ok(())
1015 }
1016
1017 async fn debug_standard_trace_bad_block_to_file(
1018 &self,
1019 _block: BlockNumberOrTag,
1020 _opts: Option<GethDebugTracingCallOptions>,
1021 ) -> RpcResult<()> {
1022 Ok(())
1023 }
1024
1025 async fn debug_standard_trace_block_to_file(
1026 &self,
1027 _block: BlockNumberOrTag,
1028 _opts: Option<GethDebugTracingCallOptions>,
1029 ) -> RpcResult<()> {
1030 Ok(())
1031 }
1032
1033 async fn debug_start_cpu_profile(&self, _file: String) -> RpcResult<()> {
1034 Ok(())
1035 }
1036
1037 async fn debug_start_go_trace(&self, _file: String) -> RpcResult<()> {
1038 Ok(())
1039 }
1040
1041 async fn debug_state_root_with_updates(
1042 &self,
1043 hashed_state: HashedPostState,
1044 block_id: Option<BlockId>,
1045 ) -> RpcResult<(B256, TrieUpdates)> {
1046 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1047 }
1048
1049 async fn debug_stop_cpu_profile(&self) -> RpcResult<()> {
1050 Ok(())
1051 }
1052
1053 async fn debug_stop_go_trace(&self) -> RpcResult<()> {
1054 Ok(())
1055 }
1056
1057 async fn debug_storage_range_at(
1058 &self,
1059 _block_hash: B256,
1060 _tx_idx: usize,
1061 _contract_address: Address,
1062 _key_start: B256,
1063 _max_result: u64,
1064 ) -> RpcResult<()> {
1065 Ok(())
1066 }
1067
1068 async fn debug_trace_bad_block(
1069 &self,
1070 _block_hash: B256,
1071 _opts: Option<GethDebugTracingCallOptions>,
1072 ) -> RpcResult<()> {
1073 Ok(())
1074 }
1075
1076 async fn debug_verbosity(&self, _level: usize) -> RpcResult<()> {
1077 Ok(())
1078 }
1079
1080 async fn debug_vmodule(&self, _pattern: String) -> RpcResult<()> {
1081 Ok(())
1082 }
1083
1084 async fn debug_write_block_profile(&self, _file: String) -> RpcResult<()> {
1085 Ok(())
1086 }
1087
1088 async fn debug_write_mem_profile(&self, _file: String) -> RpcResult<()> {
1089 Ok(())
1090 }
1091
1092 async fn debug_write_mutex_profile(&self, _file: String) -> RpcResult<()> {
1093 Ok(())
1094 }
1095}
1096
1097impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1098 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1099 f.debug_struct("DebugApi").finish_non_exhaustive()
1100 }
1101}
1102
1103impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1104 fn clone(&self) -> Self {
1105 Self { inner: Arc::clone(&self.inner) }
1106 }
1107}
1108
1109struct DebugApiInner<Eth: RpcNodeCore> {
1110 eth_api: Eth,
1112 blocking_task_guard: BlockingTaskGuard,
1114 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1116}
1117
1118#[derive(Clone, Debug)]
1120struct BadBlockStore<B: BlockTrait> {
1121 inner: Arc<RwLock<VecDeque<Arc<RecoveredBlock<B>>>>>,
1122 limit: usize,
1123}
1124
1125impl<B: BlockTrait> BadBlockStore<B> {
1126 fn new(limit: usize) -> Self {
1128 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1129 }
1130
1131 fn insert(&self, block: RecoveredBlock<B>) {
1134 let hash = block.hash();
1135 let mut guard = self.inner.write();
1136
1137 if guard.iter().any(|b| b.hash() == hash) {
1139 return;
1140 }
1141 guard.push_back(Arc::new(block));
1142
1143 while guard.len() > self.limit {
1144 guard.pop_front();
1145 }
1146 }
1147
1148 fn all(&self) -> Vec<Arc<RecoveredBlock<B>>> {
1150 let guard = self.inner.read();
1151 guard.iter().rev().cloned().collect()
1152 }
1153}
1154
1155impl<B: BlockTrait> Default for BadBlockStore<B> {
1156 fn default() -> Self {
1157 Self::new(64)
1158 }
1159}