@@ -30,6 +30,7 @@ pub mod deneb;
3030pub mod errors;
3131mod is_valid_indexed_attestation;
3232pub mod process_operations;
33+ pub mod process_withdrawals;
3334pub mod signature_sets;
3435pub mod tests;
3536mod verify_attestation;
@@ -39,7 +40,6 @@ mod verify_deposit;
3940mod verify_exit;
4041mod verify_proposer_slashing;
4142
42- use crate :: common:: decrease_balance;
4343use crate :: common:: update_progressive_balances_cache:: {
4444 initialize_progressive_balances_cache, update_progressive_balances_metrics,
4545} ;
@@ -171,13 +171,20 @@ pub fn per_block_processing<E: EthSpec, Payload: AbstractExecPayload<E>>(
171171 // previous block.
172172 if is_execution_enabled ( state, block. body ( ) ) {
173173 let body = block. body ( ) ;
174- // TODO(EIP-7732): build out process_withdrawals variant for gloas
175- process_withdrawals :: < E , Payload > ( state, body. execution_payload ( ) ?, spec) ?;
176- process_execution_payload :: < E , Payload > ( state, body, spec) ?;
177- }
174+ if state. fork_name_unchecked ( ) . gloas_enabled ( ) {
175+ process_withdrawals:: gloas:: process_withdrawals :: < E > ( state, spec) ?;
178176
179- // TODO(EIP-7732): build out process_execution_bid
180- // process_execution_bid(state, block, verify_signatures, spec)?;
177+ // TODO(EIP-7732): build out process_execution_bid
178+ // process_execution_bid(state, block, verify_signatures, spec)?;
179+ } else {
180+ process_withdrawals:: capella:: process_withdrawals :: < E , Payload > (
181+ state,
182+ body. execution_payload ( ) ?,
183+ spec,
184+ ) ?;
185+ process_execution_payload :: < E , Payload > ( state, body, spec) ?;
186+ }
187+ }
181188
182189 process_randao ( state, block, verify_randao, ctxt, spec) ?;
183190 process_eth1_data ( state, block. body ( ) . eth1_data ( ) ) ?;
@@ -515,17 +522,70 @@ pub fn compute_timestamp_at_slot<E: EthSpec>(
515522
516523/// Compute the next batch of withdrawals which should be included in a block.
517524///
518- /// https://github.com/ethereum/consensus-specs/blob/dev/specs/electra/beacon-chain.md#new-get_expected_withdrawals
525+ /// https://ethereum.github.io/consensus-specs/specs/gloas/beacon-chain/#modified-get_expected_withdrawals
526+ #[ allow( clippy:: type_complexity) ]
519527pub fn get_expected_withdrawals < E : EthSpec > (
520528 state : & BeaconState < E > ,
521529 spec : & ChainSpec ,
522- ) -> Result < ( Withdrawals < E > , Option < usize > ) , BlockProcessingError > {
530+ ) -> Result < ( Withdrawals < E > , Option < usize > , Option < usize > ) , BlockProcessingError > {
523531 let epoch = state. current_epoch ( ) ;
524532 let mut withdrawal_index = state. next_withdrawal_index ( ) ?;
525533 let mut validator_index = state. next_withdrawal_validator_index ( ) ?;
526534 let mut withdrawals = Vec :: < Withdrawal > :: with_capacity ( E :: max_withdrawals_per_payload ( ) ) ;
527535 let fork_name = state. fork_name_unchecked ( ) ;
528536
537+ // [New in Gloas:EIP7732]
538+ // Sweep for builder payments
539+ let processed_builder_withdrawals_count =
540+ if let Ok ( builder_pending_withdrawals) = state. builder_pending_withdrawals ( ) {
541+ let mut processed_builder_withdrawals_count = 0 ;
542+ for withdrawal in builder_pending_withdrawals {
543+ if withdrawal. withdrawable_epoch > epoch
544+ || withdrawals. len ( ) . safe_add ( 1 ) ? == E :: max_withdrawals_per_payload ( )
545+ {
546+ break ;
547+ }
548+
549+ if process_withdrawals:: is_builder_payment_withdrawable ( state, withdrawal) ? {
550+ let total_withdrawn = withdrawals
551+ . iter ( )
552+ . filter_map ( |w| {
553+ ( w. validator_index == withdrawal. builder_index ) . then_some ( w. amount )
554+ } )
555+ . safe_sum ( ) ?;
556+ let balance = state
557+ . get_balance ( withdrawal. builder_index as usize ) ?
558+ . safe_sub ( total_withdrawn) ?;
559+ let builder = state. get_validator ( withdrawal. builder_index as usize ) ?;
560+
561+ let withdrawable_balance = if builder. slashed {
562+ std:: cmp:: min ( balance, withdrawal. amount )
563+ } else if balance > spec. min_activation_balance {
564+ std:: cmp:: min (
565+ balance. safe_sub ( spec. min_activation_balance ) ?,
566+ withdrawal. amount ,
567+ )
568+ } else {
569+ 0
570+ } ;
571+
572+ if withdrawable_balance > 0 {
573+ withdrawals. push ( Withdrawal {
574+ index : withdrawal_index,
575+ validator_index : withdrawal. builder_index ,
576+ address : withdrawal. fee_recipient ,
577+ amount : withdrawable_balance,
578+ } ) ;
579+ withdrawal_index. safe_add_assign ( 1 ) ?;
580+ }
581+ }
582+ processed_builder_withdrawals_count. safe_add_assign ( 1 ) ?;
583+ }
584+ Some ( processed_builder_withdrawals_count)
585+ } else {
586+ None
587+ } ;
588+
529589 // [New in Electra:EIP7251]
530590 // Consume pending partial withdrawals
531591 let processed_partial_withdrawals_count =
@@ -626,71 +686,9 @@ pub fn get_expected_withdrawals<E: EthSpec>(
626686 . safe_rem ( state. validators ( ) . len ( ) as u64 ) ?;
627687 }
628688
629- Ok ( ( withdrawals. into ( ) , processed_partial_withdrawals_count) )
630- }
631-
632- /// Apply withdrawals to the state.
633- /// TODO(EIP-7732): abstract this out and create gloas variant
634- pub fn process_withdrawals < E : EthSpec , Payload : AbstractExecPayload < E > > (
635- state : & mut BeaconState < E > ,
636- payload : Payload :: Ref < ' _ > ,
637- spec : & ChainSpec ,
638- ) -> Result < ( ) , BlockProcessingError > {
639- if state. fork_name_unchecked ( ) . capella_enabled ( ) {
640- let ( expected_withdrawals, processed_partial_withdrawals_count) =
641- get_expected_withdrawals ( state, spec) ?;
642- let expected_root = expected_withdrawals. tree_hash_root ( ) ;
643- let withdrawals_root = payload. withdrawals_root ( ) ?;
644-
645- if expected_root != withdrawals_root {
646- return Err ( BlockProcessingError :: WithdrawalsRootMismatch {
647- expected : expected_root,
648- found : withdrawals_root,
649- } ) ;
650- }
651-
652- for withdrawal in expected_withdrawals. iter ( ) {
653- decrease_balance (
654- state,
655- withdrawal. validator_index as usize ,
656- withdrawal. amount ,
657- ) ?;
658- }
659-
660- // Update pending partial withdrawals [New in Electra:EIP7251]
661- if let Some ( processed_partial_withdrawals_count) = processed_partial_withdrawals_count {
662- state
663- . pending_partial_withdrawals_mut ( ) ?
664- . pop_front ( processed_partial_withdrawals_count) ?;
665- }
666-
667- // Update the next withdrawal index if this block contained withdrawals
668- if let Some ( latest_withdrawal) = expected_withdrawals. last ( ) {
669- * state. next_withdrawal_index_mut ( ) ? = latest_withdrawal. index . safe_add ( 1 ) ?;
670-
671- // Update the next validator index to start the next withdrawal sweep
672- if expected_withdrawals. len ( ) == E :: max_withdrawals_per_payload ( ) {
673- // Next sweep starts after the latest withdrawal's validator index
674- let next_validator_index = latest_withdrawal
675- . validator_index
676- . safe_add ( 1 ) ?
677- . safe_rem ( state. validators ( ) . len ( ) as u64 ) ?;
678- * state. next_withdrawal_validator_index_mut ( ) ? = next_validator_index;
679- }
680- }
681-
682- // Advance sweep by the max length of the sweep if there was not a full set of withdrawals
683- if expected_withdrawals. len ( ) != E :: max_withdrawals_per_payload ( ) {
684- let next_validator_index = state
685- . next_withdrawal_validator_index ( ) ?
686- . safe_add ( spec. max_validators_per_withdrawals_sweep ) ?
687- . safe_rem ( state. validators ( ) . len ( ) as u64 ) ?;
688- * state. next_withdrawal_validator_index_mut ( ) ? = next_validator_index;
689- }
690-
691- Ok ( ( ) )
692- } else {
693- // these shouldn't even be encountered but they're here for completeness
694- Ok ( ( ) )
695- }
689+ Ok ( (
690+ withdrawals. into ( ) ,
691+ processed_builder_withdrawals_count,
692+ processed_partial_withdrawals_count,
693+ ) )
696694}
0 commit comments