feat(debug_traceTransaction): initial commit (#1469)

* 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>
This commit is contained in:
wren 2022-07-24 17:46:38 -04:00 committed by GitHub
parent d22fb2bd0b
commit cb7e586645
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 94 additions and 5 deletions

View File

@ -4,6 +4,7 @@
### Unreleased ### 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) - 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) - 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) - Allow configuration of the output directory of the generated `BuildInfo` [#1433](https://github.com/gakonst/ethers-rs/pull/1433)

View File

@ -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>,
}

View File

@ -8,6 +8,9 @@ use std::collections::BTreeMap;
mod filter; mod filter;
pub use filter::*; pub use filter::*;
mod geth;
pub use geth::*;
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
/// Description of the type of trace to make /// Description of the type of trace to make
pub enum TraceType { pub enum TraceType {

View File

@ -510,6 +510,17 @@ pub trait Middleware: Sync + Send + Debug {
self.inner().txpool_status().await.map_err(FromErr::from) 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 // Parity `trace` support
/// Executes the given call and returns a number of possible traces for it /// Executes the given call and returns a number of possible traces for it

View File

@ -22,9 +22,9 @@ use ethers_core::{
types::{ types::{
transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed}, transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed},
Address, Block, BlockId, BlockNumber, BlockTrace, Bytes, EIP1186ProofResponse, FeeHistory, Address, Block, BlockId, BlockNumber, BlockTrace, Bytes, EIP1186ProofResponse, FeeHistory,
Filter, FilterBlockOption, Log, NameOrAddress, Selector, Signature, Trace, TraceFilter, Filter, FilterBlockOption, GethDebugTracingOptions, GethTrace, Log, NameOrAddress,
TraceType, Transaction, TransactionReceipt, TransactionRequest, TxHash, TxpoolContent, Selector, Signature, Trace, TraceFilter, TraceType, Transaction, TransactionReceipt,
TxpoolInspect, TxpoolStatus, H256, U256, U64, TransactionRequest, TxHash, TxpoolContent, TxpoolInspect, TxpoolStatus, H256, U256, U64,
}, },
utils, utils,
}; };
@ -1021,6 +1021,17 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
self.request("txpool_status", ()).await 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 /// Executes the given call and returns a number of possible traces for it
async fn trace_call<T: Into<TypedTransaction> + Send + Sync>( async fn trace_call<T: Into<TypedTransaction> + Send + Sync>(
&self, &self,
@ -1243,12 +1254,12 @@ impl<P: JsonRpcClient> Provider<P> {
// otherwise, decode_bytes panics // otherwise, decode_bytes panics
if data.0.is_empty() { 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); let resolver_address: Address = decode_bytes(ParamType::Address, data);
if resolver_address == Address::zero() { if resolver_address == Address::zero() {
return Err(ProviderError::EnsError(ens_name.to_owned())) return Err(ProviderError::EnsError(ens_name.to_string()))
} }
// resolve // resolve

View File

@ -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(())
}