mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
resolve merge conflicts between untstable and release-v7.0.0
This commit is contained in:
@@ -51,8 +51,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.state_root_at_slot(state_slot)?
|
||||
.ok_or(BeaconChainError::NoStateForSlot(state_slot))?;
|
||||
|
||||
// This branch is reached from the HTTP API. We assume the user wants
|
||||
// to cache states so that future calls are faster.
|
||||
let state = self
|
||||
.get_state(&state_root, Some(state_slot))?
|
||||
.get_state(&state_root, Some(state_slot), true)?
|
||||
.ok_or(BeaconChainError::MissingBeaconState(state_root))?;
|
||||
|
||||
if state.fork_name_unchecked().altair_enabled() {
|
||||
|
||||
@@ -1126,6 +1126,12 @@ fn verify_head_block_is_known<T: BeaconChainTypes>(
|
||||
}
|
||||
}
|
||||
|
||||
if !verify_attestation_is_finalized_checkpoint_or_descendant(attestation.data(), chain) {
|
||||
return Err(Error::HeadBlockFinalized {
|
||||
beacon_block_root: attestation.data().beacon_block_root,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(block)
|
||||
} else if chain.is_pre_finalization_block(attestation.data().beacon_block_root)? {
|
||||
Err(Error::HeadBlockFinalized {
|
||||
@@ -1359,6 +1365,29 @@ pub fn verify_committee_index<E: EthSpec>(attestation: AttestationRef<E>) -> Res
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_attestation_is_finalized_checkpoint_or_descendant<T: BeaconChainTypes>(
|
||||
attestation_data: &AttestationData,
|
||||
chain: &BeaconChain<T>,
|
||||
) -> bool {
|
||||
// If we have a split block newer than finalization then we also ban attestations which are not
|
||||
// descended from that split block. It's important not to try checking `is_descendant` if
|
||||
// finality is ahead of the split and the split block has been pruned, as `is_descendant` will
|
||||
// return `false` in this case.
|
||||
let fork_choice = chain.canonical_head.fork_choice_read_lock();
|
||||
let attestation_block_root = attestation_data.beacon_block_root;
|
||||
let finalized_slot = fork_choice
|
||||
.finalized_checkpoint()
|
||||
.epoch
|
||||
.start_slot(T::EthSpec::slots_per_epoch());
|
||||
let split = chain.store.get_split_info();
|
||||
let is_descendant_from_split_block = split.slot == 0
|
||||
|| split.slot <= finalized_slot
|
||||
|| fork_choice.is_descendant(split.block_root, attestation_block_root);
|
||||
|
||||
fork_choice.is_finalized_checkpoint_or_descendant(attestation_block_root)
|
||||
&& is_descendant_from_split_block
|
||||
}
|
||||
|
||||
/// Assists in readability.
|
||||
type CommitteesPerSlot = u64;
|
||||
|
||||
|
||||
@@ -325,8 +325,10 @@ impl AttesterCache {
|
||||
return Ok(value);
|
||||
}
|
||||
|
||||
// We use `cache_state = true` here because if we are attesting to the state it's likely
|
||||
// to be recent and useful for other things.
|
||||
let mut state: BeaconState<T::EthSpec> = chain
|
||||
.get_state(&state_root, None)?
|
||||
.get_state(&state_root, None, true)?
|
||||
.ok_or(Error::MissingBeaconState(state_root))?;
|
||||
|
||||
if state.slot() > slot {
|
||||
|
||||
@@ -42,7 +42,7 @@ use crate::light_client_optimistic_update_verification::{
|
||||
Error as LightClientOptimisticUpdateError, VerifiedLightClientOptimisticUpdate,
|
||||
};
|
||||
use crate::light_client_server_cache::LightClientServerCache;
|
||||
use crate::migrate::BackgroundMigrator;
|
||||
use crate::migrate::{BackgroundMigrator, ManualFinalizationNotification};
|
||||
use crate::naive_aggregation_pool::{
|
||||
AggregatedAttestationMap, Error as NaiveAggregationError, NaiveAggregationPool,
|
||||
SyncContributionAggregateMap,
|
||||
@@ -118,8 +118,8 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use store::iter::{BlockRootsIterator, ParentRootBlockIterator, StateRootsIterator};
|
||||
use store::{
|
||||
BlobSidecarListFromRoot, DatabaseBlock, Error as DBError, HotColdDB, KeyValueStore,
|
||||
KeyValueStoreOp, StoreItem, StoreOp,
|
||||
BlobSidecarListFromRoot, DatabaseBlock, Error as DBError, HotColdDB, HotStateSummary,
|
||||
KeyValueStore, KeyValueStoreOp, StoreItem, StoreOp,
|
||||
};
|
||||
use task_executor::{ShutdownReason, TaskExecutor};
|
||||
use tokio::sync::oneshot;
|
||||
@@ -812,8 +812,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let block = self
|
||||
.get_blinded_block(&block_root)?
|
||||
.ok_or(Error::MissingBeaconBlock(block_root))?;
|
||||
// This method is only used in tests, so we may as well cache states to make CI go brr.
|
||||
// TODO(release-v7) move this method out of beacon chain and into `store_tests`` or something equivalent.
|
||||
let state = self
|
||||
.get_state(&block.state_root(), Some(block.slot()))?
|
||||
.get_state(&block.state_root(), Some(block.slot()), true)?
|
||||
.ok_or_else(|| Error::MissingBeaconState(block.state_root()))?;
|
||||
let iter = BlockRootsIterator::owned(&self.store, state);
|
||||
Ok(std::iter::once(Ok((block_root, block.slot())))
|
||||
@@ -1339,8 +1341,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
&self,
|
||||
state_root: &Hash256,
|
||||
slot: Option<Slot>,
|
||||
update_cache: bool,
|
||||
) -> Result<Option<BeaconState<T::EthSpec>>, Error> {
|
||||
Ok(self.store.get_state(state_root, slot)?)
|
||||
Ok(self.store.get_state(state_root, slot, update_cache)?)
|
||||
}
|
||||
|
||||
/// Return the sync committee at `slot + 1` from the canonical chain.
|
||||
@@ -1512,8 +1515,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
})?
|
||||
.ok_or(Error::NoStateForSlot(slot))?;
|
||||
|
||||
// This branch is mostly reached from the HTTP API when doing analysis, or in niche
|
||||
// situations when producing a block. In the HTTP API case we assume the user wants
|
||||
// to cache states so that future calls are faster, and that if the cache is
|
||||
// struggling due to non-finality that they will dial down inessential calls. In the
|
||||
// block proposal case we want to cache the state so that we can process the block
|
||||
// quickly after it has been signed.
|
||||
Ok(self
|
||||
.get_state(&state_root, Some(slot))?
|
||||
.get_state(&state_root, Some(slot), true)?
|
||||
.ok_or(Error::NoStateForSlot(slot))?)
|
||||
}
|
||||
}
|
||||
@@ -1695,6 +1704,45 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn manually_compact_database(&self) {
|
||||
self.store_migrator.process_manual_compaction();
|
||||
}
|
||||
|
||||
pub fn manually_finalize_state(
|
||||
&self,
|
||||
state_root: Hash256,
|
||||
checkpoint: Checkpoint,
|
||||
) -> Result<(), Error> {
|
||||
let HotStateSummary {
|
||||
slot,
|
||||
latest_block_root,
|
||||
..
|
||||
} = self
|
||||
.store
|
||||
.load_hot_state_summary(&state_root)
|
||||
.map_err(BeaconChainError::DBError)?
|
||||
.ok_or(BeaconChainError::MissingHotStateSummary(state_root))?;
|
||||
|
||||
if slot != checkpoint.epoch.start_slot(T::EthSpec::slots_per_epoch())
|
||||
|| latest_block_root != *checkpoint.root
|
||||
{
|
||||
return Err(BeaconChainError::InvalidCheckpoint {
|
||||
state_root,
|
||||
checkpoint,
|
||||
});
|
||||
}
|
||||
|
||||
let notif = ManualFinalizationNotification {
|
||||
state_root: state_root.into(),
|
||||
checkpoint,
|
||||
head_tracker: self.head_tracker.clone(),
|
||||
genesis_block_root: self.genesis_block_root,
|
||||
};
|
||||
|
||||
self.store_migrator.process_manual_finalization(notif);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns an aggregated `Attestation`, if any, that has a matching `attestation.data`.
|
||||
///
|
||||
/// The attestation will be obtained from `self.naive_aggregation_pool`.
|
||||
@@ -2839,6 +2887,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
chain_segment: Vec<RpcBlock<T::EthSpec>>,
|
||||
notify_execution_layer: NotifyExecutionLayer,
|
||||
) -> ChainSegmentResult {
|
||||
for block in chain_segment.iter() {
|
||||
if let Err(error) = self.check_invalid_block_roots(block.block_root()) {
|
||||
return ChainSegmentResult::Failed {
|
||||
imported_blocks: vec![],
|
||||
error,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let mut imported_blocks = vec![];
|
||||
|
||||
// Filter uninteresting blocks from the chain segment in a blocking task.
|
||||
@@ -3330,6 +3387,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.remove_notified(&block_root, r)
|
||||
}
|
||||
|
||||
/// Check for known and configured invalid block roots before processing.
|
||||
pub fn check_invalid_block_roots(&self, block_root: Hash256) -> Result<(), BlockError> {
|
||||
if self.config.invalid_block_roots.contains(&block_root) {
|
||||
Err(BlockError::KnownInvalidExecutionPayload(block_root))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `Ok(block_root)` if the given `unverified_block` was successfully verified and
|
||||
/// imported into the chain.
|
||||
///
|
||||
@@ -6775,9 +6841,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
})?;
|
||||
let beacon_state_root = beacon_block.state_root();
|
||||
|
||||
// This branch is reached from the HTTP API. We assume the user wants
|
||||
// to cache states so that future calls are faster.
|
||||
let mut beacon_state = self
|
||||
.store
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot()))?
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot()), true)?
|
||||
.ok_or_else(|| {
|
||||
Error::DBInconsistent(format!("Missing state {:?}", beacon_state_root))
|
||||
})?;
|
||||
@@ -6929,8 +6997,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
if signed_beacon_block.slot() % T::EthSpec::slots_per_epoch() == 0 {
|
||||
let block = self.get_blinded_block(&block_hash).unwrap().unwrap();
|
||||
// This branch is reached from the HTTP API. We assume the user wants
|
||||
// to cache states so that future calls are faster.
|
||||
let state = self
|
||||
.get_state(&block.state_root(), Some(block.slot()))
|
||||
.get_state(&block.state_root(), Some(block.slot()), true)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
finalized_blocks.insert(state.finalized_checkpoint().root);
|
||||
|
||||
@@ -282,6 +282,9 @@ pub enum BlockError {
|
||||
/// problems to worry about than losing peers, and we're doing the network a favour by
|
||||
/// disconnecting.
|
||||
ParentExecutionPayloadInvalid { parent_root: Hash256 },
|
||||
/// This is a known invalid block that was listed in Lighthouses configuration.
|
||||
/// At the moment this error is only relevant as part of the Holesky network recovery efforts.
|
||||
KnownInvalidExecutionPayload(Hash256),
|
||||
/// The block is a slashable equivocation from the proposer.
|
||||
///
|
||||
/// ## Peer scoring
|
||||
@@ -862,6 +865,9 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
|
||||
return Err(BlockError::DuplicateFullyImported(block_root));
|
||||
}
|
||||
|
||||
// Do not process a block that is known to be invalid.
|
||||
chain.check_invalid_block_roots(block_root)?;
|
||||
|
||||
// Do not process a block that doesn't descend from the finalized root.
|
||||
//
|
||||
// We check this *before* we load the parent so that we can return a more detailed error.
|
||||
@@ -1080,6 +1086,9 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
|
||||
.fork_name(&chain.spec)
|
||||
.map_err(BlockError::InconsistentFork)?;
|
||||
|
||||
// Check whether the block is a banned block prior to loading the parent.
|
||||
chain.check_invalid_block_roots(block_root)?;
|
||||
|
||||
let (mut parent, block) = load_parent(block, chain)?;
|
||||
|
||||
let state = cheap_state_advance_to_obtain_committees::<_, BlockError>(
|
||||
@@ -1746,7 +1755,22 @@ pub fn check_block_is_finalized_checkpoint_or_descendant<
|
||||
fork_choice: &BeaconForkChoice<T>,
|
||||
block: B,
|
||||
) -> Result<B, BlockError> {
|
||||
if fork_choice.is_finalized_checkpoint_or_descendant(block.parent_root()) {
|
||||
// If we have a split block newer than finalization then we also ban blocks which are not
|
||||
// descended from that split block. It's important not to try checking `is_descendant` if
|
||||
// finality is ahead of the split and the split block has been pruned, as `is_descendant` will
|
||||
// return `false` in this case.
|
||||
let finalized_slot = fork_choice
|
||||
.finalized_checkpoint()
|
||||
.epoch
|
||||
.start_slot(T::EthSpec::slots_per_epoch());
|
||||
let split = chain.store.get_split_info();
|
||||
let is_descendant_from_split_block = split.slot == 0
|
||||
|| split.slot <= finalized_slot
|
||||
|| fork_choice.is_descendant(split.block_root, block.parent_root());
|
||||
|
||||
if fork_choice.is_finalized_checkpoint_or_descendant(block.parent_root())
|
||||
&& is_descendant_from_split_block
|
||||
{
|
||||
Ok(block)
|
||||
} else {
|
||||
// If fork choice does *not* consider the parent to be a descendant of the finalized block,
|
||||
|
||||
@@ -282,8 +282,13 @@ where
|
||||
.get_blinded_block(&chain.genesis_block_root)
|
||||
.map_err(|e| descriptive_db_error("genesis block", &e))?
|
||||
.ok_or("Genesis block not found in store")?;
|
||||
// We're resuming from some state in the db so it makes sense to cache it.
|
||||
let genesis_state = store
|
||||
.get_state(&genesis_block.state_root(), Some(genesis_block.slot()))
|
||||
.get_state(
|
||||
&genesis_block.state_root(),
|
||||
Some(genesis_block.slot()),
|
||||
true,
|
||||
)
|
||||
.map_err(|e| descriptive_db_error("genesis state", &e))?
|
||||
.ok_or("Genesis state not found in store")?;
|
||||
|
||||
|
||||
@@ -773,6 +773,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.execution_status
|
||||
.is_optimistic_or_invalid();
|
||||
|
||||
// Update the state cache so it doesn't mistakenly prune the new head.
|
||||
self.store
|
||||
.state_cache
|
||||
.lock()
|
||||
.update_head_block_root(new_cached_head.head_block_root());
|
||||
|
||||
// Detect and potentially report any re-orgs.
|
||||
let reorg_distance = detect_reorg(
|
||||
&old_snapshot.beacon_state,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
pub use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::time::Duration;
|
||||
use types::{Checkpoint, Epoch};
|
||||
use std::str::FromStr;
|
||||
use std::{collections::HashSet, sync::LazyLock, time::Duration};
|
||||
use types::{Checkpoint, Epoch, Hash256};
|
||||
|
||||
pub const DEFAULT_RE_ORG_HEAD_THRESHOLD: ReOrgThreshold = ReOrgThreshold(20);
|
||||
pub const DEFAULT_RE_ORG_PARENT_THRESHOLD: ReOrgThreshold = ReOrgThreshold(160);
|
||||
@@ -19,6 +20,12 @@ pub const FORK_CHOICE_LOOKAHEAD_FACTOR: u32 = 24;
|
||||
/// Default sync tolerance epochs.
|
||||
pub const DEFAULT_SYNC_TOLERANCE_EPOCHS: u64 = 2;
|
||||
|
||||
/// Invalid block root to be banned from processing and importing on Holesky network by default.
|
||||
pub static INVALID_HOLESKY_BLOCK_ROOT: LazyLock<Hash256> = LazyLock::new(|| {
|
||||
Hash256::from_str("2db899881ed8546476d0b92c6aa9110bea9a4cd0dbeb5519eb0ea69575f1f359")
|
||||
.expect("valid block root")
|
||||
});
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
|
||||
pub struct ChainConfig {
|
||||
/// Maximum number of slots to skip when importing an attestation.
|
||||
@@ -104,6 +111,11 @@ pub struct ChainConfig {
|
||||
pub block_publishing_delay: Option<Duration>,
|
||||
/// Artificial delay for data column publishing. For PeerDAS testing only.
|
||||
pub data_column_publishing_delay: Option<Duration>,
|
||||
/// Block roots of "banned" blocks which Lighthouse will refuse to import.
|
||||
///
|
||||
/// On Holesky there is a block which is added to this set by default but which can be removed
|
||||
/// by using `--invalid-block-roots ""`.
|
||||
pub invalid_block_roots: HashSet<Hash256>,
|
||||
}
|
||||
|
||||
impl Default for ChainConfig {
|
||||
@@ -142,6 +154,7 @@ impl Default for ChainConfig {
|
||||
sync_tolerance_epochs: DEFAULT_SYNC_TOLERANCE_EPOCHS,
|
||||
block_publishing_delay: None,
|
||||
data_column_publishing_delay: None,
|
||||
invalid_block_roots: HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ pub enum BeaconChainError {
|
||||
ForkChoiceStoreError(ForkChoiceStoreError),
|
||||
MissingBeaconBlock(Hash256),
|
||||
MissingBeaconState(Hash256),
|
||||
MissingHotStateSummary(Hash256),
|
||||
SlotProcessingError(SlotProcessingError),
|
||||
EpochProcessingError(EpochProcessingError),
|
||||
StateAdvanceError(StateAdvanceError),
|
||||
@@ -181,9 +182,9 @@ pub enum BeaconChainError {
|
||||
execution_block_hash: Option<ExecutionBlockHash>,
|
||||
},
|
||||
ForkchoiceUpdate(execution_layer::Error),
|
||||
FinalizedCheckpointMismatch {
|
||||
head_state: Checkpoint,
|
||||
fork_choice: Hash256,
|
||||
InvalidCheckpoint {
|
||||
state_root: Hash256,
|
||||
checkpoint: Checkpoint,
|
||||
},
|
||||
InvalidSlot(Slot),
|
||||
HeadBlockNotFullyVerified {
|
||||
|
||||
@@ -113,8 +113,9 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
|
||||
|
||||
// Advance finalized state to finalized epoch (to handle skipped slots).
|
||||
let finalized_state_root = finalized_block.state_root();
|
||||
// The enshrined finalized state should be in the state cache.
|
||||
let mut finalized_state = store
|
||||
.get_state(&finalized_state_root, Some(finalized_block.slot()))
|
||||
.get_state(&finalized_state_root, Some(finalized_block.slot()), true)
|
||||
.map_err(|e| format!("Error loading finalized state: {:?}", e))?
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
|
||||
@@ -317,8 +317,11 @@ impl<T: BeaconChainTypes> LightClientServerCache<T> {
|
||||
metrics::inc_counter(&metrics::LIGHT_CLIENT_SERVER_CACHE_PREV_BLOCK_CACHE_MISS);
|
||||
|
||||
// Compute the value, handling potential errors.
|
||||
// This state should already be cached. By electing not to cache it here
|
||||
// we remove any chance of the light client server from affecting the state cache.
|
||||
// We'd like the light client server to be as minimally invasive as possible.
|
||||
let mut state = store
|
||||
.get_state(block_state_root, Some(block_slot))?
|
||||
.get_state(block_state_root, Some(block_slot), false)?
|
||||
.ok_or_else(|| {
|
||||
BeaconChainError::DBInconsistent(format!("Missing state {:?}", block_state_root))
|
||||
})?;
|
||||
|
||||
@@ -123,14 +123,23 @@ pub enum Notification {
|
||||
Finalization(FinalizationNotification),
|
||||
Reconstruction,
|
||||
PruneBlobs(Epoch),
|
||||
ManualFinalization(ManualFinalizationNotification),
|
||||
ManualCompaction,
|
||||
}
|
||||
|
||||
pub struct ManualFinalizationNotification {
|
||||
pub state_root: BeaconStateHash,
|
||||
pub checkpoint: Checkpoint,
|
||||
pub head_tracker: Arc<HeadTracker>,
|
||||
pub genesis_block_root: Hash256,
|
||||
}
|
||||
|
||||
pub struct FinalizationNotification {
|
||||
finalized_state_root: BeaconStateHash,
|
||||
finalized_checkpoint: Checkpoint,
|
||||
head_tracker: Arc<HeadTracker>,
|
||||
prev_migration: Arc<Mutex<PrevMigration>>,
|
||||
genesis_block_root: Hash256,
|
||||
pub finalized_state_root: BeaconStateHash,
|
||||
pub finalized_checkpoint: Checkpoint,
|
||||
pub head_tracker: Arc<HeadTracker>,
|
||||
pub prev_migration: Arc<Mutex<PrevMigration>>,
|
||||
pub genesis_block_root: Hash256,
|
||||
}
|
||||
|
||||
impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Hot, Cold> {
|
||||
@@ -187,6 +196,22 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn process_manual_compaction(&self) {
|
||||
if let Some(Notification::ManualCompaction) =
|
||||
self.send_background_notification(Notification::ManualCompaction)
|
||||
{
|
||||
Self::run_manual_compaction(self.db.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_manual_finalization(&self, notif: ManualFinalizationNotification) {
|
||||
if let Some(Notification::ManualFinalization(notif)) =
|
||||
self.send_background_notification(Notification::ManualFinalization(notif))
|
||||
{
|
||||
Self::run_manual_migration(self.db.clone(), notif);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_reconstruction(&self) {
|
||||
if let Some(Notification::Reconstruction) =
|
||||
self.send_background_notification(Notification::Reconstruction)
|
||||
@@ -277,6 +302,25 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
}
|
||||
}
|
||||
|
||||
fn run_manual_migration(
|
||||
db: Arc<HotColdDB<E, Hot, Cold>>,
|
||||
notif: ManualFinalizationNotification,
|
||||
) {
|
||||
// We create a "dummy" prev migration
|
||||
let prev_migration = PrevMigration {
|
||||
epoch: Epoch::new(1),
|
||||
epochs_per_migration: 2,
|
||||
};
|
||||
let notif = FinalizationNotification {
|
||||
finalized_state_root: notif.state_root,
|
||||
finalized_checkpoint: notif.checkpoint,
|
||||
head_tracker: notif.head_tracker,
|
||||
prev_migration: Arc::new(prev_migration.into()),
|
||||
genesis_block_root: notif.genesis_block_root,
|
||||
};
|
||||
Self::run_migration(db, notif);
|
||||
}
|
||||
|
||||
/// Perform the actual work of `process_finalization`.
|
||||
fn run_migration(db: Arc<HotColdDB<E, Hot, Cold>>, notif: FinalizationNotification) {
|
||||
// Do not run too frequently.
|
||||
@@ -303,7 +347,8 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
let finalized_state_root = notif.finalized_state_root;
|
||||
let finalized_block_root = notif.finalized_checkpoint.root;
|
||||
|
||||
let finalized_state = match db.get_state(&finalized_state_root.into(), None) {
|
||||
// The enshrined finalized state should be in the state cache.
|
||||
let finalized_state = match db.get_state(&finalized_state_root.into(), None, true) {
|
||||
Ok(Some(state)) => state,
|
||||
other => {
|
||||
error!(
|
||||
@@ -382,6 +427,15 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
debug!("Database consolidation complete");
|
||||
}
|
||||
|
||||
fn run_manual_compaction(db: Arc<HotColdDB<E, Hot, Cold>>) {
|
||||
debug!("Running manual compaction");
|
||||
if let Err(error) = db.compact() {
|
||||
warn!(?error, "Database compaction failed");
|
||||
} else {
|
||||
debug!("Manual compaction completed");
|
||||
}
|
||||
}
|
||||
|
||||
/// Spawn a new child thread to run the migration process.
|
||||
///
|
||||
/// Return a channel handle for sending requests to the thread.
|
||||
@@ -394,16 +448,30 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
while let Ok(notif) = rx.recv() {
|
||||
let mut reconstruction_notif = None;
|
||||
let mut finalization_notif = None;
|
||||
let mut manual_finalization_notif = None;
|
||||
let mut manual_compaction_notif = None;
|
||||
let mut prune_blobs_notif = None;
|
||||
match notif {
|
||||
Notification::Reconstruction => reconstruction_notif = Some(notif),
|
||||
Notification::Finalization(fin) => finalization_notif = Some(fin),
|
||||
Notification::ManualFinalization(fin) => manual_finalization_notif = Some(fin),
|
||||
Notification::PruneBlobs(dab) => prune_blobs_notif = Some(dab),
|
||||
Notification::ManualCompaction => manual_compaction_notif = Some(notif),
|
||||
}
|
||||
// Read the rest of the messages in the channel, taking the best of each type.
|
||||
for notif in rx.try_iter() {
|
||||
match notif {
|
||||
Notification::Reconstruction => reconstruction_notif = Some(notif),
|
||||
Notification::ManualCompaction => manual_compaction_notif = Some(notif),
|
||||
Notification::ManualFinalization(fin) => {
|
||||
if let Some(current) = manual_finalization_notif.as_mut() {
|
||||
if fin.checkpoint.epoch > current.checkpoint.epoch {
|
||||
*current = fin;
|
||||
}
|
||||
} else {
|
||||
manual_finalization_notif = Some(fin);
|
||||
}
|
||||
}
|
||||
Notification::Finalization(fin) => {
|
||||
if let Some(current) = finalization_notif.as_mut() {
|
||||
if fin.finalized_checkpoint.epoch
|
||||
@@ -426,12 +494,18 @@ impl<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<E>> BackgroundMigrator<E, Ho
|
||||
if let Some(fin) = finalization_notif {
|
||||
Self::run_migration(db.clone(), fin);
|
||||
}
|
||||
if let Some(fin) = manual_finalization_notif {
|
||||
Self::run_manual_migration(db.clone(), fin);
|
||||
}
|
||||
if let Some(dab) = prune_blobs_notif {
|
||||
Self::run_prune_blobs(db.clone(), dab);
|
||||
}
|
||||
if reconstruction_notif.is_some() {
|
||||
Self::run_reconstruction(db.clone(), Some(inner_tx.clone()));
|
||||
}
|
||||
if manual_compaction_notif.is_some() {
|
||||
Self::run_manual_compaction(db.clone());
|
||||
}
|
||||
}
|
||||
});
|
||||
(tx, thread)
|
||||
|
||||
@@ -857,7 +857,7 @@ where
|
||||
pub fn get_hot_state(&self, state_hash: BeaconStateHash) -> Option<BeaconState<E>> {
|
||||
self.chain
|
||||
.store
|
||||
.load_hot_state(&state_hash.into())
|
||||
.load_hot_state(&state_hash.into(), true)
|
||||
.unwrap()
|
||||
.map(|(state, _)| state)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user