1use alloy_consensus::{transaction::SignerRecoverable, BlockHeader};
2use alloy_eips::{eip2718::Encodable2718, BlockId, BlockNumberOrTag};
3use alloy_genesis::ChainConfig;
4use alloy_primitives::{uint, Address, Bytes, B256};
5use alloy_rlp::{Decodable, Encodable};
6use alloy_rpc_types_debug::ExecutionWitness;
7use alloy_rpc_types_eth::{
8 state::EvmOverrides, Block as RpcBlock, BlockError, Bundle, 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::{ChainSpecProvider, EthChainSpec, EthereumHardforks};
18use reth_evm::{execute::Executor, ConfigureEvm, EvmEnvFor, TxEnvFor};
19use reth_primitives_traits::{
20 Block as _, BlockBody, ReceiptWithBloom, RecoveredBlock, SignedTransaction,
21};
22use reth_revm::{
23 database::StateProviderDatabase,
24 db::{CacheDB, State},
25 witness::ExecutionWitnessRecord,
26};
27use reth_rpc_api::DebugApiServer;
28use reth_rpc_convert::RpcTxReq;
29use reth_rpc_eth_api::{
30 helpers::{EthTransactions, TraceExt},
31 EthApiTypes, FromEthApiError, RpcNodeCore,
32};
33use reth_rpc_eth_types::{EthApiError, StateCacheDb};
34use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
35use reth_storage_api::{
36 BlockIdReader, BlockReaderIdExt, HeaderProvider, ProviderBlock, ReceiptProviderIdExt,
37 StateProofProvider, StateProviderFactory, StateRootProvider, TransactionVariant,
38};
39use reth_tasks::pool::BlockingTaskGuard;
40use reth_trie_common::{updates::TrieUpdates, HashedPostState};
41use revm::{context_interface::Transaction, state::EvmState, DatabaseCommit};
42use revm_inspectors::tracing::{
43 FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig, TransactionContext,
44};
45use std::sync::Arc;
46use tokio::sync::{AcquireError, OwnedSemaphorePermit};
47
48pub struct DebugApi<Eth> {
52 inner: Arc<DebugApiInner<Eth>>,
53}
54
55impl<Eth> DebugApi<Eth> {
58 pub fn new(eth_api: Eth, blocking_task_guard: BlockingTaskGuard) -> Self {
60 let inner = Arc::new(DebugApiInner { eth_api, blocking_task_guard });
61 Self { inner }
62 }
63
64 pub fn eth_api(&self) -> &Eth {
66 &self.inner.eth_api
67 }
68}
69
70impl<Eth: RpcNodeCore> DebugApi<Eth> {
71 pub fn provider(&self) -> &Eth::Provider {
73 self.inner.eth_api.provider()
74 }
75}
76
77impl<Eth> DebugApi<Eth>
80where
81 Eth: EthApiTypes + TraceExt + 'static,
82{
83 async fn acquire_trace_permit(&self) -> Result<OwnedSemaphorePermit, AcquireError> {
85 self.inner.blocking_task_guard.clone().acquire_owned().await
86 }
87
88 async fn trace_block(
90 &self,
91 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
92 evm_env: EvmEnvFor<Eth::Evm>,
93 opts: GethDebugTracingOptions,
94 ) -> Result<Vec<TraceResult>, Eth::Error> {
95 let this = self.clone();
97 self.eth_api()
98 .spawn_with_state_at_block(block.parent_hash().into(), move |state| {
99 let mut results = Vec::with_capacity(block.body().transactions().len());
100 let mut db = CacheDB::new(StateProviderDatabase::new(state));
101
102 this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
103
104 let mut transactions = block.transactions_recovered().enumerate().peekable();
105 let mut inspector = None;
106 while let Some((index, tx)) = transactions.next() {
107 let tx_hash = *tx.tx_hash();
108
109 let tx_env = this.eth_api().evm_config().tx_env(tx);
110
111 let (result, state_changes) = this.trace_transaction(
112 &opts,
113 evm_env.clone(),
114 tx_env,
115 &mut db,
116 Some(TransactionContext {
117 block_hash: Some(block.hash()),
118 tx_hash: Some(tx_hash),
119 tx_index: Some(index),
120 }),
121 &mut inspector,
122 )?;
123
124 inspector = inspector.map(|insp| insp.fused());
125
126 results.push(TraceResult::Success { result, tx_hash: Some(tx_hash) });
127 if transactions.peek().is_some() {
128 db.commit(state_changes)
131 }
132 }
133
134 Ok(results)
135 })
136 .await
137 }
138
139 pub async fn debug_trace_raw_block(
145 &self,
146 rlp_block: Bytes,
147 opts: GethDebugTracingOptions,
148 ) -> Result<Vec<TraceResult>, Eth::Error> {
149 let block: ProviderBlock<Eth::Provider> = Decodable::decode(&mut rlp_block.as_ref())
150 .map_err(BlockError::RlpDecodeRawBlock)
151 .map_err(Eth::Error::from_eth_err)?;
152
153 let evm_env = self.eth_api().evm_config().evm_env(block.header());
154
155 let senders =
157 if self.provider().chain_spec().is_homestead_active_at_block(block.header().number()) {
158 block
159 .body()
160 .transactions()
161 .iter()
162 .map(|tx| tx.recover_signer().map_err(Eth::Error::from_eth_err))
163 .collect::<Result<Vec<_>, _>>()?
164 .into_iter()
165 .collect()
166 } else {
167 block
168 .body()
169 .transactions()
170 .iter()
171 .map(|tx| tx.recover_signer_unchecked().map_err(Eth::Error::from_eth_err))
172 .collect::<Result<Vec<_>, _>>()?
173 .into_iter()
174 .collect()
175 };
176
177 self.trace_block(Arc::new(block.into_recovered_with_signers(senders)), evm_env, opts).await
178 }
179
180 pub async fn debug_trace_block(
182 &self,
183 block_id: BlockId,
184 opts: GethDebugTracingOptions,
185 ) -> Result<Vec<TraceResult>, Eth::Error> {
186 let block_hash = self
187 .provider()
188 .block_hash_for_id(block_id)
189 .map_err(Eth::Error::from_eth_err)?
190 .ok_or(EthApiError::HeaderNotFound(block_id))?;
191
192 let ((evm_env, _), block) = futures::try_join!(
193 self.eth_api().evm_env_at(block_hash.into()),
194 self.eth_api().recovered_block(block_hash.into()),
195 )?;
196
197 let block = block.ok_or(EthApiError::HeaderNotFound(block_id))?;
198
199 self.trace_block(block, evm_env, opts).await
200 }
201
202 pub async fn debug_trace_transaction(
206 &self,
207 tx_hash: B256,
208 opts: GethDebugTracingOptions,
209 ) -> Result<GethTrace, Eth::Error> {
210 let (transaction, block) = match self.eth_api().transaction_and_block(tx_hash).await? {
211 None => return Err(EthApiError::TransactionNotFound.into()),
212 Some(res) => res,
213 };
214 let (evm_env, _) = self.eth_api().evm_env_at(block.hash().into()).await?;
215
216 let state_at: BlockId = block.parent_hash().into();
219 let block_hash = block.hash();
220
221 let this = self.clone();
222 self.eth_api()
223 .spawn_with_state_at_block(state_at, move |state| {
224 let block_txs = block.transactions_recovered();
225
226 let tx = transaction.into_recovered();
228
229 let mut db = CacheDB::new(StateProviderDatabase::new(state));
230
231 this.eth_api().apply_pre_execution_changes(&block, &mut db, &evm_env)?;
232
233 let index = this.eth_api().replay_transactions_until(
235 &mut db,
236 evm_env.clone(),
237 block_txs,
238 *tx.tx_hash(),
239 )?;
240
241 let tx_env = this.eth_api().evm_config().tx_env(&tx);
242
243 this.trace_transaction(
244 &opts,
245 evm_env,
246 tx_env,
247 &mut db,
248 Some(TransactionContext {
249 block_hash: Some(block_hash),
250 tx_index: Some(index),
251 tx_hash: Some(*tx.tx_hash()),
252 }),
253 &mut None,
254 )
255 .map(|(trace, _)| trace)
256 })
257 .await
258 }
259
260 pub async fn debug_trace_call(
266 &self,
267 call: RpcTxReq<Eth::NetworkTypes>,
268 block_id: Option<BlockId>,
269 opts: GethDebugTracingCallOptions,
270 ) -> Result<GethTrace, Eth::Error> {
271 let at = block_id.unwrap_or_default();
272 let GethDebugTracingCallOptions { tracing_options, state_overrides, block_overrides } =
273 opts;
274 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
275 let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options;
276
277 let this = self.clone();
278 if let Some(tracer) = tracer {
279 #[allow(unreachable_patterns)]
280 return match tracer {
281 GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
282 GethDebugBuiltInTracerType::FourByteTracer => {
283 let mut inspector = FourByteInspector::default();
284 let inspector = self
285 .eth_api()
286 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
287 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
288 Ok(inspector)
289 })
290 .await?;
291 Ok(FourByteFrame::from(&inspector).into())
292 }
293 GethDebugBuiltInTracerType::CallTracer => {
294 let call_config = tracer_config
295 .into_call_config()
296 .map_err(|_| EthApiError::InvalidTracerConfig)?;
297
298 let mut inspector = TracingInspector::new(
299 TracingInspectorConfig::from_geth_call_config(&call_config),
300 );
301
302 let frame = self
303 .eth_api()
304 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
305 let gas_limit = tx_env.gas_limit();
306 let res =
307 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
308 let frame = inspector
309 .with_transaction_gas_limit(gas_limit)
310 .into_geth_builder()
311 .geth_call_traces(call_config, res.result.gas_used());
312 Ok(frame.into())
313 })
314 .await?;
315 Ok(frame)
316 }
317 GethDebugBuiltInTracerType::PreStateTracer => {
318 let prestate_config = tracer_config
319 .into_pre_state_config()
320 .map_err(|_| EthApiError::InvalidTracerConfig)?;
321 let mut inspector = TracingInspector::new(
322 TracingInspectorConfig::from_geth_prestate_config(&prestate_config),
323 );
324
325 let frame = self
326 .eth_api()
327 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
328 let db = db.0;
331
332 let gas_limit = tx_env.gas_limit();
333 let res = this.eth_api().inspect(
334 &mut *db,
335 evm_env,
336 tx_env,
337 &mut inspector,
338 )?;
339 let frame = inspector
340 .with_transaction_gas_limit(gas_limit)
341 .into_geth_builder()
342 .geth_prestate_traces(&res, &prestate_config, db)
343 .map_err(Eth::Error::from_eth_err)?;
344 Ok(frame)
345 })
346 .await?;
347 Ok(frame.into())
348 }
349 GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()),
350 GethDebugBuiltInTracerType::MuxTracer => {
351 let mux_config = tracer_config
352 .into_mux_config()
353 .map_err(|_| EthApiError::InvalidTracerConfig)?;
354
355 let mut inspector = MuxInspector::try_from_config(mux_config)
356 .map_err(Eth::Error::from_eth_err)?;
357
358 let frame = self
359 .inner
360 .eth_api
361 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
362 let db = db.0;
365
366 let tx_info = TransactionInfo {
367 block_number: Some(evm_env.block_env.number.saturating_to()),
368 base_fee: Some(evm_env.block_env.basefee),
369 hash: None,
370 block_hash: None,
371 index: None,
372 };
373
374 let res = this.eth_api().inspect(
375 &mut *db,
376 evm_env,
377 tx_env,
378 &mut inspector,
379 )?;
380 let frame = inspector
381 .try_into_mux_frame(&res, db, tx_info)
382 .map_err(Eth::Error::from_eth_err)?;
383 Ok(frame.into())
384 })
385 .await?;
386 Ok(frame)
387 }
388 GethDebugBuiltInTracerType::FlatCallTracer => {
389 let flat_call_config = tracer_config
390 .into_flat_call_config()
391 .map_err(|_| EthApiError::InvalidTracerConfig)?;
392
393 let mut inspector = TracingInspector::new(
394 TracingInspectorConfig::from_flat_call_config(&flat_call_config),
395 );
396
397 let frame: FlatCallFrame = self
398 .inner
399 .eth_api
400 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
401 let gas_limit = tx_env.gas_limit();
402 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
403 let tx_info = TransactionInfo::default();
404 let frame: FlatCallFrame = inspector
405 .with_transaction_gas_limit(gas_limit)
406 .into_parity_builder()
407 .into_localized_transaction_traces(tx_info);
408 Ok(frame)
409 })
410 .await?;
411
412 Ok(frame.into())
413 }
414 },
415 #[cfg(not(feature = "js-tracer"))]
416 GethDebugTracerType::JsTracer(_) => {
417 Err(EthApiError::Unsupported("JS Tracer is not enabled").into())
418 }
419 #[cfg(feature = "js-tracer")]
420 GethDebugTracerType::JsTracer(code) => {
421 let config = tracer_config.into_json();
422
423 let (_, at) = self.eth_api().evm_env_at(at).await?;
424
425 let res = self
426 .eth_api()
427 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
428 let db = db.0;
431
432 let mut inspector =
433 revm_inspectors::tracing::js::JsInspector::new(code, config)
434 .map_err(Eth::Error::from_eth_err)?;
435 let res = this.eth_api().inspect(
436 &mut *db,
437 evm_env.clone(),
438 tx_env.clone(),
439 &mut inspector,
440 )?;
441 inspector
442 .json_result(res, &tx_env, &evm_env.block_env, db)
443 .map_err(Eth::Error::from_eth_err)
444 })
445 .await?;
446
447 Ok(GethTrace::JS(res))
448 }
449 _ => {
450 Err(EthApiError::Unsupported("unsupported tracer").into())
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 gas_limit = tx_env.gas_limit();
466 let res = this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
467 Ok((res, 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<RpcTxReq<Eth::NetworkTypes>>>,
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 += uint!(1_U256);
585 evm_env.block_env.timestamp += uint!(12_U256);
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.eth_api().evm_config().executor(db);
641
642 let mut witness_record = ExecutionWitnessRecord::default();
643
644 let _ = block_executor
645 .execute_with_state_closure(&block, |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.saturating_to()),
738 base_fee: Some(evm_env.block_env.basefee),
739 };
740
741 if let Some(tracer) = tracer {
742 #[allow(unreachable_patterns)]
743 return match tracer {
744 GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
745 GethDebugBuiltInTracerType::FourByteTracer => {
746 let mut inspector = FourByteInspector::default();
747 let res = 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 gas_limit = tx_env.gas_limit();
763 let res = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
764
765 inspector.set_transaction_gas_limit(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 gas_limit = tx_env.gas_limit();
785 let res =
786 self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
787
788 inspector.set_transaction_gas_limit(gas_limit);
789 let frame = inspector
790 .geth_builder()
791 .geth_prestate_traces(&res, &prestate_config, db)
792 .map_err(Eth::Error::from_eth_err)?;
793
794 return Ok((frame.into(), res.state))
795 }
796 GethDebugBuiltInTracerType::NoopTracer => {
797 Ok((NoopFrame::default().into(), Default::default()))
798 }
799 GethDebugBuiltInTracerType::MuxTracer => {
800 let mux_config = tracer_config
801 .clone()
802 .into_mux_config()
803 .map_err(|_| EthApiError::InvalidTracerConfig)?;
804
805 let mut inspector = MuxInspector::try_from_config(mux_config)
806 .map_err(Eth::Error::from_eth_err)?;
807
808 let res =
809 self.eth_api().inspect(&mut *db, evm_env, tx_env, &mut inspector)?;
810 let frame = inspector
811 .try_into_mux_frame(&res, db, tx_info)
812 .map_err(Eth::Error::from_eth_err)?;
813 return Ok((frame.into(), res.state))
814 }
815 GethDebugBuiltInTracerType::FlatCallTracer => {
816 let flat_call_config = tracer_config
817 .clone()
818 .into_flat_call_config()
819 .map_err(|_| EthApiError::InvalidTracerConfig)?;
820
821 let mut inspector = TracingInspector::new(
822 TracingInspectorConfig::from_flat_call_config(&flat_call_config),
823 );
824
825 let gas_limit = tx_env.gas_limit();
826 let res = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
827 let frame: FlatCallFrame = inspector
828 .with_transaction_gas_limit(gas_limit)
829 .into_parity_builder()
830 .into_localized_transaction_traces(tx_info);
831
832 return Ok((frame.into(), res.state));
833 }
834 },
835 #[cfg(not(feature = "js-tracer"))]
836 GethDebugTracerType::JsTracer(_) => {
837 Err(EthApiError::Unsupported("JS Tracer is not enabled").into())
838 }
839 #[cfg(feature = "js-tracer")]
840 GethDebugTracerType::JsTracer(code) => {
841 let config = tracer_config.clone().into_json();
842 let mut inspector =
843 revm_inspectors::tracing::js::JsInspector::with_transaction_context(
844 code.clone(),
845 config,
846 transaction_context.unwrap_or_default(),
847 )
848 .map_err(Eth::Error::from_eth_err)?;
849 let res = self.eth_api().inspect(
850 &mut *db,
851 evm_env.clone(),
852 tx_env.clone(),
853 &mut inspector,
854 )?;
855
856 let state = res.state.clone();
857 let result = inspector
858 .json_result(res, &tx_env, &evm_env.block_env, db)
859 .map_err(Eth::Error::from_eth_err)?;
860 Ok((GethTrace::JS(result), state))
861 }
862 _ => {
863 Err(EthApiError::Unsupported("unsupported tracer").into())
866 }
867 }
868 }
869
870 let mut inspector = fused_inspector.get_or_insert_with(|| {
872 let inspector_config = TracingInspectorConfig::from_geth_config(config);
873 TracingInspector::new(inspector_config)
874 });
875 let gas_limit = tx_env.gas_limit();
876 let res = self.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
877 let gas_used = res.result.gas_used();
878 let return_value = res.result.into_output().unwrap_or_default();
879 inspector.set_transaction_gas_limit(gas_limit);
880 let frame = inspector.geth_builder().geth_traces(gas_used, return_value, *config);
881
882 Ok((frame.into(), res.state))
883 }
884
885 async fn debug_state_root_with_updates(
888 &self,
889 hashed_state: HashedPostState,
890 block_id: Option<BlockId>,
891 ) -> Result<(B256, TrieUpdates), Eth::Error> {
892 self.inner
893 .eth_api
894 .spawn_blocking_io(move |this| {
895 let state = this
896 .provider()
897 .state_by_block_id(block_id.unwrap_or_default())
898 .map_err(Eth::Error::from_eth_err)?;
899 state.state_root_with_updates(hashed_state).map_err(Eth::Error::from_eth_err)
900 })
901 .await
902 }
903}
904
905#[async_trait]
906impl<Eth> DebugApiServer<RpcTxReq<Eth::NetworkTypes>> for DebugApi<Eth>
907where
908 Eth: EthApiTypes + EthTransactions + TraceExt + 'static,
909{
910 async fn raw_header(&self, block_id: BlockId) -> RpcResult<Bytes> {
912 let header = match block_id {
913 BlockId::Hash(hash) => self.provider().header(&hash.into()).to_rpc_result()?,
914 BlockId::Number(number_or_tag) => {
915 let number = self
916 .provider()
917 .convert_block_number(number_or_tag)
918 .to_rpc_result()?
919 .ok_or_else(|| {
920 internal_rpc_err("Pending block not supported".to_string())
921 })?;
922 self.provider().header_by_number(number).to_rpc_result()?
923 }
924 };
925
926 let mut res = Vec::new();
927 if let Some(header) = header {
928 header.encode(&mut res);
929 }
930
931 Ok(res.into())
932 }
933
934 async fn raw_block(&self, block_id: BlockId) -> RpcResult<Bytes> {
936 let block = self
937 .provider()
938 .block_by_id(block_id)
939 .to_rpc_result()?
940 .ok_or(EthApiError::HeaderNotFound(block_id))?;
941 let mut res = Vec::new();
942 block.encode(&mut res);
943 Ok(res.into())
944 }
945
946 async fn raw_transaction(&self, hash: B256) -> RpcResult<Option<Bytes>> {
952 self.eth_api().raw_transaction_by_hash(hash).await.map_err(Into::into)
953 }
954
955 async fn raw_transactions(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
958 let block = self
959 .provider()
960 .block_with_senders_by_id(block_id, TransactionVariant::NoHash)
961 .to_rpc_result()?
962 .unwrap_or_default();
963 Ok(block.into_transactions_recovered().map(|tx| tx.encoded_2718().into()).collect())
964 }
965
966 async fn raw_receipts(&self, block_id: BlockId) -> RpcResult<Vec<Bytes>> {
968 Ok(self
969 .provider()
970 .receipts_by_block_id(block_id)
971 .to_rpc_result()?
972 .unwrap_or_default()
973 .into_iter()
974 .map(|receipt| ReceiptWithBloom::from(receipt).encoded_2718().into())
975 .collect())
976 }
977
978 async fn bad_blocks(&self) -> RpcResult<Vec<RpcBlock>> {
980 Ok(vec![])
981 }
982
983 async fn debug_trace_chain(
985 &self,
986 _start_exclusive: BlockNumberOrTag,
987 _end_inclusive: BlockNumberOrTag,
988 ) -> RpcResult<Vec<BlockTraceResult>> {
989 Err(internal_rpc_err("unimplemented"))
990 }
991
992 async fn debug_trace_block(
994 &self,
995 rlp_block: Bytes,
996 opts: Option<GethDebugTracingOptions>,
997 ) -> RpcResult<Vec<TraceResult>> {
998 let _permit = self.acquire_trace_permit().await;
999 Self::debug_trace_raw_block(self, rlp_block, opts.unwrap_or_default())
1000 .await
1001 .map_err(Into::into)
1002 }
1003
1004 async fn debug_trace_block_by_hash(
1006 &self,
1007 block: B256,
1008 opts: Option<GethDebugTracingOptions>,
1009 ) -> RpcResult<Vec<TraceResult>> {
1010 let _permit = self.acquire_trace_permit().await;
1011 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
1012 .await
1013 .map_err(Into::into)
1014 }
1015
1016 async fn debug_trace_block_by_number(
1018 &self,
1019 block: BlockNumberOrTag,
1020 opts: Option<GethDebugTracingOptions>,
1021 ) -> RpcResult<Vec<TraceResult>> {
1022 let _permit = self.acquire_trace_permit().await;
1023 Self::debug_trace_block(self, block.into(), opts.unwrap_or_default())
1024 .await
1025 .map_err(Into::into)
1026 }
1027
1028 async fn debug_trace_transaction(
1030 &self,
1031 tx_hash: B256,
1032 opts: Option<GethDebugTracingOptions>,
1033 ) -> RpcResult<GethTrace> {
1034 let _permit = self.acquire_trace_permit().await;
1035 Self::debug_trace_transaction(self, tx_hash, opts.unwrap_or_default())
1036 .await
1037 .map_err(Into::into)
1038 }
1039
1040 async fn debug_trace_call(
1042 &self,
1043 request: RpcTxReq<Eth::NetworkTypes>,
1044 block_id: Option<BlockId>,
1045 opts: Option<GethDebugTracingCallOptions>,
1046 ) -> RpcResult<GethTrace> {
1047 let _permit = self.acquire_trace_permit().await;
1048 Self::debug_trace_call(self, request, block_id, opts.unwrap_or_default())
1049 .await
1050 .map_err(Into::into)
1051 }
1052
1053 async fn debug_trace_call_many(
1054 &self,
1055 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
1056 state_context: Option<StateContext>,
1057 opts: Option<GethDebugTracingCallOptions>,
1058 ) -> RpcResult<Vec<Vec<GethTrace>>> {
1059 let _permit = self.acquire_trace_permit().await;
1060 Self::debug_trace_call_many(self, bundles, state_context, opts).await.map_err(Into::into)
1061 }
1062
1063 async fn debug_execution_witness(
1065 &self,
1066 block: BlockNumberOrTag,
1067 ) -> RpcResult<ExecutionWitness> {
1068 let _permit = self.acquire_trace_permit().await;
1069 Self::debug_execution_witness(self, block).await.map_err(Into::into)
1070 }
1071
1072 async fn debug_execution_witness_by_block_hash(
1074 &self,
1075 hash: B256,
1076 ) -> RpcResult<ExecutionWitness> {
1077 let _permit = self.acquire_trace_permit().await;
1078 Self::debug_execution_witness_by_block_hash(self, hash).await.map_err(Into::into)
1079 }
1080
1081 async fn debug_backtrace_at(&self, _location: &str) -> RpcResult<()> {
1082 Ok(())
1083 }
1084
1085 async fn debug_account_range(
1086 &self,
1087 _block_number: BlockNumberOrTag,
1088 _start: Bytes,
1089 _max_results: u64,
1090 _nocode: bool,
1091 _nostorage: bool,
1092 _incompletes: bool,
1093 ) -> RpcResult<()> {
1094 Ok(())
1095 }
1096
1097 async fn debug_block_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
1098 Ok(())
1099 }
1100
1101 async fn debug_chaindb_compact(&self) -> RpcResult<()> {
1102 Ok(())
1103 }
1104
1105 async fn debug_chain_config(&self) -> RpcResult<ChainConfig> {
1106 Ok(self.provider().chain_spec().genesis().config.clone())
1107 }
1108
1109 async fn debug_chaindb_property(&self, _property: String) -> RpcResult<()> {
1110 Ok(())
1111 }
1112
1113 async fn debug_code_by_hash(
1114 &self,
1115 hash: B256,
1116 block_id: Option<BlockId>,
1117 ) -> RpcResult<Option<Bytes>> {
1118 Self::debug_code_by_hash(self, hash, block_id).await.map_err(Into::into)
1119 }
1120
1121 async fn debug_cpu_profile(&self, _file: String, _seconds: u64) -> RpcResult<()> {
1122 Ok(())
1123 }
1124
1125 async fn debug_db_ancient(&self, _kind: String, _number: u64) -> RpcResult<()> {
1126 Ok(())
1127 }
1128
1129 async fn debug_db_ancients(&self) -> RpcResult<()> {
1130 Ok(())
1131 }
1132
1133 async fn debug_db_get(&self, _key: String) -> RpcResult<()> {
1134 Ok(())
1135 }
1136
1137 async fn debug_dump_block(&self, _number: BlockId) -> RpcResult<()> {
1138 Ok(())
1139 }
1140
1141 async fn debug_free_os_memory(&self) -> RpcResult<()> {
1142 Ok(())
1143 }
1144
1145 async fn debug_freeze_client(&self, _node: String) -> RpcResult<()> {
1146 Ok(())
1147 }
1148
1149 async fn debug_gc_stats(&self) -> RpcResult<()> {
1150 Ok(())
1151 }
1152
1153 async fn debug_get_accessible_state(
1154 &self,
1155 _from: BlockNumberOrTag,
1156 _to: BlockNumberOrTag,
1157 ) -> RpcResult<()> {
1158 Ok(())
1159 }
1160
1161 async fn debug_get_modified_accounts_by_hash(
1162 &self,
1163 _start_hash: B256,
1164 _end_hash: B256,
1165 ) -> RpcResult<()> {
1166 Ok(())
1167 }
1168
1169 async fn debug_get_modified_accounts_by_number(
1170 &self,
1171 _start_number: u64,
1172 _end_number: u64,
1173 ) -> RpcResult<()> {
1174 Ok(())
1175 }
1176
1177 async fn debug_go_trace(&self, _file: String, _seconds: u64) -> RpcResult<()> {
1178 Ok(())
1179 }
1180
1181 async fn debug_intermediate_roots(
1182 &self,
1183 _block_hash: B256,
1184 _opts: Option<GethDebugTracingCallOptions>,
1185 ) -> RpcResult<()> {
1186 Ok(())
1187 }
1188
1189 async fn debug_mem_stats(&self) -> RpcResult<()> {
1190 Ok(())
1191 }
1192
1193 async fn debug_mutex_profile(&self, _file: String, _nsec: u64) -> RpcResult<()> {
1194 Ok(())
1195 }
1196
1197 async fn debug_preimage(&self, _hash: B256) -> RpcResult<()> {
1198 Ok(())
1199 }
1200
1201 async fn debug_print_block(&self, _number: u64) -> RpcResult<()> {
1202 Ok(())
1203 }
1204
1205 async fn debug_seed_hash(&self, _number: u64) -> RpcResult<B256> {
1206 Ok(Default::default())
1207 }
1208
1209 async fn debug_set_block_profile_rate(&self, _rate: u64) -> RpcResult<()> {
1210 Ok(())
1211 }
1212
1213 async fn debug_set_gc_percent(&self, _v: i32) -> RpcResult<()> {
1214 Ok(())
1215 }
1216
1217 async fn debug_set_head(&self, _number: u64) -> RpcResult<()> {
1218 Ok(())
1219 }
1220
1221 async fn debug_set_mutex_profile_fraction(&self, _rate: i32) -> RpcResult<()> {
1222 Ok(())
1223 }
1224
1225 async fn debug_set_trie_flush_interval(&self, _interval: String) -> RpcResult<()> {
1226 Ok(())
1227 }
1228
1229 async fn debug_stacks(&self) -> RpcResult<()> {
1230 Ok(())
1231 }
1232
1233 async fn debug_standard_trace_bad_block_to_file(
1234 &self,
1235 _block: BlockNumberOrTag,
1236 _opts: Option<GethDebugTracingCallOptions>,
1237 ) -> RpcResult<()> {
1238 Ok(())
1239 }
1240
1241 async fn debug_standard_trace_block_to_file(
1242 &self,
1243 _block: BlockNumberOrTag,
1244 _opts: Option<GethDebugTracingCallOptions>,
1245 ) -> RpcResult<()> {
1246 Ok(())
1247 }
1248
1249 async fn debug_start_cpu_profile(&self, _file: String) -> RpcResult<()> {
1250 Ok(())
1251 }
1252
1253 async fn debug_start_go_trace(&self, _file: String) -> RpcResult<()> {
1254 Ok(())
1255 }
1256
1257 async fn debug_state_root_with_updates(
1258 &self,
1259 hashed_state: HashedPostState,
1260 block_id: Option<BlockId>,
1261 ) -> RpcResult<(B256, TrieUpdates)> {
1262 Self::debug_state_root_with_updates(self, hashed_state, block_id).await.map_err(Into::into)
1263 }
1264
1265 async fn debug_stop_cpu_profile(&self) -> RpcResult<()> {
1266 Ok(())
1267 }
1268
1269 async fn debug_stop_go_trace(&self) -> RpcResult<()> {
1270 Ok(())
1271 }
1272
1273 async fn debug_storage_range_at(
1274 &self,
1275 _block_hash: B256,
1276 _tx_idx: usize,
1277 _contract_address: Address,
1278 _key_start: B256,
1279 _max_result: u64,
1280 ) -> RpcResult<()> {
1281 Ok(())
1282 }
1283
1284 async fn debug_trace_bad_block(
1285 &self,
1286 _block_hash: B256,
1287 _opts: Option<GethDebugTracingCallOptions>,
1288 ) -> RpcResult<()> {
1289 Ok(())
1290 }
1291
1292 async fn debug_verbosity(&self, _level: usize) -> RpcResult<()> {
1293 Ok(())
1294 }
1295
1296 async fn debug_vmodule(&self, _pattern: String) -> RpcResult<()> {
1297 Ok(())
1298 }
1299
1300 async fn debug_write_block_profile(&self, _file: String) -> RpcResult<()> {
1301 Ok(())
1302 }
1303
1304 async fn debug_write_mem_profile(&self, _file: String) -> RpcResult<()> {
1305 Ok(())
1306 }
1307
1308 async fn debug_write_mutex_profile(&self, _file: String) -> RpcResult<()> {
1309 Ok(())
1310 }
1311}
1312
1313impl<Eth> std::fmt::Debug for DebugApi<Eth> {
1314 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1315 f.debug_struct("DebugApi").finish_non_exhaustive()
1316 }
1317}
1318
1319impl<Eth> Clone for DebugApi<Eth> {
1320 fn clone(&self) -> Self {
1321 Self { inner: Arc::clone(&self.inner) }
1322 }
1323}
1324
1325struct DebugApiInner<Eth> {
1326 eth_api: Eth,
1328 blocking_task_guard: BlockingTaskGuard,
1330}