Skip to content

Commit ddc5468

Browse files
authored
feat(cheatcodes): getStorageAccesses (#11296)
1 parent 5f8c855 commit ddc5468

File tree

5 files changed

+89
-3
lines changed

5 files changed

+89
-3
lines changed

crates/cheatcodes/assets/cheatcodes.json

Lines changed: 20 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
@@ -432,6 +432,10 @@ interface Vm {
432432
#[cheatcode(group = Evm, safety = Safe)]
433433
function getStateDiffJson() external view returns (string memory diff);
434434

435+
/// Returns an array of `StorageAccess` from current `vm.stateStateDiffRecording` session
436+
#[cheatcode(group = Evm, safety = Safe)]
437+
function getStorageAccesses() external view returns (StorageAccess[] memory accesses);
438+
435439
// -------- Recording Map Writes --------
436440

437441
/// Starts recording all map SSTOREs for later retrieval.

crates/cheatcodes/src/evm.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,20 @@ impl Cheatcode for getStateDiffJsonCall {
855855
}
856856
}
857857

858+
impl Cheatcode for getStorageAccessesCall {
859+
fn apply(&self, state: &mut Cheatcodes) -> Result {
860+
let mut storage_accesses = Vec::new();
861+
862+
if let Some(recorded_diffs) = &state.recorded_account_diffs_stack {
863+
for account_accesses in recorded_diffs.iter().flatten() {
864+
storage_accesses.extend(account_accesses.storageAccesses.clone());
865+
}
866+
}
867+
868+
Ok(storage_accesses.abi_encode())
869+
}
870+
}
871+
858872
impl Cheatcode for broadcastRawTransactionCall {
859873
fn apply_full(&self, ccx: &mut CheatsCtxt, executor: &mut dyn CheatcodesExecutor) -> Result {
860874
let tx = TxEnvelope::decode(&mut self.data.as_ref())

testdata/cheats/Vm.sol

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

testdata/default/cheats/RecordAccountAccesses.t.sol

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ contract RecordAccountAccessesTest is DSTest {
269269
);
270270
string memory diffsJson = cheats.getStateDiffJson();
271271
assertEq(
272-
"{\"0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9\":{\"label\":null,\"contract\":\"default/cheats/RecordAccountAccesses.t.sol:StorageAccessor\",\"balanceDiff\":null,\"nonceDiff\":null,\"stateDiff\":{\"0x00000000000000000000000000000000000000000000000000000000000004d3\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x000000000000000000000000000000000000000000000000000000000000162e\"}}},\"0xc7183455a4c133ae270771860664b6b7ec320bb1\":{\"label\":null,\"contract\":\"default/cheats/RecordAccountAccesses.t.sol:StorageAccessor\",\"balanceDiff\":null,\"nonceDiff\":null,\"stateDiff\":{\"0x000000000000000000000000000000000000000000000000000000000000162e\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x00000000000000000000000000000000000000000000000000000000000004d2\"}}}}",
272+
'{"0x5991a2df15a8f6a256d3ec51e99254cd3fb576a9":{"label":null,"contract":"default/cheats/RecordAccountAccesses.t.sol:StorageAccessor","balanceDiff":null,"nonceDiff":null,"stateDiff":{"0x00000000000000000000000000000000000000000000000000000000000004d3":{"previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","newValue":"0x000000000000000000000000000000000000000000000000000000000000162e"}}},"0xc7183455a4c133ae270771860664b6b7ec320bb1":{"label":null,"contract":"default/cheats/RecordAccountAccesses.t.sol:StorageAccessor","balanceDiff":null,"nonceDiff":null,"stateDiff":{"0x000000000000000000000000000000000000000000000000000000000000162e":{"previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","newValue":"0x00000000000000000000000000000000000000000000000000000000000004d2"}}}}',
273273
diffsJson
274274
);
275275
Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(cheats.stopAndReturnStateDiff());
@@ -491,7 +491,7 @@ contract RecordAccountAccessesTest is DSTest {
491491
cheats.getStateDiff()
492492
);
493493
assertEq(
494-
"{\"0x00000000000000000000000000000000000004d2\":{\"label\":null,\"contract\":null,\"balanceDiff\":{\"previousValue\":\"0x0\",\"newValue\":\"0x16345785d8a0000\"},\"nonceDiff\":null,\"stateDiff\":{}}}",
494+
'{"0x00000000000000000000000000000000000004d2":{"label":null,"contract":null,"balanceDiff":{"previousValue":"0x0","newValue":"0x16345785d8a0000"},"nonceDiff":null,"stateDiff":{}}}',
495495
cheats.getStateDiffJson()
496496
);
497497
Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(cheats.stopAndReturnStateDiff());
@@ -837,7 +837,7 @@ contract RecordAccountAccessesTest is DSTest {
837837
cheats.getStateDiff()
838838
);
839839
assertEq(
840-
"{\"0x2e234dae75c793f67a35089c9d99245e1c58470b\":{\"label\":\"NestedStorer\",\"contract\":\"default/cheats/RecordAccountAccesses.t.sol:NestedStorer\",\"balanceDiff\":null,\"nonceDiff\":null,\"stateDiff\":{\"0x4566fa0cd03218c55bba914d793f5e6b9113172c1f684bb5f464c08c867e8977\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"},\"0xbf57896b60daefa2c41de2feffecfc11debd98ea8c913a5170f60e53959ac00a\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"},\"0xc664893a982d78bbeab379feef216ff517b7ea73626b280723be1ace370364cd\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"},\"0xdc5330afa9872081253545dca3f448752688ff1b098b38c1abe4c4cdff4b0b0e\":{\"previousValue\":\"0x0000000000000000000000000000000000000000000000000000000000000000\",\"newValue\":\"0x0000000000000000000000000000000000000000000000000000000000000001\"}}}}",
840+
'{"0x2e234dae75c793f67a35089c9d99245e1c58470b":{"label":"NestedStorer","contract":"default/cheats/RecordAccountAccesses.t.sol:NestedStorer","balanceDiff":null,"nonceDiff":null,"stateDiff":{"0x4566fa0cd03218c55bba914d793f5e6b9113172c1f684bb5f464c08c867e8977":{"previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","newValue":"0x0000000000000000000000000000000000000000000000000000000000000001"},"0xbf57896b60daefa2c41de2feffecfc11debd98ea8c913a5170f60e53959ac00a":{"previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","newValue":"0x0000000000000000000000000000000000000000000000000000000000000001"},"0xc664893a982d78bbeab379feef216ff517b7ea73626b280723be1ace370364cd":{"previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","newValue":"0x0000000000000000000000000000000000000000000000000000000000000001"},"0xdc5330afa9872081253545dca3f448752688ff1b098b38c1abe4c4cdff4b0b0e":{"previousValue":"0x0000000000000000000000000000000000000000000000000000000000000000","newValue":"0x0000000000000000000000000000000000000000000000000000000000000001"}}}}',
841841
cheats.getStateDiffJson()
842842
);
843843
Vm.AccountAccess[] memory called = filterExtcodesizeForLegacyTests(cheats.stopAndReturnStateDiff());
@@ -1403,4 +1403,51 @@ contract RecordAccountAccessesTest is DSTest {
14031403
function deriveCreate2Address(address deployer, bytes32 salt, bytes32 codeHash) internal pure returns (address) {
14041404
return address(uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, codeHash)))));
14051405
}
1406+
1407+
/// @notice Simple test for getStorageAccesses() cheatcode
1408+
function testGetStorageAccesses() public {
1409+
StorageAccessor accessor = test1;
1410+
1411+
// Start recording to enable storage access tracking
1412+
cheats.startStateDiffRecording();
1413+
1414+
// Perform a read operation
1415+
accessor.read(bytes32(uint256(789)));
1416+
1417+
// Perform a write operation
1418+
accessor.write(bytes32(uint256(123)), bytes32(uint256(456)));
1419+
1420+
// Perform another read operation after the write
1421+
accessor.read(bytes32(uint256(123)));
1422+
1423+
// Get all storage accesses
1424+
Vm.StorageAccess[] memory accesses = cheats.getStorageAccesses();
1425+
1426+
// Check we have 3 storage accesses (2 reads + 1 write)
1427+
assertEq(accesses.length, 3, "should have 3 storage accesses");
1428+
1429+
// Check the first read access
1430+
assertEq(accesses[0].account, address(accessor));
1431+
assertEq(accesses[0].slot, bytes32(uint256(789)));
1432+
assertEq(accesses[0].isWrite, false);
1433+
assertEq(accesses[0].previousValue, bytes32(uint256(0)));
1434+
assertEq(accesses[0].newValue, bytes32(uint256(0)));
1435+
assertEq(accesses[0].reverted, false);
1436+
1437+
// Check the write access
1438+
assertEq(accesses[1].account, address(accessor));
1439+
assertEq(accesses[1].slot, bytes32(uint256(123)));
1440+
assertEq(accesses[1].isWrite, true);
1441+
assertEq(accesses[1].previousValue, bytes32(uint256(0)));
1442+
assertEq(accesses[1].newValue, bytes32(uint256(456)));
1443+
assertEq(accesses[1].reverted, false);
1444+
1445+
// Check the second read access (reading the value we just wrote)
1446+
assertEq(accesses[2].account, address(accessor));
1447+
assertEq(accesses[2].slot, bytes32(uint256(123)));
1448+
assertEq(accesses[2].isWrite, false);
1449+
assertEq(accesses[2].previousValue, bytes32(uint256(456)));
1450+
assertEq(accesses[2].newValue, bytes32(uint256(456)));
1451+
assertEq(accesses[2].reverted, false);
1452+
}
14061453
}

0 commit comments

Comments
 (0)