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