Add Deneb readiness logging (#5074)
This commit is contained in:
parent
f22e5b0f85
commit
a0b407c15d
@ -1,5 +1,4 @@
|
||||
//! Provides tools for checking if a node is ready for the Capella upgrade and following merge
|
||||
//! transition.
|
||||
//! Provides tools for checking if a node is ready for the Capella upgrade.
|
||||
|
||||
use crate::{BeaconChain, BeaconChainTypes};
|
||||
use execution_layer::http::{
|
||||
|
121
beacon_node/beacon_chain/src/deneb_readiness.rs
Normal file
121
beacon_node/beacon_chain/src/deneb_readiness.rs
Normal file
@ -0,0 +1,121 @@
|
||||
//! Provides tools for checking if a node is ready for the Deneb upgrade.
|
||||
|
||||
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 Deneb fork when we will start issuing warnings about preparation.
|
||||
use super::merge_readiness::SECONDS_IN_A_WEEK;
|
||||
pub const DENEB_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 DenebReadiness {
|
||||
/// The execution engine is deneb-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 DenebReadiness {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
DenebReadiness::Ready => {
|
||||
write!(f, "This node appears ready for Deneb.")
|
||||
}
|
||||
DenebReadiness::ExchangeCapabilitiesFailed { error } => write!(
|
||||
f,
|
||||
"Could not exchange capabilities with the \
|
||||
execution endpoint: {}",
|
||||
error
|
||||
),
|
||||
DenebReadiness::NoExecutionEndpoint => write!(
|
||||
f,
|
||||
"The --execution-endpoint flag is not specified, this is a \
|
||||
requirement post-merge"
|
||||
),
|
||||
DenebReadiness::V3MethodsNotSupported { error } => write!(
|
||||
f,
|
||||
"Execution endpoint does not support Deneb methods: {}",
|
||||
error
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// Returns `true` if deneb epoch is set and Deneb fork has occurred or will
|
||||
/// occur within `DENEB_READINESS_PREPARATION_SECONDS`
|
||||
pub fn is_time_to_prepare_for_deneb(&self, current_slot: Slot) -> bool {
|
||||
if let Some(deneb_epoch) = self.spec.deneb_fork_epoch {
|
||||
let deneb_slot = deneb_epoch.start_slot(T::EthSpec::slots_per_epoch());
|
||||
let deneb_readiness_preparation_slots =
|
||||
DENEB_READINESS_PREPARATION_SECONDS / self.spec.seconds_per_slot;
|
||||
// Return `true` if Deneb has happened or is within the preparation time.
|
||||
current_slot + deneb_readiness_preparation_slots > deneb_slot
|
||||
} else {
|
||||
// The Deneb 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 capella.
|
||||
pub async fn check_deneb_readiness(&self) -> DenebReadiness {
|
||||
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
|
||||
DenebReadiness::ExchangeCapabilitiesFailed {
|
||||
error: format!("{:?}", e),
|
||||
}
|
||||
}
|
||||
Ok(capabilities) => {
|
||||
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 {
|
||||
DenebReadiness::Ready
|
||||
} else {
|
||||
DenebReadiness::V3MethodsNotSupported {
|
||||
error: missing_methods,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DenebReadiness::NoExecutionEndpoint
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ pub mod canonical_head;
|
||||
pub mod capella_readiness;
|
||||
pub mod chain_config;
|
||||
pub mod data_availability_checker;
|
||||
pub mod deneb_readiness;
|
||||
mod early_attester_cache;
|
||||
mod errors;
|
||||
pub mod eth1_chain;
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::metrics;
|
||||
use beacon_chain::{
|
||||
capella_readiness::CapellaReadiness,
|
||||
deneb_readiness::DenebReadiness,
|
||||
merge_readiness::{GenesisExecutionPayloadStatus, MergeConfig, MergeReadiness},
|
||||
BeaconChain, BeaconChainTypes, ExecutionStatus,
|
||||
};
|
||||
@ -319,6 +320,7 @@ pub fn spawn_notifier<T: BeaconChainTypes>(
|
||||
eth1_logging(&beacon_chain, &log);
|
||||
merge_readiness_logging(current_slot, &beacon_chain, &log).await;
|
||||
capella_readiness_logging(current_slot, &beacon_chain, &log).await;
|
||||
deneb_readiness_logging(current_slot, &beacon_chain, &log).await;
|
||||
}
|
||||
};
|
||||
|
||||
@ -356,8 +358,8 @@ async fn merge_readiness_logging<T: BeaconChainTypes>(
|
||||
}
|
||||
|
||||
if merge_completed && !has_execution_layer {
|
||||
// Logging of the EE being offline is handled in the other readiness logging functions.
|
||||
if !beacon_chain.is_time_to_prepare_for_capella(current_slot) {
|
||||
// logging of the EE being offline is handled in `capella_readiness_logging()`
|
||||
error!(
|
||||
log,
|
||||
"Execution endpoint required";
|
||||
@ -445,12 +447,15 @@ async fn capella_readiness_logging<T: BeaconChainTypes>(
|
||||
}
|
||||
|
||||
if capella_completed && !has_execution_layer {
|
||||
error!(
|
||||
log,
|
||||
"Execution endpoint required";
|
||||
"info" => "you need a Capella enabled execution engine to validate blocks, see: \
|
||||
https://lighthouse-book.sigmaprime.io/merge-migration.html"
|
||||
);
|
||||
// Logging of the EE being offline is handled in the other readiness logging functions.
|
||||
if !beacon_chain.is_time_to_prepare_for_deneb(current_slot) {
|
||||
error!(
|
||||
log,
|
||||
"Execution endpoint required";
|
||||
"info" => "you need a Capella enabled execution engine to validate blocks, see: \
|
||||
https://lighthouse-book.sigmaprime.io/merge-migration.html"
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -479,6 +484,65 @@ async fn capella_readiness_logging<T: BeaconChainTypes>(
|
||||
}
|
||||
}
|
||||
|
||||
/// Provides some helpful logging to users to indicate if their node is ready for Deneb
|
||||
async fn deneb_readiness_logging<T: BeaconChainTypes>(
|
||||
current_slot: Slot,
|
||||
beacon_chain: &BeaconChain<T>,
|
||||
log: &Logger,
|
||||
) {
|
||||
let deneb_completed = beacon_chain
|
||||
.canonical_head
|
||||
.cached_head()
|
||||
.snapshot
|
||||
.beacon_block
|
||||
.message()
|
||||
.body()
|
||||
.execution_payload()
|
||||
.map_or(false, |payload| payload.blob_gas_used().is_ok());
|
||||
|
||||
let has_execution_layer = beacon_chain.execution_layer.is_some();
|
||||
|
||||
if deneb_completed && has_execution_layer
|
||||
|| !beacon_chain.is_time_to_prepare_for_deneb(current_slot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if deneb_completed && !has_execution_layer {
|
||||
error!(
|
||||
log,
|
||||
"Execution endpoint required";
|
||||
"info" => "you need a Deneb enabled execution engine to validate blocks, see: \
|
||||
https://lighthouse-book.sigmaprime.io/merge-migration.html"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
match beacon_chain.check_deneb_readiness().await {
|
||||
DenebReadiness::Ready => {
|
||||
info!(
|
||||
log,
|
||||
"Ready for Deneb";
|
||||
"info" => "ensure the execution endpoint is updated to the latest Deneb/Cancun release"
|
||||
)
|
||||
}
|
||||
readiness @ DenebReadiness::ExchangeCapabilitiesFailed { error: _ } => {
|
||||
error!(
|
||||
log,
|
||||
"Not ready for Deneb";
|
||||
"hint" => "the execution endpoint may be offline",
|
||||
"info" => %readiness,
|
||||
)
|
||||
}
|
||||
readiness => warn!(
|
||||
log,
|
||||
"Not ready for Deneb";
|
||||
"hint" => "try updating the execution endpoint",
|
||||
"info" => %readiness,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
async fn genesis_execution_payload_logging<T: BeaconChainTypes>(
|
||||
beacon_chain: &BeaconChain<T>,
|
||||
log: &Logger,
|
||||
|
@ -39,6 +39,7 @@ pub trait ExecPayload<T: EthSpec>: Debug + Clone + PartialEq + Hash + TreeHash +
|
||||
fn transactions(&self) -> Option<&Transactions<T>>;
|
||||
/// fork-specific fields
|
||||
fn withdrawals_root(&self) -> Result<Hash256, Error>;
|
||||
fn blob_gas_used(&self) -> Result<u64, Error>;
|
||||
|
||||
/// Is this a default payload with 0x0 roots for transactions and withdrawals?
|
||||
fn is_default_with_zero_roots(&self) -> bool;
|
||||
@ -254,6 +255,13 @@ impl<T: EthSpec> ExecPayload<T> for FullPayload<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
match self {
|
||||
FullPayload::Merge(_) | FullPayload::Capella(_) => Err(Error::IncorrectStateVariant),
|
||||
FullPayload::Deneb(ref inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
|
||||
map_full_payload_ref!(&'a _, self.to_ref(), move |payload, cons| {
|
||||
cons(payload);
|
||||
@ -372,6 +380,15 @@ impl<'b, T: EthSpec> ExecPayload<T> for FullPayloadRef<'b, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
match self {
|
||||
FullPayloadRef::Merge(_) | FullPayloadRef::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
|
||||
map_full_payload_ref!(&'a _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
@ -533,6 +550,15 @@ impl<T: EthSpec> ExecPayload<T> for BlindedPayload<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
match self {
|
||||
BlindedPayload::Merge(_) | BlindedPayload::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
BlindedPayload::Deneb(ref inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots(&self) -> bool {
|
||||
self.to_ref().is_default_with_zero_roots()
|
||||
}
|
||||
@ -621,6 +647,15 @@ impl<'b, T: EthSpec> ExecPayload<T> for BlindedPayloadRef<'b, T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
match self {
|
||||
BlindedPayloadRef::Merge(_) | BlindedPayloadRef::Capella(_) => {
|
||||
Err(Error::IncorrectStateVariant)
|
||||
}
|
||||
BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_default_with_zero_roots<'a>(&'a self) -> bool {
|
||||
map_blinded_payload_ref!(&'b _, self, move |payload, cons| {
|
||||
cons(payload);
|
||||
@ -646,7 +681,8 @@ macro_rules! impl_exec_payload_common {
|
||||
$block_type_variant:ident, // Blinded | Full
|
||||
$is_default_with_empty_roots:block,
|
||||
$f:block,
|
||||
$g:block) => {
|
||||
$g:block,
|
||||
$h:block) => {
|
||||
impl<T: EthSpec> ExecPayload<T> for $wrapper_type<T> {
|
||||
fn block_type() -> BlockType {
|
||||
BlockType::$block_type_variant
|
||||
@ -704,6 +740,11 @@ macro_rules! impl_exec_payload_common {
|
||||
let g = $g;
|
||||
g(self)
|
||||
}
|
||||
|
||||
fn blob_gas_used(&self) -> Result<u64, Error> {
|
||||
let h = $h;
|
||||
h(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> From<$wrapped_type<T>> for $wrapper_type<T> {
|
||||
@ -741,6 +782,14 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
wrapper_ref_type.withdrawals_root()
|
||||
};
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_header<T>) -> Result<u64, Error> =
|
||||
|payload: &$wrapper_type_header<T>| {
|
||||
let wrapper_ref_type = BlindedPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.blob_gas_used()
|
||||
};
|
||||
c
|
||||
}
|
||||
);
|
||||
|
||||
@ -820,6 +869,14 @@ macro_rules! impl_exec_payload_for_fork {
|
||||
wrapper_ref_type.withdrawals_root()
|
||||
};
|
||||
c
|
||||
},
|
||||
{
|
||||
let c: for<'a> fn(&'a $wrapper_type_full<T>) -> Result<u64, Error> =
|
||||
|payload: &$wrapper_type_full<T>| {
|
||||
let wrapper_ref_type = FullPayloadRef::$fork_variant(&payload);
|
||||
wrapper_ref_type.blob_gas_used()
|
||||
};
|
||||
c
|
||||
}
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user