@@ -291,6 +291,84 @@ public void ParallelWorldState_bal_validation_rejects_missing_account_only_reads
291291 Assert . Throws < ParallelWorldState . InvalidBlockLevelAccessListException > ( act ) ;
292292 }
293293
294+ [ Test , MaxTime ( Timeout . MaxTestTime ) ]
295+ public void ParallelWorldState_bal_generation_skips_pre_execution_system_account_read ( )
296+ {
297+ ParallelWorldState stateProvider = new ( TestWorldStateFactory . CreateForTest ( ) )
298+ {
299+ TracingEnabled = true
300+ } ;
301+
302+ using ( stateProvider . BeginSystemAccountReadSuppression ( ) )
303+ {
304+ stateProvider . AddAccountRead ( Address . SystemUser ) ;
305+ }
306+
307+ Assert . That ( stateProvider . GeneratedBlockAccessList . AccountChanges , Is . Empty ) ;
308+ }
309+
310+ [ Test , MaxTime ( Timeout . MaxTestTime ) ]
311+ public void ParallelWorldState_bal_generation_suppresses_system_account_read_across_multiple_system_call_indexes ( )
312+ {
313+ ParallelWorldState stateProvider = new ( TestWorldStateFactory . CreateForTest ( ) )
314+ {
315+ TracingEnabled = true
316+ } ;
317+
318+ AddSystemCallAccountReads ( TestItem . AddressA ) ;
319+ AddSystemCallAccountReads ( TestItem . AddressB ) ;
320+
321+ stateProvider . GeneratedBlockAccessList . IncrementBlockAccessIndex ( ) ;
322+ stateProvider . GeneratedBlockAccessList . IncrementBlockAccessIndex ( ) ;
323+
324+ AddSystemCallAccountReads ( TestItem . AddressC ) ;
325+ AddSystemCallAccountReads ( TestItem . AddressD ) ;
326+
327+ Assert . That ( stateProvider . GeneratedBlockAccessList . GetAccountChanges ( Address . SystemUser ) , Is . Null ) ;
328+ Assert . That ( stateProvider . GeneratedBlockAccessList . GetAccountChanges ( TestItem . AddressA ) , Is . Not . Null ) ;
329+ Assert . That ( stateProvider . GeneratedBlockAccessList . GetAccountChanges ( TestItem . AddressB ) , Is . Not . Null ) ;
330+ Assert . That ( stateProvider . GeneratedBlockAccessList . GetAccountChanges ( TestItem . AddressC ) , Is . Not . Null ) ;
331+ Assert . That ( stateProvider . GeneratedBlockAccessList . GetAccountChanges ( TestItem . AddressD ) , Is . Not . Null ) ;
332+
333+ void AddSystemCallAccountReads ( Address target )
334+ {
335+ using ( stateProvider . BeginSystemAccountReadSuppression ( ) )
336+ {
337+ stateProvider . AddAccountRead ( Address . SystemUser ) ;
338+ stateProvider . AddAccountRead ( target ) ;
339+ }
340+ }
341+ }
342+
343+ [ Test , MaxTime ( Timeout . MaxTestTime ) ]
344+ public void ParallelWorldState_bal_validation_rejects_surplus_pre_execution_system_account_read ( )
345+ {
346+ ParallelWorldState stateProvider = new ( TestWorldStateFactory . CreateForTest ( ) ) ;
347+ BlockAccessList suggestedBlockAccessList = new ( ) ;
348+ suggestedBlockAccessList . AddAccountRead ( Address . SystemUser ) ;
349+ stateProvider . LoadSuggestedBlockAccessList ( suggestedBlockAccessList , 10_000 ) ;
350+
351+ TestDelegate act = ( ) => stateProvider . ValidateBlockAccessList ( Build . A . BlockHeader . TestObject , 0 , 10_000 ) ;
352+
353+ Assert . Throws < ParallelWorldState . InvalidBlockLevelAccessListException > ( act ) ;
354+ }
355+
356+ [ Test , MaxTime ( Timeout . MaxTestTime ) ]
357+ public void ParallelWorldState_bal_validation_rejects_missing_explicit_system_account_read ( )
358+ {
359+ ParallelWorldState stateProvider = new ( TestWorldStateFactory . CreateForTest ( ) )
360+ {
361+ TracingEnabled = true
362+ } ;
363+ stateProvider . LoadSuggestedBlockAccessList ( new BlockAccessList ( ) , 10_000 ) ;
364+ stateProvider . GeneratedBlockAccessList . IncrementBlockAccessIndex ( ) ;
365+ stateProvider . AddAccountRead ( Address . SystemUser ) ;
366+
367+ TestDelegate act = ( ) => stateProvider . ValidateBlockAccessList ( Build . A . BlockHeader . TestObject , 1 , 10_000 ) ;
368+
369+ Assert . Throws < ParallelWorldState . InvalidBlockLevelAccessListException > ( act ) ;
370+ }
371+
294372 [ Test , MaxTime ( Timeout . MaxTestTime ) ]
295373 public void BranchProcessor_no_prewarmer_still_processes_successfully ( )
296374 {
@@ -385,6 +463,13 @@ public void ValidateBlockAccessList(BlockHeader block, ushort index, long gasRem
385463 => ValidatedGasRemaining . Add ( gasRemaining ) ;
386464
387465 public void SetBlockAccessList ( Block block , IReleaseSpec spec ) { }
466+ public IDisposable BeginSystemAccountReadSuppression ( ) => EmptyDisposable . Instance ;
467+
468+ private sealed class EmptyDisposable : IDisposable
469+ {
470+ public static EmptyDisposable Instance { get ; } = new ( ) ;
471+ public void Dispose ( ) { }
472+ }
388473 }
389474
390475 public static IEnumerable < TestCaseData > BlockValidationTransactionsExecutor_bal_validation_cases ( )
0 commit comments