Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions crates/cheatcodes/assets/cheatcodes.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/cheatcodes/spec/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,10 @@ interface Vm {
StorageAccess[] storageAccesses;
/// Call depth traversed during the recording of state differences
uint64 depth;
/// The previous nonce of the accessed account.
uint64 oldNonce;
/// The new nonce of the accessed account.
uint64 newNonce;
}

/// The result of the `stopDebugTraceRecording` call
Expand Down
39 changes: 39 additions & 0 deletions crates/cheatcodes/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ struct BalanceDiff {
new_value: U256,
}

/// Nonce diff info.
#[derive(Serialize, Default)]
#[serde(rename_all = "camelCase")]
struct NonceDiff {
/// Initial nonce value.
previous_value: u64,
/// Current nonce value.
new_value: u64,
}

/// Account state diff info.
#[derive(Serialize, Default)]
#[serde(rename_all = "camelCase")]
Expand All @@ -123,6 +133,8 @@ struct AccountStateDiffs {
label: Option<String>,
/// Account balance changes.
balance_diff: Option<BalanceDiff>,
/// Account nonce changes.
nonce_diff: Option<NonceDiff>,
/// State changes, per slot.
state_diff: BTreeMap<B256, SlotStateDiff>,
}
Expand All @@ -143,6 +155,12 @@ impl Display for AccountStateDiffs {
balance_diff.previous_value, balance_diff.new_value
)?;
}
// Print nonce diff if changed.
if let Some(nonce_diff) = &self.nonce_diff
&& nonce_diff.previous_value != nonce_diff.new_value
{
writeln!(f, "- nonce diff: {} → {}", nonce_diff.previous_value, nonce_diff.new_value)?;
}
// Print state diff if any.
if !&self.state_diff.is_empty() {
writeln!(f, "- state diff:")?;
Expand Down Expand Up @@ -1209,6 +1227,7 @@ fn get_recorded_state_diffs(state: &mut Cheatcodes) -> BTreeMap<Address, Account
.filter(|account_access| {
!account_access.storageAccesses.is_empty()
|| account_access.oldBalance != account_access.newBalance
|| account_access.oldNonce != account_access.newNonce
})
.for_each(|account_access| {
// Record account balance diffs.
Expand All @@ -1231,6 +1250,26 @@ fn get_recorded_state_diffs(state: &mut Cheatcodes) -> BTreeMap<Address, Account
}
}

// Record account nonce diffs.
if account_access.oldNonce != account_access.newNonce {
let account_diff =
state_diffs.entry(account_access.account).or_insert_with(|| {
AccountStateDiffs {
label: state.labels.get(&account_access.account).cloned(),
..Default::default()
}
});
// Update nonce diff. Do not overwrite the initial nonce if already set.
if let Some(diff) = &mut account_diff.nonce_diff {
diff.new_value = account_access.newNonce;
} else {
account_diff.nonce_diff = Some(NonceDiff {
previous_value: account_access.oldNonce,
new_value: account_access.newNonce,
});
}
}

// Record account state diffs.
for storage_access in &account_access.storageAccesses {
if storage_access.isWrite && !storage_access.reverted {
Expand Down
26 changes: 23 additions & 3 deletions crates/cheatcodes/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -933,12 +933,15 @@ impl Cheatcodes {
// nonce, a non-zero KECCAK_EMPTY codehash, or non-empty code
let initialized;
let old_balance;
let old_nonce;
if let Ok(acc) = ecx.journaled_state.load_account(call.target_address) {
initialized = acc.info.exists();
old_balance = acc.info.balance;
old_nonce = acc.info.nonce;
} else {
initialized = false;
old_balance = U256::ZERO;
old_nonce = 0;
}
let kind = match call.scheme {
CallScheme::Call => crate::Vm::AccountAccessKind::Call,
Expand All @@ -962,6 +965,8 @@ impl Cheatcodes {
initialized,
oldBalance: old_balance,
newBalance: U256::ZERO, // updated on call_end
oldNonce: old_nonce,
newNonce: 0, // updated on call_end
value: call.call_value(),
data: call.input.bytes(ecx),
reverted: false,
Expand Down Expand Up @@ -1327,6 +1332,7 @@ impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for Cheatcodes {
{
debug_assert!(access_is_call(call_access.kind));
call_access.newBalance = acc.info.balance;
call_access.newNonce = acc.info.nonce;
}
// Merge the last depth's AccountAccesses into the AccountAccesses at the
// current depth, or push them back onto the pending
Expand Down Expand Up @@ -1642,6 +1648,8 @@ impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for Cheatcodes {
initialized: true,
oldBalance: U256::ZERO, // updated on create_end
newBalance: U256::ZERO, // updated on create_end
oldNonce: 0, // new contract starts with nonce 0
newNonce: 1, // updated on create_end (contracts start with nonce 1)
value: input.value(),
data: input.init_code(),
reverted: false,
Expand Down Expand Up @@ -1748,6 +1756,7 @@ impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for Cheatcodes {
&& let Ok(created_acc) = ecx.journaled_state.load_account(address)
{
create_access.newBalance = created_acc.info.balance;
create_access.newNonce = created_acc.info.nonce;
create_access.deployedCode =
created_acc.info.code.clone().unwrap_or_default().original_bytes();
}
Expand Down Expand Up @@ -1945,13 +1954,15 @@ impl Cheatcodes {
// Ensure that we're not selfdestructing a context recording was initiated on
let Some(last) = account_accesses.last_mut() else { return };

// get previous balance and initialized status of the target account
// get previous balance, nonce and initialized status of the target account
let target = try_or_return!(interpreter.stack.peek(0));
let target = Address::from_word(B256::from(target));
let (initialized, old_balance) = ecx
let (initialized, old_balance, old_nonce) = ecx
.journaled_state
.load_account(target)
.map(|account| (account.info.exists(), account.info.balance))
.map(|account| {
(account.info.exists(), account.info.balance, account.info.nonce)
})
.unwrap_or_default();

// load balance of this account
Expand All @@ -1972,6 +1983,8 @@ impl Cheatcodes {
initialized,
oldBalance: old_balance,
newBalance: old_balance + value,
oldNonce: old_nonce,
newNonce: old_nonce, // nonce doesn't change on selfdestruct
value,
data: Bytes::new(),
reverted: false,
Expand Down Expand Up @@ -2059,12 +2072,15 @@ impl Cheatcodes {
Address::from_word(B256::from(try_or_return!(interpreter.stack.peek(0))));
let initialized;
let balance;
let nonce;
if let Ok(acc) = ecx.journaled_state.load_account(address) {
initialized = acc.info.exists();
balance = acc.info.balance;
nonce = acc.info.nonce;
} else {
initialized = false;
balance = U256::ZERO;
nonce = 0;
}
let curr_depth = ecx
.journaled_state
Expand All @@ -2082,6 +2098,8 @@ impl Cheatcodes {
initialized,
oldBalance: balance,
newBalance: balance,
oldNonce: nonce,
newNonce: nonce, // EXT* operations don't change nonce
value: U256::ZERO,
data: Bytes::new(),
reverted: false,
Expand Down Expand Up @@ -2360,6 +2378,8 @@ fn append_storage_access(
// The remaining fields are defaults
oldBalance: U256::ZERO,
newBalance: U256::ZERO,
oldNonce: 0,
newNonce: 0,
value: U256::ZERO,
data: Bytes::new(),
deployedCode: Bytes::new(),
Expand Down
2 changes: 1 addition & 1 deletion testdata/cheats/Vm.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading