From a6607e52d5a244a900d3e49db8c464451f673862 Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Fri, 14 Nov 2025 21:59:50 -0300 Subject: [PATCH 01/13] Reimport the checkpoint sync block --- .../beacon_chain/src/block_verification.rs | 16 +++++-- .../beacon_chain/src/historical_blocks.rs | 46 +++++++------------ .../network_beacon_processor/sync_methods.rs | 3 +- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index 5078e24a51c..ad611fabf10 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -1685,14 +1685,20 @@ fn check_block_against_finalized_slot( // // Fork choice has the most up-to-date view of finalization and there's no point importing a // block which conflicts with the fork-choice view of finalization. - let finalized_slot = chain - .canonical_head - .cached_head() - .finalized_checkpoint() + let finalized_checkpoint = chain.canonical_head.cached_head().finalized_checkpoint(); + let finalized_slot = finalized_checkpoint .epoch .start_slot(T::EthSpec::slots_per_epoch()); - if block.slot() <= finalized_slot { + let would_revert_finalized_slot = if block.slot() < finalized_slot { + true + } else if block.slot() == finalized_slot { + block_root != finalized_checkpoint.root + } else { + false + }; + // Allow to re-import the finalized block if it's the same + if would_revert_finalized_slot { chain.pre_finalization_block_rejected(block_root); Err(BlockError::WouldRevertFinalizedSlot { block_slot: block.slot(), diff --git a/beacon_node/beacon_chain/src/historical_blocks.rs b/beacon_node/beacon_chain/src/historical_blocks.rs index 15e0a55cf5a..4aef2c771d2 100644 --- a/beacon_node/beacon_chain/src/historical_blocks.rs +++ b/beacon_node/beacon_chain/src/historical_blocks.rs @@ -56,42 +56,30 @@ impl BeaconChain { /// `SignatureSetError` or `InvalidSignature` will be returned. /// /// To align with sync we allow some excess blocks with slots greater than or equal to - /// `oldest_block_slot` to be provided. They will be ignored without being checked. + /// `oldest_block_slot` to be provided. They will be re-imported to fill the columns of the + /// checkpoint sync block. /// /// This function should not be called concurrently with any other function that mutates /// the anchor info (including this function itself). If a concurrent mutation occurs that /// would violate consistency then an `AnchorInfoConcurrentMutation` error will be returned. - /// - /// Return the number of blocks successfully imported. #[instrument(skip_all)] pub fn import_historical_block_batch( &self, - mut blocks: Vec>, - ) -> Result { + blocks: Vec>, + ) -> Result<(), HistoricalBlockError> { let anchor_info = self.store.get_anchor_info(); let blob_info = self.store.get_blob_info(); let data_column_info = self.store.get_data_column_info(); // Take all blocks with slots less than the oldest block slot. - let num_relevant = blocks.partition_point(|available_block| { - available_block.block().slot() < anchor_info.oldest_block_slot - }); - - let total_blocks = blocks.len(); - blocks.truncate(num_relevant); - let blocks_to_import = blocks; - - if blocks_to_import.len() != total_blocks { - debug!( - oldest_block_slot = %anchor_info.oldest_block_slot, - total_blocks, - ignored = total_blocks.saturating_sub(blocks_to_import.len()), - "Ignoring some historic blocks" - ); - } - - if blocks_to_import.is_empty() { - return Ok(0); + for block in &blocks { + if block.block().slot() >= anchor_info.oldest_block_slot { + debug!( + oldest_block_slot = %anchor_info.oldest_block_slot, + block_slot = %block.block().slot(), + "Reimporting historic block" + ); + } } let mut expected_block_root = anchor_info.oldest_block_parent; @@ -100,11 +88,11 @@ impl BeaconChain { let mut new_oldest_data_column_slot = data_column_info.oldest_data_column_slot; let mut blob_batch = Vec::::new(); - let mut cold_batch = Vec::with_capacity(blocks_to_import.len()); - let mut hot_batch = Vec::with_capacity(blocks_to_import.len()); - let mut signed_blocks = Vec::with_capacity(blocks_to_import.len()); + let mut cold_batch = Vec::with_capacity(blocks.len()); + let mut hot_batch = Vec::with_capacity(blocks.len()); + let mut signed_blocks = Vec::with_capacity(blocks.len()); - for available_block in blocks_to_import.into_iter().rev() { + for available_block in blocks.into_iter().rev() { let (block_root, block, block_data) = available_block.deconstruct(); if block_root != expected_block_root { @@ -286,6 +274,6 @@ impl BeaconChain { self.store_migrator.process_reconstruction(); } - Ok(num_relevant) + Ok(()) } } diff --git a/beacon_node/network/src/network_beacon_processor/sync_methods.rs b/beacon_node/network/src/network_beacon_processor/sync_methods.rs index 41160fcfe45..f2485bbc5e7 100644 --- a/beacon_node/network/src/network_beacon_processor/sync_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/sync_methods.rs @@ -770,8 +770,9 @@ impl NetworkBeaconProcessor { ); } + let imported_blocks = available_blocks.len(); match self.chain.import_historical_block_batch(available_blocks) { - Ok(imported_blocks) => { + Ok(()) => { metrics::inc_counter( &metrics::BEACON_PROCESSOR_BACKFILL_CHAIN_SEGMENT_SUCCESS_TOTAL, ); From 774665975cb0688ff800cf644fc901febcd83df4 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 13:48:19 +1100 Subject: [PATCH 02/13] Fix tests --- .../beacon_chain/src/historical_blocks.rs | 70 ++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/beacon_node/beacon_chain/src/historical_blocks.rs b/beacon_node/beacon_chain/src/historical_blocks.rs index 4aef2c771d2..48ca6de6107 100644 --- a/beacon_node/beacon_chain/src/historical_blocks.rs +++ b/beacon_node/beacon_chain/src/historical_blocks.rs @@ -1,5 +1,5 @@ use crate::data_availability_checker::{AvailableBlock, AvailableBlockData}; -use crate::{BeaconChain, BeaconChainTypes, metrics}; +use crate::{BeaconChain, BeaconChainTypes, WhenSlotSkipped, metrics}; use itertools::Itertools; use state_processing::{ per_block_processing::ParallelSignatureSets, @@ -34,6 +34,8 @@ pub enum HistoricalBlockError { ValidatorPubkeyCacheTimeout, /// Logic error: should never occur. IndexOutOfBounds, + /// Logic error: should never occur. + MissingOldestBlockRoot { slot: Slot }, /// Internal store error StoreError(StoreError), } @@ -65,37 +67,71 @@ impl BeaconChain { #[instrument(skip_all)] pub fn import_historical_block_batch( &self, - blocks: Vec>, + mut blocks: Vec>, ) -> Result<(), HistoricalBlockError> { let anchor_info = self.store.get_anchor_info(); let blob_info = self.store.get_blob_info(); let data_column_info = self.store.get_data_column_info(); - // Take all blocks with slots less than the oldest block slot. - for block in &blocks { - if block.block().slot() >= anchor_info.oldest_block_slot { - debug!( - oldest_block_slot = %anchor_info.oldest_block_slot, - block_slot = %block.block().slot(), - "Reimporting historic block" - ); - } + // Take all blocks with slots less than or equal to the oldest block slot. + // + // This allows for reimport of the blobs/columns for the finalized block after checkpoint + // sync. + let num_relevant = blocks.partition_point(|available_block| { + available_block.block().slot() <= anchor_info.oldest_block_slot + }); + let total_blocks = blocks.len(); + blocks.truncate(num_relevant); + + let blocks_to_import = blocks; + if blocks_to_import.len() != total_blocks { + debug!( + oldest_block_slot = %anchor_info.oldest_block_slot, + total_blocks, + ignored = total_blocks.saturating_sub(blocks_to_import.len()), + "Ignoring some historic blocks" + ); + } + + if blocks_to_import.is_empty() { + return Ok(()); } let mut expected_block_root = anchor_info.oldest_block_parent; + let mut last_block_root = expected_block_root; let mut prev_block_slot = anchor_info.oldest_block_slot; let mut new_oldest_blob_slot = blob_info.oldest_blob_slot; let mut new_oldest_data_column_slot = data_column_info.oldest_data_column_slot; let mut blob_batch = Vec::::new(); - let mut cold_batch = Vec::with_capacity(blocks.len()); - let mut hot_batch = Vec::with_capacity(blocks.len()); - let mut signed_blocks = Vec::with_capacity(blocks.len()); + let mut cold_batch = Vec::with_capacity(blocks_to_import.len()); + let mut hot_batch = Vec::with_capacity(blocks_to_import.len()); + let mut signed_blocks = Vec::with_capacity(blocks_to_import.len()); - for available_block in blocks.into_iter().rev() { + for available_block in blocks_to_import.into_iter().rev() { let (block_root, block, block_data) = available_block.deconstruct(); - if block_root != expected_block_root { + if block.slot() == anchor_info.oldest_block_slot { + // When reimporting, verify that this is actually the same block (same block root). + let oldest_block_root = self + .block_root_at_slot(block.slot(), WhenSlotSkipped::None) + .ok() + .flatten() + .ok_or(HistoricalBlockError::MissingOldestBlockRoot { slot: block.slot() })?; + if block_root != oldest_block_root { + return Err(HistoricalBlockError::MismatchedBlockRoot { + block_root, + expected_block_root: oldest_block_root, + }); + } + + debug!( + ?block_root, + slot = %block.slot(), + "Re-importing historic block" + ); + last_block_root = block_root; + } else if block_root != expected_block_root { return Err(HistoricalBlockError::MismatchedBlockRoot { block_root, expected_block_root, @@ -186,7 +222,7 @@ impl BeaconChain { .ok_or(HistoricalBlockError::IndexOutOfBounds)? .iter() .map(|block| block.parent_root()) - .chain(iter::once(anchor_info.oldest_block_parent)); + .chain(iter::once(last_block_root)); let signature_set = signed_blocks .iter() .zip_eq(block_roots) From 226609c166830af13ef2ab74104c46bce693b78e Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 13:56:32 +1100 Subject: [PATCH 03/13] Peer penalty --- .../src/network_beacon_processor/sync_methods.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/beacon_node/network/src/network_beacon_processor/sync_methods.rs b/beacon_node/network/src/network_beacon_processor/sync_methods.rs index f2485bbc5e7..08cab92e4a1 100644 --- a/beacon_node/network/src/network_beacon_processor/sync_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/sync_methods.rs @@ -805,6 +805,16 @@ impl NetworkBeaconProcessor { // The peer is faulty if they bad signatures. Some(PeerAction::LowToleranceError) } + HistoricalBlockError::MissingOldestBlockRoot { slot } => { + warn!( + %slot, + error = "missing_oldest_block_root", + "Backfill batch processing error" + ); + // This is an internal error, do not penalize the peer. + None + } + HistoricalBlockError::ValidatorPubkeyCacheTimeout => { warn!( error = "pubkey_cache_timeout", From 3c423a81e5bfab595104a87349559c587e40d993 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 15:04:12 +1100 Subject: [PATCH 04/13] Minimise whitespace diff --- beacon_node/beacon_chain/src/historical_blocks.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/beacon_node/beacon_chain/src/historical_blocks.rs b/beacon_node/beacon_chain/src/historical_blocks.rs index 48ca6de6107..2ebf1e212c7 100644 --- a/beacon_node/beacon_chain/src/historical_blocks.rs +++ b/beacon_node/beacon_chain/src/historical_blocks.rs @@ -80,10 +80,11 @@ impl BeaconChain { let num_relevant = blocks.partition_point(|available_block| { available_block.block().slot() <= anchor_info.oldest_block_slot }); + let total_blocks = blocks.len(); blocks.truncate(num_relevant); - let blocks_to_import = blocks; + if blocks_to_import.len() != total_blocks { debug!( oldest_block_slot = %anchor_info.oldest_block_slot, From b46df5536b5f7f55fee5f510c0c7ef659711a031 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 15:04:32 +1100 Subject: [PATCH 05/13] Revert unnecessary forwards sync change --- .../beacon_chain/src/block_verification.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index ad611fabf10..5078e24a51c 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -1685,20 +1685,14 @@ fn check_block_against_finalized_slot( // // Fork choice has the most up-to-date view of finalization and there's no point importing a // block which conflicts with the fork-choice view of finalization. - let finalized_checkpoint = chain.canonical_head.cached_head().finalized_checkpoint(); - let finalized_slot = finalized_checkpoint + let finalized_slot = chain + .canonical_head + .cached_head() + .finalized_checkpoint() .epoch .start_slot(T::EthSpec::slots_per_epoch()); - let would_revert_finalized_slot = if block.slot() < finalized_slot { - true - } else if block.slot() == finalized_slot { - block_root != finalized_checkpoint.root - } else { - false - }; - // Allow to re-import the finalized block if it's the same - if would_revert_finalized_slot { + if block.slot() <= finalized_slot { chain.pre_finalization_block_rejected(block_root); Err(BlockError::WouldRevertFinalizedSlot { block_slot: block.slot(), From e1adef7efef751ed5286dbd59c9cabf72e4b273e Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 15:06:44 +1100 Subject: [PATCH 06/13] Revert imported_blocks change --- beacon_node/beacon_chain/src/historical_blocks.rs | 8 +++++--- .../network/src/network_beacon_processor/sync_methods.rs | 3 +-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/beacon_node/beacon_chain/src/historical_blocks.rs b/beacon_node/beacon_chain/src/historical_blocks.rs index 2ebf1e212c7..e4040eea6b0 100644 --- a/beacon_node/beacon_chain/src/historical_blocks.rs +++ b/beacon_node/beacon_chain/src/historical_blocks.rs @@ -64,11 +64,13 @@ impl BeaconChain { /// This function should not be called concurrently with any other function that mutates /// the anchor info (including this function itself). If a concurrent mutation occurs that /// would violate consistency then an `AnchorInfoConcurrentMutation` error will be returned. + /// + /// Return the number of blocks successfully imported. #[instrument(skip_all)] pub fn import_historical_block_batch( &self, mut blocks: Vec>, - ) -> Result<(), HistoricalBlockError> { + ) -> Result { let anchor_info = self.store.get_anchor_info(); let blob_info = self.store.get_blob_info(); let data_column_info = self.store.get_data_column_info(); @@ -95,7 +97,7 @@ impl BeaconChain { } if blocks_to_import.is_empty() { - return Ok(()); + return Ok(0); } let mut expected_block_root = anchor_info.oldest_block_parent; @@ -311,6 +313,6 @@ impl BeaconChain { self.store_migrator.process_reconstruction(); } - Ok(()) + Ok(num_relevant) } } diff --git a/beacon_node/network/src/network_beacon_processor/sync_methods.rs b/beacon_node/network/src/network_beacon_processor/sync_methods.rs index 08cab92e4a1..e49ae134fe4 100644 --- a/beacon_node/network/src/network_beacon_processor/sync_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/sync_methods.rs @@ -770,9 +770,8 @@ impl NetworkBeaconProcessor { ); } - let imported_blocks = available_blocks.len(); match self.chain.import_historical_block_batch(available_blocks) { - Ok(()) => { + Ok(imported_blocks) => { metrics::inc_counter( &metrics::BEACON_PROCESSOR_BACKFILL_CHAIN_SEGMENT_SUCCESS_TOTAL, ); From 173b71905e0e04b7beb8964296ca0bec0519da40 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 15:50:47 +1100 Subject: [PATCH 07/13] Fix unaligned checkpoint sync --- beacon_node/store/src/hot_cold_store.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index a0a75dbb0d4..10b63e9b457 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -639,6 +639,7 @@ impl, Cold: ItemStore> HotColdDB let block = if blinded_block.message().execution_payload().is_err() || blinded_block.slot() >= split.slot + || block_root == split.block_root { // Re-constructing the full block should always succeed here. let full_block = self.make_full_block(block_root, blinded_block)?; From ebf151f34328d1c22bc94cb835c69214de742792 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 16:02:44 +1100 Subject: [PATCH 08/13] Fix bug in unaligned checkpoint sync --- beacon_node/store/src/hot_cold_store.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index 10b63e9b457..4cbb600fef1 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -639,7 +639,7 @@ impl, Cold: ItemStore> HotColdDB let block = if blinded_block.message().execution_payload().is_err() || blinded_block.slot() >= split.slot - || block_root == split.block_root + || *block_root == split.block_root { // Re-constructing the full block should always succeed here. let full_block = self.make_full_block(block_root, blinded_block)?; From 4b996e23299a0d923b863789fb128a3a9bed9216 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 17:02:26 +1100 Subject: [PATCH 09/13] Fix HTTP tests with more minimal change --- beacon_node/beacon_chain/src/historical_blocks.rs | 7 ++++--- beacon_node/execution_layer/src/test_utils/mock_builder.rs | 4 ++-- beacon_node/store/src/hot_cold_store.rs | 3 +-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/beacon_node/beacon_chain/src/historical_blocks.rs b/beacon_node/beacon_chain/src/historical_blocks.rs index e4040eea6b0..3fbb13397eb 100644 --- a/beacon_node/beacon_chain/src/historical_blocks.rs +++ b/beacon_node/beacon_chain/src/historical_blocks.rs @@ -75,12 +75,13 @@ impl BeaconChain { let blob_info = self.store.get_blob_info(); let data_column_info = self.store.get_data_column_info(); - // Take all blocks with slots less than or equal to the oldest block slot. + // Take all blocks with slots less than the oldest block slot, or equal to the anchor slot. // // This allows for reimport of the blobs/columns for the finalized block after checkpoint // sync. let num_relevant = blocks.partition_point(|available_block| { - available_block.block().slot() <= anchor_info.oldest_block_slot + available_block.block().slot() < anchor_info.oldest_block_slot + || available_block.block().slot() == anchor_info.anchor_slot }); let total_blocks = blocks.len(); @@ -114,7 +115,7 @@ impl BeaconChain { for available_block in blocks_to_import.into_iter().rev() { let (block_root, block, block_data) = available_block.deconstruct(); - if block.slot() == anchor_info.oldest_block_slot { + if block.slot() == anchor_info.anchor_slot { // When reimporting, verify that this is actually the same block (same block root). let oldest_block_root = self .block_root_at_slot(block.slot(), WhenSlotSkipped::None) diff --git a/beacon_node/execution_layer/src/test_utils/mock_builder.rs b/beacon_node/execution_layer/src/test_utils/mock_builder.rs index df1e371719b..9967668a5f8 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -842,7 +842,7 @@ impl MockBuilder { .beacon_client .get_beacon_blocks::(BlockId::Finalized) .await - .map_err(|_| "couldn't get finalized block".to_string())? + .map_err(|e| format!("couldn't get finalized block: {e:?}"))? .ok_or_else(|| "missing finalized block".to_string())? .data() .message() @@ -855,7 +855,7 @@ impl MockBuilder { .beacon_client .get_beacon_blocks::(BlockId::Justified) .await - .map_err(|_| "couldn't get justified block".to_string())? + .map_err(|e| format!("couldn't get justified block: {e:?}"))? .ok_or_else(|| "missing justified block".to_string())? .data() .message() diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index 4cbb600fef1..2227784b087 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -639,7 +639,6 @@ impl, Cold: ItemStore> HotColdDB let block = if blinded_block.message().execution_payload().is_err() || blinded_block.slot() >= split.slot - || *block_root == split.block_root { // Re-constructing the full block should always succeed here. let full_block = self.make_full_block(block_root, blinded_block)?; @@ -650,7 +649,7 @@ impl, Cold: ItemStore> HotColdDB .inspect(|cache| cache.lock().put_block(*block_root, full_block.clone())); DatabaseBlock::Full(full_block) - } else if !self.config.prune_payloads { + } else if !self.config.prune_payloads || *block_root == split.block_root { // If payload pruning is disabled there's a chance we may have the payload of // this finalized block. Attempt to load it but don't error in case it's missing. let fork_name = blinded_block.fork_name(&self.spec)?; From ccf1abbc34baf253d492c110f2c54b79fb2ca02d Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Tue, 18 Nov 2025 17:21:09 +1100 Subject: [PATCH 10/13] Revert accidental addition of broken anchor_slot thing --- beacon_node/beacon_chain/src/historical_blocks.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/beacon_node/beacon_chain/src/historical_blocks.rs b/beacon_node/beacon_chain/src/historical_blocks.rs index 3fbb13397eb..e4040eea6b0 100644 --- a/beacon_node/beacon_chain/src/historical_blocks.rs +++ b/beacon_node/beacon_chain/src/historical_blocks.rs @@ -75,13 +75,12 @@ impl BeaconChain { let blob_info = self.store.get_blob_info(); let data_column_info = self.store.get_data_column_info(); - // Take all blocks with slots less than the oldest block slot, or equal to the anchor slot. + // Take all blocks with slots less than or equal to the oldest block slot. // // This allows for reimport of the blobs/columns for the finalized block after checkpoint // sync. let num_relevant = blocks.partition_point(|available_block| { - available_block.block().slot() < anchor_info.oldest_block_slot - || available_block.block().slot() == anchor_info.anchor_slot + available_block.block().slot() <= anchor_info.oldest_block_slot }); let total_blocks = blocks.len(); @@ -115,7 +114,7 @@ impl BeaconChain { for available_block in blocks_to_import.into_iter().rev() { let (block_root, block, block_data) = available_block.deconstruct(); - if block.slot() == anchor_info.anchor_slot { + if block.slot() == anchor_info.oldest_block_slot { // When reimporting, verify that this is actually the same block (same block root). let oldest_block_root = self .block_root_at_slot(block.slot(), WhenSlotSkipped::None) From bfa481e304e2f05aa40fe0de177fbdeac4312d7b Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 19 Nov 2025 09:50:07 +1100 Subject: [PATCH 11/13] Add comment clarifying split block case --- beacon_node/store/src/hot_cold_store.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index 2227784b087..e926caa9c77 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -652,6 +652,12 @@ impl, Cold: ItemStore> HotColdDB } else if !self.config.prune_payloads || *block_root == split.block_root { // If payload pruning is disabled there's a chance we may have the payload of // this finalized block. Attempt to load it but don't error in case it's missing. + // + // We also allow for the split block's payload to be loaded *if it exists*. This is + // necessary on startup when syncing from an unaligned checkpoint (a checkpoint state + // at a skipped slot), and then loading the canonical head (with payload). If we modify + // payload pruning in future so that it doesn't prune the split block's payload, then + // this case could move to the case above where we error if the payload is missing. let fork_name = blinded_block.fork_name(&self.spec)?; if let Some(payload) = self.get_execution_payload(block_root, fork_name)? { DatabaseBlock::Full( From a2c62c3f083a01303c66b51a0e0f7ae28e575ee8 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Wed, 19 Nov 2025 17:24:55 +1100 Subject: [PATCH 12/13] Fix md format --- book/src/advanced_blobs.md | 12 ++++++------ book/src/advanced_database.md | 10 +++++----- book/src/api_vc_endpoints.md | 4 ++-- book/src/archived_merge_migration.md | 16 ++++++++-------- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/book/src/advanced_blobs.md b/book/src/advanced_blobs.md index ccc29acf263..3c005e74312 100644 --- a/book/src/advanced_blobs.md +++ b/book/src/advanced_blobs.md @@ -6,12 +6,12 @@ With the [Fusaka](https://ethereum.org/roadmap/fusaka) upgrade, the main feature Table below summarizes the role of relevant flags in Lighthouse beacon node: -| | Post-Deneb, Pre-Fulu || Post-Fulu || -|-------|----------|----------|-----------|----------| -| Flag | Usage | Can serve blobs? | Usage | Can serve blobs? | -| --prune-blobs false | Does not prune blobs since using the flag | Yes, for blobs since using the flag and for the past 18 days | Does not prune data columns since using the flag | No | -| --semi-supernode | - | - | Store half data columns | Yes, for blobs since using the flag for a max of 18 days | -| --supernode | - | - | Store all data columns | Yes, for blobs since using the flag for a max of 18 days | +| | Post-Deneb, Pre-Fulu | | Post-Fulu | | +|---------------------|-------------------------------------------|--------------------------------------------------------------|--------------------------------------------------|----------------------------------------------------------| +| Flag | Usage | Can serve blobs? | Usage | Can serve blobs? | +| --prune-blobs false | Does not prune blobs since using the flag | Yes, for blobs since using the flag and for the past 18 days | Does not prune data columns since using the flag | No | +| --semi-supernode | - | - | Store half data columns | Yes, for blobs since using the flag for a max of 18 days | +| --supernode | - | - | Store all data columns | Yes, for blobs since using the flag for a max of 18 days | While both `--supernode` and `--semi-supernode` can serve blobs, a supernode will be faster to respond to blobs queries as it skips the blob reconstruction step. Running a supernode also helps the network by serving the data columns to its peers. diff --git a/book/src/advanced_database.md b/book/src/advanced_database.md index 4e77046c2dd..16437367949 100644 --- a/book/src/advanced_database.md +++ b/book/src/advanced_database.md @@ -63,11 +63,11 @@ that we have observed are: The following table lists the data for different configurations. Note that the disk space requirement is for the `chain_db` and `freezer_db`, excluding the `blobs_db`. -| Hierarchy Exponents | Storage Requirement | Sequential Slot Query | Uncached Query | Time to Sync | -|---|---|---|---|---| -| 5,9,11,13,16,18,21 (default) | 418 GiB | 250-700 ms | up to 10 s | 1 week | -| 5,7,11 (frequent snapshots) | 589 GiB | 250-700 ms | up to 6 s | 1 week | -| 0,5,7,11 (per-slot diffs) | 2500 GiB | 250-700 ms | up to 4 s | 7 weeks | +| Hierarchy Exponents | Storage Requirement | Sequential Slot Query | Uncached Query | Time to Sync | +|------------------------------|---------------------|-----------------------|----------------|--------------| +| 5,9,11,13,16,18,21 (default) | 418 GiB | 250-700 ms | up to 10 s | 1 week | +| 5,7,11 (frequent snapshots) | 589 GiB | 250-700 ms | up to 6 s | 1 week | +| 0,5,7,11 (per-slot diffs) | 2500 GiB | 250-700 ms | up to 4 s | 7 weeks | [Jim](https://github.com/mcdee) has done some experiments to study the response time of querying random slots (uncached query) for `--hierarchy-exponents 0,5,7,11` (per-slot diffs) and `--hierarchy-exponents 5,9,11,13,17,21` (per-epoch diffs), as show in the figures below. From the figures, two points can be concluded: diff --git a/book/src/api_vc_endpoints.md b/book/src/api_vc_endpoints.md index 14f4933e171..d128b13b2f8 100644 --- a/book/src/api_vc_endpoints.md +++ b/book/src/api_vc_endpoints.md @@ -132,7 +132,7 @@ Returns information regarding the health of the host machine. | Property | Specification | |-------------------|--------------------------------------------| -| Path | `/lighthouse/ui/health` | +| Path | `/lighthouse/ui/health` | | Method | GET | | Required Headers | [`Authorization`](./api_vc_auth_header.md) | | Typical Responses | 200 | @@ -178,7 +178,7 @@ Returns the graffiti that will be used for the next block proposal of each valid | Property | Specification | |-------------------|--------------------------------------------| -| Path | `/lighthouse/ui/graffiti` | +| Path | `/lighthouse/ui/graffiti` | | Method | GET | | Required Headers | [`Authorization`](./api_vc_auth_header.md) | | Typical Responses | 200 | diff --git a/book/src/archived_merge_migration.md b/book/src/archived_merge_migration.md index ac9c78c5e3b..b983db23ae7 100644 --- a/book/src/archived_merge_migration.md +++ b/book/src/archived_merge_migration.md @@ -25,14 +25,14 @@ All networks (**Mainnet**, **Goerli (Prater)**, **Ropsten**, **Sepolia**, **Kiln
-| Network | Bellatrix | The Merge | Remark | -|---------|-------------------------------|-------------------------------| -----------| -| Ropsten | 2nd June 2022 | 8th June 2022 | Deprecated | -| Sepolia | 20th June 2022 | 6th July 2022 | | -| Goerli | 4th August 2022 | 10th August 2022 | Previously named `Prater`| -| Mainnet | 6th September 2022| 15th September 2022| | -| Chiado | 10th October 2022 | 4th November 2022 | | -| Gnosis | 30th November 2022| 8th December 2022 | | +| Network | Bellatrix | The Merge | Remark | +|---------|-------------------------------|--------------------------------|---------------------------| +| Ropsten | 2nd June 2022 | 8th June 2022 | Deprecated | +| Sepolia | 20th June 2022 | 6th July 2022 | | +| Goerli | 4th August 2022 | 10th August 2022 | Previously named `Prater` | +| Mainnet | 6th September 2022 | 15th September 2022 | | +| Chiado | 10th October 2022 | 4th November 2022 | | +| Gnosis | 30th November 2022 | 8th December 2022 | |
From 2a2e97ef9d1da9218a98cd6731af39deba2db282 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Wed, 19 Nov 2025 19:41:55 +1100 Subject: [PATCH 13/13] Remove now-invalid multilingual option --- book/book.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/book/book.toml b/book/book.toml index 7b143710a5f..c0d38f61470 100644 --- a/book/book.toml +++ b/book/book.toml @@ -1,7 +1,6 @@ [book] authors = ["Paul Hauner", "Age Manning"] language = "en" -multilingual = false src = "src" title = "Lighthouse Book"