@@ -2,6 +2,7 @@ package electra
22
33import (
44 "context"
5+ "fmt"
56
67 "github.com/pkg/errors"
78 "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
@@ -13,7 +14,9 @@ import (
1314 "github.com/prysmaticlabs/prysm/v5/contracts/deposit"
1415 "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
1516 enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1"
17+ eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
1618 ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
19+ "github.com/prysmaticlabs/prysm/v5/time/slots"
1720 log "github.com/sirupsen/logrus"
1821 "go.opencensus.io/trace"
1922)
@@ -190,12 +193,27 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, domain []byte) error
190193// available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit(state)
191194// processed_amount = 0
192195// next_deposit_index = 0
196+ // deposits_to_postpone = []
193197//
194198// for deposit in state.pending_balance_deposits:
195- // if processed_amount + deposit.amount > available_for_processing:
196- // break
197- // increase_balance(state, deposit.index, deposit.amount)
198- // processed_amount += deposit.amount
199+ // validator = state.validators[deposit.index]
200+ // # Validator is exiting, postpone the deposit until after withdrawable epoch
201+ // if validator.exit_epoch < FAR_FUTURE_EPOCH:
202+ // if get_current_epoch(state) <= validator.withdrawable_epoch:
203+ // deposits_to_postpone.append(deposit)
204+ // # Deposited balance will never become active. Increase balance but do not consume churn
205+ // else:
206+ // increase_balance(state, deposit.index, deposit.amount)
207+ // # Validator is not exiting, attempt to process deposit
208+ // else:
209+ // # Deposit does not fit in the churn, no more deposit processing in this epoch.
210+ // if processed_amount + deposit.amount > available_for_processing:
211+ // break
212+ // # Deposit fits in the churn, process it. Increase balance and consume churn.
213+ // else:
214+ // increase_balance(state, deposit.index, deposit.amount)
215+ // processed_amount += deposit.amount
216+ // # Regardless of how the deposit was handled, we move on in the queue.
199217// next_deposit_index += 1
200218//
201219// state.pending_balance_deposits = state.pending_balance_deposits[next_deposit_index:]
@@ -204,6 +222,8 @@ func verifyDepositDataSigningRoot(obj *ethpb.Deposit_Data, domain []byte) error
204222// state.deposit_balance_to_consume = Gwei(0)
205223// else:
206224// state.deposit_balance_to_consume = available_for_processing - processed_amount
225+ //
226+ // state.pending_balance_deposits += deposits_to_postpone
207227func ProcessPendingBalanceDeposits (ctx context.Context , st state.BeaconState , activeBalance primitives.Gwei ) error {
208228 _ , span := trace .StartSpan (ctx , "electra.ProcessPendingBalanceDeposits" )
209229 defer span .End ()
@@ -216,35 +236,67 @@ func ProcessPendingBalanceDeposits(ctx context.Context, st state.BeaconState, ac
216236 if err != nil {
217237 return err
218238 }
219-
220239 availableForProcessing := depBalToConsume + helpers .ActivationExitChurnLimit (activeBalance )
240+ processedAmount := uint64 (0 )
221241 nextDepositIndex := 0
242+ var depositsToPostpone []* eth.PendingBalanceDeposit
222243
223244 deposits , err := st .PendingBalanceDeposits ()
224245 if err != nil {
225246 return err
226247 }
227248
249+ // constants
250+ ffe := params .BeaconConfig ().FarFutureEpoch
251+ curEpoch := slots .ToEpoch (st .Slot ())
252+
228253 for _ , balanceDeposit := range deposits {
229- if primitives .Gwei (balanceDeposit .Amount ) > availableForProcessing {
230- break
254+ v , err := st .ValidatorAtIndexReadOnly (balanceDeposit .Index )
255+ if err != nil {
256+ return fmt .Errorf ("failed to fetch validator at index: %w" , err )
231257 }
232- if err := helpers .IncreaseBalance (st , balanceDeposit .Index , balanceDeposit .Amount ); err != nil {
233- return err
258+
259+ // If the validator is currently exiting, postpone the deposit until after the withdrawable
260+ // epoch.
261+ if v .ExitEpoch () < ffe {
262+ if curEpoch <= v .WithdrawableEpoch () {
263+ depositsToPostpone = append (depositsToPostpone , balanceDeposit )
264+ } else {
265+ // The deposited balance will never become active. Therefore, we increase the balance but do
266+ // not consume the churn.
267+ if err := helpers .IncreaseBalance (st , balanceDeposit .Index , balanceDeposit .Amount ); err != nil {
268+ return err
269+ }
270+ }
271+ } else {
272+ if primitives .Gwei (processedAmount + balanceDeposit .Amount ) > availableForProcessing {
273+ break
274+ }
275+
276+ if err := helpers .IncreaseBalance (st , balanceDeposit .Index , balanceDeposit .Amount ); err != nil {
277+ return err
278+ }
279+ processedAmount += balanceDeposit .Amount
234280 }
235- availableForProcessing -= primitives . Gwei ( balanceDeposit . Amount )
281+
236282 nextDepositIndex ++
237283 }
238284
239- deposits = deposits [nextDepositIndex :]
285+ // Combined operation:
286+ // - state.pending_balance_deposits = state.pending_balance_deposits[next_deposit_index:]
287+ // - state.pending_balance_deposits += deposits_to_postpone
288+ // However, the number of remaining deposits must be maintained to properly update the deposit
289+ // balance to consume.
290+ numRemainingDeposits := len (deposits [nextDepositIndex :])
291+ deposits = append (deposits [nextDepositIndex :], depositsToPostpone ... )
240292 if err := st .SetPendingBalanceDeposits (deposits ); err != nil {
241293 return err
242294 }
243295
244- if len ( deposits ) == 0 {
296+ if numRemainingDeposits == 0 {
245297 return st .SetDepositBalanceToConsume (0 )
246298 } else {
247- return st .SetDepositBalanceToConsume (availableForProcessing )
299+ return st .SetDepositBalanceToConsume (availableForProcessing - primitives . Gwei ( processedAmount ) )
248300 }
249301}
250302
0 commit comments