From 2614cba5a773ec58efec595ad9c9d785a30e1cef Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 10:58:56 +0800 Subject: [PATCH 01/26] delete reorg parent and head cli --- beacon_node/beacon_chain/src/chain_config.rs | 6 ++-- beacon_node/src/cli.rs | 20 ------------- beacon_node/src/config.rs | 17 ++++------- lighthouse/tests/beacon_node.rs | 30 +++++--------------- testing/ef_tests/src/cases/fork_choice.rs | 13 ++++++--- 5 files changed, 23 insertions(+), 63 deletions(-) diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index b2c017a469d..8f2be87d756 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -5,8 +5,6 @@ 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); pub const DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION: Epoch = Epoch::new(2); /// Default to 1/12th of the slot, which is 1 second on mainnet. pub const DEFAULT_RE_ORG_CUTOFF_DENOMINATOR: u32 = 12; @@ -134,8 +132,8 @@ impl Default for ChainConfig { weak_subjectivity_checkpoint: None, archive: false, max_network_size: 10 * 1_048_576, // 10M - re_org_head_threshold: Some(DEFAULT_RE_ORG_HEAD_THRESHOLD), - re_org_parent_threshold: Some(DEFAULT_RE_ORG_PARENT_THRESHOLD), + re_org_head_threshold: None, + re_org_parent_threshold: None, re_org_max_epochs_since_finalization: DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, re_org_cutoff_millis: None, re_org_disallowed_offsets: DisallowedReOrgOffsets::default(), diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 51cda0fac3b..b2256a00298 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -1315,26 +1315,6 @@ pub fn cli_app() -> Command { .help_heading(FLAG_HEADER) .display_order(0) ) - .arg( - Arg::new("proposer-reorg-threshold") - .long("proposer-reorg-threshold") - .action(ArgAction::Set) - .value_name("PERCENT") - .help("Percentage of head vote weight below which to attempt a proposer reorg. \ - Default: 20%") - .conflicts_with("disable-proposer-reorgs") - .display_order(0) - ) - .arg( - Arg::new("proposer-reorg-parent-threshold") - .long("proposer-reorg-parent-threshold") - .value_name("PERCENT") - .help("Percentage of parent vote weight above which to attempt a proposer reorg. \ - Default: 160%") - .conflicts_with("disable-proposer-reorgs") - .action(ArgAction::Set) - .display_order(0) - ) .arg( Arg::new("proposer-reorg-epochs-since-finalization") .long("proposer-reorg-epochs-since-finalization") diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 8ba2c0f3214..6fa2f3074fd 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -1,7 +1,6 @@ use account_utils::{STDIN_INPUTS_FLAG, read_input_from_user}; use beacon_chain::chain_config::{ - DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR, DEFAULT_RE_ORG_HEAD_THRESHOLD, - DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DEFAULT_RE_ORG_PARENT_THRESHOLD, + DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DisallowedReOrgOffsets, INVALID_HOLESKY_BLOCK_ROOT, ReOrgThreshold, }; use beacon_chain::custody_context::NodeCustodyType; @@ -745,22 +744,16 @@ pub fn get_config( client_config.chain.re_org_head_threshold = None; client_config.chain.re_org_parent_threshold = None; } else { - client_config.chain.re_org_head_threshold = Some( - clap_utils::parse_optional(cli_args, "proposer-reorg-threshold")? - .map(ReOrgThreshold) - .unwrap_or(DEFAULT_RE_ORG_HEAD_THRESHOLD), - ); + client_config.chain.re_org_head_threshold = + spec.reorg_head_weight_threshold.map(ReOrgThreshold); client_config.chain.re_org_max_epochs_since_finalization = clap_utils::parse_optional(cli_args, "proposer-reorg-epochs-since-finalization")? .unwrap_or(DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION); client_config.chain.re_org_cutoff_millis = clap_utils::parse_optional(cli_args, "proposer-reorg-cutoff")?; - client_config.chain.re_org_parent_threshold = Some( - clap_utils::parse_optional(cli_args, "proposer-reorg-parent-threshold")? - .map(ReOrgThreshold) - .unwrap_or(DEFAULT_RE_ORG_PARENT_THRESHOLD), - ); + client_config.chain.re_org_parent_threshold = + spec.reorg_parent_weight_threshold.map(ReOrgThreshold); if let Some(disallowed_offsets_str) = clap_utils::parse_optional::(cli_args, "proposer-reorg-disallowed-offsets")? diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 0c5d9a59334..db0414bf9bb 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -1,8 +1,7 @@ use crate::exec::{CommandLineTestExec, CompletedTest}; use beacon_node::beacon_chain::chain_config::{ - DEFAULT_RE_ORG_CUTOFF_DENOMINATOR, DEFAULT_RE_ORG_HEAD_THRESHOLD, - DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DEFAULT_SYNC_TOLERANCE_EPOCHS, - DisallowedReOrgOffsets, + DEFAULT_RE_ORG_CUTOFF_DENOMINATOR, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, + DEFAULT_SYNC_TOLERANCE_EPOCHS, DisallowedReOrgOffsets, ReOrgThreshold, }; use beacon_node::beacon_chain::custody_context::NodeCustodyType; use beacon_node::{ @@ -2345,10 +2344,11 @@ fn enable_proposer_re_orgs_default() { CommandLineTest::new() .run_with_zero_port() .with_config(|config| { - assert_eq!( - config.chain.re_org_head_threshold, - Some(DEFAULT_RE_ORG_HEAD_THRESHOLD) - ); + let expected = types::ChainSpec::mainnet() + .reorg_head_weight_threshold + .unwrap() + .map(ReOrgThreshold); + assert_eq!(config.chain.re_org_head_threshold, expected); assert_eq!( config.chain.re_org_max_epochs_since_finalization, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, @@ -2371,22 +2371,6 @@ fn disable_proposer_re_orgs() { }); } -#[test] -fn proposer_re_org_parent_threshold() { - CommandLineTest::new() - .flag("proposer-reorg-parent-threshold", Some("90")) - .run_with_zero_port() - .with_config(|config| assert_eq!(config.chain.re_org_parent_threshold.unwrap().0, 90)); -} - -#[test] -fn proposer_re_org_head_threshold() { - CommandLineTest::new() - .flag("proposer-reorg-threshold", Some("90")) - .run_with_zero_port() - .with_config(|config| assert_eq!(config.chain.re_org_head_threshold.unwrap().0, 90)); -} - #[test] fn proposer_re_org_max_epochs_since_finalization() { CommandLineTest::new() diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 2af205ee471..477e9f996ea 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -5,8 +5,7 @@ use beacon_chain::beacon_proposer_cache::compute_proposer_duties_from_head; use beacon_chain::blob_verification::GossipBlobError; use beacon_chain::block_verification_types::LookupBlock; use beacon_chain::chain_config::{ - DEFAULT_RE_ORG_HEAD_THRESHOLD, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, - DEFAULT_RE_ORG_PARENT_THRESHOLD, DisallowedReOrgOffsets, + DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DisallowedReOrgOffsets, ReOrgThreshold, }; use beacon_chain::data_column_verification::GossipVerifiedDataColumn; use beacon_chain::slot_clock::SlotClock; @@ -979,8 +978,14 @@ impl Tester { let proposer_head_result = fc.get_proposer_head( slot, canonical_head, - DEFAULT_RE_ORG_HEAD_THRESHOLD, - DEFAULT_RE_ORG_PARENT_THRESHOLD, + self.spec + .reorg_head_weight_threshold + .map(ReOrgThreshold) + .unwrap(), + self.spec + .reorg_parent_weight_threshold + .map(ReOrgThreshold) + .unwrap(), &DisallowedReOrgOffsets::default(), DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, ); From edf9451183e85e8940ba9b235b9fdc18e0fe79f0 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 10:59:04 +0800 Subject: [PATCH 02/26] test --- lighthouse/tests/beacon_node.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index db0414bf9bb..9613fd7ac79 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2346,7 +2346,6 @@ fn enable_proposer_re_orgs_default() { .with_config(|config| { let expected = types::ChainSpec::mainnet() .reorg_head_weight_threshold - .unwrap() .map(ReOrgThreshold); assert_eq!(config.chain.re_org_head_threshold, expected); assert_eq!( From 8b277c0b3c200525655c4fcba2d22ce818466c2d Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 11:26:03 +0800 Subject: [PATCH 03/26] delete reorg max cli flag --- beacon_node/beacon_chain/src/chain_config.rs | 3 +-- beacon_node/src/cli.rs | 10 -------- beacon_node/src/config.rs | 11 +++++---- lighthouse/tests/beacon_node.rs | 26 ++++++-------------- testing/ef_tests/src/cases/fork_choice.rs | 15 +++++------ 5 files changed, 22 insertions(+), 43 deletions(-) diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 8f2be87d756..32578b21c59 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -5,7 +5,6 @@ use std::str::FromStr; use std::{collections::HashSet, sync::LazyLock, time::Duration}; use types::{Checkpoint, Epoch, Hash256}; -pub const DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION: Epoch = Epoch::new(2); /// Default to 1/12th of the slot, which is 1 second on mainnet. pub const DEFAULT_RE_ORG_CUTOFF_DENOMINATOR: u32 = 12; pub const DEFAULT_FORK_CHOICE_BEFORE_PROPOSAL_TIMEOUT: u64 = 250; @@ -134,7 +133,7 @@ impl Default for ChainConfig { max_network_size: 10 * 1_048_576, // 10M re_org_head_threshold: None, re_org_parent_threshold: None, - re_org_max_epochs_since_finalization: DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, + re_org_max_epochs_since_finalization: Epoch::new(2), re_org_cutoff_millis: None, re_org_disallowed_offsets: DisallowedReOrgOffsets::default(), fork_choice_before_proposal_timeout_ms: DEFAULT_FORK_CHOICE_BEFORE_PROPOSAL_TIMEOUT, diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index b2256a00298..eb4c05d8b01 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -1315,16 +1315,6 @@ pub fn cli_app() -> Command { .help_heading(FLAG_HEADER) .display_order(0) ) - .arg( - Arg::new("proposer-reorg-epochs-since-finalization") - .long("proposer-reorg-epochs-since-finalization") - .action(ArgAction::Set) - .value_name("EPOCHS") - .help("Maximum number of epochs since finalization at which proposer reorgs are \ - allowed. Default: 2") - .conflicts_with("disable-proposer-reorgs") - .display_order(0) - ) .arg( Arg::new("proposer-reorg-cutoff") .long("proposer-reorg-cutoff") diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 6fa2f3074fd..e4e35dbd6d4 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -1,7 +1,7 @@ use account_utils::{STDIN_INPUTS_FLAG, read_input_from_user}; use beacon_chain::chain_config::{ - DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, - DisallowedReOrgOffsets, INVALID_HOLESKY_BLOCK_ROOT, ReOrgThreshold, + DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR, DisallowedReOrgOffsets, INVALID_HOLESKY_BLOCK_ROOT, + ReOrgThreshold, }; use beacon_chain::custody_context::NodeCustodyType; use beacon_chain::graffiti_calculator::GraffitiOrigin; @@ -746,9 +746,10 @@ pub fn get_config( } else { client_config.chain.re_org_head_threshold = spec.reorg_head_weight_threshold.map(ReOrgThreshold); - client_config.chain.re_org_max_epochs_since_finalization = - clap_utils::parse_optional(cli_args, "proposer-reorg-epochs-since-finalization")? - .unwrap_or(DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION); + client_config.chain.re_org_max_epochs_since_finalization = spec + .reorg_max_epochs_since_finalization + .map(Epoch::new) + .unwrap_or(Epoch::new(2)); client_config.chain.re_org_cutoff_millis = clap_utils::parse_optional(cli_args, "proposer-reorg-cutoff")?; diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 9613fd7ac79..aefaad83846 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -1,7 +1,7 @@ use crate::exec::{CommandLineTestExec, CompletedTest}; use beacon_node::beacon_chain::chain_config::{ - DEFAULT_RE_ORG_CUTOFF_DENOMINATOR, DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, - DEFAULT_SYNC_TOLERANCE_EPOCHS, DisallowedReOrgOffsets, ReOrgThreshold, + DEFAULT_RE_ORG_CUTOFF_DENOMINATOR, DEFAULT_SYNC_TOLERANCE_EPOCHS, DisallowedReOrgOffsets, + ReOrgThreshold, }; use beacon_node::beacon_chain::custody_context::NodeCustodyType; use beacon_node::{ @@ -2348,10 +2348,11 @@ fn enable_proposer_re_orgs_default() { .reorg_head_weight_threshold .map(ReOrgThreshold); assert_eq!(config.chain.re_org_head_threshold, expected); - assert_eq!( - config.chain.re_org_max_epochs_since_finalization, - DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, - ); + let expected = types::ChainSpec::mainnet() + .reorg_max_epochs_since_finalization + .map(Epoch::new) + .unwrap(); + assert_eq!(config.chain.re_org_max_epochs_since_finalization, expected,); assert_eq!( config.chain.re_org_cutoff(Duration::from_secs(12)), Duration::from_secs(12) / DEFAULT_RE_ORG_CUTOFF_DENOMINATOR @@ -2370,19 +2371,6 @@ fn disable_proposer_re_orgs() { }); } -#[test] -fn proposer_re_org_max_epochs_since_finalization() { - CommandLineTest::new() - .flag("proposer-reorg-epochs-since-finalization", Some("8")) - .run_with_zero_port() - .with_config(|config| { - assert_eq!( - config.chain.re_org_max_epochs_since_finalization.as_u64(), - 8 - ) - }); -} - #[test] fn proposer_re_org_cutoff() { CommandLineTest::new() diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 477e9f996ea..5fe393bd419 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -4,9 +4,7 @@ use ::fork_choice::{PayloadVerificationStatus, ProposerHeadError}; use beacon_chain::beacon_proposer_cache::compute_proposer_duties_from_head; use beacon_chain::blob_verification::GossipBlobError; use beacon_chain::block_verification_types::LookupBlock; -use beacon_chain::chain_config::{ - DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DisallowedReOrgOffsets, ReOrgThreshold, -}; +use beacon_chain::chain_config::{DisallowedReOrgOffsets, ReOrgThreshold}; use beacon_chain::data_column_verification::GossipVerifiedDataColumn; use beacon_chain::slot_clock::SlotClock; use beacon_chain::{ @@ -32,9 +30,9 @@ use std::time::Duration; use types::{ Attestation, AttestationRef, AttesterSlashing, AttesterSlashingRef, BeaconBlock, BeaconState, BlobSidecar, BlobsList, BlockImportSource, Checkpoint, DataColumnSidecar, - DataColumnSidecarList, DataColumnSubnetId, ExecutionBlockHash, Hash256, IndexedAttestation, - KzgProof, ProposerPreparationData, SignedBeaconBlock, SignedExecutionPayloadEnvelope, Slot, - Uint256, + DataColumnSidecarList, DataColumnSubnetId, Epoch, ExecutionBlockHash, Hash256, + IndexedAttestation, KzgProof, ProposerPreparationData, SignedBeaconBlock, + SignedExecutionPayloadEnvelope, Slot, Uint256, }; // When set to true, cache any states fetched from the db. @@ -987,7 +985,10 @@ impl Tester { .map(ReOrgThreshold) .unwrap(), &DisallowedReOrgOffsets::default(), - DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, + self.spec + .reorg_max_epochs_since_finalization + .map(Epoch::new) + .unwrap(), ); let proposer_head = match proposer_head_result { Ok(head) => head.parent_node.root(), From 8946f48f8c42a6e9905ee7e6168b2b6b30eb6e46 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 11:26:32 +0800 Subject: [PATCH 04/26] simplify test --- lighthouse/tests/beacon_node.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index aefaad83846..96fdaeb09d6 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2344,15 +2344,6 @@ fn enable_proposer_re_orgs_default() { CommandLineTest::new() .run_with_zero_port() .with_config(|config| { - let expected = types::ChainSpec::mainnet() - .reorg_head_weight_threshold - .map(ReOrgThreshold); - assert_eq!(config.chain.re_org_head_threshold, expected); - let expected = types::ChainSpec::mainnet() - .reorg_max_epochs_since_finalization - .map(Epoch::new) - .unwrap(); - assert_eq!(config.chain.re_org_max_epochs_since_finalization, expected,); assert_eq!( config.chain.re_org_cutoff(Duration::from_secs(12)), Duration::from_secs(12) / DEFAULT_RE_ORG_CUTOFF_DENOMINATOR From fe7093771e3e52151b524133a3f3be4beb074aa9 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 11:36:03 +0800 Subject: [PATCH 05/26] update cli help text --- book/src/help_bn.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/book/src/help_bn.md b/book/src/help_bn.md index b580bcae528..356c261321d 100644 --- a/book/src/help_bn.md +++ b/book/src/help_bn.md @@ -317,15 +317,6 @@ Options: SLOTS_PER_EPOCH == N`. By default only re-orgs at offset 0 will be avoided. Any offsets supplied with this flag will impose additional restrictions. - --proposer-reorg-epochs-since-finalization - Maximum number of epochs since finalization at which proposer reorgs - are allowed. Default: 2 - --proposer-reorg-parent-threshold - Percentage of parent vote weight above which to attempt a proposer - reorg. Default: 160% - --proposer-reorg-threshold - Percentage of head vote weight below which to attempt a proposer - reorg. Default: 20% --prune-blobs Prune blobs from Lighthouse's database when they are older than the data data availability boundary relative to the current epoch. From f33e33aa0fb54afbbdbe92757d9145739a71f535 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 11:41:56 +0800 Subject: [PATCH 06/26] update book --- book/src/advanced_re-orgs.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/book/src/advanced_re-orgs.md b/book/src/advanced_re-orgs.md index 3a31778786d..88ff1c9d093 100644 --- a/book/src/advanced_re-orgs.md +++ b/book/src/advanced_re-orgs.md @@ -14,8 +14,6 @@ attestations and transactions that can be included. There are three flags which control the re-orging behaviour: * `--disable-proposer-reorgs`: turn re-orging off (it's on by default). -* `--proposer-reorg-threshold N`: attempt to orphan blocks with less than N% of the committee vote. If this parameter isn't set then N defaults to 20% when the feature is enabled. -* `--proposer-reorg-epochs-since-finalization N`: only attempt to re-org late blocks when the number of epochs since finalization is less than or equal to N. The default is 2 epochs, meaning re-orgs will only be attempted when the chain is finalizing optimally. * `--proposer-reorg-cutoff T`: only attempt to re-org late blocks when the proposal is being made before T milliseconds into the slot. Delays between the validator client and the beacon node can From 6d6cd17dc755621c661031f981537ad82359c9f4 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 12:00:05 +0800 Subject: [PATCH 07/26] test lint --- lighthouse/tests/beacon_node.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 96fdaeb09d6..eba18c6f9fd 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -1,7 +1,6 @@ use crate::exec::{CommandLineTestExec, CompletedTest}; use beacon_node::beacon_chain::chain_config::{ DEFAULT_RE_ORG_CUTOFF_DENOMINATOR, DEFAULT_SYNC_TOLERANCE_EPOCHS, DisallowedReOrgOffsets, - ReOrgThreshold, }; use beacon_node::beacon_chain::custody_context::NodeCustodyType; use beacon_node::{ From 5dc993d4a482608532389986f0645e8a8650852e Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 17:41:13 +0800 Subject: [PATCH 08/26] fix http reorg test --- beacon_node/beacon_chain/src/builder.rs | 6 ++++++ beacon_node/http_api/tests/interactive_tests.rs | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index 19eb1aa8778..564bc4380f0 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -181,6 +181,12 @@ where self } + /// Sets the proposer parent re-org threshold + pub fn proposer_re_org_parent_threshold(mut self, threshold: Option) -> Self { + self.chain_config.re_org_parent_threshold = threshold; + self + } + /// Sets the proposer re-org max epochs since finalization. pub fn proposer_re_org_max_epochs_since_finalization( mut self, diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index 15f61537a06..97c3aa3bc00 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -184,7 +184,8 @@ pub struct ReOrgTest { parent_distance: u64, /// Number of slots between head block and block proposal slot. head_distance: u64, - re_org_threshold: u64, + re_org_head_threshold: u64, + re_org_parent_threshold: u64, max_epochs_since_finalization: u64, percent_parent_votes: usize, percent_empty_votes: usize, @@ -204,7 +205,8 @@ impl Default for ReOrgTest { head_slot: Slot::new(E::slots_per_epoch() - 2), parent_distance: 1, head_distance: 1, - re_org_threshold: 20, + re_org_head_threshold: 20, + re_org_parent_threshold: 160, max_epochs_since_finalization: 2, percent_parent_votes: 100, percent_empty_votes: 100, @@ -390,7 +392,8 @@ pub async fn proposer_boost_re_org_test( head_slot, parent_distance, head_distance, - re_org_threshold, + re_org_head_threshold, + re_org_parent_threshold, max_epochs_since_finalization, percent_parent_votes, percent_empty_votes, @@ -433,6 +436,7 @@ pub async fn proposer_boost_re_org_test( Some(Box::new(move |builder| { builder .proposer_re_org_head_threshold(Some(ReOrgThreshold(re_org_threshold))) + .proposer_re_org_parent_threshold(Some(ReOrgThreshold(re_org_parent_threshold))) .proposer_re_org_max_epochs_since_finalization(Epoch::new( max_epochs_since_finalization, )) From 9fc7249e7a3e15d8e3eb5b812474ea33e5befbdf Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 17:42:01 +0800 Subject: [PATCH 09/26] fix error --- beacon_node/http_api/tests/interactive_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index 97c3aa3bc00..faf106d8c9b 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -435,7 +435,7 @@ pub async fn proposer_boost_re_org_test( None, Some(Box::new(move |builder| { builder - .proposer_re_org_head_threshold(Some(ReOrgThreshold(re_org_threshold))) + .proposer_re_org_head_threshold(Some(ReOrgThreshold(re_org_head_threshold))) .proposer_re_org_parent_threshold(Some(ReOrgThreshold(re_org_parent_threshold))) .proposer_re_org_max_epochs_since_finalization(Epoch::new( max_epochs_since_finalization, From 739472f013eedc541231f843d287947ada0c16a3 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 18:04:43 +0800 Subject: [PATCH 10/26] fix ef-test --- testing/ef_tests/src/cases/fork_choice.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 5fe393bd419..9d93416b305 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -487,6 +487,8 @@ impl Tester { .keypairs(vec![]) .chain_config(ChainConfig { archive: true, + re_org_head_threshold: spec.reorg_head_weight_threshold.map(ReOrgThreshold), + re_org_parent_threshold: spec.reorg_parent_weight_threshold.map(ReOrgThreshold), ..ChainConfig::default() }) .genesis_state_ephemeral_store(case.anchor_state.clone()) From 187ebff0d850e97372f812d9d6d7a4528e46a0eb Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 27 Apr 2026 19:35:17 +0800 Subject: [PATCH 11/26] put default --- beacon_node/beacon_chain/src/chain_config.rs | 4 ++-- testing/ef_tests/src/cases/fork_choice.rs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 32578b21c59..9de16d49bcb 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -131,8 +131,8 @@ impl Default for ChainConfig { weak_subjectivity_checkpoint: None, archive: false, max_network_size: 10 * 1_048_576, // 10M - re_org_head_threshold: None, - re_org_parent_threshold: None, + re_org_head_threshold: Some(ReOrgThreshold(20)), + re_org_parent_threshold: Some(ReOrgThreshold(160)), re_org_max_epochs_since_finalization: Epoch::new(2), re_org_cutoff_millis: None, re_org_disallowed_offsets: DisallowedReOrgOffsets::default(), diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 9d93416b305..5fe393bd419 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -487,8 +487,6 @@ impl Tester { .keypairs(vec![]) .chain_config(ChainConfig { archive: true, - re_org_head_threshold: spec.reorg_head_weight_threshold.map(ReOrgThreshold), - re_org_parent_threshold: spec.reorg_parent_weight_threshold.map(ReOrgThreshold), ..ChainConfig::default() }) .genesis_state_ephemeral_store(case.anchor_state.clone()) From 1a053d319305c913dcd4c825ab605324e32a7467 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Thu, 30 Apr 2026 21:11:36 +0800 Subject: [PATCH 12/26] revise --- beacon_node/beacon_chain/src/beacon_chain.rs | 7 ++++--- beacon_node/beacon_chain/src/block_production/mod.rs | 4 ++-- beacon_node/beacon_chain/src/builder.rs | 6 ------ beacon_node/beacon_chain/src/chain_config.rs | 3 --- beacon_node/http_api/tests/interactive_tests.rs | 8 ++------ beacon_node/src/config.rs | 3 --- lighthouse/tests/beacon_node.rs | 5 +---- 7 files changed, 9 insertions(+), 27 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index f3861ac7276..814cec4df7e 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -105,7 +105,7 @@ use operation_pool::{ CompactAttestationRef, OperationPool, PersistedOperationPool, ReceivedPreCapella, }; use parking_lot::{Mutex, RwLock, RwLockWriteGuard}; -use proto_array::{DoNotReOrg, ProposerHeadError}; +use proto_array::{DoNotReOrg, ProposerHeadError, ReOrgThreshold}; use rand::RngCore; use safe_arith::SafeArith; use slasher::Slasher; @@ -4940,8 +4940,9 @@ impl BeaconChain { // Never override if proposer re-orgs are disabled. let re_org_head_threshold = self - .config - .re_org_head_threshold + .spec + .reorg_head_weight_threshold + .map(ReOrgThreshold) .ok_or(Box::new(DoNotReOrg::ReOrgsDisabled.into()))?; let re_org_parent_threshold = self diff --git a/beacon_node/beacon_chain/src/block_production/mod.rs b/beacon_node/beacon_chain/src/block_production/mod.rs index fd5e3810232..7c5eaf9fe57 100644 --- a/beacon_node/beacon_chain/src/block_production/mod.rs +++ b/beacon_node/beacon_chain/src/block_production/mod.rs @@ -1,7 +1,7 @@ use std::{sync::Arc, time::Duration}; use fork_choice::PayloadStatus; -use proto_array::ProposerHeadError; +use proto_array::{ProposerHeadError, ReOrgThreshold}; use slot_clock::SlotClock; use tracing::{debug, error, info, instrument, warn}; use types::{BeaconState, Hash256, SignedExecutionPayloadEnvelope, Slot}; @@ -174,7 +174,7 @@ impl BeaconChain { head_slot: Slot, canonical_head: Hash256, ) -> Option<(BeaconState, Hash256)> { - let re_org_head_threshold = self.config.re_org_head_threshold?; + let re_org_head_threshold = self.spec.reorg_head_weight_threshold.map(ReOrgThreshold)?; let re_org_parent_threshold = self.config.re_org_parent_threshold?; if self.spec.proposer_score_boost.is_none() { diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index 564bc4380f0..57222bc343d 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -175,12 +175,6 @@ where self } - /// Sets the proposer re-org threshold. - pub fn proposer_re_org_head_threshold(mut self, threshold: Option) -> Self { - self.chain_config.re_org_head_threshold = threshold; - self - } - /// Sets the proposer parent re-org threshold pub fn proposer_re_org_parent_threshold(mut self, threshold: Option) -> Self { self.chain_config.re_org_parent_threshold = threshold; diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 9de16d49bcb..9e0fdd8b4c5 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -38,8 +38,6 @@ pub struct ChainConfig { pub archive: bool, /// The max size of a message that can be sent over the network. pub max_network_size: usize, - /// Maximum percentage of the head committee weight at which to attempt re-orging the canonical head. - pub re_org_head_threshold: Option, /// Minimum percentage of the parent committee weight at which to attempt re-orging the canonical head. pub re_org_parent_threshold: Option, /// Maximum number of epochs since finalization for attempting a proposer re-org. @@ -131,7 +129,6 @@ impl Default for ChainConfig { weak_subjectivity_checkpoint: None, archive: false, max_network_size: 10 * 1_048_576, // 10M - re_org_head_threshold: Some(ReOrgThreshold(20)), re_org_parent_threshold: Some(ReOrgThreshold(160)), re_org_max_epochs_since_finalization: Epoch::new(2), re_org_cutoff_millis: None, diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index faf106d8c9b..46f45921de5 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -23,7 +23,7 @@ use std::sync::Arc; use std::time::Duration; use types::{ Address, Epoch, EthSpec, ExecPayload, ExecutionBlockHash, ForkName, Hash256, MainnetEthSpec, - MinimalEthSpec, ProposerPreparationData, Slot, Uint256, + MinimalEthSpec, ProposerPreparationData, Slot, }; type E = MainnetEthSpec; @@ -184,7 +184,6 @@ pub struct ReOrgTest { parent_distance: u64, /// Number of slots between head block and block proposal slot. head_distance: u64, - re_org_head_threshold: u64, re_org_parent_threshold: u64, max_epochs_since_finalization: u64, percent_parent_votes: usize, @@ -205,7 +204,6 @@ impl Default for ReOrgTest { head_slot: Slot::new(E::slots_per_epoch() - 2), parent_distance: 1, head_distance: 1, - re_org_head_threshold: 20, re_org_parent_threshold: 160, max_epochs_since_finalization: 2, percent_parent_votes: 100, @@ -392,7 +390,6 @@ pub async fn proposer_boost_re_org_test( head_slot, parent_distance, head_distance, - re_org_head_threshold, re_org_parent_threshold, max_epochs_since_finalization, percent_parent_votes, @@ -411,7 +408,7 @@ pub async fn proposer_boost_re_org_test( // Issue is that `get_validator_blocks_v3` below expects to be able to use `state.latest_execution_payload_header` during `produce_block_on_state` -> `produce_partial_beacon_block` -> `get_execution_payload`, but gloas will no longer support this state field // This will be resolved in a subsequent block processing PR let mut spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); - spec.terminal_total_difficulty = Uint256::from(1); + spec.reorg_head_weight_threshold = Some(20); // Ensure there are enough validators to have `attesters_per_slot`. let attesters_per_slot = 10; @@ -435,7 +432,6 @@ pub async fn proposer_boost_re_org_test( None, Some(Box::new(move |builder| { builder - .proposer_re_org_head_threshold(Some(ReOrgThreshold(re_org_head_threshold))) .proposer_re_org_parent_threshold(Some(ReOrgThreshold(re_org_parent_threshold))) .proposer_re_org_max_epochs_since_finalization(Epoch::new( max_epochs_since_finalization, diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index e4e35dbd6d4..dc1545fcb92 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -741,11 +741,8 @@ pub fn get_config( } if cli_args.get_flag("disable-proposer-reorgs") { - client_config.chain.re_org_head_threshold = None; client_config.chain.re_org_parent_threshold = None; } else { - client_config.chain.re_org_head_threshold = - spec.reorg_head_weight_threshold.map(ReOrgThreshold); client_config.chain.re_org_max_epochs_since_finalization = spec .reorg_max_epochs_since_finalization .map(Epoch::new) diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index eba18c6f9fd..0fe65d977ad 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2355,10 +2355,7 @@ fn disable_proposer_re_orgs() { CommandLineTest::new() .flag("disable-proposer-reorgs", None) .run_with_zero_port() - .with_config(|config| { - assert_eq!(config.chain.re_org_head_threshold, None); - assert_eq!(config.chain.re_org_parent_threshold, None) - }); + .with_config(|config| assert_eq!(config.chain.re_org_parent_threshold, None)); } #[test] From 71d0612ea606bd2c26dff8088e19b12522e4bba3 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Thu, 30 Apr 2026 21:47:21 +0800 Subject: [PATCH 13/26] revise --- beacon_node/beacon_chain/src/beacon_chain.rs | 13 +++++++++--- .../beacon_chain/src/block_production/mod.rs | 14 ++++++++++--- beacon_node/beacon_chain/src/builder.rs | 21 +++---------------- beacon_node/beacon_chain/src/chain_config.rs | 8 +------ .../http_api/tests/interactive_tests.rs | 19 ++++------------- beacon_node/src/config.rs | 9 -------- lighthouse/tests/beacon_node.rs | 8 ------- 7 files changed, 29 insertions(+), 63 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 814cec4df7e..11fb2de9334 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -4946,10 +4946,17 @@ impl BeaconChain { .ok_or(Box::new(DoNotReOrg::ReOrgsDisabled.into()))?; let re_org_parent_threshold = self - .config - .re_org_parent_threshold + .spec + .reorg_parent_weight_threshold + .map(ReOrgThreshold) .ok_or(Box::new(DoNotReOrg::ReOrgsDisabled.into()))?; + let re_org_max_epochs_since_finalization = self + .spec + .reorg_max_epochs_since_finalization + .map(Epoch::new) + .unwrap_or(Epoch::new(2)); + let head_block_root = canonical_forkchoice_params.head_root; // Perform initial checks and load the relevant info from fork choice. @@ -4961,7 +4968,7 @@ impl BeaconChain { re_org_head_threshold, re_org_parent_threshold, &self.config.re_org_disallowed_offsets, - self.config.re_org_max_epochs_since_finalization, + re_org_max_epochs_since_finalization, ) .map_err(|e| e.map_inner_error(Error::ProposerHeadForkChoiceError))?; diff --git a/beacon_node/beacon_chain/src/block_production/mod.rs b/beacon_node/beacon_chain/src/block_production/mod.rs index 7c5eaf9fe57..7b1e75484f8 100644 --- a/beacon_node/beacon_chain/src/block_production/mod.rs +++ b/beacon_node/beacon_chain/src/block_production/mod.rs @@ -4,7 +4,7 @@ use fork_choice::PayloadStatus; use proto_array::{ProposerHeadError, ReOrgThreshold}; use slot_clock::SlotClock; use tracing::{debug, error, info, instrument, warn}; -use types::{BeaconState, Hash256, SignedExecutionPayloadEnvelope, Slot}; +use types::{BeaconState, Epoch, Hash256, SignedExecutionPayloadEnvelope, Slot}; use crate::{ BeaconChain, BeaconChainTypes, BlockProductionError, StateSkipConfig, @@ -175,7 +175,15 @@ impl BeaconChain { canonical_head: Hash256, ) -> Option<(BeaconState, Hash256)> { let re_org_head_threshold = self.spec.reorg_head_weight_threshold.map(ReOrgThreshold)?; - let re_org_parent_threshold = self.config.re_org_parent_threshold?; + let re_org_parent_threshold = self + .spec + .reorg_parent_weight_threshold + .map(ReOrgThreshold)?; + let re_org_max_epochs_since_finalization = self + .spec + .reorg_max_epochs_since_finalization + .map(Epoch::new) + .unwrap_or(Epoch::new(2)); if self.spec.proposer_score_boost.is_none() { warn!( @@ -223,7 +231,7 @@ impl BeaconChain { re_org_head_threshold, re_org_parent_threshold, &self.config.re_org_disallowed_offsets, - self.config.re_org_max_epochs_since_finalization, + re_org_max_epochs_since_finalization, ) .map_err(|e| match e { ProposerHeadError::DoNotReOrg(reason) => { diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index 57222bc343d..7b8b1e7399f 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -29,7 +29,7 @@ use kzg::Kzg; use logging::crit; use operation_pool::{OperationPool, PersistedOperationPool}; use parking_lot::{Mutex, RwLock}; -use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold}; +use proto_array::DisallowedReOrgOffsets; use rand::RngCore; use rayon::prelude::*; use slasher::Slasher; @@ -46,8 +46,8 @@ use tracing::{debug, error, info, warn}; use tree_hash::TreeHash; use types::data::CustodyIndex; use types::{ - BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList, Epoch, EthSpec, - Hash256, SignedBeaconBlock, Slot, + BeaconState, BlobSidecarList, ChainSpec, ColumnIndex, DataColumnSidecarList, EthSpec, Hash256, + SignedBeaconBlock, Slot, }; /// An empty struct used to "witness" all the `BeaconChainTypes` traits. It has no user-facing @@ -175,21 +175,6 @@ where self } - /// Sets the proposer parent re-org threshold - pub fn proposer_re_org_parent_threshold(mut self, threshold: Option) -> Self { - self.chain_config.re_org_parent_threshold = threshold; - self - } - - /// Sets the proposer re-org max epochs since finalization. - pub fn proposer_re_org_max_epochs_since_finalization( - mut self, - epochs_since_finalization: Epoch, - ) -> Self { - self.chain_config.re_org_max_epochs_since_finalization = epochs_since_finalization; - self - } - /// Sets the proposer re-org disallowed offsets list. pub fn proposer_re_org_disallowed_offsets( mut self, diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 9e0fdd8b4c5..71a0e1a78b0 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -3,7 +3,7 @@ pub use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold}; use serde::{Deserialize, Serialize}; use std::str::FromStr; use std::{collections::HashSet, sync::LazyLock, time::Duration}; -use types::{Checkpoint, Epoch, Hash256}; +use types::{Checkpoint, Hash256}; /// Default to 1/12th of the slot, which is 1 second on mainnet. pub const DEFAULT_RE_ORG_CUTOFF_DENOMINATOR: u32 = 12; @@ -38,10 +38,6 @@ pub struct ChainConfig { pub archive: bool, /// The max size of a message that can be sent over the network. pub max_network_size: usize, - /// Minimum percentage of the parent committee weight at which to attempt re-orging the canonical head. - pub re_org_parent_threshold: Option, - /// Maximum number of epochs since finalization for attempting a proposer re-org. - pub re_org_max_epochs_since_finalization: Epoch, /// Maximum delay after the start of the slot at which to propose a reorging block. pub re_org_cutoff_millis: Option, /// Additional epoch offsets at which re-orging block proposals are not permitted. @@ -129,8 +125,6 @@ impl Default for ChainConfig { weak_subjectivity_checkpoint: None, archive: false, max_network_size: 10 * 1_048_576, // 10M - re_org_parent_threshold: Some(ReOrgThreshold(160)), - re_org_max_epochs_since_finalization: Epoch::new(2), re_org_cutoff_millis: None, re_org_disallowed_offsets: DisallowedReOrgOffsets::default(), fork_choice_before_proposal_timeout_ms: DEFAULT_FORK_CHOICE_BEFORE_PROPOSAL_TIMEOUT, diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index 46f45921de5..e8b5c0ed6f2 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -2,7 +2,7 @@ use beacon_chain::custody_context::NodeCustodyType; use beacon_chain::{ ChainConfig, - chain_config::{DisallowedReOrgOffsets, ReOrgThreshold}, + chain_config::DisallowedReOrgOffsets, test_utils::{ AttestationStrategy, BlockStrategy, LightClientStrategy, SyncCommitteeStrategy, test_spec, }, @@ -184,8 +184,6 @@ pub struct ReOrgTest { parent_distance: u64, /// Number of slots between head block and block proposal slot. head_distance: u64, - re_org_parent_threshold: u64, - max_epochs_since_finalization: u64, percent_parent_votes: usize, percent_empty_votes: usize, percent_head_votes: usize, @@ -204,8 +202,6 @@ impl Default for ReOrgTest { head_slot: Slot::new(E::slots_per_epoch() - 2), parent_distance: 1, head_distance: 1, - re_org_parent_threshold: 160, - max_epochs_since_finalization: 2, percent_parent_votes: 100, percent_empty_votes: 100, percent_head_votes: 0, @@ -390,8 +386,6 @@ pub async fn proposer_boost_re_org_test( head_slot, parent_distance, head_distance, - re_org_parent_threshold, - max_epochs_since_finalization, percent_parent_votes, percent_empty_votes, percent_head_votes, @@ -431,14 +425,9 @@ pub async fn proposer_boost_re_org_test( validator_count, None, Some(Box::new(move |builder| { - builder - .proposer_re_org_parent_threshold(Some(ReOrgThreshold(re_org_parent_threshold))) - .proposer_re_org_max_epochs_since_finalization(Epoch::new( - max_epochs_since_finalization, - )) - .proposer_re_org_disallowed_offsets( - DisallowedReOrgOffsets::new::(disallowed_offsets).unwrap(), - ) + builder.proposer_re_org_disallowed_offsets( + DisallowedReOrgOffsets::new::(disallowed_offsets).unwrap(), + ) })), Default::default(), false, diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index dc1545fcb92..c553ee8f49a 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -1,7 +1,6 @@ use account_utils::{STDIN_INPUTS_FLAG, read_input_from_user}; use beacon_chain::chain_config::{ DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR, DisallowedReOrgOffsets, INVALID_HOLESKY_BLOCK_ROOT, - ReOrgThreshold, }; use beacon_chain::custody_context::NodeCustodyType; use beacon_chain::graffiti_calculator::GraffitiOrigin; @@ -741,18 +740,10 @@ pub fn get_config( } if cli_args.get_flag("disable-proposer-reorgs") { - client_config.chain.re_org_parent_threshold = None; } else { - client_config.chain.re_org_max_epochs_since_finalization = spec - .reorg_max_epochs_since_finalization - .map(Epoch::new) - .unwrap_or(Epoch::new(2)); client_config.chain.re_org_cutoff_millis = clap_utils::parse_optional(cli_args, "proposer-reorg-cutoff")?; - client_config.chain.re_org_parent_threshold = - spec.reorg_parent_weight_threshold.map(ReOrgThreshold); - if let Some(disallowed_offsets_str) = clap_utils::parse_optional::(cli_args, "proposer-reorg-disallowed-offsets")? { diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 0fe65d977ad..9fd28f874aa 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2350,14 +2350,6 @@ fn enable_proposer_re_orgs_default() { }); } -#[test] -fn disable_proposer_re_orgs() { - CommandLineTest::new() - .flag("disable-proposer-reorgs", None) - .run_with_zero_port() - .with_config(|config| assert_eq!(config.chain.re_org_parent_threshold, None)); -} - #[test] fn proposer_re_org_cutoff() { CommandLineTest::new() From 4373c19617a2280229cac45267161cb9e2fba888 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Thu, 30 Apr 2026 23:35:06 +0800 Subject: [PATCH 14/26] remove reorg cutoff --- beacon_node/beacon_chain/src/beacon_chain.rs | 11 ++++++-- .../beacon_chain/src/block_production/mod.rs | 10 +++++-- beacon_node/beacon_chain/src/chain_config.rs | 14 ---------- .../http_api/tests/interactive_tests.rs | 3 +-- beacon_node/src/config.rs | 3 --- lighthouse/tests/beacon_node.rs | 27 +------------------ 6 files changed, 19 insertions(+), 49 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 11fb2de9334..d40602a606d 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -140,10 +140,10 @@ use task_executor::{RayonPoolType, ShutdownReason, TaskExecutor}; use tokio_stream::Stream; use tracing::{debug, debug_span, error, info, info_span, instrument, trace, warn}; use tree_hash::TreeHash; +use types::consts::bellatrix::BASIS_POINTS; use types::data::{ColumnIndex, FixedBlobSidecarList}; use types::execution::BlockProductionVersion; use types::*; - pub type ForkChoiceError = fork_choice::Error; /// Alias to appease clippy. @@ -4989,7 +4989,14 @@ impl BeaconChain { .and_then(|slot_start| { let now = self.slot_clock.now_duration()?; let slot_delay = now.saturating_sub(slot_start); - Some(slot_delay <= self.config.re_org_cutoff(self.spec.get_slot_duration())) + + let slot_duration_millis = self.spec.get_slot_duration().as_millis() as u64; + let re_org_cutoff_millis = slot_duration_millis + .saturating_mul(self.spec.proposer_reorg_cutoff_bps) + .saturating_div(BASIS_POINTS); + let re_org_cutoff_duration = Duration::from_millis(re_org_cutoff_millis); + + Some(slot_delay <= re_org_cutoff_duration) }) .unwrap_or(false) } else { diff --git a/beacon_node/beacon_chain/src/block_production/mod.rs b/beacon_node/beacon_chain/src/block_production/mod.rs index 7b1e75484f8..dc9790d340a 100644 --- a/beacon_node/beacon_chain/src/block_production/mod.rs +++ b/beacon_node/beacon_chain/src/block_production/mod.rs @@ -4,6 +4,7 @@ use fork_choice::PayloadStatus; use proto_array::{ProposerHeadError, ReOrgThreshold}; use slot_clock::SlotClock; use tracing::{debug, error, info, instrument, warn}; +use types::consts::bellatrix::BASIS_POINTS; use types::{BeaconState, Epoch, Hash256, SignedExecutionPayloadEnvelope, Slot}; use crate::{ @@ -206,8 +207,13 @@ impl BeaconChain { // 1. It seems we have time to propagate and still receive the proposer boost. // 2. The current head block was seen late. // 3. The `get_proposer_head` conditions from fork choice pass. - let proposing_on_time = - slot_delay < self.config.re_org_cutoff(self.spec.get_slot_duration()); + let slot_duration_millis = self.spec.get_slot_duration().as_millis() as u64; + let re_org_cutoff_millis = slot_duration_millis + .saturating_mul(self.spec.proposer_reorg_cutoff_bps) + .saturating_div(BASIS_POINTS); + let re_org_cutoff_duration = Duration::from_millis(re_org_cutoff_millis); + + let proposing_on_time = slot_delay < re_org_cutoff_duration; if !proposing_on_time { debug!(reason = "not proposing on time", "Not attempting re-org"); return None; diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 71a0e1a78b0..42d22d61e1d 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -5,8 +5,6 @@ use std::str::FromStr; use std::{collections::HashSet, sync::LazyLock, time::Duration}; use types::{Checkpoint, Hash256}; -/// Default to 1/12th of the slot, which is 1 second on mainnet. -pub const DEFAULT_RE_ORG_CUTOFF_DENOMINATOR: u32 = 12; pub const DEFAULT_FORK_CHOICE_BEFORE_PROPOSAL_TIMEOUT: u64 = 250; /// Default fraction of a slot lookahead for payload preparation (12/3 = 4 seconds on mainnet). @@ -38,8 +36,6 @@ pub struct ChainConfig { pub archive: bool, /// The max size of a message that can be sent over the network. pub max_network_size: usize, - /// Maximum delay after the start of the slot at which to propose a reorging block. - pub re_org_cutoff_millis: Option, /// Additional epoch offsets at which re-orging block proposals are not permitted. /// /// By default this list is empty, but it can be useful for reacting to network conditions, e.g. @@ -125,7 +121,6 @@ impl Default for ChainConfig { weak_subjectivity_checkpoint: None, archive: false, max_network_size: 10 * 1_048_576, // 10M - re_org_cutoff_millis: None, re_org_disallowed_offsets: DisallowedReOrgOffsets::default(), fork_choice_before_proposal_timeout_ms: DEFAULT_FORK_CHOICE_BEFORE_PROPOSAL_TIMEOUT, // Builder fallback configs that are set in `clap` will override these. @@ -159,12 +154,3 @@ impl Default for ChainConfig { } } } - -impl ChainConfig { - /// The latest delay from the start of the slot at which to attempt a 1-slot re-org. - pub fn re_org_cutoff(&self, slot_duration: Duration) -> Duration { - self.re_org_cutoff_millis - .map(Duration::from_millis) - .unwrap_or_else(|| slot_duration / DEFAULT_RE_ORG_CUTOFF_DENOMINATOR) - } -} diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index e8b5c0ed6f2..9089fc18388 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -401,8 +401,7 @@ pub async fn proposer_boost_re_org_test( // TODO(EIP-7732): extend test for Gloas by reverting back to using `ForkName::latest()` // Issue is that `get_validator_blocks_v3` below expects to be able to use `state.latest_execution_payload_header` during `produce_block_on_state` -> `produce_partial_beacon_block` -> `get_execution_payload`, but gloas will no longer support this state field // This will be resolved in a subsequent block processing PR - let mut spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); - spec.reorg_head_weight_threshold = Some(20); + let spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); // Ensure there are enough validators to have `attesters_per_slot`. let attesters_per_slot = 10; diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index c553ee8f49a..6bee2348bce 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -741,9 +741,6 @@ pub fn get_config( if cli_args.get_flag("disable-proposer-reorgs") { } else { - client_config.chain.re_org_cutoff_millis = - clap_utils::parse_optional(cli_args, "proposer-reorg-cutoff")?; - if let Some(disallowed_offsets_str) = clap_utils::parse_optional::(cli_args, "proposer-reorg-disallowed-offsets")? { diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 9fd28f874aa..032f14073bd 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -1,6 +1,6 @@ use crate::exec::{CommandLineTestExec, CompletedTest}; use beacon_node::beacon_chain::chain_config::{ - DEFAULT_RE_ORG_CUTOFF_DENOMINATOR, DEFAULT_SYNC_TOLERANCE_EPOCHS, DisallowedReOrgOffsets, + DEFAULT_SYNC_TOLERANCE_EPOCHS, DisallowedReOrgOffsets, }; use beacon_node::beacon_chain::custody_context::NodeCustodyType; use beacon_node::{ @@ -2338,31 +2338,6 @@ fn ensure_panic_on_failed_launch() { }); } -#[test] -fn enable_proposer_re_orgs_default() { - CommandLineTest::new() - .run_with_zero_port() - .with_config(|config| { - assert_eq!( - config.chain.re_org_cutoff(Duration::from_secs(12)), - Duration::from_secs(12) / DEFAULT_RE_ORG_CUTOFF_DENOMINATOR - ); - }); -} - -#[test] -fn proposer_re_org_cutoff() { - CommandLineTest::new() - .flag("proposer-reorg-cutoff", Some("500")) - .run_with_zero_port() - .with_config(|config| { - assert_eq!( - config.chain.re_org_cutoff(Duration::from_secs(12)), - Duration::from_millis(500) - ) - }); -} - #[test] fn proposer_re_org_disallowed_offsets_default() { CommandLineTest::new() From 11cd4133afa7a641f09f5790c58e309d5bf39738 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Thu, 30 Apr 2026 23:44:38 +0800 Subject: [PATCH 15/26] remove mut --- beacon_node/http_api/tests/interactive_tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index fc544c311a7..31ada721516 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -396,7 +396,7 @@ pub async fn proposer_boost_re_org_test( // TODO(EIP-7732): extend test for Gloas — `get_validator_blocks_v3` is missing the // `Eth-Execution-Payload-Blinded` header for Gloas block production responses. - let mut spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); + let spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); // Ensure there are enough validators to have `attesters_per_slot`. let attesters_per_slot = 10; From 8521fb797dfb717967a51d762a813ebf8486d950 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 4 May 2026 08:16:04 +0800 Subject: [PATCH 16/26] cli --- beacon_node/src/cli.rs | 32 ++++++++++++++++++++++++++++---- beacon_node/src/config.rs | 5 ++++- book/src/advanced_re-orgs.md | 5 ----- book/src/help_bn.md | 11 +++++++---- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index eb4c05d8b01..37c2232aaab 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -1315,15 +1315,39 @@ pub fn cli_app() -> Command { .help_heading(FLAG_HEADER) .display_order(0) ) + .arg( + Arg::new("proposer-reorg-threshold") + .long("proposer-reorg-threshold") + .action(ArgAction::Set) + .value_name("PERCENT") + .help("DEPRECATED. This flag has no effect.") + .conflicts_with("disable-proposer-reorgs") + .display_order(0) + ) + .arg( + Arg::new("proposer-reorg-parent-threshold") + .long("proposer-reorg-parent-threshold") + .value_name("PERCENT") + .help("DEPRECATED. This flag has no effect.") + .conflicts_with("disable-proposer-reorgs") + .action(ArgAction::Set) + .display_order(0) + ) + .arg( + Arg::new("proposer-reorg-epochs-since-finalization") + .long("proposer-reorg-epochs-since-finalization") + .action(ArgAction::Set) + .value_name("EPOCHS") + .help("DEPRECATED. This flag has no effect.") + .conflicts_with("disable-proposer-reorgs") + .display_order(0) + ) .arg( Arg::new("proposer-reorg-cutoff") .long("proposer-reorg-cutoff") .value_name("MILLISECONDS") .action(ArgAction::Set) - .help("Maximum delay after the start of the slot at which to propose a reorging \ - block. Lower values can prevent failed reorgs by ensuring the block has \ - ample time to propagate and be processed by the network. The default is \ - 1/12th of a slot (1 second on mainnet)") + .help("DEPRECATED. This flag has no effect.") .conflicts_with("disable-proposer-reorgs") .display_order(0) ) diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 6bee2348bce..22c35fefe86 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -25,6 +25,7 @@ use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs}; use std::num::NonZeroU16; use std::path::{Path, PathBuf}; use std::str::FromStr; +use std::sync::Arc; use std::time::Duration; use tracing::{info, warn}; use types::graffiti::GraffitiString; @@ -43,7 +44,7 @@ pub fn get_config( cli_args: &ArgMatches, context: &RuntimeContext, ) -> Result { - let spec = &context.eth2_config.spec; + let mut spec = context.eth2_config.spec.clone(); let mut client_config = ClientConfig::default(); @@ -740,6 +741,8 @@ pub fn get_config( } if cli_args.get_flag("disable-proposer-reorgs") { + Arc::make_mut(&mut spec).reorg_head_weight_threshold = None; + Arc::make_mut(&mut spec).reorg_parent_weight_threshold = None; } else { if let Some(disallowed_offsets_str) = clap_utils::parse_optional::(cli_args, "proposer-reorg-disallowed-offsets")? diff --git a/book/src/advanced_re-orgs.md b/book/src/advanced_re-orgs.md index 88ff1c9d093..a86028ae9e0 100644 --- a/book/src/advanced_re-orgs.md +++ b/book/src/advanced_re-orgs.md @@ -15,11 +15,6 @@ There are three flags which control the re-orging behaviour: * `--disable-proposer-reorgs`: turn re-orging off (it's on by default). meaning re-orgs will only be attempted when the chain is finalizing optimally. -* `--proposer-reorg-cutoff T`: only attempt to re-org late blocks when the proposal is being made - before T milliseconds into the slot. Delays between the validator client and the beacon node can - cause some blocks to be requested later than the start of the slot, which makes them more likely - to fail. The default cutoff is 1000ms on mainnet, which gives blocks 3000ms to be signed and - propagated before the attestation deadline at 4000ms. * `--proposer-reorg-disallowed-offsets N1,N2,N3...`: Prohibit Lighthouse from attempting to reorg at specific offsets in each epoch. A disallowed offset `N` prevents reorging blocks from being proposed at any `slot` such that `slot % SLOTS_PER_EPOCH == N`. The value to this flag is a diff --git a/book/src/help_bn.md b/book/src/help_bn.md index 356c261321d..a69d26dc0d0 100644 --- a/book/src/help_bn.md +++ b/book/src/help_bn.md @@ -306,10 +306,7 @@ Options: values are useful for ensuring the EL is given ample notice. Default: 1/3 of a slot. --proposer-reorg-cutoff - Maximum delay after the start of the slot at which to propose a - reorging block. Lower values can prevent failed reorgs by ensuring the - block has ample time to propagate and be processed by the network. The - default is 1/12th of a slot (1 second on mainnet) + DEPRECATED. This flag has no effect. --proposer-reorg-disallowed-offsets Comma-separated list of integer offsets which can be used to avoid proposing reorging blocks at certain slots. An offset of N means that @@ -317,6 +314,12 @@ Options: SLOTS_PER_EPOCH == N`. By default only re-orgs at offset 0 will be avoided. Any offsets supplied with this flag will impose additional restrictions. + --proposer-reorg-epochs-since-finalization + DEPRECATED. This flag has no effect. + --proposer-reorg-parent-threshold + DEPRECATED. This flag has no effect. + --proposer-reorg-threshold + DEPRECATED. This flag has no effect. --prune-blobs Prune blobs from Lighthouse's database when they are older than the data data availability boundary relative to the current epoch. From ff00dd06eea33a08d8059063f911bb2c3f76f7fe Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Mon, 4 May 2026 09:04:06 +0800 Subject: [PATCH 17/26] cli fmt and book --- beacon_node/src/cli.rs | 2 +- book/src/advanced_re-orgs.md | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 37c2232aaab..39b8efa31be 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -1317,7 +1317,7 @@ pub fn cli_app() -> Command { ) .arg( Arg::new("proposer-reorg-threshold") - .long("proposer-reorg-threshold") + .long("proposer-reorg-threshold") .action(ArgAction::Set) .value_name("PERCENT") .help("DEPRECATED. This flag has no effect.") diff --git a/book/src/advanced_re-orgs.md b/book/src/advanced_re-orgs.md index a86028ae9e0..71751f354fb 100644 --- a/book/src/advanced_re-orgs.md +++ b/book/src/advanced_re-orgs.md @@ -14,7 +14,6 @@ attestations and transactions that can be included. There are three flags which control the re-orging behaviour: * `--disable-proposer-reorgs`: turn re-orging off (it's on by default). - meaning re-orgs will only be attempted when the chain is finalizing optimally. * `--proposer-reorg-disallowed-offsets N1,N2,N3...`: Prohibit Lighthouse from attempting to reorg at specific offsets in each epoch. A disallowed offset `N` prevents reorging blocks from being proposed at any `slot` such that `slot % SLOTS_PER_EPOCH == N`. The value to this flag is a From 652fef75a566f16fa5fc3823ba7edc62c444a2fa Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Wed, 6 May 2026 17:55:17 +0800 Subject: [PATCH 18/26] revise --- beacon_node/beacon_chain/src/beacon_chain.rs | 24 +++------ .../beacon_chain/src/block_production/mod.rs | 14 ++---- beacon_node/beacon_chain/src/chain_config.rs | 3 ++ beacon_node/src/config.rs | 36 ++++++-------- consensus/proto_array/src/proto_array.rs | 8 ++- consensus/types/src/core/chain_spec.rs | 49 ++++++++----------- testing/ef_tests/src/cases/fork_choice.rs | 15 ++---- 7 files changed, 58 insertions(+), 91 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 8cf15bb6fcd..2ddb1a9c2a5 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5113,23 +5113,14 @@ impl BeaconChain { let _timer = metrics::start_timer(&metrics::FORK_CHOICE_OVERRIDE_FCU_TIMES); // Never override if proposer re-orgs are disabled. - let re_org_head_threshold = self - .spec - .reorg_head_weight_threshold - .map(ReOrgThreshold) - .ok_or(Box::new(DoNotReOrg::ReOrgsDisabled.into()))?; - - let re_org_parent_threshold = self - .spec - .reorg_parent_weight_threshold - .map(ReOrgThreshold) - .ok_or(Box::new(DoNotReOrg::ReOrgsDisabled.into()))?; + if self.config.disable_proposer_reorg { + return Err(Box::new(DoNotReOrg::ReOrgsDisabled.into())); + }; - let re_org_max_epochs_since_finalization = self - .spec - .reorg_max_epochs_since_finalization - .map(Epoch::new) - .unwrap_or(Epoch::new(2)); + let re_org_head_threshold = ReOrgThreshold(self.spec.reorg_head_weight_threshold); + let re_org_parent_threshold = ReOrgThreshold(self.spec.reorg_parent_weight_threshold); + let re_org_max_epochs_since_finalization = + Epoch::new(self.spec.reorg_max_epochs_since_finalization); let head_block_root = canonical_forkchoice_params.head_root; @@ -5155,6 +5146,7 @@ impl BeaconChain { // If a re-orging proposal isn't made by the `re_org_cutoff` then we give up // and allow the fork choice update for the canonical head through so that we may attest // correctly. + let current_slot_ok = if head_slot == fork_choice_slot { true } else if re_org_block_slot == fork_choice_slot { diff --git a/beacon_node/beacon_chain/src/block_production/mod.rs b/beacon_node/beacon_chain/src/block_production/mod.rs index dc9790d340a..ded14dfc03c 100644 --- a/beacon_node/beacon_chain/src/block_production/mod.rs +++ b/beacon_node/beacon_chain/src/block_production/mod.rs @@ -175,16 +175,10 @@ impl BeaconChain { head_slot: Slot, canonical_head: Hash256, ) -> Option<(BeaconState, Hash256)> { - let re_org_head_threshold = self.spec.reorg_head_weight_threshold.map(ReOrgThreshold)?; - let re_org_parent_threshold = self - .spec - .reorg_parent_weight_threshold - .map(ReOrgThreshold)?; - let re_org_max_epochs_since_finalization = self - .spec - .reorg_max_epochs_since_finalization - .map(Epoch::new) - .unwrap_or(Epoch::new(2)); + let re_org_head_threshold = ReOrgThreshold(self.spec.reorg_head_weight_threshold); + let re_org_parent_threshold = ReOrgThreshold(self.spec.reorg_parent_weight_threshold); + let re_org_max_epochs_since_finalization = + Epoch::new(self.spec.reorg_max_epochs_since_finalization); if self.spec.proposer_score_boost.is_none() { warn!( diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 42d22d61e1d..630ecf4a852 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -112,6 +112,8 @@ pub struct ChainConfig { pub enable_partial_columns: bool, /// The node's custody type, determining how many data columns to custody and sample. pub node_custody_type: NodeCustodyType, + /// Disable proposer re-org + pub disable_proposer_reorg: bool, } impl Default for ChainConfig { @@ -151,6 +153,7 @@ impl Default for ChainConfig { disable_get_blobs: false, enable_partial_columns: false, node_custody_type: NodeCustodyType::Fullnode, + disable_proposer_reorg: false, } } } diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 22c35fefe86..16d208d5941 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -25,7 +25,6 @@ use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs}; use std::num::NonZeroU16; use std::path::{Path, PathBuf}; use std::str::FromStr; -use std::sync::Arc; use std::time::Duration; use tracing::{info, warn}; use types::graffiti::GraffitiString; @@ -44,7 +43,7 @@ pub fn get_config( cli_args: &ArgMatches, context: &RuntimeContext, ) -> Result { - let mut spec = context.eth2_config.spec.clone(); + let spec = context.eth2_config.spec.clone(); let mut client_config = ClientConfig::default(); @@ -740,24 +739,21 @@ pub fn get_config( .individual_tracking_threshold = count; } - if cli_args.get_flag("disable-proposer-reorgs") { - Arc::make_mut(&mut spec).reorg_head_weight_threshold = None; - Arc::make_mut(&mut spec).reorg_parent_weight_threshold = None; - } else { - if let Some(disallowed_offsets_str) = - clap_utils::parse_optional::(cli_args, "proposer-reorg-disallowed-offsets")? - { - let disallowed_offsets = disallowed_offsets_str - .split(',') - .map(|s| { - s.parse() - .map_err(|e| format!("invalid disallowed-offsets: {e:?}")) - }) - .collect::, _>>()?; - client_config.chain.re_org_disallowed_offsets = - DisallowedReOrgOffsets::new::(disallowed_offsets) - .map_err(|e| format!("invalid disallowed-offsets: {e:?}"))?; - } + client_config.chain.disable_proposer_reorg = cli_args.get_flag("disable-proposer-reorgs"); + + if let Some(disallowed_offsets_str) = + clap_utils::parse_optional::(cli_args, "proposer-reorg-disallowed-offsets")? + { + let disallowed_offsets = disallowed_offsets_str + .split(',') + .map(|s| { + s.parse() + .map_err(|e| format!("invalid disallowed-offsets: {e:?}")) + }) + .collect::, _>>()?; + client_config.chain.re_org_disallowed_offsets = + DisallowedReOrgOffsets::new::(disallowed_offsets) + .map_err(|e| format!("invalid disallowed-offsets: {e:?}"))?; } client_config.chain.prepare_payload_lookahead = diff --git a/consensus/proto_array/src/proto_array.rs b/consensus/proto_array/src/proto_array.rs index 78f5026689a..d07f63d89ad 100644 --- a/consensus/proto_array/src/proto_array.rs +++ b/consensus/proto_array/src/proto_array.rs @@ -667,11 +667,9 @@ impl ProtoArray { justified_balances: &JustifiedBalances, spec: &ChainSpec, ) -> bool { - let reorg_threshold = calculate_committee_fraction::( - justified_balances, - spec.reorg_head_weight_threshold.unwrap_or(20), - ) - .unwrap_or(0); + let reorg_threshold = + calculate_committee_fraction::(justified_balances, spec.reorg_head_weight_threshold) + .unwrap_or(0); let head_weight = head_node .attestation_score(PayloadStatus::Pending) diff --git a/consensus/types/src/core/chain_spec.rs b/consensus/types/src/core/chain_spec.rs index c54d032891a..295f5f7f799 100644 --- a/consensus/types/src/core/chain_spec.rs +++ b/consensus/types/src/core/chain_spec.rs @@ -150,9 +150,9 @@ pub struct ChainSpec { * Fork choice */ pub proposer_score_boost: Option, - pub reorg_head_weight_threshold: Option, - pub reorg_parent_weight_threshold: Option, - pub reorg_max_epochs_since_finalization: Option, + pub reorg_head_weight_threshold: u64, + pub reorg_parent_weight_threshold: u64, + pub reorg_max_epochs_since_finalization: u64, /* * Eth1 @@ -1151,9 +1151,9 @@ impl ChainSpec { * Fork choice */ proposer_score_boost: Some(40), - reorg_head_weight_threshold: Some(20), - reorg_parent_weight_threshold: Some(160), - reorg_max_epochs_since_finalization: Some(2), + reorg_head_weight_threshold: 20, + reorg_parent_weight_threshold: 160, + reorg_max_epochs_since_finalization: 2, /* * Eth1 @@ -1573,9 +1573,9 @@ impl ChainSpec { * Fork choice */ proposer_score_boost: Some(40), - reorg_head_weight_threshold: Some(20), - reorg_parent_weight_threshold: Some(160), - reorg_max_epochs_since_finalization: Some(2), + reorg_head_weight_threshold: 20, + reorg_parent_weight_threshold: 160, + reorg_max_epochs_since_finalization: 2, /* * Eth1 @@ -2013,12 +2013,12 @@ pub struct Config { #[serde(skip_serializing_if = "Option::is_none")] proposer_score_boost: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - reorg_head_weight_threshold: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - reorg_parent_weight_threshold: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - reorg_max_epochs_since_finalization: Option>, + #[serde(with = "serde_utils::quoted_u64")] + reorg_head_weight_threshold: u64, + #[serde(with = "serde_utils::quoted_u64")] + reorg_parent_weight_threshold: u64, + #[serde(with = "serde_utils::quoted_u64")] + reorg_max_epochs_since_finalization: u64, #[serde(with = "serde_utils::quoted_u64")] deposit_chain_id: u64, @@ -2604,15 +2604,9 @@ impl Config { max_per_epoch_activation_churn_limit: spec.max_per_epoch_activation_churn_limit, proposer_score_boost: spec.proposer_score_boost.map(|value| MaybeQuoted { value }), - reorg_head_weight_threshold: spec - .reorg_head_weight_threshold - .map(|value| MaybeQuoted { value }), - reorg_parent_weight_threshold: spec - .reorg_parent_weight_threshold - .map(|value| MaybeQuoted { value }), - reorg_max_epochs_since_finalization: spec - .reorg_max_epochs_since_finalization - .map(|value| MaybeQuoted { value }), + reorg_head_weight_threshold: spec.reorg_head_weight_threshold, + reorg_parent_weight_threshold: spec.reorg_parent_weight_threshold, + reorg_max_epochs_since_finalization: spec.reorg_max_epochs_since_finalization, deposit_chain_id: spec.deposit_chain_id, deposit_network_id: spec.deposit_network_id, @@ -2822,10 +2816,9 @@ impl Config { max_per_epoch_activation_churn_limit, churn_limit_quotient, proposer_score_boost: proposer_score_boost.map(|q| q.value), - reorg_head_weight_threshold: reorg_head_weight_threshold.map(|q| q.value), - reorg_parent_weight_threshold: reorg_parent_weight_threshold.map(|q| q.value), - reorg_max_epochs_since_finalization: reorg_max_epochs_since_finalization - .map(|q| q.value), + reorg_head_weight_threshold, + reorg_parent_weight_threshold, + reorg_max_epochs_since_finalization, deposit_chain_id, deposit_network_id, deposit_contract_address, diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 5a9d62848dc..70405b87ffc 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -968,19 +968,10 @@ impl Tester { let proposer_head_result = fc.get_proposer_head( slot, canonical_head, - self.spec - .reorg_head_weight_threshold - .map(ReOrgThreshold) - .unwrap(), - self.spec - .reorg_parent_weight_threshold - .map(ReOrgThreshold) - .unwrap(), + ReOrgThreshold(self.spec.reorg_head_weight_threshold), + ReOrgThreshold(self.spec.reorg_parent_weight_threshold), &DisallowedReOrgOffsets::default(), - self.spec - .reorg_max_epochs_since_finalization - .map(Epoch::new) - .unwrap(), + Epoch::new(self.spec.reorg_max_epochs_since_finalization), ); let proposer_head = match proposer_head_result { Ok(head) => head.parent_node.root(), From 0ed9f25b4e394a7bdce52560d60ae0359f676d55 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Wed, 6 May 2026 18:53:29 +0800 Subject: [PATCH 19/26] fix test --- consensus/types/src/core/chain_spec.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/consensus/types/src/core/chain_spec.rs b/consensus/types/src/core/chain_spec.rs index 295f5f7f799..408abd12b94 100644 --- a/consensus/types/src/core/chain_spec.rs +++ b/consensus/types/src/core/chain_spec.rs @@ -2013,10 +2013,13 @@ pub struct Config { #[serde(skip_serializing_if = "Option::is_none")] proposer_score_boost: Option>, + #[serde(default = "default_reorg_head_weight_threshold")] #[serde(with = "serde_utils::quoted_u64")] reorg_head_weight_threshold: u64, + #[serde(default = "default_reorg_parent_weight_threshold")] #[serde(with = "serde_utils::quoted_u64")] reorg_parent_weight_threshold: u64, + #[serde(default = "default_reorg_max_epochs_since_finalization")] #[serde(with = "serde_utils::quoted_u64")] reorg_max_epochs_since_finalization: u64, @@ -2411,6 +2414,18 @@ const fn default_max_per_epoch_activation_churn_limit_gloas() -> u64 { 256_000_000_000 } +const fn default_reorg_head_weight_threshold() -> u64 { + 20 +} + +const fn default_reorg_parent_weight_threshold() -> u64 { + 160 +} + +const fn default_reorg_max_epochs_since_finalization() -> u64 { + 2 +} + fn max_blocks_by_root_request_common(max_request_blocks: u64) -> usize { let max_request_blocks = max_request_blocks as usize; RuntimeVariableList::::new( From 42cb94b125fbb599fae858c49e9b7ab14feb2306 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Wed, 6 May 2026 19:51:33 +0800 Subject: [PATCH 20/26] revise --- Cargo.lock | 1 + beacon_node/beacon_chain/src/beacon_chain.rs | 11 +++---- .../beacon_chain/src/block_production/mod.rs | 10 +++---- beacon_node/beacon_chain/src/chain_config.rs | 2 +- consensus/types/src/core/chain_spec.rs | 2 +- lighthouse/tests/beacon_node.rs | 29 +++++++++++++++++++ lighthouse/tests/exec.rs | 3 +- lighthouse/tests/main.rs | 3 +- testing/ef_tests/Cargo.toml | 1 + testing/ef_tests/src/cases/fork_choice.rs | 3 +- 10 files changed, 45 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aefd51a9501..610f48d593b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2851,6 +2851,7 @@ dependencies = [ "kzg", "logging", "milhouse", + "proto_array", "rayon", "serde", "serde_json", diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 2ddb1a9c2a5..e9f1e2beea3 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -142,7 +142,6 @@ use task_executor::{RayonPoolType, ShutdownReason, TaskExecutor}; use tokio_stream::Stream; use tracing::{debug, debug_span, error, info, info_span, instrument, trace, warn}; use tree_hash::TreeHash; -use types::consts::bellatrix::BASIS_POINTS; use types::data::{ColumnIndex, FixedBlobSidecarList}; use types::execution::BlockProductionVersion; use types::*; @@ -5155,12 +5154,10 @@ impl BeaconChain { .and_then(|slot_start| { let now = self.slot_clock.now_duration()?; let slot_delay = now.saturating_sub(slot_start); - - let slot_duration_millis = self.spec.get_slot_duration().as_millis() as u64; - let re_org_cutoff_millis = slot_duration_millis - .saturating_mul(self.spec.proposer_reorg_cutoff_bps) - .saturating_div(BASIS_POINTS); - let re_org_cutoff_duration = Duration::from_millis(re_org_cutoff_millis); + let re_org_cutoff_duration = self + .spec + .compute_slot_component_duration(self.spec.proposer_reorg_cutoff_bps) + .ok()?; Some(slot_delay <= re_org_cutoff_duration) }) diff --git a/beacon_node/beacon_chain/src/block_production/mod.rs b/beacon_node/beacon_chain/src/block_production/mod.rs index ded14dfc03c..a94bc697b94 100644 --- a/beacon_node/beacon_chain/src/block_production/mod.rs +++ b/beacon_node/beacon_chain/src/block_production/mod.rs @@ -4,7 +4,6 @@ use fork_choice::PayloadStatus; use proto_array::{ProposerHeadError, ReOrgThreshold}; use slot_clock::SlotClock; use tracing::{debug, error, info, instrument, warn}; -use types::consts::bellatrix::BASIS_POINTS; use types::{BeaconState, Epoch, Hash256, SignedExecutionPayloadEnvelope, Slot}; use crate::{ @@ -201,11 +200,10 @@ impl BeaconChain { // 1. It seems we have time to propagate and still receive the proposer boost. // 2. The current head block was seen late. // 3. The `get_proposer_head` conditions from fork choice pass. - let slot_duration_millis = self.spec.get_slot_duration().as_millis() as u64; - let re_org_cutoff_millis = slot_duration_millis - .saturating_mul(self.spec.proposer_reorg_cutoff_bps) - .saturating_div(BASIS_POINTS); - let re_org_cutoff_duration = Duration::from_millis(re_org_cutoff_millis); + let re_org_cutoff_duration = self + .spec + .compute_slot_component_duration(self.spec.proposer_reorg_cutoff_bps) + .ok()?; let proposing_on_time = slot_delay < re_org_cutoff_duration; if !proposing_on_time { diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index 630ecf4a852..dde09bf1057 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -1,5 +1,5 @@ use crate::custody_context::NodeCustodyType; -pub use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold}; +pub use proto_array::DisallowedReOrgOffsets; use serde::{Deserialize, Serialize}; use std::str::FromStr; use std::{collections::HashSet, sync::LazyLock, time::Duration}; diff --git a/consensus/types/src/core/chain_spec.rs b/consensus/types/src/core/chain_spec.rs index 408abd12b94..7f7dd0ea79a 100644 --- a/consensus/types/src/core/chain_spec.rs +++ b/consensus/types/src/core/chain_spec.rs @@ -918,7 +918,7 @@ impl ChainSpec { } /// Calculate the duration into a slot for a given slot component - fn compute_slot_component_duration( + pub fn compute_slot_component_duration( &self, component_basis_points: u64, ) -> Result { diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index 032f14073bd..d1978454fda 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2338,6 +2338,35 @@ fn ensure_panic_on_failed_launch() { }); } +#[test] +fn enable_proposer_re_orgs_default() { + CommandLineTest::new() + .run_with_zero_port() + .with_config_and_spec::(|_config, spec| { + assert_eq!(spec.reorg_head_weight_threshold, 20); + assert_eq!(spec.reorg_parent_weight_threshold, 160); + assert_eq!(spec.reorg_max_epochs_since_finalization, 2); + assert_eq!(spec.proposer_reorg_cutoff_bps, 1667); + }); +} + +#[test] +fn enable_proposer_re_orgs() { + CommandLineTest::new() + .run_with_zero_port() + // Default disable_proposer_reorg when the flag is not used = false + .with_config(|config| assert!(!config.chain.disable_proposer_reorg)); +} + +#[test] +fn disable_proposer_re_orgs() { + CommandLineTest::new() + .flag("disable-proposer-reorgs", None) + .run_with_zero_port() + // When --disable-proposer-reorg is used, the field in ChainConfig should become true + .with_config(|config| assert!(config.chain.disable_proposer_reorg)); +} + #[test] fn proposer_re_org_disallowed_offsets_default() { CommandLineTest::new() diff --git a/lighthouse/tests/exec.rs b/lighthouse/tests/exec.rs index a25558bc2f0..e949423385b 100644 --- a/lighthouse/tests/exec.rs +++ b/lighthouse/tests/exec.rs @@ -143,8 +143,7 @@ impl CompletedTest { pub fn with_config_and_dir(self, func: F) { func(&self.config, &self.dir); } - - #[allow(dead_code)] + pub fn with_config_and_spec(self, func: F) { let spec = ChainSpec::from_config::(&self.chain_config).unwrap(); func(&self.config, spec); diff --git a/lighthouse/tests/main.rs b/lighthouse/tests/main.rs index bf587f79df7..b487229e262 100644 --- a/lighthouse/tests/main.rs +++ b/lighthouse/tests/main.rs @@ -1,5 +1,4 @@ -#![cfg(not(debug_assertions))] - +#[cfg(not(debug_assertions))] mod account_manager; mod beacon_node; mod boot_node; diff --git a/testing/ef_tests/Cargo.toml b/testing/ef_tests/Cargo.toml index 9d09c3dfe68..ac51e827ad6 100644 --- a/testing/ef_tests/Cargo.toml +++ b/testing/ef_tests/Cargo.toml @@ -28,6 +28,7 @@ hex = { workspace = true } kzg = { workspace = true } logging = { workspace = true } milhouse = { workspace = true } +proto_array = { workspace = true } rayon = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 70405b87ffc..4f84525d9d0 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -4,7 +4,7 @@ use ::fork_choice::{PayloadVerificationStatus, ProposerHeadError}; use beacon_chain::beacon_proposer_cache::compute_proposer_duties_from_head; use beacon_chain::blob_verification::GossipBlobError; use beacon_chain::block_verification_types::LookupBlock; -use beacon_chain::chain_config::{DisallowedReOrgOffsets, ReOrgThreshold}; +use beacon_chain::chain_config::DisallowedReOrgOffsets; use beacon_chain::data_column_verification::GossipVerifiedDataColumn; use beacon_chain::slot_clock::SlotClock; use beacon_chain::{ @@ -19,6 +19,7 @@ use beacon_chain::{ use execution_layer::{ PayloadStatusV1, PayloadStatusV1Status, json_structures::JsonPayloadStatusV1Status, }; +use proto_array::ReOrgThreshold; use serde::Deserialize; use ssz_derive::Decode; use state_processing::VerifySignatures; From f9b761bc5f5c8fe1039329b597e5856672e40f4a Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Wed, 6 May 2026 20:00:14 +0800 Subject: [PATCH 21/26] cfg debug --- lighthouse/tests/beacon_node.rs | 22 +++++++++++----------- lighthouse/tests/exec.rs | 3 ++- lighthouse/tests/main.rs | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index d1978454fda..e597ecbd184 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2338,17 +2338,17 @@ fn ensure_panic_on_failed_launch() { }); } -#[test] -fn enable_proposer_re_orgs_default() { - CommandLineTest::new() - .run_with_zero_port() - .with_config_and_spec::(|_config, spec| { - assert_eq!(spec.reorg_head_weight_threshold, 20); - assert_eq!(spec.reorg_parent_weight_threshold, 160); - assert_eq!(spec.reorg_max_epochs_since_finalization, 2); - assert_eq!(spec.proposer_reorg_cutoff_bps, 1667); - }); -} +// #[test] +// fn enable_proposer_re_orgs_default() { +// CommandLineTest::new() +// .run_with_zero_port() +// .with_config_and_spec::(|_config, spec| { +// assert_eq!(spec.reorg_head_weight_threshold, 20); +// assert_eq!(spec.reorg_parent_weight_threshold, 160); +// assert_eq!(spec.reorg_max_epochs_since_finalization, 2); +// assert_eq!(spec.proposer_reorg_cutoff_bps, 1667); +// }); +// } #[test] fn enable_proposer_re_orgs() { diff --git a/lighthouse/tests/exec.rs b/lighthouse/tests/exec.rs index e949423385b..a25558bc2f0 100644 --- a/lighthouse/tests/exec.rs +++ b/lighthouse/tests/exec.rs @@ -143,7 +143,8 @@ impl CompletedTest { pub fn with_config_and_dir(self, func: F) { func(&self.config, &self.dir); } - + + #[allow(dead_code)] pub fn with_config_and_spec(self, func: F) { let spec = ChainSpec::from_config::(&self.chain_config).unwrap(); func(&self.config, spec); diff --git a/lighthouse/tests/main.rs b/lighthouse/tests/main.rs index b487229e262..8bb8fc2b4f4 100644 --- a/lighthouse/tests/main.rs +++ b/lighthouse/tests/main.rs @@ -1,4 +1,4 @@ -#[cfg(not(debug_assertions))] +#![cfg(not(debug_assertions))] mod account_manager; mod beacon_node; mod boot_node; From 34793f2746a3e176080399a41389f0028d6f80e7 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Wed, 6 May 2026 20:00:58 +0800 Subject: [PATCH 22/26] test --- lighthouse/tests/beacon_node.rs | 22 +++++++++++----------- lighthouse/tests/exec.rs | 3 +-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index e597ecbd184..d1978454fda 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2338,17 +2338,17 @@ fn ensure_panic_on_failed_launch() { }); } -// #[test] -// fn enable_proposer_re_orgs_default() { -// CommandLineTest::new() -// .run_with_zero_port() -// .with_config_and_spec::(|_config, spec| { -// assert_eq!(spec.reorg_head_weight_threshold, 20); -// assert_eq!(spec.reorg_parent_weight_threshold, 160); -// assert_eq!(spec.reorg_max_epochs_since_finalization, 2); -// assert_eq!(spec.proposer_reorg_cutoff_bps, 1667); -// }); -// } +#[test] +fn enable_proposer_re_orgs_default() { + CommandLineTest::new() + .run_with_zero_port() + .with_config_and_spec::(|_config, spec| { + assert_eq!(spec.reorg_head_weight_threshold, 20); + assert_eq!(spec.reorg_parent_weight_threshold, 160); + assert_eq!(spec.reorg_max_epochs_since_finalization, 2); + assert_eq!(spec.proposer_reorg_cutoff_bps, 1667); + }); +} #[test] fn enable_proposer_re_orgs() { diff --git a/lighthouse/tests/exec.rs b/lighthouse/tests/exec.rs index a25558bc2f0..e949423385b 100644 --- a/lighthouse/tests/exec.rs +++ b/lighthouse/tests/exec.rs @@ -143,8 +143,7 @@ impl CompletedTest { pub fn with_config_and_dir(self, func: F) { func(&self.config, &self.dir); } - - #[allow(dead_code)] + pub fn with_config_and_spec(self, func: F) { let spec = ChainSpec::from_config::(&self.chain_config).unwrap(); func(&self.config, spec); From 401b12ed1120675dbfafcd09b0f3b2202fa57da1 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Wed, 6 May 2026 20:02:06 +0800 Subject: [PATCH 23/26] fmt --- lighthouse/tests/exec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lighthouse/tests/exec.rs b/lighthouse/tests/exec.rs index e949423385b..696cf2f40a4 100644 --- a/lighthouse/tests/exec.rs +++ b/lighthouse/tests/exec.rs @@ -143,7 +143,7 @@ impl CompletedTest { pub fn with_config_and_dir(self, func: F) { func(&self.config, &self.dir); } - + pub fn with_config_and_spec(self, func: F) { let spec = ChainSpec::from_config::(&self.chain_config).unwrap(); func(&self.config, spec); From 2f4029777dd6c7556d0a03ddcd00f0563b3e4f73 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Wed, 6 May 2026 20:41:42 +0800 Subject: [PATCH 24/26] add some asserts --- beacon_node/http_api/tests/interactive_tests.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index 31ada721516..74f95e92c49 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -398,6 +398,11 @@ pub async fn proposer_boost_re_org_test( // `Eth-Execution-Payload-Blinded` header for Gloas block production responses. let spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); + assert_eq!(spec.reorg_head_weight_threshold, 20); + assert_eq!(spec.reorg_parent_weight_threshold, 160); + assert_eq!(spec.reorg_max_epochs_since_finalization, 2); + assert_eq!(spec.proposer_reorg_cutoff_bps, 1667); + // Ensure there are enough validators to have `attesters_per_slot`. let attesters_per_slot = 10; let validator_count = E::slots_per_epoch() as usize * attesters_per_slot; From a739c4ae34c4ecfd87ad7ce05604573b1b5acc3e Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Thu, 7 May 2026 08:46:43 +0800 Subject: [PATCH 25/26] simplify --- beacon_node/beacon_chain/src/beacon_chain.rs | 1 - beacon_node/http_api/tests/interactive_tests.rs | 5 ----- beacon_node/src/config.rs | 2 +- lighthouse/tests/main.rs | 1 + 4 files changed, 2 insertions(+), 7 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index e9f1e2beea3..1f3c0910e25 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5145,7 +5145,6 @@ impl BeaconChain { // If a re-orging proposal isn't made by the `re_org_cutoff` then we give up // and allow the fork choice update for the canonical head through so that we may attest // correctly. - let current_slot_ok = if head_slot == fork_choice_slot { true } else if re_org_block_slot == fork_choice_slot { diff --git a/beacon_node/http_api/tests/interactive_tests.rs b/beacon_node/http_api/tests/interactive_tests.rs index 74f95e92c49..31ada721516 100644 --- a/beacon_node/http_api/tests/interactive_tests.rs +++ b/beacon_node/http_api/tests/interactive_tests.rs @@ -398,11 +398,6 @@ pub async fn proposer_boost_re_org_test( // `Eth-Execution-Payload-Blinded` header for Gloas block production responses. let spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); - assert_eq!(spec.reorg_head_weight_threshold, 20); - assert_eq!(spec.reorg_parent_weight_threshold, 160); - assert_eq!(spec.reorg_max_epochs_since_finalization, 2); - assert_eq!(spec.proposer_reorg_cutoff_bps, 1667); - // Ensure there are enough validators to have `attesters_per_slot`. let attesters_per_slot = 10; let validator_count = E::slots_per_epoch() as usize * attesters_per_slot; diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 16d208d5941..e00afffb38d 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -43,7 +43,7 @@ pub fn get_config( cli_args: &ArgMatches, context: &RuntimeContext, ) -> Result { - let spec = context.eth2_config.spec.clone(); + let spec = &context.eth2_config.spec; let mut client_config = ClientConfig::default(); diff --git a/lighthouse/tests/main.rs b/lighthouse/tests/main.rs index 8bb8fc2b4f4..bf587f79df7 100644 --- a/lighthouse/tests/main.rs +++ b/lighthouse/tests/main.rs @@ -1,4 +1,5 @@ #![cfg(not(debug_assertions))] + mod account_manager; mod beacon_node; mod boot_node; From 85f3f0a384ffbda510ab2a658683a5f9c00f6b23 Mon Sep 17 00:00:00 2001 From: Tan Chee Keong Date: Thu, 7 May 2026 09:23:25 +0800 Subject: [PATCH 26/26] reduce diff --- beacon_node/beacon_chain/src/beacon_chain.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 1f3c0910e25..0bf01281204 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -145,6 +145,7 @@ use tree_hash::TreeHash; use types::data::{ColumnIndex, FixedBlobSidecarList}; use types::execution::BlockProductionVersion; use types::*; + pub type ForkChoiceError = fork_choice::Error; /// Alias to appease clippy.