Skip to content

Commit f0c491b

Browse files
authored
feat(cheatcodes): add nonce diffs to AccountStateDiffs (#11215)
* feat(`cheatcodes`): add nonce diffs to AccountStateDiffs * fmt * fix test Issue9643Test * fix
1 parent ab4375e commit f0c491b

File tree

7 files changed

+143
-9
lines changed

7 files changed

+143
-9
lines changed

crates/cheatcodes/assets/cheatcodes.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cheatcodes/spec/src/vm.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,10 @@ interface Vm {
278278
StorageAccess[] storageAccesses;
279279
/// Call depth traversed during the recording of state differences
280280
uint64 depth;
281+
/// The previous nonce of the accessed account.
282+
uint64 oldNonce;
283+
/// The new nonce of the accessed account.
284+
uint64 newNonce;
281285
}
282286

283287
/// The result of the `stopDebugTraceRecording` call

crates/cheatcodes/src/evm.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ struct BalanceDiff {
115115
new_value: U256,
116116
}
117117

118+
/// Nonce diff info.
119+
#[derive(Serialize, Default)]
120+
#[serde(rename_all = "camelCase")]
121+
struct NonceDiff {
122+
/// Initial nonce value.
123+
previous_value: u64,
124+
/// Current nonce value.
125+
new_value: u64,
126+
}
127+
118128
/// Account state diff info.
119129
#[derive(Serialize, Default)]
120130
#[serde(rename_all = "camelCase")]
@@ -123,6 +133,8 @@ struct AccountStateDiffs {
123133
label: Option<String>,
124134
/// Account balance changes.
125135
balance_diff: Option<BalanceDiff>,
136+
/// Account nonce changes.
137+
nonce_diff: Option<NonceDiff>,
126138
/// State changes, per slot.
127139
state_diff: BTreeMap<B256, SlotStateDiff>,
128140
}
@@ -143,6 +155,12 @@ impl Display for AccountStateDiffs {
143155
balance_diff.previous_value, balance_diff.new_value
144156
)?;
145157
}
158+
// Print nonce diff if changed.
159+
if let Some(nonce_diff) = &self.nonce_diff
160+
&& nonce_diff.previous_value != nonce_diff.new_value
161+
{
162+
writeln!(f, "- nonce diff: {} → {}", nonce_diff.previous_value, nonce_diff.new_value)?;
163+
}
146164
// Print state diff if any.
147165
if !&self.state_diff.is_empty() {
148166
writeln!(f, "- state diff:")?;
@@ -1209,6 +1227,7 @@ fn get_recorded_state_diffs(state: &mut Cheatcodes) -> BTreeMap<Address, Account
12091227
.filter(|account_access| {
12101228
!account_access.storageAccesses.is_empty()
12111229
|| account_access.oldBalance != account_access.newBalance
1230+
|| account_access.oldNonce != account_access.newNonce
12121231
})
12131232
.for_each(|account_access| {
12141233
// Record account balance diffs.
@@ -1231,6 +1250,26 @@ fn get_recorded_state_diffs(state: &mut Cheatcodes) -> BTreeMap<Address, Account
12311250
}
12321251
}
12331252

1253+
// Record account nonce diffs.
1254+
if account_access.oldNonce != account_access.newNonce {
1255+
let account_diff =
1256+
state_diffs.entry(account_access.account).or_insert_with(|| {
1257+
AccountStateDiffs {
1258+
label: state.labels.get(&account_access.account).cloned(),
1259+
..Default::default()
1260+
}
1261+
});
1262+
// Update nonce diff. Do not overwrite the initial nonce if already set.
1263+
if let Some(diff) = &mut account_diff.nonce_diff {
1264+
diff.new_value = account_access.newNonce;
1265+
} else {
1266+
account_diff.nonce_diff = Some(NonceDiff {
1267+
previous_value: account_access.oldNonce,
1268+
new_value: account_access.newNonce,
1269+
});
1270+
}
1271+
}
1272+
12341273
// Record account state diffs.
12351274
for storage_access in &account_access.storageAccesses {
12361275
if storage_access.isWrite && !storage_access.reverted {

crates/cheatcodes/src/inspector.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -933,12 +933,15 @@ impl Cheatcodes {
933933
// nonce, a non-zero KECCAK_EMPTY codehash, or non-empty code
934934
let initialized;
935935
let old_balance;
936+
let old_nonce;
936937
if let Ok(acc) = ecx.journaled_state.load_account(call.target_address) {
937938
initialized = acc.info.exists();
938939
old_balance = acc.info.balance;
940+
old_nonce = acc.info.nonce;
939941
} else {
940942
initialized = false;
941943
old_balance = U256::ZERO;
944+
old_nonce = 0;
942945
}
943946
let kind = match call.scheme {
944947
CallScheme::Call => crate::Vm::AccountAccessKind::Call,
@@ -962,6 +965,8 @@ impl Cheatcodes {
962965
initialized,
963966
oldBalance: old_balance,
964967
newBalance: U256::ZERO, // updated on call_end
968+
oldNonce: old_nonce,
969+
newNonce: 0, // updated on call_end
965970
value: call.call_value(),
966971
data: call.input.bytes(ecx),
967972
reverted: false,
@@ -1327,6 +1332,7 @@ impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for Cheatcodes {
13271332
{
13281333
debug_assert!(access_is_call(call_access.kind));
13291334
call_access.newBalance = acc.info.balance;
1335+
call_access.newNonce = acc.info.nonce;
13301336
}
13311337
// Merge the last depth's AccountAccesses into the AccountAccesses at the
13321338
// current depth, or push them back onto the pending
@@ -1642,6 +1648,8 @@ impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for Cheatcodes {
16421648
initialized: true,
16431649
oldBalance: U256::ZERO, // updated on create_end
16441650
newBalance: U256::ZERO, // updated on create_end
1651+
oldNonce: 0, // new contract starts with nonce 0
1652+
newNonce: 1, // updated on create_end (contracts start with nonce 1)
16451653
value: input.value(),
16461654
data: input.init_code(),
16471655
reverted: false,
@@ -1748,6 +1756,7 @@ impl Inspector<EthEvmContext<&mut dyn DatabaseExt>> for Cheatcodes {
17481756
&& let Ok(created_acc) = ecx.journaled_state.load_account(address)
17491757
{
17501758
create_access.newBalance = created_acc.info.balance;
1759+
create_access.newNonce = created_acc.info.nonce;
17511760
create_access.deployedCode =
17521761
created_acc.info.code.clone().unwrap_or_default().original_bytes();
17531762
}
@@ -1945,13 +1954,15 @@ impl Cheatcodes {
19451954
// Ensure that we're not selfdestructing a context recording was initiated on
19461955
let Some(last) = account_accesses.last_mut() else { return };
19471956

1948-
// get previous balance and initialized status of the target account
1957+
// get previous balance, nonce and initialized status of the target account
19491958
let target = try_or_return!(interpreter.stack.peek(0));
19501959
let target = Address::from_word(B256::from(target));
1951-
let (initialized, old_balance) = ecx
1960+
let (initialized, old_balance, old_nonce) = ecx
19521961
.journaled_state
19531962
.load_account(target)
1954-
.map(|account| (account.info.exists(), account.info.balance))
1963+
.map(|account| {
1964+
(account.info.exists(), account.info.balance, account.info.nonce)
1965+
})
19551966
.unwrap_or_default();
19561967

19571968
// load balance of this account
@@ -1972,6 +1983,8 @@ impl Cheatcodes {
19721983
initialized,
19731984
oldBalance: old_balance,
19741985
newBalance: old_balance + value,
1986+
oldNonce: old_nonce,
1987+
newNonce: old_nonce, // nonce doesn't change on selfdestruct
19751988
value,
19761989
data: Bytes::new(),
19771990
reverted: false,
@@ -2059,12 +2072,15 @@ impl Cheatcodes {
20592072
Address::from_word(B256::from(try_or_return!(interpreter.stack.peek(0))));
20602073
let initialized;
20612074
let balance;
2075+
let nonce;
20622076
if let Ok(acc) = ecx.journaled_state.load_account(address) {
20632077
initialized = acc.info.exists();
20642078
balance = acc.info.balance;
2079+
nonce = acc.info.nonce;
20652080
} else {
20662081
initialized = false;
20672082
balance = U256::ZERO;
2083+
nonce = 0;
20682084
}
20692085
let curr_depth = ecx
20702086
.journaled_state
@@ -2082,6 +2098,8 @@ impl Cheatcodes {
20822098
initialized,
20832099
oldBalance: balance,
20842100
newBalance: balance,
2101+
oldNonce: nonce,
2102+
newNonce: nonce, // EXT* operations don't change nonce
20852103
value: U256::ZERO,
20862104
data: Bytes::new(),
20872105
reverted: false,
@@ -2360,6 +2378,8 @@ fn append_storage_access(
23602378
// The remaining fields are defaults
23612379
oldBalance: U256::ZERO,
23622380
newBalance: U256::ZERO,
2381+
oldNonce: 0,
2382+
newNonce: 0,
23632383
value: U256::ZERO,
23642384
data: Bytes::new(),
23652385
deployedCode: Bytes::new(),

testdata/cheats/Vm.sol

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)