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 evm_tracing_events::{EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter};
29
	use parity_scale_codec::Encode;
30

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

            
36
	struct ListenerProxy<T>(pub Rc<RefCell<T>>);
37
	impl<T: GasometerListener> GasometerListener for ListenerProxy<T> {
38
60
		fn event(&mut self, event: evm_gasometer::tracing::Event) {
39
60
			self.0.borrow_mut().event(event);
40
60
		}
41
	}
42

            
43
	impl<T: RuntimeListener> RuntimeListener for ListenerProxy<T> {
44
		fn event(&mut self, event: evm_runtime::tracing::Event) {
45
			self.0.borrow_mut().event(event);
46
		}
47
	}
48

            
49
	impl<T: EvmListener> EvmListener for ListenerProxy<T> {
50
		fn event(&mut self, event: evm::tracing::Event) {
51
			self.0.borrow_mut().event(event);
52
		}
53
	}
54

            
55
	pub struct EvmTracer {
56
		step_event_filter: StepEventFilter,
57
	}
58

            
59
	impl EvmTracer {
60
192
		pub fn new() -> Self {
61
192
			Self {
62
192
				step_event_filter: moonbeam_primitives_ext::moonbeam_ext::step_event_filter(),
63
192
			}
64
192
		}
65

            
66
		/// Setup event listeners and execute provided closure.
67
		///
68
		/// Consume the tracer and return it alongside the return value of
69
		/// the closure.
70
80
		pub fn trace<R, F: FnOnce() -> R>(self, f: F) {
71
80
			let wrapped = Rc::new(RefCell::new(self));
72
80

            
73
80
			let mut gasometer = ListenerProxy(Rc::clone(&wrapped));
74
80
			let mut runtime = ListenerProxy(Rc::clone(&wrapped));
75
80
			let mut evm = ListenerProxy(Rc::clone(&wrapped));
76
80

            
77
80
			// Each line wraps the previous `f` into a `using` call.
78
80
			// Listening to new events results in adding one new line.
79
80
			// Order is irrelevant when registering listeners.
80
80
			let f = || runtime_using(&mut runtime, f);
81
80
			let f = || gasometer_using(&mut gasometer, f);
82
80
			let f = || evm_using(&mut evm, f);
83
80
			f();
84
80
		}
85

            
86
96
		pub fn emit_new() {
87
96
			moonbeam_primitives_ext::moonbeam_ext::call_list_new();
88
96
		}
89
	}
90

            
91
	impl EvmListener for EvmTracer {
92
		/// Proxies `evm::tracing::Event` to the host.
93
		fn event(&mut self, event: evm::tracing::Event) {
94
			let event: EvmEvent = event.into();
95
			let message = event.encode();
96
			moonbeam_primitives_ext::moonbeam_ext::evm_event(message);
97
		}
98
	}
99

            
100
	impl GasometerListener for EvmTracer {
101
		/// Proxies `evm_gasometer::tracing::Event` to the host.
102
144
		fn event(&mut self, event: evm_gasometer::tracing::Event) {
103
144
			let event: GasometerEvent = event.into();
104
144
			let message = event.encode();
105
144
			moonbeam_primitives_ext::moonbeam_ext::gasometer_event(message);
106
144
		}
107
	}
108

            
109
	impl RuntimeListener for EvmTracer {
110
		/// Proxies `evm_runtime::tracing::Event` to the host.
111
		fn event(&mut self, event: evm_runtime::tracing::Event) {
112
			let event = RuntimeEvent::from_evm_event(event, self.step_event_filter);
113
			let message = event.encode();
114
			moonbeam_primitives_ext::moonbeam_ext::runtime_event(message);
115
		}
116
	}
117
}