Skip to content

Commit 0467078

Browse files
authored
feat(forge): add vm.setArbitraryStorage with overwrites (#10219)
* feat(forge): add vm.setArbitraryStorage with overwrites * Changes after review: better naming, import
1 parent 7a7ad4e commit 0467078

File tree

6 files changed

+101
-6
lines changed

6 files changed

+101
-6
lines changed

crates/cheatcodes/assets/cheatcodes.json

Lines changed: 21 additions & 1 deletion
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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,6 +2826,11 @@ interface Vm {
28262826
#[cheatcode(group = Utilities)]
28272827
function setArbitraryStorage(address target) external;
28282828

2829+
/// Utility cheatcode to set arbitrary storage for given target address and overwrite
2830+
/// any storage slots that have been previously set.
2831+
#[cheatcode(group = Utilities)]
2832+
function setArbitraryStorage(address target, bool overwrite) external;
2833+
28292834
/// Sorts an array in ascending order.
28302835
#[cheatcode(group = Utilities)]
28312836
function sort(uint256[] calldata array) external returns (uint256[] memory);

crates/cheatcodes/src/inspector.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
};
2424
use alloy_primitives::{
2525
hex,
26-
map::{AddressHashMap, HashMap},
26+
map::{AddressHashMap, HashMap, HashSet},
2727
Address, Bytes, Log, TxKind, B256, U256,
2828
};
2929
use alloy_rpc_types::{
@@ -301,12 +301,19 @@ pub struct ArbitraryStorage {
301301
pub values: HashMap<Address, HashMap<U256, U256>>,
302302
/// Mapping of address with storage copied to arbitrary storage address source.
303303
pub copies: HashMap<Address, Address>,
304+
/// Address with storage slots that should be overwritten even if previously set.
305+
pub overwrites: HashSet<Address>,
304306
}
305307

306308
impl ArbitraryStorage {
307309
/// Marks an address with arbitrary storage.
308-
pub fn mark_arbitrary(&mut self, address: &Address) {
310+
pub fn mark_arbitrary(&mut self, address: &Address, overwrite: bool) {
309311
self.values.insert(*address, HashMap::default());
312+
if overwrite {
313+
self.overwrites.insert(*address);
314+
} else {
315+
self.overwrites.remove(address);
316+
}
310317
}
311318

312319
/// Maps an address that copies storage with the arbitrary storage address.
@@ -1210,6 +1217,27 @@ where {
12101217
}
12111218
}
12121219

1220+
/// Whether the given slot of address with arbitrary storage should be overwritten.
1221+
/// True if address is marked as and overwrite and if no value was previously generated for
1222+
/// given slot.
1223+
pub fn should_overwrite_arbitrary_storage(
1224+
&self,
1225+
address: &Address,
1226+
storage_slot: U256,
1227+
) -> bool {
1228+
match &self.arbitrary_storage {
1229+
Some(storage) => {
1230+
storage.overwrites.contains(address) &&
1231+
storage
1232+
.values
1233+
.get(address)
1234+
.and_then(|arbitrary_values| arbitrary_values.get(&storage_slot))
1235+
.is_none()
1236+
}
1237+
None => false,
1238+
}
1239+
}
1240+
12131241
/// Whether the given address is a copy of an address with arbitrary storage.
12141242
pub fn is_arbitrary_storage_copy(&self, address: &Address) -> bool {
12151243
match &self.arbitrary_storage {
@@ -1844,7 +1872,9 @@ impl Cheatcodes {
18441872
return;
18451873
};
18461874

1847-
if value.is_cold && value.data.is_zero() {
1875+
if (value.is_cold && value.data.is_zero()) ||
1876+
self.should_overwrite_arbitrary_storage(&target_address, key)
1877+
{
18481878
if self.has_arbitrary_storage(&target_address) {
18491879
let arbitrary_value = self.rng().gen();
18501880
self.arbitrary_storage.as_mut().unwrap().save(

crates/cheatcodes/src/utils.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,19 @@ impl Cheatcode for resumeTracingCall {
193193
}
194194
}
195195

196-
impl Cheatcode for setArbitraryStorageCall {
196+
impl Cheatcode for setArbitraryStorage_0Call {
197197
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
198198
let Self { target } = self;
199-
ccx.state.arbitrary_storage().mark_arbitrary(target);
199+
ccx.state.arbitrary_storage().mark_arbitrary(target, false);
200+
201+
Ok(Default::default())
202+
}
203+
}
204+
205+
impl Cheatcode for setArbitraryStorage_1Call {
206+
fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
207+
let Self { target, overwrite } = self;
208+
ccx.state.arbitrary_storage().mark_arbitrary(target, *overwrite);
200209

201210
Ok(Default::default())
202211
}

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/ArbitraryStorage.t.sol

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,3 +123,33 @@ contract SymbolicStorageWithSeedTest is DSTest {
123123
assertEq(uint256(storage_value), 0);
124124
}
125125
}
126+
127+
// <https://github.com/foundry-rs/foundry/issues/10084>
128+
contract ArbitraryStorageOverwriteWithSeedTest is DSTest {
129+
Vm vm = Vm(HEVM_ADDRESS);
130+
uint256 _value;
131+
132+
function testArbitraryStorageFalse(uint256 value) public {
133+
_value = value;
134+
vm.setArbitraryStorage(address(this), false);
135+
assertEq(_value, value);
136+
}
137+
138+
function testArbitraryStorageTrue(uint256 value) public {
139+
_value = value;
140+
vm.setArbitraryStorage(address(this), true);
141+
assertTrue(_value != value);
142+
}
143+
144+
function testArbitraryStorageFalse_setAfter(uint256 value) public {
145+
vm.setArbitraryStorage(address(this), false);
146+
_value = value;
147+
assertEq(_value, value);
148+
}
149+
150+
function testArbitraryStorageTrue_setAfter(uint256 value) public {
151+
vm.setArbitraryStorage(address(this), true);
152+
_value = value;
153+
assertEq(_value, value);
154+
}
155+
}

0 commit comments

Comments
 (0)