diff --git a/CHANGELOG.md b/CHANGELOG.md index 7137a120..47862703 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/ethers-core/src/types/trace/geth.rs b/ethers-core/src/types/trace/geth.rs new file mode 100644 index 00000000..786099c9 --- /dev/null +++ b/ethers-core/src/types/trace/geth.rs @@ -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, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct StructLog { + depth: u64, + error: Option, + gas: u64, + #[serde(rename = "gasCost")] + gas_cost: u64, + memory: Option>, + op: String, + pc: U256, + stack: Vec, + storage: BTreeMap, +} + +/// Bindings for additional `debug_traceTransaction` options +/// +/// See +#[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, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub disable_stack: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub enable_memory: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub enable_return_data: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub tracer: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub timeout: Option, +} diff --git a/ethers-core/src/types/trace/mod.rs b/ethers-core/src/types/trace/mod.rs index 7a77e86e..437daadb 100644 --- a/ethers-core/src/types/trace/mod.rs +++ b/ethers-core/src/types/trace/mod.rs @@ -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 { diff --git a/ethers-providers/src/lib.rs b/ethers-providers/src/lib.rs index a977cf6f..da7cfa84 100644 --- a/ethers-providers/src/lib.rs +++ b/ethers-providers/src/lib.rs @@ -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 { + 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 diff --git a/ethers-providers/src/provider.rs b/ethers-providers/src/provider.rs index e01d67ce..9c9202be 100644 --- a/ethers-providers/src/provider.rs +++ b/ethers-providers/src/provider.rs @@ -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, }; @@ -1021,6 +1021,17 @@ impl Middleware for Provider

{ 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 { + 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 + Send + Sync>( &self, @@ -1243,12 +1254,12 @@ impl Provider

{ // 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 diff --git a/examples/geth_trace_transaction.rs b/examples/geth_trace_transaction.rs new file mode 100644 index 00000000..e76266e3 --- /dev/null +++ b/examples/geth_trace_transaction.rs @@ -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::::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(()) +}