mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 20:57:10 +00:00
Resolve merge conflicts
This commit is contained in:
@@ -8,7 +8,7 @@ use safe_arith::{ArithError, SafeArith};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_utils::quoted_u64::MaybeQuoted;
|
||||
use ssz::Encode;
|
||||
use ssz_types::{RuntimeVariableList, VariableList};
|
||||
use ssz_types::RuntimeVariableList;
|
||||
use tree_hash::TreeHash;
|
||||
|
||||
use crate::{
|
||||
@@ -16,7 +16,6 @@ use crate::{
|
||||
APPLICATION_DOMAIN_BUILDER, Address, ApplicationDomain, EnrForkId, Epoch, EthSpec,
|
||||
EthSpecId, ExecutionBlockHash, Hash256, MainnetEthSpec, Slot, Uint256,
|
||||
},
|
||||
data::{BlobIdentifier, DataColumnSubnetId, DataColumnsByRootIdentifier},
|
||||
fork::{Fork, ForkData, ForkName},
|
||||
};
|
||||
|
||||
@@ -823,10 +822,6 @@ impl ChainSpec {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_data_column_sidecar_subnets(&self) -> impl Iterator<Item = DataColumnSubnetId> {
|
||||
(0..self.data_column_sidecar_subnet_count).map(DataColumnSubnetId::new)
|
||||
}
|
||||
|
||||
/// Worst-case compressed length for a given payload of size n when using snappy.
|
||||
///
|
||||
/// https://github.com/google/snappy/blob/32ded457c0b1fe78ceb8397632c416568d6714a0/snappy.cc#L218C1-L218C47
|
||||
@@ -2110,37 +2105,41 @@ fn max_blocks_by_root_request_common(max_request_blocks: u64) -> usize {
|
||||
.len()
|
||||
}
|
||||
|
||||
fn max_blobs_by_root_request_common(max_request_blob_sidecars: u64) -> usize {
|
||||
let max_request_blob_sidecars = max_request_blob_sidecars as usize;
|
||||
let empty_blob_identifier = BlobIdentifier {
|
||||
block_root: Hash256::zero(),
|
||||
index: 0,
|
||||
};
|
||||
// Simplified function which precomputes the size of a `List` of `BlobIdentifiers`.
|
||||
pub(crate) fn max_blobs_by_root_request_common(max_request_blob_sidecars: u64) -> usize {
|
||||
// BlobIdentifier is a fixed-size struct with two fields:
|
||||
// - block_root: Hash256 (32 bytes)
|
||||
// - index: u64 (8 bytes)
|
||||
// Total per element: 32 + 8 = 40 bytes
|
||||
// Since BlobIdentifier is fixed-size, the outer List does not add any byte overhead.
|
||||
let blob_identifier_ssz_size = 40_usize;
|
||||
|
||||
RuntimeVariableList::<BlobIdentifier>::new(
|
||||
vec![empty_blob_identifier; max_request_blob_sidecars],
|
||||
max_request_blob_sidecars,
|
||||
)
|
||||
.expect("creating a RuntimeVariableList of size `max_request_blob_sidecars` should succeed")
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
(max_request_blob_sidecars as usize)
|
||||
.safe_mul(blob_identifier_ssz_size)
|
||||
.expect("should not overflow")
|
||||
}
|
||||
|
||||
fn max_data_columns_by_root_request_common<E: EthSpec>(max_request_blocks: u64) -> usize {
|
||||
let max_request_blocks = max_request_blocks as usize;
|
||||
// Simplified function which precomputes the size of a `List` of `DataColumnIdentifiers`.
|
||||
pub(crate) fn max_data_columns_by_root_request_common<E: EthSpec>(
|
||||
max_request_blocks: u64,
|
||||
) -> usize {
|
||||
// DataColumnsByRootIdentifier is a variable-size struct with two fields:
|
||||
// - block_root: Hash256 (32 bytes)
|
||||
// - columns: List<ColumnIndex, NumberOfColumns> (4 byte offset + n × 8 bytes)
|
||||
// Since DataColumnsByRootIdentifier is variable-size, the outer List adds a
|
||||
// 4-byte offset per element.
|
||||
// Total per element: 4 (outer offset) + 32 (block_root) + 4 (columns offset) + n × 8
|
||||
let column_index_ssz_size = 8_usize;
|
||||
let ssz_fixed_size = 40_usize;
|
||||
|
||||
let empty_data_columns_by_root_id = DataColumnsByRootIdentifier {
|
||||
block_root: Hash256::zero(),
|
||||
columns: VariableList::repeat_full(0),
|
||||
};
|
||||
let data_columns_by_root_identifier_ssz_size = column_index_ssz_size
|
||||
.safe_mul(E::number_of_columns())
|
||||
.and_then(|b| b.safe_add(ssz_fixed_size))
|
||||
.expect("should not overflow");
|
||||
|
||||
RuntimeVariableList::<DataColumnsByRootIdentifier<E>>::new(
|
||||
vec![empty_data_columns_by_root_id; max_request_blocks],
|
||||
max_request_blocks,
|
||||
)
|
||||
.expect("creating a RuntimeVariableList of size `max_request_blocks` should succeed")
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
(max_request_blocks as usize)
|
||||
.safe_mul(data_columns_by_root_identifier_ssz_size)
|
||||
.expect("should not overflow")
|
||||
}
|
||||
|
||||
fn default_max_blocks_by_root_request() -> usize {
|
||||
|
||||
@@ -38,6 +38,11 @@ pub use signing_data::{SignedRoot, SigningData};
|
||||
pub use slot_data::SlotData;
|
||||
pub use slot_epoch::{Epoch, Slot};
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) use chain_spec::{
|
||||
max_blobs_by_root_request_common, max_data_columns_by_root_request_common,
|
||||
};
|
||||
|
||||
pub type Hash256 = alloy_primitives::B256;
|
||||
pub type Uint256 = alloy_primitives::U256;
|
||||
pub type Hash64 = alloy_primitives::B64;
|
||||
|
||||
@@ -300,3 +300,39 @@ pub type BlobSidecarList<E> = RuntimeVariableList<Arc<BlobSidecar<E>>>;
|
||||
/// Alias for a non length-constrained list of `BlobSidecar`s.
|
||||
pub type FixedBlobSidecarList<E> = RuntimeFixedVector<Option<Arc<BlobSidecar<E>>>>;
|
||||
pub type BlobsList<E> = VariableList<Blob<E>, <E as EthSpec>::MaxBlobCommitmentsPerBlock>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::core::max_blobs_by_root_request_common;
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
|
||||
// This is the "correct" implementation of max_blobs_by_root_request.
|
||||
// This test ensures that the simplified implementation doesn't deviate from it.
|
||||
fn max_blobs_by_root_request_implementation(max_request_blob_sidecars: u64) -> usize {
|
||||
let max_request_blob_sidecars = max_request_blob_sidecars as usize;
|
||||
let empty_blob_identifier = BlobIdentifier {
|
||||
block_root: Hash256::zero(),
|
||||
index: 0,
|
||||
};
|
||||
|
||||
RuntimeVariableList::<BlobIdentifier>::new(
|
||||
vec![empty_blob_identifier; max_request_blob_sidecars],
|
||||
max_request_blob_sidecars,
|
||||
)
|
||||
.expect("creating a RuntimeVariableList of size `max_request_blob_sidecars` should succeed")
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_blobs_by_root_request_matches_simplified() {
|
||||
for n in [0, 1, 2, 8, 16, 32, 64, 128, 256, 512, 768, 1024, 1152] {
|
||||
assert_eq!(
|
||||
max_blobs_by_root_request_common(n),
|
||||
max_blobs_by_root_request_implementation(n),
|
||||
"Mismatch at n={n}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,21 +3,23 @@ use std::sync::Arc;
|
||||
use bls::Signature;
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use kzg::{KzgCommitment, KzgProof};
|
||||
use kzg::{CellsAndKzgProofs, Kzg, KzgCommitment, KzgProof, BYTES_PER_BLOB};
|
||||
use merkle_proof::verify_merkle_proof;
|
||||
use safe_arith::ArithError;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz::Encode;
|
||||
use ssz::{Decode, Encode};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use ssz_types::Error as SszError;
|
||||
use ssz_types::{FixedVector, VariableList};
|
||||
use superstruct::superstruct;
|
||||
use test_random_derive::TestRandom;
|
||||
use tree_hash::TreeHash;
|
||||
use tree_hash_derive::TreeHash;
|
||||
|
||||
use crate::{
|
||||
block::{BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockHeader, SignedBeaconBlockHeader},
|
||||
core::{Epoch, EthSpec, Hash256, Slot},
|
||||
block::{BLOB_KZG_COMMITMENTS_INDEX, BeaconBlockHeader, SignedBeaconBlock, SignedBeaconBlockHeader},
|
||||
core::{ChainSpec, Epoch, EthSpec, Hash256, Slot},
|
||||
data::BlobsList,
|
||||
fork::ForkName,
|
||||
kzg_ext::{KzgCommitments, KzgError},
|
||||
state::BeaconStateError,
|
||||
@@ -38,15 +40,43 @@ pub struct DataColumnsByRootIdentifier<E: EthSpec> {
|
||||
|
||||
pub type DataColumnSidecarList<E> = Vec<Arc<DataColumnSidecar<E>>>;
|
||||
|
||||
#[superstruct(
|
||||
variants(Fulu, Gloas),
|
||||
variant_attributes(
|
||||
derive(
|
||||
Debug,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Decode,
|
||||
Encode,
|
||||
TestRandom,
|
||||
Educe,
|
||||
TreeHash,
|
||||
),
|
||||
context_deserialize(ForkName),
|
||||
educe(PartialEq, Hash(bound(E: EthSpec))),
|
||||
serde(bound = "E: EthSpec", deny_unknown_fields),
|
||||
cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)
|
||||
),
|
||||
ref_attributes(derive(TreeHash), tree_hash(enum_behaviour = "transparent")),
|
||||
cast_error(ty = "DataColumnSidecarError", expr = "DataColumnSidecarError::IncorrectStateVariant"),
|
||||
partial_getter_error(ty = "DataColumnSidecarError", expr = "DataColumnSidecarError::IncorrectStateVariant")
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "arbitrary",
|
||||
derive(arbitrary::Arbitrary),
|
||||
arbitrary(bound = "E: EthSpec")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode, TreeHash, TestRandom, Educe)]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[educe(PartialEq, Eq, Hash(bound(E: EthSpec)))]
|
||||
#[context_deserialize(ForkName)]
|
||||
#[derive(Debug, Clone, Serialize, TreeHash, Encode, Educe, Deserialize)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(bound = "E: EthSpec", untagged, deny_unknown_fields)]
|
||||
#[tree_hash(enum_behaviour = "transparent")]
|
||||
#[ssz(enum_behaviour = "transparent")]
|
||||
pub struct DataColumnSidecar<E: EthSpec> {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub index: ColumnIndex,
|
||||
@@ -55,20 +85,184 @@ pub struct DataColumnSidecar<E: EthSpec> {
|
||||
/// All the KZG commitments and proofs associated with the block, used for verifying sample cells.
|
||||
pub kzg_commitments: KzgCommitments<E>,
|
||||
pub kzg_proofs: VariableList<KzgProof, E::MaxBlobCommitmentsPerBlock>,
|
||||
#[superstruct(only(Fulu))]
|
||||
pub signed_block_header: SignedBeaconBlockHeader,
|
||||
/// An inclusion proof, proving the inclusion of `blob_kzg_commitments` in `BeaconBlockBody`.
|
||||
#[superstruct(only(Fulu))]
|
||||
pub kzg_commitments_inclusion_proof: FixedVector<Hash256, E::KzgCommitmentsInclusionProofDepth>,
|
||||
#[superstruct(only(Gloas), partial_getter(rename = "slot_gloas"))]
|
||||
pub slot: Slot,
|
||||
#[superstruct(only(Gloas))]
|
||||
pub beacon_block_root: Hash256,
|
||||
}
|
||||
|
||||
impl<E: EthSpec> DataColumnSidecar<E> {
|
||||
pub fn slot(&self) -> Slot {
|
||||
self.signed_block_header.message.slot
|
||||
match self {
|
||||
DataColumnSidecar::Fulu(column) => column.slot(),
|
||||
DataColumnSidecar::Gloas(column) => column.slot,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn epoch(&self) -> Epoch {
|
||||
self.slot().epoch(E::slots_per_epoch())
|
||||
}
|
||||
|
||||
pub fn block_root(&self) -> Hash256 {
|
||||
match self {
|
||||
DataColumnSidecar::Fulu(column) => column.block_root(),
|
||||
DataColumnSidecar::Gloas(column) => column.beacon_block_root,
|
||||
}
|
||||
}
|
||||
|
||||
/// Custom SSZ decoder that takes a `ForkName` as context.
|
||||
pub fn from_ssz_bytes_for_fork(
|
||||
bytes: &[u8],
|
||||
fork_name: ForkName,
|
||||
) -> Result<Self, ssz::DecodeError> {
|
||||
match fork_name {
|
||||
ForkName::Base
|
||||
| ForkName::Altair
|
||||
| ForkName::Bellatrix
|
||||
| ForkName::Capella
|
||||
| ForkName::Deneb
|
||||
| ForkName::Electra => Err(ssz::DecodeError::NoMatchingVariant),
|
||||
ForkName::Fulu => Ok(DataColumnSidecar::Fulu(
|
||||
DataColumnSidecarFulu::from_ssz_bytes(bytes)?,
|
||||
)),
|
||||
ForkName::Gloas => Ok(DataColumnSidecar::Gloas(
|
||||
DataColumnSidecarGloas::from_ssz_bytes(bytes)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build data column sidecars from blobs and a signed beacon block.
|
||||
///
|
||||
/// This method computes cells and cell proofs from the blobs using KZG,
|
||||
/// then constructs the appropriate data column sidecar variant (Fulu or Gloas)
|
||||
/// based on the block's fork.
|
||||
pub fn build_sidecars(
|
||||
blobs: BlobsList<E>,
|
||||
block: &SignedBeaconBlock<E>,
|
||||
kzg: &Kzg,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<DataColumnSidecarList<E>, DataColumnSidecarError> {
|
||||
if blobs.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let kzg_commitments = block
|
||||
.message()
|
||||
.body()
|
||||
.blob_kzg_commitments()
|
||||
.map_err(|_| DataColumnSidecarError::PreDeneb)?
|
||||
.clone();
|
||||
|
||||
// Compute cells and proofs for each blob
|
||||
let blob_cells_and_proofs: Vec<CellsAndKzgProofs> = blobs
|
||||
.iter()
|
||||
.map(|blob| {
|
||||
let blob_bytes: &[u8; BYTES_PER_BLOB] =
|
||||
blob.as_ref().try_into().map_err(|_| {
|
||||
DataColumnSidecarError::KzgError(KzgError::InconsistentArrayLength(
|
||||
format!(
|
||||
"blob should have size {}, got {}",
|
||||
BYTES_PER_BLOB,
|
||||
blob.len()
|
||||
),
|
||||
))
|
||||
})?;
|
||||
kzg.compute_cells_and_proofs(blob_bytes)
|
||||
.map_err(DataColumnSidecarError::KzgError)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let number_of_columns = E::number_of_columns();
|
||||
let max_blobs_per_block =
|
||||
spec.max_blobs_per_block(block.slot().epoch(E::slots_per_epoch())) as usize;
|
||||
|
||||
// Initialize columns and proofs vectors
|
||||
let mut columns: Vec<Vec<Cell<E>>> =
|
||||
vec![Vec::with_capacity(max_blobs_per_block); number_of_columns];
|
||||
let mut column_kzg_proofs: Vec<Vec<KzgProof>> =
|
||||
vec![Vec::with_capacity(max_blobs_per_block); number_of_columns];
|
||||
|
||||
// Arrange cells and proofs into columns
|
||||
for (blob_cells, blob_cell_proofs) in &blob_cells_and_proofs {
|
||||
for col_idx in 0..number_of_columns {
|
||||
let cell = blob_cells.get(col_idx).ok_or_else(|| {
|
||||
DataColumnSidecarError::DataColumnIndexOutOfBounds
|
||||
})?;
|
||||
let cell_vec: Vec<u8> = cell.to_vec();
|
||||
let cell = Cell::<E>::try_from(cell_vec)?;
|
||||
|
||||
let proof = blob_cell_proofs.get(col_idx).ok_or_else(|| {
|
||||
DataColumnSidecarError::DataColumnIndexOutOfBounds
|
||||
})?;
|
||||
|
||||
columns
|
||||
.get_mut(col_idx)
|
||||
.ok_or(DataColumnSidecarError::DataColumnIndexOutOfBounds)?
|
||||
.push(cell);
|
||||
column_kzg_proofs
|
||||
.get_mut(col_idx)
|
||||
.ok_or(DataColumnSidecarError::DataColumnIndexOutOfBounds)?
|
||||
.push(*proof);
|
||||
}
|
||||
}
|
||||
|
||||
// Build sidecars based on fork
|
||||
let fork_name = block.fork_name_unchecked();
|
||||
if fork_name.gloas_enabled() {
|
||||
// Gloas variant
|
||||
let beacon_block_root = block.canonical_root();
|
||||
let slot = block.slot();
|
||||
|
||||
columns
|
||||
.into_iter()
|
||||
.zip(column_kzg_proofs)
|
||||
.enumerate()
|
||||
.map(|(index, (col, proofs))| {
|
||||
Ok(Arc::new(DataColumnSidecar::Gloas(DataColumnSidecarGloas {
|
||||
index: index as u64,
|
||||
column: DataColumn::<E>::try_from(col)?,
|
||||
kzg_commitments: kzg_commitments.clone(),
|
||||
kzg_proofs: VariableList::try_from(proofs)?,
|
||||
slot,
|
||||
beacon_block_root,
|
||||
})))
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
// Fulu variant
|
||||
let signed_block_header = block.signed_block_header();
|
||||
let kzg_commitments_inclusion_proof =
|
||||
block.message().body().kzg_commitments_merkle_proof()?;
|
||||
|
||||
columns
|
||||
.into_iter()
|
||||
.zip(column_kzg_proofs)
|
||||
.enumerate()
|
||||
.map(|(index, (col, proofs))| {
|
||||
Ok(Arc::new(DataColumnSidecar::Fulu(DataColumnSidecarFulu {
|
||||
index: index as u64,
|
||||
column: DataColumn::<E>::try_from(col)?,
|
||||
kzg_commitments: kzg_commitments.clone(),
|
||||
kzg_proofs: VariableList::try_from(proofs)?,
|
||||
signed_block_header: signed_block_header.clone(),
|
||||
kzg_commitments_inclusion_proof: kzg_commitments_inclusion_proof.clone(),
|
||||
})))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> DataColumnSidecarFulu<E> {
|
||||
pub fn slot(&self) -> Slot {
|
||||
self.signed_block_header.message.slot
|
||||
}
|
||||
|
||||
pub fn block_root(&self) -> Hash256 {
|
||||
self.signed_block_header.message.tree_hash_root()
|
||||
}
|
||||
@@ -132,6 +326,39 @@ impl<E: EthSpec> DataColumnSidecar<E> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: EthSpec> DataColumnSidecarGloas<E> {
|
||||
pub fn min_size() -> usize {
|
||||
// min size is one cell
|
||||
Self {
|
||||
index: 0,
|
||||
column: VariableList::new(vec![Cell::<E>::default()]).unwrap(),
|
||||
kzg_commitments: VariableList::new(vec![KzgCommitment::empty_for_testing()]).unwrap(),
|
||||
kzg_proofs: VariableList::new(vec![KzgProof::empty()]).unwrap(),
|
||||
slot: Slot::new(0),
|
||||
beacon_block_root: Hash256::ZERO,
|
||||
}
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
}
|
||||
|
||||
pub fn max_size(max_blobs_per_block: usize) -> usize {
|
||||
Self {
|
||||
index: 0,
|
||||
column: VariableList::new(vec![Cell::<E>::default(); max_blobs_per_block]).unwrap(),
|
||||
kzg_commitments: VariableList::new(vec![
|
||||
KzgCommitment::empty_for_testing();
|
||||
max_blobs_per_block
|
||||
])
|
||||
.unwrap(),
|
||||
kzg_proofs: VariableList::new(vec![KzgProof::empty(); max_blobs_per_block]).unwrap(),
|
||||
slot: Slot::new(0),
|
||||
beacon_block_root: Hash256::ZERO,
|
||||
}
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DataColumnSidecarError {
|
||||
ArithError(ArithError),
|
||||
@@ -145,6 +372,7 @@ pub enum DataColumnSidecarError {
|
||||
SszError(SszError),
|
||||
BuildSidecarFailed(String),
|
||||
InvalidCellProofLength { expected: usize, actual: usize },
|
||||
IncorrectStateVariant,
|
||||
}
|
||||
|
||||
impl From<ArithError> for DataColumnSidecarError {
|
||||
@@ -170,3 +398,43 @@ impl From<SszError> for DataColumnSidecarError {
|
||||
Self::SszError(e)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::core::{MainnetEthSpec, max_data_columns_by_root_request_common};
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use ssz_types::RuntimeVariableList;
|
||||
|
||||
// This is the "correct" implementation of max_data_columns_by_root_request.
|
||||
// This test ensures that the simplified implementation doesn't deviate from it.
|
||||
fn max_data_columns_by_root_request_implementation<E: EthSpec>(
|
||||
max_request_blocks: u64,
|
||||
) -> usize {
|
||||
let max_request_blocks = max_request_blocks as usize;
|
||||
|
||||
let empty_data_columns_by_root_id = DataColumnsByRootIdentifier {
|
||||
block_root: Hash256::zero(),
|
||||
columns: VariableList::repeat_full(0),
|
||||
};
|
||||
|
||||
RuntimeVariableList::<DataColumnsByRootIdentifier<E>>::new(
|
||||
vec![empty_data_columns_by_root_id; max_request_blocks],
|
||||
max_request_blocks,
|
||||
)
|
||||
.expect("creating a RuntimeVariableList of size `max_request_blocks` should succeed")
|
||||
.as_ssz_bytes()
|
||||
.len()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_data_columns_by_root_request_matches_simplified() {
|
||||
for n in [0, 1, 2, 8, 16, 32, 64, 128, 256, 512, 1024] {
|
||||
assert_eq!(
|
||||
max_data_columns_by_root_request_common::<MainnetEthSpec>(n),
|
||||
max_data_columns_by_root_request_implementation::<MainnetEthSpec>(n),
|
||||
"Mismatch at n={n}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,3 +72,9 @@ impl From<&DataColumnSubnetId> for u64 {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_data_column_sidecar_subnets_from_spec(
|
||||
spec: &ChainSpec,
|
||||
) -> impl Iterator<Item = DataColumnSubnetId> {
|
||||
(0..spec.data_column_sidecar_subnet_count).map(DataColumnSubnetId::new)
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@ pub use data_column_custody_group::{
|
||||
};
|
||||
pub use data_column_sidecar::{
|
||||
Cell, ColumnIndex, DataColumn, DataColumnSidecar, DataColumnSidecarError,
|
||||
DataColumnSidecarList, DataColumnsByRootIdentifier,
|
||||
DataColumnSidecarFulu, DataColumnSidecarGloas, DataColumnSidecarList,
|
||||
DataColumnsByRootIdentifier,
|
||||
};
|
||||
pub use data_column_subnet_id::DataColumnSubnetId;
|
||||
pub use data_column_subnet_id::{DataColumnSubnetId, all_data_column_sidecar_subnets_from_spec};
|
||||
|
||||
use crate::core::EthSpec;
|
||||
use ssz_types::FixedVector;
|
||||
|
||||
Reference in New Issue
Block a user