@@ -32,6 +32,7 @@ pub struct SinglePassConfig {
3232 pub pending_consolidations : bool ,
3333 pub effective_balance_updates : bool ,
3434 pub proposer_lookahead : bool ,
35+ pub builder_pending_payments : bool ,
3536}
3637
3738impl Default for SinglePassConfig {
@@ -51,6 +52,7 @@ impl SinglePassConfig {
5152 pending_consolidations : true ,
5253 effective_balance_updates : true ,
5354 proposer_lookahead : true ,
55+ builder_pending_payments : true ,
5456 }
5557 }
5658
@@ -64,6 +66,7 @@ impl SinglePassConfig {
6466 pending_consolidations : false ,
6567 effective_balance_updates : false ,
6668 proposer_lookahead : false ,
69+ builder_pending_payments : false ,
6770 }
6871 }
6972}
@@ -469,10 +472,14 @@ pub fn process_epoch_single_pass<E: EthSpec>(
469472 process_proposer_lookahead ( state, spec) ?;
470473 }
471474
475+ if conf. builder_pending_payments && fork_name. gloas_enabled ( ) {
476+ process_builder_pending_payments ( state, spec) ?;
477+ }
478+
472479 Ok ( summary)
473480}
474481
475- // TOOO (EIP-7917): use balances cache
482+ // TODO (EIP-7917): use balances cache
476483pub fn process_proposer_lookahead < E : EthSpec > (
477484 state : & mut BeaconState < E > ,
478485 spec : & ChainSpec ,
@@ -502,6 +509,69 @@ pub fn process_proposer_lookahead<E: EthSpec>(
502509 Ok ( ( ) )
503510}
504511
512+ /// Calculate the quorum threshold for builder payments based on total active balance.
513+ pub fn get_builder_payment_quorum_threshold < E : EthSpec > (
514+ state : & BeaconState < E > ,
515+ spec : & ChainSpec ,
516+ ) -> Result < u64 , Error > {
517+ let total_active_balance = state. get_total_active_balance ( ) ?;
518+
519+ let quorum = total_active_balance
520+ . safe_div ( E :: slots_per_epoch ( ) ) ?
521+ . safe_mul ( spec. builder_payment_threshold_numerator ) ?;
522+
523+ quorum
524+ . safe_div ( spec. builder_payment_threshold_denominator )
525+ . map_err ( Error :: from)
526+ }
527+
528+ /// Process builder pending payments, moving qualifying payments to withdrawals.
529+ /// TODO(EIP-7732): Add EF consensus-spec tests for `process_builder_pending_payments`
530+ /// Currently blocked by EF consensus-spec-tests for Gloas not yet integrated.
531+ pub fn process_builder_pending_payments < E : EthSpec > (
532+ state : & mut BeaconState < E > ,
533+ spec : & ChainSpec ,
534+ ) -> Result < ( ) , Error > {
535+ let quorum = get_builder_payment_quorum_threshold ( state, spec) ?;
536+
537+ // Collect qualifying payments
538+ let qualifying_payments = state
539+ . builder_pending_payments ( ) ?
540+ . iter ( )
541+ . take ( E :: slots_per_epoch ( ) as usize )
542+ . filter ( |payment| payment. weight > quorum)
543+ . cloned ( )
544+ . collect :: < Vec < _ > > ( ) ;
545+
546+ // Update `builder_pending_withdrawals` with qualifying `builder_pending_payments`
547+ qualifying_payments
548+ . into_iter ( )
549+ . try_for_each ( |payment| -> Result < ( ) , Error > {
550+ let exit_queue_epoch =
551+ state. compute_exit_epoch_and_update_churn ( payment. withdrawal . amount , spec) ?;
552+ let withdrawable_epoch =
553+ exit_queue_epoch. safe_add ( spec. min_validator_withdrawability_delay ) ?;
554+
555+ let mut withdrawal = payment. withdrawal . clone ( ) ;
556+ withdrawal. withdrawable_epoch = withdrawable_epoch;
557+ state. builder_pending_withdrawals_mut ( ) ?. push ( withdrawal) ?;
558+ Ok ( ( ) )
559+ } ) ?;
560+
561+ // Move remaining `builder_pending_payments` to start of list and set the rest to default
562+ let new_payments = state
563+ . builder_pending_payments ( ) ?
564+ . iter ( )
565+ . skip ( E :: slots_per_epoch ( ) as usize )
566+ . cloned ( )
567+ . chain ( ( 0 ..E :: slots_per_epoch ( ) as usize ) . map ( |_| types:: BuilderPendingPayment :: default ( ) ) )
568+ . collect :: < Vec < _ > > ( ) ;
569+
570+ * state. builder_pending_payments_mut ( ) ? = Vector :: new ( new_payments) ?;
571+
572+ Ok ( ( ) )
573+ }
574+
505575fn process_single_inactivity_update (
506576 inactivity_score : & mut Cow < u64 > ,
507577 validator_info : & ValidatorInfo ,
0 commit comments