1use alloy_consensus::{constants::KECCAK_EMPTY, 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::{
10 state::EvmOverrides, Account, AccountInfo, BlockError, Bundle, Index, StateContext,
11};
12use alloy_rpc_types_trace::geth::{
13 BlockTraceResult, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult,
14};
15use async_trait::async_trait;
16use futures::Stream;
17use jsonrpsee::core::RpcResult;
18use parking_lot::RwLock;
19use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
20use reth_engine_primitives::ConsensusEngineEvent;
21use reth_errors::RethError;
22use reth_evm::{block::BlockExecutor, execute::Executor, ConfigureEvm, EvmEnvFor};
23use reth_primitives_traits::{
24 Block as BlockTrait, BlockBody, BlockTy, ReceiptWithBloom, RecoveredBlock,
25};
26use reth_revm::{db::State, witness::ExecutionWitnessRecord};
27use reth_rpc_api::DebugApiServer;
28use reth_rpc_convert::RpcTxReq;
29use reth_rpc_eth_api::{
30 helpers::{EthTransactions, TraceExt},
31 FromEthApiError, FromEvmError, RpcConvert, RpcNodeCore,
32};
33use reth_rpc_eth_types::{EthApiError, StateCacheDb};
34use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
35use reth_storage_api::{
36 BlockIdReader, BlockReaderIdExt, HashedPostStateProvider, HeaderProvider, ProviderBlock,
37 ReceiptProviderIdExt, StateProviderFactory, StateRootProvider, StorageRootProvider,
38 TransactionVariant,
39};
40use reth_tasks::{pool::BlockingTaskGuard, Runtime};
41use reth_transaction_pool::TransactionPool;
42use reth_trie_common::{
43 updates::TrieUpdates, ExecutionWitnessMode, HashedPostState, HashedStorage,
44};
45use revm::{database::states::bundle_state::BundleRetention, Database, DatabaseCommit};
46use revm_inspectors::tracing::{DebugInspector, TransactionContext};
47use serde::{Deserialize, Serialize};
48use std::{collections::VecDeque, sync::Arc};
49use tokio::sync::{AcquireError, OwnedSemaphorePermit};
50use tokio_stream::StreamExt;
51
52pub struct DebugApi<Eth: RpcNodeCore> {
56 inner: Arc<DebugApiInner<Eth>>,
57}
58
59impl<Eth> DebugApi<Eth>
60where
61 Eth: RpcNodeCore,
62{
63 pub fn new(
65 eth_api: Eth,
66 blocking_task_guard: BlockingTaskGuard,
67 executor: &Runtime,
68 mut stream: impl Stream<Item = ConsensusEngineEvent<Eth::Primitives>> + Send + Unpin + 'static,
69 ) -> Self {
70 let bad_block_store = BadBlockStore::default();
71 let inner = Arc::new(DebugApiInner {
72 eth_api,
73 blocking_task_guard,
74 bad_block_store: bad_block_store.clone(),
75 });
76
77 executor.spawn_task(async move {
79 while let Some(event) = stream.next().await {
80 if let ConsensusEngineEvent::InvalidBlock { block, error } = event &&
81 let Ok(recovered) = RecoveredBlock::try_recover_sealed(*block)
82 {
83 bad_block_store.insert(recovered, error);
84 }
85 }
86 });
87
88 Self { inner }
89 }
90
91 pub fn eth_api(&self) -> &Eth {
93 &self.inner.eth_api
94 }
95
96 pub fn provider(&self) -> &Eth::Provider {
98 self.inner.eth_api.provider()
99 }
100}
101
102impl<Eth> DebugApi<Eth>
105where
106 Eth: TraceExt,
107{
108 async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
110 self.inner.blocking_task_guard.clone().acquire_owned().await
111 }
112
113 async fn trace_block(
115 &self,
116 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
117 evm_env: EvmEnvFor<Eth::Evm>,
118 opts: GethDebugTracingOptions,
119 ) -> Result<Vec<TraceResult>, Eth::Error> {
120 self.eth_api()
121 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
122 let mut results = Vec::with_capacity(block.body().transactions().len());
123
124 eth_api.apply_pre_execution_changes(&block, &mut db)?;
125
126 let mut transactions = block.transactions_recovered().enumerate().peekable();
127 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
128 while let Some((index, tx)) = transactions.next() {
129 let tx_hash = *tx.tx_hash();
130 let tx_env = eth_api.evm_config().tx_env(tx);
131
132 let res = eth_api.inspect(
133 &mut db,
134 evm_env.clone(),
135 tx_env.clone(),
136 &mut inspector,
137 )?;
138 let result = inspector
139 .get_result(
140 Some(TransactionContext {
141 block_hash: Some(block.hash()),
142 tx_hash: Some(tx_hash),
143 tx_index: Some(index),
144 }),
145 &tx_env,
146 &evm_env.block_env,
147 &res,
148 &mut db,
149 )
150 .map_err(Eth::Error::from_eth_err)?;
151
152 results.push(TraceResult::Success { result, tx_hash: Some(tx_hash) });
153 if transactions.peek().is_some() {
154 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
155 db.commit(res.state)
158 }
159 }
160
161 Ok(results)
162 })
163 .await
164 }
165
166 pub async fn debug_trace_raw_block(
172 &self,
173 rlp_block: Bytes,
174 opts: GethDebugTracingOptions,
175 ) -> Result<Vec<TraceResult>, Eth::Error> {
176 let block: ProviderBlock<Eth::Provider> = Decodable::decode(&mut rlp_block.as_ref())
177 .map_err(BlockError::RlpDecodeRawBlock)
178 .map_err(Eth::Error::from_eth_err)?;
179
180 let evm_env = self
181 .eth_api()
182 .evm_config()
183 .evm_env(block.header())
184 .map_err(RethError::other)
185 .map_err(Eth::Error::from_eth_err)?;
186
187 let senders =
189 if self.provider().chain_spec().is_homestead_active_at_block(block.header().number()) {
190 block.body().recover_signers()
191 } else {
192 block.body().recover_signers_unchecked()
193 }
194 .map_err(Eth::Error::from_eth_err)?;
195
196 self.trace_block(Arc::new(block.into_recovered_with_signers(senders)), evm_env, opts).await
197 }
198
199 pub async fn debug_trace_block(
201 &self,
202 block_id: BlockId,
203 opts: GethDebugTracingOptions,
204 ) -> Result<Vec<TraceResult>, Eth::Error> {
205 let block = self
206 .eth_api()
207 .recovered_block(block_id)
208 .await?
209 .ok_or(EthApiError::TracingBlockNotFound(block_id))?;
210 if block.number() == 0 {
212 return Err(EthApiError::GenesisNotTraceable.into())
213 }
214 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
215
216 self.trace_block(block, evm_env, opts).await
217 }
218
219 pub async fn debug_trace_transaction(
223 &self,
224 tx_hash: B256,
225 opts: GethDebugTracingOptions,
226 ) -> Result<GethTrace, Eth::Error> {
227 let (transaction, block) = match self.eth_api().transaction_and_block(tx_hash).await? {
228 None => return Err(EthApiError::TracingTransactionNotFound.into()),
229 Some(res) => res,
230 };
231 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
232
233 let state_at: BlockId = block.parent_hash().into();
236 let block_hash = block.hash();
237
238 self.eth_api()
239 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
240 let block_txs = block.transactions_recovered();
241
242 let tx = transaction.into_recovered();
244
245 eth_api.apply_pre_execution_changes(&block, &mut db)?;
246
247 let index = eth_api.replay_transactions_until(
249 &mut db,
250 evm_env.clone(),
251 block_txs,
252 *tx.tx_hash(),
253 )?;
254
255 let tx_env = eth_api.evm_config().tx_env(&tx);
256
257 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
258 let res =
259 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
260 let trace = inspector
261 .get_result(
262 Some(TransactionContext {
263 block_hash: Some(block_hash),
264 tx_index: Some(index),
265 tx_hash: Some(*tx.tx_hash()),
266 }),
267 &tx_env,
268 &evm_env.block_env,
269 &res,
270 &mut db,
271 )
272 .map_err(Eth::Error::from_eth_err)?;
273
274 Ok(trace)
275 })
276 .await
277 }
278
279 pub async fn debug_trace_call(
289 &self,
290 call: RpcTxReq<Eth::NetworkTypes>,
291 block_id: Option<BlockId>,
292 opts: GethDebugTracingCallOptions,
293 ) -> Result<GethTrace, Eth::Error> {
294 let at = block_id.unwrap_or_default();
295 let GethDebugTracingCallOptions {
296 tracing_options,
297 state_overrides,
298 block_overrides,
299 tx_index,
300 } = opts;
301 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
302
303 if let Some(tx_idx) = tx_index {
305 return self
306 .debug_trace_call_at_tx_index(call, at, tx_idx as usize, tracing_options, overrides)
307 .await;
308 }
309
310 let this = self.clone();
311 self.eth_api()
312 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
313 let mut inspector =
314 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
315 let res = this.eth_api().inspect(
316 &mut *db,
317 evm_env.clone(),
318 tx_env.clone(),
319 &mut inspector,
320 )?;
321 let trace = inspector
322 .get_result(None, &tx_env, &evm_env.block_env, &res, db)
323 .map_err(Eth::Error::from_eth_err)?;
324 Ok(trace)
325 })
326 .await
327 }
328
329 async fn debug_trace_call_at_tx_index(
333 &self,
334 call: RpcTxReq<Eth::NetworkTypes>,
335 block_id: BlockId,
336 tx_index: usize,
337 tracing_options: GethDebugTracingOptions,
338 overrides: EvmOverrides,
339 ) -> Result<GethTrace, Eth::Error> {
340 let block = self
342 .eth_api()
343 .recovered_block(block_id)
344 .await?
345 .ok_or(EthApiError::HeaderNotFound(block_id))?;
346
347 if tx_index >= block.transaction_count() {
348 return Err(EthApiError::InvalidParams(format!(
350 "tx_index {} out of bounds for block with {} transactions",
351 tx_index,
352 block.transaction_count()
353 ))
354 .into())
355 }
356
357 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
358
359 let state_at = block.parent_hash();
361
362 self.eth_api()
363 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
364 eth_api.apply_pre_execution_changes(&block, &mut db)?;
366
367 eth_api.replay_transactions_until(
369 &mut db,
370 evm_env.clone(),
371 block.transactions_recovered(),
372 *block.body().transactions()[tx_index].tx_hash(),
373 )?;
374
375 let (evm_env, tx_env) =
377 eth_api.prepare_call_env(evm_env, call, &mut db, overrides)?;
378
379 let mut inspector =
380 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
381 let res =
382 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
383 let trace = inspector
384 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
385 .map_err(Eth::Error::from_eth_err)?;
386
387 Ok(trace)
388 })
389 .await
390 }
391
392 pub async fn debug_trace_call_many(
396 &self,
397 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
398 state_context: Option<StateContext>,
399 opts: Option<GethDebugTracingCallOptions>,
400 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
401 if bundles.is_empty() {
402 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
403 }
404
405 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
406 let transaction_index = transaction_index.unwrap_or_default();
407
408 let target_block = block_number.unwrap_or_default();
409 let block = self
410 .eth_api()
411 .recovered_block(target_block)
412 .await?
413 .ok_or(EthApiError::HeaderNotFound(target_block))?;
414 let mut evm_env =
415 self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
416
417 let opts = opts.unwrap_or_default();
418 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
419
420 let mut at = block.parent_hash();
423 let mut replay_block_txs = true;
424
425 let num_txs =
427 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
428 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
432 at = block.hash();
433 replay_block_txs = false;
434 }
435
436 self.eth_api()
437 .spawn_with_state_at_block(at, move |eth_api, mut db| {
438 let mut all_bundles = Vec::with_capacity(bundles.len());
440
441 if replay_block_txs {
442 eth_api.apply_pre_execution_changes(&block, &mut db)?;
445
446 let transactions = block.transactions_recovered().take(num_txs);
447
448 for tx in transactions {
450 let tx_env = eth_api.evm_config().tx_env(tx);
451 let res = eth_api.transact(&mut db, evm_env.clone(), tx_env)?;
452 db.commit(res.state);
453 }
454 }
455
456 let mut bundles = bundles.into_iter().peekable();
458 let mut inspector = DebugInspector::new(tracing_options.clone())
459 .map_err(Eth::Error::from_eth_err)?;
460 while let Some(bundle) = bundles.next() {
461 let mut results = Vec::with_capacity(bundle.transactions.len());
462 let Bundle { transactions, block_override } = bundle;
463
464 let block_overrides = block_override.map(Box::new);
465
466 let mut transactions = transactions.into_iter().peekable();
467 while let Some(tx) = transactions.next() {
468 let state_overrides = state_overrides.take();
470 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
471
472 let (evm_env, tx_env) =
473 eth_api.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
474
475 let res = eth_api.inspect(
476 &mut db,
477 evm_env.clone(),
478 tx_env.clone(),
479 &mut inspector,
480 )?;
481 let trace = inspector
482 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
483 .map_err(Eth::Error::from_eth_err)?;
484
485 if transactions.peek().is_some() || bundles.peek().is_some() {
488 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
489 db.commit(res.state);
490 }
491 results.push(trace);
492 }
493 evm_env.block_env.inner_mut().number += uint!(1_U256);
495 evm_env.block_env.inner_mut().timestamp += uint!(12_U256);
496
497 all_bundles.push(results);
498 }
499 Ok(all_bundles)
500 })
501 .await
502 }
503
504 pub async fn debug_execution_witness_by_block_hash(
507 &self,
508 hash: B256,
509 mode: Option<ExecutionWitnessMode>,
510 ) -> Result<ExecutionWitness, Eth::Error> {
511 let this = self.clone();
512 let block = this
513 .eth_api()
514 .recovered_block(hash.into())
515 .await?
516 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
517
518 self.debug_execution_witness_for_block(block, mode.unwrap_or_default()).await
519 }
520
521 pub async fn debug_execution_witness(
526 &self,
527 block_id: BlockNumberOrTag,
528 mode: Option<ExecutionWitnessMode>,
529 ) -> Result<ExecutionWitness, Eth::Error> {
530 let this = self.clone();
531 let block = this
532 .eth_api()
533 .recovered_block(block_id.into())
534 .await?
535 .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;
536
537 self.debug_execution_witness_for_block(block, mode.unwrap_or_default()).await
538 }
539
540 pub async fn debug_execution_witness_for_block(
542 &self,
543 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
544 mode: ExecutionWitnessMode,
545 ) -> Result<ExecutionWitness, Eth::Error> {
546 let block_number = block.header().number();
547 self.eth_api()
548 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
549 let block_executor = eth_api.evm_config().executor(&mut db);
550
551 let mut witness_record = ExecutionWitnessRecord::default();
552
553 let _ = block_executor
554 .execute_with_state_closure(&block, |statedb: &State<_>| {
555 witness_record.record_executed_state(statedb, mode);
556 })
557 .map_err(|err| EthApiError::Internal(err.into()))?;
558
559 Ok(witness_record
560 .into_execution_witness(&db.database.0, eth_api.provider(), block_number, mode)
561 .map_err(EthApiError::from)?)
562 })
563 .await
564 }
565
566 pub async fn debug_account_at(
569 &self,
570 block_id: BlockId,
571 tx_index: Index,
572 address: Address,
573 ) -> Result<Option<Account>, Eth::Error> {
574 self.replay_block_until(block_id, tx_index, move |db| Self::account(db, address))
575 .await
576 .map(Option::flatten)
577 }
578
579 pub async fn debug_account_info_at(
582 &self,
583 block_id: BlockId,
584 tx_index: Index,
585 address: Address,
586 ) -> Result<Option<AccountInfo>, Eth::Error> {
587 self.replay_block_until(block_id, tx_index, move |db| Self::account_info(db, address)).await
588 }
589
590 async fn replay_block_until<F, R>(
593 &self,
594 block_id: BlockId,
595 tx_index: Index,
596 f: F,
597 ) -> Result<Option<R>, Eth::Error>
598 where
599 F: FnOnce(&mut StateCacheDb) -> Result<R, Eth::Error> + Send + 'static,
600 R: Send + 'static,
601 {
602 let block = self
603 .eth_api()
604 .recovered_block(block_id)
605 .await?
606 .ok_or(EthApiError::HeaderNotFound(block_id))?;
607 let tx_index = usize::from(tx_index);
608 let transaction_count = block.transaction_count();
609 if tx_index >= transaction_count {
610 return Err(EthApiError::InvalidParams(format!(
611 "tx_index {tx_index} out of bounds for block with {transaction_count} transactions"
612 ))
613 .into())
614 }
615
616 self.eth_api()
617 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
618 let mut executor = eth_api
619 .evm_config()
620 .executor_for_block(&mut db, block.sealed_block())
621 .map_err(RethError::other)
622 .map_err(Eth::Error::from_eth_err)?;
623 executor.apply_pre_execution_changes().map_err(Eth::Error::from_eth_err)?;
624
625 for tx in block.transactions_recovered().take(tx_index + 1) {
626 executor.execute_transaction(tx).map_err(Eth::Error::from_eth_err)?;
627 }
628 drop(executor);
629
630 f(&mut db)
631 })
632 .await
633 .map(Some)
634 }
635
636 fn account(db: &mut StateCacheDb, address: Address) -> Result<Option<Account>, Eth::Error> {
638 let account = db.basic(address).map_err(Eth::Error::from_eth_err)?;
639 let Some(account) = account else { return Ok(None) };
640
641 let balance = account.balance;
642 let nonce = account.nonce;
643 let code_hash = account.code_hash;
644 let hashed_storage = db
645 .cache
646 .accounts
647 .get(&address)
648 .and_then(|account| {
649 account.account.as_ref().map(|plain_account| {
650 HashedStorage::from_plain_storage(account.status, plain_account.storage.iter())
651 })
652 })
653 .unwrap_or_default();
654 let storage_root =
655 db.database.storage_root(address, hashed_storage).map_err(Eth::Error::from_eth_err)?;
656
657 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
658 }
659
660 fn account_info<DB>(db: &mut DB, address: Address) -> Result<AccountInfo, Eth::Error>
662 where
663 DB: Database,
664 EthApiError: From<DB::Error>,
665 {
666 let account = db.basic(address).map_err(Eth::Error::from_eth_err)?.unwrap_or_default();
667 let code = if account.code_hash == KECCAK_EMPTY {
668 Default::default()
669 } else if let Some(code) = account.code {
670 code.original_bytes()
671 } else {
672 db.code_by_hash(account.code_hash).map_err(Eth::Error::from_eth_err)?.original_bytes()
673 };
674
675 Ok(AccountInfo { balance: account.balance, nonce: account.nonce, code })
676 }
677
678 pub async fn debug_code_by_hash(
681 &self,
682 hash: B256,
683 block_id: Option<BlockId>,
684 ) -> Result<Option<Bytes>, Eth::Error> {
685 Ok(self
686 .provider()
687 .state_by_block_id(block_id.unwrap_or_default())
688 .map_err(Eth::Error::from_eth_err)?
689 .bytecode_by_hash(&hash)
690 .map_err(Eth::Error::from_eth_err)?
691 .map(|b| b.original_bytes()))
692 }
693
694 async fn debug_state_root_with_updates(
697 &self,
698 hashed_state: HashedPostState,
699 block_id: Option<BlockId>,
700 ) -> Result<(B256, TrieUpdates), Eth::Error> {
701 self.inner
702 .eth_api
703 .spawn_blocking_io(move |this| {
704 let state = this
705 .provider()
706 .state_by_block_id(block_id.unwrap_or_default())
707 .map_err(Eth::Error::from_eth_err)?;
708 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
709 })
710 .await
711 }
712
713 pub async fn intermediate_roots(&self, block_hash: B256) -> Result<Vec<B256>, Eth::Error> {
715 let block = self
716 .eth_api()
717 .recovered_block(block_hash.into())
718 .await?
719 .ok_or(EthApiError::HeaderNotFound(block_hash.into()))?;
720 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
721
722 self.eth_api()
723 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
724 db.transition_state = Some(Default::default());
726
727 eth_api.apply_pre_execution_changes(&block, &mut db)?;
728
729 let mut roots = Vec::with_capacity(block.body().transactions().len());
730 for tx in block.transactions_recovered() {
731 let tx_env = eth_api.evm_config().tx_env(tx);
732 {
733 let mut evm = eth_api.evm_config().evm_with_env(&mut db, evm_env.clone());
734 evm.transact_commit(tx_env).map_err(Eth::Error::from_evm_err)?;
735 }
736 db.merge_transitions(BundleRetention::PlainState);
738 let hashed_state = db.database.hashed_post_state(&db.bundle_state);
740 let root =
741 db.database.state_root(hashed_state).map_err(Eth::Error::from_eth_err)?;
742 roots.push(root);
743 }
744
745 Ok(roots)
746 })
747 .await
748 }
749}
750
751#[async_trait]
752impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
753where
754 Eth: EthTransactions + TraceExt,
755{
756 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
758 let header = match block_id {
759 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
760 BlockId::Number(number_or_tag) => {
761 let number = self
762 .provider()
763 .convert_block_number(number_or_tag)
764 .to_rpc_result()?
765 .ok_or(EthApiError::HeaderNotFound(block_id))?;
766 self.provider().header_by_number(number).to_rpc_result()?
767 }
768 }
769 .ok_or(EthApiError::HeaderNotFound(block_id))?;
770
771 let mut res = Vec::new();
772 header.encode(&mut res);
773 Ok(res.into())
774 }
775
776 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
778 let block = self
779 .provider()
780 .block_by_id(block_id)
781 .to_rpc_result()?
782 .ok_or(EthApiError::HeaderNotFound(block_id))?;
783 let mut res = Vec::new();
784 block.encode(&mut res);
785 Ok(res.into())
786 }
787
788 async fn raw_block_access_list(&self, block_id: BlockId) -> RpcResult<Bytes> {
790 self.eth_api()
791 .get_raw_block_access_list(block_id)
792 .await
793 .map_err(Into::into)?
794 .ok_or_else(|| EthApiError::HeaderNotFound(block_id).into())
795 }
796
797 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
803 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
804 }
805
806 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
809 let block: RecoveredBlock<BlockTy<Eth::Primitives>> = self
810 .provider()
811 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
812 .to_rpc_result()?
813 .unwrap_or_default();
814 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
815 }
816
817 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
819 Ok(self
820 .provider()
821 .receipts_by_block_id(block_id)
822 .to_rpc_result()?
823 .ok_or(EthApiError::HeaderNotFound(block_id))?
824 .into_iter()
825 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
826 .collect())
827 }
828
829 async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>> {
831 let entries = self.inner.bad_block_store.all();
832 let mut bad_blocks = Vec::with_capacity(entries.len());
833
834 #[derive(Serialize, Deserialize)]
835 struct BadBlockSerde<T> {
836 block: T,
837 hash: B256,
838 rlp: Bytes,
839 reason: String,
840 }
841
842 for entry in entries {
843 let rlp = alloy_rlp::encode(entry.block.sealed_block()).into();
844 let hash = entry.block.hash();
845
846 let block = entry
847 .block
848 .clone_into_rpc_block(
849 BlockTransactionsKind::Full,
850 |tx, tx_info| self.eth_api().converter().fill(tx, tx_info),
851 |header, size| self.eth_api().converter().convert_header(header, size),
852 )
853 .map_err(|err| Eth::Error::from(err).into())?;
854
855 let bad_block =
856 serde_json::to_value(BadBlockSerde { block, hash, rlp, reason: entry.reason })
857 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
858
859 bad_blocks.push(bad_block);
860 }
861
862 Ok(bad_blocks)
863 }
864
865 async fn debug_clear_txpool(&self) -> RpcResult<()> {
867 let pool = self.eth_api().pool();
868 let all_hashes = pool.all_transaction_hashes();
869 let _ = pool.remove_transactions(all_hashes);
870 Ok(())
871 }
872
873 async fn debug_trace_chain(
875 &self,
876 _start_exclusive: BlockNumberOrTag,
877 _end_inclusive: BlockNumberOrTag,
878 ) -> RpcResult<Vec<BlockTraceResult>> {
879 Err(internal_rpc_err("unimplemented"))
880 }
881
882 async fn debug_trace_block(
884 &self,
885 rlp_block: Bytes,
886 opts: Option<GethDebugTracingOptions>,
887 ) -> RpcResult<Vec<TraceResult>> {
888 let _permit = self.acquire_trace_permit().await;
889 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
890 .await
891 .map_err(Into::into)
892 }
893
894 async fn debug_trace_block_by_hash(
896 &self,
897 block: B256,
898 opts: Option<GethDebugTracingOptions>,
899 ) -> RpcResult<Vec<TraceResult>> {
900 let _permit = self.acquire_trace_permit().await;
901 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
902 .await
903 .map_err(Into::into)
904 }
905
906 async fn debug_trace_block_by_number(
908 &self,
909 block: BlockNumberOrTag,
910 opts: Option<GethDebugTracingOptions>,
911 ) -> RpcResult<Vec<TraceResult>> {
912 let _permit = self.acquire_trace_permit().await;
913 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
914 .await
915 .map_err(Into::into)
916 }
917
918 async fn debug_trace_transaction(
920 &self,
921 tx_hash: B256,
922 opts: Option<GethDebugTracingOptions>,
923 ) -> RpcResult<GethTrace> {
924 let _permit = self.acquire_trace_permit().await;
925 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
926 .await
927 .map_err(Into::into)
928 }
929
930 async fn debug_trace_call(
932 &self,
933 request: RpcTxReq<Eth::NetworkTypes>,
934 block_id: Option<BlockId>,
935 opts: Option<GethDebugTracingCallOptions>,
936 ) -> RpcResult<GethTrace> {
937 let _permit = self.acquire_trace_permit().await;
938 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
939 .await
940 .map_err(Into::into)
941 }
942
943 async fn debug_trace_call_many(
944 &self,
945 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
946 state_context: Option<StateContext>,
947 opts: Option<GethDebugTracingCallOptions>,
948 ) -> RpcResult<Vec<Vec<GethTrace>>> {
949 let _permit = self.acquire_trace_permit().await;
950 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
951 }
952
953 async fn debug_execution_witness(
955 &self,
956 block: BlockNumberOrTag,
957 mode: Option<ExecutionWitnessMode>,
958 ) -> RpcResult<ExecutionWitness> {
959 let _permit = self.acquire_trace_permit().await;
960 Self::debug_execution_witness(self, block, mode).await.map_err(Into::into)
961 }
962
963 async fn debug_execution_witness_by_block_hash(
965 &self,
966 hash: B256,
967 mode: Option<ExecutionWitnessMode>,
968 ) -> RpcResult<ExecutionWitness> {
969 let _permit = self.acquire_trace_permit().await;
970 Self::debug_execution_witness_by_block_hash(self, hash, mode).await.map_err(Into::into)
971 }
972
973 async fn debug_account_at(
975 &self,
976 block_id: BlockId,
977 tx_index: Index,
978 address: Address,
979 ) -> RpcResult<Option<Account>> {
980 let _permit = self.acquire_trace_permit().await;
981 Self::debug_account_at(self, block_id, tx_index, address).await.map_err(Into::into)
982 }
983
984 async fn debug_account_info_at(
986 &self,
987 block_id: BlockId,
988 tx_index: Index,
989 address: Address,
990 ) -> RpcResult<Option<AccountInfo>> {
991 let _permit = self.acquire_trace_permit().await;
992 Self::debug_account_info_at(self, block_id, tx_index, address).await.map_err(Into::into)
993 }
994
995 async fn debug_account_range(
996 &self,
997 _block_number: BlockNumberOrTag,
998 _start: Bytes,
999 _max_results: u64,
1000 _nocode: bool,
1001 _nostorage: bool,
1002 _incompletes: bool,
1003 ) -> RpcResult<()> {
1004 Ok(())
1005 }
1006
1007 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
1008 Ok(())
1009 }
1010
1011 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
1012 Ok(self.provider().chain_spec().genesis().config.clone())
1013 }
1014
1015 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
1016 Ok(())
1017 }
1018
1019 async fn debug_code_by_hash(
1020 &self,
1021 hash: B256,
1022 block_id: Option<BlockId>,
1023 ) -> RpcResult<Option<Bytes>> {
1024 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
1025 }
1026
1027 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
1028 Ok(())
1029 }
1030
1031 async fn debug_db_ancients(&self) -> RpcResult<()> {
1032 Ok(())
1033 }
1034
1035 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
1046 let key_bytes = if key.starts_with("0x") {
1047 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
1048 } else {
1049 key.into_bytes()
1050 };
1051
1052 if key_bytes.len() != 33 {
1053 return Err(EthApiError::InvalidParams(format!(
1054 "Key must be 33 bytes, got {}",
1055 key_bytes.len()
1056 ))
1057 .into());
1058 }
1059 if key_bytes[0] != 0x63 {
1060 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
1061 }
1062
1063 let code_hash = B256::from_slice(&key_bytes[1..33]);
1064
1065 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
1067 }
1068
1069 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
1070 Ok(())
1071 }
1072
1073 async fn debug_free_os_memory(&self) -> RpcResult<()> {
1074 Ok(())
1075 }
1076
1077 async fn debug_gc_stats(&self) -> RpcResult<()> {
1078 Ok(())
1079 }
1080
1081 async fn debug_get_accessible_state(
1082 &self,
1083 _from: BlockNumberOrTag,
1084 _to: BlockNumberOrTag,
1085 ) -> RpcResult<()> {
1086 Ok(())
1087 }
1088
1089 async fn debug_get_modified_accounts_by_hash(
1090 &self,
1091 _start_hash: B256,
1092 _end_hash: B256,
1093 ) -> RpcResult<()> {
1094 Ok(())
1095 }
1096
1097 async fn debug_get_modified_accounts_by_number(
1098 &self,
1099 _start_number: u64,
1100 _end_number: u64,
1101 ) -> RpcResult<()> {
1102 Ok(())
1103 }
1104
1105 async fn debug_intermediate_roots(
1106 &self,
1107 block_hash: B256,
1108 _opts: Option<GethDebugTracingCallOptions>,
1109 ) -> RpcResult<Vec<B256>> {
1110 let _permit = self.acquire_trace_permit().await;
1111 self.intermediate_roots(block_hash).await.map_err(Into::into)
1112 }
1113
1114 async fn debug_mem_stats(&self) -> RpcResult<()> {
1115 Ok(())
1116 }
1117
1118 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
1119 Ok(())
1120 }
1121
1122 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
1123 Ok(())
1124 }
1125
1126 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
1127 Ok(Default::default())
1128 }
1129
1130 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
1131 Ok(())
1132 }
1133
1134 async fn debug_set_head(&self, _number: U64) -> RpcResult<()> {
1135 Ok(())
1136 }
1137
1138 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1139 Ok(())
1140 }
1141
1142 async fn debug_standard_trace_bad_block_to_file(
1143 &self,
1144 _block: BlockNumberOrTag,
1145 _opts: Option<GethDebugTracingCallOptions>,
1146 ) -> RpcResult<()> {
1147 Ok(())
1148 }
1149
1150 async fn debug_standard_trace_block_to_file(
1151 &self,
1152 _block: BlockNumberOrTag,
1153 _opts: Option<GethDebugTracingCallOptions>,
1154 ) -> RpcResult<()> {
1155 Ok(())
1156 }
1157
1158 async fn debug_state_root_with_updates(
1159 &self,
1160 hashed_state: HashedPostState,
1161 block_id: Option<BlockId>,
1162 ) -> RpcResult<(B256, TrieUpdates)> {
1163 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1164 }
1165
1166 async fn debug_storage_range_at(
1167 &self,
1168 _block_hash: B256,
1169 _tx_idx: usize,
1170 _contract_address: Address,
1171 _key_start: B256,
1172 _max_result: u64,
1173 ) -> RpcResult<()> {
1174 Ok(())
1175 }
1176
1177 async fn debug_trace_bad_block(
1178 &self,
1179 block_hash: B256,
1180 opts: Option<GethDebugTracingCallOptions>,
1181 ) -> RpcResult<Vec<TraceResult>> {
1182 let _permit = self.acquire_trace_permit().await;
1183 let entry = self
1184 .inner
1185 .bad_block_store
1186 .get(block_hash)
1187 .ok_or_else(|| internal_rpc_err("bad block not found in cache"))?;
1188
1189 let evm_env = self
1190 .eth_api()
1191 .evm_config()
1192 .evm_env(entry.block.header())
1193 .map_err(RethError::other)
1194 .to_rpc_result()?;
1195
1196 let opts = opts.map(|o| o.tracing_options).unwrap_or_default();
1197 self.trace_block(entry.block.clone(), evm_env, opts).await.map_err(Into::into)
1198 }
1199}
1200
1201impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1202 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1203 f.debug_struct("DebugApi").finish_non_exhaustive()
1204 }
1205}
1206
1207impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1208 fn clone(&self) -> Self {
1209 Self { inner: Arc::clone(&self.inner) }
1210 }
1211}
1212
1213struct DebugApiInner<Eth: RpcNodeCore> {
1214 eth_api: Eth,
1216 blocking_task_guard: BlockingTaskGuard,
1218 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1220}
1221
1222#[derive(Clone, Debug)]
1224struct BadBlockStore<B: BlockTrait> {
1225 inner: Arc<RwLock<VecDeque<BadBlockEntry<B>>>>,
1226 limit: usize,
1227}
1228
1229#[derive(Clone, Debug)]
1231struct BadBlockEntry<B: BlockTrait> {
1232 block: Arc<RecoveredBlock<B>>,
1233 reason: String,
1234}
1235
1236impl<B: BlockTrait> BadBlockStore<B> {
1237 fn new(limit: usize) -> Self {
1239 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1240 }
1241
1242 fn insert(&self, block: RecoveredBlock<B>, reason: String) {
1245 let hash = block.hash();
1246 let mut guard = self.inner.write();
1247
1248 if guard.iter().any(|entry| entry.block.hash() == hash) {
1250 return;
1251 }
1252 guard.push_back(BadBlockEntry { block: Arc::new(block), reason });
1253
1254 while guard.len() > self.limit {
1255 guard.pop_front();
1256 }
1257 }
1258
1259 fn all(&self) -> Vec<BadBlockEntry<B>> {
1261 let guard = self.inner.read();
1262 guard.iter().rev().cloned().collect()
1263 }
1264
1265 fn get(&self, hash: B256) -> Option<BadBlockEntry<B>> {
1267 let guard = self.inner.read();
1268 guard.iter().find(|entry| entry.block.hash() == hash).cloned()
1269 }
1270}
1271
1272impl<B: BlockTrait> Default for BadBlockStore<B> {
1273 fn default() -> Self {
1274 Self::new(64)
1275 }
1276}