1
// Copyright 2019-2022 PureStake Inc.
2
// This file is part of Moonbeam.
3

            
4
// Moonbeam is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Moonbeam is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Moonbeam.  If not, see <http://www.gnu.org/licenses/>.
16

            
17
use super::blockscout::BlockscoutCallInner;
18
use crate::types::{
19
	single::{Call, Log, TransactionTrace},
20
	CallResult, CallType, CreateResult,
21
};
22

            
23
use crate::listeners::call_list::Listener;
24

            
25
use crate::types::serialization::*;
26
use serde::Serialize;
27

            
28
use crate::types::block::BlockTransactionTrace;
29
use ethereum_types::{H160, U256};
30
use parity_scale_codec::{Decode, Encode};
31
use sp_std::{cmp::Ordering, vec::Vec};
32

            
33
pub struct Formatter;
34

            
35
impl super::ResponseFormatter for Formatter {
36
	type Listener = Listener;
37
	type Response = Vec<BlockTransactionTrace>;
38

            
39
	fn format(mut listener: Listener) -> Option<Vec<BlockTransactionTrace>> {
40
		// Remove empty BTreeMaps pushed to `entries`.
41
		// I.e. InvalidNonce or other pallet_evm::runner exits
42
		listener.entries.retain(|x| !x.is_empty());
43
		let mut traces = Vec::new();
44
		for (eth_tx_index, entry) in listener.entries.iter().enumerate() {
45
			let mut result: Vec<Call> = entry
46
				.into_iter()
47
				.map(|(_, it)| {
48
					let from = it.from;
49
					let trace_address = it.trace_address.clone();
50
					let value = it.value;
51
					let gas = it.gas;
52
					let gas_used = it.gas_used;
53
					let inner = it.inner.clone();
54
					Call::CallTracer(CallTracerCall {
55
						from: from,
56
						gas: gas,
57
						gas_used: gas_used,
58
						trace_address: Some(trace_address.clone()),
59
						inner: match inner.clone() {
60
							BlockscoutCallInner::Call {
61
								input,
62
								to,
63
								res,
64
								call_type,
65
							} => CallTracerInner::Call {
66
								call_type: match call_type {
67
									CallType::Call => "CALL".as_bytes().to_vec(),
68
									CallType::CallCode => "CALLCODE".as_bytes().to_vec(),
69
									CallType::DelegateCall => "DELEGATECALL".as_bytes().to_vec(),
70
									CallType::StaticCall => "STATICCALL".as_bytes().to_vec(),
71
								},
72
								to,
73
								input,
74
								res: res.clone(),
75
								value: Some(value),
76
								logs: match res {
77
									CallResult::Output { .. } => it.logs.clone(),
78
									CallResult::Error { .. } => Vec::new(),
79
								},
80
							},
81
							BlockscoutCallInner::Create { init, res } => CallTracerInner::Create {
82
								input: init,
83
								error: match res {
84
									CreateResult::Success { .. } => None,
85
									CreateResult::Error { ref error } => Some(error.clone()),
86
								},
87
								to: match res {
88
									CreateResult::Success {
89
										created_contract_address_hash,
90
										..
91
									} => Some(created_contract_address_hash),
92
									CreateResult::Error { .. } => None,
93
								},
94
								output: match res {
95
									CreateResult::Success {
96
										created_contract_code,
97
										..
98
									} => Some(created_contract_code),
99
									CreateResult::Error { .. } => None,
100
								},
101
								value: value,
102
								call_type: "CREATE".as_bytes().to_vec(),
103
							},
104
							BlockscoutCallInner::SelfDestruct { balance, to } => {
105
								CallTracerInner::SelfDestruct {
106
									value: balance,
107
									to,
108
									call_type: "SELFDESTRUCT".as_bytes().to_vec(),
109
								}
110
							}
111
						},
112
						calls: Vec::new(),
113
					})
114
				})
115
				.collect();
116
			// Geth's `callTracer` expects a tree of nested calls and we have a stack.
117
			//
118
			// We iterate over the sorted stack, and push each children to it's
119
			// parent (the item which's `trace_address` matches &T[0..T.len()-1]) until there
120
			// is a single item on the list.
121
			//
122
			// The last remaining item is the context call with all it's descendants. I.e.
123
			//
124
			// 		# Input
125
			// 		[]
126
			// 		[0]
127
			// 		[0,0]
128
			// 		[0,0,0]
129
			// 		[0,1]
130
			// 		[0,1,0]
131
			// 		[0,1,1]
132
			// 		[0,1,2]
133
			// 		[1]
134
			// 		[1,0]
135
			//
136
			// 		# Sorted
137
			// 		[0,0,0] -> pop 0 and push to [0,0]
138
			// 		[0,1,0] -> pop 0 and push to [0,1]
139
			// 		[0,1,1] -> pop 1 and push to [0,1]
140
			// 		[0,1,2] -> pop 2 and push to [0,1]
141
			// 		[0,0] -> pop 0 and push to [0]
142
			// 		[0,1] -> pop 1 and push to [0]
143
			// 		[1,0] -> pop 0 and push to [1]
144
			// 		[0] -> pop 0 and push to root
145
			// 		[1] -> pop 1 and push to root
146
			// 		[]
147
			//
148
			// 		# Result
149
			// 		root {
150
			// 			calls: {
151
			// 				0 { 0 { 0 }, 1 { 0, 1, 2 }},
152
			// 				1 { 0 },
153
			// 			}
154
			// 		}
155
			if result.len() > 1 {
156
				// Sort the stack. Assume there is no `Ordering::Equal`, as we are
157
				// sorting by index.
158
				//
159
				// We consider an item to be `Ordering::Less` when:
160
				// 	- Is closer to the root or
161
				//	- Is greater than its sibling.
162
				result.sort_by(|a, b| match (a, b) {
163
					(
164
						Call::CallTracer(CallTracerCall {
165
							trace_address: Some(a),
166
							..
167
						}),
168
						Call::CallTracer(CallTracerCall {
169
							trace_address: Some(b),
170
							..
171
						}),
172
					) => {
173
						let a_len = a.len();
174
						let b_len = b.len();
175
						let sibling_greater_than = |a: &Vec<u32>, b: &Vec<u32>| -> bool {
176
							for (i, a_value) in a.iter().enumerate() {
177
								if a_value > &b[i] {
178
									return true;
179
								} else if a_value < &b[i] {
180
									return false;
181
								} else {
182
									continue;
183
								}
184
							}
185
							return false;
186
						};
187
						if b_len > a_len || (a_len == b_len && sibling_greater_than(&a, &b)) {
188
							Ordering::Less
189
						} else {
190
							Ordering::Greater
191
						}
192
					}
193
					_ => unreachable!(),
194
				});
195
				// Stack pop-and-push.
196
				while result.len() > 1 {
197
					let mut last = result
198
						.pop()
199
						.expect("result.len() > 1, so pop() necessarily returns an element");
200
					// Find the parent index.
201
					if let Some(index) =
202
						result
203
							.iter()
204
							.position(|current| match (last.clone(), current) {
205
								(
206
									Call::CallTracer(CallTracerCall {
207
										trace_address: Some(a),
208
										..
209
									}),
210
									Call::CallTracer(CallTracerCall {
211
										trace_address: Some(b),
212
										..
213
									}),
214
								) => {
215
									&b[..]
216
										== a.get(0..a.len() - 1).expect(
217
											"non-root element while traversing trace result",
218
										)
219
								}
220
								_ => unreachable!(),
221
							}) {
222
						// Remove `trace_address` from result.
223
						if let Call::CallTracer(CallTracerCall {
224
							ref mut trace_address,
225
							..
226
						}) = last
227
						{
228
							*trace_address = None;
229
						}
230
						// Push the children to parent.
231
						if let Some(Call::CallTracer(CallTracerCall { calls, .. })) =
232
							result.get_mut(index)
233
						{
234
							calls.push(last);
235
						}
236
					}
237
				}
238
			}
239
			// Remove `trace_address` from result.
240
			if let Some(Call::CallTracer(CallTracerCall { trace_address, .. })) = result.get_mut(0)
241
			{
242
				*trace_address = None;
243
			}
244
			if result.len() == 1 {
245
				traces.push(BlockTransactionTrace {
246
					tx_position: eth_tx_index as u32,
247
					// Use default, the correct value will be set upstream
248
					tx_hash: Default::default(),
249
					result: TransactionTrace::CallListNested(
250
						result
251
							.pop()
252
							.expect("result.len() == 1, so pop() necessarily returns this element"),
253
					),
254
				});
255
			}
256
		}
257
		if traces.is_empty() {
258
			return None;
259
		}
260
		return Some(traces);
261
	}
262
}
263

            
264
#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Serialize)]
265
#[serde(rename_all = "camelCase")]
266
pub struct CallTracerCall {
267
	pub from: H160,
268

            
269
	/// Indices of parent calls. Used to build the Etherscan nested response.
270
	#[serde(skip_serializing_if = "Option::is_none")]
271
	pub trace_address: Option<Vec<u32>>,
272

            
273
	/// Remaining gas in the runtime.
274
	pub gas: U256,
275
	/// Gas used by this context.
276
	pub gas_used: U256,
277

            
278
	#[serde(flatten)]
279
	pub inner: CallTracerInner,
280

            
281
	#[serde(skip_serializing_if = "Vec::is_empty")]
282
	pub calls: Vec<Call>,
283
}
284

            
285
#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, Serialize)]
286
#[serde(untagged)]
287
pub enum CallTracerInner {
288
	Call {
289
		#[serde(rename = "type", serialize_with = "opcode_serialize")]
290
		call_type: Vec<u8>,
291
		to: H160,
292
		#[serde(serialize_with = "bytes_0x_serialize")]
293
		input: Vec<u8>,
294
		/// "output" or "error" field
295
		#[serde(flatten)]
296
		res: CallResult,
297

            
298
		#[serde(skip_serializing_if = "Option::is_none")]
299
		value: Option<U256>,
300

            
301
		#[serde(skip_serializing_if = "Vec::is_empty")]
302
		logs: Vec<Log>,
303
	},
304
	Create {
305
		#[serde(rename = "type", serialize_with = "opcode_serialize")]
306
		call_type: Vec<u8>,
307
		#[serde(serialize_with = "bytes_0x_serialize")]
308
		input: Vec<u8>,
309
		#[serde(skip_serializing_if = "Option::is_none")]
310
		to: Option<H160>,
311
		#[serde(
312
			skip_serializing_if = "Option::is_none",
313
			serialize_with = "option_bytes_0x_serialize"
314
		)]
315
		output: Option<Vec<u8>>,
316
		#[serde(
317
			skip_serializing_if = "Option::is_none",
318
			serialize_with = "option_string_serialize"
319
		)]
320
		error: Option<Vec<u8>>,
321
		value: U256,
322
	},
323
	SelfDestruct {
324
		#[serde(rename = "type", serialize_with = "opcode_serialize")]
325
		call_type: Vec<u8>,
326
		to: H160,
327
		value: U256,
328
	},
329
}