mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-11 18:04:18 +00:00
Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra
This commit is contained in:
@@ -44,107 +44,15 @@ pub mod attesting_indices_base {
|
||||
}
|
||||
|
||||
pub mod attesting_indices_electra {
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::per_block_processing::errors::{AttestationInvalid as Invalid, BlockOperationError};
|
||||
use itertools::Itertools;
|
||||
use safe_arith::SafeArith;
|
||||
use types::*;
|
||||
|
||||
// TODO(electra) remove duplicate code
|
||||
// get_indexed_attestation is almost an exact duplicate
|
||||
// the only differences are the invalid selection proof
|
||||
// and aggregator not in committee checks
|
||||
pub fn get_indexed_attestation_from_signed_aggregate<E: EthSpec>(
|
||||
committees: &[BeaconCommittee],
|
||||
signed_aggregate: &SignedAggregateAndProofElectra<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<IndexedAttestation<E>, BeaconStateError> {
|
||||
let mut output: HashSet<u64> = HashSet::new();
|
||||
|
||||
let committee_bits = &signed_aggregate.message.aggregate.committee_bits;
|
||||
let aggregation_bits = &signed_aggregate.message.aggregate.aggregation_bits;
|
||||
let aggregator_index = signed_aggregate.message.aggregator_index;
|
||||
let attestation = &signed_aggregate.message.aggregate;
|
||||
|
||||
let committee_indices = get_committee_indices::<E>(committee_bits);
|
||||
|
||||
let mut committee_offset = 0;
|
||||
|
||||
let committees_map: HashMap<u64, &BeaconCommittee> = committees
|
||||
.iter()
|
||||
.map(|committee| (committee.index, committee))
|
||||
.collect();
|
||||
|
||||
let committee_count_per_slot = committees.len() as u64;
|
||||
let mut participant_count = 0;
|
||||
|
||||
// TODO(electra):
|
||||
// Note: this clones the signature which is known to be a relatively slow operation.
|
||||
//
|
||||
// Future optimizations should remove this clone.
|
||||
let selection_proof =
|
||||
SelectionProof::from(signed_aggregate.message.selection_proof.clone());
|
||||
|
||||
for index in committee_indices {
|
||||
if let Some(&beacon_committee) = committees_map.get(&index) {
|
||||
if !selection_proof
|
||||
.is_aggregator(beacon_committee.committee.len(), spec)
|
||||
.map_err(BeaconStateError::ArithError)?
|
||||
{
|
||||
return Err(BeaconStateError::InvalidSelectionProof { aggregator_index });
|
||||
}
|
||||
|
||||
if !beacon_committee
|
||||
.committee
|
||||
.contains(&(aggregator_index as usize))
|
||||
{
|
||||
return Err(BeaconStateError::AggregatorNotInCommittee { aggregator_index });
|
||||
}
|
||||
|
||||
// This check is new to the spec's `process_attestation` in Electra.
|
||||
if index >= committee_count_per_slot {
|
||||
return Err(BeaconStateError::InvalidCommitteeIndex(index));
|
||||
}
|
||||
|
||||
participant_count.safe_add_assign(beacon_committee.committee.len() as u64)?;
|
||||
let committee_attesters = beacon_committee
|
||||
.committee
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, &index)| {
|
||||
if let Ok(aggregation_bit_index) = committee_offset.safe_add(i) {
|
||||
if aggregation_bits.get(aggregation_bit_index).unwrap_or(false) {
|
||||
return Some(index as u64);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<HashSet<u64>>();
|
||||
|
||||
output.extend(committee_attesters);
|
||||
|
||||
committee_offset.safe_add_assign(beacon_committee.committee.len())?;
|
||||
} else {
|
||||
return Err(Error::NoCommitteeFound(index));
|
||||
}
|
||||
}
|
||||
|
||||
// This check is new to the spec's `process_attestation` in Electra.
|
||||
if participant_count as usize != aggregation_bits.len() {
|
||||
return Err(Error::InvalidBitfield);
|
||||
}
|
||||
|
||||
let mut indices = output.into_iter().collect_vec();
|
||||
indices.sort_unstable();
|
||||
|
||||
Ok(IndexedAttestation::Electra(IndexedAttestationElectra {
|
||||
attesting_indices: VariableList::new(indices)?,
|
||||
data: attestation.data.clone(),
|
||||
signature: attestation.signature.clone(),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Compute an Electra IndexedAttestation given a list of committees.
|
||||
///
|
||||
/// Committees must be sorted by ascending order 0..committees_per_slot
|
||||
pub fn get_indexed_attestation<E: EthSpec>(
|
||||
committees: &[BeaconCommittee],
|
||||
attestation: &AttestationElectra<E>,
|
||||
@@ -167,17 +75,7 @@ pub mod attesting_indices_electra {
|
||||
attestation: &AttestationElectra<E>,
|
||||
) -> Result<IndexedAttestation<E>, BlockOperationError<Invalid>> {
|
||||
let committees = beacon_state.get_beacon_committees_at_slot(attestation.data.slot)?;
|
||||
let attesting_indices = get_attesting_indices::<E>(
|
||||
&committees,
|
||||
&attestation.aggregation_bits,
|
||||
&attestation.committee_bits,
|
||||
)?;
|
||||
|
||||
Ok(IndexedAttestation::Electra(IndexedAttestationElectra {
|
||||
attesting_indices: VariableList::new(attesting_indices)?,
|
||||
data: attestation.data.clone(),
|
||||
signature: attestation.signature.clone(),
|
||||
}))
|
||||
get_indexed_attestation(&committees, attestation)
|
||||
}
|
||||
|
||||
/// Shortcut for getting the attesting indices while fetching the committee from the state's cache.
|
||||
@@ -190,51 +88,47 @@ pub mod attesting_indices_electra {
|
||||
}
|
||||
|
||||
/// Returns validator indices which participated in the attestation, sorted by increasing index.
|
||||
///
|
||||
/// Committees must be sorted by ascending order 0..committees_per_slot
|
||||
pub fn get_attesting_indices<E: EthSpec>(
|
||||
committees: &[BeaconCommittee],
|
||||
aggregation_bits: &BitList<E::MaxValidatorsPerSlot>,
|
||||
committee_bits: &BitVector<E::MaxCommitteesPerSlot>,
|
||||
) -> Result<Vec<u64>, BeaconStateError> {
|
||||
let mut output: HashSet<u64> = HashSet::new();
|
||||
let mut attesting_indices = vec![];
|
||||
|
||||
let committee_indices = get_committee_indices::<E>(committee_bits);
|
||||
|
||||
let mut committee_offset = 0;
|
||||
|
||||
let committees_map: HashMap<u64, &BeaconCommittee> = committees
|
||||
.iter()
|
||||
.map(|committee| (committee.index, committee))
|
||||
.collect();
|
||||
|
||||
let committee_count_per_slot = committees.len() as u64;
|
||||
let mut participant_count = 0;
|
||||
for index in committee_indices {
|
||||
if let Some(&beacon_committee) = committees_map.get(&index) {
|
||||
// This check is new to the spec's `process_attestation` in Electra.
|
||||
if index >= committee_count_per_slot {
|
||||
return Err(BeaconStateError::InvalidCommitteeIndex(index));
|
||||
}
|
||||
participant_count.safe_add_assign(beacon_committee.committee.len() as u64)?;
|
||||
let committee_attesters = beacon_committee
|
||||
.committee
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, &index)| {
|
||||
if let Ok(aggregation_bit_index) = committee_offset.safe_add(i) {
|
||||
if aggregation_bits.get(aggregation_bit_index).unwrap_or(false) {
|
||||
return Some(index as u64);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<HashSet<u64>>();
|
||||
let beacon_committee = committees
|
||||
.get(index as usize)
|
||||
.ok_or(Error::NoCommitteeFound(index))?;
|
||||
|
||||
output.extend(committee_attesters);
|
||||
|
||||
committee_offset.safe_add_assign(beacon_committee.committee.len())?;
|
||||
} else {
|
||||
return Err(Error::NoCommitteeFound(index));
|
||||
// This check is new to the spec's `process_attestation` in Electra.
|
||||
if index >= committee_count_per_slot {
|
||||
return Err(BeaconStateError::InvalidCommitteeIndex(index));
|
||||
}
|
||||
participant_count.safe_add_assign(beacon_committee.committee.len() as u64)?;
|
||||
let committee_attesters = beacon_committee
|
||||
.committee
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, &index)| {
|
||||
if let Ok(aggregation_bit_index) = committee_offset.safe_add(i) {
|
||||
if aggregation_bits.get(aggregation_bit_index).unwrap_or(false) {
|
||||
return Some(index as u64);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.collect::<HashSet<u64>>();
|
||||
|
||||
attesting_indices.extend(committee_attesters);
|
||||
committee_offset.safe_add_assign(beacon_committee.committee.len())?;
|
||||
}
|
||||
|
||||
// This check is new to the spec's `process_attestation` in Electra.
|
||||
@@ -242,10 +136,9 @@ pub mod attesting_indices_electra {
|
||||
return Err(BeaconStateError::InvalidBitfield);
|
||||
}
|
||||
|
||||
let mut indices = output.into_iter().collect_vec();
|
||||
indices.sort_unstable();
|
||||
attesting_indices.sort_unstable();
|
||||
|
||||
Ok(indices)
|
||||
Ok(attesting_indices)
|
||||
}
|
||||
|
||||
pub fn get_committee_indices<E: EthSpec>(
|
||||
|
||||
@@ -129,6 +129,7 @@ pub enum BlockProcessingError {
|
||||
target_address: Address,
|
||||
},
|
||||
InavlidConsolidationSignature,
|
||||
PendingAttestationInElectra,
|
||||
}
|
||||
|
||||
impl From<BeaconStateError> for BlockProcessingError {
|
||||
|
||||
@@ -91,33 +91,30 @@ pub mod base {
|
||||
)
|
||||
.map_err(|e| e.into_with_index(i))?;
|
||||
|
||||
match attestation {
|
||||
AttestationRef::Base(att) => {
|
||||
let pending_attestation = PendingAttestation {
|
||||
aggregation_bits: att.aggregation_bits.clone(),
|
||||
data: att.data.clone(),
|
||||
inclusion_delay: state.slot().safe_sub(att.data.slot)?.as_u64(),
|
||||
proposer_index,
|
||||
};
|
||||
|
||||
if attestation.data().target.epoch == state.current_epoch() {
|
||||
state
|
||||
.as_base_mut()?
|
||||
.current_epoch_attestations
|
||||
.push(pending_attestation)?;
|
||||
} else {
|
||||
state
|
||||
.as_base_mut()?
|
||||
.previous_epoch_attestations
|
||||
.push(pending_attestation)?;
|
||||
}
|
||||
}
|
||||
AttestationRef::Electra(_) => {
|
||||
// TODO(electra) pending attestations are only phase 0
|
||||
// so we should just raise a relevant error here
|
||||
todo!()
|
||||
}
|
||||
let AttestationRef::Base(attestation) = attestation else {
|
||||
// Pending attestations have been deprecated in a altair, this branch should
|
||||
// never happen
|
||||
return Err(BlockProcessingError::PendingAttestationInElectra);
|
||||
};
|
||||
|
||||
let pending_attestation = PendingAttestation {
|
||||
aggregation_bits: attestation.aggregation_bits.clone(),
|
||||
data: attestation.data.clone(),
|
||||
inclusion_delay: state.slot().safe_sub(attestation.data.slot)?.as_u64(),
|
||||
proposer_index,
|
||||
};
|
||||
|
||||
if attestation.data.target.epoch == state.current_epoch() {
|
||||
state
|
||||
.as_base_mut()?
|
||||
.current_epoch_attestations
|
||||
.push(pending_attestation)?;
|
||||
} else {
|
||||
state
|
||||
.as_base_mut()?
|
||||
.previous_epoch_attestations
|
||||
.push(pending_attestation)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -326,7 +326,6 @@ where
|
||||
genesis_validators_root,
|
||||
);
|
||||
|
||||
// TODO(electra), signing root isnt unique in the case of electra
|
||||
let message = indexed_attestation.data().signing_root(domain);
|
||||
|
||||
Ok(SignatureSet::multiple_pubkeys(signature, pubkeys, message))
|
||||
|
||||
@@ -30,7 +30,7 @@ impl Default for InclusionInfo {
|
||||
/// Defaults to `delay` at its maximum value and `proposer_index` at zero.
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
delay: u64::max_value(),
|
||||
delay: u64::MAX,
|
||||
proposer_index: 0,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user