@@ -659,85 +659,109 @@ pub fn get_pending_partial_withdrawals<E: EthSpec>(
659659 Ok ( Some ( processed_count) )
660660}
661661
662- /// Compute the next batch of withdrawals which should be included in a block .
662+ /// Get withdrawals from the validator sweep .
663663///
664- /// https://ethereum.github.io/consensus-specs/specs/gloas/beacon-chain/#modified-get_expected_withdrawals
665- #[ allow( clippy:: type_complexity) ]
666- pub fn get_expected_withdrawals < E : EthSpec > (
664+ /// This function iterates through validators starting from `next_withdrawal_validator_index`
665+ /// and adds full or partial withdrawals for eligible validators.
666+ ///
667+ /// https://ethereum.github.io/consensus-specs/specs/capella/beacon-chain/#new-get_validators_sweep_withdrawals
668+ pub fn get_validators_sweep_withdrawals < E : EthSpec > (
667669 state : & BeaconState < E > ,
670+ withdrawal_index : & mut u64 ,
671+ withdrawals : & mut Vec < Withdrawal > ,
668672 spec : & ChainSpec ,
669- ) -> Result < ( Withdrawals < E > , Option < usize > , Option < usize > ) , BlockProcessingError > {
673+ ) -> Result < u64 , BlockProcessingError > {
670674 let epoch = state. current_epoch ( ) ;
671- let mut withdrawal_index = state. next_withdrawal_index ( ) ?;
672- let mut withdrawals = Vec :: < Withdrawal > :: with_capacity ( E :: max_withdrawals_per_payload ( ) ) ;
673675 let fork_name = state. fork_name_unchecked ( ) ;
674-
675676 let mut validator_index = state. next_withdrawal_validator_index ( ) ?;
676-
677- // [New in Gloas:EIP7732]
678- // Get builder withdrawals
679- let processed_builder_withdrawals_count =
680- get_builder_withdrawals ( state, & mut withdrawal_index, & mut withdrawals) ?;
681-
682- // [New in Electra:EIP7251]
683- // Get partial withdrawals.
684- let processed_partial_withdrawals_count =
685- get_pending_partial_withdrawals ( state, & mut withdrawal_index, & mut withdrawals, spec) ?;
686-
687- let bound = std:: cmp:: min (
677+ let validators_limit = std:: cmp:: min (
688678 state. validators ( ) . len ( ) as u64 ,
689679 spec. max_validators_per_withdrawals_sweep ,
690680 ) ;
691- for _ in 0 ..bound {
681+ let withdrawals_limit = E :: max_withdrawals_per_payload ( ) ;
682+
683+ // There must be at least one space reserved for validator sweep withdrawals
684+ block_verify ! (
685+ withdrawals. len( ) < withdrawals_limit,
686+ BlockProcessingError :: WithdrawalsLimitExceeded {
687+ limit: withdrawals_limit,
688+ prior_withdrawals: withdrawals. len( )
689+ }
690+ ) ;
691+
692+ let mut processed_count: u64 = 0 ;
693+
694+ for _ in 0 ..validators_limit {
695+ if withdrawals. len ( ) >= withdrawals_limit {
696+ break ;
697+ }
698+
692699 let validator = state. get_validator ( validator_index as usize ) ?;
693- let partially_withdrawn_balance = withdrawals
694- . iter ( )
695- . filter_map ( |withdrawal| {
696- ( withdrawal. validator_index == validator_index) . then_some ( withdrawal. amount )
697- } )
698- . safe_sum ( ) ?;
699- let balance = state
700- . balances ( )
701- . get ( validator_index as usize )
702- . ok_or ( BeaconStateError :: BalancesOutOfBounds (
703- validator_index as usize ,
704- ) ) ?
705- . safe_sub ( partially_withdrawn_balance) ?;
700+ let balance = get_balance_after_withdrawals ( state, validator_index, withdrawals) ?;
701+
706702 if validator. is_fully_withdrawable_validator ( balance, epoch, spec, fork_name) {
707703 withdrawals. push ( Withdrawal {
708- index : withdrawal_index,
704+ index : * withdrawal_index,
709705 validator_index,
710706 address : validator
711- . get_execution_withdrawal_address ( spec, state . fork_name_unchecked ( ) )
707+ . get_execution_withdrawal_address ( spec, fork_name )
712708 . ok_or ( BlockProcessingError :: WithdrawalCredentialsInvalid ) ?,
713709 amount : balance,
714710 } ) ;
715711 withdrawal_index. safe_add_assign ( 1 ) ?;
716712 } else if validator. is_partially_withdrawable_validator ( balance, spec, fork_name) {
717713 withdrawals. push ( Withdrawal {
718- index : withdrawal_index,
714+ index : * withdrawal_index,
719715 validator_index,
720716 address : validator
721- . get_execution_withdrawal_address ( spec, state . fork_name_unchecked ( ) )
717+ . get_execution_withdrawal_address ( spec, fork_name )
722718 . ok_or ( BlockProcessingError :: WithdrawalCredentialsInvalid ) ?,
723719 amount : balance. safe_sub ( validator. get_max_effective_balance ( spec, fork_name) ) ?,
724720 } ) ;
725721 withdrawal_index. safe_add_assign ( 1 ) ?;
726722 }
727- if withdrawals. len ( ) == E :: max_withdrawals_per_payload ( ) {
728- break ;
729- }
723+
730724 validator_index = validator_index
731725 . safe_add ( 1 ) ?
732726 . safe_rem ( state. validators ( ) . len ( ) as u64 ) ?;
727+ processed_count. safe_add_assign ( 1 ) ?;
733728 }
734729
730+ Ok ( processed_count)
731+ }
732+
733+ /// Compute the next batch of withdrawals which should be included in a block.
734+ ///
735+ /// https://ethereum.github.io/consensus-specs/specs/gloas/beacon-chain/#modified-get_expected_withdrawals
736+ #[ allow( clippy:: type_complexity) ]
737+ pub fn get_expected_withdrawals < E : EthSpec > (
738+ state : & BeaconState < E > ,
739+ spec : & ChainSpec ,
740+ ) -> Result < ( Withdrawals < E > , Option < usize > , Option < usize > , u64 ) , BlockProcessingError > {
741+ let mut withdrawal_index = state. next_withdrawal_index ( ) ?;
742+ let mut withdrawals = Vec :: < Withdrawal > :: with_capacity ( E :: max_withdrawals_per_payload ( ) ) ;
743+
744+ // [New in Gloas:EIP7732]
745+ // Get builder withdrawals
746+ let processed_builder_withdrawals_count =
747+ get_builder_withdrawals ( state, & mut withdrawal_index, & mut withdrawals) ?;
748+
749+ // [New in Electra:EIP7251]
750+ // Get partial withdrawals.
751+ let processed_partial_withdrawals_count =
752+ get_pending_partial_withdrawals ( state, & mut withdrawal_index, & mut withdrawals, spec) ?;
753+
754+ // Get validators sweep withdrawals
755+ let processed_validators_sweep_count =
756+ get_validators_sweep_withdrawals ( state, & mut withdrawal_index, & mut withdrawals, spec) ?;
757+
735758 Ok ( (
736759 withdrawals
737760 . try_into ( )
738761 . map_err ( BlockProcessingError :: SszTypesError ) ?,
739762 processed_builder_withdrawals_count,
740763 processed_partial_withdrawals_count,
764+ processed_validators_sweep_count,
741765 ) )
742766}
743767
0 commit comments