Skip to content

Commit 4b56d03

Browse files
authored
Gloas process epoch (#8287)
* add process_builder_pending_payments to epoch processing * per_slot_processing modified * add process_builder_pending_payments to single pass process epoch * update process_builder_pending_payments per latest spec
1 parent 8480f93 commit 4b56d03

File tree

2 files changed

+93
-3
lines changed

2 files changed

+93
-3
lines changed

consensus/state_processing/src/per_epoch_processing/single_pass.rs

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ use std::cmp::{max, min};
1313
use std::collections::{BTreeSet, HashMap};
1414
use tracing::instrument;
1515
use types::{
16-
ActivationQueue, BeaconState, BeaconStateError, ChainSpec, Checkpoint, DepositData, Epoch,
17-
EthSpec, ExitCache, ForkName, List, ParticipationFlags, PendingDeposit,
16+
ActivationQueue, BeaconState, BeaconStateError, BuilderPendingPayment, ChainSpec, Checkpoint,
17+
DepositData, Epoch, EthSpec, ExitCache, ForkName, List, ParticipationFlags, PendingDeposit,
1818
ProgressiveBalancesCache, RelativeEpoch, Unsigned, Validator, Vector,
1919
consts::altair::{
2020
NUM_FLAG_INDICES, PARTICIPATION_FLAG_WEIGHTS, TIMELY_HEAD_FLAG_INDEX,
@@ -32,6 +32,7 @@ pub struct SinglePassConfig {
3232
pub pending_consolidations: bool,
3333
pub effective_balance_updates: bool,
3434
pub proposer_lookahead: bool,
35+
pub builder_pending_payments: bool,
3536
}
3637

3738
impl Default for SinglePassConfig {
@@ -51,6 +52,7 @@ impl SinglePassConfig {
5152
pending_consolidations: true,
5253
effective_balance_updates: true,
5354
proposer_lookahead: true,
55+
builder_pending_payments: true,
5456
}
5557
}
5658

@@ -64,6 +66,7 @@ impl SinglePassConfig {
6466
pending_consolidations: false,
6567
effective_balance_updates: false,
6668
proposer_lookahead: false,
69+
builder_pending_payments: false,
6770
}
6871
}
6972
}
@@ -454,6 +457,12 @@ pub fn process_epoch_single_pass<E: EthSpec>(
454457
)?;
455458
}
456459

460+
// Process builder pending payments outside the single-pass loop, as they depend on balances for multiple
461+
// validators and cannot be computed accurately inside the loop.
462+
if fork_name.gloas_enabled() && conf.builder_pending_payments {
463+
process_builder_pending_payments(state, state_ctxt, spec)?;
464+
}
465+
457466
// Finally, finish updating effective balance caches. We need this to happen *after* processing
458467
// of pending consolidations, which recomputes some effective balances.
459468
if conf.effective_balance_updates {
@@ -472,7 +481,7 @@ pub fn process_epoch_single_pass<E: EthSpec>(
472481
Ok(summary)
473482
}
474483

475-
// TOOO(EIP-7917): use balances cache
484+
// TODO(EIP-7917): use balances cache
476485
pub fn process_proposer_lookahead<E: EthSpec>(
477486
state: &mut BeaconState<E>,
478487
spec: &ChainSpec,
@@ -502,6 +511,68 @@ pub fn process_proposer_lookahead<E: EthSpec>(
502511
Ok(())
503512
}
504513

514+
/// Calculate the quorum threshold for builder payments based on total active balance.
515+
fn get_builder_payment_quorum_threshold<E: EthSpec>(
516+
state_ctxt: &StateContext,
517+
spec: &ChainSpec,
518+
) -> Result<u64, Error> {
519+
let per_slot_balance = state_ctxt
520+
.total_active_balance
521+
.safe_div(E::slots_per_epoch())?;
522+
let quorum = per_slot_balance.safe_mul(spec.builder_payment_threshold_numerator)?;
523+
quorum
524+
.safe_div(spec.builder_payment_threshold_denominator)
525+
.map_err(Error::from)
526+
}
527+
528+
/// Process builder pending payments, moving qualifying payments to withdrawals.
529+
/// TODO(EIP-7732): Add EF consensus-spec tests for `process_builder_pending_payments`
530+
/// Currently blocked by EF consensus-spec-tests for Gloas not yet integrated.
531+
fn process_builder_pending_payments<E: EthSpec>(
532+
state: &mut BeaconState<E>,
533+
state_ctxt: &StateContext,
534+
spec: &ChainSpec,
535+
) -> Result<(), Error> {
536+
let quorum = get_builder_payment_quorum_threshold::<E>(state_ctxt, spec)?;
537+
538+
// Collect qualifying payments
539+
let qualifying_payments = state
540+
.builder_pending_payments()?
541+
.iter()
542+
.take(E::slots_per_epoch() as usize)
543+
.filter(|payment| payment.weight > quorum)
544+
.cloned()
545+
.collect::<Vec<_>>();
546+
547+
// Update `builder_pending_withdrawals` with qualifying `builder_pending_payments`
548+
qualifying_payments
549+
.into_iter()
550+
.try_for_each(|payment| -> Result<(), Error> {
551+
let exit_queue_epoch =
552+
state.compute_exit_epoch_and_update_churn(payment.withdrawal.amount, spec)?;
553+
let withdrawable_epoch =
554+
exit_queue_epoch.safe_add(spec.min_validator_withdrawability_delay)?;
555+
556+
let mut withdrawal = payment.withdrawal.clone();
557+
withdrawal.withdrawable_epoch = withdrawable_epoch;
558+
state.builder_pending_withdrawals_mut()?.push(withdrawal)?;
559+
Ok(())
560+
})?;
561+
562+
// Move remaining `builder_pending_payments` to start of list and set the rest to default
563+
let new_payments = state
564+
.builder_pending_payments()?
565+
.iter()
566+
.skip(E::slots_per_epoch() as usize)
567+
.cloned()
568+
.chain((0..E::slots_per_epoch() as usize).map(|_| BuilderPendingPayment::default()))
569+
.collect::<Vec<_>>();
570+
571+
*state.builder_pending_payments_mut()? = Vector::new(new_payments)?;
572+
573+
Ok(())
574+
}
575+
505576
fn process_single_inactivity_update(
506577
inactivity_score: &mut Cow<u64>,
507578
validator_info: &ValidatorInfo,

consensus/state_processing/src/per_slot_processing.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub enum Error {
1313
EpochProcessingError(EpochProcessingError),
1414
ArithError(ArithError),
1515
InconsistentStateFork(InconsistentFork),
16+
BitfieldError(ssz::BitfieldError),
1617
}
1718

1819
impl From<ArithError> for Error {
@@ -21,6 +22,12 @@ impl From<ArithError> for Error {
2122
}
2223
}
2324

25+
impl From<ssz::BitfieldError> for Error {
26+
fn from(e: ssz::BitfieldError) -> Self {
27+
Self::BitfieldError(e)
28+
}
29+
}
30+
2431
/// Advances a state forward by one slot, performing per-epoch processing if required.
2532
///
2633
/// If the root of the supplied `state` is known, then it can be passed as `state_root`. If
@@ -49,6 +56,18 @@ pub fn per_slot_processing<E: EthSpec>(
4956

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

59+
// Unset the next payload availability
60+
if state.fork_name_unchecked().gloas_enabled() {
61+
let next_slot_index = state
62+
.slot()
63+
.as_usize()
64+
.safe_add(1)?
65+
.safe_rem(E::slots_per_historical_root())?;
66+
state
67+
.execution_payload_availability_mut()?
68+
.set(next_slot_index, false)?;
69+
}
70+
5271
// Process fork upgrades here. Note that multiple upgrades can potentially run
5372
// in sequence if they are scheduled in the same Epoch (common in testnets)
5473
if state.slot().safe_rem(E::slots_per_epoch())? == 0 {

0 commit comments

Comments
 (0)