mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-29 17:18:08 -05:00
fix(rpc): commit tx state changes when tracing block (#2605)
This commit is contained in:
@@ -27,7 +27,7 @@ use reth_rpc_types::{
|
||||
BlockError, CallRequest, RichBlock,
|
||||
};
|
||||
use revm::primitives::Env;
|
||||
use revm_primitives::{BlockEnv, CfgEnv};
|
||||
use revm_primitives::{db::DatabaseCommit, BlockEnv, CfgEnv};
|
||||
|
||||
/// `debug` API implementation.
|
||||
///
|
||||
@@ -72,13 +72,19 @@ where
|
||||
let mut results = Vec::with_capacity(transactions.len());
|
||||
let mut db = SubState::new(State::new(state));
|
||||
|
||||
for tx in transactions {
|
||||
let mut transactions = transactions.into_iter().peekable();
|
||||
while let Some(tx) = transactions.next() {
|
||||
let tx = tx.into_ecrecovered().ok_or(BlockError::InvalidSignature)?;
|
||||
let tx = tx_env_with_recovered(&tx);
|
||||
let env = Env { cfg: cfg.clone(), block: block_env.clone(), tx };
|
||||
// TODO(mattsse): get rid of clone by extracting necessary opts fields into a struct
|
||||
let result = trace_transaction(opts.clone(), env, &mut db)?;
|
||||
let (result, state_changes) = trace_transaction(opts.clone(), env, &mut db)?;
|
||||
results.push(TraceResult::Success { result });
|
||||
|
||||
if transactions.peek().is_some() {
|
||||
// need to apply the state changes of this transaction before executing the next
|
||||
// transaction
|
||||
db.commit(state_changes)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
@@ -157,7 +163,7 @@ where
|
||||
replay_transactions_until(&mut db, cfg.clone(), block_env.clone(), block_txs, tx.hash)?;
|
||||
|
||||
let env = Env { cfg, block: block_env, tx: tx_env_with_recovered(&tx) };
|
||||
trace_transaction(opts, env, &mut db)
|
||||
trace_transaction(opts, env, &mut db).map(|(trace, _)| trace)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -329,14 +335,16 @@ impl<Client, Eth> std::fmt::Debug for DebugApi<Client, Eth> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Executes the configured transaction in the environment on the given database.
|
||||
/// Executes the configured transaction with the environment on the given database.
|
||||
///
|
||||
/// Returns the trace frame and the state that got updated after executing the transaction.
|
||||
///
|
||||
/// Note: this does not apply any state overrides if they're configured in the `opts`.
|
||||
fn trace_transaction(
|
||||
opts: GethDebugTracingOptions,
|
||||
env: Env,
|
||||
db: &mut SubState<StateProviderBox<'_>>,
|
||||
) -> EthResult<GethTraceFrame> {
|
||||
) -> EthResult<(GethTraceFrame, revm_primitives::State)> {
|
||||
let GethDebugTracingOptions { config, tracer, tracer_config, .. } = opts;
|
||||
if let Some(tracer) = tracer {
|
||||
// valid matching config
|
||||
@@ -350,8 +358,8 @@ fn trace_transaction(
|
||||
GethDebugTracerType::BuiltInTracer(tracer) => match tracer {
|
||||
GethDebugBuiltInTracerType::FourByteTracer => {
|
||||
let mut inspector = FourByteInspector::default();
|
||||
let _ = inspect(db, env, &mut inspector)?;
|
||||
return Ok(FourByteFrame::from(inspector).into())
|
||||
let (res, _) = inspect(db, env, &mut inspector)?;
|
||||
return Ok((FourByteFrame::from(inspector).into(), res.state))
|
||||
}
|
||||
GethDebugBuiltInTracerType::CallTracer => {
|
||||
todo!()
|
||||
@@ -359,7 +367,9 @@ fn trace_transaction(
|
||||
GethDebugBuiltInTracerType::PreStateTracer => {
|
||||
todo!()
|
||||
}
|
||||
GethDebugBuiltInTracerType::NoopTracer => Ok(NoopFrame::default().into()),
|
||||
GethDebugBuiltInTracerType::NoopTracer => {
|
||||
Ok((NoopFrame::default().into(), Default::default()))
|
||||
}
|
||||
},
|
||||
GethDebugTracerType::JsTracer(_) => {
|
||||
Err(EthApiError::Unsupported("javascript tracers are unsupported."))
|
||||
@@ -377,5 +387,5 @@ fn trace_transaction(
|
||||
|
||||
let frame = inspector.into_geth_builder().geth_traces(U256::from(gas_used), config);
|
||||
|
||||
Ok(frame.into())
|
||||
Ok((frame.into(), res.state))
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ use reth_rpc_types::{
|
||||
BlockError, CallRequest, Index, TransactionInfo,
|
||||
};
|
||||
use revm::primitives::Env;
|
||||
use revm_primitives::ResultAndState;
|
||||
use revm_primitives::{db::DatabaseCommit, ExecutionResult};
|
||||
use std::collections::HashSet;
|
||||
use tokio::sync::{AcquireError, OwnedSemaphorePermit};
|
||||
|
||||
@@ -211,7 +211,7 @@ where
|
||||
f: F,
|
||||
) -> EthResult<Option<Vec<R>>>
|
||||
where
|
||||
F: Fn(TransactionInfo, TracingInspector, ResultAndState) -> EthResult<R> + Send,
|
||||
F: Fn(TransactionInfo, TracingInspector, ExecutionResult) -> EthResult<R> + Send,
|
||||
{
|
||||
let ((cfg, block_env, _), block) = futures::try_join!(
|
||||
self.eth_api.evm_env_at(block_id),
|
||||
@@ -236,7 +236,9 @@ where
|
||||
let mut results = Vec::with_capacity(transactions.len());
|
||||
let mut db = SubState::new(State::new(state));
|
||||
|
||||
for (idx, tx) in transactions.into_iter().enumerate() {
|
||||
let mut transactions = transactions.into_iter().enumerate().peekable();
|
||||
|
||||
while let Some((idx, tx)) = transactions.next() {
|
||||
let tx = tx.into_ecrecovered().ok_or(BlockError::InvalidSignature)?;
|
||||
let tx_info = TransactionInfo {
|
||||
hash: Some(tx.hash()),
|
||||
@@ -251,7 +253,15 @@ where
|
||||
|
||||
let mut inspector = TracingInspector::new(config);
|
||||
let (res, _) = inspect(&mut db, env, &mut inspector)?;
|
||||
results.push(f(tx_info, inspector, res)?);
|
||||
results.push(f(tx_info, inspector, res.result)?);
|
||||
|
||||
// need to apply the state changes of this transaction before executing the next
|
||||
// transaction
|
||||
if transactions.peek().is_some() {
|
||||
// need to apply the state changes of this transaction before executing the
|
||||
// next transaction
|
||||
db.commit(res.state)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
@@ -286,8 +296,7 @@ where
|
||||
trace_types: HashSet<TraceType>,
|
||||
) -> EthResult<Option<Vec<TraceResultsWithTransactionHash>>> {
|
||||
self.trace_block_with(block_id, tracing_config(&trace_types), |tx_info, inspector, res| {
|
||||
let full_trace =
|
||||
inspector.into_parity_builder().into_trace_results(res.result, &trace_types);
|
||||
let full_trace = inspector.into_parity_builder().into_trace_results(res, &trace_types);
|
||||
let trace = TraceResultsWithTransactionHash {
|
||||
transaction_hash: tx_info.hash.expect("tx hash is set"),
|
||||
full_trace,
|
||||
|
||||
Reference in New Issue
Block a user