Skip to content

Commit 5c8acea

Browse files
committed
Update get_expected_withdrawals to return processed_validators_sweep_count.
1 parent b403504 commit 5c8acea

File tree

6 files changed

+76
-50
lines changed

6 files changed

+76
-50
lines changed

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4794,7 +4794,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
47944794
let proposal_epoch = proposal_slot.epoch(T::EthSpec::slots_per_epoch());
47954795
if head_state.current_epoch() == proposal_epoch {
47964796
return get_expected_withdrawals(&unadvanced_state, &self.spec)
4797-
.map(|(withdrawals, _, _)| withdrawals)
4797+
.map(|(withdrawals, _, _, _)| withdrawals)
47984798
.map_err(Error::PrepareProposerFailed);
47994799
}
48004800

@@ -4812,7 +4812,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
48124812
&self.spec,
48134813
)?;
48144814
get_expected_withdrawals(&advanced_state, &self.spec)
4815-
.map(|(withdrawals, _, _)| withdrawals)
4815+
.map(|(withdrawals, _, _, _)| withdrawals)
48164816
.map_err(Error::PrepareProposerFailed)
48174817
}
48184818

beacon_node/http_api/src/builder_states.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn get_next_withdrawals<T: BeaconChainTypes>(
3232
}
3333

3434
match get_expected_withdrawals(&state, &chain.spec) {
35-
Ok((withdrawals, _, _)) => Ok(withdrawals),
35+
Ok((withdrawals, _, _, _)) => Ok(withdrawals),
3636
Err(e) => Err(warp_utils::reject::custom_server_error(format!(
3737
"failed to get expected withdrawal: {:?}",
3838
e

consensus/state_processing/src/per_block_processing.rs

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -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

consensus/state_processing/src/per_block_processing/process_withdrawals.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ pub mod capella {
8282
) -> Result<(), BlockProcessingError> {
8383
// check if capella enabled because this function will run on the merge block where the fork is technically still Bellatrix
8484
if state.fork_name_unchecked().capella_enabled() {
85-
let (expected_withdrawals, _, partial_withdrawals_count) =
85+
let (expected_withdrawals, _, partial_withdrawals_count, _) =
8686
get_expected_withdrawals(state, spec)?;
8787

8888
let expected_root = expected_withdrawals.tree_hash_root();
@@ -127,7 +127,7 @@ pub mod gloas {
127127
return Ok(());
128128
}
129129

130-
let (expected_withdrawals, builder_withdrawals_count, partial_withdrawals_count) =
130+
let (expected_withdrawals, builder_withdrawals_count, partial_withdrawals_count, _) =
131131
get_expected_withdrawals(state, spec)?;
132132

133133
for withdrawal in expected_withdrawals.iter() {

testing/ef_tests/src/cases/operations.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ use types::{
2828
Attestation, AttesterSlashing, BeaconBlock, BeaconBlockBody, BeaconBlockBodyBellatrix,
2929
BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu,
3030
BeaconState, BlindedPayload, ConsolidationRequest, Deposit, DepositRequest, ExecutionPayload,
31-
ForkVersionDecode, FullPayload, PayloadAttestation, ProposerSlashing, SignedBlsToExecutionChange,
32-
SignedVoluntaryExit, SyncAggregate, WithdrawalRequest,
31+
ForkVersionDecode, FullPayload, PayloadAttestation, ProposerSlashing,
32+
SignedBlsToExecutionChange, SignedVoluntaryExit, SyncAggregate, WithdrawalRequest,
3333
};
3434

3535
#[derive(Debug, Clone, Default, Deserialize)]

testing/ef_tests/tests/tests.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,10 @@ mod ssz_static {
378378
.run();
379379
SszStaticHandler::<BeaconBlockBodyFulu<MinimalEthSpec>, MinimalEthSpec>::fulu_only().run();
380380
SszStaticHandler::<BeaconBlockBodyFulu<MainnetEthSpec>, MainnetEthSpec>::fulu_only().run();
381-
SszStaticHandler::<BeaconBlockBodyGloas<MinimalEthSpec>, MinimalEthSpec>::gloas_only().run();
382-
SszStaticHandler::<BeaconBlockBodyGloas<MainnetEthSpec>, MainnetEthSpec>::gloas_only().run();
381+
SszStaticHandler::<BeaconBlockBodyGloas<MinimalEthSpec>, MinimalEthSpec>::gloas_only()
382+
.run();
383+
SszStaticHandler::<BeaconBlockBodyGloas<MainnetEthSpec>, MainnetEthSpec>::gloas_only()
384+
.run();
383385
}
384386

385387
// Altair and later

0 commit comments

Comments
 (0)