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