Add checkpoint sync

This commit is contained in:
Pawan Dhananjay
2026-03-30 19:41:09 -07:00
parent aa5292df99
commit 871697280e
7 changed files with 155 additions and 7 deletions

View File

@@ -941,6 +941,28 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
)?
}
/// Returns the Pending (pre-payload) state root at the given slot in the canonical chain.
///
/// In ePBS (Gloas+), if the canonical state at `slot` is Full (post-payload), this resolves
/// to the same-slot Pending state root. For skipped slots or pre-Gloas, returns the canonical
/// state root unchanged.
pub fn pending_state_root_at_slot(&self, request_slot: Slot) -> Result<Option<Hash256>, Error> {
let Some(root) = self.state_root_at_slot(request_slot)? else {
return Ok(None);
};
// Pre-Gloas: all states are inherently Pending.
if !self
.spec
.fork_name_at_slot::<T::EthSpec>(request_slot)
.gloas_enabled()
{
return Ok(Some(root));
}
Ok(Some(self.store.resolve_pending_state_root(&root)?))
}
/// Returns the block root at the given slot, if any. Only returns roots in the canonical chain.
///
/// ## Notes

View File

@@ -42,6 +42,7 @@ use store::{Error as StoreError, HotColdDB, ItemStore, KeyValueStoreOp};
use task_executor::{ShutdownReason, TaskExecutor};
use tracing::{debug, error, info, warn};
use tree_hash::TreeHash;
use types::SignedExecutionPayloadEnvelope;
use types::data::CustodyIndex;
use types::{
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList,
@@ -426,6 +427,7 @@ where
mut weak_subj_state: BeaconState<E>,
weak_subj_block: SignedBeaconBlock<E>,
weak_subj_blobs: Option<BlobSidecarList<E>>,
weak_subj_payload: Option<SignedExecutionPayloadEnvelope<E>>,
genesis_state: BeaconState<E>,
) -> Result<Self, String> {
let store = self
@@ -601,6 +603,13 @@ where
.map_err(|e| format!("Failed to store weak subjectivity blobs: {e:?}"))?;
}
}
if let Some(ref envelope) = weak_subj_payload {
store
.put_payload_envelope(&weak_subj_block_root, envelope.clone())
.map_err(|e| {
format!("Failed to store weak subjectivity payload envelope: {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
@@ -617,10 +626,25 @@ where
.map_err(|e| format!("Failed to initialize data column info: {:?}", e))?,
);
if self
.spec
.fork_name_at_slot::<E>(weak_subj_slot)
.gloas_enabled()
{
let envelope = weak_subj_payload.as_ref().ok_or_else(|| {
"Gloas checkpoint sync requires an execution payload envelope".to_string()
})?;
if envelope.message.beacon_block_root != weak_subj_block_root {
return Err(format!(
"Envelope beacon_block_root {:?} does not match block root {:?}",
envelope.message.beacon_block_root, weak_subj_block_root
));
}
}
// TODO(gloas): add check that checkpoint state is Pending
let snapshot = BeaconSnapshot {
beacon_block_root: weak_subj_block_root,
execution_envelope: None,
execution_envelope: weak_subj_payload.map(Arc::new),
beacon_block: Arc::new(weak_subj_block),
beacon_state: weak_subj_state,
};