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
//! Substrate EVM tracing.
18
//!
19
//! The purpose of this crate is enable tracing the EVM opcode execution and will be used by
20
//! both Dapp developers - to get a granular view on their transactions - and indexers to access
21
//! the EVM callstack (internal transactions).
22
//!
23
//! Proxies EVM messages to the host functions.
24

            
25
#![cfg_attr(not(feature = "std"), no_std)]
26

            
27
pub mod tracer {
28
	use ethereum_types::H256;
29
	use evm_tracing_events::{EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter};
30
	use parity_scale_codec::{Decode, Encode};
31

            
32
	use evm::tracing::{using as evm_using, EventListener as EvmListener};
33
	use evm_gasometer::tracing::{using as gasometer_using, EventListener as GasometerListener};
34
	use evm_runtime::tracing::{using as runtime_using, EventListener as RuntimeListener};
35
	use sp_runtime::DispatchError;
36
	use sp_std::{cell::RefCell, rc::Rc};
37

            
38
	/// The current EthereumXcmTransaction trace status.
39
	#[derive(Clone, Debug, Encode, Decode, PartialEq, Eq)]
40
	pub enum EthereumTracingStatus {
41
		/// A full block trace.
42
		Block,
43
		/// A single transaction.
44
		Transaction(H256),
45
		/// Exit signal.
46
		TransactionExited,
47
	}
48

            
49
	environmental::environmental!(ETHEREUM_TRACING_STATUS: EthereumTracingStatus);
50

            
51
	struct ListenerProxy<T>(pub Rc<RefCell<T>>);
52
	impl<T: GasometerListener> GasometerListener for ListenerProxy<T> {
53
60
		fn event(&mut self, event: evm_gasometer::tracing::Event) {
54
60
			self.0.borrow_mut().event(event);
55
60
		}
56
	}
57

            
58
	impl<T: RuntimeListener> RuntimeListener for ListenerProxy<T> {
59
		fn event(&mut self, event: evm_runtime::tracing::Event) {
60
			self.0.borrow_mut().event(event);
61
		}
62
	}
63

            
64
	impl<T: EvmListener> EvmListener for ListenerProxy<T> {
65
		fn event(&mut self, event: evm::tracing::Event) {
66
			self.0.borrow_mut().event(event);
67
		}
68
	}
69

            
70
	pub struct EthereumTracer;
71

            
72
	impl EthereumTracer {
73
20
		pub fn transaction(
74
20
			tx_hash: H256,
75
20
			func: impl FnOnce() -> Result<(), DispatchError>,
76
20
		) -> Result<(), DispatchError> {
77
20
			ETHEREUM_TRACING_STATUS::using(&mut EthereumTracingStatus::Transaction(tx_hash), func)
78
20
		}
79

            
80
20
		pub fn block(
81
20
			func: impl FnOnce() -> Result<(), DispatchError>,
82
20
		) -> Result<(), DispatchError> {
83
20
			ETHEREUM_TRACING_STATUS::using(&mut EthereumTracingStatus::Block, func)
84
20
		}
85

            
86
		pub fn transaction_exited() {
87
			ETHEREUM_TRACING_STATUS::with(|state| {
88
				*state = EthereumTracingStatus::TransactionExited
89
			});
90
		}
91

            
92
880
		pub fn status() -> Option<EthereumTracingStatus> {
93
880
			ETHEREUM_TRACING_STATUS::with(|state| state.clone())
94
880
		}
95
	}
96

            
97
	pub struct EvmTracer {
98
		step_event_filter: StepEventFilter,
99
	}
100

            
101
	impl EvmTracer {
102
192
		pub fn new() -> Self {
103
192
			Self {
104
192
				step_event_filter: moonbeam_primitives_ext::moonbeam_ext::step_event_filter(),
105
192
			}
106
192
		}
107

            
108
		/// Setup event listeners and execute provided closure.
109
		///
110
		/// Consume the tracer and return it alongside the return value of
111
		/// the closure.
112
80
		pub fn trace<R, F: FnOnce() -> R>(self, f: F) {
113
80
			let wrapped = Rc::new(RefCell::new(self));
114
80

            
115
80
			let mut gasometer = ListenerProxy(Rc::clone(&wrapped));
116
80
			let mut runtime = ListenerProxy(Rc::clone(&wrapped));
117
80
			let mut evm = ListenerProxy(Rc::clone(&wrapped));
118
80

            
119
80
			// Each line wraps the previous `f` into a `using` call.
120
80
			// Listening to new events results in adding one new line.
121
80
			// Order is irrelevant when registering listeners.
122
80
			let f = || runtime_using(&mut runtime, f);
123
80
			let f = || gasometer_using(&mut gasometer, f);
124
80
			let f = || evm_using(&mut evm, f);
125
80
			f();
126
80
		}
127

            
128
96
		pub fn emit_new() {
129
96
			moonbeam_primitives_ext::moonbeam_ext::call_list_new();
130
96
		}
131
	}
132

            
133
	impl EvmListener for EvmTracer {
134
		/// Proxies `evm::tracing::Event` to the host.
135
		fn event(&mut self, event: evm::tracing::Event) {
136
			let event: EvmEvent = event.into();
137
			let message = event.encode();
138
			moonbeam_primitives_ext::moonbeam_ext::evm_event(message);
139
		}
140
	}
141

            
142
	impl GasometerListener for EvmTracer {
143
		/// Proxies `evm_gasometer::tracing::Event` to the host.
144
144
		fn event(&mut self, event: evm_gasometer::tracing::Event) {
145
144
			let event: GasometerEvent = event.into();
146
144
			let message = event.encode();
147
144
			moonbeam_primitives_ext::moonbeam_ext::gasometer_event(message);
148
144
		}
149
	}
150

            
151
	impl RuntimeListener for EvmTracer {
152
		/// Proxies `evm_runtime::tracing::Event` to the host.
153
		fn event(&mut self, event: evm_runtime::tracing::Event) {
154
			let event = RuntimeEvent::from_evm_event(event, self.step_event_filter);
155
			let message = event.encode();
156
			moonbeam_primitives_ext::moonbeam_ext::runtime_event(message);
157
		}
158
	}
159
}