mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-20 22:38:34 +00:00
Relax requirements that a checkpoint state must be epoch aligned post-gloas
This commit is contained in:
@@ -172,8 +172,9 @@ where
|
||||
let mut anchor_state = anchor.beacon_state;
|
||||
let mut anchor_block_header = anchor_state.latest_block_header().clone();
|
||||
|
||||
// The anchor state MUST be on an epoch boundary (it should be advanced by the caller).
|
||||
if !anchor_state
|
||||
// Pre-gloas the anchor state MUST be on an epoch boundary (it should be advanced by the caller).
|
||||
// Post-gloas this requirement is relaxed.
|
||||
if !anchor_state.fork_name_unchecked().gloas_enabled() && !anchor_state
|
||||
.slot()
|
||||
.as_u64()
|
||||
.is_multiple_of(E::slots_per_epoch())
|
||||
|
||||
@@ -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::StatePayloadStatus;
|
||||
use types::data::CustodyIndex;
|
||||
use types::{
|
||||
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList,
|
||||
@@ -433,9 +434,15 @@ where
|
||||
.clone()
|
||||
.ok_or("weak_subjectivity_state requires a store")?;
|
||||
|
||||
// Ensure the state is advanced to an epoch boundary.
|
||||
// Pre-gloas ensure the state is advanced to an epoch boundary.
|
||||
// Post-gloas checkpoint states are always pending (post-block) and cannot
|
||||
// be advanced across epoch boundaries without first checking for a payload
|
||||
// envelope.
|
||||
let slots_per_epoch = E::slots_per_epoch();
|
||||
if weak_subj_state.slot() % slots_per_epoch != 0 {
|
||||
|
||||
if !weak_subj_state.fork_name_unchecked().gloas_enabled()
|
||||
&& weak_subj_state.slot() % slots_per_epoch != 0
|
||||
{
|
||||
debug!(
|
||||
state_slot = %weak_subj_state.slot(),
|
||||
block_slot = %weak_subj_block.slot(),
|
||||
@@ -568,7 +575,7 @@ where
|
||||
// Write the state, block and blobs non-atomically, it doesn't matter if they're forgotten
|
||||
// about on a crash restart.
|
||||
store
|
||||
.update_finalized_state(
|
||||
.set_initial_finalized_state(
|
||||
weak_subj_state_root,
|
||||
weak_subj_block_root,
|
||||
weak_subj_state.clone(),
|
||||
@@ -617,7 +624,15 @@ where
|
||||
.map_err(|e| format!("Failed to initialize data column info: {:?}", e))?,
|
||||
);
|
||||
|
||||
// TODO(gloas): add check that checkpoint state is Pending
|
||||
if weak_subj_state.fork_name_unchecked().gloas_enabled()
|
||||
&& weak_subj_state.payload_status() != StatePayloadStatus::Pending
|
||||
{
|
||||
return Err(format!(
|
||||
"Checkpoint sync state must be Pending (post-block) for Gloas, got {:?}",
|
||||
weak_subj_state.payload_status()
|
||||
));
|
||||
}
|
||||
|
||||
let snapshot = BeaconSnapshot {
|
||||
beacon_block_root: weak_subj_block_root,
|
||||
execution_envelope: None,
|
||||
|
||||
@@ -101,6 +101,7 @@ pub enum Error {
|
||||
from_state_slot: Slot,
|
||||
target_slot: Slot,
|
||||
},
|
||||
FinalizedStateAlreadySet,
|
||||
}
|
||||
|
||||
pub trait HandleUnavailable<T> {
|
||||
|
||||
@@ -474,6 +474,25 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> HotColdDB<E, Hot, Cold>
|
||||
}
|
||||
}
|
||||
|
||||
/// See [`StateCache::set_initial_finalized_state`](crate::state_cache::StateCache::set_initial_finalized_state).
|
||||
pub fn set_initial_finalized_state(
|
||||
&self,
|
||||
state_root: Hash256,
|
||||
block_root: Hash256,
|
||||
state: BeaconState<E>,
|
||||
) -> Result<(), Error> {
|
||||
let start_slot = self.get_anchor_info().anchor_slot;
|
||||
let pre_finalized_slots_to_retain = self
|
||||
.hierarchy
|
||||
.closest_layer_points(state.slot(), start_slot);
|
||||
self.state_cache.lock().set_initial_finalized_state(
|
||||
state_root,
|
||||
block_root,
|
||||
state,
|
||||
&pre_finalized_slots_to_retain,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn update_finalized_state(
|
||||
&self,
|
||||
state_root: Hash256,
|
||||
|
||||
@@ -124,6 +124,36 @@ impl<E: EthSpec> StateCache<E> {
|
||||
roots
|
||||
}
|
||||
|
||||
/// Used by checkpoint sync to initialize the finalized state in the state cache.
|
||||
///
|
||||
/// Post-gloas the checkpoint state may not be epoch-aligned, e.g when the epoch boundary
|
||||
/// slot is skipped. We relax the epoch-alignment requirement for the initial state only.
|
||||
/// Runtime finalization updates should use [`update_finalized_state`](Self::update_finalized_state),
|
||||
/// which enforces alignment.
|
||||
pub fn set_initial_finalized_state(
|
||||
&mut self,
|
||||
state_root: Hash256,
|
||||
block_root: Hash256,
|
||||
state: BeaconState<E>,
|
||||
pre_finalized_slots_to_retain: &[Slot],
|
||||
) -> Result<(), Error> {
|
||||
if self.finalized_state.is_some() {
|
||||
return Err(Error::FinalizedStateAlreadySet);
|
||||
}
|
||||
|
||||
if !state.fork_name_unchecked().gloas_enabled() && state.slot() % E::slots_per_epoch() != 0
|
||||
{
|
||||
return Err(Error::FinalizedStateUnaligned);
|
||||
}
|
||||
|
||||
self.update_finalized_state_inner(
|
||||
state_root,
|
||||
block_root,
|
||||
state,
|
||||
pre_finalized_slots_to_retain,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn update_finalized_state(
|
||||
&mut self,
|
||||
state_root: Hash256,
|
||||
@@ -135,6 +165,21 @@ impl<E: EthSpec> StateCache<E> {
|
||||
return Err(Error::FinalizedStateUnaligned);
|
||||
}
|
||||
|
||||
self.update_finalized_state_inner(
|
||||
state_root,
|
||||
block_root,
|
||||
state,
|
||||
pre_finalized_slots_to_retain,
|
||||
)
|
||||
}
|
||||
|
||||
fn update_finalized_state_inner(
|
||||
&mut self,
|
||||
state_root: Hash256,
|
||||
block_root: Hash256,
|
||||
state: BeaconState<E>,
|
||||
pre_finalized_slots_to_retain: &[Slot],
|
||||
) -> Result<(), Error> {
|
||||
if self
|
||||
.finalized_state
|
||||
.as_ref()
|
||||
|
||||
Reference in New Issue
Block a user