mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 16:55:46 +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_state = anchor.beacon_state;
|
||||||
let mut anchor_block_header = anchor_state.latest_block_header().clone();
|
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).
|
// Pre-gloas the anchor state MUST be on an epoch boundary (it should be advanced by the caller).
|
||||||
if !anchor_state
|
// Post-gloas this requirement is relaxed.
|
||||||
|
if !anchor_state.fork_name_unchecked().gloas_enabled() && !anchor_state
|
||||||
.slot()
|
.slot()
|
||||||
.as_u64()
|
.as_u64()
|
||||||
.is_multiple_of(E::slots_per_epoch())
|
.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 task_executor::{ShutdownReason, TaskExecutor};
|
||||||
use tracing::{debug, error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
|
use types::StatePayloadStatus;
|
||||||
use types::data::CustodyIndex;
|
use types::data::CustodyIndex;
|
||||||
use types::{
|
use types::{
|
||||||
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList,
|
BeaconBlock, BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList,
|
||||||
@@ -433,9 +434,15 @@ where
|
|||||||
.clone()
|
.clone()
|
||||||
.ok_or("weak_subjectivity_state requires a store")?;
|
.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();
|
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!(
|
debug!(
|
||||||
state_slot = %weak_subj_state.slot(),
|
state_slot = %weak_subj_state.slot(),
|
||||||
block_slot = %weak_subj_block.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
|
// Write the state, block and blobs non-atomically, it doesn't matter if they're forgotten
|
||||||
// about on a crash restart.
|
// about on a crash restart.
|
||||||
store
|
store
|
||||||
.update_finalized_state(
|
.set_initial_finalized_state(
|
||||||
weak_subj_state_root,
|
weak_subj_state_root,
|
||||||
weak_subj_block_root,
|
weak_subj_block_root,
|
||||||
weak_subj_state.clone(),
|
weak_subj_state.clone(),
|
||||||
@@ -617,7 +624,15 @@ where
|
|||||||
.map_err(|e| format!("Failed to initialize data column info: {:?}", e))?,
|
.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 {
|
let snapshot = BeaconSnapshot {
|
||||||
beacon_block_root: weak_subj_block_root,
|
beacon_block_root: weak_subj_block_root,
|
||||||
execution_envelope: None,
|
execution_envelope: None,
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ pub enum Error {
|
|||||||
from_state_slot: Slot,
|
from_state_slot: Slot,
|
||||||
target_slot: Slot,
|
target_slot: Slot,
|
||||||
},
|
},
|
||||||
|
FinalizedStateAlreadySet,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait HandleUnavailable<T> {
|
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(
|
pub fn update_finalized_state(
|
||||||
&self,
|
&self,
|
||||||
state_root: Hash256,
|
state_root: Hash256,
|
||||||
|
|||||||
@@ -124,6 +124,36 @@ impl<E: EthSpec> StateCache<E> {
|
|||||||
roots
|
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(
|
pub fn update_finalized_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
state_root: Hash256,
|
state_root: Hash256,
|
||||||
@@ -135,6 +165,21 @@ impl<E: EthSpec> StateCache<E> {
|
|||||||
return Err(Error::FinalizedStateUnaligned);
|
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
|
if self
|
||||||
.finalized_state
|
.finalized_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|||||||
@@ -396,8 +396,9 @@ where
|
|||||||
current_slot: Option<Slot>,
|
current_slot: Option<Slot>,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Self, Error<T::Error>> {
|
) -> Result<Self, Error<T::Error>> {
|
||||||
// Sanity check: the anchor must lie on an epoch boundary.
|
// Pre-gloas sanity check: the anchor must lie on an epoch boundary.
|
||||||
if anchor_state.slot() % E::slots_per_epoch() != 0 {
|
// Post-gloas we relax this requirement
|
||||||
|
if !anchor_state.fork_name_unchecked().gloas_enabled() && anchor_state.slot() % E::slots_per_epoch() != 0 {
|
||||||
return Err(Error::InvalidAnchor {
|
return Err(Error::InvalidAnchor {
|
||||||
block_slot: anchor_block.slot(),
|
block_slot: anchor_block.slot(),
|
||||||
state_slot: anchor_state.slot(),
|
state_slot: anchor_state.slot(),
|
||||||
|
|||||||
Reference in New Issue
Block a user