mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 00:58:11 -05:00
feat(rpc): impl parity trace_transaction (#1765)
This commit is contained in:
@@ -1,11 +1,4 @@
|
||||
use crate::tracing::types::{CallTrace, CallTraceNode, LogCallOrder};
|
||||
use reth_primitives::{Address, JsonU256, H256, U256};
|
||||
use reth_rpc_types::trace::{
|
||||
geth::{DefaultFrame, GethDebugTracingOptions, StructLog},
|
||||
parity::{ActionType, TransactionTrace},
|
||||
};
|
||||
use revm::interpreter::{opcode, InstructionResult};
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
/// An arena of recorded traces.
|
||||
///
|
||||
@@ -49,112 +42,4 @@ impl CallTraceArena {
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the traces of the transaction for `trace_transaction`
|
||||
pub fn parity_traces(&self) -> Vec<TransactionTrace> {
|
||||
let traces = Vec::with_capacity(self.arena.len());
|
||||
for (_idx, node) in self.arena.iter().cloned().enumerate() {
|
||||
let _action = node.parity_action();
|
||||
let _result = node.parity_result();
|
||||
|
||||
let _action_type = if node.status() == InstructionResult::SelfDestruct {
|
||||
ActionType::Selfdestruct
|
||||
} else {
|
||||
node.kind().into()
|
||||
};
|
||||
|
||||
todo!()
|
||||
|
||||
// let trace = TransactionTrace {
|
||||
// action,
|
||||
// result: Some(result),
|
||||
// trace_address: self.info.trace_address(idx),
|
||||
// subtraces: node.children.len(),
|
||||
// };
|
||||
// traces.push(trace)
|
||||
}
|
||||
|
||||
traces
|
||||
}
|
||||
|
||||
/// Recursively fill in the geth trace by going through the traces
|
||||
///
|
||||
/// TODO rewrite this iteratively
|
||||
fn add_to_geth_trace(
|
||||
&self,
|
||||
storage: &mut HashMap<Address, BTreeMap<H256, H256>>,
|
||||
trace_node: &CallTraceNode,
|
||||
struct_logs: &mut Vec<StructLog>,
|
||||
opts: &GethDebugTracingOptions,
|
||||
) {
|
||||
let mut child_id = 0;
|
||||
// Iterate over the steps inside the given trace
|
||||
for step in trace_node.trace.steps.iter() {
|
||||
let mut log: StructLog = step.into();
|
||||
|
||||
// Fill in memory and storage depending on the options
|
||||
if !opts.disable_storage.unwrap_or_default() {
|
||||
let contract_storage = storage.entry(step.contract).or_default();
|
||||
if let Some((key, value)) = step.state_diff {
|
||||
contract_storage.insert(key.into(), value.into());
|
||||
log.storage = Some(contract_storage.clone());
|
||||
}
|
||||
}
|
||||
if opts.disable_stack.unwrap_or_default() {
|
||||
log.stack = None;
|
||||
}
|
||||
if !opts.enable_memory.unwrap_or_default() {
|
||||
log.memory = None;
|
||||
}
|
||||
|
||||
// Add step to geth trace
|
||||
struct_logs.push(log);
|
||||
|
||||
// If the opcode is a call, the descend into child trace
|
||||
match step.op.u8() {
|
||||
opcode::CREATE |
|
||||
opcode::CREATE2 |
|
||||
opcode::DELEGATECALL |
|
||||
opcode::CALL |
|
||||
opcode::STATICCALL |
|
||||
opcode::CALLCODE => {
|
||||
self.add_to_geth_trace(
|
||||
storage,
|
||||
&self.arena[trace_node.children[child_id]],
|
||||
struct_logs,
|
||||
opts,
|
||||
);
|
||||
child_id += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a geth-style trace e.g. for `debug_traceTransaction`
|
||||
pub fn geth_traces(
|
||||
&self,
|
||||
// TODO(mattsse): This should be the total gas used, or gas used by last CallTrace?
|
||||
receipt_gas_used: U256,
|
||||
opts: GethDebugTracingOptions,
|
||||
) -> DefaultFrame {
|
||||
if self.arena.is_empty() {
|
||||
return Default::default()
|
||||
}
|
||||
// Fetch top-level trace
|
||||
let main_trace_node = &self.arena[0];
|
||||
let main_trace = &main_trace_node.trace;
|
||||
|
||||
let mut struct_logs = Vec::new();
|
||||
let mut storage = HashMap::new();
|
||||
self.add_to_geth_trace(&mut storage, main_trace_node, &mut struct_logs, &opts);
|
||||
|
||||
DefaultFrame {
|
||||
// If the top-level trace succeeded, then it was a success
|
||||
failed: !main_trace.success,
|
||||
gas: JsonU256(receipt_gas_used),
|
||||
return_value: main_trace.output.clone().into(),
|
||||
struct_logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104
crates/revm/revm-inspectors/src/tracing/builder/geth.rs
Normal file
104
crates/revm/revm-inspectors/src/tracing/builder/geth.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
//! Geth trace builder
|
||||
|
||||
use crate::tracing::{types::CallTraceNode, TraceInspectorConfig};
|
||||
use reth_primitives::{Address, JsonU256, H256, U256};
|
||||
use reth_rpc_types::trace::geth::*;
|
||||
use revm::interpreter::opcode;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
/// A type for creating geth style traces
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct GethTraceBuilder {
|
||||
/// Recorded trace nodes.
|
||||
nodes: Vec<CallTraceNode>,
|
||||
/// How the traces were recorded
|
||||
_config: TraceInspectorConfig,
|
||||
}
|
||||
|
||||
impl GethTraceBuilder {
|
||||
/// Returns a new instance of the builder
|
||||
pub(crate) fn new(nodes: Vec<CallTraceNode>, _config: TraceInspectorConfig) -> Self {
|
||||
Self { nodes, _config }
|
||||
}
|
||||
|
||||
/// Recursively fill in the geth trace by going through the traces
|
||||
///
|
||||
/// TODO rewrite this iteratively
|
||||
fn add_to_geth_trace(
|
||||
&self,
|
||||
storage: &mut HashMap<Address, BTreeMap<H256, H256>>,
|
||||
trace_node: &CallTraceNode,
|
||||
struct_logs: &mut Vec<StructLog>,
|
||||
opts: &GethDebugTracingOptions,
|
||||
) {
|
||||
let mut child_id = 0;
|
||||
// Iterate over the steps inside the given trace
|
||||
for step in trace_node.trace.steps.iter() {
|
||||
let mut log: StructLog = step.into();
|
||||
|
||||
// Fill in memory and storage depending on the options
|
||||
if !opts.disable_storage.unwrap_or_default() {
|
||||
let contract_storage = storage.entry(step.contract).or_default();
|
||||
if let Some((key, value)) = step.state_diff {
|
||||
contract_storage.insert(key.into(), value.into());
|
||||
log.storage = Some(contract_storage.clone());
|
||||
}
|
||||
}
|
||||
if opts.disable_stack.unwrap_or_default() {
|
||||
log.stack = None;
|
||||
}
|
||||
if !opts.enable_memory.unwrap_or_default() {
|
||||
log.memory = None;
|
||||
}
|
||||
|
||||
// Add step to geth trace
|
||||
struct_logs.push(log);
|
||||
|
||||
// If the opcode is a call, the descend into child trace
|
||||
match step.op.u8() {
|
||||
opcode::CREATE |
|
||||
opcode::CREATE2 |
|
||||
opcode::DELEGATECALL |
|
||||
opcode::CALL |
|
||||
opcode::STATICCALL |
|
||||
opcode::CALLCODE => {
|
||||
self.add_to_geth_trace(
|
||||
storage,
|
||||
&self.nodes[trace_node.children[child_id]],
|
||||
struct_logs,
|
||||
opts,
|
||||
);
|
||||
child_id += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a geth-style trace e.g. for `debug_traceTransaction`
|
||||
pub fn geth_traces(
|
||||
&self,
|
||||
// TODO(mattsse): This should be the total gas used, or gas used by last CallTrace?
|
||||
receipt_gas_used: U256,
|
||||
opts: GethDebugTracingOptions,
|
||||
) -> DefaultFrame {
|
||||
if self.nodes.is_empty() {
|
||||
return Default::default()
|
||||
}
|
||||
// Fetch top-level trace
|
||||
let main_trace_node = &self.nodes[0];
|
||||
let main_trace = &main_trace_node.trace;
|
||||
|
||||
let mut struct_logs = Vec::new();
|
||||
let mut storage = HashMap::new();
|
||||
self.add_to_geth_trace(&mut storage, main_trace_node, &mut struct_logs, &opts);
|
||||
|
||||
DefaultFrame {
|
||||
// If the top-level trace succeeded, then it was a success
|
||||
failed: !main_trace.success,
|
||||
gas: JsonU256(receipt_gas_used),
|
||||
return_value: main_trace.output.clone().into(),
|
||||
struct_logs,
|
||||
}
|
||||
}
|
||||
}
|
||||
4
crates/revm/revm-inspectors/src/tracing/builder/mod.rs
Normal file
4
crates/revm/revm-inspectors/src/tracing/builder/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! Builder types for building traces
|
||||
|
||||
pub(crate) mod geth;
|
||||
pub(crate) mod parity;
|
||||
104
crates/revm/revm-inspectors/src/tracing/builder/parity.rs
Normal file
104
crates/revm/revm-inspectors/src/tracing/builder/parity.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use crate::tracing::{types::CallTraceNode, TraceInspectorConfig};
|
||||
use reth_rpc_types::{trace::parity::*, TransactionInfo};
|
||||
|
||||
/// A type for creating parity style traces
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ParityTraceBuilder {
|
||||
/// Recorded trace nodes
|
||||
nodes: Vec<CallTraceNode>,
|
||||
/// How the traces were recorded
|
||||
_config: TraceInspectorConfig,
|
||||
}
|
||||
|
||||
impl ParityTraceBuilder {
|
||||
/// Returns a new instance of the builder
|
||||
pub(crate) fn new(nodes: Vec<CallTraceNode>, _config: TraceInspectorConfig) -> Self {
|
||||
Self { nodes, _config }
|
||||
}
|
||||
|
||||
/// Returns the trace addresses of all transactions in the set
|
||||
fn trace_addresses(&self) -> Vec<Vec<usize>> {
|
||||
let mut all_addresses = Vec::with_capacity(self.nodes.len());
|
||||
for idx in 0..self.nodes.len() {
|
||||
all_addresses.push(self.trace_address(idx));
|
||||
}
|
||||
all_addresses
|
||||
}
|
||||
|
||||
/// 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
|
||||
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.nodes[idx];
|
||||
while let Some(parent) = node.parent {
|
||||
// the index of the child call in the arena
|
||||
let child_idx = node.idx;
|
||||
node = &self.nodes[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
|
||||
}
|
||||
|
||||
/// Returns an iterator over all recorded traces for `trace_transaction`
|
||||
pub fn into_localized_transaction_traces_iter(
|
||||
self,
|
||||
info: TransactionInfo,
|
||||
) -> impl Iterator<Item = LocalizedTransactionTrace> {
|
||||
self.into_transaction_traces_iter().map(move |trace| {
|
||||
let TransactionInfo { hash, index, block_hash, block_number } = info;
|
||||
LocalizedTransactionTrace {
|
||||
trace,
|
||||
transaction_position: index,
|
||||
transaction_hash: hash,
|
||||
block_number,
|
||||
block_hash,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns an iterator over all recorded traces for `trace_transaction`
|
||||
pub fn into_localized_transaction_traces(
|
||||
self,
|
||||
info: TransactionInfo,
|
||||
) -> Vec<LocalizedTransactionTrace> {
|
||||
self.into_localized_transaction_traces_iter(info).collect()
|
||||
}
|
||||
|
||||
/// Returns an iterator over all recorded traces for `trace_transaction`
|
||||
pub fn into_transaction_traces_iter(self) -> impl Iterator<Item = TransactionTrace> {
|
||||
let trace_addresses = self.trace_addresses();
|
||||
|
||||
self.nodes.into_iter().zip(trace_addresses).map(|(node, trace_address)| {
|
||||
let action = node.parity_action();
|
||||
let output = TraceResult::parity_success(node.parity_trace_output());
|
||||
TransactionTrace {
|
||||
action,
|
||||
result: Some(output),
|
||||
trace_address,
|
||||
subtraces: node.children.len(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the raw traces of the transaction
|
||||
pub fn into_transaction_traces(self) -> Vec<TransactionTrace> {
|
||||
self.into_transaction_traces_iter().collect()
|
||||
}
|
||||
}
|
||||
@@ -18,9 +18,11 @@ use revm::{
|
||||
use types::{CallTrace, CallTraceStep};
|
||||
|
||||
mod arena;
|
||||
mod builder;
|
||||
mod config;
|
||||
mod types;
|
||||
mod utils;
|
||||
pub use builder::{geth::GethTraceBuilder, parity::ParityTraceBuilder};
|
||||
pub use config::TraceInspectorConfig;
|
||||
|
||||
/// An inspector that collects call traces.
|
||||
@@ -60,9 +62,14 @@ impl TracingInspector {
|
||||
}
|
||||
}
|
||||
|
||||
/// Consumes the Inspector and returns the recorded.
|
||||
pub fn finalize(self) -> CallTraceArena {
|
||||
self.traces
|
||||
/// Consumes the Inspector and returns a [ParityTraceBuilder].
|
||||
pub fn into_parity_builder(self) -> ParityTraceBuilder {
|
||||
ParityTraceBuilder::new(self.traces.arena, self.config)
|
||||
}
|
||||
|
||||
/// Consumes the Inspector and returns a [GethTraceBuilder].
|
||||
pub fn into_geth_builder(self) -> GethTraceBuilder {
|
||||
GethTraceBuilder::new(self.traces.arena, self.config)
|
||||
}
|
||||
|
||||
/// Configures a [GasInspector]
|
||||
|
||||
@@ -158,7 +158,7 @@ impl CallTraceNode {
|
||||
}
|
||||
|
||||
/// Returns the `Output` for a parity trace
|
||||
pub(crate) fn parity_result(&self) -> TraceOutput {
|
||||
pub(crate) fn parity_trace_output(&self) -> TraceOutput {
|
||||
match self.kind() {
|
||||
CallKind::Call | CallKind::StaticCall | CallKind::CallCode | CallKind::DelegateCall => {
|
||||
TraceOutput::Call(CallOutput {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::config::revm_spec;
|
||||
use reth_primitives::{
|
||||
Address, ChainSpec, Head, Header, Transaction, TransactionKind, TransactionSigned, TxEip1559,
|
||||
TxEip2930, TxLegacy, U256,
|
||||
Address, ChainSpec, Head, Header, Transaction, TransactionKind, TransactionSignedEcRecovered,
|
||||
TxEip1559, TxEip2930, TxLegacy, U256,
|
||||
};
|
||||
use revm::primitives::{AnalysisKind, BlockEnv, CfgEnv, SpecId, TransactTo, TxEnv};
|
||||
|
||||
@@ -57,8 +57,23 @@ pub fn fill_block_env(block_env: &mut BlockEnv, header: &Header, after_merge: bo
|
||||
block_env.gas_limit = U256::from(header.gas_limit);
|
||||
}
|
||||
|
||||
/// Fill transaction environment from Transaction.
|
||||
pub fn fill_tx_env(tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) {
|
||||
/// Returns a new [TxEnv] filled with the transaction's data.
|
||||
pub fn tx_env_with_recovered(transaction: &TransactionSignedEcRecovered) -> TxEnv {
|
||||
let mut tx_env = TxEnv::default();
|
||||
fill_tx_env(&mut tx_env, transaction.as_ref(), transaction.signer());
|
||||
tx_env
|
||||
}
|
||||
|
||||
/// Fill transaction environment from [TransactionSignedEcRecovered].
|
||||
pub fn fill_tx_env_with_recovered(tx_env: &mut TxEnv, transaction: &TransactionSignedEcRecovered) {
|
||||
fill_tx_env(tx_env, transaction.as_ref(), transaction.signer())
|
||||
}
|
||||
|
||||
/// Fill transaction environment from a [Transaction] and the given sender address.
|
||||
pub fn fill_tx_env<T>(tx_env: &mut TxEnv, transaction: T, sender: Address)
|
||||
where
|
||||
T: AsRef<Transaction>,
|
||||
{
|
||||
tx_env.caller = sender;
|
||||
match transaction.as_ref() {
|
||||
Transaction::Legacy(TxLegacy {
|
||||
|
||||
@@ -10,6 +10,20 @@ use std::collections::BTreeMap;
|
||||
/// Result type for parity style transaction trace
|
||||
pub type TraceResult = crate::trace::common::TraceResult<TraceOutput, String>;
|
||||
|
||||
// === impl TraceResult ===
|
||||
|
||||
impl TraceResult {
|
||||
/// Wraps the result type in a [TraceResult::Success] variant
|
||||
pub fn parity_success(result: TraceOutput) -> Self {
|
||||
TraceResult::Success { result }
|
||||
}
|
||||
|
||||
/// Wraps the result type in a [TraceResult::Error] variant
|
||||
pub fn parity_error(error: String) -> Self {
|
||||
TraceResult::Error { error }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum TraceType {
|
||||
@@ -190,10 +204,18 @@ pub struct TransactionTrace {
|
||||
pub struct LocalizedTransactionTrace {
|
||||
#[serde(flatten)]
|
||||
pub trace: TransactionTrace,
|
||||
/// Transaction index within the block, None if pending.
|
||||
pub transaction_position: Option<usize>,
|
||||
/// Hash of the transaction
|
||||
pub transaction_hash: Option<H256>,
|
||||
pub block_number: U64,
|
||||
pub block_hash: H256,
|
||||
/// Block number the transaction is included in, None if pending.
|
||||
///
|
||||
/// Note: this deviates from <https://openethereum.github.io/JSONRPC-trace-module#trace_transaction> which always returns a block number
|
||||
pub block_number: Option<u64>,
|
||||
/// Hash of the block, if not pending
|
||||
///
|
||||
/// Note: this deviates from <https://openethereum.github.io/JSONRPC-trace-module#trace_transaction> which always returns a block number
|
||||
pub block_hash: Option<H256>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
|
||||
17
crates/rpc/rpc-types/src/eth/transaction/common.rs
Normal file
17
crates/rpc/rpc-types/src/eth/transaction/common.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
//! Commonly used additional types that are not part of the JSON RPC spec but are often required
|
||||
//! when working with RPC types, such as [Transaction](crate::Transaction)
|
||||
|
||||
use reth_primitives::{TxHash, H256};
|
||||
|
||||
/// Additional fields in the context of a block that contains this transaction.
|
||||
#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)]
|
||||
pub struct TransactionInfo {
|
||||
/// Hash of the transaction.
|
||||
pub hash: Option<TxHash>,
|
||||
/// Index of the transaction in the block
|
||||
pub index: Option<usize>,
|
||||
/// Hash of the block.
|
||||
pub block_hash: Option<H256>,
|
||||
/// Number of the block.
|
||||
pub block_number: Option<u64>,
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
mod common;
|
||||
mod receipt;
|
||||
mod request;
|
||||
mod signature;
|
||||
mod typed;
|
||||
|
||||
pub use common::TransactionInfo;
|
||||
pub use receipt::TransactionReceipt;
|
||||
pub use request::TransactionRequest;
|
||||
pub use signature::Signature;
|
||||
|
||||
@@ -10,7 +10,7 @@ use reth_primitives::{
|
||||
};
|
||||
use reth_provider::{providers::ChainState, BlockProvider, EvmEnvProvider, StateProviderFactory};
|
||||
use reth_rlp::Decodable;
|
||||
use reth_rpc_types::{Index, Transaction, TransactionRequest};
|
||||
use reth_rpc_types::{Index, Transaction, TransactionInfo, TransactionRequest};
|
||||
use reth_transaction_pool::{TransactionOrigin, TransactionPool};
|
||||
use revm::primitives::{BlockEnv, CfgEnv};
|
||||
|
||||
@@ -216,6 +216,45 @@ pub enum TransactionSource {
|
||||
},
|
||||
}
|
||||
|
||||
// === impl TransactionSource ===
|
||||
|
||||
impl TransactionSource {
|
||||
/// Consumes the type and returns the wrapped transaction.
|
||||
pub fn into_recovered(self) -> TransactionSignedEcRecovered {
|
||||
self.into()
|
||||
}
|
||||
|
||||
/// Returns the transaction and block related info, if not pending
|
||||
pub fn split(self) -> (TransactionSignedEcRecovered, TransactionInfo) {
|
||||
match self {
|
||||
TransactionSource::Pool(tx) => {
|
||||
let hash = tx.hash();
|
||||
(
|
||||
tx,
|
||||
TransactionInfo {
|
||||
hash: Some(hash),
|
||||
index: None,
|
||||
block_hash: None,
|
||||
block_number: None,
|
||||
},
|
||||
)
|
||||
}
|
||||
TransactionSource::Database { transaction, index, block_hash, block_number } => {
|
||||
let hash = transaction.hash();
|
||||
(
|
||||
transaction,
|
||||
TransactionInfo {
|
||||
hash: Some(hash),
|
||||
index: Some(index),
|
||||
block_hash: Some(block_hash),
|
||||
block_number: Some(block_number),
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionSource> for TransactionSignedEcRecovered {
|
||||
fn from(value: TransactionSource) -> Self {
|
||||
match value {
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
use crate::{
|
||||
eth::{cache::EthStateCache, EthTransactions},
|
||||
eth::{cache::EthStateCache, revm_utils::inspect, EthTransactions},
|
||||
result::internal_rpc_err,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use jsonrpsee::core::RpcResult as Result;
|
||||
use reth_primitives::{BlockId, Bytes, H256};
|
||||
use reth_provider::{BlockProvider, EvmEnvProvider, StateProviderFactory};
|
||||
use reth_revm::{
|
||||
database::{State, SubState},
|
||||
env::tx_env_with_recovered,
|
||||
tracing::{TraceInspectorConfig, TracingInspector},
|
||||
};
|
||||
use reth_rpc_api::TraceApiServer;
|
||||
use reth_rpc_types::{
|
||||
trace::{filter::TraceFilter, parity::*},
|
||||
CallRequest, Index,
|
||||
};
|
||||
use revm::primitives::Env;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// `trace` API implementation.
|
||||
@@ -115,14 +121,28 @@ where
|
||||
&self,
|
||||
hash: H256,
|
||||
) -> Result<Option<Vec<LocalizedTransactionTrace>>> {
|
||||
let (_transaction, at) = match self.eth_api.transaction_by_hash_at(hash).await? {
|
||||
let (transaction, at) = match self.eth_api.transaction_by_hash_at(hash).await? {
|
||||
None => return Ok(None),
|
||||
Some(res) => res,
|
||||
};
|
||||
|
||||
let (_cfg, _block_env, _at) = self.eth_api.evm_env_at(at).await?;
|
||||
let (cfg, block, at) = self.eth_api.evm_env_at(at).await?;
|
||||
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
let (tx, tx_info) = transaction.split();
|
||||
|
||||
let traces = self.eth_api.with_state_at(at, |state| {
|
||||
let tx = tx_env_with_recovered(&tx);
|
||||
let env = Env { cfg, block, tx };
|
||||
let db = SubState::new(State::new(state));
|
||||
let mut inspector = TracingInspector::new(TraceInspectorConfig::default_parity());
|
||||
|
||||
inspect(db, env, &mut inspector)?;
|
||||
|
||||
let traces = inspector.into_parity_builder().into_localized_transaction_traces(tx_info);
|
||||
|
||||
Ok(traces)
|
||||
})?;
|
||||
Ok(Some(traces))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user