From e21a433748251ea719f93b5aaf21b39a900f19be Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Thu, 27 Nov 2025 10:00:21 +1100 Subject: [PATCH] Allow manual checkpoint sync without blobs (#8470) Since merging this PR, we don't need `--checkpoint-blobs`, even prior to Fulu: - https://github.com/sigp/lighthouse/pull/8417 This PR removes the mandatory check for blobs prior to Fulu, enabling simpler manual checkpoint sync. Co-Authored-By: Michael Sproul Co-Authored-By: Jimmy Chen --- beacon_node/beacon_chain/tests/store_tests.rs | 29 ++++++++++++++----- beacon_node/client/src/builder.rs | 11 ++----- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/beacon_node/beacon_chain/tests/store_tests.rs b/beacon_node/beacon_chain/tests/store_tests.rs index cf175a56d7..0733d901fc 100644 --- a/beacon_node/beacon_chain/tests/store_tests.rs +++ b/beacon_node/beacon_chain/tests/store_tests.rs @@ -2705,7 +2705,7 @@ async fn weak_subjectivity_sync_easy() { let num_initial_slots = E::slots_per_epoch() * 11; let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9); let slots = (1..num_initial_slots).map(Slot::new).collect(); - weak_subjectivity_sync_test(slots, checkpoint_slot, None).await + weak_subjectivity_sync_test(slots, checkpoint_slot, None, true).await } #[tokio::test] @@ -2713,7 +2713,7 @@ async fn weak_subjectivity_sync_single_block_batches() { let num_initial_slots = E::slots_per_epoch() * 11; let checkpoint_slot = Slot::new(E::slots_per_epoch() * 9); let slots = (1..num_initial_slots).map(Slot::new).collect(); - weak_subjectivity_sync_test(slots, checkpoint_slot, Some(1)).await + weak_subjectivity_sync_test(slots, checkpoint_slot, Some(1), true).await } #[tokio::test] @@ -2727,7 +2727,7 @@ async fn weak_subjectivity_sync_unaligned_advanced_checkpoint() { slot <= checkpoint_slot - 3 || slot > checkpoint_slot }) .collect(); - weak_subjectivity_sync_test(slots, checkpoint_slot, None).await + weak_subjectivity_sync_test(slots, checkpoint_slot, None, true).await } #[tokio::test] @@ -2741,7 +2741,7 @@ async fn weak_subjectivity_sync_unaligned_unadvanced_checkpoint() { slot <= checkpoint_slot || slot > checkpoint_slot + 3 }) .collect(); - weak_subjectivity_sync_test(slots, checkpoint_slot, None).await + weak_subjectivity_sync_test(slots, checkpoint_slot, None, true).await } // Regression test for https://github.com/sigp/lighthouse/issues/4817 @@ -2753,7 +2753,7 @@ async fn weak_subjectivity_sync_skips_at_genesis() { let end_slot = E::slots_per_epoch() * 4; let slots = (start_slot..end_slot).map(Slot::new).collect(); let checkpoint_slot = Slot::new(E::slots_per_epoch() * 2); - weak_subjectivity_sync_test(slots, checkpoint_slot, None).await + weak_subjectivity_sync_test(slots, checkpoint_slot, None, true).await } // Checkpoint sync from the genesis state. @@ -2766,13 +2766,24 @@ async fn weak_subjectivity_sync_from_genesis() { let end_slot = E::slots_per_epoch() * 2; let slots = (start_slot..end_slot).map(Slot::new).collect(); let checkpoint_slot = Slot::new(0); - weak_subjectivity_sync_test(slots, checkpoint_slot, None).await + weak_subjectivity_sync_test(slots, checkpoint_slot, None, true).await +} + +// Test checkpoint sync without providing blobs - backfill should fetch them. +#[tokio::test] +async fn weak_subjectivity_sync_without_blobs() { + let start_slot = 4; + let end_slot = E::slots_per_epoch() * 4; + let slots = (start_slot..end_slot).map(Slot::new).collect(); + let checkpoint_slot = Slot::new(E::slots_per_epoch() * 2); + weak_subjectivity_sync_test(slots, checkpoint_slot, None, false).await } async fn weak_subjectivity_sync_test( slots: Vec, checkpoint_slot: Slot, backfill_batch_size: Option, + provide_blobs: bool, ) { // Build an initial chain on one harness, representing a synced node with full history. let num_final_blocks = E::slots_per_epoch() * 2; @@ -2874,7 +2885,11 @@ async fn weak_subjectivity_sync_test( .weak_subjectivity_state( wss_state, wss_block.clone(), - wss_blobs_opt.clone(), + if provide_blobs { + wss_blobs_opt.clone() + } else { + None + }, genesis_state, ) .unwrap() diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 380e0c114a..bac61fc735 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -354,15 +354,10 @@ where let anchor_block = SignedBeaconBlock::from_ssz_bytes(&anchor_block_bytes, &spec) .map_err(|e| format!("Unable to parse weak subj block SSZ: {:?}", e))?; - // `BlobSidecar` is no longer used from Fulu onwards (superseded by `DataColumnSidecar`), - // which will be fetched via rpc instead (unimplemented). - let is_before_fulu = !spec - .fork_name_at_slot::(anchor_block.slot()) - .fulu_enabled(); - let anchor_blobs = if is_before_fulu && anchor_block.message().body().has_blobs() { + // Providing blobs is optional now and not providing them is recommended. + // Backfill can handle downloading the blobs or columns for the checkpoint block. + let anchor_blobs = if let Some(anchor_blobs_bytes) = anchor_blobs_bytes { let max_blobs_len = spec.max_blobs_per_block(anchor_block.epoch()) as usize; - let anchor_blobs_bytes = anchor_blobs_bytes - .ok_or("Blobs for checkpoint must be provided using --checkpoint-blobs")?; Some( BlobSidecarList::from_ssz_bytes(&anchor_blobs_bytes, max_blobs_len) .map_err(|e| format!("Unable to parse weak subj blobs SSZ: {e:?}"))?,