1
// Copyright 2019-2025 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(listener: Listener) -> Option<Vec<BlockTransactionTrace>> {
40
		let mut traces = Vec::new();
41
		for (eth_tx_index, entry) in listener.entries.iter().enumerate() {
42
			// Skip empty BTreeMaps pushed to `entries`.
43
			// I.e. InvalidNonce or other pallet_evm::runner exits
44
			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
			// Geth's `callTracer` expects a tree of nested calls and we have a stack.
123
			//
124
			// We iterate over the sorted stack, and push each children to it's
125
			// parent (the item which's `trace_address` matches &T[0..T.len()-1]) until there
126
			// is a single item on the list.
127
			//
128
			// The last remaining item is the context call with all it's descendants. I.e.
129
			//
130
			// 		# Input
131
			// 		[]
132
			// 		[0]
133
			// 		[0,0]
134
			// 		[0,0,0]
135
			// 		[0,1]
136
			// 		[0,1,0]
137
			// 		[0,1,1]
138
			// 		[0,1,2]
139
			// 		[1]
140
			// 		[1,0]
141
			//
142
			// 		# Sorted
143
			// 		[0,0,0] -> pop 0 and push to [0,0]
144
			// 		[0,1,0] -> pop 0 and push to [0,1]
145
			// 		[0,1,1] -> pop 1 and push to [0,1]
146
			// 		[0,1,2] -> pop 2 and push to [0,1]
147
			// 		[0,0] -> pop 0 and push to [0]
148
			// 		[0,1] -> pop 1 and push to [0]
149
			// 		[1,0] -> pop 0 and push to [1]
150
			// 		[0] -> pop 0 and push to root
151
			// 		[1] -> pop 1 and push to root
152
			// 		[]
153
			//
154
			// 		# Result
155
			// 		root {
156
			// 			calls: {
157
			// 				0 { 0 { 0 }, 1 { 0, 1, 2 }},
158
			// 				1 { 0 },
159
			// 			}
160
			// 		}
161
			if result.len() > 1 {
162
				// Sort the stack. Assume there is no `Ordering::Equal`, as we are
163
				// sorting by index.
164
				//
165
				// We consider an item to be `Ordering::Less` when:
166
				// 	- Is closer to the root or
167
				//	- Is greater than its sibling.
168
				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
				// Stack pop-and-push.
202
				while result.len() > 1 {
203
					let mut last = result
204
						.pop()
205
						.expect("result.len() > 1, so pop() necessarily returns an element");
206
					// Find the parent index.
207
					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
						// Remove `trace_address` from result.
229
						if let Call::CallTracer(CallTracerCall {
230
							ref mut trace_address,
231
							..
232
						}) = last
233
						{
234
							*trace_address = None;
235
						}
236
						// Push the children to parent.
237
						if let Some(Call::CallTracer(CallTracerCall { calls, .. })) =
238
							result.get_mut(index)
239
						{
240
							calls.push(last);
241
						}
242
					}
243
				}
244
			}
245
			// Remove `trace_address` from result.
246
			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
					// Use default, the correct value will be set upstream
254
					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")]
272
pub struct CallTracerCall {
273
	pub from: H160,
274

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

            
279
	/// Remaining gas in the runtime.
280
	pub gas: U256,
281
	/// Gas used by this context.
282
	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)]
293
pub 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
		/// "output" or "error" field
301
		#[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
}