Attestation superstruct changes for EIP 7549 (#5644)

* update

* experiment

* superstruct changes

* revert

* superstruct changes

* fix tests

* indexed attestation

* indexed attestation superstruct

* updated TODOs
This commit is contained in:
Eitan Seri-Levi
2024-04-30 19:49:08 +03:00
committed by GitHub
parent 4a48d7b546
commit 3b7132bc0d
56 changed files with 943 additions and 429 deletions

View File

@@ -1,4 +1,4 @@
use crate::attestation_storage::AttestationRef;
use crate::attestation_storage::{AttestationRef, CompactIndexedAttestation};
use crate::max_cover::MaxCover;
use crate::reward_cache::RewardCache;
use state_processing::common::{
@@ -83,7 +83,7 @@ impl<'a, E: EthSpec> AttMaxCover<'a, E> {
let fresh_validators_rewards = att
.indexed
.attesting_indices
.attesting_indices()
.iter()
.filter_map(|&index| {
if reward_cache
@@ -175,7 +175,11 @@ pub fn earliest_attestation_validators<E: EthSpec>(
base_state: &BeaconStateBase<E>,
) -> BitList<E::MaxValidatorsPerCommittee> {
// Bitfield of validators whose attestations are new/fresh.
let mut new_validators = attestation.indexed.aggregation_bits.clone();
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!(),
};
let state_attestations = if attestation.checkpoint.target_epoch == state.current_epoch() {
&base_state.current_epoch_attestations

View File

@@ -2,8 +2,8 @@ use crate::AttestationStats;
use itertools::Itertools;
use std::collections::HashMap;
use types::{
AggregateSignature, Attestation, AttestationData, BeaconState, BitList, Checkpoint, Epoch,
EthSpec, Hash256, Slot,
attestation::{AttestationBase, AttestationElectra}, superstruct, AggregateSignature, Attestation, AttestationData,
BeaconState, BitList, BitVector, Checkpoint, Epoch, EthSpec, Hash256, Slot,
};
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
@@ -20,11 +20,18 @@ pub struct CompactAttestationData {
pub target_root: Hash256,
}
#[superstruct(variants(Base, Electra), variant_attributes(derive(Debug, PartialEq,)))]
#[derive(Debug, PartialEq)]
pub struct CompactIndexedAttestation<E: EthSpec> {
pub attesting_indices: Vec<u64>,
#[superstruct(only(Base), partial_getter(rename = "aggregation_bits_base"))]
pub aggregation_bits: BitList<E::MaxValidatorsPerCommittee>,
#[superstruct(only(Electra), partial_getter(rename = "aggregation_bits_electra"))]
pub aggregation_bits: BitList<E::MaxValidatorsPerCommitteePerSlot>,
pub signature: AggregateSignature,
pub index: u64,
#[superstruct(only(Electra))]
pub committee_bits: BitVector<E::MaxCommitteesPerSlot>,
}
#[derive(Debug)]
@@ -54,20 +61,29 @@ pub struct AttestationDataMap<E: EthSpec> {
impl<E: EthSpec> SplitAttestation<E> {
pub fn new(attestation: Attestation<E>, attesting_indices: Vec<u64>) -> Self {
let checkpoint = CheckpointKey {
source: attestation.data.source,
target_epoch: attestation.data.target.epoch,
source: attestation.data().source,
target_epoch: attestation.data().target.epoch,
};
let data = CompactAttestationData {
slot: attestation.data.slot,
index: attestation.data.index,
beacon_block_root: attestation.data.beacon_block_root,
target_root: attestation.data.target.root,
slot: attestation.data().slot,
index: attestation.data().index,
beacon_block_root: attestation.data().beacon_block_root,
target_root: attestation.data().target.root,
};
let indexed = CompactIndexedAttestation {
attesting_indices,
aggregation_bits: attestation.aggregation_bits,
signature: attestation.signature,
let indexed = match attestation.clone() {
Attestation::Base(attn) => {
CompactIndexedAttestation::Base(CompactIndexedAttestationBase {
attesting_indices,
aggregation_bits: attn.aggregation_bits,
signature: attestation.signature().clone(),
index: data.index,
})
}
// TODO(electra) implement electra variant
Attestation::Electra(_) => todo!(),
};
Self {
checkpoint,
data,
@@ -99,10 +115,18 @@ impl<'a, E: EthSpec> AttestationRef<'a, E> {
}
pub fn clone_as_attestation(&self) -> Attestation<E> {
Attestation {
aggregation_bits: self.indexed.aggregation_bits.clone(),
data: self.attestation_data(),
signature: self.indexed.signature.clone(),
match self.indexed {
CompactIndexedAttestation::Base(indexed_att) => Attestation::Base(AttestationBase {
aggregation_bits: indexed_att.aggregation_bits.clone(),
data: self.attestation_data(),
signature: indexed_att.signature.clone(),
}),
CompactIndexedAttestation::Electra(indexed_att) => Attestation::Electra(AttestationElectra {
aggregation_bits: indexed_att.aggregation_bits.clone(),
data: self.attestation_data(),
signature: indexed_att.signature.clone(),
committee_bits: indexed_att.committee_bits.clone(),
}),
}
}
}
@@ -125,6 +149,34 @@ impl CheckpointKey {
}
impl<E: EthSpec> CompactIndexedAttestation<E> {
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
match (self, other) {
(CompactIndexedAttestation::Base(this), CompactIndexedAttestation::Base(other)) => {
this.signers_disjoint_from(other)
}
(CompactIndexedAttestation::Electra(_), CompactIndexedAttestation::Electra(_)) => {
todo!()
}
// 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) {
match (self, other) {
(CompactIndexedAttestation::Base(this), CompactIndexedAttestation::Base(other)) => {
this.aggregate(other)
}
(CompactIndexedAttestation::Electra(_), CompactIndexedAttestation::Electra(_)) => {
todo!()
}
// TODO(electra) is a mix of electra and base compact indexed attestations an edge case we need to deal with?
_ => (),
}
}
}
impl<E: EthSpec> CompactIndexedAttestationBase<E> {
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
self.aggregation_bits
.intersection(&other.aggregation_bits)

View File

@@ -913,7 +913,7 @@ mod release_tests {
let att2_split = SplitAttestation::new(att2.clone(), att2_indices);
assert_eq!(
att1.aggregation_bits.num_set_bits(),
att1.num_set_aggregation_bits(),
earliest_attestation_validators(
&att1_split.as_ref(),
&state,
@@ -927,8 +927,8 @@ mod release_tests {
.unwrap()
.current_epoch_attestations
.push(PendingAttestation {
aggregation_bits: att1.aggregation_bits.clone(),
data: att1.data.clone(),
aggregation_bits: att1.aggregation_bits_base().unwrap().clone(),
data: att1.data().clone(),
inclusion_delay: 0,
proposer_index: 0,
})
@@ -1007,7 +1007,7 @@ mod release_tests {
let agg_att = &block_attestations[0];
assert_eq!(
agg_att.aggregation_bits.num_set_bits(),
agg_att.num_set_aggregation_bits(),
spec.target_committee_size as usize
);
@@ -1243,7 +1243,7 @@ mod release_tests {
// All the best attestations should be signed by at least `big_step_size` (4) validators.
for att in &best_attestations {
assert!(att.aggregation_bits.num_set_bits() >= big_step_size);
assert!(att.num_set_aggregation_bits() >= big_step_size);
}
}

View File

@@ -76,7 +76,7 @@ impl<E: EthSpec> PersistedOperationPool<E> {
.map(|att| {
(
att.clone_as_attestation(),
att.indexed.attesting_indices.clone(),
att.indexed.attesting_indices().clone(),
)
})
.collect();