evm_tracing_events/
runtime.rs

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
17extern crate alloc;
18
19use super::Context;
20use alloc::vec::Vec;
21use ethereum_types::{H160, H256, U256};
22pub use evm::{ExitError, ExitReason, ExitSucceed, Opcode};
23use parity_scale_codec::{Decode, Encode};
24
25#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)]
26pub struct Stack {
27	pub data: Vec<H256>,
28	pub limit: u64,
29}
30
31impl 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)]
41pub struct Memory {
42	pub data: Vec<u8>,
43	pub effective_len: U256,
44	pub limit: u64,
45}
46
47impl 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)]
58pub 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
66pub type Trap = Vec<u8>; // Should hold the marshalled Opcode.
67
68#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
69pub 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")]
96impl 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>`.
163pub 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}