Skip to content

Commit 975b1d8

Browse files
Runtime level implementation
1 parent 1a7c611 commit 975b1d8

File tree

18 files changed

+1424
-2
lines changed

18 files changed

+1424
-2
lines changed

Cargo.lock

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ bytes = { version = "1", default-features = false }
2020
chrono = { version = "0.4", default-features = false }
2121
clap = { version = "4", default-features = false }
2222
ed25519-dalek = { version = "2", default-features = false }
23+
environmental = { version = "1.1", default-features = false }
2324
ethereum = { version = "0.14", default-features = false }
2425
ethers-core = { version = "2.0.14", default-features = false }
2526
evm = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false }
27+
evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false }
28+
evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false }
2629
fdlimit = { version = "0.2", default-features = false }
2730
futures = { version = "0.3", default-features = false }
2831
getrandom = { version = "0.3", default-features = false }
@@ -132,6 +135,7 @@ sp-keystore = { git = "https://github.com/humanode-network/substrate", tag = "lo
132135
sp-offchain = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
133136
sp-panic-handler = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
134137
sp-runtime = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
138+
sp-runtime-interface = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
135139
sp-session = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
136140
sp-staking = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
137141
sp-std = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }

crates/evm-tracer/Cargo.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
[package]
2+
name = "evm-tracer"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
primitives-evm-tracing-events = { path = "../primitives-evm-tracing-events", default-features = false, features = ["evm-tracing"] }
9+
primitives-evm-tracing-ext = { path = "../primitives-evm-tracing-ext", default-features = false }
10+
11+
codec = { workspace = true, features = ["derive"] }
12+
evm = { workspace = true, features = ["tracing"] }
13+
evm-gasometer = { workspace = true, features = ["tracing"] }
14+
evm-runtime = { workspace = true, features = ["tracing"] }
15+
sp-std = { workspace = true }
16+
17+
[features]
18+
default = ["std"]
19+
std = [
20+
"codec/std",
21+
"evm-gasometer/std",
22+
"evm-runtime/std",
23+
"evm/std",
24+
"primitives-evm-tracing-events/std",
25+
"primitives-evm-tracing-ext/std",
26+
"sp-std/std",
27+
]

crates/evm-tracer/src/lib.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//! Substrate EVM tracer.
2+
//!
3+
//! Enables tracing the EVM opcode execution and proxies EVM messages to the host functions.
4+
5+
#![cfg_attr(not(feature = "std"), no_std)]
6+
7+
use codec::Encode;
8+
use evm::tracing::{using as evm_using, EventListener as EvmListener};
9+
use evm_gasometer::tracing::{using as gasometer_using, EventListener as GasometerListener};
10+
use evm_runtime::tracing::{using as runtime_using, EventListener as RuntimeListener};
11+
use primitives_evm_tracing_events::{EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter};
12+
use sp_std::{cell::RefCell, rc::Rc};
13+
14+
/// Listener proxy.
15+
struct ListenerProxy<T>(pub Rc<RefCell<T>>);
16+
17+
impl<T: GasometerListener> GasometerListener for ListenerProxy<T> {
18+
fn event(&mut self, event: evm_gasometer::tracing::Event) {
19+
self.0.borrow_mut().event(event);
20+
}
21+
}
22+
23+
impl<T: RuntimeListener> RuntimeListener for ListenerProxy<T> {
24+
fn event(&mut self, event: evm_runtime::tracing::Event) {
25+
self.0.borrow_mut().event(event);
26+
}
27+
}
28+
29+
impl<T: EvmListener> EvmListener for ListenerProxy<T> {
30+
fn event(&mut self, event: evm::tracing::Event) {
31+
self.0.borrow_mut().event(event);
32+
}
33+
}
34+
35+
/// EVM tracer.
36+
pub struct EvmTracer {
37+
/// Step event filter.
38+
step_event_filter: StepEventFilter,
39+
}
40+
41+
impl Default for EvmTracer {
42+
fn default() -> Self {
43+
Self {
44+
step_event_filter: primitives_evm_tracing_ext::evm_tracing_ext::step_event_filter(),
45+
}
46+
}
47+
}
48+
49+
impl EvmTracer {
50+
/// Setup event listeners and execute provided closure.
51+
///
52+
/// Consume the tracer and return it alongside the return value of
53+
/// the closure.
54+
pub fn trace<R, F: FnOnce() -> R>(self, f: F) {
55+
let wrapped = Rc::new(RefCell::new(self));
56+
57+
let mut gasometer = ListenerProxy(Rc::clone(&wrapped));
58+
let mut runtime = ListenerProxy(Rc::clone(&wrapped));
59+
let mut evm = ListenerProxy(Rc::clone(&wrapped));
60+
61+
// Each line wraps the previous `f` into a `using` call.
62+
// Listening to new events results in adding one new line.
63+
// Order is irrelevant when registering listeners.
64+
let f = || runtime_using(&mut runtime, f);
65+
let f = || gasometer_using(&mut gasometer, f);
66+
let f = || evm_using(&mut evm, f);
67+
f();
68+
}
69+
70+
/// Emit new call stack.
71+
pub fn emit_new() {
72+
primitives_evm_tracing_ext::evm_tracing_ext::call_list_new();
73+
}
74+
}
75+
76+
impl EvmListener for EvmTracer {
77+
fn event(&mut self, event: evm::tracing::Event) {
78+
let event: EvmEvent = event.into();
79+
let message = event.encode();
80+
primitives_evm_tracing_ext::evm_tracing_ext::evm_event(message);
81+
}
82+
}
83+
84+
impl GasometerListener for EvmTracer {
85+
fn event(&mut self, event: evm_gasometer::tracing::Event) {
86+
let event: GasometerEvent = event.into();
87+
let message = event.encode();
88+
primitives_evm_tracing_ext::evm_tracing_ext::gasometer_event(message);
89+
}
90+
}
91+
92+
impl RuntimeListener for EvmTracer {
93+
fn event(&mut self, event: evm_runtime::tracing::Event) {
94+
let event = RuntimeEvent::from_evm_event(event, self.step_event_filter);
95+
let message = event.encode();
96+
primitives_evm_tracing_ext::evm_tracing_ext::runtime_event(message);
97+
}
98+
}

crates/evm-tracing-api/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "evm-tracing-api"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
ethereum = { workspace = true, features = ["with-codec"] }
9+
sp-api = { workspace = true }
10+
sp-core = { workspace = true }
11+
sp-runtime = { workspace = true }
12+
13+
[features]
14+
default = ["std"]
15+
std = [
16+
"ethereum/std",
17+
"sp-api/std",
18+
"sp-core/std",
19+
"sp-runtime/std",
20+
]

crates/evm-tracing-api/src/lib.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//! The runtime API for the EVM tracing logic.
2+
3+
#![cfg_attr(not(feature = "std"), no_std)]
4+
5+
use ethereum::TransactionV2 as Transaction;
6+
use sp_core::{sp_std::vec::Vec, H160, H256, U256};
7+
8+
sp_api::decl_runtime_apis! {
9+
/// Runtime API for the EVM tracing logic.
10+
pub trait EvmTracingApi {
11+
/// Trace transaction.
12+
fn trace_transaction(
13+
extrinsics: Vec<Block::Extrinsic>,
14+
transaction: &Transaction,
15+
header: &Block::Header,
16+
) -> Result<(), sp_runtime::DispatchError>;
17+
18+
/// Trace block.
19+
fn trace_block(
20+
extrinsics: Vec<Block::Extrinsic>,
21+
known_transactions: Vec<H256>,
22+
header: &Block::Header,
23+
) -> Result<(), sp_runtime::DispatchError>;
24+
25+
/// Trace call execution.
26+
// Allow too many arguments to pass them in the way used at EVM runner call.
27+
#[allow(clippy::too_many_arguments)]
28+
fn trace_call(
29+
header: &Block::Header,
30+
from: H160,
31+
to: H160,
32+
data: Vec<u8>,
33+
value: U256,
34+
gas_limit: U256,
35+
max_fee_per_gas: Option<U256>,
36+
max_priority_fee_per_gas: Option<U256>,
37+
nonce: Option<U256>,
38+
access_list: Option<Vec<(H160, Vec<H256>)>>,
39+
) -> Result<(), sp_runtime::DispatchError>;
40+
}
41+
}

crates/humanode-peer/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ humanode-rpc = { path = "../humanode-rpc" }
2020
humanode-runtime = { path = "../humanode-runtime" }
2121
keystore-bioauth-account-id = { path = "../keystore-bioauth-account-id" }
2222
ngrok-api = { path = "../ngrok-api" }
23+
primitives-evm-tracing-ext = { path = "../primitives-evm-tracing-ext" }
2324
robonode-client = { path = "../robonode-client" }
2425

2526
async-trait = { workspace = true }

crates/humanode-peer/src/service/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,13 @@ pub struct ExecutorDispatch;
3333
impl sc_executor::NativeExecutionDispatch for ExecutorDispatch {
3434
/// Only enable the benchmarking host functions when we actually want to benchmark.
3535
#[cfg(feature = "runtime-benchmarks")]
36-
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
36+
type ExtendHostFunctions = (
37+
frame_benchmarking::benchmarking::HostFunctions,
38+
primitives_evm_tracing_ext::evm_tracing_ext::HostFunctions,
39+
);
3740
/// Otherwise we only use the default Substrate host functions.
3841
#[cfg(not(feature = "runtime-benchmarks"))]
39-
type ExtendHostFunctions = ();
42+
type ExtendHostFunctions = (primitives_evm_tracing_ext::evm_tracing_ext::HostFunctions,);
4043

4144
fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
4245
humanode_runtime::api::dispatch(method, data)

crates/humanode-runtime/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ eip712-account-claim = { path = "../eip712-account-claim", default-features = fa
1717
eip712-common = { path = "../eip712-common", default-features = false }
1818
eip712-token-claim = { path = "../eip712-token-claim", default-features = false }
1919
evm-nonces-recovery = { path = "../evm-nonces-recovery", default-features = false }
20+
evm-tracer = { path = "../evm-tracer", default-features = false, optional = true }
21+
evm-tracing-api = { path = "../evm-tracing-api", default-features = false }
2022
keystore-bioauth-account-id = { path = "../keystore-bioauth-account-id", default-features = false }
2123
pallet-balanced-currency-swap-bridges-initializer = { path = "../pallet-balanced-currency-swap-bridges-initializer", default-features = false }
2224
pallet-bioauth = { path = "../pallet-bioauth", default-features = false }
@@ -155,6 +157,8 @@ std = [
155157
"eip712-token-claim/std",
156158
"ethereum/std",
157159
"evm-nonces-recovery/std",
160+
"evm-tracer/std",
161+
"evm-tracing-api/std",
158162
"fp-evm/std",
159163
"fp-rpc/std",
160164
"fp-self-contained/std",

0 commit comments

Comments
 (0)