Skip to content

Commit

Permalink
feat: add support for js tracer to geth trace, fix different return t…
Browse files Browse the repository at this point in the history
…ypes (#2064)

* feat: add support for js tracer to geth trace, fix different return types

* chore: fix clippy

* chore: update geth structs
  • Loading branch information
Vid201 committed Jan 31, 2023
1 parent 969c10a commit 7e7f904
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Unreleased

- Add support for custom JavaScript tracer to `debug_traceCall` and `debug_traceTransaction` [#2064](https://github.com/gakonst/ethers-rs/pull/2064)
- Add a `Send` bound to the `IntoFuture` implementation of `ContractCall` [#2083](https://github.com/gakonst/ethers-rs/pull/2083)
- Bump [`svm-rs`](https://github.com/roynalnaruto/svm-rs) dependency to fix conflicts with Rust Crytpo packages [#2051](https://github.com/gakonst/ethers-rs/pull/2051)
- Avoid unnecessary allocations in `utils` [#2046](https://github.com/gakonst/ethers-rs/pull/2046)
Expand Down
80 changes: 61 additions & 19 deletions ethers-core/src/types/trace/geth.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
use crate::{
types::{Bytes, H256, U256},
types::{Address, Bytes, NameOrAddress, H256, U256},
utils::from_int_or_hex,
};
use serde::{Deserialize, Serialize, Serializer};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::BTreeMap;

// https://github.com/ethereum/go-ethereum/blob/a9ef135e2dd53682d106c6a2aede9187026cc1de/eth/tracers/logger/logger.go#L406-L411
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct GethTrace {
pub struct DefaultFrame {
pub failed: bool,
#[serde(deserialize_with = "from_int_or_hex")]
pub gas: U256,
#[serde(serialize_with = "serialize_bytes", rename = "returnValue")]
#[serde(rename = "returnValue")]
pub return_value: Bytes,
#[serde(rename = "structLogs")]
pub struct_logs: Vec<StructLog>,
Expand All @@ -21,34 +22,83 @@ pub struct GethTrace {
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct StructLog {
pub depth: u64,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
pub gas: u64,
#[serde(rename = "gasCost")]
pub gas_cost: u64,
/// ref <https://github.com/ethereum/go-ethereum/blob/366d2169fbc0e0f803b68c042b77b6b480836dbc/eth/tracers/logger/logger.go#L450-L452>
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub memory: Option<Vec<String>>,
pub op: String,
pub pc: u64,
#[serde(rename = "refund", skip_serializing_if = "Option::is_none")]
#[serde(default, rename = "refund", skip_serializing_if = "Option::is_none")]
pub refund_counter: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stack: Option<Vec<U256>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub storage: Option<BTreeMap<H256, H256>>,
}

// https://github.com/ethereum/go-ethereum/blob/a9ef135e2dd53682d106c6a2aede9187026cc1de/eth/tracers/native/call.go#L37
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct CallFrame {
#[serde(rename = "type")]
pub typ: String,
pub from: Address,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub to: Option<NameOrAddress>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub value: Option<U256>,
#[serde(deserialize_with = "from_int_or_hex")]
pub gas: U256,
#[serde(deserialize_with = "from_int_or_hex", rename = "gasUsed")]
pub gas_used: U256,
pub input: Bytes,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub output: Option<Bytes>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub calls: Option<Vec<CallFrame>>,
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum GethTraceFrame {
Default(DefaultFrame),
CallTracer(CallFrame),
}

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum GethTrace {
Known(GethTraceFrame),
Unknown(Value),
}

/// Available built-in tracers
///
/// See <https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers>
pub enum GethDebugTracerType {
/// callTracer (native)
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub enum GethDebugBuiltInTracerType {
#[serde(rename = "callTracer")]
CallTracer,
}

/// Available tracers
///
/// See <https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers> and <https://geth.ethereum.org/docs/developers/evm-tracing/custom-tracer>
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(untagged)]
pub enum GethDebugTracerType {
/// built-in tracer
BuiltInTracer(GethDebugBuiltInTracerType),

/// custom JS tracer
JsTracer(String),
}

/// Bindings for additional `debug_traceTransaction` options
///
/// See <https://geth.ethereum.org/docs/rpc/ns-debug#debug_tracetransaction>
Expand Down Expand Up @@ -79,11 +129,3 @@ pub struct GethDebugTracingCallOptions {
pub tracing_options: GethDebugTracingOptions,
// TODO: Add stateoverrides and blockoverrides options
}

fn serialize_bytes<S, T>(x: T, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<[u8]>,
{
s.serialize_str(&hex::encode(x.as_ref()))
}
22 changes: 0 additions & 22 deletions examples/transactions/examples/trace.rs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
use ethers::prelude::*;
use ethers::{
core::types::GethDebugTracingOptions,
providers::{Http, Middleware, Provider},
types::{
Address, BlockId, Bytes, GethDebugBuiltInTracerType, GethDebugTracerType,
GethDebugTracingCallOptions, TransactionRequest,
},
};
use eyre::Result;
use std::str::FromStr;

Expand All @@ -14,7 +21,9 @@ async fn main() -> Result<()> {
tracing_options: GethDebugTracingOptions {
disable_storage: Some(true),
enable_memory: Some(false),
tracer: Some(GethDebugTracerType::CallTracer),
tracer: Some(GethDebugTracerType::BuiltInTracer(
GethDebugBuiltInTracerType::CallTracer,
)),
..Default::default()
},
};
Expand Down
47 changes: 47 additions & 0 deletions examples/transactions/examples/trace_transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use ethers::{
core::types::{GethDebugTracingOptions, H256},
providers::{Http, Middleware, Provider},
types::{GethDebugBuiltInTracerType, GethDebugTracerType},
};
use eyre::Result;
use std::str::FromStr;

/// use `debug_traceTransaction` to fetch traces
/// requires, a valid endpoint in `RPC_URL` env var that supports `debug_traceTransaction`
#[tokio::main]
async fn main() -> Result<()> {
if let Ok(url) = std::env::var("RPC_URL") {
let client = Provider::<Http>::try_from(url)?;
let tx_hash = "0x97a02abf405d36939e5b232a5d4ef5206980c5a6661845436058f30600c52df7";
let h: H256 = H256::from_str(tx_hash)?;

// default tracer
let options = GethDebugTracingOptions::default();
let traces = client.debug_trace_transaction(h, options).await?;
println!("{traces:?}");

// call tracer
let options = GethDebugTracingOptions {
disable_storage: Some(true),
enable_memory: Some(false),
tracer: Some(GethDebugTracerType::BuiltInTracer(
GethDebugBuiltInTracerType::CallTracer,
)),
..Default::default()
};
let traces = client.debug_trace_transaction(h, options).await?;
println!("{traces:?}");

// js tracer
let options = GethDebugTracingOptions {
disable_storage: Some(true),
enable_memory: Some(false),
tracer: Some(GethDebugTracerType::JsTracer(String::from("{data: [], fault: function(log) {}, step: function(log) { if(log.op.toString() == \"DELEGATECALL\") this.data.push(log.stack.peek(0)); }, result: function() { return this.data; }}"))),
..Default::default()
};
let traces = client.debug_trace_transaction(h, options).await?;
println!("{traces:?}");
}

Ok(())
}

0 comments on commit 7e7f904

Please sign in to comment.