77from collections .abc import Callable
88from random import Random
99
10- from eth2spec .test .helpers .blob import (
11- get_sample_blob_tx ,
12- )
10+ from eth2spec .test .helpers .blob import get_sample_blob_tx
1311from eth2spec .test .helpers .execution_payload import (
1412 build_randomized_execution_payload ,
1513 compute_el_block_hash_for_block ,
1614)
17- from eth2spec .test .helpers .inactivity_scores import (
18- randomize_inactivity_scores ,
15+ from eth2spec .test .helpers .forks import (
16+ is_post_altair ,
17+ is_post_bellatrix ,
18+ is_post_capella ,
19+ is_post_deneb ,
1920)
21+ from eth2spec .test .helpers .inactivity_scores import randomize_inactivity_scores
2022from eth2spec .test .helpers .multi_operations import (
2123 build_random_block_from_state_for_next_slot ,
2224 get_random_bls_to_execution_changes ,
@@ -60,6 +62,143 @@ def _randomize_deposit_state(spec, state, stats):
6062 }
6163
6264
65+ def _randomize_phase0_fields (spec , state ):
66+ """Set Phase0-specific fields to realistic non-default values."""
67+
68+ rng = Random (8020 ) # same seed as other randomization functions
69+ current_epoch = spec .get_current_epoch (state )
70+
71+ # Randomize ETH1 data votes (simulate realistic ETH1 voting)
72+ if len (state .eth1_data_votes ) == 0 :
73+ num_votes = rng .randint (1 , min (10 , spec .EPOCHS_PER_ETH1_VOTING_PERIOD ))
74+ for i in range (num_votes ):
75+ eth1_data = spec .Eth1Data (
76+ deposit_root = rng .randbytes (32 ),
77+ deposit_count = rng .randint (1 , 1000 ),
78+ block_hash = rng .randbytes (32 ),
79+ )
80+ state .eth1_data_votes .append (eth1_data )
81+
82+ # Randomize historical roots
83+ if current_epoch > 0 and len (state .historical_roots ) == 0 :
84+ num_historical = rng .randint (0 , min (3 , current_epoch ))
85+ for i in range (num_historical ):
86+ state .historical_roots .append (rng .randbytes (32 ))
87+
88+ # Randomize RANDAO mixes
89+ for i in range (min (len (state .randao_mixes ), spec .EPOCHS_PER_HISTORICAL_VECTOR )):
90+ if state .randao_mixes [i ] == b"\x00 " * 32 : # Only modify empty ones
91+ state .randao_mixes [i ] = rng .randbytes (32 )
92+
93+ # Add some slashing penalties
94+ current_epoch_index = current_epoch % spec .EPOCHS_PER_SLASHINGS_VECTOR
95+ if state .slashings [current_epoch_index ] == 0 :
96+ penalty = spec .EFFECTIVE_BALANCE_INCREMENT * rng .randint (0 , 10 )
97+ state .slashings [current_epoch_index ] = penalty
98+
99+
100+ def _randomize_altair_fields (spec , state ):
101+ """Set Altair-specific fields to realistic non-default values."""
102+ if not is_post_altair (spec ):
103+ return
104+
105+ rng = Random (4242 ) # consistent seed with inactivity scores
106+
107+ # Simulate sync committee rotation to catch transition bugs
108+ if hasattr (state , "current_sync_committee" ) and hasattr (state , "next_sync_committee" ):
109+ current_epoch = spec .get_current_epoch (state )
110+ active_validators = spec .get_active_validator_indices (state , current_epoch )
111+
112+ if len (active_validators ) >= spec .SYNC_COMMITTEE_SIZE :
113+ shuffled_validators = list (active_validators )
114+ rng .shuffle (shuffled_validators )
115+ next_committee_indices = shuffled_validators [: spec .SYNC_COMMITTEE_SIZE ]
116+ next_pubkeys = [state .validators [i ].pubkey for i in next_committee_indices ]
117+ state .next_sync_committee .pubkeys = next_pubkeys
118+
119+ if next_pubkeys :
120+ state .next_sync_committee .aggregate_pubkey = rng .randbytes (48 )
121+
122+
123+ def _randomize_bellatrix_fields (spec , state ):
124+ """Set Bellatrix-specific fields to realistic non-default values."""
125+ if not is_post_bellatrix (spec ):
126+ return
127+
128+ rng = Random (3456 ) # consistent seed with block randomization
129+
130+ if hasattr (state , "latest_execution_payload_header" ):
131+ empty_header = spec .ExecutionPayloadHeader ()
132+ if state .latest_execution_payload_header == empty_header :
133+ state .latest_execution_payload_header = spec .ExecutionPayloadHeader (
134+ parent_hash = rng .randbytes (32 ),
135+ fee_recipient = rng .randbytes (20 ),
136+ state_root = rng .randbytes (32 ),
137+ receipts_root = rng .randbytes (32 ),
138+ logs_bloom = rng .randbytes (spec .BYTES_PER_LOGS_BLOOM ),
139+ prev_randao = rng .randbytes (32 ),
140+ block_number = rng .randint (1 , 1000000 ),
141+ gas_limit = rng .randint (8000000 , 30000000 ),
142+ gas_used = rng .randint (100000 , 15000000 ),
143+ timestamp = rng .randint (1609459200 , 2000000000 ),
144+ extra_data = rng .randbytes (rng .randint (0 , 32 )),
145+ base_fee_per_gas = rng .randint (1 , 100000000000 ),
146+ block_hash = rng .randbytes (32 ),
147+ transactions_root = rng .randbytes (32 ),
148+ )
149+
150+
151+ def _randomize_capella_fields (spec , state ):
152+ """Set Capella-specific fields to realistic non-default values."""
153+ if not is_post_capella (spec ):
154+ return
155+
156+ rng = Random (7890 )
157+
158+ # Randomize withdrawal credentials to simulate realistic validator states
159+ if hasattr (state , "validators" ):
160+ num_validators = len (state .validators )
161+
162+ # Set some validators to have ETH1 withdrawal credentials (0x01 prefix)
163+ # to simulate realistic pre-Capella state where some validators haven't
164+ # updated their credentials yet
165+ for i in range (min (num_validators , 20 )):
166+ validator = state .validators [i ]
167+
168+ # ~30% chance to set ETH1 withdrawal credentials
169+ if rng .random () < 0.3 :
170+ eth1_address = rng .randbytes (20 )
171+ validator .withdrawal_credentials = b"\x01 " + b"\x00 " * 11 + eth1_address
172+
173+
174+ def _randomize_deneb_fields (spec , state ):
175+ """Set Deneb-specific fields to realistic non-default values."""
176+ if not is_post_deneb (spec ):
177+ return
178+
179+ rng = Random (9999 )
180+
181+ if hasattr (state , "historical_summaries" ) and len (state .historical_summaries ) == 0 :
182+ current_epoch = spec .get_current_epoch (state )
183+ num_summaries = rng .randint (0 , min (3 , current_epoch // 100 ))
184+
185+ for i in range (num_summaries ):
186+ historical_summary = spec .HistoricalSummary (
187+ block_summary_root = rng .randbytes (32 ),
188+ state_summary_root = rng .randbytes (32 ),
189+ )
190+ state .historical_summaries .append (historical_summary )
191+
192+
193+ def randomize_state_phase0 (spec , state , stats , exit_fraction = 0.1 , slash_fraction = 0.1 ):
194+ scenario_state = randomize_state (
195+ spec , state , stats , exit_fraction = exit_fraction , slash_fraction = slash_fraction
196+ )
197+
198+ _randomize_phase0_fields (spec , state )
199+ return scenario_state
200+
201+
63202def randomize_state (spec , state , stats , exit_fraction = 0.1 , slash_fraction = 0.1 ):
64203 randomize_state_helper (spec , state , exit_fraction = exit_fraction , slash_fraction = slash_fraction )
65204 scenario_state = _randomize_deposit_state (spec , state , stats )
@@ -71,30 +210,31 @@ def randomize_state_altair(spec, state, stats, exit_fraction=0.1, slash_fraction
71210 spec , state , stats , exit_fraction = exit_fraction , slash_fraction = slash_fraction
72211 )
73212 randomize_inactivity_scores (spec , state )
213+ _randomize_altair_fields (spec , state )
74214 return scenario_state
75215
76216
77217def randomize_state_bellatrix (spec , state , stats , exit_fraction = 0.1 , slash_fraction = 0.1 ):
78218 scenario_state = randomize_state_altair (
79219 spec , state , stats , exit_fraction = exit_fraction , slash_fraction = slash_fraction
80220 )
81- # TODO: randomize execution payload, merge status, etc.
221+ _randomize_bellatrix_fields ( spec , state )
82222 return scenario_state
83223
84224
85225def randomize_state_capella (spec , state , stats , exit_fraction = 0.1 , slash_fraction = 0.1 ):
86226 scenario_state = randomize_state_bellatrix (
87227 spec , state , stats , exit_fraction = exit_fraction , slash_fraction = slash_fraction
88228 )
89- # TODO: randomize withdrawals
229+ _randomize_capella_fields ( spec , state )
90230 return scenario_state
91231
92232
93233def randomize_state_deneb (spec , state , stats , exit_fraction = 0.1 , slash_fraction = 0.1 ):
94234 scenario_state = randomize_state_capella (
95235 spec , state , stats , exit_fraction = exit_fraction , slash_fraction = slash_fraction
96236 )
97- # TODO: randomize execution payload
237+ _randomize_deneb_fields ( spec , state )
98238 return scenario_state
99239
100240
0 commit comments