Skip to content

Commit

Permalink
get attesting indices electra impl
Browse files Browse the repository at this point in the history
  • Loading branch information
eserilev committed May 6, 2024
1 parent 19a9479 commit 1af04b3
Show file tree
Hide file tree
Showing 16 changed files with 361 additions and 120 deletions.
139 changes: 102 additions & 37 deletions beacon_node/beacon_chain/src/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ use crate::{
BeaconChain, BeaconChainError, BeaconChainTypes,
};
use bls::verify_signature_sets;
use itertools::Itertools;
use proto_array::Block as ProtoBlock;
use slog::debug;
use slot_clock::SlotClock;
use state_processing::{
common::get_indexed_attestation,
per_block_processing::errors::AttestationValidationError,
common::{attesting_indices_base, attesting_indices_electra},
per_block_processing::errors::{AttestationValidationError, BlockOperationError},
signature_sets::{
indexed_attestation_signature_set_from_pubkeys,
signed_aggregate_selection_proof_signature_set, signed_aggregate_signature_set,
Expand All @@ -55,8 +56,9 @@ use std::borrow::Cow;
use strum::AsRefStr;
use tree_hash::TreeHash;
use types::{
Attestation, AttestationRef, BeaconCommittee, ChainSpec, CommitteeIndex, Epoch, EthSpec,
ForkName, Hash256, IndexedAttestation, SelectionProof, SignedAggregateAndProof, Slot, SubnetId,
Attestation, AttestationRef, BeaconCommittee, BeaconStateError::NoCommitteeFound, ChainSpec,
CommitteeIndex, Epoch, EthSpec, ForkName, Hash256, IndexedAttestation, SelectionProof,
SignedAggregateAndProof, Slot, SubnetId,
};

pub use batch::{batch_verify_aggregated_attestations, batch_verify_unaggregated_attestations};
Expand Down Expand Up @@ -545,32 +547,59 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
};

let get_indexed_attestation_with_committee =
|(committee, _): (BeaconCommittee, CommitteesPerSlot)| {
// 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());

if !selection_proof
.is_aggregator(committee.committee.len(), &chain.spec)
.map_err(|e| Error::BeaconChainError(e.into()))?
{
return Err(Error::InvalidSelectionProof { aggregator_index });
}

// Ensure the aggregator is a member of the committee for which it is aggregating.
if !committee.committee.contains(&(aggregator_index as usize)) {
return Err(Error::AggregatorNotInCommittee { aggregator_index });
|(committees, _): (Vec<BeaconCommittee>, CommitteesPerSlot)| {
match attestation {
AttestationRef::Base(att) => {
let committee = committees
.iter()
.filter(|&committee| committee.index == att.data.index)
.at_most_one()
.map_err(|_| Error::NoCommitteeForSlotAndIndex {
slot: att.data.slot,
index: att.data.index,
})?;

if let Some(committee) = committee {
// 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(),
);

if !selection_proof
.is_aggregator(committee.committee.len(), &chain.spec)
.map_err(|e| Error::BeaconChainError(e.into()))?
{
return Err(Error::InvalidSelectionProof { aggregator_index });
}

// Ensure the aggregator is a member of the committee for which it is aggregating.
if !committee.committee.contains(&(aggregator_index as usize)) {
return Err(Error::AggregatorNotInCommittee { aggregator_index });
}
attesting_indices_base::get_indexed_attestation(
committee.committee,
att,
)
.map_err(|e| BeaconChainError::from(e).into())
} else {
Err(Error::NoCommitteeForSlotAndIndex {
slot: att.data.slot,
index: att.data.index,
})
}
}
AttestationRef::Electra(att) => {
attesting_indices_electra::get_indexed_attestation(&committees, att)
.map_err(|e| BeaconChainError::from(e).into())
}
}

get_indexed_attestation(committee.committee, attestation)
.map_err(|e| BeaconChainError::from(e).into())
};

let indexed_attestation = match map_attestation_committee(
let indexed_attestation = match map_attestation_committees(
chain,
attestation,
&attestation,
get_indexed_attestation_with_committee,
) {
Ok(indexed_attestation) => indexed_attestation,
Expand Down Expand Up @@ -1252,13 +1281,49 @@ pub fn obtain_indexed_attestation_and_committees_per_slot<T: BeaconChainTypes>(
chain: &BeaconChain<T>,
attestation: AttestationRef<T::EthSpec>,
) -> Result<(IndexedAttestation<T::EthSpec>, CommitteesPerSlot), Error> {
map_attestation_committee(chain, attestation, |(committee, committees_per_slot)| {
get_indexed_attestation(committee.committee, attestation)
.map(|attestation| (attestation, committees_per_slot))
.map_err(Error::Invalid)
map_attestation_committees(chain, &attestation, |(committees, committees_per_slot)| {
match attestation {
AttestationRef::Base(att) => {
let committee = committees
.iter()
.filter(|&committee| committee.index == att.data.index)
.at_most_one()
.map_err(|_| Error::NoCommitteeForSlotAndIndex {
slot: att.data.slot,
index: att.data.index,
})?;

if let Some(committee) = committee {
attesting_indices_base::get_indexed_attestation(committee.committee, att)
.map(|attestation| (attestation, committees_per_slot))
.map_err(Error::Invalid)
} else {
Err(Error::NoCommitteeForSlotAndIndex {
slot: att.data.slot,
index: att.data.index,
})
}
}
AttestationRef::Electra(att) => {
attesting_indices_electra::get_indexed_attestation(&committees, att)
.map(|attestation| (attestation, committees_per_slot))
.map_err(|e| {
if e == BlockOperationError::BeaconStateError(NoCommitteeFound) {
Error::NoCommitteeForSlotAndIndex {
slot: att.data.slot,
index: att.committee_index(),
}
} else {
Error::Invalid(e)
}
})
}
}
})
}

// TODO(electra) update comments below to reflect logic changes
// i.e. this now runs the map_fn on a list of committees for the slot of the provided attestation
/// Runs the `map_fn` with the committee and committee count per slot for the given `attestation`.
///
/// This function exists in this odd "map" pattern because efficiently obtaining the committee for
Expand All @@ -1268,14 +1333,14 @@ pub fn obtain_indexed_attestation_and_committees_per_slot<T: BeaconChainTypes>(
///
/// If the committee for `attestation` isn't found in the `shuffling_cache`, we will read a state
/// from disk and then update the `shuffling_cache`.
fn map_attestation_committee<T, F, R>(
fn map_attestation_committees<T, F, R>(
chain: &BeaconChain<T>,
attestation: AttestationRef<T::EthSpec>,
attestation: &AttestationRef<T::EthSpec>,
map_fn: F,
) -> Result<R, Error>
where
T: BeaconChainTypes,
F: Fn((BeaconCommittee, CommitteesPerSlot)) -> Result<R, Error>,
F: Fn((Vec<BeaconCommittee>, CommitteesPerSlot)) -> Result<R, Error>,
{
let attestation_epoch = attestation.data().slot.epoch(T::EthSpec::slots_per_epoch());
let target = &attestation.data().target;
Expand All @@ -1301,12 +1366,12 @@ where
let committees_per_slot = committee_cache.committees_per_slot();

Ok(committee_cache
.get_beacon_committee(attestation.data().slot, attestation.data().index)
.map(|committee| map_fn((committee, committees_per_slot)))
.unwrap_or_else(|| {
.get_beacon_committees_at_slot(attestation.data().slot)
.map(|committees| map_fn((committees, committees_per_slot)))
.unwrap_or_else(|_| {
Err(Error::NoCommitteeForSlotAndIndex {
slot: attestation.data().slot,
index: attestation.data().index,
index: attestation.committee_index(),
})
}))
})
Expand Down
21 changes: 18 additions & 3 deletions beacon_node/http_api/src/block_packing_efficiency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,24 @@ impl<E: EthSpec> PackingEfficiencyHandler<E> {
}
}
}
// TODO(electra) implement electra variant
AttestationRef::Electra(_) => {
todo!()
AttestationRef::Electra(attn) => {
for (position, voted) in attn.aggregation_bits.iter().enumerate() {
if voted {
let unique_attestation = UniqueAttestation {
slot: attn.data.slot,
committee_index: attn.data.index,
committee_position: position,
};
let inclusion_distance: u64 = block
.slot()
.as_u64()
.checked_sub(attn.data.slot.as_u64())
.ok_or(PackingEfficiencyError::InvalidAttestationError)?;

self.available_attestations.remove(&unique_attestation);
attestations_in_block.insert(unique_attestation, inclusion_distance);
}
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions beacon_node/http_api/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3285,6 +3285,7 @@ impl ApiTester {
.unwrap()
.data;

// TODO(electra) make fork-agnostic
let mut attestation = Attestation::Base(AttestationBase {
aggregation_bits: BitList::with_capacity(duty.committee_length as usize).unwrap(),
data: attestation_data,
Expand Down
2 changes: 1 addition & 1 deletion beacon_node/network/src/sync/block_lookups/parent_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub(crate) fn compute_parent_chains(nodes: &[Node]) -> Vec<NodeChain> {
// Iterate blocks with no children
for tip in nodes {
let mut block_root = tip.block_root;
if parent_to_child.get(&block_root).is_none() {
if !parent_to_child.contains_key(&block_root) {
let mut chain = vec![];

// Resolve chain of blocks
Expand Down
2 changes: 1 addition & 1 deletion beacon_node/operation_pool/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::attestation_storage::{AttestationRef, CompactIndexedAttestation};
use crate::max_cover::MaxCover;
use crate::reward_cache::RewardCache;
use state_processing::common::{
base, get_attestation_participation_flag_indices, get_attesting_indices,
base, get_attestation_participation_flag_indices, attesting_indices_base::get_attesting_indices,
};
use std::collections::HashMap;
use types::{
Expand Down
11 changes: 9 additions & 2 deletions beacon_node/operation_pool/src/attestation_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,15 @@ impl<E: EthSpec> SplitAttestation<E> {
index: data.index,
})
}
// TODO(electra) implement electra variant
Attestation::Electra(_) => todo!(),
Attestation::Electra(attn) => {
CompactIndexedAttestation::Electra(CompactIndexedAttestationElectra {
attesting_indices,
aggregation_bits: attn.aggregation_bits,
signature: attestation.signature().clone(),
index: data.index,
committee_bits: attn.committee_bits,
})
},
};

Self {
Expand Down
4 changes: 3 additions & 1 deletion beacon_node/operation_pool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,9 @@ mod release_tests {
op_pool
.insert_attestation(att.clone_as_attestation(), attesting_indices.clone())
.unwrap();
op_pool.insert_attestation(att.clone_as_attestation(), attesting_indices).unwrap();
op_pool
.insert_attestation(att.clone_as_attestation(), attesting_indices)
.unwrap();
}

assert_eq!(op_pool.num_attestations(), committees.len());
Expand Down
Loading

0 comments on commit 1af04b3

Please sign in to comment.