cs_mwc_web3/api/
traces.rs

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/// `Trace` namespace
9#[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    /// Executes the given call and returns a number of possible traces for it
29    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    /// Traces a call to `eth_sendRawTransaction` without making the call, returning the traces
42    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    /// Replays a transaction, returning the traces
49    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    /// Replays all transactions in a block returning the requested traces for each transaction
59    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    /// Returns traces created at given block
73    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    /// Return traces matching the given filter
79    ///
80    /// See [TraceFilterBuilder](../types/struct.TraceFilterBuilder.html)
81    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    /// Returns trace at the given position
87    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    /// Returns all traces of a given transaction
94    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}