Skip to content

Commit 222ee96

Browse files
Runtime level implementation
1 parent 1a7c611 commit 222ee96

File tree

18 files changed

+1423
-3
lines changed

18 files changed

+1423
-3
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+
evm-tracing-events = { path = "../evm-tracing-events", default-features = false, features = ["evm-tracing"] }
9+
evm-tracing-host-api = { path = "../evm-tracing-host-api", 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-tracing-events/std",
24+
"evm-tracing-host-api/std",
25+
"evm/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 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: evm_tracing_host_api::externalities::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+
evm_tracing_host_api::externalities::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+
evm_tracing_host_api::externalities::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+
evm_tracing_host_api::externalities::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+
evm_tracing_host_api::externalities::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+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[package]
2+
name = "evm-tracing-events"
3+
version = "0.1.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[dependencies]
8+
codec = { workspace = true }
9+
environmental = { workspace = true }
10+
evm = { workspace = true, features = ["with-codec"] }
11+
evm-gasometer = { workspace = true }
12+
evm-runtime = { workspace = true }
13+
sp-core = { workspace = true }
14+
sp-runtime-interface = { workspace = true }
15+
16+
[features]
17+
default = ["std"]
18+
evm-tracing = [
19+
"evm-gasometer/tracing",
20+
"evm-runtime/tracing",
21+
"evm/tracing",
22+
]
23+
std = [
24+
"codec/std",
25+
"environmental/std",
26+
"evm-gasometer/std",
27+
"evm-runtime/std",
28+
"evm/std",
29+
"sp-core/std",
30+
"sp-runtime-interface/std",
31+
]

0 commit comments

Comments
 (0)