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
extern crate alloc;
18

            
19
use super::Context;
20
use alloc::vec::Vec;
21
use ethereum_types::{H160, H256, U256};
22
pub use evm::{ExitError, ExitReason, ExitSucceed, Opcode};
23
use parity_scale_codec::{Decode, Encode};
24

            
25
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)]
26
pub struct Stack {
27
	pub data: Vec<H256>,
28
	pub limit: u64,
29
}
30

            
31
impl From<&evm::Stack> for Stack {
32
	fn from(i: &evm::Stack) -> Self {
33
		Self {
34
			data: i.data().clone(),
35
			limit: i.limit() as u64,
36
		}
37
	}
38
}
39

            
40
#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)]
41
pub struct Memory {
42
	pub data: Vec<u8>,
43
	pub effective_len: U256,
44
	pub limit: u64,
45
}
46

            
47
impl From<&evm::Memory> for Memory {
48
	fn from(i: &evm::Memory) -> Self {
49
		Self {
50
			data: i.data().clone(),
51
			effective_len: i.effective_len(),
52
			limit: i.limit() as u64,
53
		}
54
	}
55
}
56

            
57
#[derive(Clone, Copy, Debug, Eq, PartialEq, Encode, Decode)]
58
pub enum Capture<E, T> {
59
	/// The machine has exited. It cannot be executed again.
60
	Exit(E),
61
	/// The machine has trapped. It is waiting for external information, and can
62
	/// be executed again.
63
	Trap(T),
64
}
65

            
66
pub type Trap = Vec<u8>; // Should hold the marshalled Opcode.
67

            
68
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
69
pub enum RuntimeEvent {
70
	Step {
71
		context: Context,
72
		// This needs to be marshalled in the runtime no matter what.
73
		opcode: Vec<u8>,
74
		// We can use ExitReason with `with-codec` feature,
75
		position: Result<u64, ExitReason>,
76
		stack: Option<Stack>,
77
		memory: Option<Memory>,
78
	},
79
	StepResult {
80
		result: Result<(), Capture<ExitReason, Trap>>,
81
		return_value: Vec<u8>,
82
	},
83
	SLoad {
84
		address: H160,
85
		index: H256,
86
		value: H256,
87
	},
88
	SStore {
89
		address: H160,
90
		index: H256,
91
		value: H256,
92
	},
93
}
94

            
95
#[cfg(feature = "evm-tracing")]
96
impl RuntimeEvent {
97
	pub fn from_evm_event<'a>(
98
		i: evm_runtime::tracing::Event<'a>,
99
		filter: crate::StepEventFilter,
100
	) -> Self {
101
		match i {
102
			evm_runtime::tracing::Event::Step {
103
				context,
104
				opcode,
105
				position,
106
				stack,
107
				memory,
108
			} => Self::Step {
109
				context: context.clone().into(),
110
				opcode: opcodes_string(opcode),
111
				position: match position {
112
					Ok(position) => Ok(*position as u64),
113
					Err(e) => Err(e.clone()),
114
				},
115
				stack: if filter.enable_stack {
116
					Some(stack.into())
117
				} else {
118
					None
119
				},
120
				memory: if filter.enable_memory {
121
					Some(memory.into())
122
				} else {
123
					None
124
				},
125
			},
126
			evm_runtime::tracing::Event::StepResult {
127
				result,
128
				return_value,
129
			} => Self::StepResult {
130
				result: match result {
131
					Ok(_) => Ok(()),
132
					Err(capture) => match capture {
133
						evm::Capture::Exit(e) => Err(Capture::Exit(e.clone())),
134
						evm::Capture::Trap(t) => Err(Capture::Trap(opcodes_string(*t))),
135
					},
136
				},
137
				return_value: return_value.to_vec(),
138
			},
139
			evm_runtime::tracing::Event::SLoad {
140
				address,
141
				index,
142
				value,
143
			} => Self::SLoad {
144
				address,
145
				index,
146
				value,
147
			},
148
			evm_runtime::tracing::Event::SStore {
149
				address,
150
				index,
151
				value,
152
			} => Self::SStore {
153
				address,
154
				index,
155
				value,
156
			},
157
		}
158
	}
159
}
160

            
161
#[cfg(feature = "evm-tracing")]
162
/// Converts an Opcode into its name, stored in a `Vec<u8>`.
163
pub fn opcodes_string(opcode: Opcode) -> Vec<u8> {
164
	let tmp;
165
	let out = match opcode {
166
		Opcode(0) => "Stop",
167
		Opcode(1) => "Add",
168
		Opcode(2) => "Mul",
169
		Opcode(3) => "Sub",
170
		Opcode(4) => "Div",
171
		Opcode(5) => "SDiv",
172
		Opcode(6) => "Mod",
173
		Opcode(7) => "SMod",
174
		Opcode(8) => "AddMod",
175
		Opcode(9) => "MulMod",
176
		Opcode(10) => "Exp",
177
		Opcode(11) => "SignExtend",
178
		Opcode(16) => "Lt",
179
		Opcode(17) => "Gt",
180
		Opcode(18) => "Slt",
181
		Opcode(19) => "Sgt",
182
		Opcode(20) => "Eq",
183
		Opcode(21) => "IsZero",
184
		Opcode(22) => "And",
185
		Opcode(23) => "Or",
186
		Opcode(24) => "Xor",
187
		Opcode(25) => "Not",
188
		Opcode(26) => "Byte",
189
		Opcode(27) => "Shl",
190
		Opcode(28) => "Shr",
191
		Opcode(29) => "Sar",
192
		Opcode(32) => "Keccak256",
193
		Opcode(48) => "Address",
194
		Opcode(49) => "Balance",
195
		Opcode(50) => "Origin",
196
		Opcode(51) => "Caller",
197
		Opcode(52) => "CallValue",
198
		Opcode(53) => "CallDataLoad",
199
		Opcode(54) => "CallDataSize",
200
		Opcode(55) => "CallDataCopy",
201
		Opcode(56) => "CodeSize",
202
		Opcode(57) => "CodeCopy",
203
		Opcode(58) => "GasPrice",
204
		Opcode(59) => "ExtCodeSize",
205
		Opcode(60) => "ExtCodeCopy",
206
		Opcode(61) => "ReturnDataSize",
207
		Opcode(62) => "ReturnDataCopy",
208
		Opcode(63) => "ExtCodeHash",
209
		Opcode(64) => "BlockHash",
210
		Opcode(65) => "Coinbase",
211
		Opcode(66) => "Timestamp",
212
		Opcode(67) => "Number",
213
		Opcode(68) => "Difficulty",
214
		Opcode(69) => "GasLimit",
215
		Opcode(70) => "ChainId",
216
		Opcode(80) => "Pop",
217
		Opcode(81) => "MLoad",
218
		Opcode(82) => "MStore",
219
		Opcode(83) => "MStore8",
220
		Opcode(84) => "SLoad",
221
		Opcode(85) => "SStore",
222
		Opcode(86) => "Jump",
223
		Opcode(87) => "JumpI",
224
		Opcode(88) => "GetPc",
225
		Opcode(89) => "MSize",
226
		Opcode(90) => "Gas",
227
		Opcode(91) => "JumpDest",
228
		Opcode(92) => "TLoad",
229
		Opcode(93) => "TStore",
230
		Opcode(94) => "MCopy",
231
		Opcode(96) => "Push1",
232
		Opcode(97) => "Push2",
233
		Opcode(98) => "Push3",
234
		Opcode(99) => "Push4",
235
		Opcode(100) => "Push5",
236
		Opcode(101) => "Push6",
237
		Opcode(102) => "Push7",
238
		Opcode(103) => "Push8",
239
		Opcode(104) => "Push9",
240
		Opcode(105) => "Push10",
241
		Opcode(106) => "Push11",
242
		Opcode(107) => "Push12",
243
		Opcode(108) => "Push13",
244
		Opcode(109) => "Push14",
245
		Opcode(110) => "Push15",
246
		Opcode(111) => "Push16",
247
		Opcode(112) => "Push17",
248
		Opcode(113) => "Push18",
249
		Opcode(114) => "Push19",
250
		Opcode(115) => "Push20",
251
		Opcode(116) => "Push21",
252
		Opcode(117) => "Push22",
253
		Opcode(118) => "Push23",
254
		Opcode(119) => "Push24",
255
		Opcode(120) => "Push25",
256
		Opcode(121) => "Push26",
257
		Opcode(122) => "Push27",
258
		Opcode(123) => "Push28",
259
		Opcode(124) => "Push29",
260
		Opcode(125) => "Push30",
261
		Opcode(126) => "Push31",
262
		Opcode(127) => "Push32",
263
		Opcode(128) => "Dup1",
264
		Opcode(129) => "Dup2",
265
		Opcode(130) => "Dup3",
266
		Opcode(131) => "Dup4",
267
		Opcode(132) => "Dup5",
268
		Opcode(133) => "Dup6",
269
		Opcode(134) => "Dup7",
270
		Opcode(135) => "Dup8",
271
		Opcode(136) => "Dup9",
272
		Opcode(137) => "Dup10",
273
		Opcode(138) => "Dup11",
274
		Opcode(139) => "Dup12",
275
		Opcode(140) => "Dup13",
276
		Opcode(141) => "Dup14",
277
		Opcode(142) => "Dup15",
278
		Opcode(143) => "Dup16",
279
		Opcode(144) => "Swap1",
280
		Opcode(145) => "Swap2",
281
		Opcode(146) => "Swap3",
282
		Opcode(147) => "Swap4",
283
		Opcode(148) => "Swap5",
284
		Opcode(149) => "Swap6",
285
		Opcode(150) => "Swap7",
286
		Opcode(151) => "Swap8",
287
		Opcode(152) => "Swap9",
288
		Opcode(153) => "Swap10",
289
		Opcode(154) => "Swap11",
290
		Opcode(155) => "Swap12",
291
		Opcode(156) => "Swap13",
292
		Opcode(157) => "Swap14",
293
		Opcode(158) => "Swap15",
294
		Opcode(159) => "Swap16",
295
		Opcode(160) => "Log0",
296
		Opcode(161) => "Log1",
297
		Opcode(162) => "Log2",
298
		Opcode(163) => "Log3",
299
		Opcode(164) => "Log4",
300
		Opcode(176) => "JumpTo",
301
		Opcode(177) => "JumpIf",
302
		Opcode(178) => "JumpSub",
303
		Opcode(180) => "JumpSubv",
304
		Opcode(181) => "BeginSub",
305
		Opcode(182) => "BeginData",
306
		Opcode(184) => "ReturnSub",
307
		Opcode(185) => "PutLocal",
308
		Opcode(186) => "GetLocal",
309
		Opcode(225) => "SLoadBytes",
310
		Opcode(226) => "SStoreBytes",
311
		Opcode(227) => "SSize",
312
		Opcode(240) => "Create",
313
		Opcode(241) => "Call",
314
		Opcode(242) => "CallCode",
315
		Opcode(243) => "Return",
316
		Opcode(244) => "DelegateCall",
317
		Opcode(245) => "Create2",
318
		Opcode(250) => "StaticCall",
319
		Opcode(252) => "TxExecGas",
320
		Opcode(253) => "Revert",
321
		Opcode(254) => "Invalid",
322
		Opcode(255) => "SelfDestruct",
323
		Opcode(n) => {
324
			tmp = alloc::format!("Unknown({})", n);
325
			&tmp
326
		}
327
	};
328
	out.as_bytes().to_vec()
329
}