diff --git a/Cargo.toml b/Cargo.toml index b2044f8e..e4a56794 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -333,6 +333,7 @@ git-version = '0.3' glob = '0.3' good_lp = { version = '1', default-features = false, features = ['highs'] } hash_hasher = '2' +hashlink = '0.9' hex = { version = '0.4', features = ['serde'] } hex-literal = '0.4' hex_fmt = '0.3' diff --git a/eth2_libp2p b/eth2_libp2p index 2fa0806d..cd94317b 160000 --- a/eth2_libp2p +++ b/eth2_libp2p @@ -1 +1 @@ -Subproject commit 2fa0806de801602c2594a75e4dbb53d242676a3f +Subproject commit cd94317bcf623e7f501cfd5370423bd95fdaff65 diff --git a/fork_choice_control/src/helpers.rs b/fork_choice_control/src/helpers.rs index 6560ebe8..9b62421d 100644 --- a/fork_choice_control/src/helpers.rs +++ b/fork_choice_control/src/helpers.rs @@ -253,7 +253,7 @@ impl Context

{ } pub fn on_blob_sidecar(&mut self, blob_sidecar: BlobSidecar

) -> Option> { - let subnet_id = misc::compute_subnet_for_blob_sidecar(blob_sidecar.index); + let subnet_id = misc::compute_subnet_for_blob_sidecar(self.config(), blob_sidecar.index); self.controller().on_gossip_blob_sidecar( Arc::new(blob_sidecar), diff --git a/fork_choice_store/src/store.rs b/fork_choice_store/src/store.rs index 7681ab81..66f3e969 100644 --- a/fork_choice_store/src/store.rs +++ b/fork_choice_store/src/store.rs @@ -1722,7 +1722,8 @@ impl Store

{ // [REJECT] The sidecar is for the correct subnet -- i.e. compute_subnet_for_blob_sidecar(blob_sidecar.index) == subnet_id. if let Some(actual) = origin.subnet_id() { - let expected = misc::compute_subnet_for_blob_sidecar(blob_sidecar.index); + let expected = + misc::compute_subnet_for_blob_sidecar(&self.chain_config, blob_sidecar.index); ensure!( actual == expected, diff --git a/helper_functions/src/misc.rs b/helper_functions/src/misc.rs index c5818a64..a730d935 100644 --- a/helper_functions/src/misc.rs +++ b/helper_functions/src/misc.rs @@ -17,7 +17,7 @@ use types::{ combined::{Attestation, SignedBeaconBlock}, config::Config, deneb::{ - consts::{BlobCommitmentTreeDepth, BlobSidecarSubnetCount, VERSIONED_HASH_VERSION_KZG}, + consts::{BlobCommitmentTreeDepth, VERSIONED_HASH_VERSION_KZG}, containers::BlobSidecar, primitives::{ Blob, BlobCommitmentInclusionProof, BlobIndex, KzgCommitment, KzgProof, VersionedHash, @@ -204,8 +204,8 @@ pub fn compute_subnet_for_attestation( /// [`compute_subnet_for_blob_sidecar`](https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.1/specs/deneb/validator.md#sidecar) #[must_use] -pub fn compute_subnet_for_blob_sidecar(blob_index: BlobIndex) -> SubnetId { - blob_index.mod_typenum::() +pub const fn compute_subnet_for_blob_sidecar(config: &Config, blob_index: BlobIndex) -> SubnetId { + blob_index % config.blob_sidecar_subnet_count } /// diff --git a/p2p/src/network.rs b/p2p/src/network.rs index 16017abe..9f8eb6e9 100644 --- a/p2p/src/network.rs +++ b/p2p/src/network.rs @@ -534,7 +534,11 @@ impl Network

{ } fn publish_blob_sidecar(&self, blob_sidecar: Arc>) { - let subnet_id = misc::compute_subnet_for_blob_sidecar(blob_sidecar.index); + let subnet_id = misc::compute_subnet_for_blob_sidecar( + self.controller.chain_config(), + blob_sidecar.index, + ); + let blob_identifier: BlobIdentifier = blob_sidecar.as_ref().into(); debug!("publishing blob sidecar: {blob_identifier:?}, subnet_id: {subnet_id}"); @@ -843,22 +847,32 @@ impl Network

{ self.handle_blocks_by_root_request(peer_id, peer_request_id, request_id, request); Ok(()) } + RequestType::DataColumnsByRange(_) => { + debug!("received DataColumnsByRange request (peer_id: {peer_id})"); + Ok(()) + } + RequestType::DataColumnsByRoot(_) => { + debug!("received DataColumnsByRoot request (peer_id: {peer_id})"); + Ok(()) + } RequestType::LightClientBootstrap(_) => { // TODO(Altair Light Client Sync Protocol) debug!("received LightClientBootstrap request (peer_id: {peer_id})"); - Ok(()) } RequestType::LightClientFinalityUpdate => { // TODO(Altair Light Client Sync Protocol) debug!("received LightClientFinalityUpdate request (peer_id: {peer_id})"); - Ok(()) } RequestType::LightClientOptimisticUpdate => { // TODO(Altair Light Client Sync Protocol) debug!("received LightClientOptimisticUpdate request (peer_id: {peer_id})"); - + Ok(()) + } + RequestType::LightClientUpdatesByRange(_) => { + // TODO(Altair Light Client Sync Protocol) + debug!("received LightClientUpdatesByRange request (peer_id: {peer_id})"); Ok(()) } RequestType::BlobsByRange(request) => { @@ -1290,6 +1304,7 @@ impl Network

{ request_id: {request_id}", ); } + Response::DataColumnsByRange(_) | Response::DataColumnsByRoot(_) => {} Response::LightClientBootstrap(_) => { // TODO(Altair Light Client Sync Protocol) debug!("received LightClientBootstrap response chunk (peer_id: {peer_id})"); @@ -1302,6 +1317,10 @@ impl Network

{ // TODO(Altair Light Client Sync Protocol) debug!("received LightClientOptimisticUpdate response (peer_id: {peer_id})"); } + Response::LightClientUpdatesByRange(_) => { + // TODO(Altair Light Client Sync Protocol) + debug!("received LightClientUpdatesByRange response (peer_id: {peer_id})"); + } } } @@ -1372,9 +1391,7 @@ impl Network

{ block_seen, ); } - PubsubMessage::DataColumnSidecar(_) => { - // TODO - } + PubsubMessage::DataColumnSidecar(_) => {} PubsubMessage::AggregateAndProofAttestation(aggregate_and_proof) => { if let Some(metrics) = self.metrics.as_ref() { metrics.register_gossip_object(&["aggregate_and_proof_attestation"]); @@ -1725,7 +1742,7 @@ impl Network

{ let current_phase = self.fork_context.current_fork(); - for kind in core_topics_to_subscribe(current_phase) + for kind in core_topics_to_subscribe(self.controller.chain_config(), current_phase) .iter() .filter(|kind| !subscribed_topics.contains(kind)) .cloned() diff --git a/types/src/combined.rs b/types/src/combined.rs index fefe566c..37e6881a 100644 --- a/types/src/combined.rs +++ b/types/src/combined.rs @@ -19,6 +19,7 @@ use crate::{ BeaconBlock as AltairBeaconBlock, LightClientBootstrap as AltairLightClientBootstrap, LightClientFinalityUpdate as AltairLightClientFinalityUpdate, LightClientOptimisticUpdate as AltairLightClientOptimisticUpdate, + LightClientUpdate as AltairLightClientUpdate, SignedBeaconBlock as AltairSignedBeaconBlock, }, }, @@ -41,6 +42,7 @@ use crate::{ LightClientBootstrap as CapellaLightClientBootstrap, LightClientFinalityUpdate as CapellaLightClientFinalityUpdate, LightClientOptimisticUpdate as CapellaLightClientOptimisticUpdate, + LightClientUpdate as CapellaLightClientUpdate, SignedBeaconBlock as CapellaSignedBeaconBlock, SignedBlindedBeaconBlock as CapellaSignedBlindedBeaconBlock, }, @@ -55,6 +57,7 @@ use crate::{ LightClientBootstrap as DenebLightClientBootstrap, LightClientFinalityUpdate as DenebLightClientFinalityUpdate, LightClientOptimisticUpdate as DenebLightClientOptimisticUpdate, + LightClientUpdate as DenebLightClientUpdate, SignedBeaconBlock as DenebSignedBeaconBlock, SignedBlindedBeaconBlock as DenebSignedBlindedBeaconBlock, }, @@ -69,6 +72,7 @@ use crate::{ LightClientBootstrap as ElectraLightClientBootstrap, LightClientFinalityUpdate as ElectraLightClientFinalityUpdate, LightClientOptimisticUpdate as ElectraLightClientOptimisticUpdate, + LightClientUpdate as ElectraLightClientUpdate, SignedAggregateAndProof as ElectraSignedAggregateAndProof, SignedBeaconBlock as ElectraSignedBeaconBlock, SignedBlindedBeaconBlock as ElectraSignedBlindedBeaconBlock, @@ -1214,6 +1218,64 @@ impl SszWrite for LightClientOptimisticUpdate

{ } } +#[derive(Clone, PartialEq, Eq, Debug)] +pub enum LightClientUpdate { + // Boxed to pass `clippy::large_enum_variant`. + Altair(Box>), + Capella(Box>), + Deneb(Box>), + Electra(Box>), +} + +// It is difficult to implement `SszRead` for the combined `LightClientUpdate`. +// `attested_header` starts with a slot, but `LightClientHeader` becomes variable-size in Capella. +// It is possible to distinguish variants of `LightClientUpdate` by length as of Capella, +// but it becomes more difficult in Deneb and may become impossible in later phases. +assert_not_impl_any!(LightClientUpdate: SszRead); + +impl SszSize for LightClientUpdate

{ + // The const parameter should be `Self::VARIANT_COUNT`, but `Self` refers to a generic type. + // Type parameters cannot be used in `const` contexts until `generic_const_exprs` is stable. + const SIZE: Size = Size::for_untagged_union::<{ Phase::CARDINALITY - 2 }>([ + AltairLightClientUpdate::

::SIZE, + CapellaLightClientUpdate::

::SIZE, + DenebLightClientUpdate::

::SIZE, + ElectraLightClientUpdate::

::SIZE, + ]); +} + +impl SszWrite for LightClientUpdate

{ + fn write_variable(&self, bytes: &mut Vec) -> Result<(), WriteError> { + match self { + Self::Altair(update) => { + let size = AltairLightClientUpdate::

::SIZE.get(); + let length_before = bytes.len(); + let length_after = length_before + size; + + bytes.resize(length_after, 0); + update.write_fixed(&mut bytes[length_before..]); + + Ok(()) + } + Self::Capella(update) => update.write_variable(bytes), + Self::Deneb(update) => update.write_variable(bytes), + Self::Electra(update) => update.write_variable(bytes), + } + } +} + +impl LightClientUpdate

{ + #[must_use] + pub fn signature_slot(&self) -> Slot { + match self { + Self::Altair(update) => update.signature_slot, + Self::Capella(update) => update.signature_slot, + Self::Deneb(update) => update.signature_slot, + Self::Electra(update) => update.signature_slot, + } + } +} + #[derive(Clone, PartialEq, Eq, Debug, From, Deserialize, Serialize)] #[serde(bound = "", untagged)] pub enum AggregateAndProof { @@ -1591,30 +1653,40 @@ mod spec_tests { ["consensus-spec-tests/tests/minimal/altair/ssz_static/LightClientFinalityUpdate/*/*"] [altair_minimal_finality_update] [LightClientFinalityUpdate] [Minimal] [Altair]; ["consensus-spec-tests/tests/mainnet/altair/ssz_static/LightClientOptimisticUpdate/*/*"] [altair_mainnet_optimistic_update] [LightClientOptimisticUpdate] [Mainnet] [Altair]; ["consensus-spec-tests/tests/minimal/altair/ssz_static/LightClientOptimisticUpdate/*/*"] [altair_minimal_optimistic_update] [LightClientOptimisticUpdate] [Minimal] [Altair]; + ["consensus-spec-tests/tests/mainnet/altair/ssz_static/LightClientUpdate/*/*"] [altair_mainnet_update] [LightClientUpdate] [Mainnet] [Altair]; + ["consensus-spec-tests/tests/minimal/altair/ssz_static/LightClientUpdate/*/*"] [altair_minimal_update] [LightClientUpdate] [Minimal] [Altair]; ["consensus-spec-tests/tests/mainnet/bellatrix/ssz_static/LightClientBootstrap/*/*"] [bellatrix_mainnet_bootstrap] [LightClientBootstrap] [Mainnet] [Altair]; ["consensus-spec-tests/tests/minimal/bellatrix/ssz_static/LightClientBootstrap/*/*"] [bellatrix_minimal_bootstrap] [LightClientBootstrap] [Minimal] [Altair]; ["consensus-spec-tests/tests/mainnet/bellatrix/ssz_static/LightClientFinalityUpdate/*/*"] [bellatrix_mainnet_finality_update] [LightClientFinalityUpdate] [Mainnet] [Altair]; ["consensus-spec-tests/tests/minimal/bellatrix/ssz_static/LightClientFinalityUpdate/*/*"] [bellatrix_minimal_finality_update] [LightClientFinalityUpdate] [Minimal] [Altair]; ["consensus-spec-tests/tests/mainnet/bellatrix/ssz_static/LightClientOptimisticUpdate/*/*"] [bellatrix_mainnet_optimistic_update] [LightClientOptimisticUpdate] [Mainnet] [Altair]; ["consensus-spec-tests/tests/minimal/bellatrix/ssz_static/LightClientOptimisticUpdate/*/*"] [bellatrix_minimal_optimistic_update] [LightClientOptimisticUpdate] [Minimal] [Altair]; + ["consensus-spec-tests/tests/mainnet/bellatrix/ssz_static/LightClientUpdate/*/*"] [bellatrix_mainnet_update] [LightClientUpdate] [Mainnet] [Altair]; + ["consensus-spec-tests/tests/minimal/bellatrix/ssz_static/LightClientUpdate/*/*"] [bellatrix_minimal_update] [LightClientUpdate] [Minimal] [Altair]; ["consensus-spec-tests/tests/mainnet/capella/ssz_static/LightClientBootstrap/*/*"] [capella_mainnet_bootstrap] [LightClientBootstrap] [Mainnet] [Capella]; ["consensus-spec-tests/tests/minimal/capella/ssz_static/LightClientBootstrap/*/*"] [capella_minimal_bootstrap] [LightClientBootstrap] [Minimal] [Capella]; ["consensus-spec-tests/tests/mainnet/capella/ssz_static/LightClientFinalityUpdate/*/*"] [capella_mainnet_finality_update] [LightClientFinalityUpdate] [Mainnet] [Capella]; ["consensus-spec-tests/tests/minimal/capella/ssz_static/LightClientFinalityUpdate/*/*"] [capella_minimal_finality_update] [LightClientFinalityUpdate] [Minimal] [Capella]; ["consensus-spec-tests/tests/mainnet/capella/ssz_static/LightClientOptimisticUpdate/*/*"] [capella_mainnet_optimistic_update] [LightClientOptimisticUpdate] [Mainnet] [Capella]; ["consensus-spec-tests/tests/minimal/capella/ssz_static/LightClientOptimisticUpdate/*/*"] [capella_minimal_optimistic_update] [LightClientOptimisticUpdate] [Minimal] [Capella]; + ["consensus-spec-tests/tests/mainnet/capella/ssz_static/LightClientUpdate/*/*"] [capella_mainnet_update] [LightClientUpdate] [Mainnet] [Capella]; + ["consensus-spec-tests/tests/minimal/capella/ssz_static/LightClientUpdate/*/*"] [capella_minimal_update] [LightClientUpdate] [Minimal] [Capella]; ["consensus-spec-tests/tests/mainnet/deneb/ssz_static/LightClientBootstrap/*/*"] [deneb_mainnet_bootstrap] [LightClientBootstrap] [Mainnet] [Deneb]; ["consensus-spec-tests/tests/minimal/deneb/ssz_static/LightClientBootstrap/*/*"] [deneb_minimal_bootstrap] [LightClientBootstrap] [Minimal] [Deneb]; ["consensus-spec-tests/tests/mainnet/deneb/ssz_static/LightClientFinalityUpdate/*/*"] [deneb_mainnet_finality_update] [LightClientFinalityUpdate] [Mainnet] [Deneb]; ["consensus-spec-tests/tests/minimal/deneb/ssz_static/LightClientFinalityUpdate/*/*"] [deneb_minimal_finality_update] [LightClientFinalityUpdate] [Minimal] [Deneb]; ["consensus-spec-tests/tests/mainnet/deneb/ssz_static/LightClientOptimisticUpdate/*/*"] [deneb_mainnet_optimistic_update] [LightClientOptimisticUpdate] [Mainnet] [Deneb]; ["consensus-spec-tests/tests/minimal/deneb/ssz_static/LightClientOptimisticUpdate/*/*"] [deneb_minimal_optimistic_update] [LightClientOptimisticUpdate] [Minimal] [Deneb]; + ["consensus-spec-tests/tests/mainnet/deneb/ssz_static/LightClientUpdate/*/*"] [deneb_mainnet_update] [LightClientUpdate] [Mainnet] [Deneb]; + ["consensus-spec-tests/tests/minimal/deneb/ssz_static/LightClientUpdate/*/*"] [deneb_minimal_update] [LightClientUpdate] [Minimal] [Deneb]; ["consensus-spec-tests/tests/mainnet/electra/ssz_static/LightClientBootstrap/*/*"] [electra_mainnet_bootstrap] [LightClientBootstrap] [Mainnet] [Electra]; ["consensus-spec-tests/tests/minimal/electra/ssz_static/LightClientBootstrap/*/*"] [electra_minimal_bootstrap] [LightClientBootstrap] [Minimal] [Electra]; ["consensus-spec-tests/tests/mainnet/electra/ssz_static/LightClientFinalityUpdate/*/*"] [electra_mainnet_finality_update] [LightClientFinalityUpdate] [Mainnet] [Electra]; ["consensus-spec-tests/tests/minimal/electra/ssz_static/LightClientFinalityUpdate/*/*"] [electra_minimal_finality_update] [LightClientFinalityUpdate] [Minimal] [Electra]; ["consensus-spec-tests/tests/mainnet/electra/ssz_static/LightClientOptimisticUpdate/*/*"] [electra_mainnet_optimistic_update] [LightClientOptimisticUpdate] [Mainnet] [Electra]; ["consensus-spec-tests/tests/minimal/electra/ssz_static/LightClientOptimisticUpdate/*/*"] [electra_minimal_optimistic_update] [LightClientOptimisticUpdate] [Minimal] [Electra]; + ["consensus-spec-tests/tests/mainnet/electra/ssz_static/LightClientUpdate/*/*"] [electra_mainnet_update] [LightClientUpdate] [Mainnet] [Electra]; + ["consensus-spec-tests/tests/minimal/electra/ssz_static/LightClientUpdate/*/*"] [electra_minimal_update] [LightClientUpdate] [Minimal] [Electra]; )] #[test_resources(glob)] fn function_name(case: Case) { diff --git a/types/src/deneb/consts.rs b/types/src/deneb/consts.rs index 02ed3dfa..a49647d3 100644 --- a/types/src/deneb/consts.rs +++ b/types/src/deneb/consts.rs @@ -1,14 +1,11 @@ use hex_literal::hex; use ssz::MerkleElements; -use typenum::{U32, U6}; +use typenum::U32; use crate::{deneb::primitives::KzgCommitment, preset::Preset}; pub const VERSIONED_HASH_VERSION_KZG: &[u8] = &hex!("01"); -// TODO(feature/deneb): Can `BlobSidecarSubnetCount` be a `const`? -// It's never used as a type even in `eth2_libp2p`. -pub type BlobSidecarSubnetCount = U6; pub type BytesPerFieldElement = U32; pub type BlobCommitmentTreeDepth

= <