diff --git a/types/src/config.rs b/types/src/config.rs index a4cf9d5..19c0cc9 100644 --- a/types/src/config.rs +++ b/types/src/config.rs @@ -67,6 +67,8 @@ pub struct Config { #[serde(with = "serde_utils::string_or_native")] pub electra_fork_epoch: Epoch, pub electra_fork_version: Version, + #[serde(with = "serde_utils::string_or_native")] + pub eip7594_fork_epoch: Epoch, // Time parameters #[serde(with = "serde_utils::string_or_native")] @@ -135,6 +137,8 @@ pub struct Config { pub min_epochs_for_blob_sidecars_requests: u64, #[serde(with = "serde_utils::string_or_native")] pub blob_sidecar_subnet_count: u64, + #[serde(with = "serde_utils::string_or_native")] + pub data_column_sidecar_subnet_count: u64, // Transition pub terminal_block_hash: ExecutionBlockHash, @@ -142,6 +146,12 @@ pub struct Config { pub terminal_block_hash_activation_epoch: Epoch, pub terminal_total_difficulty: Difficulty, + // Custody + #[serde(with = "serde_utils::string_or_native")] + pub custody_requirement: u64, + #[serde(with = "serde_utils::string_or_native")] + pub samples_per_slot: u64, + // Later phases and other unknown variables // // Collect unknown variables in a map so we can log a warning about them. @@ -181,6 +191,7 @@ impl Default for Config { deneb_fork_version: H32(hex!("04000000")), electra_fork_epoch: FAR_FUTURE_EPOCH, electra_fork_version: H32(hex!("05000000")), + eip7594_fork_epoch: FAR_FUTURE_EPOCH, // Time parameters eth1_follow_distance: 2048, @@ -222,6 +233,7 @@ impl Default for Config { max_request_blob_sidecars: 768, min_epochs_for_blob_sidecars_requests: 4096, blob_sidecar_subnet_count: 6, + data_column_sidecar_subnet_count: 64, // Transition terminal_block_hash: ExecutionBlockHash::zero(), @@ -230,6 +242,10 @@ impl Default for Config { "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc00" )), + // Custody + custody_requirement: 4, + samples_per_slot: 16, + // Later phases and other unknown variables unknown: BTreeMap::new(), } @@ -687,6 +703,11 @@ impl Config { .map(|(phase, _)| phase) } + #[must_use] + pub const fn is_eip7594_fork(&self, epoch: Epoch) -> bool { + epoch >= self.eip7594_fork_epoch + } + fn fork_slots(&self) -> impl Iterator)> + '_ { enum_iterator::all().map(|phase| (phase, self.fork_slot::

(phase))) } diff --git a/types/src/eip7594.rs b/types/src/eip7594.rs new file mode 100644 index 0000000..6a7f707 --- /dev/null +++ b/types/src/eip7594.rs @@ -0,0 +1,143 @@ +use core::fmt; + +use serde::{Deserialize, Serialize}; +use ssz::{ByteVector, ContiguousList, ContiguousVector, Ssz, SszHash as _, H256}; +use typenum::{Prod, U128, U4, U64}; + +use crate::{ + deneb::{ + consts::BytesPerFieldElement, + primitives::{KzgCommitment, KzgProof}, + }, + phase0::containers::SignedBeaconBlockHeader, + preset::Preset, +}; + +type FieldElementsPerCell = U64; +type BytesPerCell = Prod; + +pub type ColumnIndex = u64; +pub type Cell = Box>; +pub type NumberOfColumns = U128; + +type DataColumn

= ContiguousList::MaxBlobCommitmentsPerBlock>; + +pub type KzgCommitmentsInclusionProofDepth = U4; + +pub type BlobCommitmentsInclusionProof = ContiguousVector; + +pub const CUSTODY_REQUIREMENT: u64 = 4; +pub const DATA_COLUMN_SIDECAR_SUBNET_COUNT: u64 = 32; +pub const SAMPLES_PER_SLOT: u64 = 16; + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Deserialize, Serialize, Ssz)] +#[serde(deny_unknown_fields)] +pub struct DataColumnIdentifier { + pub block_root: H256, + #[serde(with = "serde_utils::string_or_native")] + pub index: ColumnIndex, +} + +#[derive(Clone, Default, PartialEq, Eq, Deserialize, Serialize, Ssz)] +#[serde(bound = "", deny_unknown_fields)] +pub struct DataColumnSidecar { + #[serde(with = "serde_utils::string_or_native")] + pub index: ColumnIndex, + pub column: DataColumn

, + pub kzg_commitments: ContiguousList, + pub kzg_proofs: ContiguousList, + pub signed_block_header: SignedBeaconBlockHeader, + pub kzg_commitments_inclusion_proof: BlobCommitmentsInclusionProof, +} + +impl DataColumnSidecar

{ + #[must_use] + pub const fn slot(&self) -> u64 { + self.signed_block_header.message.slot + } + + #[must_use] + pub fn full() -> Self { + Self { + column: DataColumn::

::full(Box::default()), + kzg_commitments: ContiguousList::full(KzgCommitment::repeat_byte(u8::MAX)), + kzg_proofs: ContiguousList::full(KzgProof::repeat_byte(u8::MAX)), + ..Default::default() + } + } +} + +impl fmt::Debug for DataColumnSidecar

{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DataColumnSidecar") + .field("index", &self.index) + .field( + "kzg_commitments_inclusion_proof", + &self.kzg_commitments_inclusion_proof, + ) + .field("signed_block_header", &self.signed_block_header) + .field("kzg_commitments", &self.kzg_commitments) + .finish() + } +} + +impl From<&DataColumnSidecar

> for DataColumnIdentifier { + fn from(sidecar: &DataColumnSidecar

) -> Self { + let DataColumnSidecar { + index, + signed_block_header, + .. + } = *sidecar; + + let block_header = signed_block_header.message; + let block_root = block_header.hash_tree_root(); + + Self { block_root, index } + } +} + +#[cfg(test)] +mod tests { + use spec_test_utils::Case; + use test_generator::test_resources; + + use crate::{ + preset::{Mainnet, Minimal}, + unphased::spec_tests, + }; + + macro_rules! tests_for_type { + ( + $type: ident $(<_ $bracket: tt)?, + $mainnet_glob: literal, + $minimal_glob: literal, + ) => { + #[allow(non_snake_case)] + mod $type { + use super::*; + + #[test_resources($mainnet_glob)] + fn mainnet(case: Case) { + spec_tests::run_spec_test_case::(case); + } + + #[test_resources($minimal_glob)] + fn minimal(case: Case) { + spec_tests::run_spec_test_case::(case); + } + } + }; + } + + tests_for_type! { + DataColumnIdentifier, + "consensus-spec-tests/tests/mainnet/eip7594/ssz_static/DataColumnIdentifier/*/*", + "consensus-spec-tests/tests/minimal/eip7594/ssz_static/DataColumnIdentifier/*/*", + } + + tests_for_type! { + DataColumnSidecar<_>, + "consensus-spec-tests/tests/mainnet/eip7594/ssz_static/DataColumnSidecar/*/*", + "consensus-spec-tests/tests/minimal/eip7594/ssz_static/DataColumnSidecar/*/*", + } +} diff --git a/types/src/lib.rs b/types/src/lib.rs index a68d286..221b4b3 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -64,6 +64,8 @@ pub mod deneb { mod spec_tests; } +pub mod eip7594; + pub mod electra { pub mod beacon_state; pub mod consts; diff --git a/types/src/nonstandard.rs b/types/src/nonstandard.rs index e85dc29..769a566 100644 --- a/types/src/nonstandard.rs +++ b/types/src/nonstandard.rs @@ -24,6 +24,7 @@ use crate::{ containers::{BlobIdentifier, BlobSidecar}, primitives::{Blob, KzgCommitment, KzgProof}, }, + eip7594::{DataColumnIdentifier, DataColumnSidecar}, phase0::primitives::{Gwei, Uint256, UnixSeconds, ValidatorIndex, H256}, preset::Preset, }; @@ -193,6 +194,12 @@ pub struct BlockRewards { pub attester_slashings: Gwei, } +#[derive(Clone, Debug)] +pub struct DataColumnSidecarWithId { + pub data_column_sidecar: Arc>, + pub data_column_id: DataColumnIdentifier, +} + #[derive(Clone, Copy)] pub struct Participation { pub previous: ParticipationFlags, diff --git a/types/src/preset.rs b/types/src/preset.rs index d925695..b913802 100644 --- a/types/src/preset.rs +++ b/types/src/preset.rs @@ -27,6 +27,7 @@ use crate::{ consts::BytesPerFieldElement, primitives::{Blob, KzgCommitment, KzgProof}, }, + eip7594::Cell, electra::containers::{ Attestation as ElectraAttestation, AttesterSlashing as ElectraAttesterSlashing, ConsolidationRequest, DepositRequest, PendingBalanceDeposit, PendingConsolidation, @@ -112,7 +113,12 @@ pub trait Preset: Copy + Eq + Ord + Hash + Default + Debug + Send + Sync + 'stat + ArrayLengthCopy + Debug + Eq; - type MaxBlobCommitmentsPerBlock: MerkleElements + Eq + Debug + Send + Sync; + type MaxBlobCommitmentsPerBlock: MerkleElements + + MerkleElements + + Eq + + Debug + + Send + + Sync; type MaxBlobsPerBlock: MerkleElements> + MerkleElements + MerkleElements