Skip to content
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
5166496
Add CI check for build with evm-tracing feature
dmitrylavrenov Jun 20, 2025
d21ad4a
Add evm-tracing feature to humanode-runtime
dmitrylavrenov Jun 20, 2025
898bbcd
[evm-tracing-0] add evm-tracing test suite to e2e ts tests (#1574)
dmitrylavrenov Jul 28, 2025
26f05be
[evm-tracing-0-1] add debug e2e tests logic implementation (#1575)
dmitrylavrenov Aug 26, 2025
85f0c70
[evm-tracing-1] runtime level implementation (#1544)
dmitrylavrenov Aug 28, 2025
898b7b0
[evm-tracing-2] сlient-side implementation (#1565)
dmitrylavrenov Sep 16, 2025
580f661
[evm-tracing-3] implement RPC side (#1568)
dmitrylavrenov Oct 1, 2025
587685a
[evm-tracing-4] cli part implementation (#1572)
dmitrylavrenov Oct 7, 2025
a08006e
[evm-tracing] Add more e2e tests (#1622)
dmitrylavrenov Oct 31, 2025
e47ffbe
Imporve opcode type usage by reusing evm::Opcode
dmitrylavrenov Oct 31, 2025
27a4cf2
Fix serialization implementation
dmitrylavrenov Oct 31, 2025
67181fd
Remove unused features
dmitrylavrenov Oct 31, 2025
3025cc5
Rename is_known_opcode to opcode_known_name
dmitrylavrenov Nov 4, 2025
e661328
Use as_u8() for getting opcode byte value
dmitrylavrenov Nov 4, 2025
c238ca6
Introduce marshalled opcode type
dmitrylavrenov Nov 7, 2025
ac78782
Implement encoding and decoding through a Vec for MarshalledOpcode
dmitrylavrenov Nov 8, 2025
357c9d9
Use a string representation for opcode
dmitrylavrenov Nov 10, 2025
a69d4d6
Return Error for Display
dmitrylavrenov Nov 13, 2025
3af03cb
Avoid using intermediate way to do opcode to string
dmitrylavrenov Nov 13, 2025
ce000a6
Return opcode_known_name to original place
dmitrylavrenov Nov 13, 2025
9659a59
Use cow instead of vec
dmitrylavrenov Nov 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/actions/plan/modes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ export const code = {
cargoArgs: "--locked --workspace --features try-runtime",
cargoCacheKey: "try-runtime",
},
buildEvmTracing: {
name: "build with evm-tracing",
cargoCommand: "build",
cargoArgs: "--locked --workspace --features evm-tracing",
cargoCacheKey: "evm-tracing",
},
} satisfies Modes;

export const build = {
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ jobs:
- suite: "try-runtime"
build-args: "--features try-runtime"
skip-ts-tests: true
- suite: "evm-tracing"
build-args: "--features evm-tracing"
skip-bash-tests: true
fail-fast: false
name: End-to-end tests / ${{ matrix.test.suite }}
runs-on: ubuntu-24.04
Expand Down
109 changes: 104 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@ bytes = { version = "1", default-features = false }
chrono = { version = "0.4", default-features = false }
clap = { version = "4", default-features = false }
ed25519-dalek = { version = "2", default-features = false }
environmental = { version = "1.1", default-features = false }
ethereum = { version = "0.14", default-features = false }
ethers-core = { version = "2.0.14", default-features = false }
evm = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false }
evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false }
evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false }
fdlimit = { version = "0.2", default-features = false }
futures = { version = "0.3", default-features = false }
getrandom = { version = "0.3", default-features = false }
Expand Down Expand Up @@ -55,6 +58,7 @@ serde = { version = "1", default-features = false }
serde_json = { version = "1", default-features = false }
sha3 = { version = "0.10", default-features = false }
similar-asserts = { version = "1", default-features = false }
smallvec = { version = "1.13", default-features = false }
static_assertions = { version = "1", default-features = false }
syn = { version = "2", default-features = false }
thiserror = { version = "1.0.69", default-features = false }
Expand Down Expand Up @@ -132,6 +136,7 @@ sp-keystore = { git = "https://github.com/humanode-network/substrate", tag = "lo
sp-offchain = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
sp-panic-handler = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
sp-runtime = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
sp-runtime-interface = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
sp-session = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
sp-staking = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
sp-std = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
Expand All @@ -140,6 +145,7 @@ sp-tracing = { git = "https://github.com/humanode-network/substrate", tag = "loc
sp-transaction-pool = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
sp-version = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
substrate-frame-rpc-system = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
substrate-prometheus-endpoint = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
substrate-wasm-builder = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }
try-runtime-cli = { git = "https://github.com/humanode-network/substrate", tag = "locked/polkadot-v0.9.43-2025-03-22", default-features = false }

Expand Down
27 changes: 27 additions & 0 deletions crates/evm-tracer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "evm-tracer"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
evm-tracing-events = { path = "../evm-tracing-events", default-features = false, features = ["evm-tracing"] }
evm-tracing-host-api = { path = "../evm-tracing-host-api", default-features = false }

codec = { workspace = true, features = ["derive"] }
evm = { workspace = true, features = ["tracing"] }
evm-gasometer = { workspace = true, features = ["tracing"] }
evm-runtime = { workspace = true, features = ["tracing"] }
sp-std = { workspace = true }

[features]
default = ["std"]
std = [
"codec/std",
"evm-gasometer/std",
"evm-runtime/std",
"evm-tracing-events/std",
"evm-tracing-host-api/std",
"evm/std",
"sp-std/std",
]
98 changes: 98 additions & 0 deletions crates/evm-tracer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//! Substrate EVM tracer.
//!
//! Enables tracing the EVM opcode execution and proxies EVM messages to the host functions.

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

use codec::Encode;
use evm::tracing::{using as evm_using, EventListener as EvmListener};
use evm_gasometer::tracing::{using as gasometer_using, EventListener as GasometerListener};
use evm_runtime::tracing::{using as runtime_using, EventListener as RuntimeListener};
use evm_tracing_events::{EvmEvent, GasometerEvent, RuntimeEvent, StepEventFilter};
use sp_std::{cell::RefCell, rc::Rc};

/// Listener proxy.
struct ListenerProxy<T>(pub Rc<RefCell<T>>);

impl<T: GasometerListener> GasometerListener for ListenerProxy<T> {
fn event(&mut self, event: evm_gasometer::tracing::Event) {
self.0.borrow_mut().event(event);
}
}

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

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

/// EVM tracer.
pub struct EvmTracer {
/// Step event filter.
step_event_filter: StepEventFilter,
}

impl Default for EvmTracer {
fn default() -> Self {
Self {
step_event_filter: evm_tracing_host_api::externalities::step_event_filter(),
}
}
}

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

let mut gasometer = ListenerProxy(Rc::clone(&wrapped));
let mut runtime = ListenerProxy(Rc::clone(&wrapped));
let mut evm = ListenerProxy(Rc::clone(&wrapped));

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

/// Emit new call stack.
pub fn emit_new() {
evm_tracing_host_api::externalities::call_list_new();
}
}

impl EvmListener for EvmTracer {
fn event(&mut self, event: evm::tracing::Event) {
let event: EvmEvent = event.into();
let message = event.encode();
evm_tracing_host_api::externalities::evm_event(message);
}
}

impl GasometerListener for EvmTracer {
fn event(&mut self, event: evm_gasometer::tracing::Event) {
let event: GasometerEvent = event.into();
let message = event.encode();
evm_tracing_host_api::externalities::gasometer_event(message);
}
}

impl RuntimeListener for EvmTracer {
fn event(&mut self, event: evm_runtime::tracing::Event) {
let event = RuntimeEvent::from_evm_event(event, self.step_event_filter);
let message = event.encode();
evm_tracing_host_api::externalities::runtime_event(message);
}
}
20 changes: 20 additions & 0 deletions crates/evm-tracing-api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "evm-tracing-api"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
ethereum = { workspace = true, features = ["with-codec"] }
sp-api = { workspace = true }
sp-core = { workspace = true }
sp-runtime = { workspace = true }

[features]
default = ["std"]
std = [
"ethereum/std",
"sp-api/std",
"sp-core/std",
"sp-runtime/std",
]
Loading
Loading