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