Add is_parent_strong proposer re-org check (#5417)

* initial fork choice additions

* add helper fns

* add is_parent_strong

* Merge branch 'unstable' of https://github.com/sigp/lighthouse into add_is_parent_strong_check

* disabling proposer reorg should set parent_threshold to u64 max

* add new flag, is_parent_strong check in override fcu params

* cherry-pick changes

* Merge branch 'unstable' of https://github.com/sigp/lighthouse into add_is_parent_strong_check

* cleanup

* fmt

* Minor review tweaks
This commit is contained in:
Eitan Seri-Levi
2024-04-04 22:38:06 +03:00
committed by GitHub
parent 053525e281
commit ee69e14db9
16 changed files with 181 additions and 53 deletions

View File

@@ -517,7 +517,8 @@ where
&self,
current_slot: Slot,
canonical_head: Hash256,
re_org_threshold: ReOrgThreshold,
re_org_head_threshold: ReOrgThreshold,
re_org_parent_threshold: ReOrgThreshold,
disallowed_offsets: &DisallowedReOrgOffsets,
max_epochs_since_finalization: Epoch,
) -> Result<ProposerHeadInfo, ProposerHeadError<Error<proto_array::Error>>> {
@@ -549,7 +550,8 @@ where
current_slot,
canonical_head,
self.fc_store.justified_balances(),
re_org_threshold,
re_org_head_threshold,
re_org_parent_threshold,
disallowed_offsets,
max_epochs_since_finalization,
)
@@ -559,7 +561,8 @@ where
pub fn get_preliminary_proposer_head(
&self,
canonical_head: Hash256,
re_org_threshold: ReOrgThreshold,
re_org_head_threshold: ReOrgThreshold,
re_org_parent_threshold: ReOrgThreshold,
disallowed_offsets: &DisallowedReOrgOffsets,
max_epochs_since_finalization: Epoch,
) -> Result<ProposerHeadInfo, ProposerHeadError<Error<proto_array::Error>>> {
@@ -569,7 +572,8 @@ where
current_slot,
canonical_head,
self.fc_store.justified_balances(),
re_org_threshold,
re_org_head_threshold,
re_org_parent_threshold,
disallowed_offsets,
max_epochs_since_finalization,
)
@@ -706,6 +710,7 @@ where
// Add proposer score boost if the block is timely.
let is_before_attesting_interval =
block_delay < Duration::from_secs(spec.seconds_per_slot / INTERVALS_PER_SLOT);
let is_first_block = self.fc_store.proposer_boost_root().is_zero();
if current_slot == block.slot() && is_before_attesting_interval && is_first_block {
self.fc_store.set_proposer_boost_root(block_root);

View File

@@ -195,8 +195,10 @@ pub struct ProposerHeadInfo {
/// Information about the parent of the current head, which should be selected as the parent
/// for a new proposal *if* a re-org is decided on.
pub parent_node: ProtoNode,
/// The computed fraction of the active committee balance below which we can re-org.
pub re_org_weight_threshold: u64,
/// The computed fraction of the active head committee balance below which we can re-org.
pub re_org_head_weight_threshold: u64,
/// The computed fraction of the active parent committee balance above which we can re-org.
pub re_org_parent_weight_threshold: u64,
/// The current slot from fork choice's point of view, may lead the wall-clock slot by upto
/// 500ms.
pub current_slot: Slot,
@@ -259,7 +261,11 @@ pub enum DoNotReOrg {
},
HeadNotWeak {
head_weight: u64,
re_org_weight_threshold: u64,
re_org_head_weight_threshold: u64,
},
ParentNotStrong {
parent_weight: u64,
re_org_parent_weight_threshold: u64,
},
HeadNotLate,
NotProposing,
@@ -288,9 +294,21 @@ impl std::fmt::Display for DoNotReOrg {
),
Self::HeadNotWeak {
head_weight,
re_org_weight_threshold,
re_org_head_weight_threshold,
} => {
write!(f, "head not weak ({head_weight}/{re_org_weight_threshold})")
write!(
f,
"head not weak ({head_weight}/{re_org_head_weight_threshold})"
)
}
Self::ParentNotStrong {
parent_weight,
re_org_parent_weight_threshold,
} => {
write!(
f,
"parent not strong ({parent_weight}/{re_org_parent_weight_threshold})"
)
}
Self::HeadNotLate => {
write!(f, "head arrived on time")
@@ -486,12 +504,14 @@ impl ProtoArrayForkChoice {
/// Get the block to propose on during `current_slot`.
///
/// This function returns a *definitive* result which should be acted on.
#[allow(clippy::too_many_arguments)]
pub fn get_proposer_head<E: EthSpec>(
&self,
current_slot: Slot,
canonical_head: Hash256,
justified_balances: &JustifiedBalances,
re_org_threshold: ReOrgThreshold,
re_org_head_threshold: ReOrgThreshold,
re_org_parent_threshold: ReOrgThreshold,
disallowed_offsets: &DisallowedReOrgOffsets,
max_epochs_since_finalization: Epoch,
) -> Result<ProposerHeadInfo, ProposerHeadError<Error>> {
@@ -499,7 +519,8 @@ impl ProtoArrayForkChoice {
current_slot,
canonical_head,
justified_balances,
re_org_threshold,
re_org_head_threshold,
re_org_parent_threshold,
disallowed_offsets,
max_epochs_since_finalization,
)?;
@@ -510,14 +531,26 @@ impl ProtoArrayForkChoice {
return Err(DoNotReOrg::HeadDistance.into());
}
// Only re-org if the head's weight is less than the configured committee fraction.
// Only re-org if the head's weight is less than the heads configured committee fraction.
let head_weight = info.head_node.weight;
let re_org_weight_threshold = info.re_org_weight_threshold;
let weak_head = head_weight < re_org_weight_threshold;
let re_org_head_weight_threshold = info.re_org_head_weight_threshold;
let weak_head = head_weight < re_org_head_weight_threshold;
if !weak_head {
return Err(DoNotReOrg::HeadNotWeak {
head_weight,
re_org_weight_threshold,
re_org_head_weight_threshold,
}
.into());
}
// Only re-org if the parent's weight is greater than the parents configured committee fraction.
let parent_weight = info.parent_node.weight;
let re_org_parent_weight_threshold = info.re_org_parent_weight_threshold;
let parent_strong = parent_weight > re_org_parent_weight_threshold;
if !parent_strong {
return Err(DoNotReOrg::ParentNotStrong {
parent_weight,
re_org_parent_weight_threshold,
}
.into());
}
@@ -529,12 +562,14 @@ impl ProtoArrayForkChoice {
/// Get information about the block to propose on during `current_slot`.
///
/// This function returns a *partial* result which must be processed further.
#[allow(clippy::too_many_arguments)]
pub fn get_proposer_head_info<E: EthSpec>(
&self,
current_slot: Slot,
canonical_head: Hash256,
justified_balances: &JustifiedBalances,
re_org_threshold: ReOrgThreshold,
re_org_head_threshold: ReOrgThreshold,
re_org_parent_threshold: ReOrgThreshold,
disallowed_offsets: &DisallowedReOrgOffsets,
max_epochs_since_finalization: Epoch,
) -> Result<ProposerHeadInfo, ProposerHeadError<Error>> {
@@ -595,15 +630,20 @@ impl ProtoArrayForkChoice {
return Err(DoNotReOrg::JustificationAndFinalizationNotCompetitive.into());
}
// Compute re-org weight threshold.
let re_org_weight_threshold =
calculate_committee_fraction::<E>(justified_balances, re_org_threshold.0)
// Compute re-org weight thresholds for head and parent.
let re_org_head_weight_threshold =
calculate_committee_fraction::<E>(justified_balances, re_org_head_threshold.0)
.ok_or(Error::ReOrgThresholdOverflow)?;
let re_org_parent_weight_threshold =
calculate_committee_fraction::<E>(justified_balances, re_org_parent_threshold.0)
.ok_or(Error::ReOrgThresholdOverflow)?;
Ok(ProposerHeadInfo {
head_node,
parent_node,
re_org_weight_threshold,
re_org_head_weight_threshold,
re_org_parent_weight_threshold,
current_slot,
})
}

View File

@@ -114,6 +114,8 @@ pub struct ChainSpec {
*/
pub safe_slots_to_update_justified: u64,
pub proposer_score_boost: Option<u64>,
pub reorg_head_weight_threshold: Option<u64>,
pub reorg_parent_weight_threshold: Option<u64>,
/*
* Eth1
@@ -642,6 +644,8 @@ impl ChainSpec {
*/
safe_slots_to_update_justified: 8,
proposer_score_boost: Some(40),
reorg_head_weight_threshold: Some(20),
reorg_parent_weight_threshold: Some(160),
/*
* Eth1
@@ -912,6 +916,8 @@ impl ChainSpec {
*/
safe_slots_to_update_justified: 8,
proposer_score_boost: Some(40),
reorg_head_weight_threshold: Some(20),
reorg_parent_weight_threshold: Some(160),
/*
* Eth1