Files
lighthouse/beacon_node/beacon_chain/src/electra_readiness.rs
Mac L 13f94ef0f3 Rename Merge to Bellatrix (#5601)
* Rename Merge to Bellatrix

* Remove tree-hash-cache which got readded from the rebase
2024-04-25 20:19:41 +00:00

124 lines
5.0 KiB
Rust

//! Provides tools for checking if a node is ready for the Electra upgrade and following merge
//! transition.
use crate::{BeaconChain, BeaconChainTypes};
use execution_layer::http::{
ENGINE_FORKCHOICE_UPDATED_V3, ENGINE_GET_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V3,
};
use serde::{Deserialize, Serialize};
use std::fmt;
use std::time::Duration;
use types::*;
/// The time before the Electra fork when we will start issuing warnings about preparation.
use super::bellatrix_readiness::SECONDS_IN_A_WEEK;
pub const ELECTRA_READINESS_PREPARATION_SECONDS: u64 = SECONDS_IN_A_WEEK * 2;
pub const ENGINE_CAPABILITIES_REFRESH_INTERVAL: u64 = 300;
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
pub enum ElectraReadiness {
/// The execution engine is electra-enabled (as far as we can tell)
Ready,
/// We are connected to an execution engine which doesn't support the V3 engine api methods
V3MethodsNotSupported { error: String },
/// The transition configuration with the EL failed, there might be a problem with
/// connectivity, authentication or a difference in configuration.
ExchangeCapabilitiesFailed { error: String },
/// The user has not configured an execution endpoint
NoExecutionEndpoint,
}
impl fmt::Display for ElectraReadiness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ElectraReadiness::Ready => {
write!(f, "This node appears ready for Electra.")
}
ElectraReadiness::ExchangeCapabilitiesFailed { error } => write!(
f,
"Could not exchange capabilities with the \
execution endpoint: {}",
error
),
ElectraReadiness::NoExecutionEndpoint => write!(
f,
"The --execution-endpoint flag is not specified, this is a \
requirement post-merge"
),
ElectraReadiness::V3MethodsNotSupported { error } => write!(
f,
"Execution endpoint does not support Electra methods: {}",
error
),
}
}
}
impl<T: BeaconChainTypes> BeaconChain<T> {
/// Returns `true` if electra epoch is set and Electra fork has occurred or will
/// occur within `ELECTRA_READINESS_PREPARATION_SECONDS`
pub fn is_time_to_prepare_for_electra(&self, current_slot: Slot) -> bool {
if let Some(electra_epoch) = self.spec.electra_fork_epoch {
let electra_slot = electra_epoch.start_slot(T::EthSpec::slots_per_epoch());
let electra_readiness_preparation_slots =
ELECTRA_READINESS_PREPARATION_SECONDS / self.spec.seconds_per_slot;
// Return `true` if Electra has happened or is within the preparation time.
current_slot + electra_readiness_preparation_slots > electra_slot
} else {
// The Electra fork epoch has not been defined yet, no need to prepare.
false
}
}
/// Attempts to connect to the EL and confirm that it is ready for electra.
pub async fn check_electra_readiness(&self) -> ElectraReadiness {
if let Some(el) = self.execution_layer.as_ref() {
match el
.get_engine_capabilities(Some(Duration::from_secs(
ENGINE_CAPABILITIES_REFRESH_INTERVAL,
)))
.await
{
Err(e) => {
// The EL was either unreachable or responded with an error
ElectraReadiness::ExchangeCapabilitiesFailed {
error: format!("{:?}", e),
}
}
Ok(capabilities) => {
// TODO(electra): Update in the event we get V4s.
let mut missing_methods = String::from("Required Methods Unsupported:");
let mut all_good = true;
if !capabilities.get_payload_v3 {
missing_methods.push(' ');
missing_methods.push_str(ENGINE_GET_PAYLOAD_V3);
all_good = false;
}
if !capabilities.forkchoice_updated_v3 {
missing_methods.push(' ');
missing_methods.push_str(ENGINE_FORKCHOICE_UPDATED_V3);
all_good = false;
}
if !capabilities.new_payload_v3 {
missing_methods.push(' ');
missing_methods.push_str(ENGINE_NEW_PAYLOAD_V3);
all_good = false;
}
if all_good {
ElectraReadiness::Ready
} else {
ElectraReadiness::V3MethodsNotSupported {
error: missing_methods,
}
}
}
}
} else {
ElectraReadiness::NoExecutionEndpoint
}
}
}