Skip to content

Commit e5521b0

Browse files
committed
feat: both endpoints
1 parent 11bba29 commit e5521b0

File tree

3 files changed

+113
-46
lines changed

3 files changed

+113
-46
lines changed

crates/rpc/src/debug/endpoints.rs

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,86 @@ use crate::{
33
utils::{await_handler, response_tri},
44
};
55
use ajj::{HandlerCtx, ResponsePayload};
6-
use alloy::{consensus::BlockHeader, primitives::B256};
6+
use alloy::{consensus::BlockHeader, eips::BlockId, primitives::B256};
77
use itertools::Itertools;
88
use reth::rpc::{
99
server_types::eth::EthApiError,
1010
types::{
1111
TransactionInfo,
12-
trace::geth::{GethDebugTracingOptions, GethTrace},
12+
trace::geth::{GethDebugTracingOptions, GethTrace, TraceResult},
1313
},
1414
};
1515
use reth_node_api::FullNodeComponents;
1616
use signet_evm::EvmErrored;
1717
use signet_node_types::Pnt;
1818
use signet_types::MagicSig;
1919

20-
// /// Params for the `debug_traceBlockByNumber` and `debug_traceBlockByHash`
21-
// /// endpoints.
22-
// #[derive(Debug, serde::Deserialize)]
23-
// pub(super) struct TraceBlockParams<T>(T, #[serde(default)] Option<GethDebugTracingOptions>);
24-
25-
// /// `debug_traceBlockByNumber` and `debug_traceBlockByHash` endpoint handler.
26-
// pub(super) async fn trace_block<T, Host, Signet>(
27-
// hctx: HandlerCtx,
28-
// TraceBlockParams(id, opts): TraceBlockParams<T>,
29-
// ctx: RpcCtx<Host, Signet>,
30-
// ) -> ResponsePayload<Vec<TraceResult>, TraceError>
31-
// where
32-
// T: Into<BlockId>,
33-
// Host: FullNodeComponents,
34-
// Signet: Pnt,
35-
// {
36-
// let id = id.into();
37-
38-
// let fut = async move {
39-
// // Fetch the block by ID
40-
// let Some((hash, block)) = response_tri!(ctx.signet().raw_block(id).await) else {
41-
// return ResponsePayload::internal_error_message(
42-
// EthApiError::HeaderNotFound(id).to_string().into(),
43-
// );
44-
// };
45-
// // Instantiate the EVM with the block
46-
// let evm = response_tri!(ctx.trevm(id, block.header()));
47-
48-
// todo!()
49-
50-
// // ResponsePayload::Success(vec![])
51-
// };
52-
53-
// await_jh_option_response!(hctx.spawn_blocking(fut))
54-
// }
20+
/// Params for the `debug_traceBlockByNumber` and `debug_traceBlockByHash`
21+
/// endpoints.
22+
#[derive(Debug, serde::Deserialize)]
23+
pub(super) struct TraceBlockParams<T>(T, #[serde(default)] Option<GethDebugTracingOptions>);
24+
25+
/// Params type for `debug_traceTransaction`.`
26+
#[derive(Debug, serde::Deserialize)]
27+
pub(super) struct TraceTransactionParams(B256, #[serde(default)] Option<GethDebugTracingOptions>);
28+
29+
/// `debug_traceBlockByNumber` and `debug_traceBlockByHash` endpoint handler.
30+
pub(super) async fn trace_block<T, Host, Signet>(
31+
hctx: HandlerCtx,
32+
TraceBlockParams(id, opts): TraceBlockParams<T>,
33+
ctx: RpcCtx<Host, Signet>,
34+
) -> ResponsePayload<Vec<TraceResult>, DebugError>
35+
where
36+
T: Into<BlockId>,
37+
Host: FullNodeComponents,
38+
Signet: Pnt,
39+
{
40+
let id = id.into();
41+
let fut = async move {
42+
// Fetch the block by ID
43+
let Some((hash, block)) = response_tri!(ctx.signet().raw_block(id).await) else {
44+
return ResponsePayload::internal_error_message(
45+
EthApiError::HeaderNotFound(id).to_string().into(),
46+
);
47+
};
48+
49+
// Allocate space for the frames
50+
let mut frames = Vec::with_capacity(block.transaction_count());
51+
// Instantiate the EVM with the block
52+
let mut trevm = response_tri!(ctx.trevm(crate::LoadState::Before, block.header()));
53+
54+
// Apply all transactions in the block up, tracing each one
55+
let opts = opts.unwrap_or_default();
56+
let mut txns = block.body().transactions().enumerate().peekable();
57+
for (idx, tx) in txns
58+
.by_ref()
59+
.peeking_take_while(|(_, t)| MagicSig::try_from_signature(t.signature()).is_none())
60+
{
61+
let tx_info = TransactionInfo {
62+
hash: Some(*tx.hash()),
63+
index: Some(idx as u64),
64+
block_hash: Some(hash),
65+
block_number: Some(block.header().number()),
66+
base_fee: block.header().base_fee_per_gas(),
67+
};
68+
69+
let t = trevm.fill_tx(tx);
70+
71+
let frame;
72+
(frame, trevm) = response_tri!(crate::debug::tracer::trace(t, &opts, tx_info));
73+
frames.push(TraceResult::Success { result: frame, tx_hash: Some(*tx.hash()) });
74+
}
75+
76+
ResponsePayload::Success(frames)
77+
};
78+
79+
await_handler!(@response_option hctx.spawn_blocking(fut))
80+
}
5581

5682
/// Handle for `debug_traceTransaction`.
5783
pub(super) async fn trace_transaction<Host, Signet>(
5884
hctx: HandlerCtx,
59-
(tx_hash, opts): (B256, Option<GethDebugTracingOptions>),
85+
TraceTransactionParams(tx_hash, opts): TraceTransactionParams,
6086
ctx: RpcCtx<Host, Signet>,
6187
) -> ResponsePayload<GethTrace, DebugError>
6288
where
@@ -82,7 +108,6 @@ where
82108

83109
// Apply all transactions in the block up to (but not including) the
84110
// target one
85-
// TODO: check if the tx signature is a magic sig, and abort if so.
86111
let mut txns = block.body().transactions().enumerate().peekable();
87112
for (_idx, tx) in txns.by_ref().peeking_take_while(|(_, t)| t.hash() != tx.hash()) {
88113
if MagicSig::try_from_signature(tx.signature()).is_some() {

crates/rpc/src/debug/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ where
1818
Signet: Pnt,
1919
{
2020
ajj::Router::new()
21-
// .route("traceBlockByNumber", trace_block::<U64, _, _>)
22-
// .route("traceBlockByHash", trace_block::<B256, _, _>)
21+
.route("traceBlockByNumber", trace_block::<U64, _, _>)
22+
.route("traceBlockByHash", trace_block::<B256, _, _>)
2323
.route("traceTransaction", trace_transaction)
2424
}

crates/rpc/src/debug/tracer.rs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
//! This file is largely adapted from reth: `crates/rpc/rpc/src/debug.rs`
2+
//!
3+
//! In particular the `debug_trace_call` function.
4+
15
use crate::DebugError;
26
use reth::{
37
revm::{DatabaseRef, context::ContextTr},
@@ -7,18 +11,21 @@ use reth::{
711
TransactionInfo,
812
trace::geth::{
913
FourByteFrame, GethDebugBuiltInTracerType, GethDebugTracerConfig,
10-
GethDebugTracerType, GethDebugTracingOptions, GethTrace,
14+
GethDebugTracerType, GethDebugTracingOptions, GethTrace, NoopFrame,
1115
},
1216
},
1317
},
1418
};
15-
use revm_inspectors::tracing::{FourByteInspector, TracingInspector, TracingInspectorConfig};
19+
use revm_inspectors::tracing::{
20+
FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig,
21+
};
1622
use signet_evm::{EvmNeedsTx, EvmReady};
1723
use trevm::{
1824
helpers::Ctx,
1925
revm::{Database, DatabaseCommit, Inspector},
2026
};
2127

28+
/// Trace a transaction using the provided EVM and tracing options.
2229
pub(super) fn trace<Db, Insp>(
2330
trevm: EvmReady<Db, Insp>,
2431
config: &GethDebugTracingOptions,
@@ -28,7 +35,7 @@ where
2835
Db: Database + DatabaseCommit + DatabaseRef,
2936
Insp: Inspector<Ctx<Db>>,
3037
{
31-
let Some(tracer) = &config.tracer else { todo!() };
38+
let Some(tracer) = &config.tracer else { return Err(EthApiError::InvalidTracerConfig.into()) };
3239

3340
let GethDebugTracerType::BuiltInTracer(built_in) = tracer else {
3441
return Err(EthApiError::Unsupported("JS tracer").into());
@@ -46,13 +53,15 @@ where
4653
trace_pre_state(&config.tracer_config, trevm).map_err(Into::into)
4754
}
4855
GethDebugBuiltInTracerType::NoopTracer => Ok((
49-
Default::default(),
56+
NoopFrame::default().into(),
5057
trevm
5158
.run()
5259
.map_err(|err| EthApiError::EvmCustom(err.into_error().to_string()))?
5360
.accept_state(),
5461
)),
55-
GethDebugBuiltInTracerType::MuxTracer => todo!(),
62+
GethDebugBuiltInTracerType::MuxTracer => {
63+
trace_mux(&config.tracer_config, trevm, tx_info).map_err(Into::into)
64+
}
5665
}
5766
}
5867

@@ -168,6 +177,39 @@ where
168177
Ok((frame.into(), trevm.accept_state()))
169178
}
170179

180+
fn trace_mux<Db, Insp>(
181+
tracer_config: &GethDebugTracerConfig,
182+
trevm: EvmReady<Db, Insp>,
183+
tx_info: TransactionInfo,
184+
) -> Result<(GethTrace, EvmNeedsTx<Db, Insp>), EthApiError>
185+
where
186+
Db: Database + DatabaseCommit + DatabaseRef,
187+
Insp: Inspector<Ctx<Db>>,
188+
{
189+
let mux_config =
190+
tracer_config.clone().into_mux_config().map_err(|_| EthApiError::InvalidTracerConfig)?;
191+
192+
let mut inspector = MuxInspector::try_from_config(mux_config)
193+
.map_err(|err| EthApiError::EvmCustom(err.to_string()))?;
194+
195+
let trevm = trevm.try_with_inspector(&mut inspector, |trevm| trevm.run());
196+
let trevm = trevm.map_err(|e| EthApiError::EvmCustom(e.into_error().to_string()))?;
197+
198+
// NB: Normally we would call `trevm.accept_state()` here, but we need the
199+
// state after execution to be UNCOMMITED when we compute the prestate
200+
// diffs.
201+
let (result, mut trevm) = trevm.take_result_and_state();
202+
203+
let frame = inspector
204+
.try_into_mux_frame(&result, trevm.inner_mut_unchecked().db_mut(), tx_info)
205+
.map_err(|err| EthApiError::EvmCustom(err.to_string()))?;
206+
207+
// This is equivalent to calling `trevm.accept_state()`.
208+
trevm.inner_mut_unchecked().db_mut().commit(result.state);
209+
210+
Ok((frame.into(), trevm))
211+
}
212+
171213
// Some code in this file has been copied and modified from reth
172214
// <https://github.com/paradigmxyz/reth>
173215
// The original license is included below:

0 commit comments

Comments
 (0)