@@ -403,11 +403,11 @@ pub struct ArbitraryStorage {
403403 /// Mapping of arbitrary storage addresses to generated values (slot, arbitrary value).
404404 /// (SLOADs return random value if storage slot wasn't accessed).
405405 /// Changed values are recorded and used to copy storage to different addresses.
406- pub values : HashMap < Address , HashMap < U256 , U256 > > ,
406+ values : HashMap < Address , HashMap < U256 , U256 > > ,
407407 /// Mapping of address with storage copied to arbitrary storage address source.
408- pub copies : HashMap < Address , Address > ,
408+ copies : HashMap < Address , Address > ,
409409 /// Address with storage slots that should be overwritten even if previously set.
410- pub overwrites : HashSet < Address > ,
410+ overwrites : HashSet < Address > ,
411411}
412412
413413impl ArbitraryStorage {
@@ -428,6 +428,47 @@ impl ArbitraryStorage {
428428 }
429429 }
430430
431+ /// Returns addresses explicitly marked with arbitrary storage.
432+ fn targets ( & self ) -> impl Iterator < Item = Address > + ' _ {
433+ self . values . keys ( ) . copied ( )
434+ }
435+
436+ /// Returns addresses explicitly marked with arbitrary storage and whether nonzero slots are
437+ /// overwritten.
438+ fn target_overwrite_modes ( & self ) -> impl Iterator < Item = ( Address , bool ) > + ' _ {
439+ self . values . keys ( ) . map ( |address| ( * address, self . overwrites . contains ( address) ) )
440+ }
441+
442+ /// Returns addresses that copy storage from arbitrary-storage targets.
443+ fn copied_targets ( & self ) -> impl Iterator < Item = Address > + ' _ {
444+ self . copies . keys ( ) . copied ( )
445+ }
446+
447+ /// Returns copied arbitrary-storage targets and their source address.
448+ fn copied_target_sources ( & self ) -> impl Iterator < Item = ( Address , Address ) > + ' _ {
449+ self . copies . iter ( ) . map ( |( target, source) | ( * target, * source) )
450+ }
451+
452+ /// Caches a concrete value for a slot on an arbitrary-storage address or copied target.
453+ fn cache_value ( & mut self , address : Address , slot : U256 , data : U256 ) {
454+ if let Some ( values) = self . values . get_mut ( & address) {
455+ values. insert ( slot, data) ;
456+ return ;
457+ }
458+
459+ let Some ( source) = self . copies . get ( & address) . copied ( ) else {
460+ return ;
461+ } ;
462+ if let Some ( values) = self . values . get_mut ( & source) {
463+ values. insert ( slot, data) ;
464+ }
465+ }
466+
467+ /// Returns a cached arbitrary value for a slot.
468+ fn cached_value ( & self , address : Address , slot : U256 ) -> Option < U256 > {
469+ self . values . get ( & address) . and_then ( |values| values. get ( & slot) ) . copied ( )
470+ }
471+
431472 /// Saves arbitrary storage value for a given address:
432473 /// - store value in changed values cache.
433474 /// - update account's storage with given value.
@@ -1298,6 +1339,49 @@ impl<FEN: FoundryEvmNetwork> Cheatcodes<FEN> {
12981339 self . arbitrary_storage . get_or_insert_with ( ArbitraryStorage :: default)
12991340 }
13001341
1342+ /// Returns addresses explicitly marked with arbitrary storage.
1343+ pub fn arbitrary_storage_targets ( & self ) -> impl Iterator < Item = Address > + ' _ {
1344+ self . arbitrary_storage . as_ref ( ) . into_iter ( ) . flat_map ( ArbitraryStorage :: targets)
1345+ }
1346+
1347+ /// Returns addresses explicitly marked with arbitrary storage and whether nonzero slots are
1348+ /// overwritten.
1349+ pub fn arbitrary_storage_target_overwrite_modes (
1350+ & self ,
1351+ ) -> impl Iterator < Item = ( Address , bool ) > + ' _ {
1352+ self . arbitrary_storage
1353+ . as_ref ( )
1354+ . into_iter ( )
1355+ . flat_map ( ArbitraryStorage :: target_overwrite_modes)
1356+ }
1357+
1358+ /// Returns addresses that copy storage from arbitrary-storage targets.
1359+ pub fn arbitrary_storage_copied_targets ( & self ) -> impl Iterator < Item = Address > + ' _ {
1360+ self . arbitrary_storage . as_ref ( ) . into_iter ( ) . flat_map ( ArbitraryStorage :: copied_targets)
1361+ }
1362+
1363+ /// Returns copied arbitrary-storage targets and their source address.
1364+ pub fn arbitrary_storage_copied_target_sources (
1365+ & self ,
1366+ ) -> impl Iterator < Item = ( Address , Address ) > + ' _ {
1367+ self . arbitrary_storage
1368+ . as_ref ( )
1369+ . into_iter ( )
1370+ . flat_map ( ArbitraryStorage :: copied_target_sources)
1371+ }
1372+
1373+ /// Caches a concrete replay value for a slot on an arbitrary-storage address or copied target.
1374+ pub fn cache_arbitrary_storage_value ( & mut self , address : Address , slot : U256 , value : U256 ) {
1375+ if let Some ( storage) = & mut self . arbitrary_storage {
1376+ storage. cache_value ( address, slot, value) ;
1377+ }
1378+ }
1379+
1380+ /// Returns a cached arbitrary-storage replay value for a slot.
1381+ pub fn cached_arbitrary_storage_value ( & self , address : Address , slot : U256 ) -> Option < U256 > {
1382+ self . arbitrary_storage . as_ref ( ) . and_then ( |storage| storage. cached_value ( address, slot) )
1383+ }
1384+
13011385 /// Whether the given address has arbitrary storage.
13021386 pub fn has_arbitrary_storage ( & self , address : & Address ) -> bool {
13031387 match & self . arbitrary_storage {
@@ -2535,7 +2619,9 @@ impl<FEN: FoundryEvmNetwork> Cheatcodes<FEN> {
25352619 || self . should_overwrite_arbitrary_storage ( & target_address, key)
25362620 {
25372621 if self . has_arbitrary_storage ( & target_address) {
2538- let arbitrary_value = self . rng ( ) . random ( ) ;
2622+ let arbitrary_value = self
2623+ . cached_arbitrary_storage_value ( target_address, key)
2624+ . unwrap_or_else ( || self . rng ( ) . random ( ) ) ;
25392625 self . arbitrary_storage . as_mut ( ) . unwrap ( ) . save (
25402626 ecx,
25412627 target_address,
@@ -3218,4 +3304,18 @@ mod tests {
32183304 ) ) ;
32193305 assert ! ( cheats. has_log_hooks( ) ) ;
32203306 }
3307+
3308+ #[ test]
3309+ fn arbitrary_storage_cache_value_routes_copied_targets_to_source ( ) {
3310+ let mut storage = ArbitraryStorage :: default ( ) ;
3311+ let source = Address :: repeat_byte ( 0x11 ) ;
3312+ let copied = Address :: repeat_byte ( 0x22 ) ;
3313+ let slot = U256 :: from ( 7 ) ;
3314+
3315+ storage. mark_arbitrary ( & source, false ) ;
3316+ storage. mark_copy ( & source, & copied) ;
3317+ storage. cache_value ( copied, slot, U256 :: ZERO ) ;
3318+
3319+ assert_eq ! ( storage. cached_value( source, slot) , Some ( U256 :: ZERO ) ) ;
3320+ }
32213321}
0 commit comments