Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct SinglePassConfig {
pub pending_consolidations: bool,
pub effective_balance_updates: bool,
pub proposer_lookahead: bool,
pub builder_pending_payments: bool,
}

impl Default for SinglePassConfig {
Expand All @@ -51,6 +52,7 @@ impl SinglePassConfig {
pending_consolidations: true,
effective_balance_updates: true,
proposer_lookahead: true,
builder_pending_payments: true,
}
}

Expand All @@ -64,6 +66,7 @@ impl SinglePassConfig {
pending_consolidations: false,
effective_balance_updates: false,
proposer_lookahead: false,
builder_pending_payments: false,
}
}
}
Expand Down Expand Up @@ -469,10 +472,14 @@ pub fn process_epoch_single_pass<E: EthSpec>(
process_proposer_lookahead(state, spec)?;
}

if conf.builder_pending_payments && fork_name.gloas_enabled() {
process_builder_pending_payments(state, spec)?;
}

Ok(summary)
}

// TOOO(EIP-7917): use balances cache
// TODO(EIP-7917): use balances cache
pub fn process_proposer_lookahead<E: EthSpec>(
state: &mut BeaconState<E>,
spec: &ChainSpec,
Expand Down Expand Up @@ -502,6 +509,69 @@ pub fn process_proposer_lookahead<E: EthSpec>(
Ok(())
}

/// Calculate the quorum threshold for builder payments based on total active balance.
pub fn get_builder_payment_quorum_threshold<E: EthSpec>(
state: &BeaconState<E>,
spec: &ChainSpec,
) -> Result<u64, Error> {
let total_active_balance = state.get_total_active_balance()?;

let quorum = total_active_balance
.safe_div(E::slots_per_epoch())?
.safe_mul(spec.builder_payment_threshold_numerator)?;

quorum
.safe_div(spec.builder_payment_threshold_denominator)
.map_err(Error::from)
}

/// Process builder pending payments, moving qualifying payments to withdrawals.
/// TODO(EIP-7732): Add EF consensus-spec tests for `process_builder_pending_payments`
/// Currently blocked by EF consensus-spec-tests for Gloas not yet integrated.
pub fn process_builder_pending_payments<E: EthSpec>(
state: &mut BeaconState<E>,
spec: &ChainSpec,
) -> Result<(), Error> {
let quorum = get_builder_payment_quorum_threshold(state, spec)?;

// Collect qualifying payments
let qualifying_payments = state
.builder_pending_payments()?
.iter()
.take(E::slots_per_epoch() as usize)
.filter(|payment| payment.weight > quorum)
.cloned()
.collect::<Vec<_>>();

// Update `builder_pending_withdrawals` with qualifying `builder_pending_payments`
qualifying_payments
.into_iter()
.try_for_each(|payment| -> Result<(), Error> {
let exit_queue_epoch =
state.compute_exit_epoch_and_update_churn(payment.withdrawal.amount, spec)?;
let withdrawable_epoch =
exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?;

let mut withdrawal = payment.withdrawal.clone();
withdrawal.withdrawable_epoch = withdrawable_epoch;
state.builder_pending_withdrawals_mut()?.push(withdrawal)?;
Ok(())
})?;

// Move remaining `builder_pending_payments` to start of list and set the rest to default
let new_payments = state
.builder_pending_payments()?
.iter()
.skip(E::slots_per_epoch() as usize)
.cloned()
.chain((0..E::slots_per_epoch() as usize).map(|_| types::BuilderPendingPayment::default()))
.collect::<Vec<_>>();

*state.builder_pending_payments_mut()? = Vector::new(new_payments)?;

Ok(())
}

fn process_single_inactivity_update(
inactivity_score: &mut Cow<u64>,
validator_info: &ValidatorInfo,
Expand Down
19 changes: 19 additions & 0 deletions consensus/state_processing/src/per_slot_processing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub enum Error {
EpochProcessingError(EpochProcessingError),
ArithError(ArithError),
InconsistentStateFork(InconsistentFork),
BitfieldError(ssz::BitfieldError),
}

impl From<ArithError> for Error {
Expand All @@ -21,6 +22,12 @@ impl From<ArithError> for Error {
}
}

impl From<ssz::BitfieldError> for Error {
fn from(e: ssz::BitfieldError) -> Self {
Self::BitfieldError(e)
}
}

/// Advances a state forward by one slot, performing per-epoch processing if required.
///
/// If the root of the supplied `state` is known, then it can be passed as `state_root`. If
Expand Down Expand Up @@ -49,6 +56,18 @@ pub fn per_slot_processing<E: EthSpec>(

state.slot_mut().safe_add_assign(1)?;

// Unset the next payload availability
if state.fork_name_unchecked().gloas_enabled() {
let next_slot_index = state
.slot()
.as_usize()
.safe_add(1)?
.safe_rem(E::slots_per_historical_root())?;
state
.execution_payload_availability_mut()?
.set(next_slot_index, false)?;
}

// Process fork upgrades here. Note that multiple upgrades can potentially run
// in sequence if they are scheduled in the same Epoch (common in testnets)
if state.slot().safe_rem(E::slots_per_epoch())? == 0 {
Expand Down