Skip to content
Merged
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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion consensus-spec-tests
1 change: 1 addition & 0 deletions fork_choice_control/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ tap = { workspace = true }
thiserror = { workspace = true }
transition_functions = { workspace = true }
tynm = { workspace = true }
typenum = { workspace = true }
types = { workspace = true }

[dev-dependencies]
Expand Down
3 changes: 2 additions & 1 deletion fork_choice_control/src/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use itertools::Itertools as _;
use serde::Serialize;
use std_ext::ArcExt;
use thiserror::Error;
use typenum::Unsigned as _;
use types::{
combined::{BeaconState, SignedAggregateAndProof, SignedBeaconBlock},
deneb::containers::{BlobIdentifier, BlobSidecar},
Expand Down Expand Up @@ -579,7 +580,7 @@ where
let store_epoch = store.current_epoch();

ensure!(
requested_epoch <= store_epoch + P::MIN_SEED_LOOKAHEAD,
requested_epoch <= store_epoch + P::MinSeedLookahead::U64,
Error::EpochTooFarInTheFuture {
requested_epoch,
store_epoch,
Expand Down
2 changes: 1 addition & 1 deletion grandine-snapshot-tests
Submodule grandine-snapshot-tests updated 14 files
+22 −4 minimal/rapid-upgrade/quick-start/all-keys/built-in-validator/433-take-messages-slot-48-propose.response
+1 −1 minimal/rapid-upgrade/quick-start/all-phases-all-keys/nonstandard-read-only/head.response
+3 −3 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/blocks-head-attestations-v2.response
+3 −3 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/blocks-head-attestations.response
+1 −1 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/blocks-head-root.response
+7 −7 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/blocks-head.response
+18 −18 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/debug-fork-choice.response
+5 −5 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/headers-head.response
+5 −5 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/headers.response
+1 −1 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/heads.response
+1 −1 .../rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/states-head-finality-checkpoints.response
+1 −1 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/states-head-root.response
+39 −21 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/states-head.response
+1 −1 minimal/rapid-upgrade/quick-start/all-phases-all-keys/standard-read-only/states-justified-root.response
28 changes: 26 additions & 2 deletions helper_functions/src/accessors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ fn get_seed_by_epoch<P: Preset>(
) -> H256 {
let mix = get_randao_mix(
state,
epoch + P::EpochsPerHistoricalVector::U64 - P::MIN_SEED_LOOKAHEAD - 1,
epoch + P::EpochsPerHistoricalVector::U64 - P::MinSeedLookahead::U64 - 1,
);

hashing::hash_32_64_256(domain_type.to_fixed_bytes(), epoch, mix)
Expand Down Expand Up @@ -458,7 +458,14 @@ pub fn get_beacon_proposer_index<P: Preset>(
config: &Config,
state: &impl BeaconState<P>,
) -> Result<ValidatorIndex> {
get_or_try_init_beacon_proposer_index(config, state, true)
if let Some(proposer_lookahead) = state.proposer_lookahead() {
proposer_lookahead
.get(state.slot() % P::SlotsPerEpoch::U64)
.copied()
.map_err(Into::into)
} else {
get_or_try_init_beacon_proposer_index(config, state, true)
}
}

pub fn get_or_try_init_beacon_proposer_index<P: Preset>(
Expand Down Expand Up @@ -906,6 +913,23 @@ pub fn get_pending_balance_to_withdraw<P: Preset>(
.sum()
}

pub fn get_beacon_proposer_indices<P: Preset>(
config: &Config,
state: &impl BeaconState<P>,
epoch: Epoch,
) -> Result<Vec<ValidatorIndex>> {
let indices = get_active_validator_indices_by_epoch(state, epoch);
let seed = get_seed_by_epoch(state, epoch, DOMAIN_BEACON_PROPOSER);

misc::compute_proposer_indices(
config,
state,
epoch,
seed,
&PackedIndices::U64(indices.into_iter().collect()),
)
}

#[cfg(test)]
mod tests {
use types::{
Expand Down
32 changes: 28 additions & 4 deletions helper_functions/src/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ use bls::{
SignatureBytes,
};
use itertools::Itertools as _;
use ssz::PersistentList;
use ssz::{PersistentList, PersistentVector};
use std_ext::ArcExt as _;
use try_from_iterator::TryFromIterator as _;
use typenum::Unsigned as _;
use types::{
altair::beacon_state::BeaconState as AltairBeaconState,
bellatrix::{
Expand Down Expand Up @@ -37,6 +39,7 @@ use types::{
},
preset::Preset,
traits::{BeaconState as _, PostElectraBeaconState as _},
ProposerLookahead,
};

use crate::{accessors, misc, mutators, phase0, predicates};
Expand Down Expand Up @@ -671,9 +674,12 @@ pub fn upgrade_to_electra<P: Preset>(
pub fn upgrade_to_fulu<P: Preset>(
config: &Config,
pre: ElectraBeaconState<P>,
) -> FuluBeaconState<P> {
) -> Result<FuluBeaconState<P>> {
let epoch = accessors::get_current_epoch(&pre);

// > [New in Fulu:EIP7917]
let proposer_lookahead = initialize_proposer_lookahead(config, &pre)?;

let ElectraBeaconState {
genesis_time,
genesis_validators_root,
Expand Down Expand Up @@ -721,7 +727,7 @@ pub fn upgrade_to_fulu<P: Preset>(
epoch,
};

FuluBeaconState {
Ok(FuluBeaconState {
// > Versioning
genesis_time,
genesis_validators_root,
Expand Down Expand Up @@ -772,9 +778,26 @@ pub fn upgrade_to_fulu<P: Preset>(
pending_deposits,
pending_partial_withdrawals,
pending_consolidations,
proposer_lookahead,
// Cache
cache,
})
}

fn initialize_proposer_lookahead<P: Preset>(
config: &Config,
state: &ElectraBeaconState<P>,
) -> Result<ProposerLookahead<P>> {
let current_epoch = accessors::get_current_epoch(state);
let mut lookahead = vec![];

for i in 0..=P::MinSeedLookahead::U64 {
let indices =
accessors::get_beacon_proposer_indices(config, state, current_epoch.saturating_add(i))?;
lookahead.extend(indices);
}

PersistentVector::try_from_iter(lookahead).map_err(Into::into)
}

#[cfg(test)]
Expand Down Expand Up @@ -896,7 +919,8 @@ mod spec_tests {
let pre = case.ssz_default("pre");
let expected_post = case.ssz_default("post");

let actual_post = upgrade_to_fulu::<P>(&P::default_config(), pre);
let actual_post = upgrade_to_fulu::<P>(&P::default_config(), pre)
.expect("upgrade from Electra to Fulu should succeed");

assert_eq!(actual_post, expected_post);
}
Expand Down
16 changes: 16 additions & 0 deletions helper_functions/src/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,22 @@ pub fn compute_matrix_for_data_column_sidecar<P: Preset>(
.collect()
}

pub fn compute_proposer_indices<P: Preset>(
config: &Config,
state: &impl BeaconState<P>,
epoch: Epoch,
seed: H256,
indices: &PackedIndices,
) -> Result<Vec<ValidatorIndex>> {
let start_slot = compute_start_slot_at_epoch::<P>(epoch);
(0..P::SlotsPerEpoch::U64)
.map(|i| {
let seed = hashing::hash_256_64(seed, start_slot.saturating_add(i));
compute_proposer_index(config, state, indices, seed, epoch)
})
.collect::<Result<_>>()
}

#[cfg(test)]
mod tests {
use std::sync::Arc;
Expand Down
2 changes: 1 addition & 1 deletion ssz/src/persistent_vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ impl<T, N, B: BundleSize<T>> PersistentVector<T, N, B> {
.expect("any number below N is a valid index because self contains exactly N elements")
}

fn get(&self, index: u64) -> Result<&T, IndexError>
pub fn get(&self, index: u64) -> Result<&T, IndexError>
where
N: Unsigned + NonZero,
{
Expand Down
4 changes: 2 additions & 2 deletions transition_functions/src/combined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ pub fn process_slots<P: Preset>(
}

if Toption::Some(last_slot_in_phase) == fulu_fork_slot {
*state = fork::upgrade_to_fulu(config, electra_state.as_ref().clone()).into();
*state = fork::upgrade_to_fulu(config, electra_state.as_ref().clone())?.into();

made_progress = true;
}
Expand Down Expand Up @@ -580,7 +580,7 @@ fn post_process_slots_for_epoch_report<P: Preset>(
let fulu_fork_slot = config.fork_slot::<P>(Phase::Fulu);

if Toption::Some(post_slot) == fulu_fork_slot {
*state = fork::upgrade_to_fulu(config, electra_state.as_ref().clone()).into();
*state = fork::upgrade_to_fulu(config, electra_state.as_ref().clone())?.into();
}
}
BeaconState::Fulu(_) => {}
Expand Down
51 changes: 49 additions & 2 deletions transition_functions/src/fulu/epoch_processing.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use anyhow::Result;
use arithmetic::{NonZeroExt as _, U64Ext as _};
use helper_functions::{
accessors::{get_current_epoch, get_next_epoch},
accessors::{get_beacon_proposer_indices, get_current_epoch, get_next_epoch},
electra::{initiate_validator_exit, is_eligible_for_activation_queue},
misc::{compute_activation_exit_epoch, vec_of_default},
predicates::{is_active_validator, is_eligible_for_activation},
};
use ssz::SszHash as _;
use ssz::{PersistentVector, SszHash as _};
use try_from_iterator::TryFromIterator as _;
use typenum::Unsigned as _;
use types::{
capella::containers::HistoricalSummary, config::Config,
fulu::beacon_state::BeaconState as FuluBeaconState, preset::Preset, traits::BeaconState,
Expand Down Expand Up @@ -70,6 +72,9 @@ pub fn process_epoch(config: &Config, state: &mut FuluBeaconState<impl Preset>)
altair::process_participation_flag_updates(state);
altair::process_sync_committee_updates(state)?;

// > [New in Fulu:EIP7917]
process_proposer_lookahead(config, state)?;

state.cache.advance_epoch();

Ok(())
Expand Down Expand Up @@ -215,6 +220,28 @@ fn process_registry_updates<P: Preset>(
Ok(())
}

fn process_proposer_lookahead<P: Preset>(
config: &Config,
state: &mut FuluBeaconState<P>,
) -> Result<()> {
let mut proposer_lookahead = state.proposer_lookahead.into_iter().collect::<Vec<_>>();

let last_epoch_start = proposer_lookahead
.len()
.saturating_sub(P::SlotsPerEpoch::USIZE);
proposer_lookahead.copy_within(P::SlotsPerEpoch::USIZE.., 0);

let target_epoch = get_current_epoch(state).saturating_add(P::MinSeedLookahead::U64 + 1);
let last_proposers_indices = get_beacon_proposer_indices(config, state, target_epoch)?;
let refs = last_proposers_indices.iter().collect::<Vec<&_>>();
proposer_lookahead[last_epoch_start..].copy_from_slice(&refs);

state.proposer_lookahead =
PersistentVector::try_from_iter(proposer_lookahead.into_iter().copied())?;

Ok(())
}

#[cfg(test)]
mod spec_tests {
use spec_test_utils::Case;
Expand Down Expand Up @@ -409,6 +436,20 @@ mod spec_tests {
run_pending_consolidations_case::<Minimal>(case);
}

#[test_resources(
"consensus-spec-tests/tests/mainnet/fulu/epoch_processing/proposer_lookahead/*/*"
)]
fn mainnet_process_look(case: Case) {
run_process_look_case::<Mainnet>(case);
}

#[test_resources(
"consensus-spec-tests/tests/minimal/fulu/epoch_processing/proposer_lookahead/*/*"
)]
fn minimal_process_look(case: Case) {
run_process_look_case::<Minimal>(case);
}

fn run_justification_and_finalization_case<P: Preset>(case: Case) {
run_case::<P>(case, |state| {
let (statistics, _, _) = altair::statistics(state);
Expand Down Expand Up @@ -528,6 +569,12 @@ mod spec_tests {
run_case::<P>(case, electra::process_pending_consolidations)
}

fn run_process_look_case<P: Preset>(case: Case) {
run_case::<P>(case, |state| {
process_proposer_lookahead(&P::default_config(), state)
})
}

fn run_case<P: Preset>(
case: Case,
sub_transition: impl FnOnce(&mut FuluBeaconState<P>) -> Result<()>,
Expand Down
13 changes: 11 additions & 2 deletions types/src/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ use crate::{
electra::containers::{PendingConsolidation, PendingDeposit, PendingPartialWithdrawal},
phase0::{
containers::{Eth1Data, PendingAttestation, Validator},
primitives::{Gwei, H256},
primitives::{Gwei, ValidatorIndex, H256},
},
preset::{
MaxAttestationsPerEpoch, Preset, ProposerLookaheadLength, SlotsPerEth1VotingPeriod,
SlotsPerHistoricalRoot,
},
preset::{MaxAttestationsPerEpoch, Preset, SlotsPerEth1VotingPeriod, SlotsPerHistoricalRoot},
};

pub type RecentRoots<P> =
Expand Down Expand Up @@ -60,3 +63,9 @@ pub type PendingPartialWithdrawals<P> =

pub type PendingConsolidations<P> =
PersistentList<PendingConsolidation, <P as Preset>::PendingConsolidationsLimit>;

pub type ProposerLookahead<P> = PersistentVector<
ValidatorIndex,
ProposerLookaheadLength<P>,
UnhashedBundleSize<ValidatorIndex>,
>;
4 changes: 3 additions & 1 deletion types/src/fulu/beacon_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
collections::{
Balances, EpochParticipation, Eth1DataVotes, HistoricalRoots, HistoricalSummaries,
InactivityScores, PendingConsolidations, PendingDeposits, PendingPartialWithdrawals,
RandaoMixes, RecentRoots, Slashings, Validators,
ProposerLookahead, RandaoMixes, RecentRoots, Slashings, Validators,
},
deneb::containers::ExecutionPayloadHeader,
phase0::{
Expand Down Expand Up @@ -104,6 +104,8 @@ pub struct BeaconState<P: Preset> {
pub pending_deposits: PendingDeposits<P>,
pub pending_partial_withdrawals: PendingPartialWithdrawals<P>,
pub pending_consolidations: PendingConsolidations<P>,
#[serde(with = "serde_utils::string_or_native_sequence")]
pub proposer_lookahead: ProposerLookahead<P>,

// Cache
#[derivative(PartialEq = "ignore")]
Expand Down
2 changes: 2 additions & 0 deletions types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ pub mod fulu {
mod spec_tests;
}

pub use collections::ProposerLookahead;

mod collections;

mod unphased {
Expand Down
Loading