Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Electra attestation changes sean review #5972

32 changes: 5 additions & 27 deletions beacon_node/beacon_chain/src/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,9 @@ use std::borrow::Cow;
use strum::AsRefStr;
use tree_hash::TreeHash;
use types::{
Attestation, AttestationRef, BeaconCommittee,
BeaconStateError::{self, NoCommitteeFound},
ChainSpec, CommitteeIndex, Epoch, EthSpec, ForkName, Hash256, IndexedAttestation,
SelectionProof, SignedAggregateAndProof, Slot, SubnetId,
Attestation, AttestationRef, BeaconCommittee, BeaconStateError::NoCommitteeFound, ChainSpec,
CommitteeIndex, Epoch, EthSpec, Hash256, IndexedAttestation, SelectionProof,
SignedAggregateAndProof, Slot, SubnetId,
};

pub use batch::{batch_verify_aggregated_attestations, batch_verify_unaggregated_attestations};
Expand Down Expand Up @@ -266,30 +265,9 @@ pub enum Error {
BeaconChainError(BeaconChainError),
}

// TODO(electra) the error conversion changes here are to get a test case to pass
// this could easily be cleaned up
impl From<BeaconChainError> for Error {
fn from(e: BeaconChainError) -> Self {
match &e {
BeaconChainError::BeaconStateError(beacon_state_error) => {
if let BeaconStateError::AggregatorNotInCommittee { aggregator_index } =
beacon_state_error
{
Self::AggregatorNotInCommittee {
aggregator_index: *aggregator_index,
}
} else if let BeaconStateError::InvalidSelectionProof { aggregator_index } =
beacon_state_error
{
Self::InvalidSelectionProof {
aggregator_index: *aggregator_index,
}
} else {
Error::BeaconChainError(e)
}
}
_ => Error::BeaconChainError(e),
}
Self::BeaconChainError(e)
}
}

Expand Down Expand Up @@ -1169,7 +1147,7 @@ pub fn verify_propagation_slot_range<S: SlotClock, E: EthSpec>(

let current_fork =
spec.fork_name_at_slot::<E>(slot_clock.now().ok_or(BeaconChainError::UnableToReadSlot)?);
let earliest_permissible_slot = if current_fork < ForkName::Deneb {
let earliest_permissible_slot = if !current_fork.deneb_enabled() {
one_epoch_prior
// EIP-7045
} else {
Expand Down
4 changes: 2 additions & 2 deletions beacon_node/operation_pool/src/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,8 @@ pub fn earliest_attestation_validators<E: EthSpec>(
// Bitfield of validators whose attestations are new/fresh.
let mut new_validators = match attestation.indexed {
CompactIndexedAttestation::Base(indexed_att) => indexed_att.aggregation_bits.clone(),
// TODO(electra) per the comments above, this code path is obsolete post altair fork, so maybe we should just return an empty bitlist here?
CompactIndexedAttestation::Electra(_) => todo!(),
// This code path is obsolete post altair fork, so we just return an empty bitlist here.
CompactIndexedAttestation::Electra(_) => return BitList::with_capacity(0).unwrap(),
};

let state_attestations = if attestation.checkpoint.target_epoch == state.current_epoch() {
Expand Down
24 changes: 11 additions & 13 deletions beacon_node/operation_pool/src/attestation_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,22 +165,22 @@ impl<E: EthSpec> CompactIndexedAttestation<E> {
CompactIndexedAttestation::Electra(this),
CompactIndexedAttestation::Electra(other),
) => this.should_aggregate(other),
// TODO(electra) is a mix of electra and base compact indexed attestations an edge case we need to deal with?
_ => false,
}
}

pub fn aggregate(&mut self, other: &Self) -> Option<()> {
/// Returns `true` if aggregated, otherwise `false`.
pub fn aggregate(&mut self, other: &Self) -> bool {
match (self, other) {
(CompactIndexedAttestation::Base(this), CompactIndexedAttestation::Base(other)) => {
this.aggregate(other)
this.aggregate(other);
true
}
(
CompactIndexedAttestation::Electra(this),
CompactIndexedAttestation::Electra(other),
) => this.aggregate_same_committee(other),
// TODO(electra) is a mix of electra and base compact indexed attestations an edge case we need to deal with?
_ => None,
_ => false,
}
}
}
Expand All @@ -192,7 +192,7 @@ impl<E: EthSpec> CompactIndexedAttestationBase<E> {
.is_zero()
}

pub fn aggregate(&mut self, other: &Self) -> Option<()> {
pub fn aggregate(&mut self, other: &Self) {
self.attesting_indices = self
.attesting_indices
.drain(..)
Expand All @@ -201,8 +201,6 @@ impl<E: EthSpec> CompactIndexedAttestationBase<E> {
.collect();
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
self.signature.add_assign_aggregate(&other.signature);

Some(())
}
}

Expand All @@ -216,9 +214,10 @@ impl<E: EthSpec> CompactIndexedAttestationElectra<E> {
.is_zero()
}

pub fn aggregate_same_committee(&mut self, other: &Self) -> Option<()> {
/// Returns `true` if aggregated, otherwise `false`.
pub fn aggregate_same_committee(&mut self, other: &Self) -> bool {
if self.committee_bits != other.committee_bits {
return None;
return false;
}
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
self.attesting_indices = self
Expand All @@ -228,7 +227,7 @@ impl<E: EthSpec> CompactIndexedAttestationElectra<E> {
.dedup()
.collect();
self.signature.add_assign_aggregate(&other.signature);
Some(())
true
}

pub fn aggregate_with_disjoint_committees(&mut self, other: &Self) -> Option<()> {
Expand Down Expand Up @@ -318,8 +317,7 @@ impl<E: EthSpec> AttestationMap<E> {

for existing_attestation in attestations.iter_mut() {
if existing_attestation.should_aggregate(&indexed) {
existing_attestation.aggregate(&indexed);
aggregated = true;
aggregated = existing_attestation.aggregate(&indexed);
} else if *existing_attestation == indexed {
aggregated = true;
}
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 @@ -39,7 +39,7 @@ use std::ptr;
use types::{
sync_aggregate::Error as SyncAggregateError, typenum::Unsigned, AbstractExecPayload,
Attestation, AttestationData, AttesterSlashing, BeaconState, BeaconStateError, ChainSpec,
Epoch, EthSpec, ForkName, ProposerSlashing, SignedBeaconBlock, SignedBlsToExecutionChange,
Epoch, EthSpec, ProposerSlashing, SignedBeaconBlock, SignedBlsToExecutionChange,
SignedVoluntaryExit, Slot, SyncAggregate, SyncCommitteeContribution, Validator,
};

Expand Down Expand Up @@ -316,10 +316,10 @@ impl<E: EthSpec> OperationPool<E> {
)
.inspect(|_| num_curr_valid += 1);

let curr_epoch_limit = if fork_name < ForkName::Electra {
E::MaxAttestations::to_usize()
} else {
let curr_epoch_limit = if fork_name.electra_enabled() {
E::MaxAttestationsElectra::to_usize()
} else {
E::MaxAttestations::to_usize()
};
let prev_epoch_limit = if let BeaconState::Base(base_state) = state {
std::cmp::min(
Expand Down
1 change: 0 additions & 1 deletion consensus/state_processing/src/verify_operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ pub trait TransformPersist {
pub struct SigVerifiedOp<T: TransformPersist, E: EthSpec> {
op: T,
verified_against: VerifiedAgainst,
//#[ssz(skip_serializing, skip_deserializing)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am surprised this works.

_phantom: PhantomData<E>,
}

Expand Down
19 changes: 9 additions & 10 deletions consensus/types/src/aggregate_and_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ use tree_hash_derive::TreeHash;
derive(Debug, PartialEq, TreeHash, Serialize,),
serde(untagged, bound = "E: EthSpec"),
tree_hash(enum_behaviour = "transparent")
)
),
map_ref_into(AttestationRef)
)]
#[derive(
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
Expand All @@ -59,19 +60,17 @@ pub struct AggregateAndProof<E: EthSpec> {
impl<'a, E: EthSpec> AggregateAndProofRef<'a, E> {
/// Returns `true` if `validator_pubkey` signed over `self.aggregate.data.slot`.
pub fn aggregate(self) -> AttestationRef<'a, E> {
match self {
AggregateAndProofRef::Base(a) => AttestationRef::Base(&a.aggregate),
AggregateAndProofRef::Electra(a) => AttestationRef::Electra(&a.aggregate),
}
map_aggregate_and_proof_ref_into_attestation_ref!(&'a _, self, |inner, cons| {
cons(&inner.aggregate)
})
}
}
impl<E: EthSpec> AggregateAndProof<E> {
/// Returns `true` if `validator_pubkey` signed over `self.aggregate.data.slot`.
pub fn aggregate(&self) -> AttestationRef<E> {
match self {
AggregateAndProof::Base(a) => AttestationRef::Base(&a.aggregate),
AggregateAndProof::Electra(a) => AttestationRef::Electra(&a.aggregate),
}
pub fn aggregate<'a>(&'a self) -> AttestationRef<'a, E> {
map_aggregate_and_proof_ref_into_attestation_ref!(&'a _, self.to_ref(), |inner, cons| {
cons(&inner.aggregate)
})
}
}

Expand Down
23 changes: 2 additions & 21 deletions consensus/types/src/attestation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::slot_data::SlotData;
use crate::Checkpoint;
use crate::{test_utils::TestRandom, Hash256, Slot};
use crate::{Checkpoint, ForkName};
use derivative::Derivative;
use safe_arith::ArithError;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -99,7 +99,7 @@ impl<E: EthSpec> Attestation<E> {
target: Checkpoint,
spec: &ChainSpec,
) -> Result<Self, Error> {
if spec.fork_name_at_slot::<E>(slot) >= ForkName::Electra {
if spec.fork_name_at_slot::<E>(slot).electra_enabled() {
let mut committee_bits: BitVector<E::MaxCommitteesPerSlot> = BitVector::default();
committee_bits
.set(committee_index as usize, true)
Expand Down Expand Up @@ -277,16 +277,6 @@ impl<'a, E: EthSpec> AttestationRef<'a, E> {
}

impl<E: EthSpec> AttestationElectra<E> {
/// Are the aggregation bitfields of these attestations disjoint?
// TODO(electra): check whether the definition from CompactIndexedAttestation::should_aggregate
// is useful where this is used, i.e. only consider attestations disjoint when their committees
// match AND their aggregation bits do not intersect.
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
self.aggregation_bits
.intersection(&other.aggregation_bits)
.is_zero()
}

pub fn committee_index(&self) -> Option<u64> {
self.get_committee_indices().first().cloned()
}
Expand All @@ -304,7 +294,6 @@ impl<E: EthSpec> AttestationElectra<E> {
/// The aggregation bitfields must be disjoint, and the data must be the same.
pub fn aggregate(&mut self, other: &Self) {
debug_assert_eq!(self.data, other.data);
debug_assert!(self.signers_disjoint_from(other));
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
self.signature.add_assign_aggregate(&other.signature);
}
Expand Down Expand Up @@ -358,19 +347,11 @@ impl<E: EthSpec> AttestationElectra<E> {
}

impl<E: EthSpec> AttestationBase<E> {
/// Are the aggregation bitfields of these attestations disjoint?
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
self.aggregation_bits
.intersection(&other.aggregation_bits)
.is_zero()
}

/// Aggregate another Attestation into this one.
///
/// The aggregation bitfields must be disjoint, and the data must be the same.
pub fn aggregate(&mut self, other: &Self) {
debug_assert_eq!(self.data, other.data);
debug_assert!(self.signers_disjoint_from(other));
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
self.signature.add_assign_aggregate(&other.signature);
}
Expand Down
4 changes: 4 additions & 0 deletions consensus/types/src/fork_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ impl ForkName {
}
}

pub fn deneb_enabled(self) -> bool {
self >= ForkName::Deneb
}

pub fn electra_enabled(self) -> bool {
self >= ForkName::Electra
}
Expand Down
24 changes: 12 additions & 12 deletions consensus/types/src/signed_aggregate_and_proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ use tree_hash_derive::TreeHash;
),
serde(bound = "E: EthSpec"),
arbitrary(bound = "E: EthSpec"),
)
),
map_into(Attestation),
map_ref_into(AggregateAndProofRef)
)]
#[derive(
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
Expand Down Expand Up @@ -102,19 +104,17 @@ impl<E: EthSpec> SignedAggregateAndProof<E> {
}
}

pub fn message(&self) -> AggregateAndProofRef<E> {
match self {
SignedAggregateAndProof::Base(message) => AggregateAndProofRef::Base(&message.message),
SignedAggregateAndProof::Electra(message) => {
AggregateAndProofRef::Electra(&message.message)
}
}
pub fn message<'a>(&'a self) -> AggregateAndProofRef<'a, E> {
map_signed_aggregate_and_proof_ref_into_aggregate_and_proof_ref!(
&'a _,
self.to_ref(),
|inner, cons| { cons(&inner.message) }
)
}

pub fn into_attestation(self) -> Attestation<E> {
match self {
Self::Base(att) => Attestation::Base(att.message.aggregate),
Self::Electra(att) => Attestation::Electra(att.message.aggregate),
}
map_signed_aggregate_and_proof_into_attestation!(self, |inner, cons| {
cons(inner.message.aggregate)
})
}
}
8 changes: 0 additions & 8 deletions consensus/types/src/sync_committee_contribution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,13 @@ impl<E: EthSpec> SyncCommitteeContribution<E> {
})
}

/// Are the aggregation bitfields of these sync contribution disjoint?
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
self.aggregation_bits
.intersection(&other.aggregation_bits)
.is_zero()
}

/// Aggregate another `SyncCommitteeContribution` into this one.
///
/// The aggregation bitfields must be disjoint, and the data must be the same.
pub fn aggregate(&mut self, other: &Self) {
debug_assert_eq!(self.slot, other.slot);
debug_assert_eq!(self.beacon_block_root, other.beacon_block_root);
debug_assert_eq!(self.subcommittee_index, other.subcommittee_index);
debug_assert!(self.signers_disjoint_from(other));

self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
self.signature.add_assign_aggregate(&other.signature);
Expand Down
4 changes: 3 additions & 1 deletion testing/ef_tests/check_all_files_accessed.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@
"bls12-381-tests/deserialization_G2",
"bls12-381-tests/hash_to_G2",
"tests/.*/eip6110",
"tests/.*/whisk"
"tests/.*/whisk",
# TODO(electra): re-enable in https://github.com/sigp/lighthouse/pull/5758
"tests/.*/.*/ssz_static/IndexedAttestation"
]


Expand Down
4 changes: 4 additions & 0 deletions testing/ef_tests/src/type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type_name_generic!(AggregateAndProof);
type_name_generic!(AggregateAndProofBase, "AggregateAndProof");
type_name_generic!(AggregateAndProofElectra, "AggregateAndProof");
type_name_generic!(Attestation);
type_name_generic!(AttestationBase, "Attestation");
type_name_generic!(AttestationElectra, "Attestation");
type_name!(AttestationData);
type_name_generic!(AttesterSlashing);
type_name_generic!(AttesterSlashingBase, "AttesterSlashing");
Expand Down Expand Up @@ -76,6 +78,8 @@ type_name!(Fork);
type_name!(ForkData);
type_name_generic!(HistoricalBatch);
type_name_generic!(IndexedAttestation);
type_name_generic!(IndexedAttestationBase, "IndexedAttestation");
type_name_generic!(IndexedAttestationElectra, "IndexedAttestation");
type_name_generic!(LightClientBootstrap);
type_name_generic!(LightClientBootstrapAltair, "LightClientBootstrap");
type_name_generic!(LightClientBootstrapCapella, "LightClientBootstrap");
Expand Down
1 change: 0 additions & 1 deletion testing/ef_tests/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,6 @@ mod ssz_static {
ssz_static_test!(fork, Fork);
ssz_static_test!(fork_data, ForkData);
ssz_static_test!(historical_batch, HistoricalBatch<_>);
ssz_static_test!(indexed_attestation, IndexedAttestation<_>);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can't generate these tests with superstructed objects, but the full test implementation is included in #5758

ssz_static_test!(pending_attestation, PendingAttestation<_>);
ssz_static_test!(proposer_slashing, ProposerSlashing);
ssz_static_test!(
Expand Down
Loading