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) = event &&
75 let Ok(recovered) = RecoveredBlock::try_recover_sealed(*block)
76 {
77 bad_block_store.insert(recovered);
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 blocks = self.inner.bad_block_store.all();
701 let mut bad_blocks = Vec::with_capacity(blocks.len());
702
703 #[derive(Serialize, Deserialize)]
704 struct BadBlockSerde<T> {
705 block: T,
706 hash: B256,
707 rlp: Bytes,
708 }
709
710 for block in blocks {
711 let rlp = alloy_rlp::encode(block.sealed_block()).into();
712 let hash = block.hash();
713
714 let block = block
715 .clone_into_rpc_block(
716 BlockTransactionsKind::Full,
717 |tx, tx_info| self.eth_api().converter().fill(tx, tx_info),
718 |header, size| self.eth_api().converter().convert_header(header, size),
719 )
720 .map_err(|err| Eth::Error::from(err).into())?;
721
722 let bad_block = serde_json::to_value(BadBlockSerde { block, hash, rlp })
723 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
724
725 bad_blocks.push(bad_block);
726 }
727
728 Ok(bad_blocks)
729 }
730
731 async fn debug_trace_chain(
733 &self,
734 _start_exclusive: BlockNumberOrTag,
735 _end_inclusive: BlockNumberOrTag,
736 ) -> RpcResult<Vec<BlockTraceResult>> {
737 Err(internal_rpc_err("unimplemented"))
738 }
739
740 async fn debug_trace_block(
742 &self,
743 rlp_block: Bytes,
744 opts: Option<GethDebugTracingOptions>,
745 ) -> RpcResult<Vec<TraceResult>> {
746 let _permit = self.acquire_trace_permit().await;
747 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
748 .await
749 .map_err(Into::into)
750 }
751
752 async fn debug_trace_block_by_hash(
754 &self,
755 block: B256,
756 opts: Option<GethDebugTracingOptions>,
757 ) -> RpcResult<Vec<TraceResult>> {
758 let _permit = self.acquire_trace_permit().await;
759 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
760 .await
761 .map_err(Into::into)
762 }
763
764 async fn debug_trace_block_by_number(
766 &self,
767 block: BlockNumberOrTag,
768 opts: Option<GethDebugTracingOptions>,
769 ) -> RpcResult<Vec<TraceResult>> {
770 let _permit = self.acquire_trace_permit().await;
771 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
772 .await
773 .map_err(Into::into)
774 }
775
776 async fn debug_trace_transaction(
778 &self,
779 tx_hash: B256,
780 opts: Option<GethDebugTracingOptions>,
781 ) -> RpcResult<GethTrace> {
782 let _permit = self.acquire_trace_permit().await;
783 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
784 .await
785 .map_err(Into::into)
786 }
787
788 async fn debug_trace_call(
790 &self,
791 request: RpcTxReq<Eth::NetworkTypes>,
792 block_id: Option<BlockId>,
793 opts: Option<GethDebugTracingCallOptions>,
794 ) -> RpcResult<GethTrace> {
795 let _permit = self.acquire_trace_permit().await;
796 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
797 .await
798 .map_err(Into::into)
799 }
800
801 async fn debug_trace_call_many(
802 &self,
803 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
804 state_context: Option<StateContext>,
805 opts: Option<GethDebugTracingCallOptions>,
806 ) -> RpcResult<Vec<Vec<GethTrace>>> {
807 let _permit = self.acquire_trace_permit().await;
808 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
809 }
810
811 async fn debug_execution_witness(
813 &self,
814 block: BlockNumberOrTag,
815 mode: Option<ExecutionWitnessMode>,
816 ) -> RpcResult<ExecutionWitness> {
817 let _permit = self.acquire_trace_permit().await;
818 Self::debug_execution_witness(self, block, mode).await.map_err(Into::into)
819 }
820
821 async fn debug_execution_witness_by_block_hash(
823 &self,
824 hash: B256,
825 mode: Option<ExecutionWitnessMode>,
826 ) -> RpcResult<ExecutionWitness> {
827 let _permit = self.acquire_trace_permit().await;
828 Self::debug_execution_witness_by_block_hash(self, hash, mode).await.map_err(Into::into)
829 }
830
831 async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> {
832 Ok(())
833 }
834
835 async fn debug_account_range(
836 &self,
837 _block_number: BlockNumberOrTag,
838 _start: Bytes,
839 _max_results: u64,
840 _nocode: bool,
841 _nostorage: bool,
842 _incompletes: bool,
843 ) -> RpcResult<()> {
844 Ok(())
845 }
846
847 async fn debug_block_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
848 Ok(())
849 }
850
851 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
852 Ok(())
853 }
854
855 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
856 Ok(self.provider().chain_spec().genesis().config.clone())
857 }
858
859 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
860 Ok(())
861 }
862
863 async fn debug_code_by_hash(
864 &self,
865 hash: B256,
866 block_id: Option<BlockId>,
867 ) -> RpcResult<Option<Bytes>> {
868 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
869 }
870
871 async fn debug_cpu_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
872 Ok(())
873 }
874
875 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
876 Ok(())
877 }
878
879 async fn debug_db_ancients(&self) -> RpcResult<()> {
880 Ok(())
881 }
882
883 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
894 let key_bytes = if key.starts_with("0x") {
895 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
896 } else {
897 key.into_bytes()
898 };
899
900 if key_bytes.len() != 33 {
901 return Err(EthApiError::InvalidParams(format!(
902 "Key must be 33 bytes, got {}",
903 key_bytes.len()
904 ))
905 .into());
906 }
907 if key_bytes[0] != 0x63 {
908 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
909 }
910
911 let code_hash = B256::from_slice(&key_bytes[1..33]);
912
913 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
915 }
916
917 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
918 Ok(())
919 }
920
921 async fn debug_free_os_memory(&self) -> RpcResult<()> {
922 Ok(())
923 }
924
925 async fn debug_freeze_client(&self, _node: String) -> RpcResult<()> {
926 Ok(())
927 }
928
929 async fn debug_gc_stats(&self) -> RpcResult<()> {
930 Ok(())
931 }
932
933 async fn debug_get_accessible_state(
934 &self,
935 _from: BlockNumberOrTag,
936 _to: BlockNumberOrTag,
937 ) -> RpcResult<()> {
938 Ok(())
939 }
940
941 async fn debug_get_modified_accounts_by_hash(
942 &self,
943 _start_hash: B256,
944 _end_hash: B256,
945 ) -> RpcResult<()> {
946 Ok(())
947 }
948
949 async fn debug_get_modified_accounts_by_number(
950 &self,
951 _start_number: u64,
952 _end_number: u64,
953 ) -> RpcResult<()> {
954 Ok(())
955 }
956
957 async fn debug_go_trace(&self, _file: String, _seconds: u64) -> RpcResult<()> {
958 Ok(())
959 }
960
961 async fn debug_intermediate_roots(
962 &self,
963 block_hash: B256,
964 _opts: Option<GethDebugTracingCallOptions>,
965 ) -> RpcResult<Vec<B256>> {
966 let _permit = self.acquire_trace_permit().await;
967 self.intermediate_roots(block_hash).await.map_err(Into::into)
968 }
969
970 async fn debug_mem_stats(&self) -> RpcResult<()> {
971 Ok(())
972 }
973
974 async fn debug_mutex_profile(&self, _file: String, _nsec: u64) -> RpcResult<()> {
975 Ok(())
976 }
977
978 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
979 Ok(())
980 }
981
982 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
983 Ok(())
984 }
985
986 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
987 Ok(Default::default())
988 }
989
990 async fn debug_set_block_profile_rate(&self, _rate: u64) -> RpcResult<()> {
991 Ok(())
992 }
993
994 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
995 Ok(())
996 }
997
998 async fn debug_set_head(&self, _number: U64) -> RpcResult<()> {
999 Ok(())
1000 }
1001
1002 async fn debug_set_mutex_profile_fraction(&self, _rate: i32) -> RpcResult<()> {
1003 Ok(())
1004 }
1005
1006 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1007 Ok(())
1008 }
1009
1010 async fn debug_stacks(&self) -> RpcResult<()> {
1011 Ok(())
1012 }
1013
1014 async fn debug_standard_trace_bad_block_to_file(
1015 &self,
1016 _block: BlockNumberOrTag,
1017 _opts: Option<GethDebugTracingCallOptions>,
1018 ) -> RpcResult<()> {
1019 Ok(())
1020 }
1021
1022 async fn debug_standard_trace_block_to_file(
1023 &self,
1024 _block: BlockNumberOrTag,
1025 _opts: Option<GethDebugTracingCallOptions>,
1026 ) -> RpcResult<()> {
1027 Ok(())
1028 }
1029
1030 async fn debug_start_cpu_profile(&self, _file: String) -> RpcResult<()> {
1031 Ok(())
1032 }
1033
1034 async fn debug_start_go_trace(&self, _file: String) -> RpcResult<()> {
1035 Ok(())
1036 }
1037
1038 async fn debug_state_root_with_updates(
1039 &self,
1040 hashed_state: HashedPostState,
1041 block_id: Option<BlockId>,
1042 ) -> RpcResult<(B256, TrieUpdates)> {
1043 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1044 }
1045
1046 async fn debug_stop_cpu_profile(&self) -> RpcResult<()> {
1047 Ok(())
1048 }
1049
1050 async fn debug_stop_go_trace(&self) -> RpcResult<()> {
1051 Ok(())
1052 }
1053
1054 async fn debug_storage_range_at(
1055 &self,
1056 _block_hash: B256,
1057 _tx_idx: usize,
1058 _contract_address: Address,
1059 _key_start: B256,
1060 _max_result: u64,
1061 ) -> RpcResult<()> {
1062 Ok(())
1063 }
1064
1065 async fn debug_trace_bad_block(
1066 &self,
1067 block_hash: B256,
1068 opts: Option<GethDebugTracingCallOptions>,
1069 ) -> RpcResult<Vec<TraceResult>> {
1070 let _permit = self.acquire_trace_permit().await;
1071 let block = self
1072 .inner
1073 .bad_block_store
1074 .get(block_hash)
1075 .ok_or_else(|| internal_rpc_err("bad block not found in cache"))?;
1076
1077 let evm_env = self
1078 .eth_api()
1079 .evm_config()
1080 .evm_env(block.header())
1081 .map_err(RethError::other)
1082 .to_rpc_result()?;
1083
1084 let opts = opts.map(|o| o.tracing_options).unwrap_or_default();
1085 self.trace_block(block, evm_env, opts).await.map_err(Into::into)
1086 }
1087
1088 async fn debug_verbosity(&self, level: usize) -> RpcResult<()> {
1089 reth_tracing::set_log_verbosity(level).map_err(internal_rpc_err)
1090 }
1091
1092 async fn debug_vmodule(&self, pattern: String) -> RpcResult<()> {
1093 reth_tracing::set_log_vmodule(&pattern).map_err(internal_rpc_err)
1094 }
1095
1096 async fn debug_write_block_profile(&self, _file: String) -> RpcResult<()> {
1097 Ok(())
1098 }
1099
1100 async fn debug_write_mem_profile(&self, _file: String) -> RpcResult<()> {
1101 Ok(())
1102 }
1103
1104 async fn debug_write_mutex_profile(&self, _file: String) -> RpcResult<()> {
1105 Ok(())
1106 }
1107}
1108
1109impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1111 f.debug_struct("DebugApi").finish_non_exhaustive()
1112 }
1113}
1114
1115impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1116 fn clone(&self) -> Self {
1117 Self { inner: Arc::clone(&self.inner) }
1118 }
1119}
1120
1121struct DebugApiInner<Eth: RpcNodeCore> {
1122 eth_api: Eth,
1124 blocking_task_guard: BlockingTaskGuard,
1126 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1128}
1129
1130#[derive(Clone, Debug)]
1132struct BadBlockStore<B: BlockTrait> {
1133 inner: Arc<RwLock<VecDeque<Arc<RecoveredBlock<B>>>>>,
1134 limit: usize,
1135}
1136
1137impl<B: BlockTrait> BadBlockStore<B> {
1138 fn new(limit: usize) -> Self {
1140 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1141 }
1142
1143 fn insert(&self, block: RecoveredBlock<B>) {
1146 let hash = block.hash();
1147 let mut guard = self.inner.write();
1148
1149 if guard.iter().any(|b| b.hash() == hash) {
1151 return;
1152 }
1153 guard.push_back(Arc::new(block));
1154
1155 while guard.len() > self.limit {
1156 guard.pop_front();
1157 }
1158 }
1159
1160 fn all(&self) -> Vec<Arc<RecoveredBlock<B>>> {
1162 let guard = self.inner.read();
1163 guard.iter().rev().cloned().collect()
1164 }
1165
1166 fn get(&self, hash: B256) -> Option<Arc<RecoveredBlock<B>>> {
1168 let guard = self.inner.read();
1169 guard.iter().find(|b| b.hash() == hash).cloned()
1170 }
1171}
1172
1173impl<B: BlockTrait> Default for BadBlockStore<B> {
1174 fn default() -> Self {
1175 Self::new(64)
1176 }
1177}