55)
66
77
8+ def run_process_pending_balance_deposits (spec , state ):
9+ yield from run_epoch_processing_with (spec , state , 'process_pending_balance_deposits' )
10+
11+
812@with_electra_and_later
913@spec_state_test
1014def test_pending_deposit_min_activation_balance (spec , state ):
@@ -14,9 +18,9 @@ def test_pending_deposit_min_activation_balance(spec, state):
1418 spec .PendingBalanceDeposit (index = index , amount = amount )
1519 )
1620 pre_balance = state .balances [index ]
17- yield from run_epoch_processing_with (
18- spec , state , "process_pending_balance_deposits"
19- )
21+
22+ yield from run_process_pending_balance_deposits ( spec , state )
23+
2024 assert state .balances [index ] == pre_balance + amount
2125 # No leftover deposit balance to consume when there are no deposits left to process
2226 assert state .deposit_balance_to_consume == 0
@@ -32,9 +36,9 @@ def test_pending_deposit_balance_equal_churn(spec, state):
3236 spec .PendingBalanceDeposit (index = index , amount = amount )
3337 )
3438 pre_balance = state .balances [index ]
35- yield from run_epoch_processing_with (
36- spec , state , "process_pending_balance_deposits"
37- )
39+
40+ yield from run_process_pending_balance_deposits ( spec , state )
41+
3842 assert state .balances [index ] == pre_balance + amount
3943 assert state .deposit_balance_to_consume == 0
4044 assert state .pending_balance_deposits == []
@@ -49,9 +53,9 @@ def test_pending_deposit_balance_above_churn(spec, state):
4953 spec .PendingBalanceDeposit (index = index , amount = amount )
5054 )
5155 pre_balance = state .balances [index ]
52- yield from run_epoch_processing_with (
53- spec , state , "process_pending_balance_deposits"
54- )
56+
57+ yield from run_process_pending_balance_deposits ( spec , state )
58+
5559 # deposit was above churn, balance hasn't changed
5660 assert state .balances [index ] == pre_balance
5761 # deposit balance to consume is the full churn limit
@@ -74,9 +78,9 @@ def test_pending_deposit_preexisting_churn(spec, state):
7478 spec .PendingBalanceDeposit (index = index , amount = amount )
7579 )
7680 pre_balance = state .balances [index ]
77- yield from run_epoch_processing_with (
78- spec , state , "process_pending_balance_deposits"
79- )
81+
82+ yield from run_process_pending_balance_deposits ( spec , state )
83+
8084 # balance was deposited correctly
8185 assert state .balances [index ] == pre_balance + amount
8286 # No leftover deposit balance to consume when there are no deposits left to process
@@ -96,9 +100,9 @@ def test_multiple_pending_deposits_below_churn(spec, state):
96100 spec .PendingBalanceDeposit (index = 1 , amount = amount )
97101 )
98102 pre_balances = state .balances .copy ()
99- yield from run_epoch_processing_with (
100- spec , state , "process_pending_balance_deposits"
101- )
103+
104+ yield from run_process_pending_balance_deposits ( spec , state )
105+
102106 for i in [0 , 1 ]:
103107 assert state .balances [i ] == pre_balances [i ] + amount
104108 # No leftover deposit balance to consume when there are no deposits left to process
@@ -116,9 +120,9 @@ def test_multiple_pending_deposits_above_churn(spec, state):
116120 spec .PendingBalanceDeposit (index = i , amount = amount )
117121 )
118122 pre_balances = state .balances .copy ()
119- yield from run_epoch_processing_with (
120- spec , state , "process_pending_balance_deposits"
121- )
123+
124+ yield from run_process_pending_balance_deposits ( spec , state )
125+
122126 # First two deposits are processed, third is not because above churn
123127 for i in [0 , 1 ]:
124128 assert state .balances [i ] == pre_balances [i ] + amount
@@ -132,3 +136,143 @@ def test_multiple_pending_deposits_above_churn(spec, state):
132136 assert state .pending_balance_deposits == [
133137 spec .PendingBalanceDeposit (index = 2 , amount = amount )
134138 ]
139+
140+
141+ @with_electra_and_later
142+ @spec_state_test
143+ def test_skipped_deposit_exiting_validator (spec , state ):
144+ index = 0
145+ amount = spec .MIN_ACTIVATION_BALANCE
146+ state .pending_balance_deposits .append (spec .PendingBalanceDeposit (index = index , amount = amount ))
147+ pre_pending_balance_deposits = state .pending_balance_deposits .copy ()
148+ pre_balance = state .balances [index ]
149+ # Initiate the validator's exit
150+ spec .initiate_validator_exit (state , index )
151+
152+ yield from run_process_pending_balance_deposits (spec , state )
153+
154+ # Deposit is skipped because validator is exiting
155+ assert state .balances [index ] == pre_balance
156+ # All deposits either processed or postponed, no leftover deposit balance to consume
157+ assert state .deposit_balance_to_consume == 0
158+ # The deposit is still in the queue
159+ assert state .pending_balance_deposits == pre_pending_balance_deposits
160+
161+
162+ @with_electra_and_later
163+ @spec_state_test
164+ def test_multiple_skipped_deposits_exiting_validators (spec , state ):
165+ amount = spec .EFFECTIVE_BALANCE_INCREMENT
166+ for i in [0 , 1 , 2 ]:
167+ # Append pending deposit for validator i
168+ state .pending_balance_deposits .append (spec .PendingBalanceDeposit (index = i , amount = amount ))
169+
170+ # Initiate the exit of validator i
171+ spec .initiate_validator_exit (state , i )
172+ pre_pending_balance_deposits = state .pending_balance_deposits .copy ()
173+ pre_balances = state .balances .copy ()
174+
175+ yield from run_process_pending_balance_deposits (spec , state )
176+
177+ # All deposits are postponed, no balance changes
178+ assert state .balances == pre_balances
179+ # All deposits are postponed, no leftover deposit balance to consume
180+ assert state .deposit_balance_to_consume == 0
181+ # All deposits still in the queue, in the same order
182+ assert state .pending_balance_deposits == pre_pending_balance_deposits
183+
184+
185+ @with_electra_and_later
186+ @spec_state_test
187+ def test_multiple_pending_one_skipped (spec , state ):
188+ amount = spec .EFFECTIVE_BALANCE_INCREMENT
189+ for i in [0 , 1 , 2 ]:
190+ state .pending_balance_deposits .append (spec .PendingBalanceDeposit (index = i , amount = amount ))
191+ pre_balances = state .balances .copy ()
192+ # Initiate the second validator's exit
193+ spec .initiate_validator_exit (state , 1 )
194+
195+ yield from run_process_pending_balance_deposits (spec , state )
196+
197+ # First and last deposit are processed, second is not because of exiting
198+ for i in [0 , 2 ]:
199+ assert state .balances [i ] == pre_balances [i ] + amount
200+ assert state .balances [1 ] == pre_balances [1 ]
201+ # All deposits either processed or postponed, no leftover deposit balance to consume
202+ assert state .deposit_balance_to_consume == 0
203+ # second deposit is still in the queue
204+ assert state .pending_balance_deposits == [spec .PendingBalanceDeposit (index = 1 , amount = amount )]
205+
206+
207+ @with_electra_and_later
208+ @spec_state_test
209+ def test_mixture_of_skipped_and_above_churn (spec , state ):
210+ amount01 = spec .EFFECTIVE_BALANCE_INCREMENT
211+ amount2 = spec .MAX_EFFECTIVE_BALANCE_ELECTRA
212+ # First two validators have small deposit, third validators a large one
213+ for i in [0 , 1 ]:
214+ state .pending_balance_deposits .append (spec .PendingBalanceDeposit (index = i , amount = amount01 ))
215+ state .pending_balance_deposits .append (spec .PendingBalanceDeposit (index = 2 , amount = amount2 ))
216+ pre_balances = state .balances .copy ()
217+ # Initiate the second validator's exit
218+ spec .initiate_validator_exit (state , 1 )
219+
220+ yield from run_process_pending_balance_deposits (spec , state )
221+
222+ # First deposit is processed
223+ assert state .balances [0 ] == pre_balances [0 ] + amount01
224+ # Second deposit is postponed, third is above churn
225+ for i in [1 , 2 ]:
226+ assert state .balances [i ] == pre_balances [i ]
227+ # First deposit consumes some deposit balance
228+ # Deposit balance to consume is not reset because third deposit is not processed
229+ assert state .deposit_balance_to_consume == spec .get_activation_exit_churn_limit (state ) - amount01
230+ # second and third deposit still in the queue, but second is appended at the end
231+ assert state .pending_balance_deposits == [spec .PendingBalanceDeposit (index = 2 , amount = amount2 ),
232+ spec .PendingBalanceDeposit (index = 1 , amount = amount01 )]
233+
234+
235+ @with_electra_and_later
236+ @spec_state_test
237+ def test_processing_deposit_of_withdrawable_validator (spec , state ):
238+ index = 0
239+ amount = spec .MIN_ACTIVATION_BALANCE
240+ state .pending_balance_deposits .append (spec .PendingBalanceDeposit (index = index , amount = amount ))
241+ pre_balance = state .balances [index ]
242+ # Initiate the validator's exit
243+ spec .initiate_validator_exit (state , index )
244+ # Set epoch to withdrawable epoch + 1 to allow processing of the deposit
245+ state .slot = spec .SLOTS_PER_EPOCH * (state .validators [index ].withdrawable_epoch + 1 )
246+
247+ yield from run_process_pending_balance_deposits (spec , state )
248+
249+ # Deposit is correctly processed
250+ assert state .balances [index ] == pre_balance + amount
251+ # No leftover deposit balance to consume when there are no deposits left to process
252+ assert state .deposit_balance_to_consume == 0
253+ assert state .pending_balance_deposits == []
254+
255+
256+ @with_electra_and_later
257+ @spec_state_test
258+ def test_processing_deposit_of_withdrawable_validator_does_not_get_churned (spec , state ):
259+ amount = spec .MAX_EFFECTIVE_BALANCE_ELECTRA
260+ for i in [0 , 1 ]:
261+ state .pending_balance_deposits .append (spec .PendingBalanceDeposit (index = i , amount = amount ))
262+ pre_balances = state .balances .copy ()
263+ # Initiate the first validator's exit
264+ spec .initiate_validator_exit (state , 0 )
265+ # Set epoch to withdrawable epoch + 1 to allow processing of the deposit
266+ state .slot = spec .SLOTS_PER_EPOCH * (state .validators [0 ].withdrawable_epoch + 1 )
267+ # Don't use run_epoch_processing_with to avoid penalties being applied
268+ yield 'pre' , state
269+ spec .process_pending_balance_deposits (state )
270+ yield 'post' , state
271+ # First deposit is processed though above churn limit, because validator is withdrawable
272+ assert state .balances [0 ] == pre_balances [0 ] + amount
273+ # Second deposit is not processed because above churn
274+ assert state .balances [1 ] == pre_balances [1 ]
275+ # Second deposit is not processed, so there's leftover deposit balance to consume.
276+ # First deposit does not consume any.
277+ assert state .deposit_balance_to_consume == spec .get_activation_exit_churn_limit (state )
278+ assert state .pending_balance_deposits == [spec .PendingBalanceDeposit (index = 1 , amount = amount )]
0 commit comments