@@ -212,13 +212,18 @@ pub struct ForkDbStateSnapshot<N: Network, B: ForkBlockEnv = BlockEnv> {
212212}
213213
214214impl < N : Network , B : ForkBlockEnv > ForkDbStateSnapshot < N , B > {
215- fn get_storage ( & self , address : Address , index : U256 ) -> Option < U256 > {
216- self . local
217- . cache
218- . accounts
219- . get ( & address)
220- . and_then ( |account| account. storage . get ( & index) )
221- . copied ( )
215+ /// Lookup storage in `state_snapshot`, then fall back to the backend (remote RPC).
216+ fn storage_from_snapshot_or_backend (
217+ & self ,
218+ address : Address ,
219+ index : U256 ,
220+ ) -> Result < U256 , DatabaseError > {
221+ // Check state_snapshot.storage first (data fetched by SharedBackend / disk cache).
222+ if let Some ( val) = self . state_snapshot . storage . get ( & address) . and_then ( |s| s. get ( & index) ) {
223+ return Ok ( * val) ;
224+ }
225+ // Fall back to the underlying backend (SharedBackend → remote RPC).
226+ DatabaseRef :: storage_ref ( & self . local , address, index)
222227 }
223228}
224229
@@ -250,15 +255,9 @@ impl<N: Network, B: ForkBlockEnv> DatabaseRef for ForkDbStateSnapshot<N, B> {
250255 match self . local . cache . accounts . get ( & address) {
251256 Some ( account) => match account. storage . get ( & index) {
252257 Some ( entry) => Ok ( * entry) ,
253- None => match self . get_storage ( address, index) {
254- None => DatabaseRef :: storage_ref ( & self . local , address, index) ,
255- Some ( storage) => Ok ( storage) ,
256- } ,
257- } ,
258- None => match self . get_storage ( address, index) {
259- None => DatabaseRef :: storage_ref ( & self . local , address, index) ,
260- Some ( storage) => Ok ( storage) ,
258+ None => self . storage_from_snapshot_or_backend ( address, index) ,
261259 } ,
260+ None => self . storage_from_snapshot_or_backend ( address, index) ,
262261 }
263262 }
264263
@@ -303,4 +302,28 @@ mod tests {
303302 assert ! ( loaded. is_some( ) ) ;
304303 assert_eq ! ( loaded. unwrap( ) , info) ;
305304 }
305+
306+ /// Verifies that `ForkDbStateSnapshot::storage_ref` reads from `state_snapshot.storage`
307+ /// when the slot is missing from `local.cache.accounts`. Without this lookup the call
308+ /// would fall through to the backend and return the unrelated remote value.
309+ #[ tokio:: test( flavor = "multi_thread" ) ]
310+ async fn fork_db_state_snapshot_reads_storage_from_snapshot ( ) {
311+ let rpc = foundry_test_utils:: rpc:: next_http_rpc_endpoint ( ) ;
312+ let provider = get_http_provider ( rpc. clone ( ) ) ;
313+ let meta = BlockchainDbMeta :: new ( BlockEnv :: default ( ) , rpc) ;
314+ let db = BlockchainDb :: new ( meta, None ) ;
315+ let backend = SharedBackend :: spawn_backend ( Arc :: new ( provider) , db, None ) . await ;
316+
317+ let address = Address :: random ( ) ;
318+ let slot = U256 :: from ( 42u64 ) ;
319+ let expected = U256 :: from ( 0xdeadbeefu64 ) ;
320+
321+ let mut state_snapshot = StateSnapshot :: default ( ) ;
322+ state_snapshot. storage . entry ( address) . or_default ( ) . insert ( slot, expected) ;
323+
324+ let snapshot = ForkDbStateSnapshot { local : CacheDB :: new ( backend) , state_snapshot } ;
325+
326+ let got = DatabaseRef :: storage_ref ( & snapshot, address, slot) . unwrap ( ) ;
327+ assert_eq ! ( got, expected) ;
328+ }
306329}
0 commit comments