1use alloy_consensus::{
2 transaction::{SignerRecoverable, TxHashRef},
3 BlockHeader,
4};
5use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
6use alloy_genesis::ChainConfig;
7use alloy_primitives::{uint, Address, Bytes, B256};
8use alloy_rlp::{Decodable, Encodable};
9use alloy_rpc_types_debug::ExecutionWitness;
10use alloy_rpc_types_eth::{
11 state::EvmOverrides, Block as RpcBlock, BlockError, Bundle, StateContext, TransactionInfo,
12};
13use alloy_rpc_types_trace::geth::{
14 call::FlatCallFrame, BlockTraceResult, FourByteFrame, GethDebugBuiltInTracerType,
15 GethDebugTracerType, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace,
16 NoopFrame, TraceResult,
17};
18use async_trait::async_trait;
19use jsonrpsee::core::RpcResult;
20use reth_chainspec::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
21use reth_errors::RethError;
22use reth_evm::{execute::Executor, ConfigureEvm, EvmEnvFor, TxEnvFor};
23use reth_primitives_traits::{Block as _, BlockBody, ReceiptWithBloom, RecoveredBlock};
24use reth_revm::{
25 database::StateProviderDatabase,
26 db::{CacheDB, State},
27 witness::ExecutionWitnessRecord,
28};
29use reth_rpc_api::DebugApiServer;
30use reth_rpc_convert::RpcTxReq;
31use reth_rpc_eth_api::{
32 helpers::{EthTransactions, TraceExt},
33 EthApiTypes, FromEthApiError, RpcNodeCore,
34};
35use reth_rpc_eth_types::{EthApiError, StateCacheDb};
36use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
37use reth_storage_api::{
38 BlockIdReader, BlockReaderIdExt, HeaderProvider, ProviderBlock, ReceiptProviderIdExt,
39 StateProofProvider, StateProviderFactory, StateRootProvider, TransactionVariant,
40};
41use reth_tasks::pool::BlockingTaskGuard;
42use reth_trie_common::{updates::TrieUpdates, HashedPostState};
43use revm::{context_interface::Transaction, state::EvmState, DatabaseCommit};
44use revm_inspectors::tracing::{
45 FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig, TransactionContext,
46};
47use std::sync::Arc;
48use tokio::sync::{AcquireError, OwnedSemaphorePermit};
49
50pub struct DebugApi<Eth> {
54 inner: Arc<DebugApiInner<Eth>>,
55}
56
57impl<Eth> DebugApi<Eth> {
60 pub fn new(eth_api: Eth, blocking_task_guard: BlockingTaskGuard) -> Self {
62 let inner = Arc::new(DebugApiInner { eth_api, blocking_task_guard });
63 Self { inner }
64 }
65
66 pub fn eth_api(&self) -> &Eth {
68 &self.inner.eth_api
69 }
70}
71
72impl<Eth: RpcNodeCore> DebugApi<Eth> {
73 pub fn provider(&self) -> &Eth::Provider {
75 self.inner.eth_api.provider()
76 }
77}
78
79impl<Eth> DebugApi<Eth>
82where
83 Eth: EthApiTypes + TraceExt + 'static,
84{
85 async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
87 self.inner.blocking_task_guard.clone().acquire_owned().await
88 }
89
90 async fn trace_block(
92 &self,
93 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
94 evm_env: EvmEnvFor<Eth::Evm>,
95 opts: GethDebugTracingOptions,
96 ) -> Result<Vec<TraceResult>, Eth::Error> {
97 let this = self.clone();
99 self.eth_api()
100 .spawn_with_state_at_block(block.parent_hash().into(), move |state| {
101 let mut results = Vec::with_capacity(block.body().transactions().len());
102 let mut db = CacheDB::new(StateProviderDatabase::new(state));
103
104 this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
105
106 let mut transactions = block.transactions_recovered().enumerate().peekable();
107 let mut inspector = None;
108 while let Some((index, tx)) = transactions.next() {
109 let tx_hash = *tx.tx_hash();
110
111 let tx_env = this.eth_api().evm_config().tx_env(tx);
112
113 let (result, state_changes) = this.trace_transaction(
114 &opts,
115 evm_env.clone(),
116 tx_env,
117 &mut db,
118 Some(TransactionContext {
119 block_hash: Some(block.hash()),
120 tx_hash: Some(tx_hash),
121 tx_index: Some(index),
122 }),
123 &mut inspector,
124 )?;
125
126 inspector = inspector.map(|insp| insp.fused());
127
128 results.push(TraceResult::Success { result, tx_hash: Some(tx_hash) });
129 if transactions.peek().is_some() {
130 db.commit(state_changes)
133 }
134 }
135
136 Ok(results)
137 })
138 .await
139 }
140
141 pub async fn debug_trace_raw_block(
147 &self,
148 rlp_block: Bytes,
149 opts: GethDebugTracingOptions,
150 ) -> Result<Vec<TraceResult>, Eth::Error> {
151 let block: ProviderBlock<Eth::Provider> = Decodable::decode(&mut rlp_block.as_ref())
152 .map_err(BlockError::RlpDecodeRawBlock)
153 .map_err(Eth::Error::from_eth_err)?;
154
155 let evm_env = self
156 .eth_api()
157 .evm_config()
158 .evm_env(block.header())
159 .map_err(RethError::other)
160 .map_err(Eth::Error::from_eth_err)?;
161
162 let senders =
164 if self.provider().chain_spec().is_homestead_active_at_block(block.header().number()) {
165 block
166 .body()
167 .transactions()
168 .iter()
169 .map(|tx| tx.recover_signer().map_err(Eth::Error::from_eth_err))
170 .collect::<Result<Vec<_>, _>>()?
171 .into_iter()
172 .collect()
173 } else {
174 block
175 .body()
176 .transactions()
177 .iter()
178 .map(|tx| tx.recover_signer_unchecked().map_err(Eth::Error::from_eth_err))
179 .collect::<Result<Vec<_>, _>>()?
180 .into_iter()
181 .collect()
182 };
183
184 self.trace_block(Arc::new(block.into_recovered_with_signers(senders)), evm_env, opts).await
185 }
186
187 pub async fn debug_trace_block(
189 &self,
190 block_id: BlockId,
191 opts: GethDebugTracingOptions,
192 ) -> Result<Vec<TraceResult>, Eth::Error> {
193 let block_hash = self
194 .provider()
195 .block_hash_for_id(block_id)
196 .map_err(Eth::Error::from_eth_err)?
197 .ok_or(EthApiError::HeaderNotFound(block_id))?;
198
199 let ((evm_env, _), block) = futures::try_join!(
200 self.eth_api().evm_env_at(block_hash.into()),
201 self.eth_api().recovered_block(block_hash.into()),
202 )?;
203
204 let block = block.ok_or(EthApiError::HeaderNotFound(block_id))?;
205
206 self.trace_block(block, evm_env, opts).await
207 }
208
209 pub async fn debug_trace_transaction(
213 &self,
214 tx_hash: B256,
215 opts: GethDebugTracingOptions,
216 ) -> Result<GethTrace, Eth::Error> {
217 let (transaction, block) = match self.eth_api().transaction_and_block(tx_hash).await? {
218 None => return Err(EthApiError::TransactionNotFound.into()),
219 Some(res) => res,
220 };
221 let (evm_env, _) = self.eth_api().evm_env_at(block.hash().into()).await?;
222
223 let state_at: BlockId = block.parent_hash().into();
226 let block_hash = block.hash();
227
228 let this = self.clone();
229 self.eth_api()
230 .spawn_with_state_at_block(state_at, move |state| {
231 let block_txs = block.transactions_recovered();
232
233 let tx = transaction.into_recovered();
235
236 let mut db = CacheDB::new(StateProviderDatabase::new(state));
237
238 this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
239
240 let index = this.eth_api().replay_transactions_until(
242 &mut db,
243 evm_env.clone(),
244 block_txs,
245 *tx.tx_hash(),
246 )?;
247
248 let tx_env = this.eth_api().evm_config().tx_env(&tx);
249
250 this.trace_transaction(
251 &opts,
252 evm_env,
253 tx_env,
254 &mut db,
255 Some(TransactionContext {
256 block_hash: Some(block_hash),
257 tx_index: Some(index),
258 tx_hash: Some(*tx.tx_hash()),
259 }),
260 &mut None,
261 )
262 .map(|(trace, _)| trace)
263 })
264 .await
265 }
266
267 pub async fn debug_trace_call(
273 &self,
274 call: RpcTxReq<Eth::NetworkTypes>,
275 block_id: Option<BlockId>,
276 opts: GethDebugTracingCallOptions,
277 ) -> Result<GethTrace, Eth::Error> {
278 let at = block_id.unwrap_or_default();
279 let GethDebugTracingCallOptions {
280 tracing_options, state_overrides, block_overrides, ..
281 } = opts;
282 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
283 let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options;
284
285 let this = self.clone();
286 if let Some(tracer) = tracer {
287 #[allow(unreachable_patterns)]
288 return match tracer {
289 GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
290 GethDebugBuiltInTracerType::FourByteTracer => {
291 let mut inspector = FourByteInspector::default();
292 let inspector = self
293 .eth_api()
294 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
295 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
296 Ok(inspector)
297 })
298 .await?;
299 Ok(FourByteFrame::from(&inspector).into())
300 }
301 GethDebugBuiltInTracerType::CallTracer => {
302 let call_config = tracer_config
303 .into_call_config()
304 .map_err(|_| EthApiError::InvalidTracerConfig)?;
305
306 let mut inspector = TracingInspector::new(
307 TracingInspectorConfig::from_geth_call_config(&call_config),
308 );
309
310 let frame = self
311 .eth_api()
312 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
313 let gas_limit = tx_env.gas_limit();
314 let res =
315 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
316 let frame = inspector
317 .with_transaction_gas_limit(gas_limit)
318 .into_geth_builder()
319 .geth_call_traces(call_config, res.result.gas_used());
320 Ok(frame.into())
321 })
322 .await?;
323 Ok(frame)
324 }
325 GethDebugBuiltInTracerType::PreStateTracer => {
326 let prestate_config = tracer_config
327 .into_pre_state_config()
328 .map_err(|_| EthApiError::InvalidTracerConfig)?;
329 let mut inspector = TracingInspector::new(
330 TracingInspectorConfig::from_geth_prestate_config(&prestate_config),
331 );
332
333 let frame = self
334 .eth_api()
335 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
336 let db = db.0;
339
340 let gas_limit = tx_env.gas_limit();
341 let res = this.eth_api().inspect(
342 &mut *db,
343 evm_env,
344 tx_env,
345 &mut inspector,
346 )?;
347 let frame = inspector
348 .with_transaction_gas_limit(gas_limit)
349 .into_geth_builder()
350 .geth_prestate_traces(&res, &prestate_config, db)
351 .map_err(Eth::Error::from_eth_err)?;
352 Ok(frame)
353 })
354 .await?;
355 Ok(frame.into())
356 }
357 GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()),
358 GethDebugBuiltInTracerType::MuxTracer => {
359 let mux_config = tracer_config
360 .into_mux_config()
361 .map_err(|_| EthApiError::InvalidTracerConfig)?;
362
363 let mut inspector = MuxInspector::try_from_config(mux_config)
364 .map_err(Eth::Error::from_eth_err)?;
365
366 let frame = self
367 .inner
368 .eth_api
369 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
370 let db = db.0;
373
374 let tx_info = TransactionInfo {
375 block_number: Some(evm_env.block_env.number.saturating_to()),
376 base_fee: Some(evm_env.block_env.basefee),
377 hash: None,
378 block_hash: None,
379 index: None,
380 };
381
382 let res = this.eth_api().inspect(
383 &mut *db,
384 evm_env,
385 tx_env,
386 &mut inspector,
387 )?;
388 let frame = inspector
389 .try_into_mux_frame(&res, db, tx_info)
390 .map_err(Eth::Error::from_eth_err)?;
391 Ok(frame.into())
392 })
393 .await?;
394 Ok(frame)
395 }
396 GethDebugBuiltInTracerType::FlatCallTracer => {
397 let flat_call_config = tracer_config
398 .into_flat_call_config()
399 .map_err(|_| EthApiError::InvalidTracerConfig)?;
400
401 let mut inspector = TracingInspector::new(
402 TracingInspectorConfig::from_flat_call_config(&flat_call_config),
403 );
404
405 let frame: FlatCallFrame = self
406 .inner
407 .eth_api
408 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
409 let gas_limit = tx_env.gas_limit();
410 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
411 let tx_info = TransactionInfo::default();
412 let frame: FlatCallFrame = inspector
413 .with_transaction_gas_limit(gas_limit)
414 .into_parity_builder()
415 .into_localized_transaction_traces(tx_info);
416 Ok(frame)
417 })
418 .await?;
419
420 Ok(frame.into())
421 }
422 },
423 #[cfg(not(feature = "js-tracer"))]
424 GethDebugTracerType::JsTracer(_) => {
425 Err(EthApiError::Unsupported("JS Tracer is not enabled").into())
426 }
427 #[cfg(feature = "js-tracer")]
428 GethDebugTracerType::JsTracer(code) => {
429 let config = tracer_config.into_json();
430
431 let (_, at) = self.eth_api().evm_env_at(at).await?;
432
433 let res = self
434 .eth_api()
435 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
436 let db = db.0;
439
440 let mut inspector =
441 revm_inspectors::tracing::js::JsInspector::new(code, config)
442 .map_err(Eth::Error::from_eth_err)?;
443 let res = this.eth_api().inspect(
444 &mut *db,
445 evm_env.clone(),
446 tx_env.clone(),
447 &mut inspector,
448 )?;
449 inspector
450 .json_result(res, &tx_env, &evm_env.block_env, db)
451 .map_err(Eth::Error::from_eth_err)
452 })
453 .await?;
454
455 Ok(GethTrace::JS(res))
456 }
457 _ => {
458 Err(EthApiError::Unsupported("unsupported tracer").into())
461 }
462 }
463 }
464
465 let inspector_config = TracingInspectorConfig::from_geth_config(&config);
467
468 let mut inspector = TracingInspector::new(inspector_config);
469
470 let (res, tx_gas_limit, inspector) = self
471 .eth_api()
472 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
473 let gas_limit = tx_env.gas_limit();
474 let res = this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
475 Ok((res, gas_limit, inspector))
476 })
477 .await?;
478 let gas_used = res.result.gas_used();
479 let return_value = res.result.into_output().unwrap_or_default();
480 let frame = inspector
481 .with_transaction_gas_limit(tx_gas_limit)
482 .into_geth_builder()
483 .geth_traces(gas_used, return_value, config);
484
485 Ok(frame.into())
486 }
487
488 pub async fn debug_trace_call_many(
492 &self,
493 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
494 state_context: Option<StateContext>,
495 opts: Option<GethDebugTracingCallOptions>,
496 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
497 if bundles.is_empty() {
498 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
499 }
500
501 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
502 let transaction_index = transaction_index.unwrap_or_default();
503
504 let target_block = block_number.unwrap_or_default();
505 let ((mut evm_env, _), block) = futures::try_join!(
506 self.eth_api().evm_env_at(target_block),
507 self.eth_api().recovered_block(target_block),
508 )?;
509
510 let opts = opts.unwrap_or_default();
511 let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
512 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
513
514 let mut at = block.parent_hash();
517 let mut replay_block_txs = true;
518
519 let num_txs =
521 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
522 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
526 at = block.hash();
527 replay_block_txs = false;
528 }
529
530 let this = self.clone();
531
532 self.eth_api()
533 .spawn_with_state_at_block(at.into(), move |state| {
534 let mut all_bundles = Vec::with_capacity(bundles.len());
536 let mut db = CacheDB::new(StateProviderDatabase::new(state));
537
538 if replay_block_txs {
539 let transactions = block.transactions_recovered().take(num_txs);
542
543 for tx in transactions {
545 let tx_env = this.eth_api().evm_config().tx_env(tx);
546 let res = this.eth_api().transact(&mut db, evm_env.clone(), tx_env)?;
547 db.commit(res.state);
548 }
549 }
550
551 let mut bundles = bundles.into_iter().peekable();
553 while let Some(bundle) = bundles.next() {
554 let mut results = Vec::with_capacity(bundle.transactions.len());
555 let Bundle { transactions, block_override } = bundle;
556
557 let block_overrides = block_override.map(Box::new);
558 let mut inspector = None;
559
560 let mut transactions = transactions.into_iter().peekable();
561 while let Some(tx) = transactions.next() {
562 let state_overrides = state_overrides.take();
564 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
565
566 let (evm_env, tx_env) = this.eth_api().prepare_call_env(
567 evm_env.clone(),
568 tx,
569 &mut db,
570 overrides,
571 )?;
572
573 let (trace, state) = this.trace_transaction(
574 &tracing_options,
575 evm_env,
576 tx_env,
577 &mut db,
578 None,
579 &mut inspector,
580 )?;
581
582 inspector = inspector.map(|insp| insp.fused());
583
584 if transactions.peek().is_some() || bundles.peek().is_some() {
587 db.commit(state);
588 }
589 results.push(trace);
590 }
591 evm_env.block_env.number += uint!(1_U256);
593 evm_env.block_env.timestamp += uint!(12_U256);
594
595 all_bundles.push(results);
596 }
597 Ok(all_bundles)
598 })
599 .await
600 }
601
602 pub async fn debug_execution_witness_by_block_hash(
605 &self,
606 hash: B256,
607 ) -> Result<ExecutionWitness, Eth::Error> {
608 let this = self.clone();
609 let block = this
610 .eth_api()
611 .recovered_block(hash.into())
612 .await?
613 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
614
615 self.debug_execution_witness_for_block(block).await
616 }
617
618 pub async fn debug_execution_witness(
623 &self,
624 block_id: BlockNumberOrTag,
625 ) -> Result<ExecutionWitness, Eth::Error> {
626 let this = self.clone();
627 let block = this
628 .eth_api()
629 .recovered_block(block_id.into())
630 .await?
631 .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;
632
633 self.debug_execution_witness_for_block(block).await
634 }
635
636 pub async fn debug_execution_witness_for_block(
638 &self,
639 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
640 ) -> Result<ExecutionWitness, Eth::Error> {
641 let this = self.clone();
642 let block_number = block.header().number();
643
644 let (mut exec_witness, lowest_block_number) = self
645 .eth_api()
646 .spawn_with_state_at_block(block.parent_hash().into(), move |state_provider| {
647 let db = StateProviderDatabase::new(&state_provider);
648 let block_executor = this.eth_api().evm_config().executor(db);
649
650 let mut witness_record = ExecutionWitnessRecord::default();
651
652 let _ = block_executor
653 .execute_with_state_closure(&block, |statedb: &State<_>| {
654 witness_record.record_executed_state(statedb);
655 })
656 .map_err(|err| EthApiError::Internal(err.into()))?;
657
658 let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number } =
659 witness_record;
660
661 let state = state_provider
662 .witness(Default::default(), hashed_state)
663 .map_err(EthApiError::from)?;
664 Ok((
665 ExecutionWitness { state, codes, keys, ..Default::default() },
666 lowest_block_number,
667 ))
668 })
669 .await?;
670
671 let smallest = match lowest_block_number {
672 Some(smallest) => smallest,
673 None => {
674 block_number.saturating_sub(1)
677 }
678 };
679
680 let range = smallest..block_number;
681 exec_witness.headers = self
682 .provider()
683 .headers_range(range)
684 .map_err(EthApiError::from)?
685 .into_iter()
686 .map(|header| {
687 let mut serialized_header = Vec::new();
688 header.encode(&mut serialized_header);
689 serialized_header.into()
690 })
691 .collect();
692
693 Ok(exec_witness)
694 }
695
696 pub async fn debug_code_by_hash(
699 &self,
700 hash: B256,
701 block_id: Option<BlockId>,
702 ) -> Result<Option<Bytes>, Eth::Error> {
703 Ok(self
704 .provider()
705 .state_by_block_id(block_id.unwrap_or_default())
706 .map_err(Eth::Error::from_eth_err)?
707 .bytecode_by_hash(&hash)
708 .map_err(Eth::Error::from_eth_err)?
709 .map(|b| b.original_bytes()))
710 }
711
712 fn trace_transaction(
727 &self,
728 opts: &GethDebugTracingOptions,
729 evm_env: EvmEnvFor<Eth::Evm>,
730 tx_env: TxEnvFor<Eth::Evm>,
731 db: &mut StateCacheDb<'_>,
732 transaction_context: Option<TransactionContext>,
733 fused_inspector: &mut Option<TracingInspector>,
734 ) -> Result<(GethTrace, EvmState), Eth::Error> {
735 let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts;
736
737 let tx_info = TransactionInfo {
738 hash: transaction_context.as_ref().map(|c| c.tx_hash).unwrap_or_default(),
739 index: transaction_context
740 .as_ref()
741 .map(|c| c.tx_index.map(|i| i as u64))
742 .unwrap_or_default(),
743 block_hash: transaction_context.as_ref().map(|c| c.block_hash).unwrap_or_default(),
744 block_number: Some(evm_env.block_env.number.saturating_to()),
745 base_fee: Some(evm_env.block_env.basefee),
746 };
747
748 if let Some(tracer) = tracer {
749 #[allow(unreachable_patterns)]
750 return match tracer {
751 GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
752 GethDebugBuiltInTracerType::FourByteTracer => {
753 let mut inspector = FourByteInspector::default();
754 let res = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
755 return Ok((FourByteFrame::from(&inspector).into(), res.state))
756 }
757 GethDebugBuiltInTracerType::CallTracer => {
758 let call_config = tracer_config
759 .clone()
760 .into_call_config()
761 .map_err(|_| EthApiError::InvalidTracerConfig)?;
762
763 let mut inspector = fused_inspector.get_or_insert_with(|| {
764 TracingInspector::new(TracingInspectorConfig::from_geth_call_config(
765 &call_config,
766 ))
767 });
768
769 let gas_limit = tx_env.gas_limit();
770 let res = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
771
772 inspector.set_transaction_gas_limit(gas_limit);
773
774 let frame = inspector
775 .geth_builder()
776 .geth_call_traces(call_config, res.result.gas_used());
777
778 return Ok((frame.into(), res.state))
779 }
780 GethDebugBuiltInTracerType::PreStateTracer => {
781 let prestate_config = tracer_config
782 .clone()
783 .into_pre_state_config()
784 .map_err(|_| EthApiError::InvalidTracerConfig)?;
785
786 let mut inspector = fused_inspector.get_or_insert_with(|| {
787 TracingInspector::new(
788 TracingInspectorConfig::from_geth_prestate_config(&prestate_config),
789 )
790 });
791 let gas_limit = tx_env.gas_limit();
792 let res =
793 self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
794
795 inspector.set_transaction_gas_limit(gas_limit);
796 let frame = inspector
797 .geth_builder()
798 .geth_prestate_traces(&res, &prestate_config, db)
799 .map_err(Eth::Error::from_eth_err)?;
800
801 return Ok((frame.into(), res.state))
802 }
803 GethDebugBuiltInTracerType::NoopTracer => {
804 Ok((NoopFrame::default().into(), Default::default()))
805 }
806 GethDebugBuiltInTracerType::MuxTracer => {
807 let mux_config = tracer_config
808 .clone()
809 .into_mux_config()
810 .map_err(|_| EthApiError::InvalidTracerConfig)?;
811
812 let mut inspector = MuxInspector::try_from_config(mux_config)
813 .map_err(Eth::Error::from_eth_err)?;
814
815 let res =
816 self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
817 let frame = inspector
818 .try_into_mux_frame(&res, db, tx_info)
819 .map_err(Eth::Error::from_eth_err)?;
820 return Ok((frame.into(), res.state))
821 }
822 GethDebugBuiltInTracerType::FlatCallTracer => {
823 let flat_call_config = tracer_config
824 .clone()
825 .into_flat_call_config()
826 .map_err(|_| EthApiError::InvalidTracerConfig)?;
827
828 let mut inspector = TracingInspector::new(
829 TracingInspectorConfig::from_flat_call_config(&flat_call_config),
830 );
831
832 let gas_limit = tx_env.gas_limit();
833 let res = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
834 let frame: FlatCallFrame = inspector
835 .with_transaction_gas_limit(gas_limit)
836 .into_parity_builder()
837 .into_localized_transaction_traces(tx_info);
838
839 return Ok((frame.into(), res.state));
840 }
841 },
842 #[cfg(not(feature = "js-tracer"))]
843 GethDebugTracerType::JsTracer(_) => {
844 Err(EthApiError::Unsupported("JS Tracer is not enabled").into())
845 }
846 #[cfg(feature = "js-tracer")]
847 GethDebugTracerType::JsTracer(code) => {
848 let config = tracer_config.clone().into_json();
849 let mut inspector =
850 revm_inspectors::tracing::js::JsInspector::with_transaction_context(
851 code.clone(),
852 config,
853 transaction_context.unwrap_or_default(),
854 )
855 .map_err(Eth::Error::from_eth_err)?;
856 let res = self.eth_api().inspect(
857 &mut *db,
858 evm_env.clone(),
859 tx_env.clone(),
860 &mut inspector,
861 )?;
862
863 let state = res.state.clone();
864 let result = inspector
865 .json_result(res, &tx_env, &evm_env.block_env, db)
866 .map_err(Eth::Error::from_eth_err)?;
867 Ok((GethTrace::JS(result), state))
868 }
869 _ => {
870 Err(EthApiError::Unsupported("unsupported tracer").into())
873 }
874 }
875 }
876
877 let mut inspector = fused_inspector.get_or_insert_with(|| {
879 let inspector_config = TracingInspectorConfig::from_geth_config(config);
880 TracingInspector::new(inspector_config)
881 });
882 let gas_limit = tx_env.gas_limit();
883 let res = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
884 let gas_used = res.result.gas_used();
885 let return_value = res.result.into_output().unwrap_or_default();
886 inspector.set_transaction_gas_limit(gas_limit);
887 let frame = inspector.geth_builder().geth_traces(gas_used, return_value, *config);
888
889 Ok((frame.into(), res.state))
890 }
891
892 async fn debug_state_root_with_updates(
895 &self,
896 hashed_state: HashedPostState,
897 block_id: Option<BlockId>,
898 ) -> Result<(B256, TrieUpdates), Eth::Error> {
899 self.inner
900 .eth_api
901 .spawn_blocking_io(move |this| {
902 let state = this
903 .provider()
904 .state_by_block_id(block_id.unwrap_or_default())
905 .map_err(Eth::Error::from_eth_err)?;
906 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
907 })
908 .await
909 }
910}
911
912#[async_trait]
913impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
914where
915 Eth: EthApiTypes + EthTransactions + TraceExt + 'static,
916{
917 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
919 let header = match block_id {
920 BlockId::Hash(hash) => self.provider().header(hash.into()).to_rpc_result()?,
921 BlockId::Number(number_or_tag) => {
922 let number = self
923 .provider()
924 .convert_block_number(number_or_tag)
925 .to_rpc_result()?
926 .ok_or_else(|| {
927 internal_rpc_err("Pending block not supported".to_string())
928 })?;
929 self.provider().header_by_number(number).to_rpc_result()?
930 }
931 };
932
933 let mut res = Vec::new();
934 if let Some(header) = header {
935 header.encode(&mut res);
936 }
937
938 Ok(res.into())
939 }
940
941 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
943 let block = self
944 .provider()
945 .block_by_id(block_id)
946 .to_rpc_result()?
947 .ok_or(EthApiError::HeaderNotFound(block_id))?;
948 let mut res = Vec::new();
949 block.encode(&mut res);
950 Ok(res.into())
951 }
952
953 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
959 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
960 }
961
962 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
965 let block = self
966 .provider()
967 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
968 .to_rpc_result()?
969 .unwrap_or_default();
970 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
971 }
972
973 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
975 Ok(self
976 .provider()
977 .receipts_by_block_id(block_id)
978 .to_rpc_result()?
979 .unwrap_or_default()
980 .into_iter()
981 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
982 .collect())
983 }
984
985 async fn bad_blocks(&self) -> RpcResult<Vec<RpcBlock>> {
987 Ok(vec![])
988 }
989
990 async fn debug_trace_chain(
992 &self,
993 _start_exclusive: BlockNumberOrTag,
994 _end_inclusive: BlockNumberOrTag,
995 ) -> RpcResult<Vec<BlockTraceResult>> {
996 Err(internal_rpc_err("unimplemented"))
997 }
998
999 async fn debug_trace_block(
1001 &self,
1002 rlp_block: Bytes,
1003 opts: Option<GethDebugTracingOptions>,
1004 ) -> RpcResult<Vec<TraceResult>> {
1005 let _permit = self.acquire_trace_permit().await;
1006 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
1007 .await
1008 .map_err(Into::into)
1009 }
1010
1011 async fn debug_trace_block_by_hash(
1013 &self,
1014 block: B256,
1015 opts: Option<GethDebugTracingOptions>,
1016 ) -> RpcResult<Vec<TraceResult>> {
1017 let _permit = self.acquire_trace_permit().await;
1018 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
1019 .await
1020 .map_err(Into::into)
1021 }
1022
1023 async fn debug_trace_block_by_number(
1025 &self,
1026 block: BlockNumberOrTag,
1027 opts: Option<GethDebugTracingOptions>,
1028 ) -> RpcResult<Vec<TraceResult>> {
1029 let _permit = self.acquire_trace_permit().await;
1030 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
1031 .await
1032 .map_err(Into::into)
1033 }
1034
1035 async fn debug_trace_transaction(
1037 &self,
1038 tx_hash: B256,
1039 opts: Option<GethDebugTracingOptions>,
1040 ) -> RpcResult<GethTrace> {
1041 let _permit = self.acquire_trace_permit().await;
1042 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
1043 .await
1044 .map_err(Into::into)
1045 }
1046
1047 async fn debug_trace_call(
1049 &self,
1050 request: RpcTxReq<Eth::NetworkTypes>,
1051 block_id: Option<BlockId>,
1052 opts: Option<GethDebugTracingCallOptions>,
1053 ) -> RpcResult<GethTrace> {
1054 let _permit = self.acquire_trace_permit().await;
1055 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
1056 .await
1057 .map_err(Into::into)
1058 }
1059
1060 async fn debug_trace_call_many(
1061 &self,
1062 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
1063 state_context: Option<StateContext>,
1064 opts: Option<GethDebugTracingCallOptions>,
1065 ) -> RpcResult<Vec<Vec<GethTrace>>> {
1066 let _permit = self.acquire_trace_permit().await;
1067 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
1068 }
1069
1070 async fn debug_execution_witness(
1072 &self,
1073 block: BlockNumberOrTag,
1074 ) -> RpcResult<ExecutionWitness> {
1075 let _permit = self.acquire_trace_permit().await;
1076 Self::debug_execution_witness(self, block).await.map_err(Into::into)
1077 }
1078
1079 async fn debug_execution_witness_by_block_hash(
1081 &self,
1082 hash: B256,
1083 ) -> RpcResult<ExecutionWitness> {
1084 let _permit = self.acquire_trace_permit().await;
1085 Self::debug_execution_witness_by_block_hash(self, hash).await.map_err(Into::into)
1086 }
1087
1088 async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> {
1089 Ok(())
1090 }
1091
1092 async fn debug_account_range(
1093 &self,
1094 _block_number: BlockNumberOrTag,
1095 _start: Bytes,
1096 _max_results: u64,
1097 _nocode: bool,
1098 _nostorage: bool,
1099 _incompletes: bool,
1100 ) -> RpcResult<()> {
1101 Ok(())
1102 }
1103
1104 async fn debug_block_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
1105 Ok(())
1106 }
1107
1108 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
1109 Ok(())
1110 }
1111
1112 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
1113 Ok(self.provider().chain_spec().genesis().config.clone())
1114 }
1115
1116 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
1117 Ok(())
1118 }
1119
1120 async fn debug_code_by_hash(
1121 &self,
1122 hash: B256,
1123 block_id: Option<BlockId>,
1124 ) -> RpcResult<Option<Bytes>> {
1125 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
1126 }
1127
1128 async fn debug_cpu_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
1129 Ok(())
1130 }
1131
1132 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
1133 Ok(())
1134 }
1135
1136 async fn debug_db_ancients(&self) -> RpcResult<()> {
1137 Ok(())
1138 }
1139
1140 async fn debug_db_get(&self, _key: String) -> RpcResult<()> {
1141 Ok(())
1142 }
1143
1144 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
1145 Ok(())
1146 }
1147
1148 async fn debug_free_os_memory(&self) -> RpcResult<()> {
1149 Ok(())
1150 }
1151
1152 async fn debug_freeze_client(&self, _node: String) -> RpcResult<()> {
1153 Ok(())
1154 }
1155
1156 async fn debug_gc_stats(&self) -> RpcResult<()> {
1157 Ok(())
1158 }
1159
1160 async fn debug_get_accessible_state(
1161 &self,
1162 _from: BlockNumberOrTag,
1163 _to: BlockNumberOrTag,
1164 ) -> RpcResult<()> {
1165 Ok(())
1166 }
1167
1168 async fn debug_get_modified_accounts_by_hash(
1169 &self,
1170 _start_hash: B256,
1171 _end_hash: B256,
1172 ) -> RpcResult<()> {
1173 Ok(())
1174 }
1175
1176 async fn debug_get_modified_accounts_by_number(
1177 &self,
1178 _start_number: u64,
1179 _end_number: u64,
1180 ) -> RpcResult<()> {
1181 Ok(())
1182 }
1183
1184 async fn debug_go_trace(&self, _file: String, _seconds: u64) -> RpcResult<()> {
1185 Ok(())
1186 }
1187
1188 async fn debug_intermediate_roots(
1189 &self,
1190 _block_hash: B256,
1191 _opts: Option<GethDebugTracingCallOptions>,
1192 ) -> RpcResult<()> {
1193 Ok(())
1194 }
1195
1196 async fn debug_mem_stats(&self) -> RpcResult<()> {
1197 Ok(())
1198 }
1199
1200 async fn debug_mutex_profile(&self, _file: String, _nsec: u64) -> RpcResult<()> {
1201 Ok(())
1202 }
1203
1204 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
1205 Ok(())
1206 }
1207
1208 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
1209 Ok(())
1210 }
1211
1212 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
1213 Ok(Default::default())
1214 }
1215
1216 async fn debug_set_block_profile_rate(&self, _rate: u64) -> RpcResult<()> {
1217 Ok(())
1218 }
1219
1220 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
1221 Ok(())
1222 }
1223
1224 async fn debug_set_head(&self, _number: u64) -> RpcResult<()> {
1225 Ok(())
1226 }
1227
1228 async fn debug_set_mutex_profile_fraction(&self, _rate: i32) -> RpcResult<()> {
1229 Ok(())
1230 }
1231
1232 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1233 Ok(())
1234 }
1235
1236 async fn debug_stacks(&self) -> RpcResult<()> {
1237 Ok(())
1238 }
1239
1240 async fn debug_standard_trace_bad_block_to_file(
1241 &self,
1242 _block: BlockNumberOrTag,
1243 _opts: Option<GethDebugTracingCallOptions>,
1244 ) -> RpcResult<()> {
1245 Ok(())
1246 }
1247
1248 async fn debug_standard_trace_block_to_file(
1249 &self,
1250 _block: BlockNumberOrTag,
1251 _opts: Option<GethDebugTracingCallOptions>,
1252 ) -> RpcResult<()> {
1253 Ok(())
1254 }
1255
1256 async fn debug_start_cpu_profile(&self, _file: String) -> RpcResult<()> {
1257 Ok(())
1258 }
1259
1260 async fn debug_start_go_trace(&self, _file: String) -> RpcResult<()> {
1261 Ok(())
1262 }
1263
1264 async fn debug_state_root_with_updates(
1265 &self,
1266 hashed_state: HashedPostState,
1267 block_id: Option<BlockId>,
1268 ) -> RpcResult<(B256, TrieUpdates)> {
1269 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1270 }
1271
1272 async fn debug_stop_cpu_profile(&self) -> RpcResult<()> {
1273 Ok(())
1274 }
1275
1276 async fn debug_stop_go_trace(&self) -> RpcResult<()> {
1277 Ok(())
1278 }
1279
1280 async fn debug_storage_range_at(
1281 &self,
1282 _block_hash: B256,
1283 _tx_idx: usize,
1284 _contract_address: Address,
1285 _key_start: B256,
1286 _max_result: u64,
1287 ) -> RpcResult<()> {
1288 Ok(())
1289 }
1290
1291 async fn debug_trace_bad_block(
1292 &self,
1293 _block_hash: B256,
1294 _opts: Option<GethDebugTracingCallOptions>,
1295 ) -> RpcResult<()> {
1296 Ok(())
1297 }
1298
1299 async fn debug_verbosity(&self, _level: usize) -> RpcResult<()> {
1300 Ok(())
1301 }
1302
1303 async fn debug_vmodule(&self, _pattern: String) -> RpcResult<()> {
1304 Ok(())
1305 }
1306
1307 async fn debug_write_block_profile(&self, _file: String) -> RpcResult<()> {
1308 Ok(())
1309 }
1310
1311 async fn debug_write_mem_profile(&self, _file: String) -> RpcResult<()> {
1312 Ok(())
1313 }
1314
1315 async fn debug_write_mutex_profile(&self, _file: String) -> RpcResult<()> {
1316 Ok(())
1317 }
1318}
1319
1320impl<Eth> std::fmt::Debug for DebugApi<Eth> {
1321 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1322 f.debug_struct("DebugApi").finish_non_exhaustive()
1323 }
1324}
1325
1326impl<Eth> Clone for DebugApi<Eth> {
1327 fn clone(&self) -> Self {
1328 Self { inner: Arc::clone(&self.inner) }
1329 }
1330}
1331
1332struct DebugApiInner<Eth> {
1333 eth_api: Eth,
1335 blocking_task_guard: BlockingTaskGuard,
1337}