@@ -41,7 +41,7 @@ use revm::{
4141 EOFCreateInputs , EOFCreateKind , Gas , InstructionResult , Interpreter , InterpreterAction ,
4242 InterpreterResult ,
4343 } ,
44- primitives:: { BlockEnv , CreateScheme , EVMError , SpecId , EOF_MAGIC_BYTES } ,
44+ primitives:: { BlockEnv , CreateScheme , EVMError , EvmStorageSlot , SpecId , EOF_MAGIC_BYTES } ,
4545 EvmContext , InnerEvmContext , Inspector ,
4646} ;
4747use rustc_hash:: FxHashMap ;
@@ -254,6 +254,89 @@ impl GasMetering {
254254 }
255255}
256256
257+ /// Holds data about arbitrary storage.
258+ #[ derive( Clone , Debug , Default ) ]
259+ pub struct ArbitraryStorage {
260+ /// Mapping of arbitrary storage addresses to generated values (slot, arbitrary value).
261+ /// (SLOADs return random value if storage slot wasn't accessed).
262+ /// Changed values are recorded and used to copy storage to different addresses.
263+ pub values : HashMap < Address , HashMap < U256 , U256 > > ,
264+ /// Mapping of address with storage copied to arbitrary storage address source.
265+ pub copies : HashMap < Address , Address > ,
266+ }
267+
268+ impl ArbitraryStorage {
269+ /// Whether the given address has arbitrary storage.
270+ pub fn is_arbitrary ( & self , address : & Address ) -> bool {
271+ self . values . contains_key ( address)
272+ }
273+
274+ /// Whether the given address is a copy of an address with arbitrary storage.
275+ pub fn is_copy ( & self , address : & Address ) -> bool {
276+ self . copies . contains_key ( address)
277+ }
278+
279+ /// Marks an address with arbitrary storage.
280+ pub fn mark_arbitrary ( & mut self , address : & Address ) {
281+ self . values . insert ( * address, HashMap :: default ( ) ) ;
282+ }
283+
284+ /// Maps an address that copies storage with the arbitrary storage address.
285+ pub fn mark_copy ( & mut self , from : & Address , to : & Address ) {
286+ if self . is_arbitrary ( from) {
287+ self . copies . insert ( * to, * from) ;
288+ }
289+ }
290+
291+ /// Saves arbitrary storage value for a given address:
292+ /// - store value in changed values cache.
293+ /// - update account's storage with given value.
294+ pub fn save < DB : DatabaseExt > (
295+ & mut self ,
296+ ecx : & mut InnerEvmContext < DB > ,
297+ address : Address ,
298+ slot : U256 ,
299+ data : U256 ,
300+ ) {
301+ self . values . get_mut ( & address) . expect ( "missing arbitrary address entry" ) . insert ( slot, data) ;
302+ if let Ok ( mut account) = ecx. load_account ( address) {
303+ account. storage . insert ( slot, EvmStorageSlot :: new ( data) ) ;
304+ }
305+ }
306+
307+ /// Copies arbitrary storage value from source address to the given target address:
308+ /// - if a value is present in arbitrary values cache, then update target storage and return
309+ /// existing value.
310+ /// - if no value was yet generated for given slot, then save new value in cache and update both
311+ /// source and target storages.
312+ pub fn copy < DB : DatabaseExt > (
313+ & mut self ,
314+ ecx : & mut InnerEvmContext < DB > ,
315+ target : Address ,
316+ slot : U256 ,
317+ new_value : U256 ,
318+ ) -> U256 {
319+ let source = self . copies . get ( & target) . expect ( "missing arbitrary copy target entry" ) ;
320+ let storage_cache = self . values . get_mut ( source) . expect ( "missing arbitrary source storage" ) ;
321+ let value = match storage_cache. get ( & slot) {
322+ Some ( value) => * value,
323+ None => {
324+ storage_cache. insert ( slot, new_value) ;
325+ // Update source storage with new value.
326+ if let Ok ( mut source_account) = ecx. load_account ( * source) {
327+ source_account. storage . insert ( slot, EvmStorageSlot :: new ( new_value) ) ;
328+ }
329+ new_value
330+ }
331+ } ;
332+ // Update target storage with new value.
333+ if let Ok ( mut target_account) = ecx. load_account ( target) {
334+ target_account. storage . insert ( slot, EvmStorageSlot :: new ( value) ) ;
335+ }
336+ value
337+ }
338+ }
339+
257340/// List of transactions that can be broadcasted.
258341pub type BroadcastableTransactions = VecDeque < BroadcastableTransaction > ;
259342
@@ -320,6 +403,9 @@ pub struct Cheatcodes {
320403 // **Note**: inner must a BTreeMap because of special `Ord` impl for `MockCallDataContext`
321404 pub mocked_calls : HashMap < Address , BTreeMap < MockCallDataContext , MockCallReturnData > > ,
322405
406+ /// Mocked functions. Maps target address to be mocked to pair of (calldata, mock address).
407+ pub mocked_functions : HashMap < Address , HashMap < Bytes , Address > > ,
408+
323409 /// Expected calls
324410 pub expected_calls : ExpectedCallTracker ,
325411 /// Expected emits
@@ -368,6 +454,9 @@ pub struct Cheatcodes {
368454
369455 /// Ignored traces.
370456 pub ignored_traces : IgnoredTraces ,
457+
458+ /// Addresses with arbitrary storage.
459+ pub arbitrary_storage : ArbitraryStorage ,
371460}
372461
373462// This is not derived because calling this in `fn new` with `..Default::default()` creates a second
@@ -396,6 +485,7 @@ impl Cheatcodes {
396485 recorded_account_diffs_stack : Default :: default ( ) ,
397486 recorded_logs : Default :: default ( ) ,
398487 mocked_calls : Default :: default ( ) ,
488+ mocked_functions : Default :: default ( ) ,
399489 expected_calls : Default :: default ( ) ,
400490 expected_emits : Default :: default ( ) ,
401491 allowed_mem_writes : Default :: default ( ) ,
@@ -410,6 +500,7 @@ impl Cheatcodes {
410500 breakpoints : Default :: default ( ) ,
411501 rng : Default :: default ( ) ,
412502 ignored_traces : Default :: default ( ) ,
503+ arbitrary_storage : Default :: default ( ) ,
413504 }
414505 }
415506
@@ -1045,14 +1136,22 @@ impl<DB: DatabaseExt> Inspector<DB> for Cheatcodes {
10451136 }
10461137
10471138 #[ inline]
1048- fn step_end ( & mut self , interpreter : & mut Interpreter , _ecx : & mut EvmContext < DB > ) {
1139+ fn step_end ( & mut self , interpreter : & mut Interpreter , ecx : & mut EvmContext < DB > ) {
10491140 if self . gas_metering . paused {
10501141 self . meter_gas_end ( interpreter) ;
10511142 }
10521143
10531144 if self . gas_metering . touched {
10541145 self . meter_gas_check ( interpreter) ;
10551146 }
1147+
1148+ // `setArbitraryStorage` and `copyStorage`: add arbitrary values to storage.
1149+ if ( self . arbitrary_storage . is_arbitrary ( & interpreter. contract ( ) . target_address ) ||
1150+ self . arbitrary_storage . is_copy ( & interpreter. contract ( ) . target_address ) ) &&
1151+ interpreter. current_opcode ( ) == op:: SLOAD
1152+ {
1153+ self . arbitrary_storage_end ( interpreter, ecx) ;
1154+ }
10561155 }
10571156
10581157 fn log ( & mut self , interpreter : & mut Interpreter , _ecx : & mut EvmContext < DB > , log : & Log ) {
@@ -1465,6 +1564,43 @@ impl Cheatcodes {
14651564 }
14661565 }
14671566
1567+ /// Generates or copies arbitrary values for storage slots.
1568+ /// Invoked in inspector `step_end` (when the current opcode is not executed), if current opcode
1569+ /// to execute is `SLOAD` and storage slot is cold.
1570+ /// Ensures that in next step (when `SLOAD` opcode is executed) an arbitrary value is returned:
1571+ /// - copies the existing arbitrary storage value (or the new generated one if no value in
1572+ /// cache) from mapped source address to the target address.
1573+ /// - generates arbitrary value and saves it in target address storage.
1574+ #[ cold]
1575+ fn arbitrary_storage_end < DB : DatabaseExt > (
1576+ & mut self ,
1577+ interpreter : & mut Interpreter ,
1578+ ecx : & mut EvmContext < DB > ,
1579+ ) {
1580+ let key = try_or_return ! ( interpreter. stack( ) . peek( 0 ) ) ;
1581+ let target_address = interpreter. contract ( ) . target_address ;
1582+ if let Ok ( value) = ecx. sload ( target_address, key) {
1583+ if value. is_cold && value. data . is_zero ( ) {
1584+ let arbitrary_value = self . rng ( ) . gen ( ) ;
1585+ if self . arbitrary_storage . is_copy ( & target_address) {
1586+ self . arbitrary_storage . copy (
1587+ & mut ecx. inner ,
1588+ target_address,
1589+ key,
1590+ arbitrary_value,
1591+ ) ;
1592+ } else {
1593+ self . arbitrary_storage . save (
1594+ & mut ecx. inner ,
1595+ target_address,
1596+ key,
1597+ arbitrary_value,
1598+ ) ;
1599+ }
1600+ }
1601+ }
1602+ }
1603+
14681604 /// Records storage slots reads and writes.
14691605 #[ cold]
14701606 fn record_accesses ( & mut self , interpreter : & mut Interpreter ) {
0 commit comments