SingleAttestation

This commit is contained in:
Eitan Seri-Levi
2024-12-04 15:53:04 +07:00
parent fec502db9f
commit 366bed3a41
10 changed files with 360 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
use crate::slot_data::SlotData;
use crate::{test_utils::TestRandom, Hash256, Slot};
use crate::{Checkpoint, ForkVersionDeserialize};
use crate::{BeaconCommittee, Checkpoint, ForkVersionDeserialize};
use derivative::Derivative;
use safe_arith::ArithError;
use serde::{Deserialize, Serialize};
@@ -24,6 +24,7 @@ pub enum Error {
IncorrectStateVariant,
InvalidCommitteeLength,
InvalidCommitteeIndex,
InvalidAggregationBit,
}
impl From<ssz_types::Error> for Error {
@@ -350,6 +351,70 @@ impl<E: EthSpec> AttestationElectra<E> {
Ok(())
}
}
pub fn get_aggregation_bits(&self) -> Vec<u64> {
self.aggregation_bits
.iter()
.enumerate()
.filter_map(|(index, bit)| if bit { Some(index as u64) } else { None })
.collect()
}
pub fn to_single_attestation(
&self,
committees: &[BeaconCommittee],
) -> Result<SingleAttestation, Error> {
let committee_indices = self.get_committee_indices();
if committee_indices.len() != 1 {
return Err(Error::InvalidCommitteeLength);
}
let aggregation_bits = self.get_aggregation_bits();
if aggregation_bits.len() != 1 {
return Err(Error::InvalidAggregationBit);
}
let committee_index = *committee_indices
.first()
.ok_or(Error::InvalidCommitteeIndex)?;
let aggregation_bit = *aggregation_bits
.first()
.ok_or(Error::InvalidAggregationBit)?;
let beacon_committee = committees
.get(committee_index as usize)
.ok_or(Error::InvalidCommitteeIndex)?;
let attester_indices = beacon_committee
.committee
.iter()
.enumerate()
.filter_map(|(i, &index)| {
if aggregation_bit as usize == i {
return Some(index);
}
None
})
.collect::<Vec<_>>();
if attester_indices.len() != 1 {
return Err(Error::InvalidAggregationBit);
};
let attester_index = *attester_indices
.first()
.ok_or(Error::InvalidAggregationBit)?;
Ok(SingleAttestation {
committee_index: committee_index as usize,
attester_index,
data: self.data.clone(),
signature: self.signature.clone(),
})
}
}
impl<E: EthSpec> AttestationBase<E> {
@@ -428,6 +493,71 @@ impl<E: EthSpec> SlotData for AttestationRef<'_, E> {
}
}
#[derive(
Debug,
Clone,
Serialize,
Deserialize,
Decode,
Encode,
TestRandom,
Derivative,
arbitrary::Arbitrary,
TreeHash,
PartialEq,
)]
pub struct SingleAttestation {
pub committee_index: usize,
pub attester_index: usize,
pub data: AttestationData,
pub signature: AggregateSignature,
}
impl SingleAttestation {
pub fn to_attestation<E: EthSpec>(
&self,
committees: &[BeaconCommittee],
) -> Result<Attestation<E>, Error> {
let beacon_committee = committees
.get(self.committee_index)
.ok_or(Error::InvalidAggregationBit)?;
let aggregation_bits = beacon_committee
.committee
.iter()
.enumerate()
.filter_map(|(i, &validator_index)| {
if self.attester_index == validator_index {
return Some(i);
}
None
})
.collect::<Vec<_>>();
if aggregation_bits.len() != 1 {
return Err(Error::InvalidAggregationBit);
}
let aggregation_bit = aggregation_bits.first().unwrap();
let mut committee_bits: BitVector<E::MaxCommitteesPerSlot> = BitVector::default();
committee_bits
.set(self.committee_index, true)
.map_err(|_| Error::InvalidCommitteeIndex)?;
let mut aggregation_bits = BitList::with_capacity(beacon_committee.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(),
}))
}
}
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
#[ssz(enum_behaviour = "union")]
pub enum AttestationOnDisk<E: EthSpec> {