From fe0cf9cb6729236c6c3d5814e136905e989c889f Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Mon, 24 Feb 2025 19:30:11 +1100 Subject: [PATCH 1/7] Add test flag to override `SYNC_TOLERANCE_EPOCHS` for range sync testing (#7030) Related to #6880, an issue that's usually observed on local devnets with small number of nodes. When testing range sync, I usually shutdown a node for some period of time and restart it again. However, if it's within `SYNC_TOLERANCE_EPOCHS` (8), Lighthouse would consider the node as synced, and if it may attempt to produce a block if requested by a validator - on a local devnet, nodes frequently produce blocks - when this happens, the node ends up producing a block that would revert finality and would get disconnected from peers immediately. NOTE: This is PR#7030 cherry-picked from `unstable` to `release-v7.0.0`. Run Lighthouse BN with this flag to override: ``` --sync-tolerance--epoch 0 ``` --- beacon_node/http_api/src/lib.rs | 9 +++++++-- beacon_node/src/cli.rs | 13 +++++++++++++ beacon_node/src/config.rs | 5 ++++- lighthouse/tests/beacon_node.rs | 11 +++++++++++ scripts/local_testnet/network_params_das.yaml | 4 ++++ 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 5d75dc8c9a..adeaf9eb03 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -112,7 +112,7 @@ const API_PREFIX: &str = "eth"; /// /// This helps prevent attacks where nodes can convince us that we're syncing some non-existent /// finalized head. -const SYNC_TOLERANCE_EPOCHS: u64 = 8; +const DEFAULT_SYNC_TOLERANCE_EPOCHS: u64 = 8; /// A custom type which allows for both unsecured and TLS-enabled HTTP servers. type HttpServer = (SocketAddr, Pin + Send>>); @@ -157,6 +157,7 @@ pub struct Config { pub duplicate_block_status_code: StatusCode, pub enable_light_client_server: bool, pub target_peers: usize, + pub sync_tolerance_epochs: Option, } impl Default for Config { @@ -173,6 +174,7 @@ impl Default for Config { duplicate_block_status_code: StatusCode::ACCEPTED, enable_light_client_server: true, target_peers: 100, + sync_tolerance_epochs: None, } } } @@ -473,7 +475,10 @@ pub fn serve( ) })?; - let tolerance = SYNC_TOLERANCE_EPOCHS * T::EthSpec::slots_per_epoch(); + let sync_tolerance_epochs = config + .sync_tolerance_epochs + .unwrap_or(DEFAULT_SYNC_TOLERANCE_EPOCHS); + let tolerance = sync_tolerance_epochs * T::EthSpec::slots_per_epoch(); if head_slot + tolerance >= current_slot { Ok(()) diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index 2c8b271bd2..a8f626f064 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -1518,6 +1518,19 @@ pub fn cli_app() -> Command { .help_heading(FLAG_HEADER) .display_order(0) ) + .arg( + Arg::new("sync-tolerance-epochs") + .long("sync-tolerance-epochs") + .help("Overrides the default SYNC_TOLERANCE_EPOCHS. This flag is not intended \ + for production and MUST only be used in TESTING only. This is primarily used \ + for testing range sync, to prevent the node from producing a block before the \ + node is synced with the network which may result in the node getting \ + disconnected from peers immediately.") + .hide(true) + .requires("enable_http") + .action(ArgAction::Set) + .display_order(0) + ) .arg( Arg::new("gui") .long("gui") diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index 84320762d6..d2fdd5104b 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -8,7 +8,7 @@ use beacon_chain::graffiti_calculator::GraffitiOrigin; use beacon_chain::TrustedSetup; use clap::{parser::ValueSource, ArgMatches, Id}; use clap_utils::flags::DISABLE_MALLOC_TUNING_FLAG; -use clap_utils::{parse_flag, parse_required}; +use clap_utils::{parse_flag, parse_optional, parse_required}; use client::{ClientConfig, ClientGenesis}; use directory::{DEFAULT_BEACON_NODE_DIR, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR}; use environment::RuntimeContext; @@ -177,6 +177,9 @@ pub fn get_config( client_config.http_api.enable_light_client_server = !cli_args.get_flag("disable-light-client-server"); + + client_config.http_api.sync_tolerance_epochs = + parse_optional(cli_args, "sync-tolerance-epochs")?; } if cli_args.get_flag("light-client-server") { diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index da10c2c4bd..eaf137d57f 100644 --- a/lighthouse/tests/beacon_node.rs +++ b/lighthouse/tests/beacon_node.rs @@ -2579,6 +2579,17 @@ fn light_client_http_server_disabled() { }); } +#[test] +fn sync_tolerance_epochs() { + CommandLineTest::new() + .flag("http", None) + .flag("sync-tolerance-epochs", Some("0")) + .run_with_zero_port() + .with_config(|config| { + assert_eq!(config.http_api.sync_tolerance_epochs, Some(0)); + }); +} + #[test] fn gui_flag() { CommandLineTest::new() diff --git a/scripts/local_testnet/network_params_das.yaml b/scripts/local_testnet/network_params_das.yaml index 030aa2b820..80b4bc95c6 100644 --- a/scripts/local_testnet/network_params_das.yaml +++ b/scripts/local_testnet/network_params_das.yaml @@ -4,11 +4,15 @@ participants: cl_extra_params: - --subscribe-all-data-column-subnets - --subscribe-all-subnets + # Note: useful for testing range sync (only produce block if node is in sync to prevent forking) + - --sync-tolerance-epochs=0 - --target-peers=3 count: 2 - cl_type: lighthouse cl_image: lighthouse:local cl_extra_params: + # Note: useful for testing range sync (only produce block if node is in sync to prevent forking) + - --sync-tolerance-epochs=0 - --target-peers=3 count: 2 network_params: From 80cd8bd911d55d34df27d53ed5aeb66513608216 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Thu, 27 Feb 2025 00:07:16 +1100 Subject: [PATCH 2/7] Add `--disable-attesting` flag to validator client (#7046) Cleaned up and isolated version of the `--disable-attesting` flag for the VC, from the `holesky-rescue` branch: - https://github.com/sigp/lighthouse/pull/7041 I figured we don't need the `--disable-attesting` flag on the BN for now, and it was a much more invasive impl. --- book/src/help_vc.md | 4 ++++ validator_client/src/cli.rs | 9 +++++++++ validator_client/src/config.rs | 4 ++++ validator_client/src/lib.rs | 2 ++ .../validator_services/src/attestation_service.rs | 13 +++++++++++++ .../validator_services/src/duties_service.rs | 6 ++++++ .../src/sync_committee_service.rs | 5 +++++ 7 files changed, 43 insertions(+) diff --git a/book/src/help_vc.md b/book/src/help_vc.md index 948a09f44d..4e26977efd 100644 --- a/book/src/help_vc.md +++ b/book/src/help_vc.md @@ -175,6 +175,10 @@ Flags: If this flag is set, Lighthouse will query the Beacon Node for only block headers during proposals and will sign over headers. Useful for outsourcing execution payload construction during proposals. + --disable-attesting + Disable the performance of attestation duties (and sync committee + duties). This flag should only be used in emergencies to prioritise + block proposal duties. --disable-auto-discover If present, do not attempt to discover new validators in the validators-dir. Validators will need to be manually added to the diff --git a/validator_client/src/cli.rs b/validator_client/src/cli.rs index dfcd2064e5..68541035b6 100644 --- a/validator_client/src/cli.rs +++ b/validator_client/src/cli.rs @@ -97,6 +97,15 @@ pub struct ValidatorClient { )] pub disable_auto_discover: bool, + #[clap( + long, + help = "Disable the performance of attestation duties (and sync committee duties). This \ + flag should only be used in emergencies to prioritise block proposal duties.", + display_order = 0, + help_heading = FLAG_HEADER + )] + pub disable_attesting: bool, + #[clap( long, help = "If present, the validator client will use longer timeouts for requests \ diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index 2a848e2022..24213e83e6 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -85,6 +85,7 @@ pub struct Config { /// Configuration for the initialized validators #[serde(flatten)] pub initialized_validators: InitializedValidatorsConfig, + pub disable_attesting: bool, } impl Default for Config { @@ -126,6 +127,7 @@ impl Default for Config { validator_registration_batch_size: 500, distributed: false, initialized_validators: <_>::default(), + disable_attesting: false, } } } @@ -379,6 +381,8 @@ impl Config { true }; + config.disable_attesting = validator_client_config.disable_attesting; + Ok(config) } } diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index 70236d6a3c..10121be2ae 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -478,6 +478,7 @@ impl ProductionValidatorClient { context: duties_context, enable_high_validator_count_metrics: config.enable_high_validator_count_metrics, distributed: config.distributed, + disable_attesting: config.disable_attesting, }); // Update the metrics server. @@ -507,6 +508,7 @@ impl ProductionValidatorClient { .validator_store(validator_store.clone()) .beacon_nodes(beacon_nodes.clone()) .runtime_context(context.service_context("attestation".into())) + .disable(config.disable_attesting) .build()?; let preparation_service = PreparationServiceBuilder::new() diff --git a/validator_client/validator_services/src/attestation_service.rs b/validator_client/validator_services/src/attestation_service.rs index 9a6f94d52b..961741a977 100644 --- a/validator_client/validator_services/src/attestation_service.rs +++ b/validator_client/validator_services/src/attestation_service.rs @@ -21,6 +21,7 @@ pub struct AttestationServiceBuilder { slot_clock: Option, beacon_nodes: Option>>, context: Option>, + disable: bool, } impl AttestationServiceBuilder { @@ -31,6 +32,7 @@ impl AttestationServiceBuilder { slot_clock: None, beacon_nodes: None, context: None, + disable: false, } } @@ -59,6 +61,11 @@ impl AttestationServiceBuilder { self } + pub fn disable(mut self, disable: bool) -> Self { + self.disable = disable; + self + } + pub fn build(self) -> Result, String> { Ok(AttestationService { inner: Arc::new(Inner { @@ -77,6 +84,7 @@ impl AttestationServiceBuilder { context: self .context .ok_or("Cannot build AttestationService without runtime_context")?, + disable: self.disable, }), }) } @@ -89,6 +97,7 @@ pub struct Inner { slot_clock: T, beacon_nodes: Arc>, context: RuntimeContext, + disable: bool, } /// Attempts to produce attestations for all known validators 1/3rd of the way through each slot. @@ -120,6 +129,10 @@ impl AttestationService { /// Starts the service which periodically produces attestations. pub fn start_update_service(self, spec: &ChainSpec) -> Result<(), String> { let log = self.context.log().clone(); + if self.disable { + info!(log, "Attestation service disabled"); + return Ok(()); + } let slot_duration = Duration::from_secs(spec.seconds_per_slot); let duration_to_next_slot = self diff --git a/validator_client/validator_services/src/duties_service.rs b/validator_client/validator_services/src/duties_service.rs index 1c0fd338d2..7437ff8bcf 100644 --- a/validator_client/validator_services/src/duties_service.rs +++ b/validator_client/validator_services/src/duties_service.rs @@ -230,6 +230,7 @@ pub struct DutiesService { pub enable_high_validator_count_metrics: bool, /// If this validator is running in distributed mode. pub distributed: bool, + pub disable_attesting: bool, } impl DutiesService { @@ -403,6 +404,11 @@ pub fn start_update_service( "duties_service_proposers", ); + // Skip starting attestation duties or sync committee services. + if core_duties_service.disable_attesting { + return; + } + /* * Spawn the task which keeps track of local attestation duties. */ diff --git a/validator_client/validator_services/src/sync_committee_service.rs b/validator_client/validator_services/src/sync_committee_service.rs index 3ab5b33b6c..5f84c517f3 100644 --- a/validator_client/validator_services/src/sync_committee_service.rs +++ b/validator_client/validator_services/src/sync_committee_service.rs @@ -87,6 +87,11 @@ impl SyncCommitteeService { pub fn start_update_service(self, spec: &ChainSpec) -> Result<(), String> { let log = self.context.log().clone(); + if self.duties_service.disable_attesting { + info!(log, "Sync committee service disabled"); + return Ok(()); + } + let slot_duration = Duration::from_secs(spec.seconds_per_slot); let duration_to_next_slot = self .slot_clock From 29a295a134c56b12f3f1e9baa42007b52ade8477 Mon Sep 17 00:00:00 2001 From: Mac L Date: Wed, 5 Mar 2025 05:52:57 +0400 Subject: [PATCH 3/7] Add `--long-timeouts-multiplier` CLI flag (#7047) Adds the `--long-timeouts-multiplier` flag. Allows granular control for VC timeouts which has proved useful in Holesky. --- book/src/help_vc.md | 7 +++++++ lighthouse/tests/validator_client.rs | 16 ++++++++++++++++ validator_client/src/cli.rs | 14 ++++++++++++++ validator_client/src/config.rs | 4 ++++ validator_client/src/lib.rs | 2 +- 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/book/src/help_vc.md b/book/src/help_vc.md index 4e26977efd..f3ccdf2ae3 100644 --- a/book/src/help_vc.md +++ b/book/src/help_vc.md @@ -251,6 +251,13 @@ Flags: contain sensitive information about your validator and so this flag should be used with caution. For Windows users, the log file permissions will be inherited from the parent folder. + --long-timeouts-multiplier + If present, the validator client will use a multiplier for the timeout + when making requests to the beacon node. This only takes effect when + the `--use-long-timeouts` flag is present. The timeouts will be the + slot duration multiplied by this value. This flag is generally not + recommended, longer timeouts can cause missed duties when fallbacks + are used. [default: 1] --metrics Enable the Prometheus metrics HTTP server. Disabled by default. --prefer-builder-proposals diff --git a/lighthouse/tests/validator_client.rs b/lighthouse/tests/validator_client.rs index f28e7d9829..eccd97d486 100644 --- a/lighthouse/tests/validator_client.rs +++ b/lighthouse/tests/validator_client.rs @@ -129,6 +129,22 @@ fn use_long_timeouts_flag() { .with_config(|config| assert!(config.use_long_timeouts)); } +#[test] +fn long_timeouts_multiplier_flag_default() { + CommandLineTest::new() + .run() + .with_config(|config| assert_eq!(config.long_timeouts_multiplier, 1)); +} + +#[test] +fn long_timeouts_multiplier_flag() { + CommandLineTest::new() + .flag("use-long-timeouts", None) + .flag("long-timeouts-multiplier", Some("10")) + .run() + .with_config(|config| assert_eq!(config.long_timeouts_multiplier, 10)); +} + #[test] fn beacon_nodes_tls_certs_flag() { let dir = TempDir::new().expect("Unable to create temporary directory"); diff --git a/validator_client/src/cli.rs b/validator_client/src/cli.rs index 68541035b6..18bd736957 100644 --- a/validator_client/src/cli.rs +++ b/validator_client/src/cli.rs @@ -116,6 +116,20 @@ pub struct ValidatorClient { )] pub use_long_timeouts: bool, + #[clap( + long, + requires = "use_long_timeouts", + default_value_t = 1, + help = "If present, the validator client will use a multiplier for the timeout \ + when making requests to the beacon node. This only takes effect when \ + the `--use-long-timeouts` flag is present. The timeouts will be the slot \ + duration multiplied by this value. This flag is generally not recommended, \ + longer timeouts can cause missed duties when fallbacks are used.", + display_order = 0, + help_heading = FLAG_HEADER, + )] + pub long_timeouts_multiplier: u32, + #[clap( long, value_name = "CERTIFICATE-FILES", diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index 24213e83e6..358bdacf5c 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -49,6 +49,8 @@ pub struct Config { pub init_slashing_protection: bool, /// If true, use longer timeouts for requests made to the beacon node. pub use_long_timeouts: bool, + /// Multiplier to use for long timeouts. + pub long_timeouts_multiplier: u32, /// Graffiti to be inserted everytime we create a block. pub graffiti: Option, /// Graffiti file to load per validator graffitis. @@ -112,6 +114,7 @@ impl Default for Config { disable_auto_discover: false, init_slashing_protection: false, use_long_timeouts: false, + long_timeouts_multiplier: 1, graffiti: None, graffiti_file: None, http_api: <_>::default(), @@ -196,6 +199,7 @@ impl Config { config.disable_auto_discover = validator_client_config.disable_auto_discover; config.init_slashing_protection = validator_client_config.init_slashing_protection; config.use_long_timeouts = validator_client_config.use_long_timeouts; + config.long_timeouts_multiplier = validator_client_config.long_timeouts_multiplier; if let Some(graffiti_file_path) = validator_client_config.graffiti_file.as_ref() { let mut graffiti_file = GraffitiFile::new(graffiti_file_path.into()); diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index 10121be2ae..1b91eb71c2 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -325,7 +325,7 @@ impl ProductionValidatorClient { get_validator_block: slot_duration / HTTP_GET_VALIDATOR_BLOCK_TIMEOUT_QUOTIENT, } } else { - Timeouts::set_all(slot_duration) + Timeouts::set_all(slot_duration.saturating_mul(config.long_timeouts_multiplier)) }; Ok(BeaconNodeHttpClient::from_components( From efa6ba37bb89c562034a5d472245a70f77c163e3 Mon Sep 17 00:00:00 2001 From: Ryan Schneider Date: Tue, 4 Mar 2025 17:53:00 -0800 Subject: [PATCH 4/7] Make ExecutionBlock::total_difficulty Optional (#7050) This change makes the `total_difficulty` field in `ExecutionBlock` an `Option` since newer clients are no longer including the `totalDifficulty` field. I think this will fix https://github.com/sigp/lighthouse/issues/6937 but I was actually more focused on the builder registration case described below. In our [builder-playground](https://github.com/flashbots/builder-playground) we setup a local devnet using lighthouse, reth, and mev-boost-relay. After upgrading to reth 1.2.0 and lighthouse v7.0.0.beta.0 for Pectra, we noticed that the validator registration process was _sometimes_ failing with: ``` Feb 25 23:35:25.038 ERRO Unable to publish proposer preparation to all beacon nodes, error: Some endpoints failed, num_failed: 1 http://localhost:3500/ => RequestFailed(ServerMessage(ErrorMessage { code: 400, message: "BAD_REQUEST: error updating proposer preparations: ForkchoiceUpdate(EngineError(Api { error: Json(Error(\"missing field `totalDifficulty`\", line: 0, column: 0)) }))", stacktraces: [] })), service: preparation Feb 25 23:35:25.099 WARN Unable to publish validator registrations to the builder network, error: Some endpoints failed, num_failed: 1 http://localhost:3500/ => RequestFailed(ServerMessage(ErrorMessage { code: 400, message: "BAD_REQUEST: error updating proposer preparations: ForkchoiceUpdate(EngineError(Api { error: Json(Error(\"missing field `totalDifficulty`\", line: 0, column: 0)) }))", stacktraces: [] })), service: preparation ``` What was even more confusing, was that it was sometimes working, which actually led to a wild goose chase thinking it was a networking issue. However, when tracing through the LH code, I came across this comment: https://github.com/sigp/lighthouse/blob/70194dfc6a3f4d10c9059610f889ff5a4e863a6a/beacon_node/beacon_chain/src/beacon_chain.rs#L6048-L6049 This explained why it sometimes worked, in our playground we run lighthouse with `--prepare-payload-lookahead 8000` thus there was always a 4-second window where the call wasn't made. But, if the call was made, then this code would 100% fail with updated reth: https://github.com/sigp/lighthouse/blob/unstable/beacon_node/execution_layer/src/lib.rs#L1688-L1692 Which would then mapped to a `Error::ForkchoiceUpdate` in `update_execution_engine_forkchoice`. Anyways, the fix was to make `total_difficulty` Optional, and then to update any code paths where it was used. In doing so, I assume that if the EL doesn't include total difficulty then the chain is already post-merge. --- .../beacon_chain/src/bellatrix_readiness.rs | 2 +- beacon_node/execution_layer/src/engine_api.rs | 9 ++++++++- beacon_node/execution_layer/src/lib.rs | 16 ++++++++++------ .../src/test_utils/execution_block_generator.rs | 4 ++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/beacon_node/beacon_chain/src/bellatrix_readiness.rs b/beacon_node/beacon_chain/src/bellatrix_readiness.rs index 500588953f..412870354b 100644 --- a/beacon_node/beacon_chain/src/bellatrix_readiness.rs +++ b/beacon_node/beacon_chain/src/bellatrix_readiness.rs @@ -171,7 +171,7 @@ impl BeaconChain { return BellatrixReadiness::NotSynced; } let params = MergeConfig::from_chainspec(&self.spec); - let current_difficulty = el.get_current_difficulty().await.ok(); + let current_difficulty = el.get_current_difficulty().await.ok().flatten(); BellatrixReadiness::Ready { config: params, current_difficulty, diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index b9d878b1f8..aed6cdba67 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -142,11 +142,18 @@ pub struct ExecutionBlock { pub block_number: u64, pub parent_hash: ExecutionBlockHash, - pub total_difficulty: Uint256, + pub total_difficulty: Option, #[serde(with = "serde_utils::u64_hex_be")] pub timestamp: u64, } +impl ExecutionBlock { + pub fn terminal_total_difficulty_reached(&self, terminal_total_difficulty: Uint256) -> bool { + self.total_difficulty + .is_none_or(|td| td >= terminal_total_difficulty) + } +} + #[superstruct( variants(V1, V2, V3), variant_attributes(derive(Clone, Debug, Eq, Hash, PartialEq),), diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 4fd7188c20..cde6cc6f48 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -621,7 +621,7 @@ impl ExecutionLayer { } /// Get the current difficulty of the PoW chain. - pub async fn get_current_difficulty(&self) -> Result { + pub async fn get_current_difficulty(&self) -> Result, ApiError> { let block = self .engine() .api @@ -1680,7 +1680,8 @@ impl ExecutionLayer { self.execution_blocks().await.put(block.block_hash, block); loop { - let block_reached_ttd = block.total_difficulty >= spec.terminal_total_difficulty; + let block_reached_ttd = + block.terminal_total_difficulty_reached(spec.terminal_total_difficulty); if block_reached_ttd { if block.parent_hash == ExecutionBlockHash::zero() { return Ok(Some(block)); @@ -1689,7 +1690,8 @@ impl ExecutionLayer { .get_pow_block(engine, block.parent_hash) .await? .ok_or(ApiError::ExecutionBlockNotFound(block.parent_hash))?; - let parent_reached_ttd = parent.total_difficulty >= spec.terminal_total_difficulty; + let parent_reached_ttd = + parent.terminal_total_difficulty_reached(spec.terminal_total_difficulty); if block_reached_ttd && !parent_reached_ttd { return Ok(Some(block)); @@ -1765,9 +1767,11 @@ impl ExecutionLayer { parent: ExecutionBlock, spec: &ChainSpec, ) -> bool { - let is_total_difficulty_reached = block.total_difficulty >= spec.terminal_total_difficulty; - let is_parent_total_difficulty_valid = - parent.total_difficulty < spec.terminal_total_difficulty; + let is_total_difficulty_reached = + block.terminal_total_difficulty_reached(spec.terminal_total_difficulty); + let is_parent_total_difficulty_valid = parent + .total_difficulty + .is_some_and(|td| td < spec.terminal_total_difficulty); is_total_difficulty_reached && is_parent_total_difficulty_valid } diff --git a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs index 5a5c9e1fa9..81fb9bd7b8 100644 --- a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs +++ b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs @@ -84,14 +84,14 @@ impl Block { block_hash: block.block_hash, block_number: block.block_number, parent_hash: block.parent_hash, - total_difficulty: block.total_difficulty, + total_difficulty: Some(block.total_difficulty), timestamp: block.timestamp, }, Block::PoS(payload) => ExecutionBlock { block_hash: payload.block_hash(), block_number: payload.block_number(), parent_hash: payload.parent_hash(), - total_difficulty, + total_difficulty: Some(total_difficulty), timestamp: payload.timestamp(), }, } From 066f28770f7d21eeb5b4d5d3714abe8053ed26f2 Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Tue, 4 Mar 2025 23:21:13 -0700 Subject: [PATCH 5/7] Schedule Chiado testnet Electra hard fork (#7074) --- .../built_in_network_configs/chiado/config.yaml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/common/eth2_network_config/built_in_network_configs/chiado/config.yaml b/common/eth2_network_config/built_in_network_configs/chiado/config.yaml index 35ba3af28b..1455ec5f63 100644 --- a/common/eth2_network_config/built_in_network_configs/chiado/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/chiado/config.yaml @@ -46,7 +46,7 @@ DENEB_FORK_VERSION: 0x0400006f DENEB_FORK_EPOCH: 516608 # Wed Jan 31 2024 18:15:40 GMT+0000 # Electra ELECTRA_FORK_VERSION: 0x0500006f -ELECTRA_FORK_EPOCH: 18446744073709551615 +ELECTRA_FORK_EPOCH: 948224 # Thu Mar 6 2025 09:43:40 GMT+0000 # Fulu FULU_FORK_VERSION: 0x0600006f FULU_FORK_EPOCH: 18446744073709551615 @@ -138,6 +138,18 @@ BLOB_SIDECAR_SUBNET_COUNT: 6 # `uint64(6)` MAX_BLOBS_PER_BLOCK: 6 +# Electra +# 2**7 * 10**9 (= 128,000,000,000) +MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000 +# 2**6 * 10**9 (= 64,000,000,000) +MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 64000000000 +# `2` +BLOB_SIDECAR_SUBNET_COUNT_ELECTRA: 2 +# `uint64(2)` +MAX_BLOBS_PER_BLOCK_ELECTRA: 2 +# MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK_ELECTRA +MAX_REQUEST_BLOB_SIDECARS_ELECTRA: 256 + # DAS NUMBER_OF_COLUMNS: 128 NUMBER_OF_CUSTODY_GROUPS: 128 From 09849e841b1f92b681fd937c5347c5d482aa5caa Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Thu, 6 Mar 2025 14:50:42 +1100 Subject: [PATCH 6/7] Use `sync_tolerance_epochs` flag to control the proposer prep routines (#7044) Replace the `2 + 2 == 5` hacks from `holesky-rescue` and use the existing `sync_tolerance_epochs` flag to control the proposer prep routines. --- beacon_node/beacon_chain/src/beacon_chain.rs | 14 ++++---------- beacon_node/beacon_chain/src/chain_config.rs | 7 +++++++ beacon_node/http_api/src/lib.rs | 15 ++------------- beacon_node/src/config.rs | 11 +++++++---- lighthouse/tests/beacon_node.rs | 17 +++++++++++++++-- 5 files changed, 35 insertions(+), 29 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index eb731f7d6a..891a32a6d0 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -144,11 +144,6 @@ pub const FORK_CHOICE_DB_KEY: Hash256 = Hash256::ZERO; /// Defines how old a block can be before it's no longer a candidate for the early attester cache. const EARLY_ATTESTER_CACHE_HISTORIC_SLOTS: u64 = 4; -/// Defines a distance between the head block slot and the current slot. -/// -/// If the head block is older than this value, don't bother preparing beacon proposers. -const PREPARE_PROPOSER_HISTORIC_EPOCHS: u64 = 4; - /// If the head is more than `MAX_PER_SLOT_FORK_CHOICE_DISTANCE` slots behind the wall-clock slot, DO NOT /// run the per-slot tasks (primarily fork choice). /// @@ -4848,7 +4843,7 @@ impl BeaconChain { let proposer_index = if let Some(proposer) = cached_proposer { proposer.index as u64 } else { - if head_epoch + 2 < proposal_epoch { + if head_epoch + self.config.sync_tolerance_epochs < proposal_epoch { warn!( self.log, "Skipping proposer preparation"; @@ -6079,19 +6074,18 @@ impl BeaconChain { // Use a blocking task since blocking the core executor on the canonical head read lock can // block the core tokio executor. let chain = self.clone(); + let tolerance_slots = self.config.sync_tolerance_epochs * T::EthSpec::slots_per_epoch(); let maybe_prep_data = self .spawn_blocking_handle( move || { let cached_head = chain.canonical_head.cached_head(); // Don't bother with proposer prep if the head is more than - // `PREPARE_PROPOSER_HISTORIC_EPOCHS` prior to the current slot. + // `sync_tolerance_epochs` prior to the current slot. // // This prevents the routine from running during sync. let head_slot = cached_head.head_slot(); - if head_slot + T::EthSpec::slots_per_epoch() * PREPARE_PROPOSER_HISTORIC_EPOCHS - < current_slot - { + if head_slot + tolerance_slots < current_slot { debug!( chain.log, "Head too old for proposer prep"; diff --git a/beacon_node/beacon_chain/src/chain_config.rs b/beacon_node/beacon_chain/src/chain_config.rs index fcdd57abbc..4ca2db2aaa 100644 --- a/beacon_node/beacon_chain/src/chain_config.rs +++ b/beacon_node/beacon_chain/src/chain_config.rs @@ -16,6 +16,9 @@ pub const DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR: u32 = 3; /// Fraction of a slot lookahead for fork choice in the state advance timer (500ms on mainnet). pub const FORK_CHOICE_LOOKAHEAD_FACTOR: u32 = 24; +/// Default sync tolerance epochs. +pub const DEFAULT_SYNC_TOLERANCE_EPOCHS: u64 = 2; + #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] pub struct ChainConfig { /// Maximum number of slots to skip when importing an attestation. @@ -94,6 +97,9 @@ pub struct ChainConfig { /// The delay in milliseconds applied by the node between sending each blob or data column batch. /// This doesn't apply if the node is the block proposer. pub blob_publication_batch_interval: Duration, + /// The max distance between the head block and the current slot at which Lighthouse will + /// consider itself synced and still serve validator-related requests. + pub sync_tolerance_epochs: u64, } impl Default for ChainConfig { @@ -129,6 +135,7 @@ impl Default for ChainConfig { enable_sampling: false, blob_publication_batches: 4, blob_publication_batch_interval: Duration::from_millis(300), + sync_tolerance_epochs: DEFAULT_SYNC_TOLERANCE_EPOCHS, } } } diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index adeaf9eb03..b516a49446 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -107,13 +107,6 @@ use warp_utils::{query::multi_key_query, reject::convert_rejection, uor::Unifyin const API_PREFIX: &str = "eth"; -/// If the node is within this many epochs from the head, we declare it to be synced regardless of -/// the network sync state. -/// -/// This helps prevent attacks where nodes can convince us that we're syncing some non-existent -/// finalized head. -const DEFAULT_SYNC_TOLERANCE_EPOCHS: u64 = 8; - /// A custom type which allows for both unsecured and TLS-enabled HTTP servers. type HttpServer = (SocketAddr, Pin + Send>>); @@ -157,7 +150,6 @@ pub struct Config { pub duplicate_block_status_code: StatusCode, pub enable_light_client_server: bool, pub target_peers: usize, - pub sync_tolerance_epochs: Option, } impl Default for Config { @@ -174,7 +166,6 @@ impl Default for Config { duplicate_block_status_code: StatusCode::ACCEPTED, enable_light_client_server: true, target_peers: 100, - sync_tolerance_epochs: None, } } } @@ -475,10 +466,8 @@ pub fn serve( ) })?; - let sync_tolerance_epochs = config - .sync_tolerance_epochs - .unwrap_or(DEFAULT_SYNC_TOLERANCE_EPOCHS); - let tolerance = sync_tolerance_epochs * T::EthSpec::slots_per_epoch(); + let tolerance = + chain.config.sync_tolerance_epochs * T::EthSpec::slots_per_epoch(); if head_slot + tolerance >= current_slot { Ok(()) diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index d2fdd5104b..494f8e8882 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -8,7 +8,7 @@ use beacon_chain::graffiti_calculator::GraffitiOrigin; use beacon_chain::TrustedSetup; use clap::{parser::ValueSource, ArgMatches, Id}; use clap_utils::flags::DISABLE_MALLOC_TUNING_FLAG; -use clap_utils::{parse_flag, parse_optional, parse_required}; +use clap_utils::{parse_flag, parse_required}; use client::{ClientConfig, ClientGenesis}; use directory::{DEFAULT_BEACON_NODE_DIR, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR}; use environment::RuntimeContext; @@ -177,9 +177,6 @@ pub fn get_config( client_config.http_api.enable_light_client_server = !cli_args.get_flag("disable-light-client-server"); - - client_config.http_api.sync_tolerance_epochs = - parse_optional(cli_args, "sync-tolerance-epochs")?; } if cli_args.get_flag("light-client-server") { @@ -194,6 +191,12 @@ pub fn get_config( client_config.chain.enable_light_client_server = false; } + if let Some(sync_tolerance_epochs) = + clap_utils::parse_optional(cli_args, "sync-tolerance-epochs")? + { + client_config.chain.sync_tolerance_epochs = sync_tolerance_epochs; + } + if let Some(cache_size) = clap_utils::parse_optional(cli_args, "shuffling-cache-size")? { client_config.chain.shuffling_cache_size = cache_size; } diff --git a/lighthouse/tests/beacon_node.rs b/lighthouse/tests/beacon_node.rs index eaf137d57f..3cbb7d4e15 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::{ DisallowedReOrgOffsets, DEFAULT_RE_ORG_CUTOFF_DENOMINATOR, DEFAULT_RE_ORG_HEAD_THRESHOLD, - DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, + DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION, DEFAULT_SYNC_TOLERANCE_EPOCHS, }; use beacon_node::{ beacon_chain::graffiti_calculator::GraffitiOrigin, @@ -2586,7 +2586,20 @@ fn sync_tolerance_epochs() { .flag("sync-tolerance-epochs", Some("0")) .run_with_zero_port() .with_config(|config| { - assert_eq!(config.http_api.sync_tolerance_epochs, Some(0)); + assert_eq!(config.chain.sync_tolerance_epochs, 0); + }); +} + +#[test] +fn sync_tolerance_epochs_default() { + CommandLineTest::new() + .flag("http", None) + .run_with_zero_port() + .with_config(|config| { + assert_eq!( + config.chain.sync_tolerance_epochs, + DEFAULT_SYNC_TOLERANCE_EPOCHS + ); }); } From 166f6df5a973e5edd6faf17812f483260f50d2a1 Mon Sep 17 00:00:00 2001 From: Michael Sproul Date: Mon, 10 Mar 2025 13:58:57 +1100 Subject: [PATCH 7/7] Temporarily ignore cargo audit failures (#7092) Unblock CI by ignoring cargo audit failures. IMO we need to merge some stuff to get our PR backlog under control and can't wait for audit fixes. I've opened issues to address the actual audit failures: - https://github.com/sigp/lighthouse/issues/7090 - https://github.com/sigp/lighthouse/issues/7091 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f621f38a63..3282e4fa0e 100644 --- a/Makefile +++ b/Makefile @@ -250,7 +250,7 @@ install-audit: cargo install --force cargo-audit audit-CI: - cargo audit + cargo audit --ignore RUSTSEC-2025-0009 --ignore RUSTSEC-2024-0437 # Runs `cargo vendor` to make sure dependencies can be vendored for packaging, reproducibility and archival purpose. vendor: