diff --git a/crates/revm/revm-inspectors/src/tracing/builder/geth.rs b/crates/revm/revm-inspectors/src/tracing/builder/geth.rs index d40cc032a..7523de27d 100644 --- a/crates/revm/revm-inspectors/src/tracing/builder/geth.rs +++ b/crates/revm/revm-inspectors/src/tracing/builder/geth.rs @@ -6,7 +6,7 @@ use crate::tracing::{ }; use reth_primitives::{Address, Bytes, B256, U256}; use reth_rpc_types::trace::geth::{ - AccountChangeKind, AccountState, CallConfig, CallFrame, DefaultFrame, DiffMode, DiffStateKind, + AccountChangeKind, AccountState, CallConfig, CallFrame, DefaultFrame, DiffMode, GethDefaultTracingOptions, PreStateConfig, PreStateFrame, PreStateMode, StructLog, }; use revm::{ @@ -192,23 +192,25 @@ impl GethTraceBuilder { let is_diff = prestate_config.is_diff_mode(); if !is_diff { let mut prestate = PreStateMode::default(); - for (addr, _) in account_diffs { + for (addr, changed_acc) in account_diffs { let db_acc = db.basic(addr)?.unwrap_or_default(); - - prestate.0.insert( - addr, - AccountState::from_account_info( - db_acc.nonce, - db_acc.balance, - db_acc.code.as_ref().map(|code| code.original_bytes()), - ), + let mut pre_state = AccountState::from_account_info( + db_acc.nonce, + db_acc.balance, + db_acc.code.as_ref().map(|code| code.original_bytes()), ); + + // handle _touched_ storage slots + for (key, slot) in changed_acc.storage.iter() { + pre_state.storage.insert((*key).into(), slot.previous_or_original_value.into()); + } + + prestate.0.insert(addr, pre_state); } - self.update_storage_from_trace_prestate_mode(&mut prestate.0, DiffStateKind::Pre); Ok(PreStateFrame::Default(prestate)) } else { let mut state_diff = DiffMode::default(); - let mut change_types = HashMap::with_capacity(account_diffs.len()); + let mut account_change_kinds = HashMap::with_capacity(account_diffs.len()); for (addr, changed_acc) in account_diffs { let db_acc = db.basic(addr)?.unwrap_or_default(); let db_code = db_acc.code.as_ref(); @@ -228,14 +230,22 @@ impl GethTraceBuilder { }) .map(Into::into); - let pre_state = + let mut pre_state = AccountState::from_account_info(db_acc.nonce, db_acc.balance, pre_code); - let post_state = AccountState::from_account_info( + let mut post_state = AccountState::from_account_info( changed_acc.info.nonce, changed_acc.info.balance, changed_acc.info.code.as_ref().map(|code| code.original_bytes()), ); + + // handle storage changes + for (key, slot) in changed_acc.storage.iter().filter(|(_, slot)| slot.is_changed()) + { + pre_state.storage.insert((*key).into(), slot.previous_or_original_value.into()); + post_state.storage.insert((*key).into(), slot.present_value.into()); + } + state_diff.pre.insert(addr, pre_state); state_diff.post.insert(addr, post_state); @@ -251,44 +261,17 @@ impl GethTraceBuilder { AccountChangeKind::Modify }; - change_types.insert(addr, (pre_change, post_change)); + account_change_kinds.insert(addr, (pre_change, post_change)); } - self.update_storage_from_trace_diff_mode(&mut state_diff.pre, DiffStateKind::Pre); - self.update_storage_from_trace_diff_mode(&mut state_diff.post, DiffStateKind::Post); - // ensure we're only keeping changed entries state_diff.retain_changed().remove_zero_storage_values(); - self.diff_traces(&mut state_diff.pre, &mut state_diff.post, change_types); + self.diff_traces(&mut state_diff.pre, &mut state_diff.post, account_change_kinds); Ok(PreStateFrame::Diff(state_diff)) } } - /// Updates the account storage for all nodes in the trace for pre-state mode. - #[inline] - fn update_storage_from_trace_prestate_mode( - &self, - account_states: &mut BTreeMap, - kind: DiffStateKind, - ) { - for node in self.nodes.iter() { - node.geth_update_account_storage(account_states, kind); - } - } - - /// Updates the account storage for all nodes in the trace for diff mode. - #[inline] - fn update_storage_from_trace_diff_mode( - &self, - account_states: &mut BTreeMap, - kind: DiffStateKind, - ) { - for node in self.nodes.iter() { - node.geth_update_account_storage_diff_mode(account_states, kind); - } - } - /// Returns the difference between the pre and post state of the transaction depending on the /// kind of changes of that account (pre,post) fn diff_traces( @@ -297,10 +280,9 @@ impl GethTraceBuilder { post: &mut BTreeMap, change_type: HashMap, ) { - // Don't keep destroyed accounts in the post state post.retain(|addr, post_state| { - // only keep accounts that are not created - if change_type.get(addr).map(|ty| !ty.1.is_selfdestruct()).unwrap_or(false) { + // Don't keep destroyed accounts in the post state + if change_type.get(addr).map(|ty| ty.1.is_selfdestruct()).unwrap_or(false) { return false } if let Some(pre_state) = pre.get(addr) { diff --git a/crates/revm/revm-inspectors/src/tracing/config.rs b/crates/revm/revm-inspectors/src/tracing/config.rs index 5096d8307..382cecb99 100644 --- a/crates/revm/revm-inspectors/src/tracing/config.rs +++ b/crates/revm/revm-inspectors/src/tracing/config.rs @@ -121,6 +121,11 @@ impl TracingInspectorConfig { self } + /// Sets state diff recording to true. + pub fn with_state_diffs(self) -> Self { + self.set_steps_and_state_diffs(true) + } + /// Configure whether the tracer should record state diffs pub fn set_state_diffs(mut self, record_state_diff: bool) -> Self { self.record_state_diff = record_state_diff; diff --git a/crates/revm/revm-inspectors/src/tracing/types.rs b/crates/revm/revm-inspectors/src/tracing/types.rs index 95e84a3d0..703c413ee 100644 --- a/crates/revm/revm-inspectors/src/tracing/types.rs +++ b/crates/revm/revm-inspectors/src/tracing/types.rs @@ -4,9 +4,7 @@ use crate::tracing::{config::TraceStyle, utils::convert_memory}; use alloy_sol_types::decode_revert_reason; use reth_primitives::{Address, Bytes, B256, U256, U64}; use reth_rpc_types::trace::{ - geth::{ - AccountState, CallFrame, CallLogFrame, DiffStateKind, GethDefaultTracingOptions, StructLog, - }, + geth::{CallFrame, CallLogFrame, GethDefaultTracingOptions, StructLog}, parity::{ Action, ActionType, CallAction, CallOutput, CallType, CreateAction, CreateOutput, SelfdestructAction, TraceOutput, TransactionTrace, @@ -16,7 +14,7 @@ use revm::interpreter::{ opcode, CallContext, CallScheme, CreateScheme, InstructionResult, Memory, OpCode, Stack, }; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, VecDeque}; +use std::collections::VecDeque; /// A unified representation of a call #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)] @@ -253,16 +251,6 @@ impl CallTraceNode { stack.extend(self.call_step_stack().into_iter().rev()); } - /// Returns all changed slots and the recorded changes - fn changed_storage_slots(&self) -> BTreeMap> { - let mut changed_slots: BTreeMap> = BTreeMap::new(); - for change in self.trace.steps.iter().filter_map(|s| s.storage_change) { - changed_slots.entry(change.key).or_default().push(change); - } - - changed_slots - } - /// Returns a list of all steps in this trace in the order they were executed /// /// If the step is a call, the id of the child trace is set. @@ -446,84 +434,6 @@ impl CallTraceNode { call_frame } - - /// Adds storage in-place to account state for all accounts that were touched in the trace - /// [CallTrace] execution. - /// - /// * `account_states` - the account map updated in place. - /// * `kind` - if [DiffStateKind::Post], it adds storage values after trace transaction - /// execution, if [DiffStateKind::Pre], returns the storage values before trace execution. - pub(crate) fn geth_update_account_storage( - &self, - account_states: &mut BTreeMap, - kind: DiffStateKind, - ) { - let addr = self.trace.address; - let acc_state = account_states.entry(addr).or_default(); - for change in self.trace.steps.iter().filter_map(|s| s.storage_change) { - let StorageChange { key, value, had_value, .. } = change; - let value_to_insert = if kind.is_post() { - B256::from(value) - } else { - match had_value { - Some(had_value) => B256::from(had_value), - None => continue, - } - }; - acc_state.storage.insert(key.into(), value_to_insert); - } - } - - /// Updates the account storage for all accounts that were touched in the trace. - /// - /// Depending on the [DiffStateKind] this will either insert the initial value - /// [DiffStateKind::Pre] or the final value [DiffStateKind::Post] of the storage slot. - pub(crate) fn geth_update_account_storage_diff_mode( - &self, - account_states: &mut BTreeMap, - kind: DiffStateKind, - ) { - let addr = self.execution_address(); - let changed_slots = self.changed_storage_slots(); - - // loop over all changed slots and track the storage changes of that slot - for (slot, changes) in changed_slots { - let account = account_states.entry(addr).or_default(); - - let mut initial_value = account.storage.get(&B256::from(slot)).copied().map(Into::into); - let mut final_value = None; - - for change in changes { - if initial_value.is_none() { - // set the initial value for the first storage change depending on the change - // reason - initial_value = match change.reason { - StorageChangeReason::SSTORE => Some(change.had_value.unwrap_or_default()), - StorageChangeReason::SLOAD => Some(change.value), - }; - } - - if change.reason == StorageChangeReason::SSTORE { - // keep track of the actual state value that's updated on sstore - final_value = Some(change.value); - } - } - - if final_value.is_none() || initial_value.is_none() { - continue - } - - if initial_value == final_value { - // unchanged - continue - } - - let value_to_write = - if kind.is_post() { final_value } else { initial_value }.expect("exists; qed"); - - account.storage.insert(B256::from(slot), B256::from(value_to_write)); - } - } } pub(crate) struct CallTraceStepStackItem<'a> {