Add post attestation v2 endpoint logic to attestation service

This commit is contained in:
Eitan Seri-Levi
2024-12-13 21:51:35 +07:00
parent 366bed3a41
commit 68292ad9dd
3 changed files with 134 additions and 73 deletions

View File

@@ -30,6 +30,7 @@ pub use reqwest::{StatusCode, Url};
pub use sensitive_url::{SensitiveError, SensitiveUrl};
use serde::{de::DeserializeOwned, Serialize};
use ssz::Encode;
use types::attestation::SingleAttestation;
use std::fmt;
use std::future::Future;
use std::path::PathBuf;
@@ -1316,7 +1317,7 @@ impl BeaconNodeHttpClient {
/// `POST v2/beacon/pool/attestations`
pub async fn post_beacon_pool_attestations_v2<E: EthSpec>(
&self,
attestations: &[Attestation<E>],
attestations: &[SingleAttestation],
fork_name: ForkName,
) -> Result<(), Error> {
let mut path = self.eth_path(V2)?;

View File

@@ -232,6 +232,13 @@ impl<E: EthSpec> Attestation<E> {
Attestation::Electra(att) => att.aggregation_bits.get(index),
}
}
pub fn to_single_attestation_with_attester_index(&self, attester_index: usize) -> Result<SingleAttestation, Error> {
match self {
Self::Base(_) => Err(Error::IncorrectStateVariant),
Self::Electra(attn) => attn.to_single_attestation_with_attester_index(attester_index)
}
}
}
impl<E: EthSpec> AttestationRef<'_, E> {
@@ -288,6 +295,14 @@ impl<E: EthSpec> AttestationElectra<E> {
self.get_committee_indices().first().cloned()
}
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 get_committee_indices(&self) -> Vec<u64> {
self.committee_bits
.iter()
@@ -352,12 +367,26 @@ impl<E: EthSpec> AttestationElectra<E> {
}
}
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_with_attester_index(
&self,
attester_index: usize
) -> Result<SingleAttestation, Error> {
let committee_indices = self.get_committee_indices();
if committee_indices.len() != 1 {
return Err(Error::InvalidCommitteeLength);
}
let committee_index = *committee_indices
.first()
.ok_or(Error::InvalidCommitteeIndex)?;
Ok(SingleAttestation {
committee_index: committee_index as usize,
attester_index,
data: self.data.clone(),
signature: self.signature.clone()
})
}
pub fn to_single_attestation(
@@ -493,71 +522,6 @@ 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> {
@@ -657,6 +621,99 @@ impl<E: EthSpec> ForkVersionDeserialize for Vec<Attestation<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 {
/// Produces a `SingleAttestation` with empty signature and empty attester index.
/// ONLY USE IN ELECTRA
pub fn empty_for_signing(
committee_index: usize,
slot: Slot,
beacon_block_root: Hash256,
source: Checkpoint,
target: Checkpoint,
) -> Self {
Self {
committee_index,
attester_index: 0,
data: AttestationData {
slot,
index: 0,
beacon_block_root,
source,
target,
},
signature: AggregateSignature::infinity(),
}
}
pub fn add_signature(&mut self, signature: &AggregateSignature, committee_position: usize) {
self.attester_index = committee_position;
self.signature = signature.clone();
}
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(),
}))
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -457,8 +457,11 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
&[validator_metrics::ATTESTATIONS_HTTP_POST],
);
if fork_name.electra_enabled() {
let single_attestations = attestations.iter().zip(validator_indices).filter_map(|(a, i)| {
a.to_single_attestation_with_attester_index(*i as usize).ok()
}).collect::<Vec<_>>();
beacon_node
.post_beacon_pool_attestations_v2(attestations, fork_name)
.post_beacon_pool_attestations_v2::<E>(&single_attestations, fork_name)
.await
} else {
beacon_node