Skip to content

Commit

Permalink
compute on chain aggregate, rename attestationref, and clean up some …
Browse files Browse the repository at this point in the history
…todos
  • Loading branch information
eserilev committed May 5, 2024
1 parent 7c6526d commit 494d7ad
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 40 deletions.
10 changes: 6 additions & 4 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ use futures::channel::mpsc::Sender;
use itertools::process_results;
use itertools::Itertools;
use kzg::Kzg;
use operation_pool::{AttestationRef, OperationPool, PersistedOperationPool, ReceivedPreCapella};
use operation_pool::{
CompactAttestationRef, OperationPool, PersistedOperationPool, ReceivedPreCapella,
};
use parking_lot::{Mutex, RwLock};
use proto_array::{DoNotReOrg, ProposerHeadError};
use safe_arith::SafeArith;
Expand Down Expand Up @@ -2284,7 +2286,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pub fn filter_op_pool_attestation(
&self,
filter_cache: &mut HashMap<(Hash256, Epoch), bool>,
att: &AttestationRef<T::EthSpec>,
att: &CompactAttestationRef<T::EthSpec>,
state: &BeaconState<T::EthSpec>,
) -> bool {
*filter_cache
Expand Down Expand Up @@ -4895,11 +4897,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
initialize_epoch_cache(&mut state, &self.spec)?;

let mut prev_filter_cache = HashMap::new();
let prev_attestation_filter = |att: &AttestationRef<T::EthSpec>| {
let prev_attestation_filter = |att: &CompactAttestationRef<T::EthSpec>| {
self.filter_op_pool_attestation(&mut prev_filter_cache, att, &state)
};
let mut curr_filter_cache = HashMap::new();
let curr_attestation_filter = |att: &AttestationRef<T::EthSpec>| {
let curr_attestation_filter = |att: &CompactAttestationRef<T::EthSpec>| {
self.filter_op_pool_attestation(&mut curr_filter_cache, att, &state)
};

Expand Down
33 changes: 22 additions & 11 deletions beacon_node/beacon_chain/src/observed_aggregates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub type ObservedSyncContributions<E> = ObservedAggregates<
pub type ObservedAggregateAttestations<E> = ObservedAggregates<
Attestation<E>,
E,
BitList<<E as types::EthSpec>::MaxValidatorsPerCommittee>,
BitList<<E as types::EthSpec>::MaxValidatorsPerCommitteePerSlot>,
>;

/// A trait use to associate capacity constants with the type being stored in `ObservedAggregates`.
Expand Down Expand Up @@ -103,29 +103,40 @@ pub trait SubsetItem {
}

impl<'a, E: EthSpec> SubsetItem for AttestationRef<'a, E> {
type Item = BitList<E::MaxValidatorsPerCommittee>;
type Item = BitList<E::MaxValidatorsPerCommitteePerSlot>;
fn is_subset(&self, other: &Self::Item) -> bool {
match self {
Self::Base(att) => att.aggregation_bits.is_subset(other),
// TODO(electra) implement electra variant
Self::Electra(_) => todo!(),
Self::Base(att) => {
if let Ok(extended_aggregation_bits) = att.extend_aggregation_bits() {
return extended_aggregation_bits.is_subset(other)
}
false
},
Self::Electra(att) => att.aggregation_bits.is_subset(other),
}
}

fn is_superset(&self, other: &Self::Item) -> bool {
match self {
Self::Base(att) => other.is_subset(&att.aggregation_bits),
// TODO(electra) implement electra variant
Self::Electra(_) => todo!(),

Self::Base(att) => {
if let Ok(extended_aggregation_bits) = att.extend_aggregation_bits() {
return other.is_subset(&extended_aggregation_bits)
}
false
},
Self::Electra(att) => other.is_subset(&att.aggregation_bits),
}
}

/// Returns the sync contribution aggregation bits.
fn get_item(&self) -> Self::Item {
match self {
Self::Base(att) => att.aggregation_bits.clone(),
// TODO(electra) implement electra variant
Self::Electra(_) => todo!(),
Self::Base(att) => {
// TODO(electra) fix unwrap
att.extend_aggregation_bits().unwrap()
},
Self::Electra(att) => att.aggregation_bits.clone(),
}
}

Expand Down
20 changes: 10 additions & 10 deletions beacon_node/operation_pool/src/attestation.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::attestation_storage::{AttestationRef, CompactIndexedAttestation};
use crate::attestation_storage::{CompactAttestationRef, CompactIndexedAttestation};
use crate::max_cover::MaxCover;
use crate::reward_cache::RewardCache;
use state_processing::common::{
Expand All @@ -14,14 +14,14 @@ use types::{
#[derive(Debug, Clone)]
pub struct AttMaxCover<'a, E: EthSpec> {
/// Underlying attestation.
pub att: AttestationRef<'a, E>,
pub att: CompactAttestationRef<'a, E>,
/// Mapping of validator indices and their rewards.
pub fresh_validators_rewards: HashMap<u64, u64>,
}

impl<'a, E: EthSpec> AttMaxCover<'a, E> {
pub fn new(
att: AttestationRef<'a, E>,
att: CompactAttestationRef<'a, E>,
state: &BeaconState<E>,
reward_cache: &'a RewardCache,
total_active_balance: u64,
Expand All @@ -36,7 +36,7 @@ impl<'a, E: EthSpec> AttMaxCover<'a, E> {

/// Initialise an attestation cover object for base/phase0 hard fork.
pub fn new_for_base(
att: AttestationRef<'a, E>,
att: CompactAttestationRef<'a, E>,
state: &BeaconState<E>,
base_state: &BeaconStateBase<E>,
total_active_balance: u64,
Expand Down Expand Up @@ -69,7 +69,7 @@ impl<'a, E: EthSpec> AttMaxCover<'a, E> {

/// Initialise an attestation cover object for Altair or later.
pub fn new_for_altair_deneb(
att: AttestationRef<'a, E>,
att: CompactAttestationRef<'a, E>,
state: &BeaconState<E>,
reward_cache: &'a RewardCache,
spec: &ChainSpec,
Expand Down Expand Up @@ -119,14 +119,14 @@ impl<'a, E: EthSpec> AttMaxCover<'a, E> {

impl<'a, E: EthSpec> MaxCover for AttMaxCover<'a, E> {
type Object = Attestation<E>;
type Intermediate = AttestationRef<'a, E>;
type Intermediate = CompactAttestationRef<'a, E>;
type Set = HashMap<u64, u64>;

fn intermediate(&self) -> &AttestationRef<'a, E> {
fn intermediate(&self) -> &CompactAttestationRef<'a, E> {
&self.att
}

fn convert_to_object(att_ref: &AttestationRef<'a, E>) -> Attestation<E> {
fn convert_to_object(att_ref: &CompactAttestationRef<'a, E>) -> Attestation<E> {
att_ref.clone_as_attestation()
}

Expand All @@ -146,7 +146,7 @@ impl<'a, E: EthSpec> MaxCover for AttMaxCover<'a, E> {
/// of slashable voting, which is rare.
fn update_covering_set(
&mut self,
best_att: &AttestationRef<'a, E>,
best_att: &CompactAttestationRef<'a, E>,
covered_validators: &HashMap<u64, u64>,
) {
if self.att.data.slot == best_att.data.slot && self.att.data.index == best_att.data.index {
Expand All @@ -170,7 +170,7 @@ impl<'a, E: EthSpec> MaxCover for AttMaxCover<'a, E> {
///
/// This isn't optimal, but with the Altair fork this code is obsolete and not worth upgrading.
pub fn earliest_attestation_validators<E: EthSpec>(
attestation: &AttestationRef<E>,
attestation: &CompactAttestationRef<E>,
state: &BeaconState<E>,
base_state: &BeaconStateBase<E>,
) -> BitList<E::MaxValidatorsPerCommittee> {
Expand Down
59 changes: 49 additions & 10 deletions beacon_node/operation_pool/src/attestation_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct SplitAttestation<E: EthSpec> {
}

#[derive(Debug, Clone)]
pub struct AttestationRef<'a, E: EthSpec> {
pub struct CompactAttestationRef<'a, E: EthSpec> {
pub checkpoint: &'a CheckpointKey,
pub data: &'a CompactAttestationData,
pub indexed: &'a CompactIndexedAttestation<E>,
Expand Down 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 All @@ -92,16 +99,16 @@ impl<E: EthSpec> SplitAttestation<E> {
}
}

pub fn as_ref(&self) -> AttestationRef<E> {
AttestationRef {
pub fn as_ref(&self) -> CompactAttestationRef<E> {
CompactAttestationRef {
checkpoint: &self.checkpoint,
data: &self.data,
indexed: &self.indexed,
}
}
}

impl<'a, E: EthSpec> AttestationRef<'a, E> {
impl<'a, E: EthSpec> CompactAttestationRef<'a, E> {
pub fn attestation_data(&self) -> AttestationData {
AttestationData {
slot: self.data.slot,
Expand Down Expand Up @@ -198,6 +205,38 @@ impl<E: EthSpec> CompactIndexedAttestationBase<E> {
}
}


impl<E: EthSpec> CompactIndexedAttestationElectra<E> {
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
if self
.committee_bits
.intersection(&other.committee_bits)
.is_zero()
{
if self
.aggregation_bits
.intersection(&other.aggregation_bits)
.is_zero()
{
return true;
} else {
for (index, committee_bit) in self.committee_bits.iter().enumerate() {
if committee_bit {
if let Ok(aggregation_bit) = self.aggregation_bits.get(index) {
if let Ok(other_aggregation_bit) = other.aggregation_bits.get(index) {
if aggregation_bit == other_aggregation_bit {
return false;
}
}
}
}
}
}
}
true
}
}

impl<E: EthSpec> AttestationMap<E> {
pub fn insert(&mut self, attestation: Attestation<E>, attesting_indices: Vec<u64>) {
let SplitAttestation {
Expand Down Expand Up @@ -231,15 +270,15 @@ impl<E: EthSpec> AttestationMap<E> {
pub fn get_attestations<'a>(
&'a self,
checkpoint_key: &'a CheckpointKey,
) -> impl Iterator<Item = AttestationRef<'a, E>> + 'a {
) -> impl Iterator<Item = CompactAttestationRef<'a, E>> + 'a {
self.checkpoint_map
.get(checkpoint_key)
.into_iter()
.flat_map(|attestation_map| attestation_map.iter(checkpoint_key))
}

/// Iterate all attestations in the map.
pub fn iter(&self) -> impl Iterator<Item = AttestationRef<E>> {
pub fn iter(&self) -> impl Iterator<Item = CompactAttestationRef<E>> {
self.checkpoint_map
.iter()
.flat_map(|(checkpoint_key, attestation_map)| attestation_map.iter(checkpoint_key))
Expand Down Expand Up @@ -270,9 +309,9 @@ impl<E: EthSpec> AttestationDataMap<E> {
pub fn iter<'a>(
&'a self,
checkpoint_key: &'a CheckpointKey,
) -> impl Iterator<Item = AttestationRef<'a, E>> + 'a {
) -> impl Iterator<Item = CompactAttestationRef<'a, E>> + 'a {
self.attestations.iter().flat_map(|(data, vec_indexed)| {
vec_indexed.iter().map(|indexed| AttestationRef {
vec_indexed.iter().map(|indexed| CompactAttestationRef {
checkpoint: checkpoint_key,
data,
indexed,
Expand Down
8 changes: 4 additions & 4 deletions beacon_node/operation_pool/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod sync_aggregate_id;

pub use crate::bls_to_execution_changes::ReceivedPreCapella;
pub use attestation::{earliest_attestation_validators, AttMaxCover};
pub use attestation_storage::{AttestationRef, SplitAttestation};
pub use attestation_storage::{CompactAttestationRef, SplitAttestation};
pub use max_cover::MaxCover;
pub use persistence::{
PersistedOperationPool, PersistedOperationPoolV12, PersistedOperationPoolV14,
Expand Down Expand Up @@ -228,7 +228,7 @@ impl<E: EthSpec> OperationPool<E> {
state: &'a BeaconState<E>,
reward_cache: &'a RewardCache,
total_active_balance: u64,
validity_filter: impl FnMut(&AttestationRef<'a, E>) -> bool + Send,
validity_filter: impl FnMut(&CompactAttestationRef<'a, E>) -> bool + Send,
spec: &'a ChainSpec,
) -> impl Iterator<Item = AttMaxCover<'a, E>> + Send {
all_attestations
Expand All @@ -252,8 +252,8 @@ impl<E: EthSpec> OperationPool<E> {
pub fn get_attestations(
&self,
state: &BeaconState<E>,
prev_epoch_validity_filter: impl for<'a> FnMut(&AttestationRef<'a, E>) -> bool + Send,
curr_epoch_validity_filter: impl for<'a> FnMut(&AttestationRef<'a, E>) -> bool + Send,
prev_epoch_validity_filter: impl for<'a> FnMut(&CompactAttestationRef<'a, E>) -> bool + Send,
curr_epoch_validity_filter: impl for<'a> FnMut(&CompactAttestationRef<'a, E>) -> bool + Send,
spec: &ChainSpec,
) -> Result<Vec<Attestation<E>>, OpPoolError> {
if !matches!(state, BeaconState::Base(_)) {
Expand Down
39 changes: 38 additions & 1 deletion consensus/types/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,32 @@ impl<'a, E: EthSpec> AttestationRef<'a, E> {
impl<E: EthSpec> AttestationElectra<E> {
/// Are the aggregation bitfields of these attestations disjoint?
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
self.aggregation_bits
if self
.committee_bits
.intersection(&other.committee_bits)
.is_zero()
{
if self
.aggregation_bits
.intersection(&other.aggregation_bits)
.is_zero()
{
return true;
} else {
for (index, committee_bit) in self.committee_bits.iter().enumerate() {
if committee_bit {
if let Ok(aggregation_bit) = self.aggregation_bits.get(index) {
if let Ok(other_aggregation_bit) = other.aggregation_bits.get(index) {
if aggregation_bit == other_aggregation_bit {
return false;
}
}
}
}
}
}
}
true
}

pub fn committee_index(&self) -> u64 {
Expand All @@ -247,7 +270,9 @@ impl<E: EthSpec> AttestationElectra<E> {
pub fn aggregate(&mut self, other: &Self) {
debug_assert_eq!(self.data, other.data);
debug_assert!(self.signers_disjoint_from(other));
// TODO(electra) add debug asset to check that committee bits are disjoint
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
self.committee_bits = self.committee_bits.union(&other.committee_bits);
self.signature.add_assign_aggregate(&other.signature);
}

Expand Down Expand Up @@ -364,6 +389,18 @@ impl<E: EthSpec> AttestationBase<E> {
Ok(())
}
}


pub fn extend_aggregation_bits(&self) -> Result<BitList<E::MaxValidatorsPerCommitteePerSlot>, ssz_types::Error>{
let mut extended_aggregation_bits: BitList<E::MaxValidatorsPerCommitteePerSlot> =
BitList::with_capacity(self.aggregation_bits.len())?;

for (i, bit) in self.aggregation_bits.iter().enumerate() {
extended_aggregation_bits
.set(i, bit)?;
}
Ok(extended_aggregation_bits)
}
}

impl<E: EthSpec> SlotData for Attestation<E> {
Expand Down

0 comments on commit 494d7ad

Please sign in to comment.