Merge branch 'beacon-api-electra' of https://github.com/sigp/lighthouse into ef-tests-electra

This commit is contained in:
realbigsean
2024-06-20 10:47:22 -04:00
142 changed files with 1463 additions and 1485 deletions

View File

@@ -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>(

View File

@@ -129,6 +129,7 @@ pub enum BlockProcessingError {
target_address: Address,
},
InavlidConsolidationSignature,
PendingAttestationInElectra,
}
impl From<BeaconStateError> for BlockProcessingError {

View File

@@ -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(())

View File

@@ -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))

View File

@@ -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,
}
}