1use alloy_consensus::{transaction::TxHashRef, BlockHeader};
2use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
3use alloy_evm::{env::BlockEnvironment, Evm};
4use alloy_genesis::ChainConfig;
5use alloy_primitives::{hex::decode, uint, Address, Bytes, B256, U64};
6use alloy_rlp::{Decodable, Encodable};
7use alloy_rpc_types::BlockTransactionsKind;
8use alloy_rpc_types_debug::ExecutionWitness;
9use alloy_rpc_types_eth::{state::EvmOverrides, BlockError, Bundle, StateContext};
10use alloy_rpc_types_trace::geth::{
11 BlockTraceResult, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult,
12};
13use async_trait::async_trait;
14use futures::Stream;
15use jsonrpsee::core::RpcResult;
16use parking_lot::RwLock;
17use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
18use reth_engine_primitives::ConsensusEngineEvent;
19use reth_errors::RethError;
20use reth_evm::{execute::Executor, ConfigureEvm, EvmEnvFor};
21use reth_primitives_traits::{
22 Block as BlockTrait, BlockBody, BlockTy, ReceiptWithBloom, RecoveredBlock,
23};
24use reth_revm::{db::State, witness::ExecutionWitnessRecord};
25use reth_rpc_api::DebugApiServer;
26use reth_rpc_convert::RpcTxReq;
27use reth_rpc_eth_api::{
28 helpers::{EthTransactions, TraceExt},
29 FromEthApiError, FromEvmError, RpcConvert, RpcNodeCore,
30};
31use reth_rpc_eth_types::EthApiError;
32use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
33use reth_storage_api::{
34 BlockIdReader, BlockReaderIdExt, HashedPostStateProvider, HeaderProvider, ProviderBlock,
35 ReceiptProviderIdExt, StateProviderFactory, StateRootProvider, TransactionVariant,
36};
37use reth_tasks::{pool::BlockingTaskGuard, Runtime};
38use reth_trie_common::{updates::TrieUpdates, ExecutionWitnessMode, HashedPostState};
39use revm::{database::states::bundle_state::BundleRetention, DatabaseCommit};
40use revm_inspectors::tracing::{DebugInspector, TransactionContext};
41use serde::{Deserialize, Serialize};
42use std::{collections::VecDeque, sync::Arc};
43use tokio::sync::{AcquireError, OwnedSemaphorePermit};
44use tokio_stream::StreamExt;
45
46pub struct DebugApi<Eth: RpcNodeCore> {
50 inner: Arc<DebugApiInner<Eth>>,
51}
52
53impl<Eth> DebugApi<Eth>
54where
55 Eth: RpcNodeCore,
56{
57 pub fn new(
59 eth_api: Eth,
60 blocking_task_guard: BlockingTaskGuard,
61 executor: &Runtime,
62 mut stream: impl Stream<Item = ConsensusEngineEvent<Eth::Primitives>> + Send + Unpin + 'static,
63 ) -> Self {
64 let bad_block_store = BadBlockStore::default();
65 let inner = Arc::new(DebugApiInner {
66 eth_api,
67 blocking_task_guard,
68 bad_block_store: bad_block_store.clone(),
69 });
70
71 executor.spawn_task(async move {
73 while let Some(event) = stream.next().await {
74 if let ConsensusEngineEvent::InvalidBlock { block, error } = event &&
75 let Ok(recovered) = RecoveredBlock::try_recover_sealed(*block)
76 {
77 bad_block_store.insert(recovered, error);
78 }
79 }
80 });
81
82 Self { inner }
83 }
84
85 pub fn eth_api(&self) -> &Eth {
87 &self.inner.eth_api
88 }
89
90 pub fn provider(&self) -> &Eth::Provider {
92 self.inner.eth_api.provider()
93 }
94}
95
96impl<Eth> DebugApi<Eth>
99where
100 Eth: TraceExt,
101{
102 async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
104 self.inner.blocking_task_guard.clone().acquire_owned().await
105 }
106
107 async fn trace_block(
109 &self,
110 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
111 evm_env: EvmEnvFor<Eth::Evm>,
112 opts: GethDebugTracingOptions,
113 ) -> Result<Vec<TraceResult>, Eth::Error> {
114 self.eth_api()
115 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
116 let mut results = Vec::with_capacity(block.body().transactions().len());
117
118 eth_api.apply_pre_execution_changes(&block, &mut db)?;
119
120 let mut transactions = block.transactions_recovered().enumerate().peekable();
121 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
122 while let Some((index, tx)) = transactions.next() {
123 let tx_hash = *tx.tx_hash();
124 let tx_env = eth_api.evm_config().tx_env(tx);
125
126 let res = eth_api.inspect(
127 &mut db,
128 evm_env.clone(),
129 tx_env.clone(),
130 &mut inspector,
131 )?;
132 let result = inspector
133 .get_result(
134 Some(TransactionContext {
135 block_hash: Some(block.hash()),
136 tx_hash: Some(tx_hash),
137 tx_index: Some(index),
138 }),
139 &tx_env,
140 &evm_env.block_env,
141 &res,
142 &mut db,
143 )
144 .map_err(Eth::Error::from_eth_err)?;
145
146 results.push(TraceResult::Success { result, tx_hash: Some(tx_hash) });
147 if transactions.peek().is_some() {
148 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
149 db.commit(res.state)
152 }
153 }
154
155 Ok(results)
156 })
157 .await
158 }
159
160 pub async fn debug_trace_raw_block(
166 &self,
167 rlp_block: Bytes,
168 opts: GethDebugTracingOptions,
169 ) -> Result<Vec<TraceResult>, Eth::Error> {
170 let block: ProviderBlock<Eth::Provider> = Decodable::decode(&mut rlp_block.as_ref())
171 .map_err(BlockError::RlpDecodeRawBlock)
172 .map_err(Eth::Error::from_eth_err)?;
173
174 let evm_env = self
175 .eth_api()
176 .evm_config()
177 .evm_env(block.header())
178 .map_err(RethError::other)
179 .map_err(Eth::Error::from_eth_err)?;
180
181 let senders =
183 if self.provider().chain_spec().is_homestead_active_at_block(block.header().number()) {
184 block.body().recover_signers()
185 } else {
186 block.body().recover_signers_unchecked()
187 }
188 .map_err(Eth::Error::from_eth_err)?;
189
190 self.trace_block(Arc::new(block.into_recovered_with_signers(senders)), evm_env, opts).await
191 }
192
193 pub async fn debug_trace_block(
195 &self,
196 block_id: BlockId,
197 opts: GethDebugTracingOptions,
198 ) -> Result<Vec<TraceResult>, Eth::Error> {
199 let block = self
200 .eth_api()
201 .recovered_block(block_id)
202 .await?
203 .ok_or(EthApiError::HeaderNotFound(block_id))?;
204 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
205
206 self.trace_block(block, evm_env, opts).await
207 }
208
209 pub async fn debug_trace_transaction(
213 &self,
214 tx_hash: B256,
215 opts: GethDebugTracingOptions,
216 ) -> Result<GethTrace, Eth::Error> {
217 let (transaction, block) = match self.eth_api().transaction_and_block(tx_hash).await? {
218 None => return Err(EthApiError::TransactionNotFound.into()),
219 Some(res) => res,
220 };
221 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
222
223 let state_at: BlockId = block.parent_hash().into();
226 let block_hash = block.hash();
227
228 self.eth_api()
229 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
230 let block_txs = block.transactions_recovered();
231
232 let tx = transaction.into_recovered();
234
235 eth_api.apply_pre_execution_changes(&block, &mut db)?;
236
237 let index = eth_api.replay_transactions_until(
239 &mut db,
240 evm_env.clone(),
241 block_txs,
242 *tx.tx_hash(),
243 )?;
244
245 let tx_env = eth_api.evm_config().tx_env(&tx);
246
247 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
248 let res =
249 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
250 let trace = inspector
251 .get_result(
252 Some(TransactionContext {
253 block_hash: Some(block_hash),
254 tx_index: Some(index),
255 tx_hash: Some(*tx.tx_hash()),
256 }),
257 &tx_env,
258 &evm_env.block_env,
259 &res,
260 &mut db,
261 )
262 .map_err(Eth::Error::from_eth_err)?;
263
264 Ok(trace)
265 })
266 .await
267 }
268
269 pub async fn debug_trace_call(
279 &self,
280 call: RpcTxReq<Eth::NetworkTypes>,
281 block_id: Option<BlockId>,
282 opts: GethDebugTracingCallOptions,
283 ) -> Result<GethTrace, Eth::Error> {
284 let at = block_id.unwrap_or_default();
285 let GethDebugTracingCallOptions {
286 tracing_options,
287 state_overrides,
288 block_overrides,
289 tx_index,
290 } = opts;
291 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
292
293 if let Some(tx_idx) = tx_index {
295 return self
296 .debug_trace_call_at_tx_index(call, at, tx_idx as usize, tracing_options, overrides)
297 .await;
298 }
299
300 let this = self.clone();
301 self.eth_api()
302 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
303 let mut inspector =
304 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
305 let res = this.eth_api().inspect(
306 &mut *db,
307 evm_env.clone(),
308 tx_env.clone(),
309 &mut inspector,
310 )?;
311 let trace = inspector
312 .get_result(None, &tx_env, &evm_env.block_env, &res, db)
313 .map_err(Eth::Error::from_eth_err)?;
314 Ok(trace)
315 })
316 .await
317 }
318
319 async fn debug_trace_call_at_tx_index(
323 &self,
324 call: RpcTxReq<Eth::NetworkTypes>,
325 block_id: BlockId,
326 tx_index: usize,
327 tracing_options: GethDebugTracingOptions,
328 overrides: EvmOverrides,
329 ) -> Result<GethTrace, Eth::Error> {
330 let block = self
332 .eth_api()
333 .recovered_block(block_id)
334 .await?
335 .ok_or(EthApiError::HeaderNotFound(block_id))?;
336
337 if tx_index >= block.transaction_count() {
338 return Err(EthApiError::InvalidParams(format!(
340 "tx_index {} out of bounds for block with {} transactions",
341 tx_index,
342 block.transaction_count()
343 ))
344 .into())
345 }
346
347 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
348
349 let state_at = block.parent_hash();
351
352 self.eth_api()
353 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
354 eth_api.apply_pre_execution_changes(&block, &mut db)?;
356
357 eth_api.replay_transactions_until(
359 &mut db,
360 evm_env.clone(),
361 block.transactions_recovered(),
362 *block.body().transactions()[tx_index].tx_hash(),
363 )?;
364
365 let (evm_env, tx_env) =
367 eth_api.prepare_call_env(evm_env, call, &mut db, overrides)?;
368
369 let mut inspector =
370 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
371 let res =
372 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
373 let trace = inspector
374 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
375 .map_err(Eth::Error::from_eth_err)?;
376
377 Ok(trace)
378 })
379 .await
380 }
381
382 pub async fn debug_trace_call_many(
386 &self,
387 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
388 state_context: Option<StateContext>,
389 opts: Option<GethDebugTracingCallOptions>,
390 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
391 if bundles.is_empty() {
392 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
393 }
394
395 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
396 let transaction_index = transaction_index.unwrap_or_default();
397
398 let target_block = block_number.unwrap_or_default();
399 let block = self
400 .eth_api()
401 .recovered_block(target_block)
402 .await?
403 .ok_or(EthApiError::HeaderNotFound(target_block))?;
404 let mut evm_env =
405 self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
406
407 let opts = opts.unwrap_or_default();
408 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
409
410 let mut at = block.parent_hash();
413 let mut replay_block_txs = true;
414
415 let num_txs =
417 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
418 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
422 at = block.hash();
423 replay_block_txs = false;
424 }
425
426 self.eth_api()
427 .spawn_with_state_at_block(at, move |eth_api, mut db| {
428 let mut all_bundles = Vec::with_capacity(bundles.len());
430
431 if replay_block_txs {
432 eth_api.apply_pre_execution_changes(&block, &mut db)?;
435
436 let transactions = block.transactions_recovered().take(num_txs);
437
438 for tx in transactions {
440 let tx_env = eth_api.evm_config().tx_env(tx);
441 let res = eth_api.transact(&mut db, evm_env.clone(), tx_env)?;
442 db.commit(res.state);
443 }
444 }
445
446 let mut bundles = bundles.into_iter().peekable();
448 let mut inspector = DebugInspector::new(tracing_options.clone())
449 .map_err(Eth::Error::from_eth_err)?;
450 while let Some(bundle) = bundles.next() {
451 let mut results = Vec::with_capacity(bundle.transactions.len());
452 let Bundle { transactions, block_override } = bundle;
453
454 let block_overrides = block_override.map(Box::new);
455
456 let mut transactions = transactions.into_iter().peekable();
457 while let Some(tx) = transactions.next() {
458 let state_overrides = state_overrides.take();
460 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
461
462 let (evm_env, tx_env) =
463 eth_api.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
464
465 let res = eth_api.inspect(
466 &mut db,
467 evm_env.clone(),
468 tx_env.clone(),
469 &mut inspector,
470 )?;
471 let trace = inspector
472 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
473 .map_err(Eth::Error::from_eth_err)?;
474
475 if transactions.peek().is_some() || bundles.peek().is_some() {
478 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
479 db.commit(res.state);
480 }
481 results.push(trace);
482 }
483 evm_env.block_env.inner_mut().number += uint!(1_U256);
485 evm_env.block_env.inner_mut().timestamp += uint!(12_U256);
486
487 all_bundles.push(results);
488 }
489 Ok(all_bundles)
490 })
491 .await
492 }
493
494 pub async fn debug_execution_witness_by_block_hash(
497 &self,
498 hash: B256,
499 mode: Option<ExecutionWitnessMode>,
500 ) -> Result<ExecutionWitness, Eth::Error> {
501 let this = self.clone();
502 let block = this
503 .eth_api()
504 .recovered_block(hash.into())
505 .await?
506 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
507
508 self.debug_execution_witness_for_block(block, mode.unwrap_or_default()).await
509 }
510
511 pub async fn debug_execution_witness(
516 &self,
517 block_id: BlockNumberOrTag,
518 mode: Option<ExecutionWitnessMode>,
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, mode.unwrap_or_default()).await
528 }
529
530 pub async fn debug_execution_witness_for_block(
532 &self,
533 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
534 mode: ExecutionWitnessMode,
535 ) -> Result<ExecutionWitness, Eth::Error> {
536 let block_number = block.header().number();
537 self.eth_api()
538 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
539 let block_executor = eth_api.evm_config().executor(&mut db);
540
541 let mut witness_record = ExecutionWitnessRecord::default();
542
543 let _ = block_executor
544 .execute_with_state_closure(&block, |statedb: &State<_>| {
545 witness_record.record_executed_state(statedb, mode);
546 })
547 .map_err(|err| EthApiError::Internal(err.into()))?;
548
549 Ok(witness_record
550 .into_execution_witness(&db.database.0, eth_api.provider(), block_number, mode)
551 .map_err(EthApiError::from)?)
552 })
553 .await
554 }
555
556 pub async fn debug_code_by_hash(
559 &self,
560 hash: B256,
561 block_id: Option<BlockId>,
562 ) -> Result<Option<Bytes>, Eth::Error> {
563 Ok(self
564 .provider()
565 .state_by_block_id(block_id.unwrap_or_default())
566 .map_err(Eth::Error::from_eth_err)?
567 .bytecode_by_hash(&hash)
568 .map_err(Eth::Error::from_eth_err)?
569 .map(|b| b.original_bytes()))
570 }
571
572 async fn debug_state_root_with_updates(
575 &self,
576 hashed_state: HashedPostState,
577 block_id: Option<BlockId>,
578 ) -> Result<(B256, TrieUpdates), Eth::Error> {
579 self.inner
580 .eth_api
581 .spawn_blocking_io(move |this| {
582 let state = this
583 .provider()
584 .state_by_block_id(block_id.unwrap_or_default())
585 .map_err(Eth::Error::from_eth_err)?;
586 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
587 })
588 .await
589 }
590
591 pub async fn intermediate_roots(&self, block_hash: B256) -> Result<Vec<B256>, Eth::Error> {
593 let block = self
594 .eth_api()
595 .recovered_block(block_hash.into())
596 .await?
597 .ok_or(EthApiError::HeaderNotFound(block_hash.into()))?;
598 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
599
600 self.eth_api()
601 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
602 db.transition_state = Some(Default::default());
604
605 eth_api.apply_pre_execution_changes(&block, &mut db)?;
606
607 let mut roots = Vec::with_capacity(block.body().transactions().len());
608 for tx in block.transactions_recovered() {
609 let tx_env = eth_api.evm_config().tx_env(tx);
610 {
611 let mut evm = eth_api.evm_config().evm_with_env(&mut db, evm_env.clone());
612 evm.transact_commit(tx_env).map_err(Eth::Error::from_evm_err)?;
613 }
614 db.merge_transitions(BundleRetention::PlainState);
616 let hashed_state = db.database.hashed_post_state(&db.bundle_state);
618 let root =
619 db.database.state_root(hashed_state).map_err(Eth::Error::from_eth_err)?;
620 roots.push(root);
621 }
622
623 Ok(roots)
624 })
625 .await
626 }
627}
628
629#[async_trait]
630impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
631where
632 Eth: EthTransactions + TraceExt,
633{
634 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
636 let header = match block_id {
637 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
638 BlockId::Number(number_or_tag) => {
639 let number = self
640 .provider()
641 .convert_block_number(number_or_tag)
642 .to_rpc_result()?
643 .ok_or(EthApiError::HeaderNotFound(block_id))?;
644 self.provider().header_by_number(number).to_rpc_result()?
645 }
646 }
647 .ok_or(EthApiError::HeaderNotFound(block_id))?;
648
649 let mut res = Vec::new();
650 header.encode(&mut res);
651 Ok(res.into())
652 }
653
654 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
656 let block = self
657 .provider()
658 .block_by_id(block_id)
659 .to_rpc_result()?
660 .ok_or(EthApiError::HeaderNotFound(block_id))?;
661 let mut res = Vec::new();
662 block.encode(&mut res);
663 Ok(res.into())
664 }
665
666 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
672 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
673 }
674
675 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
678 let block: RecoveredBlock<BlockTy<Eth::Primitives>> = self
679 .provider()
680 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
681 .to_rpc_result()?
682 .unwrap_or_default();
683 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
684 }
685
686 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
688 Ok(self
689 .provider()
690 .receipts_by_block_id(block_id)
691 .to_rpc_result()?
692 .ok_or(EthApiError::HeaderNotFound(block_id))?
693 .into_iter()
694 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
695 .collect())
696 }
697
698 async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>> {
700 let entries = self.inner.bad_block_store.all();
701 let mut bad_blocks = Vec::with_capacity(entries.len());
702
703 #[derive(Serialize, Deserialize)]
704 struct BadBlockSerde<T> {
705 block: T,
706 hash: B256,
707 rlp: Bytes,
708 reason: String,
709 }
710
711 for entry in entries {
712 let rlp = alloy_rlp::encode(entry.block.sealed_block()).into();
713 let hash = entry.block.hash();
714
715 let block = entry
716 .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 =
725 serde_json::to_value(BadBlockSerde { block, hash, rlp, reason: entry.reason })
726 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
727
728 bad_blocks.push(bad_block);
729 }
730
731 Ok(bad_blocks)
732 }
733
734 async fn debug_trace_chain(
736 &self,
737 _start_exclusive: BlockNumberOrTag,
738 _end_inclusive: BlockNumberOrTag,
739 ) -> RpcResult<Vec<BlockTraceResult>> {
740 Err(internal_rpc_err("unimplemented"))
741 }
742
743 async fn debug_trace_block(
745 &self,
746 rlp_block: Bytes,
747 opts: Option<GethDebugTracingOptions>,
748 ) -> RpcResult<Vec<TraceResult>> {
749 let _permit = self.acquire_trace_permit().await;
750 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
751 .await
752 .map_err(Into::into)
753 }
754
755 async fn debug_trace_block_by_hash(
757 &self,
758 block: B256,
759 opts: Option<GethDebugTracingOptions>,
760 ) -> RpcResult<Vec<TraceResult>> {
761 let _permit = self.acquire_trace_permit().await;
762 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
763 .await
764 .map_err(Into::into)
765 }
766
767 async fn debug_trace_block_by_number(
769 &self,
770 block: BlockNumberOrTag,
771 opts: Option<GethDebugTracingOptions>,
772 ) -> RpcResult<Vec<TraceResult>> {
773 let _permit = self.acquire_trace_permit().await;
774 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
775 .await
776 .map_err(Into::into)
777 }
778
779 async fn debug_trace_transaction(
781 &self,
782 tx_hash: B256,
783 opts: Option<GethDebugTracingOptions>,
784 ) -> RpcResult<GethTrace> {
785 let _permit = self.acquire_trace_permit().await;
786 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
787 .await
788 .map_err(Into::into)
789 }
790
791 async fn debug_trace_call(
793 &self,
794 request: RpcTxReq<Eth::NetworkTypes>,
795 block_id: Option<BlockId>,
796 opts: Option<GethDebugTracingCallOptions>,
797 ) -> RpcResult<GethTrace> {
798 let _permit = self.acquire_trace_permit().await;
799 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
800 .await
801 .map_err(Into::into)
802 }
803
804 async fn debug_trace_call_many(
805 &self,
806 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
807 state_context: Option<StateContext>,
808 opts: Option<GethDebugTracingCallOptions>,
809 ) -> RpcResult<Vec<Vec<GethTrace>>> {
810 let _permit = self.acquire_trace_permit().await;
811 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
812 }
813
814 async fn debug_execution_witness(
816 &self,
817 block: BlockNumberOrTag,
818 mode: Option<ExecutionWitnessMode>,
819 ) -> RpcResult<ExecutionWitness> {
820 let _permit = self.acquire_trace_permit().await;
821 Self::debug_execution_witness(self, block, mode).await.map_err(Into::into)
822 }
823
824 async fn debug_execution_witness_by_block_hash(
826 &self,
827 hash: B256,
828 mode: Option<ExecutionWitnessMode>,
829 ) -> RpcResult<ExecutionWitness> {
830 let _permit = self.acquire_trace_permit().await;
831 Self::debug_execution_witness_by_block_hash(self, hash, mode).await.map_err(Into::into)
832 }
833
834 async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> {
835 Ok(())
836 }
837
838 async fn debug_account_range(
839 &self,
840 _block_number: BlockNumberOrTag,
841 _start: Bytes,
842 _max_results: u64,
843 _nocode: bool,
844 _nostorage: bool,
845 _incompletes: bool,
846 ) -> RpcResult<()> {
847 Ok(())
848 }
849
850 async fn debug_block_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
851 Ok(())
852 }
853
854 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
855 Ok(())
856 }
857
858 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
859 Ok(self.provider().chain_spec().genesis().config.clone())
860 }
861
862 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
863 Ok(())
864 }
865
866 async fn debug_code_by_hash(
867 &self,
868 hash: B256,
869 block_id: Option<BlockId>,
870 ) -> RpcResult<Option<Bytes>> {
871 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
872 }
873
874 async fn debug_cpu_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
875 Ok(())
876 }
877
878 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
879 Ok(())
880 }
881
882 async fn debug_db_ancients(&self) -> RpcResult<()> {
883 Ok(())
884 }
885
886 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
897 let key_bytes = if key.starts_with("0x") {
898 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
899 } else {
900 key.into_bytes()
901 };
902
903 if key_bytes.len() != 33 {
904 return Err(EthApiError::InvalidParams(format!(
905 "Key must be 33 bytes, got {}",
906 key_bytes.len()
907 ))
908 .into());
909 }
910 if key_bytes[0] != 0x63 {
911 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
912 }
913
914 let code_hash = B256::from_slice(&key_bytes[1..33]);
915
916 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
918 }
919
920 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
921 Ok(())
922 }
923
924 async fn debug_free_os_memory(&self) -> RpcResult<()> {
925 Ok(())
926 }
927
928 async fn debug_freeze_client(&self, _node: String) -> RpcResult<()> {
929 Ok(())
930 }
931
932 async fn debug_gc_stats(&self) -> RpcResult<()> {
933 Ok(())
934 }
935
936 async fn debug_get_accessible_state(
937 &self,
938 _from: BlockNumberOrTag,
939 _to: BlockNumberOrTag,
940 ) -> RpcResult<()> {
941 Ok(())
942 }
943
944 async fn debug_get_modified_accounts_by_hash(
945 &self,
946 _start_hash: B256,
947 _end_hash: B256,
948 ) -> RpcResult<()> {
949 Ok(())
950 }
951
952 async fn debug_get_modified_accounts_by_number(
953 &self,
954 _start_number: u64,
955 _end_number: u64,
956 ) -> RpcResult<()> {
957 Ok(())
958 }
959
960 async fn debug_go_trace(&self, _file: String, _seconds: u64) -> RpcResult<()> {
961 Ok(())
962 }
963
964 async fn debug_intermediate_roots(
965 &self,
966 block_hash: B256,
967 _opts: Option<GethDebugTracingCallOptions>,
968 ) -> RpcResult<Vec<B256>> {
969 let _permit = self.acquire_trace_permit().await;
970 self.intermediate_roots(block_hash).await.map_err(Into::into)
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<Vec<TraceResult>> {
1073 let _permit = self.acquire_trace_permit().await;
1074 let entry = self
1075 .inner
1076 .bad_block_store
1077 .get(block_hash)
1078 .ok_or_else(|| internal_rpc_err("bad block not found in cache"))?;
1079
1080 let evm_env = self
1081 .eth_api()
1082 .evm_config()
1083 .evm_env(entry.block.header())
1084 .map_err(RethError::other)
1085 .to_rpc_result()?;
1086
1087 let opts = opts.map(|o| o.tracing_options).unwrap_or_default();
1088 self.trace_block(entry.block.clone(), evm_env, opts).await.map_err(Into::into)
1089 }
1090
1091 async fn debug_verbosity(&self, level: usize) -> RpcResult<()> {
1092 reth_tracing::set_log_verbosity(level).map_err(internal_rpc_err)
1093 }
1094
1095 async fn debug_vmodule(&self, pattern: String) -> RpcResult<()> {
1096 reth_tracing::set_log_vmodule(&pattern).map_err(internal_rpc_err)
1097 }
1098
1099 async fn debug_write_block_profile(&self, _file: String) -> RpcResult<()> {
1100 Ok(())
1101 }
1102
1103 async fn debug_write_mem_profile(&self, _file: String) -> RpcResult<()> {
1104 Ok(())
1105 }
1106
1107 async fn debug_write_mutex_profile(&self, _file: String) -> RpcResult<()> {
1108 Ok(())
1109 }
1110}
1111
1112impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1113 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1114 f.debug_struct("DebugApi").finish_non_exhaustive()
1115 }
1116}
1117
1118impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1119 fn clone(&self) -> Self {
1120 Self { inner: Arc::clone(&self.inner) }
1121 }
1122}
1123
1124struct DebugApiInner<Eth: RpcNodeCore> {
1125 eth_api: Eth,
1127 blocking_task_guard: BlockingTaskGuard,
1129 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1131}
1132
1133#[derive(Clone, Debug)]
1135struct BadBlockStore<B: BlockTrait> {
1136 inner: Arc<RwLock<VecDeque<BadBlockEntry<B>>>>,
1137 limit: usize,
1138}
1139
1140#[derive(Clone, Debug)]
1142struct BadBlockEntry<B: BlockTrait> {
1143 block: Arc<RecoveredBlock<B>>,
1144 reason: String,
1145}
1146
1147impl<B: BlockTrait> BadBlockStore<B> {
1148 fn new(limit: usize) -> Self {
1150 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1151 }
1152
1153 fn insert(&self, block: RecoveredBlock<B>, reason: String) {
1156 let hash = block.hash();
1157 let mut guard = self.inner.write();
1158
1159 if guard.iter().any(|entry| entry.block.hash() == hash) {
1161 return;
1162 }
1163 guard.push_back(BadBlockEntry { block: Arc::new(block), reason });
1164
1165 while guard.len() > self.limit {
1166 guard.pop_front();
1167 }
1168 }
1169
1170 fn all(&self) -> Vec<BadBlockEntry<B>> {
1172 let guard = self.inner.read();
1173 guard.iter().rev().cloned().collect()
1174 }
1175
1176 fn get(&self, hash: B256) -> Option<BadBlockEntry<B>> {
1178 let guard = self.inner.read();
1179 guard.iter().find(|entry| entry.block.hash() == hash).cloned()
1180 }
1181}
1182
1183impl<B: BlockTrait> Default for BadBlockStore<B> {
1184 fn default() -> Self {
1185 Self::new(64)
1186 }
1187}