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