@@ -5,6 +5,7 @@ use reth_rpc_api::clients::DebugApiClient;
5
5
use reth_rpc_types:: trace:: geth:: { GethDebugTracerType , GethDebugTracingOptions } ;
6
6
7
7
const NOOP_TRACER : & str = include_str ! ( "../assets/noop-tracer.js" ) ;
8
+ const JS_TRACER_TEMPLATE : & str = include_str ! ( "../assets/tracer-template.js" ) ;
8
9
9
10
/// An extension trait for the Trace API.
10
11
#[ async_trait:: async_trait]
@@ -36,6 +37,106 @@ impl<T: DebugApiClient + Sync> DebugApiExt for T {
36
37
}
37
38
}
38
39
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
+
39
140
/// A javascript tracer that does nothing
40
141
#[ derive( Debug , Clone , Copy , Default ) ]
41
142
#[ non_exhaustive]
@@ -59,21 +160,35 @@ impl From<NoopJsTracer> for Option<GethDebugTracingOptions> {
59
160
#[ cfg( test) ]
60
161
mod tests {
61
162
use crate :: {
62
- debug:: { DebugApiExt , NoopJsTracer } ,
163
+ debug:: { DebugApiExt , JsTracerBuilder , NoopJsTracer } ,
63
164
utils:: parse_env_url,
64
165
} ;
65
166
use jsonrpsee:: http_client:: HttpClientBuilder ;
66
167
168
+ // random tx <https://sepolia.etherscan.io/tx/0x5525c63a805df2b83c113ebcc8c7672a3b290673c4e81335b410cd9ebc64e085>
169
+ const TX_1 : & str = "0x5525c63a805df2b83c113ebcc8c7672a3b290673c4e81335b410cd9ebc64e085" ;
170
+
67
171
#[ tokio:: test]
68
172
#[ ignore]
69
173
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 ( ) ;
73
175
let url = parse_env_url ( "RETH_RPC_TEST_NODE_URL" ) . unwrap ( ) ;
74
176
let client = HttpClientBuilder :: default ( ) . build ( url) . unwrap ( ) ;
75
177
let res =
76
178
client. debug_trace_transaction_json ( tx, NoopJsTracer :: default ( ) . into ( ) ) . await . unwrap ( ) ;
77
179
assert_eq ! ( res, serde_json:: Value :: Object ( Default :: default ( ) ) ) ;
78
180
}
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
+ }
79
194
}
0 commit comments