feat: debug_traceCall (#1949)
* feat: debug_traceCall * chore: update changelog * fix: rebase to master and change tracer from string to enum
This commit is contained in:
parent
2e32528292
commit
b27c7b0773
|
@ -4,8 +4,8 @@
|
|||
|
||||
### Unreleased
|
||||
|
||||
-
|
||||
- Fix typo in `RwClient` docs for `write_client` method.
|
||||
- Add support for Geth `debug_traceCall` [#1949](https://github.com/gakonst/ethers-rs/pull/1949)
|
||||
- Graceful handling of WebSocket transport errors [#1889](https://github.com/gakonst/ethers-rs/issues/1889) [#1815](https://github.com/gakonst/ethers-rs/issues/1815)
|
||||
- `MiddlewareBuilder` trait to instantiate a `Provider` as `Middleware` layers.
|
||||
- An `Event` builder can be instantiated specifying the event filter type, without the need to instantiate a contract.
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use crate::types::{Bytes, H256, U256};
|
||||
use crate::{
|
||||
types::{Bytes, H256, U256},
|
||||
utils::from_int_or_hex,
|
||||
};
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
|
@ -6,7 +9,8 @@ use std::collections::BTreeMap;
|
|||
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct GethTrace {
|
||||
pub failed: bool,
|
||||
pub gas: u64,
|
||||
#[serde(deserialize_with = "from_int_or_hex")]
|
||||
pub gas: U256,
|
||||
#[serde(serialize_with = "serialize_bytes", rename = "returnValue")]
|
||||
pub return_value: Bytes,
|
||||
#[serde(rename = "structLogs")]
|
||||
|
@ -35,6 +39,16 @@ pub struct StructLog {
|
|||
pub storage: Option<BTreeMap<H256, H256>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
|
||||
/// Available built-in tracers
|
||||
///
|
||||
/// See <https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers>
|
||||
pub enum GethDebugTracerType {
|
||||
/// callTracer (native)
|
||||
#[serde(rename = "callTracer")]
|
||||
CallTracer,
|
||||
}
|
||||
|
||||
/// Bindings for additional `debug_traceTransaction` options
|
||||
///
|
||||
/// See <https://geth.ethereum.org/docs/rpc/ns-debug#debug_tracetransaction>
|
||||
|
@ -50,11 +64,22 @@ pub struct GethDebugTracingOptions {
|
|||
#[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>,
|
||||
pub tracer: Option<GethDebugTracerType>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub timeout: Option<String>,
|
||||
}
|
||||
|
||||
/// Bindings for additional `debug_traceCall` options
|
||||
///
|
||||
/// See <https://geth.ethereum.org/docs/rpc/ns-debug#debug_tracecall>
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GethDebugTracingCallOptions {
|
||||
#[serde(flatten)]
|
||||
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,
|
||||
|
|
|
@ -31,7 +31,7 @@ tracing = { version = "0.1.37", default-features = false }
|
|||
tracing-futures = { version = "0.2.5", default-features = false }
|
||||
|
||||
# for gas oracles
|
||||
reqwest = { version = "0.11.13", default-features = false, features = ["json"] }
|
||||
reqwest = { version = "0.11.13", default-features = false, features = ["json", "rustls-tls"] }
|
||||
url = { version = "2.3.1", default-features = false }
|
||||
|
||||
serde_json = { version = "1.0.64", default-features = false }
|
||||
|
|
|
@ -540,6 +540,7 @@ pub trait Middleware: Sync + Send + Debug {
|
|||
}
|
||||
|
||||
// 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(
|
||||
|
@ -550,6 +551,16 @@ pub trait Middleware: Sync + Send + Debug {
|
|||
self.inner().debug_trace_transaction(tx_hash, trace_options).await.map_err(FromErr::from)
|
||||
}
|
||||
|
||||
/// Executes the given call and returns a number of possible traces for it
|
||||
async fn debug_trace_call<T: Into<TypedTransaction> + Send + Sync>(
|
||||
&self,
|
||||
req: T,
|
||||
block: Option<BlockId>,
|
||||
trace_options: GethDebugTracingCallOptions,
|
||||
) -> Result<GethTrace, ProviderError> {
|
||||
self.inner().debug_trace_call(req, block, trace_options).await.map_err(FromErr::from)
|
||||
}
|
||||
|
||||
// Parity `trace` support
|
||||
|
||||
/// Executes the given call and returns a number of possible traces for it
|
||||
|
|
|
@ -22,9 +22,10 @@ use ethers_core::{
|
|||
types::{
|
||||
transaction::{eip2718::TypedTransaction, eip2930::AccessListWithGasUsed},
|
||||
Address, Block, BlockId, BlockNumber, BlockTrace, Bytes, EIP1186ProofResponse, FeeHistory,
|
||||
Filter, FilterBlockOption, GethDebugTracingOptions, GethTrace, Log, NameOrAddress,
|
||||
Selector, Signature, Trace, TraceFilter, TraceType, Transaction, TransactionReceipt,
|
||||
TransactionRequest, TxHash, TxpoolContent, TxpoolInspect, TxpoolStatus, H256, U256, U64,
|
||||
Filter, FilterBlockOption, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace,
|
||||
Log, NameOrAddress, Selector, Signature, Trace, TraceFilter, TraceType, Transaction,
|
||||
TransactionReceipt, TransactionRequest, TxHash, TxpoolContent, TxpoolInspect, TxpoolStatus,
|
||||
H256, U256, U64,
|
||||
},
|
||||
utils,
|
||||
};
|
||||
|
@ -1048,6 +1049,20 @@ impl<P: JsonRpcClient> Middleware for Provider<P> {
|
|||
self.request("debug_traceTransaction", [tx_hash, trace_options]).await
|
||||
}
|
||||
|
||||
/// Executes the given call and returns a number of possible traces for it
|
||||
async fn debug_trace_call<T: Into<TypedTransaction> + Send + Sync>(
|
||||
&self,
|
||||
req: T,
|
||||
block: Option<BlockId>,
|
||||
trace_options: GethDebugTracingCallOptions,
|
||||
) -> Result<GethTrace, ProviderError> {
|
||||
let req = req.into();
|
||||
let req = utils::serialize(&req);
|
||||
let block = utils::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into()));
|
||||
let trace_options = utils::serialize(&trace_options);
|
||||
self.request("debug_traceCall", [req, block, 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,
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
use ethers::prelude::*;
|
||||
use eyre::Result;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// use `debug_traceCall` to fetch traces
|
||||
/// requires, a valid endpoint in `RPC_URL` env var that supports `debug_traceCall`
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
if let Ok(url) = std::env::var("RPC_URL") {
|
||||
let client = Provider::<Http>::try_from(url)?;
|
||||
let tx = TransactionRequest::new().from(Address::from_str("0xdeadbeef29292929192939494959594933929292").unwrap()).to(Address::from_str("0xde929f939d939d393f939393f93939f393929023").unwrap()).gas("0x7a120").data(Bytes::from_str("0xf00d4b5d00000000000000000000000001291230982139282304923482304912923823920000000000000000000000001293123098123928310239129839291010293810").unwrap());
|
||||
let block = BlockId::from(16213100);
|
||||
let options: GethDebugTracingCallOptions = GethDebugTracingCallOptions {
|
||||
tracing_options: GethDebugTracingOptions {
|
||||
disable_storage: Some(true),
|
||||
enable_memory: Some(false),
|
||||
tracer: Some(GethDebugTracerType::CallTracer),
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
let traces = client.debug_trace_call(tx, Some(block), options).await?;
|
||||
println!("{traces:?}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Reference in New Issue