Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 57 additions & 10 deletions beacon_node/beacon_chain/src/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ use tracing::{debug, error};
use tree_hash::TreeHash;
use types::{
Attestation, AttestationData, AttestationRef, BeaconCommittee,
BeaconStateError::NoCommitteeFound, ChainSpec, CommitteeIndex, Epoch, EthSpec, Hash256,
IndexedAttestation, SelectionProof, SignedAggregateAndProof, SingleAttestation, Slot, SubnetId,
BeaconStateError::NoCommitteeFound, ChainSpec, CommitteeIndex, Epoch, EthSpec, ForkName,
Hash256, IndexedAttestation, SelectionProof, SignedAggregateAndProof, SingleAttestation, Slot,
SubnetId,
};

pub use batch::{batch_verify_aggregated_attestations, batch_verify_unaggregated_attestations};
Expand Down Expand Up @@ -160,6 +161,12 @@ pub enum Error {
///
/// The peer has sent an invalid message.
CommitteeIndexNonZero(usize),
/// The validator index is set to an invalid value after Gloas.
///
/// ## Peer scoring
///
/// The peer has sent an invalid message.
CommitteeIndexInvalid,
/// The `attestation.data.beacon_block_root` block is unknown.
///
/// ## Peer scoring
Expand Down Expand Up @@ -551,7 +558,10 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
.tree_hash_root();

// [New in Electra:EIP7549]
verify_committee_index(attestation)?;
let fork_name = chain
.spec
.fork_name_at_slot::<T::EthSpec>(attestation.data().slot);
verify_committee_index(attestation, fork_name)?;

if chain
.observed_attestations
Expand Down Expand Up @@ -595,6 +605,17 @@ impl<'a, T: BeaconChainTypes> IndexedAggregatedAttestation<'a, T> {
// attestation and do not delay consideration for later.
let head_block = verify_head_block_is_known(chain, attestation.data(), None)?;

// [New in Gloas]: If the attested block is from the same slot as the attestation,
// index must be 0.
if fork_name.gloas_enabled()
&& head_block.slot == attestation.data().slot
&& attestation.data().index != 0
{
return Err(Error::CommitteeIndexNonZero(
attestation.data().index as usize,
));
}

// Check the attestation target root is consistent with the head root.
//
// This check is not in the specification, however we guard against it since it opens us up
Expand Down Expand Up @@ -871,7 +892,12 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {
let fork_name = chain
.spec
.fork_name_at_slot::<T::EthSpec>(attestation.data.slot);
if fork_name.electra_enabled() {
if fork_name.gloas_enabled() {
// [New in Gloas]
if attestation.data.index >= 2 {
return Err(Error::CommitteeIndexInvalid);
}
} else if fork_name.electra_enabled() {
// [New in Electra:EIP7549]
if attestation.data.index != 0 {
return Err(Error::CommitteeIndexNonZero(
Expand All @@ -890,6 +916,17 @@ impl<'a, T: BeaconChainTypes> IndexedUnaggregatedAttestation<'a, T> {
chain.config.import_max_skip_slots,
)?;

// [New in Gloas]: If the attested block is from the same slot as the attestation,
// index must be 0.
if fork_name.gloas_enabled()
&& head_block.slot == attestation.data.slot
&& attestation.data.index != 0
{
return Err(Error::CommitteeIndexNonZero(
attestation.data.index as usize,
));
}

// Check the attestation target root is consistent with the head root.
verify_attestation_target_root::<T::EthSpec>(&head_block, &attestation.data)?;

Expand Down Expand Up @@ -1404,7 +1441,10 @@ pub fn verify_signed_aggregate_signatures<T: BeaconChainTypes>(

/// Verify that the `attestation` committee index is properly set for the attestation's fork.
/// This function will only apply verification post-Electra.
pub fn verify_committee_index<E: EthSpec>(attestation: AttestationRef<E>) -> Result<(), Error> {
pub fn verify_committee_index<E: EthSpec>(
attestation: AttestationRef<E>,
fork_name: ForkName,
) -> Result<(), Error> {
if let Ok(committee_bits) = attestation.committee_bits() {
// Check to ensure that the attestation is for a single committee.
let num_committee_bits = get_committee_indices::<E>(committee_bits);
Expand All @@ -1414,11 +1454,18 @@ pub fn verify_committee_index<E: EthSpec>(attestation: AttestationRef<E>) -> Res
));
}

// Ensure the attestation index is set to zero post Electra.
if attestation.data().index != 0 {
return Err(Error::CommitteeIndexNonZero(
attestation.data().index as usize,
));
// Ensure the attestation index is valid for the fork.
let index = attestation.data().index;
if fork_name.gloas_enabled() {
// [New in Gloas]: index must be < 2.
if index >= 2 {
return Err(Error::CommitteeIndexInvalid);
}
} else {
// [New in Electra:EIP7549]: index must be 0.
if index != 0 {
return Err(Error::CommitteeIndexNonZero(index as usize));
}
}
}
Ok(())
Expand Down
Loading