1use crate::{
2 api::Namespace,
3 helpers::{self, CallFuture},
4 types::{BlockId, BlockNumber, BlockTrace, Bytes, CallRequest, Index, Trace, TraceFilter, TraceType, H256},
5 Transport,
6};
7
8#[derive(Debug, Clone)]
10pub struct Traces<T> {
11 transport: T,
12}
13
14impl<T: Transport> Namespace<T> for Traces<T> {
15 fn new(transport: T) -> Self
16 where
17 Self: Sized,
18 {
19 Traces { transport }
20 }
21
22 fn transport(&self) -> &T {
23 &self.transport
24 }
25}
26
27impl<T: Transport> Traces<T> {
28 pub fn call(
30 &self,
31 req: CallRequest,
32 trace_type: Vec<TraceType>,
33 block: Option<BlockNumber>,
34 ) -> CallFuture<BlockTrace, T::Out> {
35 let req = helpers::serialize(&req);
36 let block = helpers::serialize(&block.unwrap_or(BlockNumber::Latest));
37 let trace_type = helpers::serialize(&trace_type);
38 CallFuture::new(self.transport.execute("trace_call", vec![req, trace_type, block]))
39 }
40
41 pub fn call_many(
43 &self,
44 reqs_with_trace_types: Vec<(CallRequest, Vec<TraceType>)>,
45 block: Option<BlockId>,
46 ) -> CallFuture<Vec<BlockTrace>, T::Out> {
47 let reqs_with_trace_types = helpers::serialize(&reqs_with_trace_types);
48 let block = helpers::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into()));
49 CallFuture::new(
50 self.transport
51 .execute("trace_callMany", vec![reqs_with_trace_types, block]),
52 )
53 }
54
55 pub fn raw_transaction(&self, data: Bytes, trace_type: Vec<TraceType>) -> CallFuture<BlockTrace, T::Out> {
57 let data = helpers::serialize(&data);
58 let trace_type = helpers::serialize(&trace_type);
59 CallFuture::new(self.transport.execute("trace_rawTransaction", vec![data, trace_type]))
60 }
61
62 pub fn replay_transaction(&self, hash: H256, trace_type: Vec<TraceType>) -> CallFuture<BlockTrace, T::Out> {
64 let hash = helpers::serialize(&hash);
65 let trace_type = helpers::serialize(&trace_type);
66 CallFuture::new(
67 self.transport
68 .execute("trace_replayTransaction", vec![hash, trace_type]),
69 )
70 }
71
72 pub fn replay_block_transactions(
74 &self,
75 block: BlockNumber,
76 trace_type: Vec<TraceType>,
77 ) -> CallFuture<Vec<BlockTrace>, T::Out> {
78 let block = helpers::serialize(&block);
79 let trace_type = helpers::serialize(&trace_type);
80 CallFuture::new(
81 self.transport
82 .execute("trace_replayBlockTransactions", vec![block, trace_type]),
83 )
84 }
85
86 pub fn block(&self, block: BlockNumber) -> CallFuture<Vec<Trace>, T::Out> {
88 let block = helpers::serialize(&block);
89 CallFuture::new(self.transport.execute("trace_block", vec![block]))
90 }
91
92 pub fn filter(&self, filter: TraceFilter) -> CallFuture<Vec<Trace>, T::Out> {
96 let filter = helpers::serialize(&filter);
97 CallFuture::new(self.transport.execute("trace_filter", vec![filter]))
98 }
99
100 pub fn get(&self, hash: H256, index: Vec<Index>) -> CallFuture<Trace, T::Out> {
102 let hash = helpers::serialize(&hash);
103 let index = helpers::serialize(&index);
104 CallFuture::new(self.transport.execute("trace_get", vec![hash, index]))
105 }
106
107 pub fn transaction(&self, hash: H256) -> CallFuture<Vec<Trace>, T::Out> {
109 let hash = helpers::serialize(&hash);
110 CallFuture::new(self.transport.execute("trace_transaction", vec![hash]))
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::Traces;
117 use crate::{
118 api::Namespace,
119 types::{Address, BlockNumber, BlockTrace, CallRequest, Trace, TraceFilterBuilder, TraceType, H256},
120 };
121 use hex_literal::hex;
122
123 const EXAMPLE_BLOCKTRACE: &str = r#"
124 {
125 "output": "0x010203",
126 "stateDiff": null,
127 "trace": [
128 {
129 "action": {
130 "callType": "call",
131 "from": "0x0000000000000000000000000000000000000000",
132 "gas": "0x1dcd12f8",
133 "input": "0x",
134 "to": "0x0000000000000000000000000000000000000123",
135 "value": "0x1"
136 },
137 "result": {
138 "gasUsed": "0x0",
139 "output": "0x"
140 },
141 "subtraces": 0,
142 "traceAddress": [],
143 "type": "call"
144 }
145 ],
146 "vmTrace": null
147 }
148 "#;
149
150 const EXAMPLE_BLOCKTRACES: &str = r#"
151 [{
152 "output": "0x",
153 "stateDiff": null,
154 "trace": [
155 {
156 "action": {
157 "callType": "call",
158 "from": "0xa1e4380a3b1f749673e270229993ee55f35663b4",
159 "gas": "0x0",
160 "input": "0x",
161 "to": "0x5df9b87991262f6ba471f09758cde1c0fc1de734",
162 "value": "0x7a69"
163 },
164 "result": {
165 "gasUsed": "0x0",
166 "output": "0x"
167 },
168 "subtraces": 0,
169 "traceAddress": [],
170 "type": "call"
171 }
172 ],
173 "transactionHash": "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
174 "vmTrace": null
175 }]
176 "#;
177
178 const EXAMPLE_TRACE_ARR: &str = r#"
179 [
180 {
181 "action": {
182 "callType": "call",
183 "from": "0xaa7b131dc60b80d3cf5e59b5a21a666aa039c951",
184 "gas": "0x0",
185 "input": "0x",
186 "to": "0xd40aba8166a212d6892125f079c33e6f5ca19814",
187 "value": "0x4768d7effc3fbe"
188 },
189 "blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add",
190 "blockNumber": 3068185,
191 "result": {
192 "gasUsed": "0x0",
193 "output": "0x"
194 },
195 "subtraces": 0,
196 "traceAddress": [],
197 "transactionHash": "0x07da28d752aba3b9dd7060005e554719c6205c8a3aea358599fc9b245c52f1f6",
198 "transactionPosition": 0,
199 "type": "call"
200 }
201 ]
202 "#;
203
204 const EXAMPLE_TRACE: &str = r#"
205 {
206 "action": {
207 "callType": "call",
208 "from": "0xaa7b131dc60b80d3cf5e59b5a21a666aa039c951",
209 "gas": "0x0",
210 "input": "0x",
211 "to": "0xd40aba8166a212d6892125f079c33e6f5ca19814",
212 "value": "0x4768d7effc3fbe"
213 },
214 "blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add",
215 "blockNumber": 3068185,
216 "result": {
217 "gasUsed": "0x0",
218 "output": "0x"
219 },
220 "subtraces": 0,
221 "traceAddress": [],
222 "transactionHash": "0x07da28d752aba3b9dd7060005e554719c6205c8a3aea358599fc9b245c52f1f6",
223 "transactionPosition": 0,
224 "type": "call"
225 }
226 "#;
227
228 rpc_test!(
229 Traces:call, CallRequest {
230 from: None, to: Some(Address::from_low_u64_be(0x123)),
231 gas: None, gas_price: None,
232 value: Some(0x1.into()), data: None,
233 transaction_type: None, access_list: None,
234 max_fee_per_gas: None, max_priority_fee_per_gas: None,
235 }, vec![TraceType::Trace], None
236 =>
237 "trace_call", vec![r#"{"to":"0x0000000000000000000000000000000000000123","value":"0x1"}"#, r#"["trace"]"#, r#""latest""#];
238 ::serde_json::from_str(EXAMPLE_BLOCKTRACE).unwrap()
239 => ::serde_json::from_str::<BlockTrace>(EXAMPLE_BLOCKTRACE).unwrap()
240 );
241
242 rpc_test!(
243 Traces:raw_transaction, hex!("01020304"), vec![TraceType::Trace]
244 =>
245 "trace_rawTransaction", vec![r#""0x01020304""#, r#"["trace"]"#];
246 ::serde_json::from_str(EXAMPLE_BLOCKTRACE).unwrap()
247 => ::serde_json::from_str::<BlockTrace>(EXAMPLE_BLOCKTRACE).unwrap()
248 );
249
250 rpc_test!(
251 Traces:replay_transaction, "0000000000000000000000000000000000000000000000000000000000000123".parse::<H256>().unwrap(), vec![TraceType::Trace]
252 =>
253 "trace_replayTransaction", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#,r#"["trace"]"#];
254 ::serde_json::from_str(EXAMPLE_BLOCKTRACE).unwrap()
255 => ::serde_json::from_str::<BlockTrace>(EXAMPLE_BLOCKTRACE).unwrap()
256 );
257
258 rpc_test!(
259 Traces:replay_block_transactions, BlockNumber::Latest, vec![TraceType::Trace]
260 =>
261 "trace_replayBlockTransactions", vec![r#""latest""#, r#"["trace"]"#];
262 ::serde_json::from_str(EXAMPLE_BLOCKTRACES).unwrap()
263 => ::serde_json::from_str::<Vec<BlockTrace>>(EXAMPLE_BLOCKTRACES).unwrap()
264 );
265
266 rpc_test!(
267 Traces:block, BlockNumber::Latest
268 =>
269 "trace_block", vec![r#""latest""#];
270 ::serde_json::from_str(EXAMPLE_TRACE_ARR).unwrap()
271 => ::serde_json::from_str::<Vec<Trace>>(EXAMPLE_TRACE_ARR).unwrap()
272 );
273
274 rpc_test!(
275 Traces:filter, TraceFilterBuilder::default().build() => "trace_filter", vec!["{}"];
276 ::serde_json::from_str(EXAMPLE_TRACE_ARR).unwrap()
277 => ::serde_json::from_str::<Vec<Trace>>(EXAMPLE_TRACE_ARR).unwrap()
278 );
279
280 rpc_test!(
281 Traces:get, "0000000000000000000000000000000000000000000000000000000000000123".parse::<H256>().unwrap(), vec![0.into()]
282 =>
283 "trace_get", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#, r#"["0x0"]"#];
284 ::serde_json::from_str(EXAMPLE_TRACE).unwrap()
285 => ::serde_json::from_str::<Trace>(EXAMPLE_TRACE).unwrap()
286 );
287
288 rpc_test!(
289 Traces:transaction, "0000000000000000000000000000000000000000000000000000000000000123".parse::<H256>().unwrap()
290 =>
291 "trace_transaction", vec![r#""0x0000000000000000000000000000000000000000000000000000000000000123""#];
292 ::serde_json::from_str(EXAMPLE_TRACE_ARR).unwrap()
293 => ::serde_json::from_str::<Vec<Trace>>(EXAMPLE_TRACE_ARR).unwrap()
294 );
295}