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::HeaderNotFound(block_id))?;
210 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
211
212 self.trace_block(block, evm_env, opts).await
213 }
214
215 pub async fn debug_trace_transaction(
219 &self,
220 tx_hash: B256,
221 opts: GethDebugTracingOptions,
222 ) -> Result<GethTrace, Eth::Error> {
223 let (transaction, block) = match self.eth_api().transaction_and_block(tx_hash).await? {
224 None => return Err(EthApiError::TransactionNotFound.into()),
225 Some(res) => res,
226 };
227 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
228
229 let state_at: BlockId = block.parent_hash().into();
232 let block_hash = block.hash();
233
234 self.eth_api()
235 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
236 let block_txs = block.transactions_recovered();
237
238 let tx = transaction.into_recovered();
240
241 eth_api.apply_pre_execution_changes(&block, &mut db)?;
242
243 let index = eth_api.replay_transactions_until(
245 &mut db,
246 evm_env.clone(),
247 block_txs,
248 *tx.tx_hash(),
249 )?;
250
251 let tx_env = eth_api.evm_config().tx_env(&tx);
252
253 let mut inspector = DebugInspector::new(opts).map_err(Eth::Error::from_eth_err)?;
254 let res =
255 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
256 let trace = inspector
257 .get_result(
258 Some(TransactionContext {
259 block_hash: Some(block_hash),
260 tx_index: Some(index),
261 tx_hash: Some(*tx.tx_hash()),
262 }),
263 &tx_env,
264 &evm_env.block_env,
265 &res,
266 &mut db,
267 )
268 .map_err(Eth::Error::from_eth_err)?;
269
270 Ok(trace)
271 })
272 .await
273 }
274
275 pub async fn debug_trace_call(
285 &self,
286 call: RpcTxReq<Eth::NetworkTypes>,
287 block_id: Option<BlockId>,
288 opts: GethDebugTracingCallOptions,
289 ) -> Result<GethTrace, Eth::Error> {
290 let at = block_id.unwrap_or_default();
291 let GethDebugTracingCallOptions {
292 tracing_options,
293 state_overrides,
294 block_overrides,
295 tx_index,
296 } = opts;
297 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
298
299 if let Some(tx_idx) = tx_index {
301 return self
302 .debug_trace_call_at_tx_index(call, at, tx_idx as usize, tracing_options, overrides)
303 .await;
304 }
305
306 let this = self.clone();
307 self.eth_api()
308 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
309 let mut inspector =
310 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
311 let res = this.eth_api().inspect(
312 &mut *db,
313 evm_env.clone(),
314 tx_env.clone(),
315 &mut inspector,
316 )?;
317 let trace = inspector
318 .get_result(None, &tx_env, &evm_env.block_env, &res, db)
319 .map_err(Eth::Error::from_eth_err)?;
320 Ok(trace)
321 })
322 .await
323 }
324
325 async fn debug_trace_call_at_tx_index(
329 &self,
330 call: RpcTxReq<Eth::NetworkTypes>,
331 block_id: BlockId,
332 tx_index: usize,
333 tracing_options: GethDebugTracingOptions,
334 overrides: EvmOverrides,
335 ) -> Result<GethTrace, Eth::Error> {
336 let block = self
338 .eth_api()
339 .recovered_block(block_id)
340 .await?
341 .ok_or(EthApiError::HeaderNotFound(block_id))?;
342
343 if tx_index >= block.transaction_count() {
344 return Err(EthApiError::InvalidParams(format!(
346 "tx_index {} out of bounds for block with {} transactions",
347 tx_index,
348 block.transaction_count()
349 ))
350 .into())
351 }
352
353 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
354
355 let state_at = block.parent_hash();
357
358 self.eth_api()
359 .spawn_with_state_at_block(state_at, move |eth_api, mut db| {
360 eth_api.apply_pre_execution_changes(&block, &mut db)?;
362
363 eth_api.replay_transactions_until(
365 &mut db,
366 evm_env.clone(),
367 block.transactions_recovered(),
368 *block.body().transactions()[tx_index].tx_hash(),
369 )?;
370
371 let (evm_env, tx_env) =
373 eth_api.prepare_call_env(evm_env, call, &mut db, overrides)?;
374
375 let mut inspector =
376 DebugInspector::new(tracing_options).map_err(Eth::Error::from_eth_err)?;
377 let res =
378 eth_api.inspect(&mut db, evm_env.clone(), tx_env.clone(), &mut inspector)?;
379 let trace = inspector
380 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
381 .map_err(Eth::Error::from_eth_err)?;
382
383 Ok(trace)
384 })
385 .await
386 }
387
388 pub async fn debug_trace_call_many(
392 &self,
393 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
394 state_context: Option<StateContext>,
395 opts: Option<GethDebugTracingCallOptions>,
396 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
397 if bundles.is_empty() {
398 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
399 }
400
401 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
402 let transaction_index = transaction_index.unwrap_or_default();
403
404 let target_block = block_number.unwrap_or_default();
405 let block = self
406 .eth_api()
407 .recovered_block(target_block)
408 .await?
409 .ok_or(EthApiError::HeaderNotFound(target_block))?;
410 let mut evm_env =
411 self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
412
413 let opts = opts.unwrap_or_default();
414 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
415
416 let mut at = block.parent_hash();
419 let mut replay_block_txs = true;
420
421 let num_txs =
423 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
424 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
428 at = block.hash();
429 replay_block_txs = false;
430 }
431
432 self.eth_api()
433 .spawn_with_state_at_block(at, move |eth_api, mut db| {
434 let mut all_bundles = Vec::with_capacity(bundles.len());
436
437 if replay_block_txs {
438 eth_api.apply_pre_execution_changes(&block, &mut db)?;
441
442 let transactions = block.transactions_recovered().take(num_txs);
443
444 for tx in transactions {
446 let tx_env = eth_api.evm_config().tx_env(tx);
447 let res = eth_api.transact(&mut db, evm_env.clone(), tx_env)?;
448 db.commit(res.state);
449 }
450 }
451
452 let mut bundles = bundles.into_iter().peekable();
454 let mut inspector = DebugInspector::new(tracing_options.clone())
455 .map_err(Eth::Error::from_eth_err)?;
456 while let Some(bundle) = bundles.next() {
457 let mut results = Vec::with_capacity(bundle.transactions.len());
458 let Bundle { transactions, block_override } = bundle;
459
460 let block_overrides = block_override.map(Box::new);
461
462 let mut transactions = transactions.into_iter().peekable();
463 while let Some(tx) = transactions.next() {
464 let state_overrides = state_overrides.take();
466 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
467
468 let (evm_env, tx_env) =
469 eth_api.prepare_call_env(evm_env.clone(), tx, &mut db, overrides)?;
470
471 let res = eth_api.inspect(
472 &mut db,
473 evm_env.clone(),
474 tx_env.clone(),
475 &mut inspector,
476 )?;
477 let trace = inspector
478 .get_result(None, &tx_env, &evm_env.block_env, &res, &mut db)
479 .map_err(Eth::Error::from_eth_err)?;
480
481 if transactions.peek().is_some() || bundles.peek().is_some() {
484 inspector.fuse().map_err(Eth::Error::from_eth_err)?;
485 db.commit(res.state);
486 }
487 results.push(trace);
488 }
489 evm_env.block_env.inner_mut().number += uint!(1_U256);
491 evm_env.block_env.inner_mut().timestamp += uint!(12_U256);
492
493 all_bundles.push(results);
494 }
495 Ok(all_bundles)
496 })
497 .await
498 }
499
500 pub async fn debug_execution_witness_by_block_hash(
503 &self,
504 hash: B256,
505 mode: Option<ExecutionWitnessMode>,
506 ) -> Result<ExecutionWitness, Eth::Error> {
507 let this = self.clone();
508 let block = this
509 .eth_api()
510 .recovered_block(hash.into())
511 .await?
512 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
513
514 self.debug_execution_witness_for_block(block, mode.unwrap_or_default()).await
515 }
516
517 pub async fn debug_execution_witness(
522 &self,
523 block_id: BlockNumberOrTag,
524 mode: Option<ExecutionWitnessMode>,
525 ) -> Result<ExecutionWitness, Eth::Error> {
526 let this = self.clone();
527 let block = this
528 .eth_api()
529 .recovered_block(block_id.into())
530 .await?
531 .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;
532
533 self.debug_execution_witness_for_block(block, mode.unwrap_or_default()).await
534 }
535
536 pub async fn debug_execution_witness_for_block(
538 &self,
539 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
540 mode: ExecutionWitnessMode,
541 ) -> Result<ExecutionWitness, Eth::Error> {
542 let block_number = block.header().number();
543 self.eth_api()
544 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
545 let block_executor = eth_api.evm_config().executor(&mut db);
546
547 let mut witness_record = ExecutionWitnessRecord::default();
548
549 let _ = block_executor
550 .execute_with_state_closure(&block, |statedb: &State<_>| {
551 witness_record.record_executed_state(statedb, mode);
552 })
553 .map_err(|err| EthApiError::Internal(err.into()))?;
554
555 Ok(witness_record
556 .into_execution_witness(&db.database.0, eth_api.provider(), block_number, mode)
557 .map_err(EthApiError::from)?)
558 })
559 .await
560 }
561
562 pub async fn debug_account_at(
565 &self,
566 block_id: BlockId,
567 tx_index: Index,
568 address: Address,
569 ) -> Result<Option<Account>, Eth::Error> {
570 self.replay_block_until(block_id, tx_index, move |db| Self::account(db, address))
571 .await
572 .map(Option::flatten)
573 }
574
575 pub async fn debug_account_info_at(
578 &self,
579 block_id: BlockId,
580 tx_index: Index,
581 address: Address,
582 ) -> Result<Option<AccountInfo>, Eth::Error> {
583 self.replay_block_until(block_id, tx_index, move |db| Self::account_info(db, address)).await
584 }
585
586 async fn replay_block_until<F, R>(
589 &self,
590 block_id: BlockId,
591 tx_index: Index,
592 f: F,
593 ) -> Result<Option<R>, Eth::Error>
594 where
595 F: FnOnce(&mut StateCacheDb) -> Result<R, Eth::Error> + Send + 'static,
596 R: Send + 'static,
597 {
598 let block = self
599 .eth_api()
600 .recovered_block(block_id)
601 .await?
602 .ok_or(EthApiError::HeaderNotFound(block_id))?;
603 let tx_index = usize::from(tx_index);
604 let transaction_count = block.transaction_count();
605 if tx_index >= transaction_count {
606 return Err(EthApiError::InvalidParams(format!(
607 "tx_index {tx_index} out of bounds for block with {transaction_count} transactions"
608 ))
609 .into())
610 }
611
612 self.eth_api()
613 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
614 let mut executor = eth_api
615 .evm_config()
616 .executor_for_block(&mut db, block.sealed_block())
617 .map_err(RethError::other)
618 .map_err(Eth::Error::from_eth_err)?;
619 executor.apply_pre_execution_changes().map_err(Eth::Error::from_eth_err)?;
620
621 for tx in block.transactions_recovered().take(tx_index + 1) {
622 executor.execute_transaction(tx).map_err(Eth::Error::from_eth_err)?;
623 }
624 drop(executor);
625
626 f(&mut db)
627 })
628 .await
629 .map(Some)
630 }
631
632 fn account(db: &mut StateCacheDb, address: Address) -> Result<Option<Account>, Eth::Error> {
634 let account = db.basic(address).map_err(Eth::Error::from_eth_err)?;
635 let Some(account) = account else { return Ok(None) };
636
637 let balance = account.balance;
638 let nonce = account.nonce;
639 let code_hash = account.code_hash;
640 let hashed_storage = db
641 .cache
642 .accounts
643 .get(&address)
644 .and_then(|account| {
645 account.account.as_ref().map(|plain_account| {
646 HashedStorage::from_plain_storage(account.status, plain_account.storage.iter())
647 })
648 })
649 .unwrap_or_default();
650 let storage_root =
651 db.database.storage_root(address, hashed_storage).map_err(Eth::Error::from_eth_err)?;
652
653 Ok(Some(Account { balance, nonce, code_hash, storage_root }))
654 }
655
656 fn account_info<DB>(db: &mut DB, address: Address) -> Result<AccountInfo, Eth::Error>
658 where
659 DB: Database,
660 EthApiError: From<DB::Error>,
661 {
662 let account = db.basic(address).map_err(Eth::Error::from_eth_err)?.unwrap_or_default();
663 let code = if account.code_hash == KECCAK_EMPTY {
664 Default::default()
665 } else if let Some(code) = account.code {
666 code.original_bytes()
667 } else {
668 db.code_by_hash(account.code_hash).map_err(Eth::Error::from_eth_err)?.original_bytes()
669 };
670
671 Ok(AccountInfo { balance: account.balance, nonce: account.nonce, code })
672 }
673
674 pub async fn debug_code_by_hash(
677 &self,
678 hash: B256,
679 block_id: Option<BlockId>,
680 ) -> Result<Option<Bytes>, Eth::Error> {
681 Ok(self
682 .provider()
683 .state_by_block_id(block_id.unwrap_or_default())
684 .map_err(Eth::Error::from_eth_err)?
685 .bytecode_by_hash(&hash)
686 .map_err(Eth::Error::from_eth_err)?
687 .map(|b| b.original_bytes()))
688 }
689
690 async fn debug_state_root_with_updates(
693 &self,
694 hashed_state: HashedPostState,
695 block_id: Option<BlockId>,
696 ) -> Result<(B256, TrieUpdates), Eth::Error> {
697 self.inner
698 .eth_api
699 .spawn_blocking_io(move |this| {
700 let state = this
701 .provider()
702 .state_by_block_id(block_id.unwrap_or_default())
703 .map_err(Eth::Error::from_eth_err)?;
704 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
705 })
706 .await
707 }
708
709 pub async fn intermediate_roots(&self, block_hash: B256) -> Result<Vec<B256>, Eth::Error> {
711 let block = self
712 .eth_api()
713 .recovered_block(block_hash.into())
714 .await?
715 .ok_or(EthApiError::HeaderNotFound(block_hash.into()))?;
716 let evm_env = self.eth_api().evm_env_for_header(block.sealed_block().sealed_header())?;
717
718 self.eth_api()
719 .spawn_with_state_at_block(block.parent_hash(), move |eth_api, mut db| {
720 db.transition_state = Some(Default::default());
722
723 eth_api.apply_pre_execution_changes(&block, &mut db)?;
724
725 let mut roots = Vec::with_capacity(block.body().transactions().len());
726 for tx in block.transactions_recovered() {
727 let tx_env = eth_api.evm_config().tx_env(tx);
728 {
729 let mut evm = eth_api.evm_config().evm_with_env(&mut db, evm_env.clone());
730 evm.transact_commit(tx_env).map_err(Eth::Error::from_evm_err)?;
731 }
732 db.merge_transitions(BundleRetention::PlainState);
734 let hashed_state = db.database.hashed_post_state(&db.bundle_state);
736 let root =
737 db.database.state_root(hashed_state).map_err(Eth::Error::from_eth_err)?;
738 roots.push(root);
739 }
740
741 Ok(roots)
742 })
743 .await
744 }
745}
746
747#[async_trait]
748impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
749where
750 Eth: EthTransactions + TraceExt,
751{
752 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
754 let header = match block_id {
755 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
756 BlockId::Number(number_or_tag) => {
757 let number = self
758 .provider()
759 .convert_block_number(number_or_tag)
760 .to_rpc_result()?
761 .ok_or(EthApiError::HeaderNotFound(block_id))?;
762 self.provider().header_by_number(number).to_rpc_result()?
763 }
764 }
765 .ok_or(EthApiError::HeaderNotFound(block_id))?;
766
767 let mut res = Vec::new();
768 header.encode(&mut res);
769 Ok(res.into())
770 }
771
772 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
774 let block = self
775 .provider()
776 .block_by_id(block_id)
777 .to_rpc_result()?
778 .ok_or(EthApiError::HeaderNotFound(block_id))?;
779 let mut res = Vec::new();
780 block.encode(&mut res);
781 Ok(res.into())
782 }
783
784 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
790 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
791 }
792
793 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
796 let block: RecoveredBlock<BlockTy<Eth::Primitives>> = self
797 .provider()
798 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
799 .to_rpc_result()?
800 .unwrap_or_default();
801 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
802 }
803
804 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
806 Ok(self
807 .provider()
808 .receipts_by_block_id(block_id)
809 .to_rpc_result()?
810 .ok_or(EthApiError::HeaderNotFound(block_id))?
811 .into_iter()
812 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
813 .collect())
814 }
815
816 async fn bad_blocks(&self) -> RpcResult<Vec<serde_json::Value>> {
818 let entries = self.inner.bad_block_store.all();
819 let mut bad_blocks = Vec::with_capacity(entries.len());
820
821 #[derive(Serialize, Deserialize)]
822 struct BadBlockSerde<T> {
823 block: T,
824 hash: B256,
825 rlp: Bytes,
826 reason: String,
827 }
828
829 for entry in entries {
830 let rlp = alloy_rlp::encode(entry.block.sealed_block()).into();
831 let hash = entry.block.hash();
832
833 let block = entry
834 .block
835 .clone_into_rpc_block(
836 BlockTransactionsKind::Full,
837 |tx, tx_info| self.eth_api().converter().fill(tx, tx_info),
838 |header, size| self.eth_api().converter().convert_header(header, size),
839 )
840 .map_err(|err| Eth::Error::from(err).into())?;
841
842 let bad_block =
843 serde_json::to_value(BadBlockSerde { block, hash, rlp, reason: entry.reason })
844 .map_err(|err| EthApiError::other(internal_rpc_err(err.to_string())))?;
845
846 bad_blocks.push(bad_block);
847 }
848
849 Ok(bad_blocks)
850 }
851
852 async fn debug_clear_txpool(&self) -> RpcResult<()> {
854 let pool = self.eth_api().pool();
855 let all_hashes = pool.all_transaction_hashes();
856 let _ = pool.remove_transactions(all_hashes);
857 Ok(())
858 }
859
860 async fn debug_trace_chain(
862 &self,
863 _start_exclusive: BlockNumberOrTag,
864 _end_inclusive: BlockNumberOrTag,
865 ) -> RpcResult<Vec<BlockTraceResult>> {
866 Err(internal_rpc_err("unimplemented"))
867 }
868
869 async fn debug_trace_block(
871 &self,
872 rlp_block: Bytes,
873 opts: Option<GethDebugTracingOptions>,
874 ) -> RpcResult<Vec<TraceResult>> {
875 let _permit = self.acquire_trace_permit().await;
876 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
877 .await
878 .map_err(Into::into)
879 }
880
881 async fn debug_trace_block_by_hash(
883 &self,
884 block: B256,
885 opts: Option<GethDebugTracingOptions>,
886 ) -> RpcResult<Vec<TraceResult>> {
887 let _permit = self.acquire_trace_permit().await;
888 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
889 .await
890 .map_err(Into::into)
891 }
892
893 async fn debug_trace_block_by_number(
895 &self,
896 block: BlockNumberOrTag,
897 opts: Option<GethDebugTracingOptions>,
898 ) -> RpcResult<Vec<TraceResult>> {
899 let _permit = self.acquire_trace_permit().await;
900 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
901 .await
902 .map_err(Into::into)
903 }
904
905 async fn debug_trace_transaction(
907 &self,
908 tx_hash: B256,
909 opts: Option<GethDebugTracingOptions>,
910 ) -> RpcResult<GethTrace> {
911 let _permit = self.acquire_trace_permit().await;
912 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
913 .await
914 .map_err(Into::into)
915 }
916
917 async fn debug_trace_call(
919 &self,
920 request: RpcTxReq<Eth::NetworkTypes>,
921 block_id: Option<BlockId>,
922 opts: Option<GethDebugTracingCallOptions>,
923 ) -> RpcResult<GethTrace> {
924 let _permit = self.acquire_trace_permit().await;
925 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
926 .await
927 .map_err(Into::into)
928 }
929
930 async fn debug_trace_call_many(
931 &self,
932 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
933 state_context: Option<StateContext>,
934 opts: Option<GethDebugTracingCallOptions>,
935 ) -> RpcResult<Vec<Vec<GethTrace>>> {
936 let _permit = self.acquire_trace_permit().await;
937 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
938 }
939
940 async fn debug_execution_witness(
942 &self,
943 block: BlockNumberOrTag,
944 mode: Option<ExecutionWitnessMode>,
945 ) -> RpcResult<ExecutionWitness> {
946 let _permit = self.acquire_trace_permit().await;
947 Self::debug_execution_witness(self, block, mode).await.map_err(Into::into)
948 }
949
950 async fn debug_execution_witness_by_block_hash(
952 &self,
953 hash: B256,
954 mode: Option<ExecutionWitnessMode>,
955 ) -> RpcResult<ExecutionWitness> {
956 let _permit = self.acquire_trace_permit().await;
957 Self::debug_execution_witness_by_block_hash(self, hash, mode).await.map_err(Into::into)
958 }
959
960 async fn debug_account_at(
962 &self,
963 block_id: BlockId,
964 tx_index: Index,
965 address: Address,
966 ) -> RpcResult<Option<Account>> {
967 let _permit = self.acquire_trace_permit().await;
968 Self::debug_account_at(self, block_id, tx_index, address).await.map_err(Into::into)
969 }
970
971 async fn debug_account_info_at(
973 &self,
974 block_id: BlockId,
975 tx_index: Index,
976 address: Address,
977 ) -> RpcResult<Option<AccountInfo>> {
978 let _permit = self.acquire_trace_permit().await;
979 Self::debug_account_info_at(self, block_id, tx_index, address).await.map_err(Into::into)
980 }
981
982 async fn debug_account_range(
983 &self,
984 _block_number: BlockNumberOrTag,
985 _start: Bytes,
986 _max_results: u64,
987 _nocode: bool,
988 _nostorage: bool,
989 _incompletes: bool,
990 ) -> RpcResult<()> {
991 Ok(())
992 }
993
994 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
995 Ok(())
996 }
997
998 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
999 Ok(self.provider().chain_spec().genesis().config.clone())
1000 }
1001
1002 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
1003 Ok(())
1004 }
1005
1006 async fn debug_code_by_hash(
1007 &self,
1008 hash: B256,
1009 block_id: Option<BlockId>,
1010 ) -> RpcResult<Option<Bytes>> {
1011 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
1012 }
1013
1014 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
1015 Ok(())
1016 }
1017
1018 async fn debug_db_ancients(&self) -> RpcResult<()> {
1019 Ok(())
1020 }
1021
1022 async fn debug_db_get(&self, key: String) -> RpcResult<Option<Bytes>> {
1033 let key_bytes = if key.starts_with("0x") {
1034 decode(&key).map_err(|_| EthApiError::InvalidParams("Invalid hex key".to_string()))?
1035 } else {
1036 key.into_bytes()
1037 };
1038
1039 if key_bytes.len() != 33 {
1040 return Err(EthApiError::InvalidParams(format!(
1041 "Key must be 33 bytes, got {}",
1042 key_bytes.len()
1043 ))
1044 .into());
1045 }
1046 if key_bytes[0] != 0x63 {
1047 return Err(EthApiError::InvalidParams("Key prefix must be 0x63".to_string()).into());
1048 }
1049
1050 let code_hash = B256::from_slice(&key_bytes[1..33]);
1051
1052 self.debug_code_by_hash(code_hash, None).await.map_err(Into::into)
1054 }
1055
1056 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
1057 Ok(())
1058 }
1059
1060 async fn debug_free_os_memory(&self) -> RpcResult<()> {
1061 Ok(())
1062 }
1063
1064 async fn debug_gc_stats(&self) -> RpcResult<()> {
1065 Ok(())
1066 }
1067
1068 async fn debug_get_accessible_state(
1069 &self,
1070 _from: BlockNumberOrTag,
1071 _to: BlockNumberOrTag,
1072 ) -> RpcResult<()> {
1073 Ok(())
1074 }
1075
1076 async fn debug_get_modified_accounts_by_hash(
1077 &self,
1078 _start_hash: B256,
1079 _end_hash: B256,
1080 ) -> RpcResult<()> {
1081 Ok(())
1082 }
1083
1084 async fn debug_get_modified_accounts_by_number(
1085 &self,
1086 _start_number: u64,
1087 _end_number: u64,
1088 ) -> RpcResult<()> {
1089 Ok(())
1090 }
1091
1092 async fn debug_intermediate_roots(
1093 &self,
1094 block_hash: B256,
1095 _opts: Option<GethDebugTracingCallOptions>,
1096 ) -> RpcResult<Vec<B256>> {
1097 let _permit = self.acquire_trace_permit().await;
1098 self.intermediate_roots(block_hash).await.map_err(Into::into)
1099 }
1100
1101 async fn debug_mem_stats(&self) -> RpcResult<()> {
1102 Ok(())
1103 }
1104
1105 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
1106 Ok(())
1107 }
1108
1109 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
1110 Ok(())
1111 }
1112
1113 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
1114 Ok(Default::default())
1115 }
1116
1117 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
1118 Ok(())
1119 }
1120
1121 async fn debug_set_head(&self, _number: U64) -> RpcResult<()> {
1122 Ok(())
1123 }
1124
1125 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1126 Ok(())
1127 }
1128
1129 async fn debug_standard_trace_bad_block_to_file(
1130 &self,
1131 _block: BlockNumberOrTag,
1132 _opts: Option<GethDebugTracingCallOptions>,
1133 ) -> RpcResult<()> {
1134 Ok(())
1135 }
1136
1137 async fn debug_standard_trace_block_to_file(
1138 &self,
1139 _block: BlockNumberOrTag,
1140 _opts: Option<GethDebugTracingCallOptions>,
1141 ) -> RpcResult<()> {
1142 Ok(())
1143 }
1144
1145 async fn debug_state_root_with_updates(
1146 &self,
1147 hashed_state: HashedPostState,
1148 block_id: Option<BlockId>,
1149 ) -> RpcResult<(B256, TrieUpdates)> {
1150 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1151 }
1152
1153 async fn debug_storage_range_at(
1154 &self,
1155 _block_hash: B256,
1156 _tx_idx: usize,
1157 _contract_address: Address,
1158 _key_start: B256,
1159 _max_result: u64,
1160 ) -> RpcResult<()> {
1161 Ok(())
1162 }
1163
1164 async fn debug_trace_bad_block(
1165 &self,
1166 block_hash: B256,
1167 opts: Option<GethDebugTracingCallOptions>,
1168 ) -> RpcResult<Vec<TraceResult>> {
1169 let _permit = self.acquire_trace_permit().await;
1170 let entry = self
1171 .inner
1172 .bad_block_store
1173 .get(block_hash)
1174 .ok_or_else(|| internal_rpc_err("bad block not found in cache"))?;
1175
1176 let evm_env = self
1177 .eth_api()
1178 .evm_config()
1179 .evm_env(entry.block.header())
1180 .map_err(RethError::other)
1181 .to_rpc_result()?;
1182
1183 let opts = opts.map(|o| o.tracing_options).unwrap_or_default();
1184 self.trace_block(entry.block.clone(), evm_env, opts).await.map_err(Into::into)
1185 }
1186}
1187
1188impl<Eth: RpcNodeCore> std::fmt::Debug for DebugApi<Eth> {
1189 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1190 f.debug_struct("DebugApi").finish_non_exhaustive()
1191 }
1192}
1193
1194impl<Eth: RpcNodeCore> Clone for DebugApi<Eth> {
1195 fn clone(&self) -> Self {
1196 Self { inner: Arc::clone(&self.inner) }
1197 }
1198}
1199
1200struct DebugApiInner<Eth: RpcNodeCore> {
1201 eth_api: Eth,
1203 blocking_task_guard: BlockingTaskGuard,
1205 bad_block_store: BadBlockStore<BlockTy<Eth::Primitives>>,
1207}
1208
1209#[derive(Clone, Debug)]
1211struct BadBlockStore<B: BlockTrait> {
1212 inner: Arc<RwLock<VecDeque<BadBlockEntry<B>>>>,
1213 limit: usize,
1214}
1215
1216#[derive(Clone, Debug)]
1218struct BadBlockEntry<B: BlockTrait> {
1219 block: Arc<RecoveredBlock<B>>,
1220 reason: String,
1221}
1222
1223impl<B: BlockTrait> BadBlockStore<B> {
1224 fn new(limit: usize) -> Self {
1226 Self { inner: Arc::new(RwLock::new(VecDeque::with_capacity(limit))), limit }
1227 }
1228
1229 fn insert(&self, block: RecoveredBlock<B>, reason: String) {
1232 let hash = block.hash();
1233 let mut guard = self.inner.write();
1234
1235 if guard.iter().any(|entry| entry.block.hash() == hash) {
1237 return;
1238 }
1239 guard.push_back(BadBlockEntry { block: Arc::new(block), reason });
1240
1241 while guard.len() > self.limit {
1242 guard.pop_front();
1243 }
1244 }
1245
1246 fn all(&self) -> Vec<BadBlockEntry<B>> {
1248 let guard = self.inner.read();
1249 guard.iter().rev().cloned().collect()
1250 }
1251
1252 fn get(&self, hash: B256) -> Option<BadBlockEntry<B>> {
1254 let guard = self.inner.read();
1255 guard.iter().find(|entry| entry.block.hash() == hash).cloned()
1256 }
1257}
1258
1259impl<B: BlockTrait> Default for BadBlockStore<B> {
1260 fn default() -> Self {
1261 Self::new(64)
1262 }
1263}