Skip to content

Commit 8b4c037

Browse files
committed
Add get_builders_sweep_withdrawals and fix Gloas withdrawal tests.
1 parent 5c8acea commit 8b4c037

File tree

5 files changed

+87
-7
lines changed

5 files changed

+87
-7
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: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,70 @@ pub fn get_pending_partial_withdrawals<E: EthSpec>(
659659
Ok(Some(processed_count))
660660
}
661661

662+
/// Get withdrawals from the builders sweep.
663+
///
664+
/// This function iterates through builders starting from `next_withdrawal_builder_index`
665+
/// and adds withdrawals for builders whose withdrawable_epoch has been reached and have balance.
666+
///
667+
/// https://ethereum.github.io/consensus-specs/specs/gloas/beacon-chain/#new-get_builders_sweep_withdrawals
668+
pub fn get_builders_sweep_withdrawals<E: EthSpec>(
669+
state: &BeaconState<E>,
670+
withdrawal_index: &mut u64,
671+
withdrawals: &mut Vec<Withdrawal>,
672+
) -> Result<Option<u64>, BlockProcessingError> {
673+
let Ok(builders) = state.builders() else {
674+
// Pre-Gloas, nothing to do.
675+
return Ok(None);
676+
};
677+
678+
if builders.is_empty() {
679+
return Ok(Some(0));
680+
}
681+
682+
let epoch = state.current_epoch();
683+
let builders_limit = std::cmp::min(builders.len(), E::max_builders_per_withdrawals_sweep());
684+
// Reserve one slot for validator sweep withdrawals
685+
let withdrawals_limit = E::max_withdrawals_per_payload().saturating_sub(1);
686+
687+
block_verify!(
688+
withdrawals.len() <= withdrawals_limit,
689+
BlockProcessingError::WithdrawalsLimitExceeded {
690+
limit: withdrawals_limit,
691+
prior_withdrawals: withdrawals.len()
692+
}
693+
);
694+
695+
let mut processed_count: u64 = 0;
696+
let mut builder_index = state.next_withdrawal_builder_index()?;
697+
698+
for _ in 0..builders_limit {
699+
if withdrawals.len() >= withdrawals_limit {
700+
break;
701+
}
702+
703+
let builder = builders
704+
.get(builder_index as usize)
705+
.ok_or(BeaconStateError::UnknownBuilder(builder_index))?;
706+
707+
if builder.withdrawable_epoch <= epoch && builder.balance > 0 {
708+
withdrawals.push(Withdrawal {
709+
index: *withdrawal_index,
710+
validator_index: convert_builder_index_to_validator_index(builder_index),
711+
address: builder.execution_address,
712+
amount: builder.balance,
713+
});
714+
withdrawal_index.safe_add_assign(1)?;
715+
}
716+
717+
builder_index = builder_index
718+
.safe_add(1)?
719+
.safe_rem(builders.len() as u64)?;
720+
processed_count.safe_add_assign(1)?;
721+
}
722+
723+
Ok(Some(processed_count))
724+
}
725+
662726
/// Get withdrawals from the validator sweep.
663727
///
664728
/// This function iterates through validators starting from `next_withdrawal_validator_index`
@@ -737,7 +801,7 @@ pub fn get_validators_sweep_withdrawals<E: EthSpec>(
737801
pub fn get_expected_withdrawals<E: EthSpec>(
738802
state: &BeaconState<E>,
739803
spec: &ChainSpec,
740-
) -> Result<(Withdrawals<E>, Option<usize>, Option<usize>, u64), BlockProcessingError> {
804+
) -> Result<(Withdrawals<E>, Option<usize>, Option<usize>, Option<u64>, u64), BlockProcessingError> {
741805
let mut withdrawal_index = state.next_withdrawal_index()?;
742806
let mut withdrawals = Vec::<Withdrawal>::with_capacity(E::max_withdrawals_per_payload());
743807

@@ -751,6 +815,11 @@ pub fn get_expected_withdrawals<E: EthSpec>(
751815
let processed_partial_withdrawals_count =
752816
get_pending_partial_withdrawals(state, &mut withdrawal_index, &mut withdrawals, spec)?;
753817

818+
// [New in Gloas:EIP7732]
819+
// Get builders sweep withdrawals
820+
let processed_builders_sweep_count =
821+
get_builders_sweep_withdrawals(state, &mut withdrawal_index, &mut withdrawals)?;
822+
754823
// Get validators sweep withdrawals
755824
let processed_validators_sweep_count =
756825
get_validators_sweep_withdrawals(state, &mut withdrawal_index, &mut withdrawals, spec)?;
@@ -761,6 +830,7 @@ pub fn get_expected_withdrawals<E: EthSpec>(
761830
.map_err(BlockProcessingError::SszTypesError)?,
762831
processed_builder_withdrawals_count,
763832
processed_partial_withdrawals_count,
833+
processed_builders_sweep_count,
764834
processed_validators_sweep_count,
765835
))
766836
}

consensus/state_processing/src/per_block_processing/process_withdrawals.rs

Lines changed: 12 additions & 3 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,8 +127,14 @@ pub mod gloas {
127127
return Ok(());
128128
}
129129

130-
let (expected_withdrawals, builder_withdrawals_count, partial_withdrawals_count, _) =
131-
get_expected_withdrawals(state, spec)?;
130+
// TODO(EIP-7732): Use processed_builders_sweep_count to call update_next_withdrawal_builder_index
131+
let (
132+
expected_withdrawals,
133+
builder_withdrawals_count,
134+
partial_withdrawals_count,
135+
_processed_builders_sweep_count,
136+
_,
137+
) = get_expected_withdrawals(state, spec)?;
132138

133139
for withdrawal in expected_withdrawals.iter() {
134140
decrease_balance(
@@ -158,6 +164,9 @@ pub mod gloas {
158164
*state.builder_pending_withdrawals_mut()? = List::new(updated_builder_withdrawals)?;
159165
}
160166

167+
// [New in Gloas:EIP7732] update_payload_expected_withdrawals
168+
*state.payload_expected_withdrawals_mut()? = List::new(expected_withdrawals.to_vec())?;
169+
161170
process_withdrawals_common(state, expected_withdrawals, partial_withdrawals_count, spec)?;
162171

163172
Ok(())

consensus/types/src/state/beacon_state.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub enum BeaconStateError {
6868
EpochOutOfBounds,
6969
SlotOutOfBounds,
7070
UnknownValidator(usize),
71+
UnknownBuilder(u64),
7172
UnableToDetermineProducer,
7273
InvalidBitfield,
7374
EmptyCommittee,

0 commit comments

Comments
 (0)