Merge remote-tracking branch 'origin/unstable' into tree-states

This commit is contained in:
Michael Sproul
2022-11-30 14:14:17 +11:00
173 changed files with 6359 additions and 1655 deletions

View File

@@ -141,6 +141,8 @@ pub enum Error {
},
TotalActiveBalanceDiffUninitialized,
MissingImmutableValidator(usize),
IndexNotSupported(usize),
MerkleTreeError(merkle_proof::MerkleTreeError),
}
/// Control whether an epoch-indexed field can be indexed at the next epoch or not.
@@ -1660,6 +1662,60 @@ impl<T: EthSpec> BeaconState<T> {
};
Ok(sync_committee)
}
pub fn compute_merkle_proof(
&mut self,
generalized_index: usize,
) -> Result<Vec<Hash256>, Error> {
/* FIXME(sproul): re-enable merkle proofs
// 1. Convert generalized index to field index.
let field_index = match generalized_index {
light_client_update::CURRENT_SYNC_COMMITTEE_INDEX
| light_client_update::NEXT_SYNC_COMMITTEE_INDEX => {
// Sync committees are top-level fields, subtract off the generalized indices
// for the internal nodes. Result should be 22 or 23, the field offset of the committee
// in the `BeaconState`:
// https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#beaconstate
generalized_index
.checked_sub(tree_hash_cache::NUM_BEACON_STATE_HASH_TREE_ROOT_LEAVES)
.ok_or(Error::IndexNotSupported(generalized_index))?
}
light_client_update::FINALIZED_ROOT_INDEX => {
// Finalized root is the right child of `finalized_checkpoint`, divide by two to get
// the generalized index of `state.finalized_checkpoint`.
let finalized_checkpoint_generalized_index = generalized_index / 2;
// Subtract off the internal nodes. Result should be 105/2 - 32 = 20 which matches
// position of `finalized_checkpoint` in `BeaconState`.
finalized_checkpoint_generalized_index
.checked_sub(tree_hash_cache::NUM_BEACON_STATE_HASH_TREE_ROOT_LEAVES)
.ok_or(Error::IndexNotSupported(generalized_index))?
}
_ => return Err(Error::IndexNotSupported(generalized_index)),
};
// 2. Get all `BeaconState` leaves.
let mut cache = self
.tree_hash_cache_mut()
.take()
.ok_or(Error::TreeHashCacheNotInitialized)?;
let leaves = cache.recalculate_tree_hash_leaves(self)?;
self.tree_hash_cache_mut().restore(cache);
// 3. Make deposit tree.
// Use the depth of the `BeaconState` fields (i.e. `log2(32) = 5`).
let depth = light_client_update::CURRENT_SYNC_COMMITTEE_PROOF_LEN;
let tree = merkle_proof::MerkleTree::create(&leaves, depth);
let (_, mut proof) = tree.generate_proof(field_index, depth)?;
// 4. If we're proving the finalized root, patch in the finalized epoch to complete the proof.
if generalized_index == light_client_update::FINALIZED_ROOT_INDEX {
proof.insert(0, self.finalized_checkpoint().epoch.tree_hash_root());
}
Ok(proof)
*/
unimplemented!()
}
}
impl<T: EthSpec, V: ValidatorTrait> BeaconState<T, V> {
@@ -1718,6 +1774,12 @@ impl From<tree_hash::Error> for Error {
}
}
impl From<merkle_proof::MerkleTreeError> for Error {
fn from(e: merkle_proof::MerkleTreeError) -> Error {
Error::MerkleTreeError(e)
}
}
impl From<ArithError> for Error {
fn from(e: ArithError) -> Error {
Error::ArithError(e)

View File

@@ -784,7 +784,7 @@ impl ChainSpec {
domain_sync_committee_selection_proof: 8,
domain_contribution_and_proof: 9,
altair_fork_version: [0x01, 0x00, 0x00, 0x64],
altair_fork_epoch: Some(Epoch::new(256)),
altair_fork_epoch: Some(Epoch::new(512)),
/*
* Merge hard fork params
@@ -795,14 +795,11 @@ impl ChainSpec {
.expect("pow does not overflow"),
proportional_slashing_multiplier_bellatrix: 3,
bellatrix_fork_version: [0x02, 0x00, 0x00, 0x64],
bellatrix_fork_epoch: None,
terminal_total_difficulty: Uint256::MAX
.checked_sub(Uint256::from(2u64.pow(10)))
.expect("subtraction does not overflow")
// Add 1 since the spec declares `2**256 - 2**10` and we use
// `Uint256::MAX` which is `2*256- 1`.
.checked_add(Uint256::one())
.expect("addition does not overflow"),
bellatrix_fork_epoch: Some(Epoch::new(385536)),
terminal_total_difficulty: Uint256::from_dec_str(
"8626000000000000000000058750000000000000000000",
)
.expect("terminal_total_difficulty is a valid integer"),
terminal_block_hash: ExecutionBlockHash::zero(),
terminal_block_hash_activation_epoch: Epoch::new(u64::MAX),
safe_slots_to_import_optimistically: 128u64,

View File

@@ -40,7 +40,7 @@ impl ConfigAndPreset {
let extra_fields = get_extra_fields(spec);
if spec.bellatrix_fork_epoch.is_some()
|| fork_name == None
|| fork_name.is_none()
|| fork_name == Some(ForkName::Merge)
{
let bellatrix_preset = BellatrixPreset::from_chain_spec::<T>(spec);
@@ -65,7 +65,7 @@ impl ConfigAndPreset {
/// Get a hashmap of constants to add to the `PresetAndConfig`
pub fn get_extra_fields(spec: &ChainSpec) -> HashMap<String, Value> {
let hex_string = |value: &[u8]| format!("0x{}", hex::encode(&value)).into();
let hex_string = |value: &[u8]| format!("0x{}", hex::encode(value)).into();
let u32_hex = |v: u32| hex_string(&v.to_le_bytes());
let u8_hex = |v: u8| hex_string(&v.to_le_bytes());
hashmap! {

View File

@@ -0,0 +1,83 @@
use crate::*;
use eth2_hashing::{hash32_concat, ZERO_HASHES};
use int_to_bytes::int_to_bytes32;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use test_utils::TestRandom;
use DEPOSIT_TREE_DEPTH;
#[derive(Encode, Decode, Deserialize, Serialize, Clone, Debug, PartialEq, TestRandom)]
pub struct FinalizedExecutionBlock {
pub deposit_root: Hash256,
pub deposit_count: u64,
pub block_hash: Hash256,
pub block_height: u64,
}
impl From<&DepositTreeSnapshot> for FinalizedExecutionBlock {
fn from(snapshot: &DepositTreeSnapshot) -> Self {
Self {
deposit_root: snapshot.deposit_root,
deposit_count: snapshot.deposit_count,
block_hash: snapshot.execution_block_hash,
block_height: snapshot.execution_block_height,
}
}
}
#[derive(Encode, Decode, Deserialize, Serialize, Clone, Debug, PartialEq, TestRandom)]
pub struct DepositTreeSnapshot {
pub finalized: Vec<Hash256>,
pub deposit_root: Hash256,
pub deposit_count: u64,
pub execution_block_hash: Hash256,
pub execution_block_height: u64,
}
impl Default for DepositTreeSnapshot {
fn default() -> Self {
let mut result = Self {
finalized: vec![],
deposit_root: Hash256::default(),
deposit_count: 0,
execution_block_hash: Hash256::zero(),
execution_block_height: 0,
};
// properly set the empty deposit root
result.deposit_root = result.calculate_root().unwrap();
result
}
}
impl DepositTreeSnapshot {
// Calculates the deposit tree root from the hashes in the snapshot
pub fn calculate_root(&self) -> Option<Hash256> {
let mut size = self.deposit_count;
let mut index = self.finalized.len();
let mut deposit_root = [0; 32];
for height in 0..DEPOSIT_TREE_DEPTH {
deposit_root = if (size & 1) == 1 {
index = index.checked_sub(1)?;
hash32_concat(self.finalized.get(index)?.as_bytes(), &deposit_root)
} else {
hash32_concat(&deposit_root, ZERO_HASHES.get(height)?)
};
size /= 2;
}
// add mix-in-length
deposit_root = hash32_concat(&deposit_root, &int_to_bytes32(self.deposit_count));
Some(Hash256::from_slice(&deposit_root))
}
pub fn is_valid(&self) -> bool {
self.calculate_root()
.map_or(false, |calculated| self.deposit_root == calculated)
}
}
#[cfg(test)]
mod tests {
use super::*;
ssz_tests!(DepositTreeSnapshot);
}

View File

@@ -27,7 +27,7 @@ impl Graffiti {
impl fmt::Display for Graffiti {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", eth2_serde_utils::hex::encode(&self.0))
write!(f, "{}", eth2_serde_utils::hex::encode(self.0))
}
}

View File

@@ -36,6 +36,7 @@ pub mod contribution_and_proof;
pub mod deposit;
pub mod deposit_data;
pub mod deposit_message;
pub mod deposit_tree_snapshot;
pub mod enr_fork_id;
pub mod eth1_data;
pub mod eth_spec;
@@ -49,6 +50,9 @@ pub mod free_attestation;
pub mod graffiti;
pub mod historical_batch;
pub mod indexed_attestation;
pub mod light_client_bootstrap;
pub mod light_client_optimistic_update;
pub mod light_client_update;
pub mod pending_attestation;
pub mod proposer_preparation_data;
pub mod proposer_slashing;
@@ -116,6 +120,7 @@ pub use crate::contribution_and_proof::ContributionAndProof;
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
pub use crate::deposit_data::DepositData;
pub use crate::deposit_message::DepositMessage;
pub use crate::deposit_tree_snapshot::{DepositTreeSnapshot, FinalizedExecutionBlock};
pub use crate::enr_fork_id::EnrForkId;
pub use crate::eth1_data::Eth1Data;
pub use crate::eth_spec::EthSpecId;

View File

@@ -0,0 +1,44 @@
use super::{BeaconBlockHeader, BeaconState, EthSpec, Hash256, SyncCommittee};
use crate::{light_client_update::*, test_utils::TestRandom};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use ssz_types::FixedVector;
use std::sync::Arc;
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
/// A LightClientBootstrap is the initializer we send over to lightclient nodes
/// that are trying to generate their basic storage when booting up.
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct LightClientBootstrap<T: EthSpec> {
/// Requested beacon block header.
pub header: BeaconBlockHeader,
/// The `SyncCommittee` used in the requested period.
pub current_sync_committee: Arc<SyncCommittee<T>>,
/// Merkle proof for sync committee
pub current_sync_committee_branch: FixedVector<Hash256, CurrentSyncCommitteeProofLen>,
}
impl<T: EthSpec> LightClientBootstrap<T> {
pub fn from_beacon_state(beacon_state: &mut BeaconState<T>) -> Result<Self, Error> {
let mut header = beacon_state.latest_block_header().clone();
header.state_root = beacon_state.tree_hash_root();
let current_sync_committee_branch =
beacon_state.compute_merkle_proof(CURRENT_SYNC_COMMITTEE_INDEX)?;
Ok(LightClientBootstrap {
header,
current_sync_committee: beacon_state.current_sync_committee()?.clone(),
current_sync_committee_branch: FixedVector::new(current_sync_committee_branch)?,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MainnetEthSpec;
ssz_tests!(LightClientBootstrap<MainnetEthSpec>);
}

View File

@@ -0,0 +1,81 @@
use super::{BeaconBlockHeader, EthSpec, FixedVector, Hash256, Slot, SyncAggregate, SyncCommittee};
use crate::{light_client_update::*, test_utils::TestRandom, BeaconBlock, BeaconState, ChainSpec};
use safe_arith::ArithError;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use ssz_types::typenum::{U5, U6};
use std::sync::Arc;
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
/// A LightClientFinalityUpdate is the update lightclient request or received by a gossip that
/// signal a new finalized beacon block header for the light client sync protocol.
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct LightClientFinalityUpdate<T: EthSpec> {
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
pub attested_header: BeaconBlockHeader,
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
pub finalized_header: BeaconBlockHeader,
/// Merkle proof attesting finalized header.
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
/// current sync aggreggate
pub sync_aggregate: SyncAggregate<T>,
/// Slot of the sync aggregated singature
pub signature_slot: Slot,
}
impl<T: EthSpec> LightClientFinalityUpdate<T> {
pub fn new(
chain_spec: ChainSpec,
beacon_state: BeaconState<T>,
block: BeaconBlock<T>,
attested_state: &mut BeaconState<T>,
finalized_block: BeaconBlock<T>,
) -> Result<Self, Error> {
let altair_fork_epoch = chain_spec
.altair_fork_epoch
.ok_or(Error::AltairForkNotActive)?;
if attested_state.slot().epoch(T::slots_per_epoch()) < altair_fork_epoch {
return Err(Error::AltairForkNotActive);
}
let sync_aggregate = block.body().sync_aggregate()?;
if sync_aggregate.num_set_bits() < chain_spec.min_sync_committee_participants as usize {
return Err(Error::NotEnoughSyncCommitteeParticipants);
}
// Compute and validate attested header.
let mut attested_header = attested_state.latest_block_header().clone();
attested_header.state_root = attested_state.tree_hash_root();
// Build finalized header from finalized block
let finalized_header = BeaconBlockHeader {
slot: finalized_block.slot(),
proposer_index: finalized_block.proposer_index(),
parent_root: finalized_block.parent_root(),
state_root: finalized_block.state_root(),
body_root: finalized_block.body_root(),
};
if finalized_header.tree_hash_root() != beacon_state.finalized_checkpoint().root {
return Err(Error::InvalidFinalizedBlock);
}
let finality_branch = attested_state.compute_merkle_proof(FINALIZED_ROOT_INDEX)?;
Ok(Self {
attested_header: attested_header,
finalized_header: finalized_header,
finality_branch: FixedVector::new(finality_branch)?,
sync_aggregate: sync_aggregate.clone(),
signature_slot: block.slot(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MainnetEthSpec;
ssz_tests!(LightClientFinalityUpdate<MainnetEthSpec>);
}

View File

@@ -0,0 +1,59 @@
use super::{BeaconBlockHeader, EthSpec, Slot, SyncAggregate};
use crate::{
light_client_update::Error, test_utils::TestRandom, BeaconBlock, BeaconState, ChainSpec,
};
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
/// A LightClientOptimisticUpdate is the update we send on each slot,
/// it is based off the current unfinalized epoch is verified only against BLS signature.
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct LightClientOptimisticUpdate<T: EthSpec> {
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
pub attested_header: BeaconBlockHeader,
/// current sync aggreggate
pub sync_aggregate: SyncAggregate<T>,
/// Slot of the sync aggregated singature
pub signature_slot: Slot,
}
impl<T: EthSpec> LightClientOptimisticUpdate<T> {
pub fn new(
chain_spec: ChainSpec,
block: BeaconBlock<T>,
attested_state: BeaconState<T>,
) -> Result<Self, Error> {
let altair_fork_epoch = chain_spec
.altair_fork_epoch
.ok_or(Error::AltairForkNotActive)?;
if attested_state.slot().epoch(T::slots_per_epoch()) < altair_fork_epoch {
return Err(Error::AltairForkNotActive);
}
let sync_aggregate = block.body().sync_aggregate()?;
if sync_aggregate.num_set_bits() < chain_spec.min_sync_committee_participants as usize {
return Err(Error::NotEnoughSyncCommitteeParticipants);
}
// Compute and validate attested header.
let mut attested_header = attested_state.latest_block_header().clone();
attested_header.state_root = attested_state.tree_hash_root();
Ok(Self {
attested_header,
sync_aggregate: sync_aggregate.clone(),
signature_slot: block.slot(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MainnetEthSpec;
ssz_tests!(LightClientOptimisticUpdate<MainnetEthSpec>);
}

View File

@@ -0,0 +1,173 @@
use super::{BeaconBlockHeader, EthSpec, Hash256, Slot, SyncAggregate, SyncCommittee};
use crate::{beacon_state, test_utils::TestRandom, BeaconBlock, BeaconState, ChainSpec};
use safe_arith::ArithError;
use serde_derive::{Deserialize, Serialize};
use ssz_derive::{Decode, Encode};
use ssz_types::{
typenum::{U5, U6},
FixedVector,
};
use std::sync::Arc;
use test_random_derive::TestRandom;
use tree_hash::TreeHash;
pub const FINALIZED_ROOT_INDEX: usize = 105;
pub const CURRENT_SYNC_COMMITTEE_INDEX: usize = 54;
pub const NEXT_SYNC_COMMITTEE_INDEX: usize = 55;
pub type FinalizedRootProofLen = U6;
pub type CurrentSyncCommitteeProofLen = U5;
pub type NextSyncCommitteeProofLen = U5;
pub const FINALIZED_ROOT_PROOF_LEN: usize = 6;
pub const CURRENT_SYNC_COMMITTEE_PROOF_LEN: usize = 5;
pub const NEXT_SYNC_COMMITTEE_PROOF_LEN: usize = 5;
#[derive(Debug, PartialEq, Clone)]
pub enum Error {
SszTypesError(ssz_types::Error),
BeaconStateError(beacon_state::Error),
ArithError(ArithError),
AltairForkNotActive,
NotEnoughSyncCommitteeParticipants,
MismatchingPeriods,
InvalidFinalizedBlock,
}
impl From<ssz_types::Error> for Error {
fn from(e: ssz_types::Error) -> Error {
Error::SszTypesError(e)
}
}
impl From<beacon_state::Error> for Error {
fn from(e: beacon_state::Error) -> Error {
Error::BeaconStateError(e)
}
}
impl From<ArithError> for Error {
fn from(e: ArithError) -> Error {
Error::ArithError(e)
}
}
/// A LightClientUpdate is the update we request solely to either complete the bootstraping process,
/// or to sync up to the last committee period, we need to have one ready for each ALTAIR period
/// we go over, note: there is no need to keep all of the updates from [ALTAIR_PERIOD, CURRENT_PERIOD].
#[cfg_attr(feature = "arbitrary-fuzz", derive(arbitrary::Arbitrary))]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, Decode, TestRandom)]
#[serde(bound = "T: EthSpec")]
pub struct LightClientUpdate<T: EthSpec> {
/// The last `BeaconBlockHeader` from the last attested block by the sync committee.
pub attested_header: BeaconBlockHeader,
/// The `SyncCommittee` used in the next period.
pub next_sync_committee: Arc<SyncCommittee<T>>,
/// Merkle proof for next sync committee
pub next_sync_committee_branch: FixedVector<Hash256, NextSyncCommitteeProofLen>,
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
pub finalized_header: BeaconBlockHeader,
/// Merkle proof attesting finalized header.
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
/// current sync aggreggate
pub sync_aggregate: SyncAggregate<T>,
/// Slot of the sync aggregated singature
pub signature_slot: Slot,
}
impl<T: EthSpec> LightClientUpdate<T> {
pub fn new(
chain_spec: ChainSpec,
beacon_state: BeaconState<T>,
block: BeaconBlock<T>,
attested_state: &mut BeaconState<T>,
finalized_block: BeaconBlock<T>,
) -> Result<Self, Error> {
let altair_fork_epoch = chain_spec
.altair_fork_epoch
.ok_or(Error::AltairForkNotActive)?;
if attested_state.slot().epoch(T::slots_per_epoch()) < altair_fork_epoch {
return Err(Error::AltairForkNotActive);
}
let sync_aggregate = block.body().sync_aggregate()?;
if sync_aggregate.num_set_bits() < chain_spec.min_sync_committee_participants as usize {
return Err(Error::NotEnoughSyncCommitteeParticipants);
}
let signature_period = block.epoch().sync_committee_period(&chain_spec)?;
// Compute and validate attested header.
let mut attested_header = attested_state.latest_block_header().clone();
attested_header.state_root = attested_state.tree_hash_root();
let attested_period = attested_header
.slot
.epoch(T::slots_per_epoch())
.sync_committee_period(&chain_spec)?;
if attested_period != signature_period {
return Err(Error::MismatchingPeriods);
}
// Build finalized header from finalized block
let finalized_header = BeaconBlockHeader {
slot: finalized_block.slot(),
proposer_index: finalized_block.proposer_index(),
parent_root: finalized_block.parent_root(),
state_root: finalized_block.state_root(),
body_root: finalized_block.body_root(),
};
if finalized_header.tree_hash_root() != beacon_state.finalized_checkpoint().root {
return Err(Error::InvalidFinalizedBlock);
}
let next_sync_committee_branch =
attested_state.compute_merkle_proof(NEXT_SYNC_COMMITTEE_INDEX)?;
let finality_branch = attested_state.compute_merkle_proof(FINALIZED_ROOT_INDEX)?;
Ok(Self {
attested_header,
next_sync_committee: attested_state.next_sync_committee()?.clone(),
next_sync_committee_branch: FixedVector::new(next_sync_committee_branch)?,
finalized_header,
finality_branch: FixedVector::new(finality_branch)?,
sync_aggregate: sync_aggregate.clone(),
signature_slot: block.slot(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::MainnetEthSpec;
use ssz_types::typenum::Unsigned;
ssz_tests!(LightClientUpdate<MainnetEthSpec>);
#[test]
fn finalized_root_params() {
assert!(2usize.pow(FINALIZED_ROOT_PROOF_LEN as u32) <= FINALIZED_ROOT_INDEX);
assert!(2usize.pow(FINALIZED_ROOT_PROOF_LEN as u32 + 1) > FINALIZED_ROOT_INDEX);
assert_eq!(FinalizedRootProofLen::to_usize(), FINALIZED_ROOT_PROOF_LEN);
}
#[test]
fn current_sync_committee_params() {
assert!(
2usize.pow(CURRENT_SYNC_COMMITTEE_PROOF_LEN as u32) <= CURRENT_SYNC_COMMITTEE_INDEX
);
assert!(
2usize.pow(CURRENT_SYNC_COMMITTEE_PROOF_LEN as u32 + 1) > CURRENT_SYNC_COMMITTEE_INDEX
);
assert_eq!(
CurrentSyncCommitteeProofLen::to_usize(),
CURRENT_SYNC_COMMITTEE_PROOF_LEN
);
}
#[test]
fn next_sync_committee_params() {
assert!(2usize.pow(NEXT_SYNC_COMMITTEE_PROOF_LEN as u32) <= NEXT_SYNC_COMMITTEE_INDEX);
assert!(2usize.pow(NEXT_SYNC_COMMITTEE_PROOF_LEN as u32 + 1) > NEXT_SYNC_COMMITTEE_INDEX);
assert_eq!(
NextSyncCommitteeProofLen::to_usize(),
NEXT_SYNC_COMMITTEE_PROOF_LEN
);
}
}