Skip to content

Commit 9667dc2

Browse files
Implement checkpoint sync (#2244)
## Issue Addressed Closes #1891 Closes #1784 ## Proposed Changes Implement checkpoint sync for Lighthouse, enabling it to start from a weak subjectivity checkpoint. ## Additional Info - [x] Return unavailable status for out-of-range blocks requested by peers (#2561) - [x] Implement sync daemon for fetching historical blocks (#2561) - [x] Verify chain hashes (either in `historical_blocks.rs` or the calling module) - [x] Consistency check for initial block + state - [x] Fetch the initial state and block from a beacon node HTTP endpoint - [x] Don't crash fetching beacon states by slot from the API - [x] Background service for state reconstruction, triggered by CLI flag or API call. Considered out of scope for this PR: - Drop the requirement to provide the `--checkpoint-block` (this would require some pretty heavy refactoring of block verification) Co-authored-by: Diva M <[email protected]>
1 parent 280e4fe commit 9667dc2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+4013
-460
lines changed

Cargo.lock

Lines changed: 6 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::errors::{BeaconChainError as Error, BlockProductionError};
1414
use crate::eth1_chain::{Eth1Chain, Eth1ChainBackend};
1515
use crate::events::ServerSentEventHandler;
1616
use crate::head_tracker::HeadTracker;
17+
use crate::historical_blocks::HistoricalBlockError;
1718
use crate::migrate::BackgroundMigrator;
1819
use crate::naive_aggregation_pool::{
1920
AggregatedAttestationMap, Error as NaiveAggregationError, NaiveAggregationPool,
@@ -431,10 +432,23 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
431432
/// - Skipped slots contain the root of the closest prior
432433
/// non-skipped slot (identical to the way they are stored in `state.block_roots`).
433434
/// - Iterator returns `(Hash256, Slot)`.
435+
///
436+
/// Will return a `BlockOutOfRange` error if the requested start slot is before the period of
437+
/// history for which we have blocks stored. See `get_oldest_block_slot`.
434438
pub fn forwards_iter_block_roots(
435439
&self,
436440
start_slot: Slot,
437441
) -> Result<impl Iterator<Item = Result<(Hash256, Slot), Error>>, Error> {
442+
let oldest_block_slot = self.store.get_oldest_block_slot();
443+
if start_slot < oldest_block_slot {
444+
return Err(Error::HistoricalBlockError(
445+
HistoricalBlockError::BlockOutOfRange {
446+
slot: start_slot,
447+
oldest_block_slot,
448+
},
449+
));
450+
}
451+
438452
let local_head = self.head()?;
439453

440454
let iter = HotColdDB::forwards_block_roots_iterator(
@@ -620,6 +634,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
620634
return Ok(Some(self.genesis_state_root));
621635
}
622636

637+
// Check limits w.r.t historic state bounds.
638+
let (historic_lower_limit, historic_upper_limit) = self.store.get_historic_state_limits();
639+
if request_slot > historic_lower_limit && request_slot < historic_upper_limit {
640+
return Ok(None);
641+
}
642+
623643
// Try an optimized path of reading the root directly from the head state.
624644
let fast_lookup: Option<Hash256> = self.with_head(|head| {
625645
if head.beacon_block.slot() <= request_slot {
@@ -657,7 +677,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
657677
/// ## Notes
658678
///
659679
/// - Use the `skips` parameter to define the behaviour when `request_slot` is a skipped slot.
660-
/// - Returns `Ok(None)` for any slot higher than the current wall-clock slot.
680+
/// - Returns `Ok(None)` for any slot higher than the current wall-clock slot, or less than
681+
/// the oldest known block slot.
661682
pub fn block_root_at_slot(
662683
&self,
663684
request_slot: Slot,
@@ -667,6 +688,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
667688
WhenSlotSkipped::None => self.block_root_at_slot_skips_none(request_slot),
668689
WhenSlotSkipped::Prev => self.block_root_at_slot_skips_prev(request_slot),
669690
}
691+
.or_else(|e| match e {
692+
Error::HistoricalBlockError(_) => Ok(None),
693+
e => Err(e),
694+
})
670695
}
671696

672697
/// Returns the block root at the given slot, if any. Only returns roots in the canonical chain.

beacon_node/beacon_chain/src/block_verification.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,9 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
501501

502502
let block_root = get_block_root(&block);
503503

504+
// Disallow blocks that conflict with the anchor (weak subjectivity checkpoint), if any.
505+
check_block_against_anchor_slot(block.message(), chain)?;
506+
504507
// Do not gossip a block from a finalized slot.
505508
check_block_against_finalized_slot(block.message(), chain)?;
506509

@@ -708,6 +711,9 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
708711
.fork_name(&chain.spec)
709712
.map_err(BlockError::InconsistentFork)?;
710713

714+
// Check the anchor slot before loading the parent, to avoid spurious lookups.
715+
check_block_against_anchor_slot(block.message(), chain)?;
716+
711717
let (mut parent, block) = load_parent(block, chain)?;
712718

713719
// Reject any block that exceeds our limit on skipped slots.
@@ -1115,6 +1121,19 @@ fn check_block_skip_slots<T: BeaconChainTypes>(
11151121
Ok(())
11161122
}
11171123

1124+
/// Returns `Ok(())` if the block's slot is greater than the anchor block's slot (if any).
1125+
fn check_block_against_anchor_slot<T: BeaconChainTypes>(
1126+
block: BeaconBlockRef<'_, T::EthSpec>,
1127+
chain: &BeaconChain<T>,
1128+
) -> Result<(), BlockError<T::EthSpec>> {
1129+
if let Some(anchor_slot) = chain.store.get_anchor_slot() {
1130+
if block.slot() <= anchor_slot {
1131+
return Err(BlockError::WeakSubjectivityConflict);
1132+
}
1133+
}
1134+
Ok(())
1135+
}
1136+
11181137
/// Returns `Ok(())` if the block is later than the finalized slot on `chain`.
11191138
///
11201139
/// Returns an error if the block is earlier or equal to the finalized slot, or there was an error

0 commit comments

Comments
 (0)