44from eth2spec .test .helpers .deposits import mock_deposit
55from eth2spec .test .helpers .forks import (
66 is_post_altair ,
7+ is_post_capella ,
78 is_post_electra ,
89)
910from eth2spec .test .helpers .state import next_epoch
@@ -296,6 +297,94 @@ def set_some_pending_consolidations(spec, state, rng):
296297 return consolidation_pairs
297298
298299
300+ def set_electra_churn_fields (spec , state , rng ):
301+ """Set Electra churn-related fields to realistic non-default values if post-Electra."""
302+ current_epoch = spec .get_current_epoch (state )
303+
304+ state .earliest_exit_epoch = current_epoch + rng .randint (0 , 4 )
305+ state .earliest_consolidation_epoch = current_epoch + rng .randint (0 , 3 )
306+
307+ # Set realistic churn balances
308+ max_churn = spec .EFFECTIVE_BALANCE_INCREMENT * 10
309+ state .deposit_balance_to_consume = rng .randint (0 , max_churn )
310+ state .exit_balance_to_consume = rng .randint (0 , max_churn )
311+ state .consolidation_balance_to_consume = rng .randint (0 , max_churn )
312+
313+
314+ def set_withdrawal_fields (spec , state , rng ):
315+ """Set withdrawal-related fields to realistic non-default values if post-Capella."""
316+ state .next_withdrawal_index = rng .randint (1 , 1000 )
317+ # Ensure next_withdrawal_validator_index is non-zero and valid
318+ if len (state .validators ) > 1 :
319+ state .next_withdrawal_validator_index = rng .randint (1 , len (state .validators ) - 1 )
320+ else :
321+ state .next_withdrawal_validator_index = 0
322+
323+
324+ def set_deposit_request_fields (spec , state , rng ):
325+ """Set deposit request fields to realistic non-default values if post-Electra."""
326+ if state .deposit_requests_start_index == spec .FAR_FUTURE_EPOCH :
327+ state .deposit_requests_start_index = rng .randint (100 , 10000 )
328+
329+
330+ def set_finality_fields (spec , state , rng ):
331+ """Set finality fields to realistic non-default values safely."""
332+ current_epoch = spec .get_current_epoch (state )
333+
334+ # Only modify if they're still at genesis defaults (to avoid conflicts with patch_state_to_non_leaking)
335+ if (
336+ state .finalized_checkpoint .epoch == 0
337+ and state .current_justified_checkpoint .epoch == 0
338+ and state .previous_justified_checkpoint .epoch == 0
339+ ):
340+ # Set realistic but valid finality progression
341+ if current_epoch > 3 :
342+ finalized_epoch = max (0 , current_epoch - 3 )
343+ prev_justified_epoch = max (finalized_epoch , current_epoch - 2 )
344+ curr_justified_epoch = max (prev_justified_epoch , current_epoch - 1 )
345+
346+ # Create realistic checkpoint progression
347+ state .finalized_checkpoint = spec .Checkpoint (
348+ epoch = finalized_epoch ,
349+ root = spec .get_block_root (state , finalized_epoch )
350+ if finalized_epoch > 0
351+ else b"\x01 " * 32 ,
352+ )
353+ state .previous_justified_checkpoint = spec .Checkpoint (
354+ epoch = prev_justified_epoch ,
355+ root = spec .get_block_root (state , prev_justified_epoch )
356+ if prev_justified_epoch > 0
357+ else b"\x02 " * 32 ,
358+ )
359+ state .current_justified_checkpoint = spec .Checkpoint (
360+ epoch = curr_justified_epoch ,
361+ root = spec .get_block_root (state , curr_justified_epoch )
362+ if curr_justified_epoch > 0
363+ else b"\x03 " * 32 ,
364+ )
365+
366+
367+ def set_altair_fields (spec , state , rng ):
368+ """Set Altair-specific fields to realistic non-default values."""
369+ # TODO: Implement sync committee randomization
370+ # This would help catch bugs in Altair→Bellatrix transitions
371+ pass
372+
373+
374+ def set_bellatrix_fields (spec , state , rng ):
375+ """Set Bellatrix-specific fields to realistic non-default values."""
376+ # TODO: Implement execution payload header randomization
377+ # This would help catch bugs in Bellatrix→Capella transitions
378+ pass
379+
380+
381+ def set_deneb_fields (spec , state , rng ):
382+ """Set Deneb-specific fields to realistic non-default values."""
383+ # TODO: Implement historical summaries randomization
384+ # This would help catch bugs in Deneb→Electra transitions
385+ pass
386+
387+
299388def randomize_state (spec , state , rng = None , exit_fraction = 0.5 , slash_fraction = 0.5 ):
300389 if rng is None :
301390 rng = Random (8020 )
@@ -307,6 +396,20 @@ def randomize_state(spec, state, rng=None, exit_fraction=0.5, slash_fraction=0.5
307396 set_some_pending_deposits (spec , state , rng )
308397 set_some_pending_partial_withdrawals (spec , state , rng )
309398 set_some_pending_consolidations (spec , state , rng )
399+ set_electra_churn_fields (spec , state , rng )
400+ set_deposit_request_fields (spec , state , rng )
401+ # Apply withdrawal fields for Capella+ (includes Electra)
402+ if is_post_capella (spec ):
403+ set_withdrawal_fields (spec , state , rng )
404+ # Add finality fields for all forks (with safety checks)
405+ set_finality_fields (spec , state , rng )
406+ # TODO: Add other fork-specific fields when implemented
407+ # if is_post_altair(spec):
408+ # set_altair_fields(spec, state, rng)
409+ # if is_post_bellatrix(spec):
410+ # set_bellatrix_fields(spec, state, rng)
411+ # if is_post_deneb(spec):
412+ # set_deneb_fields(spec, state, rng)
310413
311414
312415def patch_state_to_non_leaking (spec , state ):
0 commit comments