moonbeam_client_evm_tracing/formatters/
call_tracer.rs1use super::blockscout::BlockscoutCallInner;
18use crate::types::{
19 single::{Call, Log, TransactionTrace},
20 CallResult, CallType, CreateResult,
21};
22
23use crate::listeners::call_list::Listener;
24
25use crate::types::serialization::*;
26use serde::Serialize;
27
28use crate::types::block::BlockTransactionTrace;
29use ethereum_types::{H160, U256};
30use parity_scale_codec::{Decode, Encode};
31use sp_std::{cmp::Ordering, vec::Vec};
32
33pub struct Formatter;
34
35impl super::ResponseFormatter for Formatter {
36 type Listener = Listener;
37 type Response = Vec<BlockTransactionTrace>;
38
39 fn format(listener: Listener) -> Option<Vec<BlockTransactionTrace>> {
40 let mut traces = Vec::new();
41 for (eth_tx_index, entry) in listener.entries.iter().enumerate() {
42 if entry.is_empty() {
45 log::debug!(
46 target: "tracing",
47 "Empty trace entry with transaction index {}, skipping...", eth_tx_index
48 );
49 continue;
50 }
51 let mut result: Vec<Call> = entry
52 .into_iter()
53 .map(|(_, it)| {
54 let from = it.from;
55 let trace_address = it.trace_address.clone();
56 let value = it.value;
57 let gas = it.gas;
58 let gas_used = it.gas_used;
59 let inner = it.inner.clone();
60 Call::CallTracer(CallTracerCall {
61 from: from,
62 gas: gas,
63 gas_used: gas_used,
64 trace_address: Some(trace_address.clone()),
65 inner: match inner.clone() {
66 BlockscoutCallInner::Call {
67 input,
68 to,
69 res,
70 call_type,
71 } => CallTracerInner::Call {
72 call_type: match call_type {
73 CallType::Call => "CALL".as_bytes().to_vec(),
74 CallType::CallCode => "CALLCODE".as_bytes().to_vec(),
75 CallType::DelegateCall => "DELEGATECALL".as_bytes().to_vec(),
76 CallType::StaticCall => "STATICCALL".as_bytes().to_vec(),
77 },
78 to,
79 input,
80 res: res.clone(),
81 value: Some(value),
82 logs: match res {
83 CallResult::Output { .. } => it.logs.clone(),
84 CallResult::Error { .. } => Vec::new(),
85 },
86 },
87 BlockscoutCallInner::Create { init, res } => CallTracerInner::Create {
88 input: init,
89 error: match res {
90 CreateResult::Success { .. } => None,
91 CreateResult::Error { ref error } => Some(error.clone()),
92 },
93 to: match res {
94 CreateResult::Success {
95 created_contract_address_hash,
96 ..
97 } => Some(created_contract_address_hash),
98 CreateResult::Error { .. } => None,
99 },
100 output: match res {
101 CreateResult::Success {
102 created_contract_code,
103 ..
104 } => Some(created_contract_code),
105 CreateResult::Error { .. } => None,
106 },
107 value: value,
108 call_type: "CREATE".as_bytes().to_vec(),
109 },
110 BlockscoutCallInner::SelfDestruct { balance, to } => {
111 CallTracerInner::SelfDestruct {
112 value: balance,
113 to,
114 call_type: "SELFDESTRUCT".as_bytes().to_vec(),
115 }
116 }
117 },
118 calls: Vec::new(),
119 })
120 })
121 .collect();
122 if result.len() > 1 {
162 result.sort_by(|a, b| match (a, b) {
169 (
170 Call::CallTracer(CallTracerCall {
171 trace_address: Some(a),
172 ..
173 }),
174 Call::CallTracer(CallTracerCall {
175 trace_address: Some(b),
176 ..
177 }),
178 ) => {
179 let a_len = a.len();
180 let b_len = b.len();
181 let sibling_greater_than = |a: &Vec<u32>, b: &Vec<u32>| -> bool {
182 for (i, a_value) in a.iter().enumerate() {
183 if a_value > &b[i] {
184 return true;
185 } else if a_value < &b[i] {
186 return false;
187 } else {
188 continue;
189 }
190 }
191 return false;
192 };
193 if b_len > a_len || (a_len == b_len && sibling_greater_than(&a, &b)) {
194 Ordering::Less
195 } else {
196 Ordering::Greater
197 }
198 }
199 _ => unreachable!(),
200 });
201 while result.len() > 1 {
203 let mut last = result
204 .pop()
205 .expect("result.len() > 1, so pop() necessarily returns an element");
206 if let Some(index) =
208 result
209 .iter()
210 .position(|current| match (last.clone(), current) {
211 (
212 Call::CallTracer(CallTracerCall {
213 trace_address: Some(a),
214 ..
215 }),
216 Call::CallTracer(CallTracerCall {
217 trace_address: Some(b),
218 ..
219 }),
220 ) => {
221 &b[..]
222 == a.get(0..a.len() - 1).expect(
223 "non-root element while traversing trace result",
224 )
225 }
226 _ => unreachable!(),
227 }) {
228 if let Call::CallTracer(CallTracerCall {
230 ref mut trace_address,
231 ..
232 }) = last
233 {
234 *trace_address = None;
235 }
236 if let Some(Call::CallTracer(CallTracerCall { calls, .. })) =
238 result.get_mut(index)
239 {
240 calls.push(last);
241 }
242 }
243 }
244 }
245 if let Some(Call::CallTracer(CallTracerCall { trace_address, .. })) = result.get_mut(0)
247 {
248 *trace_address = None;
249 }
250 if result.len() == 1 {
251 traces.push(BlockTransactionTrace {
252 tx_position: eth_tx_index as u32,
253 tx_hash: Default::default(),
255 result: TransactionTrace::CallListNested(
256 result
257 .pop()
258 .expect("result.len() == 1, so pop() necessarily returns this element"),
259 ),
260 });
261 }
262 }
263 if traces.is_empty() {
264 return None;
265 }
266 return Some(traces);
267 }
268}
269
270#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Serialize)]
271#[serde(rename_all = "camelCase")]
272pub struct CallTracerCall {
273 pub from: H160,
274
275 #[serde(skip_serializing_if = "Option::is_none")]
277 pub trace_address: Option<Vec<u32>>,
278
279 pub gas: U256,
281 pub gas_used: U256,
283
284 #[serde(flatten)]
285 pub inner: CallTracerInner,
286
287 #[serde(skip_serializing_if = "Vec::is_empty")]
288 pub calls: Vec<Call>,
289}
290
291#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Serialize)]
292#[serde(untagged)]
293pub enum CallTracerInner {
294 Call {
295 #[serde(rename = "type", serialize_with = "opcode_serialize")]
296 call_type: Vec<u8>,
297 to: H160,
298 #[serde(serialize_with = "bytes_0x_serialize")]
299 input: Vec<u8>,
300 #[serde(flatten)]
302 res: CallResult,
303
304 #[serde(skip_serializing_if = "Option::is_none")]
305 value: Option<U256>,
306
307 #[serde(skip_serializing_if = "Vec::is_empty")]
308 logs: Vec<Log>,
309 },
310 Create {
311 #[serde(rename = "type", serialize_with = "opcode_serialize")]
312 call_type: Vec<u8>,
313 #[serde(serialize_with = "bytes_0x_serialize")]
314 input: Vec<u8>,
315 #[serde(skip_serializing_if = "Option::is_none")]
316 to: Option<H160>,
317 #[serde(
318 skip_serializing_if = "Option::is_none",
319 serialize_with = "option_bytes_0x_serialize"
320 )]
321 output: Option<Vec<u8>>,
322 #[serde(
323 skip_serializing_if = "Option::is_none",
324 serialize_with = "option_string_serialize"
325 )]
326 error: Option<Vec<u8>>,
327 value: U256,
328 },
329 SelfDestruct {
330 #[serde(rename = "type", serialize_with = "opcode_serialize")]
331 call_type: Vec<u8>,
332 to: H160,
333 value: U256,
334 },
335}