feat(rpc): impl parity trace_transaction (#1765)

This commit is contained in:
Matthias Seitz
2023-03-15 15:03:42 +01:00
committed by GitHub
parent bba61c0b61
commit 0c434e7916
12 changed files with 349 additions and 130 deletions

View File

@ -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)]

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

View File

@ -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;

View File

@ -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 {

View File

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