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 {
273 tracing_options, state_overrides, block_overrides, ..
274 } = opts;
275 let overrides = EvmOverrides::new(state_overrides, block_overrides.map(Box::new));
276 let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options;
277
278 let this = self.clone();
279 if let Some(tracer) = tracer {
280 #[allow(unreachable_patterns)]
281 return match tracer {
282 GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
283 GethDebugBuiltInTracerType::FourByteTracer => {
284 let mut inspector = FourByteInspector::default();
285 let inspector = self
286 .eth_api()
287 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
288 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
289 Ok(inspector)
290 })
291 .await?;
292 Ok(FourByteFrame::from(&inspector).into())
293 }
294 GethDebugBuiltInTracerType::CallTracer => {
295 let call_config = tracer_config
296 .into_call_config()
297 .map_err(|_| EthApiError::InvalidTracerConfig)?;
298
299 let mut inspector = TracingInspector::new(
300 TracingInspectorConfig::from_geth_call_config(&call_config),
301 );
302
303 let frame = self
304 .eth_api()
305 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
306 let gas_limit = tx_env.gas_limit();
307 let res =
308 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
309 let frame = inspector
310 .with_transaction_gas_limit(gas_limit)
311 .into_geth_builder()
312 .geth_call_traces(call_config, res.result.gas_used());
313 Ok(frame.into())
314 })
315 .await?;
316 Ok(frame)
317 }
318 GethDebugBuiltInTracerType::PreStateTracer => {
319 let prestate_config = tracer_config
320 .into_pre_state_config()
321 .map_err(|_| EthApiError::InvalidTracerConfig)?;
322 let mut inspector = TracingInspector::new(
323 TracingInspectorConfig::from_geth_prestate_config(&prestate_config),
324 );
325
326 let frame = self
327 .eth_api()
328 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
329 let db = db.0;
332
333 let gas_limit = tx_env.gas_limit();
334 let res = this.eth_api().inspect(
335 &mut *db,
336 evm_env,
337 tx_env,
338 &mut inspector,
339 )?;
340 let frame = inspector
341 .with_transaction_gas_limit(gas_limit)
342 .into_geth_builder()
343 .geth_prestate_traces(&res, &prestate_config, db)
344 .map_err(Eth::Error::from_eth_err)?;
345 Ok(frame)
346 })
347 .await?;
348 Ok(frame.into())
349 }
350 GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()),
351 GethDebugBuiltInTracerType::MuxTracer => {
352 let mux_config = tracer_config
353 .into_mux_config()
354 .map_err(|_| EthApiError::InvalidTracerConfig)?;
355
356 let mut inspector = MuxInspector::try_from_config(mux_config)
357 .map_err(Eth::Error::from_eth_err)?;
358
359 let frame = self
360 .inner
361 .eth_api
362 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
363 let db = db.0;
366
367 let tx_info = TransactionInfo {
368 block_number: Some(evm_env.block_env.number.saturating_to()),
369 base_fee: Some(evm_env.block_env.basefee),
370 hash: None,
371 block_hash: None,
372 index: None,
373 };
374
375 let res = this.eth_api().inspect(
376 &mut *db,
377 evm_env,
378 tx_env,
379 &mut inspector,
380 )?;
381 let frame = inspector
382 .try_into_mux_frame(&res, db, tx_info)
383 .map_err(Eth::Error::from_eth_err)?;
384 Ok(frame.into())
385 })
386 .await?;
387 Ok(frame)
388 }
389 GethDebugBuiltInTracerType::FlatCallTracer => {
390 let flat_call_config = tracer_config
391 .into_flat_call_config()
392 .map_err(|_| EthApiError::InvalidTracerConfig)?;
393
394 let mut inspector = TracingInspector::new(
395 TracingInspectorConfig::from_flat_call_config(&flat_call_config),
396 );
397
398 let frame: FlatCallFrame = self
399 .inner
400 .eth_api
401 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
402 let gas_limit = tx_env.gas_limit();
403 this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
404 let tx_info = TransactionInfo::default();
405 let frame: FlatCallFrame = inspector
406 .with_transaction_gas_limit(gas_limit)
407 .into_parity_builder()
408 .into_localized_transaction_traces(tx_info);
409 Ok(frame)
410 })
411 .await?;
412
413 Ok(frame.into())
414 }
415 },
416 #[cfg(not(feature = "js-tracer"))]
417 GethDebugTracerType::JsTracer(_) => {
418 Err(EthApiError::Unsupported("JS Tracer is not enabled").into())
419 }
420 #[cfg(feature = "js-tracer")]
421 GethDebugTracerType::JsTracer(code) => {
422 let config = tracer_config.into_json();
423
424 let (_, at) = self.eth_api().evm_env_at(at).await?;
425
426 let res = self
427 .eth_api()
428 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
429 let db = db.0;
432
433 let mut inspector =
434 revm_inspectors::tracing::js::JsInspector::new(code, config)
435 .map_err(Eth::Error::from_eth_err)?;
436 let res = this.eth_api().inspect(
437 &mut *db,
438 evm_env.clone(),
439 tx_env.clone(),
440 &mut inspector,
441 )?;
442 inspector
443 .json_result(res, &tx_env, &evm_env.block_env, db)
444 .map_err(Eth::Error::from_eth_err)
445 })
446 .await?;
447
448 Ok(GethTrace::JS(res))
449 }
450 _ => {
451 Err(EthApiError::Unsupported("unsupported tracer").into())
454 }
455 }
456 }
457
458 let inspector_config = TracingInspectorConfig::from_geth_config(&config);
460
461 let mut inspector = TracingInspector::new(inspector_config);
462
463 let (res, tx_gas_limit, inspector) = self
464 .eth_api()
465 .spawn_with_call_at(call, at, overrides, move |db, evm_env, tx_env| {
466 let gas_limit = tx_env.gas_limit();
467 let res = this.eth_api().inspect(db, evm_env, tx_env, &mut inspector)?;
468 Ok((res, gas_limit, inspector))
469 })
470 .await?;
471 let gas_used = res.result.gas_used();
472 let return_value = res.result.into_output().unwrap_or_default();
473 let frame = inspector
474 .with_transaction_gas_limit(tx_gas_limit)
475 .into_geth_builder()
476 .geth_traces(gas_used, return_value, config);
477
478 Ok(frame.into())
479 }
480
481 pub async fn debug_trace_call_many(
485 &self,
486 bundles: Vec<Bundle<RpcTxReq<Eth::NetworkTypes>>>,
487 state_context: Option<StateContext>,
488 opts: Option<GethDebugTracingCallOptions>,
489 ) -> Result<Vec<Vec<GethTrace>>, Eth::Error> {
490 if bundles.is_empty() {
491 return Err(EthApiError::InvalidParams(String::from("bundles are empty.")).into())
492 }
493
494 let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
495 let transaction_index = transaction_index.unwrap_or_default();
496
497 let target_block = block_number.unwrap_or_default();
498 let ((mut evm_env, _), block) = futures::try_join!(
499 self.eth_api().evm_env_at(target_block),
500 self.eth_api().recovered_block(target_block),
501 )?;
502
503 let opts = opts.unwrap_or_default();
504 let block = block.ok_or(EthApiError::HeaderNotFound(target_block))?;
505 let GethDebugTracingCallOptions { tracing_options, mut state_overrides, .. } = opts;
506
507 let mut at = block.parent_hash();
510 let mut replay_block_txs = true;
511
512 let num_txs =
514 transaction_index.index().unwrap_or_else(|| block.body().transactions().len());
515 if !target_block.is_pending() && num_txs == block.body().transactions().len() {
519 at = block.hash();
520 replay_block_txs = false;
521 }
522
523 let this = self.clone();
524
525 self.eth_api()
526 .spawn_with_state_at_block(at.into(), move |state| {
527 let mut all_bundles = Vec::with_capacity(bundles.len());
529 let mut db = CacheDB::new(StateProviderDatabase::new(state));
530
531 if replay_block_txs {
532 let transactions = block.transactions_recovered().take(num_txs);
535
536 for tx in transactions {
538 let tx_env = this.eth_api().evm_config().tx_env(tx);
539 let res = this.eth_api().transact(&mut db, evm_env.clone(), tx_env)?;
540 db.commit(res.state);
541 }
542 }
543
544 let mut bundles = bundles.into_iter().peekable();
546 while let Some(bundle) = bundles.next() {
547 let mut results = Vec::with_capacity(bundle.transactions.len());
548 let Bundle { transactions, block_override } = bundle;
549
550 let block_overrides = block_override.map(Box::new);
551 let mut inspector = None;
552
553 let mut transactions = transactions.into_iter().peekable();
554 while let Some(tx) = transactions.next() {
555 let state_overrides = state_overrides.take();
557 let overrides = EvmOverrides::new(state_overrides, block_overrides.clone());
558
559 let (evm_env, tx_env) = this.eth_api().prepare_call_env(
560 evm_env.clone(),
561 tx,
562 &mut db,
563 overrides,
564 )?;
565
566 let (trace, state) = this.trace_transaction(
567 &tracing_options,
568 evm_env,
569 tx_env,
570 &mut db,
571 None,
572 &mut inspector,
573 )?;
574
575 inspector = inspector.map(|insp| insp.fused());
576
577 if transactions.peek().is_some() || bundles.peek().is_some() {
580 db.commit(state);
581 }
582 results.push(trace);
583 }
584 evm_env.block_env.number += uint!(1_U256);
586 evm_env.block_env.timestamp += uint!(12_U256);
587
588 all_bundles.push(results);
589 }
590 Ok(all_bundles)
591 })
592 .await
593 }
594
595 pub async fn debug_execution_witness_by_block_hash(
598 &self,
599 hash: B256,
600 ) -> Result<ExecutionWitness, Eth::Error> {
601 let this = self.clone();
602 let block = this
603 .eth_api()
604 .recovered_block(hash.into())
605 .await?
606 .ok_or(EthApiError::HeaderNotFound(hash.into()))?;
607
608 self.debug_execution_witness_for_block(block).await
609 }
610
611 pub async fn debug_execution_witness(
616 &self,
617 block_id: BlockNumberOrTag,
618 ) -> Result<ExecutionWitness, Eth::Error> {
619 let this = self.clone();
620 let block = this
621 .eth_api()
622 .recovered_block(block_id.into())
623 .await?
624 .ok_or(EthApiError::HeaderNotFound(block_id.into()))?;
625
626 self.debug_execution_witness_for_block(block).await
627 }
628
629 pub async fn debug_execution_witness_for_block(
631 &self,
632 block: Arc<RecoveredBlock<ProviderBlock<Eth::Provider>>>,
633 ) -> Result<ExecutionWitness, Eth::Error> {
634 let this = self.clone();
635 let block_number = block.header().number();
636
637 let (mut exec_witness, lowest_block_number) = self
638 .eth_api()
639 .spawn_with_state_at_block(block.parent_hash().into(), move |state_provider| {
640 let db = StateProviderDatabase::new(&state_provider);
641 let block_executor = this.eth_api().evm_config().executor(db);
642
643 let mut witness_record = ExecutionWitnessRecord::default();
644
645 let _ = block_executor
646 .execute_with_state_closure(&block, |statedb: &State<_>| {
647 witness_record.record_executed_state(statedb);
648 })
649 .map_err(|err| EthApiError::Internal(err.into()))?;
650
651 let ExecutionWitnessRecord { hashed_state, codes, keys, lowest_block_number } =
652 witness_record;
653
654 let state = state_provider
655 .witness(Default::default(), hashed_state)
656 .map_err(EthApiError::from)?;
657 Ok((
658 ExecutionWitness { state, codes, keys, ..Default::default() },
659 lowest_block_number,
660 ))
661 })
662 .await?;
663
664 let smallest = match lowest_block_number {
665 Some(smallest) => smallest,
666 None => {
667 block_number.saturating_sub(1)
670 }
671 };
672
673 let range = smallest..block_number;
674 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}