diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 64ef5ef17e5..bd1c83ebb33 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -7146,6 +7146,11 @@ impl BeaconChain { let end_slot = start_slot.saturating_add(count); let mut roots = vec![]; + // let's explicitly check count = 0 since it's a public function for readabiilty purpose. + if count == 0 { + return roots; + } + for (root, slot) in block_roots_iter { if slot < end_slot && slot >= start_slot { roots.push(root); diff --git a/beacon_node/network/src/network_beacon_processor/rpc_methods.rs b/beacon_node/network/src/network_beacon_processor/rpc_methods.rs index bc97f884922..3aae137780e 100644 --- a/beacon_node/network/src/network_beacon_processor/rpc_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/rpc_methods.rs @@ -880,8 +880,16 @@ impl NetworkBeaconProcessor { "Received BlobsByRange Request" ); + if req.count == 0 { + return Err((RpcErrorResponse::InvalidRequest, "Request count is zero")); + } + + let mut req = req; let request_start_slot = Slot::from(req.start_slot); + let request_end_slot = Slot::from(req.start_slot + req.count - 1); + let request_end_epoch = request_end_slot.epoch(T::EthSpec::slots_per_epoch()); + // Check Deneb is enabled. Blobs are available since then. let data_availability_boundary_slot = match self.chain.data_availability_boundary() { Some(boundary) => boundary.start_slot(T::EthSpec::slots_per_epoch()), None => { @@ -917,6 +925,15 @@ impl NetworkBeaconProcessor { }; } + // Check Fulu/PeerDAS is in the range. Blobs are not served since then. + if self.chain.spec.is_peer_das_enabled_for_epoch(request_end_epoch) { + // Fulu epoch is Some type by the condition above. + let fulu_epoch = self.chain.spec.fulu_fork_epoch.unwrap(); + let fulu_start_slot = fulu_epoch.start_slot(T::EthSpec::slots_per_epoch()); + // See the justification for the formula in PR https://github.com/sigp/lighthouse/pull/7328 + req.count = fulu_start_slot.as_u64().saturating_sub(req.start_slot); + } + let block_roots = self.get_block_roots_for_slot_range(req.start_slot, req.count, "BlobsByRange")?; diff --git a/beacon_node/network/src/network_beacon_processor/tests.rs b/beacon_node/network/src/network_beacon_processor/tests.rs index 292e894870f..87a55589432 100644 --- a/beacon_node/network/src/network_beacon_processor/tests.rs +++ b/beacon_node/network/src/network_beacon_processor/tests.rs @@ -1,4 +1,4 @@ -#![cfg(not(debug_assertions))] // Tests are too slow in debug. +//#![cfg(not(debug_assertions))] // Tests are too slow in debug. #![cfg(test)] use crate::{ @@ -26,11 +26,12 @@ use lighthouse_network::{ Client, MessageId, NetworkConfig, NetworkGlobals, PeerId, Response, }; use slot_clock::SlotClock; +use tracing::debug; use std::iter::Iterator; use std::sync::Arc; use std::time::Duration; use tokio::sync::mpsc; -use types::blob_sidecar::FixedBlobSidecarList; +use types::{blob_sidecar::FixedBlobSidecarList, ChainSpec}; use types::{ Attestation, AttesterSlashing, BlobSidecar, BlobSidecarList, DataColumnSidecarList, DataColumnSubnetId, Epoch, Hash256, MainnetEthSpec, ProposerSlashing, SignedAggregateAndProof, @@ -91,11 +92,28 @@ impl TestRig { } pub async fn new_parametric(chain_length: u64, enable_backfill_rate_limiting: bool) -> Self { - // This allows for testing voluntary exits without building out a massive chain. let mut spec = test_spec::(); spec.shard_committee_period = 2; let spec = Arc::new(spec); + Self::new_parametric_inner(spec, chain_length, enable_backfill_rate_limiting).await + } + + pub async fn new_parametric_with_custom_fulu_epoch( + chain_length: u64, + enable_backfill_rate_limiting: bool, + fulu_epoch: Epoch + ) -> Self { + let mut spec = test_spec::(); + spec.shard_committee_period = 2; + spec.fulu_fork_epoch = Some(fulu_epoch); + let spec = Arc::new(spec); + + Self::new_parametric_inner(spec, chain_length, enable_backfill_rate_limiting).await + } + + async fn new_parametric_inner(spec: Arc, chain_length: u64, enable_backfill_rate_limiting: bool) -> Self { + // This allows for testing voluntary exits without building out a massive chain. let harness = BeaconChainHarness::builder(MainnetEthSpec) .spec(spec.clone()) .deterministic_keypairs(VALIDATOR_COUNT) @@ -429,13 +447,13 @@ impl TestRig { } } - pub fn enqueue_blobs_by_range_request(&self, count: u64) { + pub fn enqueue_blobs_by_range_request(&self, start_slot: u64, count: u64) { self.network_beacon_processor .send_blobs_by_range_request( PeerId::random(), InboundRequestId::new_unchecked(42, 24), BlobsByRangeRequest { - start_slot: 0, + start_slot, count, }, ) @@ -1211,21 +1229,21 @@ async fn test_backfill_sync_processing_rate_limiting_disabled() { .await; } -#[tokio::test] -async fn test_blobs_by_range() { - if test_spec::().deneb_fork_epoch.is_none() { - return; - }; - let mut rig = TestRig::new(64).await; - let slot_count = 32; - rig.enqueue_blobs_by_range_request(slot_count); +async fn test_blobs_by_range( + rig: &mut TestRig, + start_slot: u64, + slot_count: u64, + //blob_count_expected: usize, +) { + rig.enqueue_blobs_by_range_request(start_slot, slot_count); let mut blob_count = 0; - for slot in 0..slot_count { + for slot in start_slot..slot_count { let root = rig .chain .block_root_at_slot(Slot::new(slot), WhenSlotSkipped::None) .unwrap(); + debug!("slot and root {} {:?}", slot, root); blob_count += root .map(|root| { rig.chain @@ -1252,5 +1270,55 @@ async fn test_blobs_by_range() { panic!("unexpected message {:?}", next); } } + debug!("{} {} {} {}", start_slot, slot_count, blob_count, actual_count); assert_eq!(blob_count, actual_count); } + +#[tokio::test] +async fn test_blobs_by_range_pre_fulu() { + if test_spec::().deneb_fork_epoch.is_none() { + return; + }; + let rig_slot = 64; + let mut rig = TestRig::new(rig_slot).await; + let slot_count = 32; + test_blobs_by_range(&mut rig, 0, slot_count).await; + test_blobs_by_range(&mut rig, 0, slot_count).await; + test_blobs_by_range(&mut rig, 0, 16).await; + test_blobs_by_range(&mut rig, 8, 16).await; + test_blobs_by_range(&mut rig, 32, slot_count).await; +} + +#[tokio::test] +async fn test_blobs_by_range_fulu() { + //if !test_spec::().is_peer_das_scheduled() { + // return; + //} + + let fulu_epoch = Slot::new(SLOTS_PER_EPOCH * 4).epoch(SLOTS_PER_EPOCH); + + let pre_fulu_start_slot = 0;//SLOTS_PER_EPOCH;// + (3 % SLOTS_PER_EPOCH); + let fulu_start_slot = SLOTS_PER_EPOCH * 6;// + (7 % SLOTS_PER_EPOCH); + let slot_count = SLOTS_PER_EPOCH;// + 1; + let slot_count_long = SLOTS_PER_EPOCH * 5;// + (2 % SLOTS_PER_EPOCH); + + let test_cases = vec![ + (0, slot_count_long), + //(pre_fulu_start_slot, slot_count), + //(pre_fulu_start_slot, 0), + //(pre_fulu_start_slot, slot_count_long), + //(fulu_start_slot, slot_count), + //(fulu_start_slot, 0), + ]; + + for (start_slot, count) in test_cases { + let mut rig = TestRig::new_parametric_with_custom_fulu_epoch( + SLOTS_PER_EPOCH * 8, + BeaconProcessorConfig::default().enable_backfill_rate_limiting, + fulu_epoch, + ) + .await; + + test_blobs_by_range(&mut rig, start_slot, count).await; + } +}