diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index 9f0f59350b..bac7a0b781 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -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 std::fmt::Debug for DebugApi { } } -/// 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>, -) -> EthResult { +) -> 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)) } diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index 9c17d30c35..d85eb7fe55 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -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>> where - F: Fn(TransactionInfo, TracingInspector, ResultAndState) -> EthResult + Send, + F: Fn(TransactionInfo, TracingInspector, ExecutionResult) -> EthResult + 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, ) -> EthResult>> { 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,