3030 balances_fn = scaled_churn_balances_exceed_activation_exit_churn_limit , threshold_fn = default_activation_threshold )
3131@spec_test
3232@single_phase
33- def test_basic_consolidation (spec , state ):
34- print (spec .config .PRESET_BASE )
33+ def test_basic_consolidation_in_current_consolidation_epoch (spec , state ):
3534 # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
35+ current_epoch = spec .get_current_epoch (state )
36+ source_index = spec .get_active_validator_indices (state , current_epoch )[0 ]
37+ target_index = spec .get_active_validator_indices (state , current_epoch )[1 ]
38+ source_privkey = pubkey_to_privkey [state .validators [source_index ].pubkey ]
39+ target_privkey = pubkey_to_privkey [state .validators [target_index ].pubkey ]
40+
41+ # Set source and target withdrawal credentials to the same eth1 credential
42+ set_eth1_withdrawal_credential_with_balance (spec , state , source_index )
43+ set_eth1_withdrawal_credential_with_balance (spec , state , target_index )
44+
45+ signed_consolidation = sign_consolidation (spec , state ,
46+ spec .Consolidation (
47+ epoch = current_epoch ,
48+ source_index = source_index ,
49+ target_index = target_index ),
50+ source_privkey , target_privkey )
51+
52+ # Set earliest consolidation epoch to the expected exit epoch
53+ expected_exit_epoch = spec .compute_activation_exit_epoch (current_epoch )
54+ state .earliest_consolidation_epoch = expected_exit_epoch
3655 consolidation_churn_limit = spec .get_consolidation_churn_limit (state )
3756 # Set the consolidation balance to consume equal to churn limit
3857 state .consolidation_balance_to_consume = consolidation_churn_limit
58+
59+ yield from run_consolidation_processing (spec , state , signed_consolidation )
60+
61+ # Check consolidation churn is decremented correctly
62+ assert state .consolidation_balance_to_consume == consolidation_churn_limit - spec .MIN_ACTIVATION_BALANCE
63+ # Check exit epoch
64+ assert state .validators [0 ].exit_epoch == expected_exit_epoch
65+
66+ @with_eip7251_and_later
67+ @with_presets ([MINIMAL ], "need sufficient consolidation churn limit" )
68+ @with_custom_state (
69+ balances_fn = scaled_churn_balances_exceed_activation_exit_churn_limit , threshold_fn = default_activation_threshold )
70+ @spec_test
71+ @single_phase
72+ def test_basic_consolidation_in_new_consolidation_epoch (spec , state ):
73+ # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
74+ # Set consolidation balance to consume to some arbitrary nonzero value below the churn limit
75+ state .consolidation_balance_to_consume = spec .EFFECTIVE_BALANCE_INCREMENT
3976 current_epoch = spec .get_current_epoch (state )
4077 source_index = spec .get_active_validator_indices (state , current_epoch )[0 ]
4178 target_index = spec .get_active_validator_indices (state , current_epoch )[1 ]
@@ -56,7 +93,92 @@ def test_basic_consolidation(spec, state):
5693
5794 expected_exit_epoch = spec .compute_activation_exit_epoch (current_epoch )
5895 # Check consolidation churn is decremented correctly
96+ # consolidation_balance_to_consume is replenished to the churn limit since we move to a new consolidation epoch
97+ consolidation_churn_limit = spec .get_consolidation_churn_limit (state )
5998 assert state .consolidation_balance_to_consume == consolidation_churn_limit - spec .MIN_ACTIVATION_BALANCE
99+ # Check exit epochs
100+ assert state .validators [0 ].exit_epoch == expected_exit_epoch
101+
102+
103+ @with_eip7251_and_later
104+ @with_presets ([MINIMAL ], "need sufficient consolidation churn limit" )
105+ @with_custom_state (
106+ balances_fn = scaled_churn_balances_exceed_activation_exit_churn_limit , threshold_fn = default_activation_threshold )
107+ @spec_test
108+ @single_phase
109+ def test_basic_consolidation_with_preexisting_churn (spec , state ):
110+ # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
111+ current_epoch = spec .get_current_epoch (state )
112+ source_index = spec .get_active_validator_indices (state , current_epoch )[0 ]
113+ target_index = spec .get_active_validator_indices (state , current_epoch )[1 ]
114+ source_privkey = pubkey_to_privkey [state .validators [source_index ].pubkey ]
115+ target_privkey = pubkey_to_privkey [state .validators [target_index ].pubkey ]
116+
117+ # Set source and target withdrawal credentials to the same eth1 credential
118+ set_eth1_withdrawal_credential_with_balance (spec , state , source_index )
119+ set_eth1_withdrawal_credential_with_balance (spec , state , target_index )
120+
121+ signed_consolidation = sign_consolidation (spec , state ,
122+ spec .Consolidation (
123+ epoch = current_epoch ,
124+ source_index = source_index ,
125+ target_index = target_index ),
126+ source_privkey , target_privkey )
127+
128+ # Set earliest consolidation epoch to the expected exit epoch
129+ expected_exit_epoch = spec .compute_activation_exit_epoch (current_epoch )
130+ state .earliest_consolidation_epoch = expected_exit_epoch
131+ # Set some nonzero preexisting churn lower than churn limit and sufficient to process the consolidation
132+ preexisting_churn = 2 * spec .MIN_ACTIVATION_BALANCE
133+ state .consolidation_balance_to_consume = preexisting_churn
134+
135+ yield from run_consolidation_processing (spec , state , signed_consolidation )
136+
137+ # Check consolidation churn is decremented correctly
138+ assert state .consolidation_balance_to_consume == preexisting_churn - spec .MIN_ACTIVATION_BALANCE
139+ # Check exit epoch
140+ assert state .validators [0 ].exit_epoch == expected_exit_epoch
141+
142+
143+ @with_eip7251_and_later
144+ @with_presets ([MINIMAL ], "need sufficient consolidation churn limit" )
145+ @with_custom_state (
146+ balances_fn = scaled_churn_balances_exceed_activation_exit_churn_limit , threshold_fn = default_activation_threshold )
147+ @spec_test
148+ @single_phase
149+ def test_basic_consolidation_with_insufficient_preexisting_churn (spec , state ):
150+ # This state has 256 validators each with 32 ETH in MINIMAL preset, 128 ETH consolidation churn
151+ current_epoch = spec .get_current_epoch (state )
152+ source_index = spec .get_active_validator_indices (state , current_epoch )[0 ]
153+ target_index = spec .get_active_validator_indices (state , current_epoch )[1 ]
154+ source_privkey = pubkey_to_privkey [state .validators [source_index ].pubkey ]
155+ target_privkey = pubkey_to_privkey [state .validators [target_index ].pubkey ]
156+
157+ # Set source and target withdrawal credentials to the same eth1 credential
158+ set_eth1_withdrawal_credential_with_balance (spec , state , source_index )
159+ set_eth1_withdrawal_credential_with_balance (spec , state , target_index )
160+
161+ signed_consolidation = sign_consolidation (spec , state ,
162+ spec .Consolidation (
163+ epoch = current_epoch ,
164+ source_index = source_index ,
165+ target_index = target_index ),
166+ source_privkey , target_privkey )
167+
168+ # Set earliest consolidation epoch to the first available epoch
169+ state .earliest_consolidation_epoch = spec .compute_activation_exit_epoch (current_epoch )
170+ # Set preexisting churn lower than required to process the consolidation
171+ preexisting_churn = spec .MIN_ACTIVATION_BALANCE - spec .EFFECTIVE_BALANCE_INCREMENT
172+ state .consolidation_balance_to_consume = preexisting_churn
173+
174+ yield from run_consolidation_processing (spec , state , signed_consolidation )
175+
176+ # It takes one more epoch to process the consolidation due to insufficient churn
177+ expected_exit_epoch = spec .compute_activation_exit_epoch (current_epoch ) + 1
178+ # Check consolidation churn is decremented correctly
179+ consolidation_churn_limit = spec .get_consolidation_churn_limit (state )
180+ remainder = spec .MIN_ACTIVATION_BALANCE % preexisting_churn
181+ assert state .consolidation_balance_to_consume == consolidation_churn_limit - remainder
60182 # Check exit epoch
61183 assert state .validators [0 ].exit_epoch == expected_exit_epoch
62184
@@ -111,6 +233,7 @@ def test_consolidation_churn_limit_balance(spec, state):
111233 source_index = spec .get_active_validator_indices (state , current_epoch )[0 ]
112234 source_validator = state .validators [source_index ]
113235 source_validator .effective_balance = consolidation_churn_limit
236+ # Churn limit increases due to higher total balance
114237 updated_consolidation_churn_limit = spec .get_consolidation_churn_limit (state )
115238 target_index = spec .get_active_validator_indices (state , current_epoch )[1 ]
116239 source_privkey = pubkey_to_privkey [state .validators [source_index ].pubkey ]
@@ -128,6 +251,7 @@ def test_consolidation_churn_limit_balance(spec, state):
128251 source_privkey , target_privkey )
129252 yield from run_consolidation_processing (spec , state , signed_consolidation )
130253
254+ # validator's effective balance fits into the churn, exit as soon as possible
131255 expected_exit_epoch = spec .compute_activation_exit_epoch (current_epoch )
132256 # Check consolidation churn is decremented correctly
133257 assert state .consolidation_balance_to_consume == updated_consolidation_churn_limit - consolidation_churn_limit
@@ -157,6 +281,7 @@ def test_consolidation_balance_larger_than_churn_limit(spec, state):
157281 set_compounding_withdrawal_credential (spec , state , source_index )
158282 set_compounding_withdrawal_credential (spec , state , target_index )
159283
284+ # Consolidation churn limit increases due to higher total balance
160285 new_churn_limit = spec .get_consolidation_churn_limit (state )
161286 remainder = state .validators [source_index ].effective_balance % new_churn_limit
162287 expected_balance = new_churn_limit - remainder
@@ -464,6 +589,21 @@ def test_invalid_exceed_pending_consolidations_limit(spec, state):
464589 source_privkey , target_privkey )
465590 yield from run_consolidation_processing (spec , state , signed_consolidation , valid = False )
466591
592+ @with_eip7251_and_later
593+ @spec_state_test
594+ def test_invalid_not_enough_consolidation_churn_available (spec , state ):
595+ state .validators = state .validators [0 :2 ]
596+ state .pending_consolidations = [spec .PendingConsolidation (source_index = 0 , target_index = 1 )]
597+ current_epoch = spec .get_current_epoch (state )
598+ source_privkey = pubkey_to_privkey [state .validators [0 ].pubkey ]
599+ target_privkey = pubkey_to_privkey [state .validators [1 ].pubkey ]
600+ # Set source and target withdrawal credentials to the same eth1 credential
601+ set_eth1_withdrawal_credential_with_balance (spec , state , 0 )
602+ set_eth1_withdrawal_credential_with_balance (spec , state , 1 )
603+ signed_consolidation = sign_consolidation (spec , state ,
604+ spec .Consolidation (epoch = current_epoch , source_index = 0 , target_index = 1 ),
605+ source_privkey , target_privkey )
606+ yield from run_consolidation_processing (spec , state , signed_consolidation , valid = False )
467607
468608@with_eip7251_and_later
469609@spec_state_test
0 commit comments