Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
49 changes: 49 additions & 0 deletions Cargo.lock

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

4 changes: 4 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 @@ -132,6 +135,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 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",
]
41 changes: 41 additions & 0 deletions crates/evm-tracing-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//! The runtime API for the EVM tracing logic.

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

use ethereum::TransactionV2 as Transaction;
use sp_core::{sp_std::vec::Vec, H160, H256, U256};

sp_api::decl_runtime_apis! {
/// Runtime API for the EVM tracing logic.
pub trait EvmTracingApi {
/// Trace transaction.
fn trace_transaction(
extrinsics: Vec<Block::Extrinsic>,
transaction: &Transaction,
header: &Block::Header,
) -> Result<(), sp_runtime::DispatchError>;

/// Trace block.
fn trace_block(
extrinsics: Vec<Block::Extrinsic>,
known_transactions: Vec<H256>,
header: &Block::Header,
) -> Result<(), sp_runtime::DispatchError>;

/// Trace call execution.
// Allow too many arguments to pass them in the way used at EVM runner call.
#[allow(clippy::too_many_arguments)]
fn trace_call(
header: &Block::Header,
from: H160,
to: H160,
data: Vec<u8>,
value: U256,
gas_limit: U256,
max_fee_per_gas: Option<U256>,
max_priority_fee_per_gas: Option<U256>,
nonce: Option<U256>,
access_list: Option<Vec<(H160, Vec<H256>)>>,
) -> Result<(), sp_runtime::DispatchError>;
}
}
31 changes: 31 additions & 0 deletions crates/evm-tracing-events/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "evm-tracing-events"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
codec = { workspace = true }
environmental = { workspace = true }
evm = { workspace = true, features = ["with-codec"] }
evm-gasometer = { workspace = true }
evm-runtime = { workspace = true }
sp-core = { workspace = true }
sp-runtime-interface = { workspace = true }

[features]
default = ["std"]
evm-tracing = [
"evm-gasometer/tracing",
"evm-runtime/tracing",
"evm/tracing",
]
std = [
"codec/std",
"environmental/std",
"evm-gasometer/std",
"evm-runtime/std",
"evm/std",
"sp-core/std",
"sp-runtime-interface/std",
]
Loading
Loading