mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 10:11:44 +00:00
[Altair] Sync committee pools (#2321)
Add pools supporting sync committees: - naive sync aggregation pool - observed sync contributions pool - observed sync contributors pool - observed sync aggregators pool Add SSZ types and tests related to sync committee signatures. Co-authored-by: Michael Sproul <michael@sigmaprime.io> Co-authored-by: realbigsean <seananderson33@gmail.com>
This commit is contained in:
@@ -144,6 +144,7 @@ pub type HeaderValidationError = BlockOperationError<HeaderInvalid>;
|
||||
pub type AttesterSlashingValidationError = BlockOperationError<AttesterSlashingInvalid>;
|
||||
pub type ProposerSlashingValidationError = BlockOperationError<ProposerSlashingInvalid>;
|
||||
pub type AttestationValidationError = BlockOperationError<AttestationInvalid>;
|
||||
pub type SyncCommitteeMessageValidationError = BlockOperationError<SyncAggregateInvalid>;
|
||||
pub type DepositValidationError = BlockOperationError<DepositInvalid>;
|
||||
pub type ExitValidationError = BlockOperationError<ExitInvalid>;
|
||||
|
||||
|
||||
@@ -8,9 +8,10 @@ use std::borrow::Cow;
|
||||
use tree_hash::TreeHash;
|
||||
use types::{
|
||||
AggregateSignature, AttesterSlashing, BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec,
|
||||
DepositData, Domain, EthSpec, Fork, Hash256, InconsistentFork, IndexedAttestation,
|
||||
ProposerSlashing, PublicKey, Signature, SignedAggregateAndProof, SignedBeaconBlock,
|
||||
SignedBeaconBlockHeader, SignedRoot, SignedVoluntaryExit, SigningData,
|
||||
DepositData, Domain, Epoch, EthSpec, Fork, Hash256, InconsistentFork, IndexedAttestation,
|
||||
ProposerSlashing, PublicKey, PublicKeyBytes, Signature, SignedAggregateAndProof,
|
||||
SignedBeaconBlock, SignedBeaconBlockHeader, SignedContributionAndProof, SignedRoot,
|
||||
SignedVoluntaryExit, SigningData, SyncAggregatorSelectionData, Unsigned,
|
||||
};
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
@@ -25,6 +26,9 @@ pub enum Error {
|
||||
/// Attempted to find the public key of a validator that does not exist. You cannot distinguish
|
||||
/// between an error and an invalid block in this case.
|
||||
ValidatorUnknown(u64),
|
||||
/// Attempted to find the public key of a validator that does not exist. You cannot distinguish
|
||||
/// between an error and an invalid block in this case.
|
||||
ValidatorPubkeyUnknown(PublicKeyBytes),
|
||||
/// The `BeaconBlock` has a `proposer_index` that does not match the index we computed locally.
|
||||
///
|
||||
/// The block is invalid.
|
||||
@@ -396,3 +400,120 @@ where
|
||||
message,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn signed_sync_aggregate_selection_proof_signature_set<'a, T, F>(
|
||||
get_pubkey: F,
|
||||
signed_contribution_and_proof: &'a SignedContributionAndProof<T>,
|
||||
fork: &Fork,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>>
|
||||
where
|
||||
T: EthSpec,
|
||||
F: Fn(usize) -> Option<Cow<'a, PublicKey>>,
|
||||
{
|
||||
let slot = signed_contribution_and_proof.message.contribution.slot;
|
||||
|
||||
let domain = spec.get_domain(
|
||||
slot.epoch(T::slots_per_epoch()),
|
||||
Domain::SyncCommitteeSelectionProof,
|
||||
fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let selection_data = SyncAggregatorSelectionData {
|
||||
slot,
|
||||
subcommittee_index: signed_contribution_and_proof
|
||||
.message
|
||||
.contribution
|
||||
.subcommittee_index,
|
||||
};
|
||||
let message = selection_data.signing_root(domain);
|
||||
let signature = &signed_contribution_and_proof.message.selection_proof;
|
||||
let validator_index = signed_contribution_and_proof.message.aggregator_index;
|
||||
|
||||
Ok(SignatureSet::single_pubkey(
|
||||
signature,
|
||||
get_pubkey(validator_index as usize).ok_or(Error::ValidatorUnknown(validator_index))?,
|
||||
message,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn signed_sync_aggregate_signature_set<'a, T, F>(
|
||||
get_pubkey: F,
|
||||
signed_contribution_and_proof: &'a SignedContributionAndProof<T>,
|
||||
fork: &Fork,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>>
|
||||
where
|
||||
T: EthSpec,
|
||||
F: Fn(usize) -> Option<Cow<'a, PublicKey>>,
|
||||
{
|
||||
let epoch = signed_contribution_and_proof
|
||||
.message
|
||||
.contribution
|
||||
.slot
|
||||
.epoch(T::slots_per_epoch());
|
||||
|
||||
let domain = spec.get_domain(
|
||||
epoch,
|
||||
Domain::ContributionAndProof,
|
||||
fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = signed_contribution_and_proof.message.signing_root(domain);
|
||||
let signature = &signed_contribution_and_proof.signature;
|
||||
let validator_index = signed_contribution_and_proof.message.aggregator_index;
|
||||
|
||||
Ok(SignatureSet::single_pubkey(
|
||||
signature,
|
||||
get_pubkey(validator_index as usize).ok_or(Error::ValidatorUnknown(validator_index))?,
|
||||
message,
|
||||
))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn sync_committee_contribution_signature_set_from_pubkeys<'a, T, F>(
|
||||
get_pubkey: F,
|
||||
pubkey_bytes: &[PublicKeyBytes],
|
||||
signature: &'a AggregateSignature,
|
||||
epoch: Epoch,
|
||||
beacon_block_root: Hash256,
|
||||
fork: &Fork,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>>
|
||||
where
|
||||
T: EthSpec,
|
||||
F: Fn(&PublicKeyBytes) -> Option<Cow<'a, PublicKey>>,
|
||||
{
|
||||
let mut pubkeys = Vec::with_capacity(T::SyncSubcommitteeSize::to_usize());
|
||||
for pubkey in pubkey_bytes {
|
||||
pubkeys.push(get_pubkey(pubkey).ok_or_else(|| Error::ValidatorPubkeyUnknown(*pubkey))?);
|
||||
}
|
||||
|
||||
let domain = spec.get_domain(epoch, Domain::SyncCommittee, &fork, genesis_validators_root);
|
||||
|
||||
let message = beacon_block_root.signing_root(domain);
|
||||
|
||||
Ok(SignatureSet::multiple_pubkeys(signature, pubkeys, message))
|
||||
}
|
||||
|
||||
pub fn sync_committee_message_set_from_pubkeys<'a, T>(
|
||||
pubkey: Cow<'a, PublicKey>,
|
||||
signature: &'a AggregateSignature,
|
||||
epoch: Epoch,
|
||||
beacon_block_root: Hash256,
|
||||
fork: &Fork,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &'a ChainSpec,
|
||||
) -> Result<SignatureSet<'a>>
|
||||
where
|
||||
T: EthSpec,
|
||||
{
|
||||
let domain = spec.get_domain(epoch, Domain::SyncCommittee, &fork, genesis_validators_root);
|
||||
|
||||
let message = beacon_block_root.signing_root(domain);
|
||||
|
||||
Ok(SignatureSet::single_pubkey(signature, pubkey, message))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::EpochProcessingError;
|
||||
use safe_arith::SafeArith;
|
||||
use std::sync::Arc;
|
||||
use types::beacon_state::BeaconState;
|
||||
use types::chain_spec::ChainSpec;
|
||||
use types::eth_spec::EthSpec;
|
||||
@@ -12,7 +13,7 @@ pub fn process_sync_committee_updates<T: EthSpec>(
|
||||
if next_epoch.safe_rem(spec.epochs_per_sync_committee_period)? == 0 {
|
||||
*state.current_sync_committee_mut()? = state.next_sync_committee()?.clone();
|
||||
|
||||
*state.next_sync_committee_mut()? = state.get_next_sync_committee(spec)?;
|
||||
*state.next_sync_committee_mut()? = Arc::new(state.get_next_sync_committee(spec)?);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::common::{get_attestation_participation_flag_indices, get_attesting_indices};
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
BeaconState, BeaconStateAltair, BeaconStateError as Error, ChainSpec, EthSpec, Fork,
|
||||
ParticipationFlags, PendingAttestation, RelativeEpoch, SyncCommittee, VariableList,
|
||||
@@ -52,6 +53,8 @@ pub fn upgrade_to_altair<E: EthSpec>(
|
||||
VariableList::new(vec![ParticipationFlags::default(); pre.validators.len()])?;
|
||||
let inactivity_scores = VariableList::new(vec![0; pre.validators.len()])?;
|
||||
|
||||
let temp_sync_committee = Arc::new(SyncCommittee::temporary()?);
|
||||
|
||||
// Where possible, use something like `mem::take` to move fields from behind the &mut
|
||||
// reference. For other fields that don't have a good default value, use `clone`.
|
||||
//
|
||||
@@ -94,8 +97,8 @@ pub fn upgrade_to_altair<E: EthSpec>(
|
||||
// Inactivity
|
||||
inactivity_scores,
|
||||
// Sync committees
|
||||
current_sync_committee: SyncCommittee::temporary()?, // not read
|
||||
next_sync_committee: SyncCommittee::temporary()?, // not read
|
||||
current_sync_committee: temp_sync_committee.clone(), // not read
|
||||
next_sync_committee: temp_sync_committee, // not read
|
||||
// Caches
|
||||
committee_caches: mem::take(&mut pre.committee_caches),
|
||||
pubkey_cache: mem::take(&mut pre.pubkey_cache),
|
||||
@@ -109,9 +112,9 @@ pub fn upgrade_to_altair<E: EthSpec>(
|
||||
// Fill in sync committees
|
||||
// Note: A duplicate committee is assigned for the current and next committee at the fork
|
||||
// boundary
|
||||
let sync_committee = post.get_next_sync_committee(spec)?;
|
||||
post.as_altair_mut()?.current_sync_committee = sync_committee.clone();
|
||||
post.as_altair_mut()?.next_sync_committee = sync_committee;
|
||||
let sync_committee = Arc::new(post.get_next_sync_committee(spec)?);
|
||||
*post.current_sync_committee_mut()? = sync_committee.clone();
|
||||
*post.next_sync_committee_mut()? = sync_committee;
|
||||
|
||||
*pre_state = post;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user