Download checkpoint blobs during checkpoint sync (#5252)

* MVP implementation (untested)

* update store checkpoint sync test

* update cli help

* Merge pull request #5253 from realbigsean/checkpoint-blobs-sean

Checkpoint blobs sean

* Warn only if blobs are missing from server

* Merge remote-tracking branch 'origin/unstable' into checkpoint-blobs

* Verify checkpoint blobs

* Move blob verification earlier
This commit is contained in:
Michael Sproul
2024-02-19 13:22:23 +11:00
committed by GitHub
parent e22c9eed8f
commit c9702cb0a1
10 changed files with 122 additions and 11 deletions

View File

@@ -39,8 +39,8 @@ use std::time::Duration;
use store::{Error as StoreError, HotColdDB, ItemStore, KeyValueStoreOp};
use task_executor::{ShutdownReason, TaskExecutor};
use types::{
BeaconBlock, BeaconState, ChainSpec, Checkpoint, Epoch, EthSpec, Graffiti, Hash256, Signature,
SignedBeaconBlock, Slot,
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, Checkpoint, Epoch, EthSpec, Graffiti,
Hash256, Signature, SignedBeaconBlock, Slot,
};
/// An empty struct used to "witness" all the `BeaconChainTypes` traits. It has no user-facing
@@ -432,6 +432,7 @@ where
mut self,
mut weak_subj_state: BeaconState<TEthSpec>,
weak_subj_block: SignedBeaconBlock<TEthSpec>,
weak_subj_blobs: Option<BlobSidecarList<TEthSpec>>,
genesis_state: BeaconState<TEthSpec>,
) -> Result<Self, String> {
let store = self
@@ -490,6 +491,29 @@ where
));
}
// Verify that blobs (if provided) match the block.
if let Some(blobs) = &weak_subj_blobs {
let commitments = weak_subj_block
.message()
.body()
.blob_kzg_commitments()
.map_err(|e| format!("Blobs provided but block does not reference them: {e:?}"))?;
if blobs.len() != commitments.len() {
return Err(format!(
"Wrong number of blobs, expected: {}, got: {}",
commitments.len(),
blobs.len()
));
}
if commitments
.iter()
.zip(blobs.iter())
.any(|(commitment, blob)| *commitment != blob.kzg_commitment)
{
return Err("Checkpoint blob does not match block commitment".into());
}
}
// Set the store's split point *before* storing genesis so that genesis is stored
// immediately in the freezer DB.
store.set_split(weak_subj_slot, weak_subj_state_root, weak_subj_block_root);
@@ -511,14 +535,19 @@ where
.do_atomically(block_root_batch)
.map_err(|e| format!("Error writing frozen block roots: {e:?}"))?;
// Write the state and block non-atomically, it doesn't matter if they're forgotten
// Write the state, block and blobs non-atomically, it doesn't matter if they're forgotten
// about on a crash restart.
store
.put_state(&weak_subj_state_root, &weak_subj_state)
.map_err(|e| format!("Failed to store weak subjectivity state: {:?}", e))?;
.map_err(|e| format!("Failed to store weak subjectivity state: {e:?}"))?;
store
.put_block(&weak_subj_block_root, weak_subj_block.clone())
.map_err(|e| format!("Failed to store weak subjectivity block: {:?}", e))?;
.map_err(|e| format!("Failed to store weak subjectivity block: {e:?}"))?;
if let Some(blobs) = weak_subj_blobs {
store
.put_blobs(&weak_subj_block_root, blobs)
.map_err(|e| format!("Failed to store weak subjectivity blobs: {e:?}"))?;
}
// Stage the database's metadata fields for atomic storage when `build` is called.
// This prevents the database from restarting in an inconsistent state if the anchor