fix(rpc): commit tx state changes when tracing block (#2605)

This commit is contained in:
Matthias Seitz
2023-05-08 17:14:18 +02:00
committed by GitHub
parent 7ca8a297a8
commit d8e3dcfe78
2 changed files with 36 additions and 17 deletions

View File

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

View File

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