mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-19 12:56:12 +00:00
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:
@@ -53,7 +53,7 @@ impl<E: EthSpec> AggregateAndProof<E> {
|
||||
let selection_proof = selection_proof
|
||||
.unwrap_or_else(|| {
|
||||
SelectionProof::new::<E>(
|
||||
aggregate.data.slot,
|
||||
aggregate.data().slot,
|
||||
secret_key,
|
||||
fork,
|
||||
genesis_validators_root,
|
||||
@@ -77,14 +77,14 @@ impl<E: EthSpec> AggregateAndProof<E> {
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> bool {
|
||||
let target_epoch = self.aggregate.data.slot.epoch(E::slots_per_epoch());
|
||||
let target_epoch = self.aggregate.data().slot.epoch(E::slots_per_epoch());
|
||||
let domain = spec.get_domain(
|
||||
target_epoch,
|
||||
Domain::SelectionProof,
|
||||
fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = self.aggregate.data.slot.signing_root(domain);
|
||||
let message = self.aggregate.data().slot.signing_root(domain);
|
||||
self.selection_proof.verify(validator_pubkey, message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
use derivative::Derivative;
|
||||
use safe_arith::ArithError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::slot_data::SlotData;
|
||||
use crate::{test_utils::TestRandom, Hash256, Slot};
|
||||
use derivative::Derivative;
|
||||
use rand::RngCore;
|
||||
use safe_arith::ArithError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Decode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::BitVector;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use super::{
|
||||
AggregateSignature, AttestationData, BitList, ChainSpec, Domain, EthSpec, Fork, SecretKey,
|
||||
@@ -20,31 +24,273 @@ pub enum Error {
|
||||
SubnetCountIsZero(ArithError),
|
||||
}
|
||||
|
||||
/// Details an attestation that can be slashable.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[superstruct(
|
||||
variants(Base, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Decode,
|
||||
Encode,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
TreeHash,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
)
|
||||
)]
|
||||
#[derive(
|
||||
arbitrary::Arbitrary,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Encode,
|
||||
Derivative,
|
||||
Deserialize,
|
||||
arbitrary::Arbitrary,
|
||||
PartialEq,
|
||||
)]
|
||||
#[derivative(PartialEq, Hash(bound = "E: EthSpec"))]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[serde(untagged)]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
pub struct Attestation<E: EthSpec> {
|
||||
#[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 data: AttestationData,
|
||||
pub signature: AggregateSignature,
|
||||
#[superstruct(only(Electra))]
|
||||
pub committee_bits: BitVector<E::MaxCommitteesPerSlot>,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Decode for Attestation<E> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
|
||||
if let Ok(result) = AttestationBase::from_ssz_bytes(bytes) {
|
||||
return Ok(Attestation::Base(result));
|
||||
}
|
||||
|
||||
if let Ok(result) = AttestationElectra::from_ssz_bytes(bytes) {
|
||||
return Ok(Attestation::Electra(result));
|
||||
}
|
||||
|
||||
Err(ssz::DecodeError::BytesInvalid(String::from(
|
||||
"bytes not valid for any fork variant",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TestRandom for Attestation<E> {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
let aggregation_bits: BitList<E::MaxValidatorsPerCommittee> = BitList::random_for_test(rng);
|
||||
// let committee_bits: BitList<E::MaxCommitteesPerSlot> = BitList::random_for_test(rng);
|
||||
let data = AttestationData::random_for_test(rng);
|
||||
let signature = AggregateSignature::random_for_test(rng);
|
||||
|
||||
Self::Base(AttestationBase {
|
||||
aggregation_bits,
|
||||
// committee_bits,
|
||||
data,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Hash for Attestation<E> {
|
||||
fn hash<H>(&self, state: &mut H)
|
||||
where
|
||||
H: Hasher,
|
||||
{
|
||||
match self {
|
||||
Attestation::Base(att) => att.hash(state),
|
||||
Attestation::Electra(att) => att.hash(state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Attestation<E> {
|
||||
/// Aggregate another Attestation into this one.
|
||||
///
|
||||
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
||||
pub fn aggregate(&mut self, other: &Self) {
|
||||
match self {
|
||||
Attestation::Base(att) => {
|
||||
debug_assert!(other.as_base().is_ok());
|
||||
|
||||
if let Ok(other) = other.as_base() {
|
||||
att.aggregate(other)
|
||||
}
|
||||
}
|
||||
Attestation::Electra(att) => {
|
||||
debug_assert!(other.as_electra().is_ok());
|
||||
|
||||
if let Ok(other) = other.as_electra() {
|
||||
att.aggregate(other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Signs `self`, setting the `committee_position`'th bit of `aggregation_bits` to `true`.
|
||||
///
|
||||
/// Returns an `AlreadySigned` error if the `committee_position`'th bit is already `true`.
|
||||
pub fn sign(
|
||||
&mut self,
|
||||
secret_key: &SecretKey,
|
||||
committee_position: usize,
|
||||
fork: &Fork,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
match self {
|
||||
Attestation::Base(att) => att.sign(
|
||||
secret_key,
|
||||
committee_position,
|
||||
fork,
|
||||
genesis_validators_root,
|
||||
spec,
|
||||
),
|
||||
Attestation::Electra(att) => att.sign(
|
||||
secret_key,
|
||||
committee_position,
|
||||
fork,
|
||||
genesis_validators_root,
|
||||
spec,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an `AlreadySigned` error if the `committee_position`'th bit is already `true`.
|
||||
pub fn add_signature(
|
||||
&mut self,
|
||||
signature: &Signature,
|
||||
committee_position: usize,
|
||||
) -> Result<(), Error> {
|
||||
match self {
|
||||
Attestation::Base(att) => att.add_signature(signature, committee_position),
|
||||
Attestation::Electra(att) => att.add_signature(signature, committee_position),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn committee_index(&self) -> u64 {
|
||||
match self {
|
||||
Attestation::Base(att) => att.data.index,
|
||||
Attestation::Electra(att) => att.committee_index(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_aggregation_bits_zero(&self) -> bool {
|
||||
match self {
|
||||
Attestation::Base(att) => att.aggregation_bits.is_zero(),
|
||||
Attestation::Electra(att) => att.aggregation_bits.is_zero(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_set_aggregation_bits(&self) -> usize {
|
||||
match self {
|
||||
Attestation::Base(att) => att.aggregation_bits.num_set_bits(),
|
||||
Attestation::Electra(att) => att.aggregation_bits.num_set_bits(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_aggregation_bit(&self, index: usize) -> Result<bool, ssz_types::Error> {
|
||||
match self {
|
||||
Attestation::Base(att) => att.aggregation_bits.get(index),
|
||||
Attestation::Electra(att) => att.aggregation_bits.get(index),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AttestationElectra<E> {
|
||||
/// Are the aggregation bitfields of these attestations disjoint?
|
||||
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
|
||||
self.aggregation_bits
|
||||
.intersection(&other.aggregation_bits)
|
||||
.is_zero()
|
||||
}
|
||||
|
||||
pub fn committee_index(&self) -> u64 {
|
||||
*self.get_committee_indices().first().unwrap_or(&0u64)
|
||||
}
|
||||
|
||||
pub fn get_committee_indices(&self) -> Vec<u64> {
|
||||
self.committee_bits
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(index, bit)| if bit { Some(index as u64) } else { None })
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Aggregate another Attestation into this one.
|
||||
///
|
||||
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
||||
pub fn aggregate(&mut self, other: &Self) {
|
||||
debug_assert_eq!(self.data, other.data);
|
||||
debug_assert!(self.signers_disjoint_from(other));
|
||||
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
||||
self.signature.add_assign_aggregate(&other.signature);
|
||||
}
|
||||
|
||||
/// Signs `self`, setting the `committee_position`'th bit of `aggregation_bits` to `true`.
|
||||
///
|
||||
/// Returns an `AlreadySigned` error if the `committee_position`'th bit is already `true`.
|
||||
pub fn sign(
|
||||
&mut self,
|
||||
secret_key: &SecretKey,
|
||||
committee_position: usize,
|
||||
fork: &Fork,
|
||||
genesis_validators_root: Hash256,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
let domain = spec.get_domain(
|
||||
self.data.target.epoch,
|
||||
Domain::BeaconAttester,
|
||||
fork,
|
||||
genesis_validators_root,
|
||||
);
|
||||
let message = self.data.signing_root(domain);
|
||||
|
||||
self.add_signature(&secret_key.sign(message), committee_position)
|
||||
}
|
||||
|
||||
/// Adds `signature` to `self` and sets the `committee_position`'th bit of `aggregation_bits` to `true`.
|
||||
///
|
||||
/// Returns an `AlreadySigned` error if the `committee_position`'th bit is already `true`.
|
||||
pub fn add_signature(
|
||||
&mut self,
|
||||
signature: &Signature,
|
||||
committee_position: usize,
|
||||
) -> Result<(), Error> {
|
||||
if self
|
||||
.aggregation_bits
|
||||
.get(committee_position)
|
||||
.map_err(Error::SszTypesError)?
|
||||
{
|
||||
Err(Error::AlreadySigned(committee_position))
|
||||
} else {
|
||||
self.aggregation_bits
|
||||
.set(committee_position, true)
|
||||
.map_err(Error::SszTypesError)?;
|
||||
|
||||
self.signature.add_assign(signature);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AttestationBase<E> {
|
||||
/// Are the aggregation bitfields of these attestations disjoint?
|
||||
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
|
||||
self.aggregation_bits
|
||||
@@ -113,7 +359,7 @@ impl<E: EthSpec> Attestation<E> {
|
||||
|
||||
impl<E: EthSpec> SlotData for Attestation<E> {
|
||||
fn get_slot(&self) -> Slot {
|
||||
self.data.slot
|
||||
self.data().slot
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::attestation::AttestationBase;
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::*;
|
||||
use derivative::Derivative;
|
||||
@@ -10,6 +11,8 @@ use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use self::indexed_attestation::IndexedAttestationBase;
|
||||
|
||||
/// A block of the `BeaconChain`.
|
||||
#[superstruct(
|
||||
variants(Base, Altair, Merge, Capella, Deneb, Electra),
|
||||
@@ -324,15 +327,16 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBase<E, Payload> {
|
||||
message: header,
|
||||
signature: Signature::empty(),
|
||||
};
|
||||
let indexed_attestation: IndexedAttestation<E> = IndexedAttestation {
|
||||
attesting_indices: VariableList::new(vec![
|
||||
0_u64;
|
||||
E::MaxValidatorsPerCommittee::to_usize()
|
||||
])
|
||||
.unwrap(),
|
||||
data: AttestationData::default(),
|
||||
signature: AggregateSignature::empty(),
|
||||
};
|
||||
let indexed_attestation: IndexedAttestation<E> =
|
||||
IndexedAttestation::Base(IndexedAttestationBase {
|
||||
attesting_indices: VariableList::new(vec![
|
||||
0_u64;
|
||||
E::MaxValidatorsPerCommittee::to_usize()
|
||||
])
|
||||
.unwrap(),
|
||||
data: AttestationData::default(),
|
||||
signature: AggregateSignature::empty(),
|
||||
});
|
||||
|
||||
let deposit_data = DepositData {
|
||||
pubkey: PublicKeyBytes::empty(),
|
||||
@@ -350,12 +354,12 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBase<E, Payload> {
|
||||
attestation_2: indexed_attestation,
|
||||
};
|
||||
|
||||
let attestation: Attestation<E> = Attestation {
|
||||
let attestation: Attestation<E> = Attestation::Base(AttestationBase {
|
||||
aggregation_bits: BitList::with_capacity(E::MaxValidatorsPerCommittee::to_usize())
|
||||
.unwrap(),
|
||||
data: AttestationData::default(),
|
||||
signature: AggregateSignature::empty(),
|
||||
};
|
||||
});
|
||||
|
||||
let deposit = Deposit {
|
||||
proof: FixedVector::from_elem(Hash256::zero()),
|
||||
|
||||
@@ -63,6 +63,8 @@ pub trait EthSpec:
|
||||
* Misc
|
||||
*/
|
||||
type MaxValidatorsPerCommittee: Unsigned + Clone + Sync + Send + Debug + PartialEq + Eq;
|
||||
type MaxValidatorsPerCommitteePerSlot: Unsigned + Clone + Sync + Send + Debug + PartialEq + Eq;
|
||||
type MaxCommitteesPerSlot: Unsigned + Clone + Sync + Send + Debug + PartialEq + Eq;
|
||||
/*
|
||||
* Time parameters
|
||||
*/
|
||||
@@ -349,6 +351,8 @@ impl EthSpec for MainnetEthSpec {
|
||||
type JustificationBitsLength = U4;
|
||||
type SubnetBitfieldLength = U64;
|
||||
type MaxValidatorsPerCommittee = U2048;
|
||||
type MaxCommitteesPerSlot = U64;
|
||||
type MaxValidatorsPerCommitteePerSlot = U131072;
|
||||
type GenesisEpoch = U0;
|
||||
type SlotsPerEpoch = U32;
|
||||
type EpochsPerEth1VotingPeriod = U64;
|
||||
@@ -424,6 +428,8 @@ impl EthSpec for MinimalEthSpec {
|
||||
SubnetBitfieldLength,
|
||||
SyncCommitteeSubnetCount,
|
||||
MaxValidatorsPerCommittee,
|
||||
MaxCommitteesPerSlot,
|
||||
MaxValidatorsPerCommitteePerSlot,
|
||||
GenesisEpoch,
|
||||
HistoricalRootsLimit,
|
||||
ValidatorRegistryLimit,
|
||||
@@ -468,6 +474,8 @@ impl EthSpec for GnosisEthSpec {
|
||||
type JustificationBitsLength = U4;
|
||||
type SubnetBitfieldLength = U64;
|
||||
type MaxValidatorsPerCommittee = U2048;
|
||||
type MaxCommitteesPerSlot = U64;
|
||||
type MaxValidatorsPerCommitteePerSlot = U131072;
|
||||
type GenesisEpoch = U0;
|
||||
type SlotsPerEpoch = U16;
|
||||
type EpochsPerEth1VotingPeriod = U64;
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
use crate::{test_utils::TestRandom, AggregateSignature, AttestationData, EthSpec, VariableList};
|
||||
use core::slice::Iter;
|
||||
use derivative::Derivative;
|
||||
use rand::RngCore;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Decode;
|
||||
use ssz::Encode;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
@@ -12,25 +16,50 @@ use tree_hash_derive::TreeHash;
|
||||
/// To be included in an `AttesterSlashing`.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
#[superstruct(
|
||||
variants(Base, Electra),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Decode,
|
||||
Encode,
|
||||
TestRandom,
|
||||
Derivative,
|
||||
arbitrary::Arbitrary,
|
||||
TreeHash,
|
||||
),
|
||||
derivative(PartialEq, Hash(bound = "E: EthSpec")),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
)
|
||||
)]
|
||||
#[derive(
|
||||
Derivative,
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Encode,
|
||||
Decode,
|
||||
TreeHash,
|
||||
TestRandom,
|
||||
Encode,
|
||||
Derivative,
|
||||
Deserialize,
|
||||
arbitrary::Arbitrary,
|
||||
PartialEq,
|
||||
)]
|
||||
#[derivative(PartialEq, Eq)] // to satisfy Clippy's lint about `Hash`
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[serde(untagged)]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
#[serde(bound = "E: EthSpec", deny_unknown_fields)]
|
||||
#[arbitrary(bound = "E: EthSpec")]
|
||||
pub struct IndexedAttestation<E: EthSpec> {
|
||||
/// Lists validator registry indices, not committee indices.
|
||||
#[superstruct(only(Base), partial_getter(rename = "attesting_indices_base"))]
|
||||
#[serde(with = "quoted_variable_list_u64")]
|
||||
pub attesting_indices: VariableList<u64, E::MaxValidatorsPerCommittee>,
|
||||
#[superstruct(only(Electra), partial_getter(rename = "attesting_indices_electra"))]
|
||||
#[serde(with = "quoted_variable_list_u64")]
|
||||
pub attesting_indices: VariableList<u64, E::MaxValidatorsPerCommitteePerSlot>,
|
||||
pub data: AttestationData,
|
||||
pub signature: AggregateSignature,
|
||||
}
|
||||
@@ -40,15 +69,84 @@ impl<E: EthSpec> IndexedAttestation<E> {
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
pub fn is_double_vote(&self, other: &Self) -> bool {
|
||||
self.data.target.epoch == other.data.target.epoch && self.data != other.data
|
||||
self.data().target.epoch == other.data().target.epoch && self.data() != other.data()
|
||||
}
|
||||
|
||||
/// Check if ``attestation_data_1`` surrounds ``attestation_data_2``.
|
||||
///
|
||||
/// Spec v0.12.1
|
||||
pub fn is_surround_vote(&self, other: &Self) -> bool {
|
||||
self.data.source.epoch < other.data.source.epoch
|
||||
&& other.data.target.epoch < self.data.target.epoch
|
||||
self.data().source.epoch < other.data().source.epoch
|
||||
&& other.data().target.epoch < self.data().target.epoch
|
||||
}
|
||||
|
||||
pub fn attesting_indices_len(&self) -> usize {
|
||||
match self {
|
||||
IndexedAttestation::Base(att) => att.attesting_indices.len(),
|
||||
IndexedAttestation::Electra(att) => att.attesting_indices.len(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attesting_indices_to_vec(&self) -> Vec<u64> {
|
||||
match self {
|
||||
IndexedAttestation::Base(att) => att.attesting_indices.to_vec(),
|
||||
IndexedAttestation::Electra(att) => att.attesting_indices.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attesting_indices_is_empty(&self) -> bool {
|
||||
match self {
|
||||
IndexedAttestation::Base(att) => att.attesting_indices.is_empty(),
|
||||
IndexedAttestation::Electra(att) => att.attesting_indices.is_empty(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attesting_indices_iter(&self) -> Iter<'_, u64> {
|
||||
match self {
|
||||
IndexedAttestation::Base(att) => att.attesting_indices.iter(),
|
||||
IndexedAttestation::Electra(att) => att.attesting_indices.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attesting_indices_first(&self) -> Option<&u64> {
|
||||
match self {
|
||||
IndexedAttestation::Base(att) => att.attesting_indices.first(),
|
||||
IndexedAttestation::Electra(att) => att.attesting_indices.first(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> Decode for IndexedAttestation<E> {
|
||||
fn is_ssz_fixed_len() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, ssz::DecodeError> {
|
||||
if let Ok(result) = IndexedAttestationBase::from_ssz_bytes(bytes) {
|
||||
return Ok(IndexedAttestation::Base(result));
|
||||
}
|
||||
|
||||
if let Ok(result) = IndexedAttestationElectra::from_ssz_bytes(bytes) {
|
||||
return Ok(IndexedAttestation::Electra(result));
|
||||
}
|
||||
|
||||
Err(ssz::DecodeError::BytesInvalid(String::from(
|
||||
"bytes not valid for any fork variant",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> TestRandom for IndexedAttestation<E> {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
let attesting_indices = VariableList::random_for_test(rng);
|
||||
let data = AttestationData::random_for_test(rng);
|
||||
let signature = AggregateSignature::random_for_test(rng);
|
||||
|
||||
Self::Base(IndexedAttestationBase {
|
||||
attesting_indices,
|
||||
data,
|
||||
signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +157,12 @@ impl<E: EthSpec> IndexedAttestation<E> {
|
||||
/// Used in the operation pool.
|
||||
impl<E: EthSpec> Hash for IndexedAttestation<E> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.attesting_indices.hash(state);
|
||||
self.data.hash(state);
|
||||
self.signature.as_ssz_bytes().hash(state);
|
||||
match self {
|
||||
IndexedAttestation::Base(att) => att.attesting_indices.hash(state),
|
||||
IndexedAttestation::Electra(att) => att.attesting_indices.hash(state),
|
||||
};
|
||||
self.data().hash(state);
|
||||
self.signature().as_ssz_bytes().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,8 +267,8 @@ mod tests {
|
||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||
let mut indexed_vote = IndexedAttestation::random_for_test(&mut rng);
|
||||
|
||||
indexed_vote.data.source.epoch = Epoch::new(source_epoch);
|
||||
indexed_vote.data.target.epoch = Epoch::new(target_epoch);
|
||||
indexed_vote.data_mut().source.epoch = Epoch::new(source_epoch);
|
||||
indexed_vote.data_mut().target.epoch = Epoch::new(target_epoch);
|
||||
indexed_vote
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ impl<E: EthSpec> SignedAggregateAndProof<E> {
|
||||
spec,
|
||||
);
|
||||
|
||||
let target_epoch = message.aggregate.data.slot.epoch(E::slots_per_epoch());
|
||||
let target_epoch = message.aggregate.data().slot.epoch(E::slots_per_epoch());
|
||||
let domain = spec.get_domain(
|
||||
target_epoch,
|
||||
Domain::AggregateAndProof,
|
||||
|
||||
Reference in New Issue
Block a user