mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-22 22:34:45 +00:00
Merge branch 'electra-epoch-proc' of https://github.com/sigp/lighthouse into electra-engine-api
This commit is contained in:
@@ -51,7 +51,6 @@ metastruct = "0.1.0"
|
||||
serde_json = { workspace = true }
|
||||
smallvec = { workspace = true }
|
||||
maplit = { workspace = true }
|
||||
strum = { workspace = true }
|
||||
milhouse = { workspace = true }
|
||||
rpds = { workspace = true }
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ 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};
|
||||
@@ -22,6 +21,7 @@ pub enum Error {
|
||||
SszTypesError(ssz_types::Error),
|
||||
AlreadySigned(usize),
|
||||
SubnetCountIsZero(ArithError),
|
||||
IncorrectStateVariant,
|
||||
}
|
||||
|
||||
#[superstruct(
|
||||
@@ -43,7 +43,9 @@ pub enum Error {
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
arbitrary(bound = "E: EthSpec"),
|
||||
),
|
||||
ref_attributes(derive(TreeHash), tree_hash(enum_behaviour = "transparent"))
|
||||
ref_attributes(derive(TreeHash), tree_hash(enum_behaviour = "transparent")),
|
||||
cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant")
|
||||
)]
|
||||
#[derive(
|
||||
Debug,
|
||||
@@ -72,37 +74,17 @@ pub struct Attestation<E: EthSpec> {
|
||||
pub signature: AggregateSignature,
|
||||
}
|
||||
|
||||
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",
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(electra): think about how to handle fork variants here
|
||||
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 aggregation_bits = BitList::random_for_test(rng);
|
||||
let data = AttestationData::random_for_test(rng);
|
||||
let signature = AggregateSignature::random_for_test(rng);
|
||||
let committee_bits = BitVector::random_for_test(rng);
|
||||
|
||||
Self::Base(AttestationBase {
|
||||
Self::Electra(AttestationElectra {
|
||||
aggregation_bits,
|
||||
// committee_bits,
|
||||
committee_bits,
|
||||
data,
|
||||
signature,
|
||||
})
|
||||
@@ -187,9 +169,9 @@ impl<E: EthSpec> Attestation<E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn committee_index(&self) -> u64 {
|
||||
pub fn committee_index(&self) -> Option<u64> {
|
||||
match self {
|
||||
Attestation::Base(att) => att.data.index,
|
||||
Attestation::Base(att) => Some(att.data.index),
|
||||
Attestation::Electra(att) => att.committee_index(),
|
||||
}
|
||||
}
|
||||
@@ -238,12 +220,31 @@ impl<'a, E: EthSpec> AttestationRef<'a, E> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn committee_index(&self) -> u64 {
|
||||
pub fn committee_index(&self) -> Option<u64> {
|
||||
match self {
|
||||
AttestationRef::Base(att) => att.data.index,
|
||||
AttestationRef::Base(att) => Some(att.data.index),
|
||||
AttestationRef::Electra(att) => att.committee_index(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_aggregation_bits(&self) -> Vec<usize> {
|
||||
match self {
|
||||
Self::Base(att) => att
|
||||
.aggregation_bits
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_i, bit)| *bit)
|
||||
.map(|(i, _bit)| i)
|
||||
.collect::<Vec<_>>(),
|
||||
Self::Electra(att) => att
|
||||
.aggregation_bits
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_i, bit)| *bit)
|
||||
.map(|(i, _bit)| i)
|
||||
.collect::<Vec<_>>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AttestationElectra<E> {
|
||||
@@ -257,8 +258,8 @@ impl<E: EthSpec> AttestationElectra<E> {
|
||||
.is_zero()
|
||||
}
|
||||
|
||||
pub fn committee_index(&self) -> u64 {
|
||||
*self.get_committee_indices().first().unwrap_or(&0u64)
|
||||
pub fn committee_index(&self) -> Option<u64> {
|
||||
self.get_committee_indices().first().cloned()
|
||||
}
|
||||
|
||||
pub fn get_committee_indices(&self) -> Vec<u64> {
|
||||
@@ -417,6 +418,65 @@ impl<'a, E: EthSpec> SlotData for AttestationRef<'a, E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
|
||||
#[ssz(enum_behaviour = "union")]
|
||||
pub enum AttestationOnDisk<E: EthSpec> {
|
||||
Base(AttestationBase<E>),
|
||||
Electra(AttestationElectra<E>),
|
||||
}
|
||||
|
||||
impl<E: EthSpec> AttestationOnDisk<E> {
|
||||
pub fn to_ref(&self) -> AttestationRefOnDisk<E> {
|
||||
match self {
|
||||
AttestationOnDisk::Base(att) => AttestationRefOnDisk::Base(att),
|
||||
AttestationOnDisk::Electra(att) => AttestationRefOnDisk::Electra(att),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Encode)]
|
||||
#[ssz(enum_behaviour = "union")]
|
||||
pub enum AttestationRefOnDisk<'a, E: EthSpec> {
|
||||
Base(&'a AttestationBase<E>),
|
||||
Electra(&'a AttestationElectra<E>),
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<Attestation<E>> for AttestationOnDisk<E> {
|
||||
fn from(attestation: Attestation<E>) -> Self {
|
||||
match attestation {
|
||||
Attestation::Base(attestation) => Self::Base(attestation),
|
||||
Attestation::Electra(attestation) => Self::Electra(attestation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> From<AttestationOnDisk<E>> for Attestation<E> {
|
||||
fn from(attestation: AttestationOnDisk<E>) -> Self {
|
||||
match attestation {
|
||||
AttestationOnDisk::Base(attestation) => Self::Base(attestation),
|
||||
AttestationOnDisk::Electra(attestation) => Self::Electra(attestation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> From<AttestationRef<'a, E>> for AttestationRefOnDisk<'a, E> {
|
||||
fn from(attestation: AttestationRef<'a, E>) -> Self {
|
||||
match attestation {
|
||||
AttestationRef::Base(attestation) => Self::Base(attestation),
|
||||
AttestationRef::Electra(attestation) => Self::Electra(attestation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, E: EthSpec> From<AttestationRefOnDisk<'a, E>> for AttestationRef<'a, E> {
|
||||
fn from(attestation: AttestationRefOnDisk<'a, E>) -> Self {
|
||||
match attestation {
|
||||
AttestationRefOnDisk::Base(attestation) => Self::Base(attestation),
|
||||
AttestationRefOnDisk::Electra(attestation) => Self::Electra(attestation),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -428,7 +488,7 @@ mod tests {
|
||||
// This test will only pass with `blst`, if we run these tests with another
|
||||
// BLS library in future we will have to make it generic.
|
||||
#[test]
|
||||
fn size_of() {
|
||||
fn size_of_base() {
|
||||
use std::mem::size_of;
|
||||
|
||||
let aggregation_bits =
|
||||
@@ -441,16 +501,43 @@ mod tests {
|
||||
assert_eq!(signature, 288 + 16);
|
||||
|
||||
let attestation_expected = aggregation_bits + attestation_data + signature;
|
||||
// TODO(electra) since we've removed attestation aggregation for electra variant
|
||||
// i've updated the attestation value expected from 488 544
|
||||
// assert_eq!(attestation_expected, 488);
|
||||
assert_eq!(attestation_expected, 488);
|
||||
assert_eq!(
|
||||
size_of::<Attestation<MainnetEthSpec>>(),
|
||||
size_of::<AttestationBase<MainnetEthSpec>>(),
|
||||
attestation_expected
|
||||
);
|
||||
}
|
||||
|
||||
// TODO(electra): can we do this with both variants or should we?
|
||||
ssz_and_tree_hash_tests!(AttestationBase<MainnetEthSpec>);
|
||||
#[test]
|
||||
fn size_of_electra() {
|
||||
use std::mem::size_of;
|
||||
|
||||
let aggregation_bits =
|
||||
size_of::<BitList<<MainnetEthSpec as EthSpec>::MaxValidatorsPerSlot>>();
|
||||
let attestation_data = size_of::<AttestationData>();
|
||||
let committee_bits =
|
||||
size_of::<BitList<<MainnetEthSpec as EthSpec>::MaxCommitteesPerSlot>>();
|
||||
let signature = size_of::<AggregateSignature>();
|
||||
|
||||
assert_eq!(aggregation_bits, 56);
|
||||
assert_eq!(committee_bits, 56);
|
||||
assert_eq!(attestation_data, 128);
|
||||
assert_eq!(signature, 288 + 16);
|
||||
|
||||
let attestation_expected = aggregation_bits + committee_bits + attestation_data + signature;
|
||||
assert_eq!(attestation_expected, 544);
|
||||
assert_eq!(
|
||||
size_of::<AttestationElectra<MainnetEthSpec>>(),
|
||||
attestation_expected
|
||||
);
|
||||
}
|
||||
|
||||
mod base {
|
||||
use super::*;
|
||||
ssz_and_tree_hash_tests!(AttestationBase<MainnetEthSpec>);
|
||||
}
|
||||
mod electra {
|
||||
use super::*;
|
||||
ssz_and_tree_hash_tests!(AttestationElectra<MainnetEthSpec>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +164,12 @@ impl<E: EthSpec> AttesterSlashing<E> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
// TODO(electra): should this be done for both variants?
|
||||
ssz_and_tree_hash_tests!(AttesterSlashingBase<MainnetEthSpec>);
|
||||
mod base {
|
||||
use super::*;
|
||||
ssz_and_tree_hash_tests!(AttesterSlashingBase<MainnetEthSpec>);
|
||||
}
|
||||
mod electra {
|
||||
use super::*;
|
||||
ssz_and_tree_hash_tests!(AttesterSlashingElectra<MainnetEthSpec>);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,14 +607,12 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockElectra<E, Payload>
|
||||
/// Return a Electra block where the block has maximum size.
|
||||
pub fn full(spec: &ChainSpec) -> Self {
|
||||
let base_block: BeaconBlockBase<_, Payload> = BeaconBlockBase::full(spec);
|
||||
// TODO(electra): check this
|
||||
let indexed_attestation: IndexedAttestationElectra<E> = IndexedAttestationElectra {
|
||||
attesting_indices: VariableList::new(vec![0_u64; E::MaxValidatorsPerSlot::to_usize()])
|
||||
.unwrap(),
|
||||
data: AttestationData::default(),
|
||||
signature: AggregateSignature::empty(),
|
||||
};
|
||||
// TODO(electra): fix this so we calculate this size correctly
|
||||
let attester_slashings = vec![
|
||||
AttesterSlashingElectra {
|
||||
attestation_1: indexed_attestation.clone(),
|
||||
@@ -627,7 +625,6 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockElectra<E, Payload>
|
||||
aggregation_bits: BitList::with_capacity(E::MaxValidatorsPerSlot::to_usize()).unwrap(),
|
||||
data: AttestationData::default(),
|
||||
signature: AggregateSignature::empty(),
|
||||
// TODO(electra): does this actually allocate the size correctly?
|
||||
committee_bits: BitVector::new(),
|
||||
};
|
||||
let mut attestations_electra = vec![];
|
||||
|
||||
@@ -251,6 +251,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload<E>> BeaconBlockBodyRef<'a, E,
|
||||
body.execution_payload.tree_hash_root(),
|
||||
body.bls_to_execution_changes.tree_hash_root(),
|
||||
body.blob_kzg_commitments.tree_hash_root(),
|
||||
body.consolidations.tree_hash_root(),
|
||||
];
|
||||
let beacon_block_body_depth = leaves.len().next_power_of_two().ilog2() as usize;
|
||||
let tree = MerkleTree::create(&leaves, beacon_block_body_depth);
|
||||
|
||||
@@ -163,6 +163,12 @@ pub enum Error {
|
||||
NonExecutionAddresWithdrawalCredential,
|
||||
NoCommitteeFound(CommitteeIndex),
|
||||
InvalidCommitteeIndex(CommitteeIndex),
|
||||
InvalidSelectionProof {
|
||||
aggregator_index: u64,
|
||||
},
|
||||
AggregatorNotInCommittee {
|
||||
aggregator_index: u64,
|
||||
},
|
||||
}
|
||||
|
||||
/// Control whether an epoch-indexed field can be indexed at the next epoch or not.
|
||||
|
||||
@@ -206,14 +206,17 @@ impl<E: EthSpec> Decode for IndexedAttestation<E> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(electra): think about how to handle fork variants here
|
||||
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 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(IndexedAttestationBase {
|
||||
attesting_indices,
|
||||
// committee_bits,
|
||||
data,
|
||||
signature,
|
||||
})
|
||||
|
||||
@@ -74,7 +74,6 @@ impl<E: EthSpec> SignedAggregateAndProof<E> {
|
||||
genesis_validators_root,
|
||||
spec,
|
||||
);
|
||||
|
||||
let target_epoch = message.aggregate().data().slot.epoch(E::slots_per_epoch());
|
||||
let domain = spec.get_domain(
|
||||
target_epoch,
|
||||
|
||||
@@ -40,13 +40,15 @@ impl SubnetId {
|
||||
/// Compute the subnet for an attestation where each slot in the
|
||||
/// attestation epoch contains `committee_count_per_slot` committees.
|
||||
pub fn compute_subnet_for_attestation<E: EthSpec>(
|
||||
attestation: &AttestationRef<E>,
|
||||
attestation: AttestationRef<E>,
|
||||
committee_count_per_slot: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<SubnetId, ArithError> {
|
||||
let committee_index = attestation.committee_index().ok_or(ArithError::Overflow)?;
|
||||
|
||||
Self::compute_subnet::<E>(
|
||||
attestation.data().slot,
|
||||
attestation.committee_index(),
|
||||
committee_index,
|
||||
committee_count_per_slot,
|
||||
spec,
|
||||
)
|
||||
|
||||
@@ -26,6 +26,15 @@ impl<N: Unsigned + Clone> TestRandom for BitVector<N> {
|
||||
fn random_for_test(rng: &mut impl RngCore) -> Self {
|
||||
let mut raw_bytes = smallvec![0; std::cmp::max(1, (N::to_usize() + 7) / 8)];
|
||||
rng.fill_bytes(&mut raw_bytes);
|
||||
// If N isn't divisible by 8
|
||||
// zero out bits greater than N
|
||||
if let Some(last_byte) = raw_bytes.last_mut() {
|
||||
let mut mask = 0;
|
||||
for i in 0..N::to_usize() % 8 {
|
||||
mask |= 1 << i;
|
||||
}
|
||||
*last_byte &= mask;
|
||||
}
|
||||
Self::from_bytes(raw_bytes).expect("we generate a valid BitVector")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user