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 <divma@protonmail.com>
This commit is contained in:
Michael Sproul
2021-09-22 00:37:28 +00:00
parent 280e4fe23d
commit 9667dc2f03
71 changed files with 4012 additions and 459 deletions

View File

@@ -77,6 +77,45 @@ pub fn block_proposal_signature_set<'a, T, F>(
block_root: Option<Hash256>,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>>
where
T: EthSpec,
F: Fn(usize) -> Option<Cow<'a, PublicKey>>,
{
let block = signed_block.message();
let proposer_index = state.get_beacon_proposer_index(block.slot(), spec)? as u64;
if proposer_index != block.proposer_index() {
return Err(Error::IncorrectBlockProposer {
block: block.proposer_index(),
local_shuffling: proposer_index,
});
}
block_proposal_signature_set_from_parts(
signed_block,
block_root,
proposer_index,
&state.fork(),
state.genesis_validators_root(),
get_pubkey,
spec,
)
}
/// A signature set that is valid if a block was signed by the expected block producer.
///
/// Unlike `block_proposal_signature_set` this does **not** check that the proposer index is
/// correct according to the shuffling. It should only be used if no suitable `BeaconState` is
/// available.
pub fn block_proposal_signature_set_from_parts<'a, T, F>(
signed_block: &'a SignedBeaconBlock<T>,
block_root: Option<Hash256>,
proposer_index: u64,
fork: &Fork,
genesis_validators_root: Hash256,
get_pubkey: F,
spec: &'a ChainSpec,
) -> Result<SignatureSet<'a>>
where
T: EthSpec,
F: Fn(usize) -> Option<Cow<'a, PublicKey>>,
@@ -87,20 +126,11 @@ where
.map_err(Error::InconsistentBlockFork)?;
let block = signed_block.message();
let proposer_index = state.get_beacon_proposer_index(block.slot(), spec)?;
if proposer_index as u64 != block.proposer_index() {
return Err(Error::IncorrectBlockProposer {
block: block.proposer_index(),
local_shuffling: proposer_index as u64,
});
}
let domain = spec.get_domain(
block.slot().epoch(T::slots_per_epoch()),
Domain::BeaconProposer,
&state.fork(),
state.genesis_validators_root(),
fork,
genesis_validators_root,
);
let message = if let Some(root) = block_root {
@@ -115,7 +145,7 @@ where
Ok(SignatureSet::single_pubkey(
signed_block.signature(),
get_pubkey(proposer_index).ok_or_else(|| Error::ValidatorUnknown(proposer_index as u64))?,
get_pubkey(proposer_index as usize).ok_or(Error::ValidatorUnknown(proposer_index))?,
message,
))
}