mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 10:11:44 +00:00
Fix block backfill with genesis skip slots (#4820)
## Issue Addressed Closes #4817. ## Proposed Changes - Fill in the linear block roots array between 0 and the slot of the first block (e.g. slots 0 and 1 on Holesky). - Backport the `--freezer`, `--skip` and `--limit` options for `lighthouse db inspect` from tree-states. This allows us to easily view the database corruption of 4817 using `lighthouse db inspect --network holesky --freezer --column bbr --output values --limit 2`. - Backport the `iter_column_from` change and `MemoryStore` overhaul from tree-states. These are required to enable `lighthouse db inspect`. - Rework `freezer_upper_limit` to allow state lookups for slots below the `state_lower_limit`. Currently state lookups will fail until state reconstruction completes entirely. There is a new regression test for the main bug, but no test for the `freezer_upper_limit` fix because we don't currently support running state reconstruction partially (see #3026). This will be fixed once we merge `tree-states`! In lieu of an automated test, I've tested manually on a Holesky node while it was reconstructing. ## Additional Info Users who backfilled Holesky to slot 0 (e.g. using `--reconstruct-historic-states`) need to either: - Re-sync from genesis. - Re-sync using checkpoint sync and the changes from this PR. Due to the recency of the Holesky genesis, writing a custom pass to fix up broken databases (which would require its own thorough testing) was deemed unnecessary. This is the primary reason for this PR being marked `backwards-incompat`. This will create few conflicts with Deneb, which I've already resolved on `tree-states-deneb` and will be happy to backport to Deneb once this PR is merged to unstable.
This commit is contained in:
@@ -135,15 +135,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
prev_block_slot = block.slot();
|
||||
expected_block_root = block.message().parent_root();
|
||||
|
||||
// If we've reached genesis, add the genesis block root to the batch and set the
|
||||
// anchor slot to 0 to indicate completion.
|
||||
// If we've reached genesis, add the genesis block root to the batch for all slots
|
||||
// between 0 and the first block slot, and set the anchor slot to 0 to indicate
|
||||
// completion.
|
||||
if expected_block_root == self.genesis_block_root {
|
||||
let genesis_slot = self.spec.genesis_slot;
|
||||
chunk_writer.set(
|
||||
genesis_slot.as_usize(),
|
||||
self.genesis_block_root,
|
||||
&mut cold_batch,
|
||||
)?;
|
||||
for slot in genesis_slot.as_usize()..block.slot().as_usize() {
|
||||
chunk_writer.set(slot, self.genesis_block_root, &mut cold_batch)?;
|
||||
}
|
||||
prev_block_slot = genesis_slot;
|
||||
expected_block_root = Hash256::zero();
|
||||
break;
|
||||
|
||||
@@ -119,10 +119,13 @@ pub fn start_otb_verification_service<T: BeaconChainTypes>(
|
||||
pub fn load_optimistic_transition_blocks<T: BeaconChainTypes>(
|
||||
chain: &BeaconChain<T>,
|
||||
) -> Result<Vec<OptimisticTransitionBlock>, StoreError> {
|
||||
process_results(chain.store.hot_db.iter_column(OTBColumn), |iter| {
|
||||
iter.map(|(_, bytes)| OptimisticTransitionBlock::from_store_bytes(&bytes))
|
||||
.collect()
|
||||
})?
|
||||
process_results(
|
||||
chain.store.hot_db.iter_column::<Hash256>(OTBColumn),
|
||||
|iter| {
|
||||
iter.map(|(_, bytes)| OptimisticTransitionBlock::from_store_bytes(&bytes))
|
||||
.collect()
|
||||
},
|
||||
)?
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
@@ -2273,6 +2273,18 @@ async fn weak_subjectivity_sync_unaligned_unadvanced_checkpoint() {
|
||||
weak_subjectivity_sync_test(slots, checkpoint_slot).await
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/sigp/lighthouse/issues/4817
|
||||
// Skip 3 slots immediately after genesis, creating a gap between the genesis block and the first
|
||||
// real block.
|
||||
#[tokio::test]
|
||||
async fn weak_subjectivity_sync_skips_at_genesis() {
|
||||
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).await
|
||||
}
|
||||
|
||||
async fn weak_subjectivity_sync_test(slots: Vec<Slot>, checkpoint_slot: Slot) {
|
||||
// Build an initial chain on one harness, representing a synced node with full history.
|
||||
let num_final_blocks = E::slots_per_epoch() * 2;
|
||||
|
||||
Reference in New Issue
Block a user