@@ -5,6 +5,7 @@ use reth_rpc_api::clients::DebugApiClient;
55use reth_rpc_types:: trace:: geth:: { GethDebugTracerType , GethDebugTracingOptions } ;
66
77const NOOP_TRACER : & str = include_str ! ( "../assets/noop-tracer.js" ) ;
8+ const JS_TRACER_TEMPLATE : & str = include_str ! ( "../assets/tracer-template.js" ) ;
89
910/// An extension trait for the Trace API.
1011#[ async_trait:: async_trait]
@@ -36,6 +37,106 @@ impl<T: DebugApiClient + Sync> DebugApiExt for T {
3637 }
3738}
3839
40+ /// A helper type that can be used to build a javascript tracer.
41+ #[ derive( Debug , Clone , Default ) ]
42+ pub struct JsTracerBuilder {
43+ setup_body : Option < String > ,
44+ fault_body : Option < String > ,
45+ result_body : Option < String > ,
46+ enter_body : Option < String > ,
47+ step_body : Option < String > ,
48+ exit_body : Option < String > ,
49+ }
50+
51+ impl JsTracerBuilder {
52+ /// Sets the body of the fault function
53+ ///
54+ /// The body code has access to the `log` and `db` variables.
55+ pub fn fault_body ( mut self , body : impl Into < String > ) -> Self {
56+ self . fault_body = Some ( body. into ( ) ) ;
57+ self
58+ }
59+
60+ /// Sets the body of the setup function
61+ ///
62+ /// This body includes the `cfg` object variable
63+ pub fn setup_body ( mut self , body : impl Into < String > ) -> Self {
64+ self . setup_body = Some ( body. into ( ) ) ;
65+ self
66+ }
67+
68+ /// Sets the body of the result function
69+ ///
70+ /// The body code has access to the `ctx` and `db` variables.
71+ ///
72+ /// ```
73+ /// use reth_rpc_api_testing_util::debug::JsTracerBuilder;
74+ /// let code = JsTracerBuilder::default().result_body("return {};").code();
75+ /// ```
76+ pub fn result_body ( mut self , body : impl Into < String > ) -> Self {
77+ self . result_body = Some ( body. into ( ) ) ;
78+ self
79+ }
80+
81+ /// Sets the body of the enter function
82+ ///
83+ /// The body code has access to the `frame` variable.
84+ pub fn enter_body ( mut self , body : impl Into < String > ) -> Self {
85+ self . enter_body = Some ( body. into ( ) ) ;
86+ self
87+ }
88+
89+ /// Sets the body of the step function
90+ ///
91+ /// The body code has access to the `log` and `db` variables.
92+ pub fn step_body ( mut self , body : impl Into < String > ) -> Self {
93+ self . step_body = Some ( body. into ( ) ) ;
94+ self
95+ }
96+
97+ /// Sets the body of the exit function
98+ ///
99+ /// The body code has access to the `res` variable.
100+ pub fn exit_body ( mut self , body : impl Into < String > ) -> Self {
101+ self . exit_body = Some ( body. into ( ) ) ;
102+ self
103+ }
104+
105+ /// Returns the tracers JS code
106+ pub fn code ( self ) -> String {
107+ let mut template = JS_TRACER_TEMPLATE . to_string ( ) ;
108+ template = template. replace ( "//<setup>" , self . setup_body . as_deref ( ) . unwrap_or_default ( ) ) ;
109+ template = template. replace ( "//<fault>" , self . fault_body . as_deref ( ) . unwrap_or_default ( ) ) ;
110+ template =
111+ template. replace ( "//<result>" , self . result_body . as_deref ( ) . unwrap_or ( "return {};" ) ) ;
112+ template = template. replace ( "//<step>" , self . step_body . as_deref ( ) . unwrap_or_default ( ) ) ;
113+ template = template. replace ( "//<enter>" , self . enter_body . as_deref ( ) . unwrap_or_default ( ) ) ;
114+ template = template. replace ( "//<exit>" , self . exit_body . as_deref ( ) . unwrap_or_default ( ) ) ;
115+ template
116+ }
117+ }
118+
119+ impl std:: fmt:: Display for JsTracerBuilder {
120+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
121+ write ! ( f, "{}" , self . clone( ) . code( ) )
122+ }
123+ }
124+
125+ impl From < JsTracerBuilder > for GethDebugTracingOptions {
126+ fn from ( b : JsTracerBuilder ) -> Self {
127+ GethDebugTracingOptions {
128+ tracer : Some ( GethDebugTracerType :: JsTracer ( b. code ( ) ) ) ,
129+ tracer_config : serde_json:: Value :: Object ( Default :: default ( ) ) . into ( ) ,
130+ ..Default :: default ( )
131+ }
132+ }
133+ }
134+ impl From < JsTracerBuilder > for Option < GethDebugTracingOptions > {
135+ fn from ( b : JsTracerBuilder ) -> Self {
136+ Some ( b. into ( ) )
137+ }
138+ }
139+
39140/// A javascript tracer that does nothing
40141#[ derive( Debug , Clone , Copy , Default ) ]
41142#[ non_exhaustive]
@@ -59,21 +160,35 @@ impl From<NoopJsTracer> for Option<GethDebugTracingOptions> {
59160#[ cfg( test) ]
60161mod tests {
61162 use crate :: {
62- debug:: { DebugApiExt , NoopJsTracer } ,
163+ debug:: { DebugApiExt , JsTracerBuilder , NoopJsTracer } ,
63164 utils:: parse_env_url,
64165 } ;
65166 use jsonrpsee:: http_client:: HttpClientBuilder ;
66167
168+ // random tx <https://sepolia.etherscan.io/tx/0x5525c63a805df2b83c113ebcc8c7672a3b290673c4e81335b410cd9ebc64e085>
169+ const TX_1 : & str = "0x5525c63a805df2b83c113ebcc8c7672a3b290673c4e81335b410cd9ebc64e085" ;
170+
67171 #[ tokio:: test]
68172 #[ ignore]
69173 async fn can_trace_noop_sepolia ( ) {
70- // random tx <https://sepolia.etherscan.io/tx/0x5525c63a805df2b83c113ebcc8c7672a3b290673c4e81335b410cd9ebc64e085>
71- let tx =
72- "0x5525c63a805df2b83c113ebcc8c7672a3b290673c4e81335b410cd9ebc64e085" . parse ( ) . unwrap ( ) ;
174+ let tx = TX_1 . parse ( ) . unwrap ( ) ;
73175 let url = parse_env_url ( "RETH_RPC_TEST_NODE_URL" ) . unwrap ( ) ;
74176 let client = HttpClientBuilder :: default ( ) . build ( url) . unwrap ( ) ;
75177 let res =
76178 client. debug_trace_transaction_json ( tx, NoopJsTracer :: default ( ) . into ( ) ) . await . unwrap ( ) ;
77179 assert_eq ! ( res, serde_json:: Value :: Object ( Default :: default ( ) ) ) ;
78180 }
181+
182+ #[ tokio:: test]
183+ #[ ignore]
184+ async fn can_trace_default_template ( ) {
185+ let tx = TX_1 . parse ( ) . unwrap ( ) ;
186+ let url = parse_env_url ( "RETH_RPC_TEST_NODE_URL" ) . unwrap ( ) ;
187+ let client = HttpClientBuilder :: default ( ) . build ( url) . unwrap ( ) ;
188+ let res = client
189+ . debug_trace_transaction_json ( tx, JsTracerBuilder :: default ( ) . into ( ) )
190+ . await
191+ . unwrap ( ) ;
192+ assert_eq ! ( res, serde_json:: Value :: Object ( Default :: default ( ) ) ) ;
193+ }
79194}
0 commit comments