Optimise and refine SingleAttestation conversion (#6934)

Closes

- https://github.com/sigp/lighthouse/issues/6805


  - Use a new `WorkEvent::GossipAttestationToConvert` to handle the conversion from `SingleAttestation` to `Attestation` _on_ the beacon processor (prevents a Tokio thread being blocked).
- Improve the error handling for single attestations. I think previously we had no ability to reprocess single attestations for unknown blocks -- we would just error. This seemed to be the case in both gossip processing and processing of `SingleAttestation`s from the HTTP API.
- Move the `SingleAttestation -> Attestation` conversion function into `beacon_chain` so that it can return the `attestation_verification::Error` type, which has well-defined error handling and peer penalties. The now-unused variants of `types::Attestation::Error` have been removed.
This commit is contained in:
Michael Sproul
2025-02-08 10:18:57 +11:00
committed by GitHub
parent cb117f859d
commit 2bd5bbdffb
10 changed files with 379 additions and 145 deletions

View File

@@ -2,7 +2,6 @@ use crate::slot_data::SlotData;
use crate::{test_utils::TestRandom, Hash256, Slot};
use crate::{Checkpoint, ForkVersionDeserialize};
use derivative::Derivative;
use safe_arith::ArithError;
use serde::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use ssz_types::BitVector;
@@ -12,22 +11,17 @@ use test_random_derive::TestRandom;
use tree_hash_derive::TreeHash;
use super::{
AggregateSignature, AttestationData, BitList, ChainSpec, CommitteeIndex, Domain, EthSpec, Fork,
SecretKey, Signature, SignedRoot,
AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey,
Signature, SignedRoot,
};
#[derive(Debug, PartialEq)]
pub enum Error {
SszTypesError(ssz_types::Error),
AlreadySigned(usize),
SubnetCountIsZero(ArithError),
IncorrectStateVariant,
InvalidCommitteeLength,
InvalidCommitteeIndex,
AttesterNotInCommittee(u64),
InvalidCommittee,
MissingCommittee,
NoCommitteeForSlotAndIndex { slot: Slot, index: CommitteeIndex },
}
impl From<ssz_types::Error> for Error {
@@ -587,38 +581,6 @@ pub struct SingleAttestation {
pub signature: AggregateSignature,
}
impl SingleAttestation {
pub fn to_attestation<E: EthSpec>(&self, committee: &[usize]) -> Result<Attestation<E>, Error> {
let aggregation_bit = committee
.iter()
.enumerate()
.find_map(|(i, &validator_index)| {
if self.attester_index as usize == validator_index {
return Some(i);
}
None
})
.ok_or(Error::AttesterNotInCommittee(self.attester_index))?;
let mut committee_bits: BitVector<E::MaxCommitteesPerSlot> = BitVector::default();
committee_bits
.set(self.committee_index as usize, true)
.map_err(|_| Error::InvalidCommitteeIndex)?;
let mut aggregation_bits =
BitList::with_capacity(committee.len()).map_err(|_| Error::InvalidCommitteeLength)?;
aggregation_bits.set(aggregation_bit, true)?;
Ok(Attestation::Electra(AttestationElectra {
aggregation_bits,
committee_bits,
data: self.data.clone(),
signature: self.signature.clone(),
}))
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -1,7 +1,6 @@
use super::{AggregateSignature, EthSpec, SignedRoot};
use crate::slot_data::SlotData;
use crate::{test_utils::TestRandom, BitVector, Hash256, Slot, SyncCommitteeMessage};
use safe_arith::ArithError;
use serde::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
@@ -11,7 +10,6 @@ use tree_hash_derive::TreeHash;
pub enum Error {
SszTypesError(ssz_types::Error),
AlreadySigned(usize),
SubnetCountIsZero(ArithError),
}
/// An aggregation of `SyncCommitteeMessage`s, used in creating a `SignedContributionAndProof`.