Resolve merge conflicts

This commit is contained in:
Eitan Seri-Levi
2026-01-02 08:52:14 -06:00
918 changed files with 49304 additions and 37273 deletions

View File

@@ -9,10 +9,12 @@ name = "beacon_node_fallback"
path = "src/lib.rs"
[dependencies]
bls = { workspace = true }
clap = { workspace = true }
eth2 = { workspace = true }
futures = { workspace = true }
itertools = { workspace = true }
sensitive_url = { workspace = true }
serde = { workspace = true }
slot_clock = { workspace = true }
strum = { workspace = true }

View File

@@ -4,13 +4,14 @@
pub mod beacon_node_health;
use beacon_node_health::{
check_node_health, BeaconNodeHealth, BeaconNodeSyncDistanceTiers, ExecutionEngineHealth,
IsOptimistic, SyncDistanceTier,
BeaconNodeHealth, BeaconNodeSyncDistanceTiers, ExecutionEngineHealth, IsOptimistic,
SyncDistanceTier, check_node_health,
};
use clap::ValueEnum;
use eth2::BeaconNodeHttpClient;
use eth2::{BeaconNodeHttpClient, Timeouts};
use futures::future;
use serde::{ser::SerializeStruct, Deserialize, Serialize, Serializer};
use sensitive_url::SensitiveUrl;
use serde::{Deserialize, Serialize, Serializer, ser::SerializeStruct};
use slot_clock::SlotClock;
use std::cmp::Ordering;
use std::fmt;
@@ -19,12 +20,12 @@ use std::future::Future;
use std::sync::Arc;
use std::time::{Duration, Instant};
use std::vec::Vec;
use strum::EnumVariantNames;
use strum::VariantNames;
use task_executor::TaskExecutor;
use tokio::{sync::RwLock, time::sleep};
use tracing::{debug, error, warn};
use types::{ChainSpec, Config as ConfigSpec, EthSpec, Slot};
use validator_metrics::{inc_counter_vec, ENDPOINT_ERRORS, ENDPOINT_REQUESTS};
use validator_metrics::{ENDPOINT_ERRORS, ENDPOINT_REQUESTS, inc_counter_vec};
/// Message emitted when the VC detects the BN is using a different spec.
const UPDATE_REQUIRED_LOG_HINT: &str = "this VC or the remote BN may need updating";
@@ -358,6 +359,13 @@ impl CandidateBeaconNode {
hint = UPDATE_REQUIRED_LOG_HINT,
"Beacon node has mismatched Fulu fork epoch"
);
} else if beacon_node_spec.gloas_fork_epoch != spec.gloas_fork_epoch {
warn!(
endpoint = %self.beacon_node,
endpoint_gloas_fork_epoch = ?beacon_node_spec.gloas_fork_epoch,
hint = UPDATE_REQUIRED_LOG_HINT,
"Beacon node has mismatched Gloas fork epoch"
);
}
Ok(())
@@ -455,6 +463,39 @@ impl<T: SlotClock> BeaconNodeFallback<T> {
(candidate_info, num_available, num_synced)
}
/// Update the list of candidates with a new list.
/// Returns `Ok(new_list)` if the update was successful.
/// Returns `Err(some_err)` if the list is empty.
pub async fn update_candidates_list(
&self,
new_list: Vec<SensitiveUrl>,
use_long_timeouts: bool,
) -> Result<Vec<SensitiveUrl>, String> {
if new_list.is_empty() {
return Err("list cannot be empty".to_string());
}
let timeouts: Timeouts = if new_list.len() == 1 || use_long_timeouts {
Timeouts::set_all(Duration::from_secs(self.spec.seconds_per_slot))
} else {
Timeouts::use_optimized_timeouts(Duration::from_secs(self.spec.seconds_per_slot))
};
let new_candidates: Vec<CandidateBeaconNode> = new_list
.clone()
.into_iter()
.enumerate()
.map(|(index, url)| {
CandidateBeaconNode::new(BeaconNodeHttpClient::new(url, timeouts.clone()), index)
})
.collect();
let mut candidates = self.candidates.write().await;
*candidates = new_candidates;
Ok(new_list)
}
/// Loop through ALL candidates in `self.candidates` and update their sync status.
///
/// It is possible for a node to return an unsynced status while continuing to serve
@@ -615,7 +656,7 @@ impl<T: SlotClock> BeaconNodeFallback<T> {
R: Future<Output = Result<O, Err>>,
Err: Debug,
{
inc_counter_vec(&ENDPOINT_REQUESTS, &[candidate.as_ref()]);
inc_counter_vec(&ENDPOINT_REQUESTS, &[candidate.server().redacted()]);
// There exists a race condition where `func` may be called when the candidate is
// actually not ready. We deem this an acceptable inefficiency.
@@ -627,7 +668,7 @@ impl<T: SlotClock> BeaconNodeFallback<T> {
error = ?e,
"Request to beacon node failed"
);
inc_counter_vec(&ENDPOINT_ERRORS, &[candidate.as_ref()]);
inc_counter_vec(&ENDPOINT_ERRORS, &[candidate.server().redacted()]);
Err((candidate.to_string(), Error::RequestFailed(e)))
}
}
@@ -711,7 +752,7 @@ async fn sort_nodes_by_health(nodes: &mut Vec<CandidateBeaconNode>) {
}
/// Serves as a cue for `BeaconNodeFallback` to tell which requests need to be broadcasted.
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, EnumVariantNames, ValueEnum)]
#[derive(Clone, Copy, Debug, PartialEq, Deserialize, Serialize, VariantNames, ValueEnum)]
#[strum(serialize_all = "kebab-case")]
pub enum ApiTopic {
None,
@@ -739,12 +780,13 @@ impl ApiTopic {
mod tests {
use super::*;
use crate::beacon_node_health::BeaconNodeHealthTier;
use bls::Signature;
use eth2::SensitiveUrl;
use eth2::Timeouts;
use slot_clock::TestingSlotClock;
use strum::VariantNames;
use types::{BeaconBlockDeneb, MainnetEthSpec, Slot};
use types::{EmptyBlock, Signature, SignedBeaconBlockDeneb, SignedBlindedBeaconBlock};
use types::{EmptyBlock, SignedBeaconBlockDeneb, SignedBlindedBeaconBlock};
use validator_test_rig::mock_beacon_node::MockBeaconNode;
type E = MainnetEthSpec;
@@ -756,10 +798,12 @@ mod tests {
let mut variants = ApiTopic::VARIANTS.to_vec();
variants.retain(|s| *s != "none");
assert_eq!(all.len(), variants.len());
assert!(variants
.iter()
.map(|topic| ApiTopic::from_str(topic, true).unwrap())
.eq(all.into_iter()));
assert!(
variants
.iter()
.map(|topic| ApiTopic::from_str(topic, true).unwrap())
.eq(all.into_iter())
);
}
#[tokio::test]