1use alloy_primitives::B256;
9use alloy_rpc_types_trace::geth::{GethDebugTracerType, GethDebugTracingOptions, GethTrace};
10use jsonrpsee::{core::RpcResult, proc_macros::rpc};
11
12use crate::stylus_tracer::take_cached_trace;
13
14pub const STYLUS_TRACER_NAME: &str = "stylusTracer";
15
16#[rpc(server, namespace = "debug")]
18pub trait StylusDebug {
19 #[method(name = "traceTransaction")]
20 async fn trace_transaction(
21 &self,
22 tx_hash: B256,
23 opts: Option<GethDebugTracingOptions>,
24 ) -> RpcResult<GethTrace>;
25}
26
27pub type DebugForwarder = std::sync::Arc<
29 dyn Fn(
30 B256,
31 Option<GethDebugTracingOptions>,
32 )
33 -> std::pin::Pin<Box<dyn std::future::Future<Output = RpcResult<GethTrace>> + Send>>
34 + Send
35 + Sync,
36>;
37
38pub struct StylusDebugHandler {
39 forwarder: DebugForwarder,
40}
41
42impl std::fmt::Debug for StylusDebugHandler {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 f.debug_struct("StylusDebugHandler").finish()
45 }
46}
47
48impl StylusDebugHandler {
49 pub fn new(forwarder: DebugForwarder) -> Self {
50 Self { forwarder }
51 }
52}
53
54#[async_trait::async_trait]
55impl StylusDebugServer for StylusDebugHandler {
56 async fn trace_transaction(
57 &self,
58 tx_hash: B256,
59 opts: Option<GethDebugTracingOptions>,
60 ) -> RpcResult<GethTrace> {
61 if let Some(ref o) = opts {
62 if let Some(GethDebugTracerType::JsTracer(name)) = &o.tracer {
63 if name == STYLUS_TRACER_NAME {
64 let records = take_cached_trace(tx_hash);
65 let value = serde_json::to_value(&records).unwrap_or_default();
66 return Ok(GethTrace::JS(value));
67 }
68 }
69 }
70 (self.forwarder)(tx_hash, opts).await
71 }
72}