Merge branch 'electra_attestation_changes' of https://github.com/sigp/lighthouse into block-processing-electra

This commit is contained in:
realbigsean
2024-05-08 12:48:09 -04:00
33 changed files with 844 additions and 317 deletions

View File

@@ -1,25 +1,162 @@
use types::*;
/// Returns validator indices which participated in the attestation, sorted by increasing index.
pub fn get_attesting_indices<E: EthSpec>(
committee: &[usize],
bitlist: &BitList<E::MaxValidatorsPerCommittee>,
) -> Result<Vec<u64>, BeaconStateError> {
if bitlist.len() != committee.len() {
return Err(BeaconStateError::InvalidBitfield);
pub mod attesting_indices_base {
use crate::per_block_processing::errors::{AttestationInvalid as Invalid, BlockOperationError};
use types::*;
/// Convert `attestation` to (almost) indexed-verifiable form.
///
/// Spec v0.12.1
pub fn get_indexed_attestation<E: EthSpec>(
committee: &[usize],
attestation: &AttestationBase<E>,
) -> Result<IndexedAttestation<E>, BlockOperationError<Invalid>> {
let attesting_indices =
get_attesting_indices::<E>(committee, &attestation.aggregation_bits)?;
Ok(IndexedAttestation::Base(IndexedAttestationBase {
attesting_indices: VariableList::new(attesting_indices)?,
data: attestation.data.clone(),
signature: attestation.signature.clone(),
}))
}
let mut indices = Vec::with_capacity(bitlist.num_set_bits());
for (i, validator_index) in committee.iter().enumerate() {
if let Ok(true) = bitlist.get(i) {
indices.push(*validator_index as u64)
/// Returns validator indices which participated in the attestation, sorted by increasing index.
pub fn get_attesting_indices<E: EthSpec>(
committee: &[usize],
bitlist: &BitList<E::MaxValidatorsPerCommittee>,
) -> Result<Vec<u64>, BeaconStateError> {
if bitlist.len() != committee.len() {
return Err(BeaconStateError::InvalidBitfield);
}
let mut indices = Vec::with_capacity(bitlist.num_set_bits());
for (i, validator_index) in committee.iter().enumerate() {
if let Ok(true) = bitlist.get(i) {
indices.push(*validator_index as u64)
}
}
indices.sort_unstable();
Ok(indices)
}
}
pub mod attesting_indices_electra {
use std::collections::{HashMap, HashSet};
use crate::per_block_processing::errors::{AttestationInvalid as Invalid, BlockOperationError};
use itertools::Itertools;
use safe_arith::SafeArith;
use types::*;
pub fn get_indexed_attestation<E: EthSpec>(
committees: &[BeaconCommittee],
attestation: &AttestationElectra<E>,
) -> Result<IndexedAttestation<E>, BlockOperationError<Invalid>> {
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(),
}))
}
indices.sort_unstable();
pub fn get_indexed_attestation_from_state<E: EthSpec>(
beacon_state: &BeaconState<E>,
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(indices)
Ok(IndexedAttestation::Electra(IndexedAttestationElectra {
attesting_indices: VariableList::new(attesting_indices)?,
data: attestation.data.clone(),
signature: attestation.signature.clone(),
}))
}
/// Shortcut for getting the attesting indices while fetching the committee from the state's cache.
pub fn get_attesting_indices_from_state<E: EthSpec>(
state: &BeaconState<E>,
att: &AttestationElectra<E>,
) -> Result<Vec<u64>, BeaconStateError> {
let committees = state.get_beacon_committees_at_slot(att.data.slot)?;
get_attesting_indices::<E>(&committees, &att.aggregation_bits, &att.committee_bits)
}
/// Returns validator indices which participated in the attestation, sorted by increasing index.
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 committee_indices = get_committee_indices::<E>(committee_bits);
let committee_offset = 0;
let committees_map: HashMap<u64, &BeaconCommittee> = committees
.iter()
.map(|committee| (committee.index, committee))
.collect();
for index in committee_indices {
if let Some(&beacon_committee) = committees_map.get(&index) {
if aggregation_bits.len() != beacon_committee.committee.len() {
return Err(BeaconStateError::InvalidBitfield);
}
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(beacon_committee.committee.len())?;
} else {
return Err(Error::NoCommitteeFound);
}
// TODO(electra) what should we do when theres no committee found for a given index?
}
let mut indices = output.into_iter().collect_vec();
indices.sort_unstable();
Ok(indices)
}
fn get_committee_indices<E: EthSpec>(
committee_bits: &BitVector<E::MaxCommitteesPerSlot>,
) -> Vec<CommitteeIndex> {
committee_bits
.iter()
.enumerate()
.filter_map(|(index, bit)| if bit { Some(index as u64) } else { None })
.collect()
}
}
/// Shortcut for getting the attesting indices while fetching the committee from the state's cache.
@@ -27,12 +164,16 @@ pub fn get_attesting_indices_from_state<E: EthSpec>(
state: &BeaconState<E>,
att: AttestationRef<E>,
) -> Result<Vec<u64>, BeaconStateError> {
let committee = state.get_beacon_committee(att.data().slot, att.data().index)?;
match att {
AttestationRef::Base(att) => {
get_attesting_indices::<E>(committee.committee, &att.aggregation_bits)
let committee = state.get_beacon_committee(att.data.slot, att.data.index)?;
attesting_indices_base::get_attesting_indices::<E>(
committee.committee,
&att.aggregation_bits,
)
}
AttestationRef::Electra(att) => {
attesting_indices_electra::get_attesting_indices_from_state::<E>(state, att)
}
// TODO(electra) implement get_attesting_indices for electra
AttestationRef::Electra(_) => todo!(),
}
}

View File

@@ -1,25 +0,0 @@
use super::get_attesting_indices;
use crate::per_block_processing::errors::{AttestationInvalid as Invalid, BlockOperationError};
use types::{indexed_attestation::IndexedAttestationBase, *};
type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
/// Convert `attestation` to (almost) indexed-verifiable form.
///
/// Spec v0.12.1
pub fn get_indexed_attestation<E: EthSpec>(
committee: &[usize],
attestation: AttestationRef<E>,
) -> Result<IndexedAttestation<E>> {
let attesting_indices = match attestation {
AttestationRef::Base(att) => get_attesting_indices::<E>(committee, &att.aggregation_bits)?,
// TODO(electra) implement get_attesting_indices for electra
AttestationRef::Electra(_) => todo!(),
};
Ok(IndexedAttestation::Base(IndexedAttestationBase {
attesting_indices: VariableList::new(attesting_indices)?,
data: attestation.data().clone(),
signature: attestation.signature().clone(),
}))
}

View File

@@ -1,7 +1,6 @@
mod deposit_data_tree;
mod get_attestation_participation;
mod get_attesting_indices;
mod get_indexed_attestation;
mod initiate_validator_exit;
mod slash_validator;
@@ -11,8 +10,9 @@ pub mod update_progressive_balances_cache;
pub use deposit_data_tree::DepositDataTree;
pub use get_attestation_participation::get_attestation_participation_flag_indices;
pub use get_attesting_indices::{get_attesting_indices, get_attesting_indices_from_state};
pub use get_indexed_attestation::get_indexed_attestation;
pub use get_attesting_indices::{
attesting_indices_base, attesting_indices_electra, get_attesting_indices_from_state,
};
pub use initiate_validator_exit::initiate_validator_exit;
pub use slash_validator::slash_validator;

View File

@@ -1,4 +1,4 @@
use crate::common::get_indexed_attestation;
use crate::common::{attesting_indices_base, attesting_indices_electra};
use crate::per_block_processing::errors::{AttestationInvalid, BlockOperationError};
use crate::EpochCacheError;
use std::collections::{hash_map::Entry, HashMap};
@@ -22,13 +22,8 @@ pub struct ConsensusContext<E: EthSpec> {
/// Block root of the block at `slot`.
pub current_block_root: Option<Hash256>,
/// Cache of indexed attestations constructed during block processing.
pub indexed_attestations: HashMap<
(
AttestationData,
BitList<E::MaxValidatorsPerCommitteePerSlot>,
),
IndexedAttestation<E>,
>,
pub indexed_attestations:
HashMap<(AttestationData, BitList<E::MaxValidatorsPerSlot>), IndexedAttestation<E>>,
}
#[derive(Debug, PartialEq, Clone)]
@@ -159,32 +154,40 @@ impl<E: EthSpec> ConsensusContext<E> {
state: &BeaconState<E>,
attestation: AttestationRef<'a, E>,
) -> Result<IndexedAttestationRef<E>, BlockOperationError<AttestationInvalid>> {
let aggregation_bits = match attestation {
match attestation {
AttestationRef::Base(attn) => {
let mut extended_aggregation_bits: BitList<E::MaxValidatorsPerCommitteePerSlot> =
BitList::with_capacity(attn.aggregation_bits.len())
.map_err(BeaconStateError::from)?;
let extended_aggregation_bits = attn
.extend_aggregation_bits()
.map_err(BeaconStateError::from)?;
for (i, bit) in attn.aggregation_bits.iter().enumerate() {
extended_aggregation_bits
.set(i, bit)
.map_err(BeaconStateError::from)?;
let key = (attn.data.clone(), extended_aggregation_bits);
match self.indexed_attestations.entry(key) {
Entry::Occupied(occupied) => Ok(occupied.into_mut()),
Entry::Vacant(vacant) => {
let committee =
state.get_beacon_committee(attn.data.slot, attn.data.index)?;
let indexed_attestation = attesting_indices_base::get_indexed_attestation(
committee.committee,
attn,
)?;
Ok(vacant.insert(indexed_attestation))
}
}
extended_aggregation_bits
}
AttestationRef::Electra(attn) => attn.aggregation_bits.clone(),
};
AttestationRef::Electra(attn) => {
let key = (attn.data.clone(), attn.aggregation_bits.clone());
let key = (attestation.data().clone(), aggregation_bits);
match self.indexed_attestations.entry(key) {
Entry::Occupied(occupied) => Ok(occupied.into_mut()),
Entry::Vacant(vacant) => {
let committee = state
.get_beacon_committee(attestation.data().slot, attestation.data().index)?;
let indexed_attestation =
get_indexed_attestation(committee.committee, attestation)?;
Ok(vacant.insert(indexed_attestation))
match self.indexed_attestations.entry(key) {
Entry::Occupied(occupied) => Ok(occupied.into_mut()),
Entry::Vacant(vacant) => {
let indexed_attestation =
attesting_indices_electra::get_indexed_attestation_from_state(
state, attn,
)?;
Ok(vacant.insert(indexed_attestation))
}
}
}
}
.map(|indexed_attestation| (*indexed_attestation).to_ref())
@@ -198,10 +201,7 @@ impl<E: EthSpec> ConsensusContext<E> {
pub fn set_indexed_attestations(
mut self,
attestations: HashMap<
(
AttestationData,
BitList<E::MaxValidatorsPerCommitteePerSlot>,
),
(AttestationData, BitList<E::MaxValidatorsPerSlot>),
IndexedAttestation<E>,
>,
) -> Self {

View File

@@ -1,4 +1,4 @@
use crate::common::get_attesting_indices;
use crate::common::attesting_indices_base::get_attesting_indices;
use safe_arith::SafeArith;
use types::{BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec, PendingAttestation};

View File

@@ -1,5 +1,7 @@
use crate::common::update_progressive_balances_cache::initialize_progressive_balances_cache;
use crate::common::{get_attestation_participation_flag_indices, get_attesting_indices};
use crate::common::{
attesting_indices_base::get_attesting_indices, get_attestation_participation_flag_indices,
};
use std::mem;
use std::sync::Arc;
use types::{