reth_rpc/
debug.rs

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