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