Skip to content

Commit

Permalink
refactor: replace tracers with reth tracers (#6428)
Browse files Browse the repository at this point in the history
* wip

* wip

not working still -.-

- gas reports
- `forge script` cannot set `gas_used` for root
  trace since that requires mut access to the arena
- event decoding not impl

possibly broken

- anvil traces (not tested)
- test traces (not tested)
- debugging (not tested)

but hey, at least it compiles...

* wip

* chore: fix deps

* remove utils import

* chore: remove errors

* chore: use render_trace_arena

* derive debug

* fix contract identification

* fix formatting

* remove stray todo

* fix empty output

* fix unrelated test :)

---------

Co-authored-by: evalir <hi@enriqueortiz.dev>
  • Loading branch information
onbjerg and Evalir authored Dec 11, 2023
1 parent e8e926e commit a3150d5
Show file tree
Hide file tree
Showing 36 changed files with 1,241 additions and 1,068 deletions.
921 changes: 730 additions & 191 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ foundry-evm-traces = { path = "crates/evm/traces" }
foundry-macros = { path = "crates/macros" }
foundry-test-utils = { path = "crates/test-utils" }

# block explorer & verification bindings
foundry-block-explorers = { version = "0.1.1", default-features = false }
# solc & compilation utilities
foundry-compilers = { version = "0.1.1", default-features = false }

## revm
Expand Down Expand Up @@ -216,6 +218,6 @@ alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy/", branch = "onbje
alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy/", branch = "onbjerg/alloy-temp-provider-trait" }

revm = { git = "https://github.com/bluealloy/revm", branch = "reth_freeze" }
revm-interpreter = { git = "https://github.com/bluealloy/revm", branch = "reth_freeze" }
revm-precompile = { git = "https://github.com/bluealloy/revm", branch = "reth_freeze" }
revm-primitives = { git = "https://github.com/bluealloy/revm", branch = "reth_freeze" }
revm-interpreter = { git = "https://github.com/bluealloy/revm", branch = "reth_freeze" }
revm-precompile = { git = "https://github.com/bluealloy/revm", branch = "reth_freeze" }
2 changes: 2 additions & 0 deletions crates/anvil/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ alloy-primitives = { workspace = true, features = ["serde"] }
alloy-rpc-types.workspace = true
alloy-providers.workspace = true
alloy-transport.workspace = true
reth-rpc-types = { git = "https://github.com/paradigmxyz/reth/", branch = "main" }


# axum related
axum.workspace = true
Expand Down
1 change: 1 addition & 0 deletions crates/anvil/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ serde = { workspace = true, optional = true }
serde_json.workspace = true
bytes = { version = "1.4" }
open-fastrlp = { version = "0.1.4", optional = true }
reth-rpc-types = { git = "https://github.com/paradigmxyz/reth/", branch = "main" }

# trie
hash-db = { version = "0.15", default-features = false }
Expand Down
7 changes: 4 additions & 3 deletions crates/anvil/core/src/eth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use alloy_rpc_types::{
state::StateOverride,
BlockId, BlockNumberOrTag as BlockNumber, CallRequest, Filter,
};
use ethers_core::types::{transaction::eip712::TypedData, GethDebugTracingOptions};
use ethers_core::types::transaction::eip712::TypedData;
use reth_rpc_types::trace::geth::GethDefaultTracingOptions;

pub mod block;
pub mod proof;
Expand Down Expand Up @@ -261,15 +262,15 @@ pub enum EthRequest {
#[cfg_attr(feature = "serde", serde(rename = "debug_traceTransaction"))]
DebugTraceTransaction(
B256,
#[cfg_attr(feature = "serde", serde(default))] GethDebugTracingOptions,
#[cfg_attr(feature = "serde", serde(default))] GethDefaultTracingOptions,
),

/// geth's `debug_traceCall` endpoint
#[cfg_attr(feature = "serde", serde(rename = "debug_traceCall"))]
DebugTraceCall(
CallRequest,
#[cfg_attr(feature = "serde", serde(default))] Option<BlockId>,
#[cfg_attr(feature = "serde", serde(default))] GethDebugTracingOptions,
#[cfg_attr(feature = "serde", serde(default))] GethDefaultTracingOptions,
),

/// Trace transaction endpoint for parity's `trace_transaction`
Expand Down
39 changes: 2 additions & 37 deletions crates/anvil/core/src/eth/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use ethers_core::{
},
};
use foundry_common::types::ToAlloy;
use foundry_evm::traces::CallTraceArena;
use foundry_evm::traces::CallTraceNode;
use revm::{
interpreter::InstructionResult,
primitives::{CreateScheme, OptimismFields, TransactTo, TxEnv},
Expand Down Expand Up @@ -1513,47 +1513,12 @@ pub struct TransactionInfo {
pub contract_address: Option<Address>,
pub logs: Vec<Log>,
pub logs_bloom: Bloom,
pub traces: CallTraceArena,
pub traces: Vec<CallTraceNode>,
pub exit: InstructionResult,
pub out: Option<Bytes>,
pub nonce: u64,
}

// === impl TransactionInfo ===

impl TransactionInfo {
/// Returns the `traceAddress` of the node in the arena
///
/// The `traceAddress` field of all returned traces, gives the exact location in the call trace
/// [index in root, index in first CALL, index in second CALL, …].
///
/// # Panics
///
/// if the `idx` does not belong to a node
pub fn trace_address(&self, idx: usize) -> Vec<usize> {
if idx == 0 {
// root call has empty traceAddress
return vec![]
}
let mut graph = vec![];
let mut node = &self.traces.arena[idx];
while let Some(parent) = node.parent {
// the index of the child call in the arena
let child_idx = node.idx;
node = &self.traces.arena[parent];
// find the index of the child call in the parent node
let call_idx = node
.children
.iter()
.position(|child| *child == child_idx)
.expect("child exists in parent");
graph.push(call_idx);
}
graph.reverse();
graph
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
27 changes: 10 additions & 17 deletions crates/anvil/src/eth/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use alloy_rpc_types::{
TransactionReceipt,
TxpoolContent,
TxpoolInspect,
// trace::{geth::{DefaultFrame, GethDebugTracingOptions, GethTrace},
// trace::{geth::{DefaultFrame, GethDefaultTracingOptions, GethTrace},
// parity::LocalizedTransactionTrace},
TxpoolInspectSummary,
TxpoolStatus,
Expand All @@ -69,11 +69,7 @@ use anvil_core::{
},
};
use anvil_rpc::{error::RpcError, response::ResponseResult};
use ethers::{
prelude::DefaultFrame,
types::{transaction::eip712::TypedData, GethDebugTracingOptions, GethTrace, Trace},
utils::rlp,
};
use ethers::{types::transaction::eip712::TypedData, utils::rlp};
use foundry_common::{
provider::alloy::ProviderBuilder,
types::{ToAlloy, ToEthers},
Expand All @@ -88,6 +84,10 @@ use foundry_evm::{
};
use futures::channel::{mpsc::Receiver, oneshot};
use parking_lot::RwLock;
use reth_rpc_types::trace::{
geth::{DefaultFrame, GethDefaultTracingOptions, GethTrace},
parity::LocalizedTransactionTrace,
};
use std::{collections::HashSet, future::Future, sync::Arc, time::Duration};

/// The client version: `anvil/v{major}.{minor}.{patch}`
Expand Down Expand Up @@ -1456,13 +1456,9 @@ impl EthApi {
pub async fn debug_trace_transaction(
&self,
tx_hash: B256,
opts: GethDebugTracingOptions,
opts: GethDefaultTracingOptions,
) -> Result<GethTrace> {
node_info!("debug_traceTransaction");
if opts.tracer.is_some() {
return Err(RpcError::invalid_params("non-default tracer not supported yet").into());
}

self.backend.debug_trace_transaction(tx_hash, opts).await
}

Expand All @@ -1473,12 +1469,9 @@ impl EthApi {
&self,
request: CallRequest,
block_number: Option<BlockId>,
opts: GethDebugTracingOptions,
opts: GethDefaultTracingOptions,
) -> Result<DefaultFrame> {
node_info!("debug_traceCall");
if opts.tracer.is_some() {
return Err(RpcError::invalid_params("non-default tracer not supported yet").into());
}
let block_request = self.block_request(block_number).await?;
let fees = FeeDetails::new(
request.gas_price.map(|g| g.to_ethers()),
Expand All @@ -1495,15 +1488,15 @@ impl EthApi {
/// Returns traces for the transaction hash via parity's tracing endpoint
///
/// Handler for RPC call: `trace_transaction`
pub async fn trace_transaction(&self, tx_hash: B256) -> Result<Vec<Trace>> {
pub async fn trace_transaction(&self, tx_hash: B256) -> Result<Vec<LocalizedTransactionTrace>> {
node_info!("trace_transaction");
self.backend.trace_transaction(tx_hash).await
}

/// Returns traces for the transaction hash via parity's tracing endpoint
///
/// Handler for RPC call: `trace_block`
pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<Trace>> {
pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<LocalizedTransactionTrace>> {
node_info!("trace_block");
self.backend.trace_block(block).await
}
Expand Down
12 changes: 9 additions & 3 deletions crates/anvil/src/eth/backend/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ use ethers::{
use foundry_common::types::{ToAlloy, ToEthers};
use foundry_evm::{
backend::DatabaseError,
inspectors::{TracingInspector, TracingInspectorConfig},
revm,
revm::{
interpreter::InstructionResult,
primitives::{BlockEnv, CfgEnv, EVMError, Env, ExecutionResult, Output, SpecId},
},
traces::{CallTraceArena, CallTraceNode},
traces::CallTraceNode,
utils::{eval_to_instruction_result, halt_to_instruction_result},
};
use std::sync::Arc;
Expand Down Expand Up @@ -171,7 +172,7 @@ impl<'a, DB: Db + ?Sized, Validator: TransactionValidator> TransactionExecutor<'
contract_address: contract_address.map(|c| c.to_ethers()),
logs,
logs_bloom: *receipt.logs_bloom(),
traces: CallTraceArena { arena: traces },
traces,
exit,
out: match out {
Some(Output::Call(b)) => Some(ethers::types::Bytes(b.0)),
Expand Down Expand Up @@ -321,7 +322,12 @@ impl<'a, 'b, DB: Db + ?Sized, Validator: TransactionValidator> Iterator
out,
gas_used,
logs: logs.unwrap_or_default().into_iter().map(Into::into).collect(),
traces: inspector.tracer.unwrap_or_default().traces.arena,
traces: inspector
.tracer
.unwrap_or(TracingInspector::new(TracingInspectorConfig::all()))
.get_traces()
.clone()
.into_nodes(),
nonce,
};

Expand Down
14 changes: 7 additions & 7 deletions crates/anvil/src/eth/backend/mem/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,20 @@ use ethers::types::Log;
use foundry_evm::{
call_inspectors,
decode::decode_console_logs,
inspectors::{LogCollector, Tracer},
inspectors::{LogCollector, TracingInspector},
revm,
revm::{
interpreter::{CallInputs, CreateInputs, Gas, InstructionResult, Interpreter},
primitives::{Address, Bytes, B256},
EVMData,
},
traces::TracingInspectorConfig,
};

/// The [`revm::Inspector`] used when transacting in the evm
#[derive(Debug, Clone, Default)]
pub struct Inspector {
pub tracer: Option<Tracer>,
pub tracer: Option<TracingInspector>,
/// collects all `console.sol` logs
pub log_collector: LogCollector,
}
Expand All @@ -34,15 +35,14 @@ impl Inspector {

/// Configures the `Tracer` [`revm::Inspector`]
pub fn with_tracing(mut self) -> Self {
self.tracer = Some(Default::default());
self.tracer = Some(TracingInspector::new(TracingInspectorConfig::all()));
self
}

/// Enables steps recording for `Tracer`.
pub fn with_steps_tracing(mut self) -> Self {
let tracer = self.tracer.get_or_insert_with(Default::default);
tracer.record_steps();
self
pub fn with_steps_tracing(self) -> Self {
// todo deprecate?
self.with_tracing()
}
}

Expand Down
Loading

0 comments on commit a3150d5

Please sign in to comment.