Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
feat(debug_traceTransaction): initial commit (#1469)
Browse files Browse the repository at this point in the history
* feat(debug_traceTransaction): initial commit

* chore(changelog): updated changelog

* feat(debug_traceTransaction): type adjusments

* feat(debug_traceTransaction): type adjusments

* Update ethers-providers/src/provider.rs

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>

* Update ethers-providers/src/provider.rs

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>

* chore(format): cargo +nightly fmt

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
  • Loading branch information
3 people authored Jul 24, 2022
1 parent d22fb2b commit cb7e586
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 5 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 Geth `debug_traceTransaction` [#1469](https://github.com/gakonst/ethers-rs/pull/1469)
- Use correct, new transaction type for `typool_content` RPC endpoint [#1501](https://github.com/gakonst/ethers-rs/pull/1501)
- Fix the default config for generated `BuildInfo` [#1458](https://github.com/gakonst/ethers-rs/pull/1458)
- Allow configuration of the output directory of the generated `BuildInfo` [#1433](https://github.com/gakonst/ethers-rs/pull/1433)
Expand Down
47 changes: 47 additions & 0 deletions ethers-core/src/types/trace/geth.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use crate::types::{Bytes, H256, U256};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

#[derive(Serialize, Deserialize, Debug)]
pub struct GethTrace {
failed: bool,
gas: u64,
#[serde(rename = "returnValue")]
return_value: Bytes,
#[serde(rename = "structLogs")]
struct_logs: Vec<StructLog>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct StructLog {
depth: u64,
error: Option<String>,
gas: u64,
#[serde(rename = "gasCost")]
gas_cost: u64,
memory: Option<Vec<String>>,
op: String,
pc: U256,
stack: Vec<String>,
storage: BTreeMap<H256, H256>,
}

/// Bindings for additional `debug_traceTransaction` options
///
/// See <https://geth.ethereum.org/docs/rpc/ns-debug#debug_tracetransaction>
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct GethDebugTracingOptions {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub disable_storage: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub disable_stack: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub enable_memory: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub enable_return_data: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tracer: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub timeout: Option<String>,
}
3 changes: 3 additions & 0 deletions ethers-core/src/types/trace/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ use std::collections::BTreeMap;
mod filter;
pub use filter::*;

mod geth;
pub use geth::*;

#[derive(Debug, Clone, Serialize)]
/// Description of the type of trace to make
pub enum TraceType {
Expand Down
11 changes: 11 additions & 0 deletions ethers-providers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,17 @@ pub trait Middleware: Sync + Send + Debug {
self.inner().txpool_status().await.map_err(FromErr::from)
}

// Geth `trace` support
/// After replaying any previous transactions in the same block,
/// Replays a transaction, returning the traces configured with passed options
async fn debug_trace_transaction(
&self,
tx_hash: TxHash,
trace_options: GethDebugTracingOptions,
) -> Result<GethTrace, ProviderError> {
self.inner().debug_trace_transaction(tx_hash, trace_options).await.map_err(FromErr::from)
}

// Parity `trace` support

/// Executes the given call and returns a number of possible traces for it
Expand Down
21 changes: 16 additions & 5 deletions ethers-providers/src/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ use ethers_core::{
types::{
transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed},
Address, Block, BlockId, BlockNumber, BlockTrace, Bytes, EIP1186ProofResponse, FeeHistory,
Filter, FilterBlockOption, Log, NameOrAddress, Selector, Signature, Trace, TraceFilter,
TraceType, Transaction, TransactionReceipt, TransactionRequest, TxHash, TxpoolContent,
TxpoolInspect, TxpoolStatus, H256, U256, U64,
Filter, FilterBlockOption, GethDebugTracingOptions, GethTrace, Log, NameOrAddress,
Selector, Signature, Trace, TraceFilter, TraceType, Transaction, TransactionReceipt,
TransactionRequest, TxHash, TxpoolContent, TxpoolInspect, TxpoolStatus, H256, U256, U64,
},
utils,
};
Expand Down Expand Up @@ -1021,6 +1021,17 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
self.request("txpool_status", ()).await
}

/// Executes the given call and returns a number of possible traces for it
async fn debug_trace_transaction(
&self,
tx_hash: TxHash,
trace_options: GethDebugTracingOptions,
) -> Result<GethTrace, ProviderError> {
let tx_hash = utils::serialize(&tx_hash);
let trace_options = utils::serialize(&trace_options);
self.request("debug_traceTransaction", [tx_hash, trace_options]).await
}

/// Executes the given call and returns a number of possible traces for it
async fn trace_call<T: Into<TypedTransaction> + Send + Sync>(
&self,
Expand Down Expand Up @@ -1243,12 +1254,12 @@ impl<P: JsonRpcClient> Provider<P> {

// otherwise, decode_bytes panics
if data.0.is_empty() {
return Err(ProviderError::EnsError(ens_name.to_owned()))
return Err(ProviderError::EnsError(ens_name.to_string()))
}

let resolver_address: Address = decode_bytes(ParamType::Address, data);
if resolver_address == Address::zero() {
return Err(ProviderError::EnsError(ens_name.to_owned()))
return Err(ProviderError::EnsError(ens_name.to_string()))
}

// resolve
Expand Down
16 changes: 16 additions & 0 deletions examples/geth_trace_transaction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use ethers::prelude::*;
use eyre::Result;
use std::{env, str::FromStr};

#[tokio::main]
async fn main() -> Result<()> {
let rpc_url: String = env::var("RPC_URL")?;
let client = Provider::<Http>::try_from(rpc_url)?;
let tx_hash = "0x97a02abf405d36939e5b232a5d4ef5206980c5a6661845436058f30600c52df7";
let h: H256 = H256::from_str(tx_hash)?;
let options: GethDebugTracingOptions = GethDebugTracingOptions::default();
let traces = client.debug_trace_transaction(h, options).await?;
println!("{:?}", traces);

Ok(())
}

0 comments on commit cb7e586

Please sign in to comment.