Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 2 additions & 27 deletions beacon_node/beacon_chain/src/beacon_block_streamer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,6 @@ mod tests {
use crate::beacon_block_streamer::{BeaconBlockStreamer, CheckCaches};
use crate::test_utils::{BeaconChainHarness, EphemeralHarnessType, test_spec};
use bls::Keypair;
use execution_layer::test_utils::Block;
use fixed_bytes::FixedBytesExtended;
use std::sync::Arc;
use std::sync::LazyLock;
Expand Down Expand Up @@ -720,7 +719,7 @@ mod tests {
async fn check_all_blocks_from_altair_to_fulu() {
let slots_per_epoch = MinimalEthSpec::slots_per_epoch() as usize;
let num_epochs = 12;
let bellatrix_fork_epoch = 2usize;
let bellatrix_fork_epoch = 0usize;
let capella_fork_epoch = 4usize;
let deneb_fork_epoch = 6usize;
let electra_fork_epoch = 8usize;
Expand All @@ -737,32 +736,8 @@ mod tests {
let spec = Arc::new(spec);

let harness = get_harness(VALIDATOR_COUNT, spec.clone());
// go to bellatrix fork
harness
.extend_slots(bellatrix_fork_epoch * slots_per_epoch)
.await;
// extend half an epoch
harness.extend_slots(slots_per_epoch / 2).await;
// trigger merge
harness
.execution_block_generator()
.move_to_terminal_block()
.expect("should move to terminal block");
let timestamp =
harness.get_timestamp_at_slot() + harness.spec.get_slot_duration().as_secs();
harness
.execution_block_generator()
.modify_last_block(|block| {
if let Block::PoW(terminal_block) = block {
terminal_block.timestamp = timestamp;
}
});
// finish out merge epoch
harness.extend_slots(slots_per_epoch / 2).await;
// finish rest of epochs
harness
.extend_slots((num_epochs - 1 - bellatrix_fork_epoch) * slots_per_epoch)
.await;
harness.extend_slots(num_epochs * slots_per_epoch).await;

let head = harness.chain.head_snapshot();
let state = &head.beacon_state;
Expand Down
84 changes: 2 additions & 82 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use crate::beacon_proposer_cache::{
};
use crate::blob_verification::{GossipBlobError, GossipVerifiedBlob};
use crate::block_times_cache::BlockTimesCache;
use crate::block_verification::POS_PANDA_BANNER;
use crate::block_verification::{
BlockError, ExecutionPendingBlock, GossipVerifiedBlock, IntoExecutionPendingBlock,
check_block_is_finalized_checkpoint_or_descendant, check_block_relevancy,
Expand Down Expand Up @@ -3501,28 +3500,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.map_err(BeaconChainError::TokioJoin)?
.ok_or(BeaconChainError::RuntimeShutdown)??;

// Log the PoS pandas if a merge transition just occurred.
if payload_verification_outcome.is_valid_merge_transition_block {
info!("{}", POS_PANDA_BANNER);
info!(slot = %block.slot(), "Proof of Stake Activated");
info!(
terminal_pow_block_hash = ?block
.message()
.execution_payload()?
.parent_hash()
.into_root(),
);
info!(
merge_transition_block_root = ?block.message().tree_hash_root(),
);
info!(
merge_transition_execution_hash = ?block
.message()
.execution_payload()?
.block_hash()
.into_root(),
);
}
Ok(ExecutedBlock::new(
block,
import_data,
Expand Down Expand Up @@ -6255,21 +6232,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
input_params: ForkchoiceUpdateParameters,
override_forkchoice_update: OverrideForkchoiceUpdate,
) -> Result<(), Error> {
let next_slot = current_slot + 1;

// There is no need to issue a `forkchoiceUpdated` (fcU) message unless the Bellatrix fork
// has:
//
// 1. Already happened.
// 2. Will happen in the next slot.
//
// The reason for a fcU message in the slot prior to the Bellatrix fork is in case the
// terminal difficulty has already been reached and a payload preparation message needs to
// be issued.
if self.slot_is_prior_to_bellatrix(next_slot) {
return Ok(());
}

let execution_layer = self
.execution_layer
.as_ref()
Expand Down Expand Up @@ -6317,50 +6279,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.unwrap_or_else(ExecutionBlockHash::zero),
)
} else {
// The head block does not have an execution block hash. We must check to see if we
// happen to be the proposer of the transition block, in which case we still need to
// send forkchoice_updated.
if self
.spec
.fork_name_at_slot::<T::EthSpec>(next_slot)
.bellatrix_enabled()
{
// We are post-bellatrix
if let Some(payload_attributes) = execution_layer
.payload_attributes(next_slot, params.head_root)
.await
{
// We are a proposer, check for terminal_pow_block_hash
if let Some(terminal_pow_block_hash) = execution_layer
.get_terminal_pow_block_hash(&self.spec, payload_attributes.timestamp())
.await
.map_err(Error::ForkchoiceUpdate)?
{
info!(
slot = %next_slot,
"Prepared POS transition block proposer"
);
(
params.head_root,
terminal_pow_block_hash,
params
.justified_hash
.unwrap_or_else(ExecutionBlockHash::zero),
params
.finalized_hash
.unwrap_or_else(ExecutionBlockHash::zero),
)
} else {
// TTD hasn't been reached yet, no need to update the EL.
return Ok(());
}
} else {
// We are not a proposer, no need to update the EL.
return Ok(());
}
} else {
return Ok(());
}
// Proposing the block for the merge is no longer supported.
return Ok(());
};

let forkchoice_updated_response = execution_layer
Expand Down
171 changes: 1 addition & 170 deletions beacon_node/beacon_chain/src/bellatrix_readiness.rs
Original file line number Diff line number Diff line change
@@ -1,126 +1,9 @@
//! Provides tools for checking if a node is ready for the Bellatrix upgrade and following merge
//! transition.
//! Provides tools for checking genesis execution payload consistency.

use crate::{BeaconChain, BeaconChainError as Error, BeaconChainTypes};
use execution_layer::BlockByNumberQuery;
use serde::{Deserialize, Serialize, Serializer};
use std::fmt;
use std::fmt::Write;
use types::*;

/// The time before the Bellatrix fork when we will start issuing warnings about preparation.
pub const SECONDS_IN_A_WEEK: u64 = 604800;
pub const BELLATRIX_READINESS_PREPARATION_SECONDS: u64 = SECONDS_IN_A_WEEK * 2;

#[derive(Default, Debug, Serialize, Deserialize)]
pub struct MergeConfig {
#[serde(serialize_with = "serialize_uint256")]
pub terminal_total_difficulty: Option<Uint256>,
#[serde(skip_serializing_if = "Option::is_none")]
pub terminal_block_hash: Option<ExecutionBlockHash>,
#[serde(skip_serializing_if = "Option::is_none")]
pub terminal_block_hash_epoch: Option<Epoch>,
}

impl fmt::Display for MergeConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.terminal_block_hash.is_none()
&& self.terminal_block_hash_epoch.is_none()
&& self.terminal_total_difficulty.is_none()
{
return write!(
f,
"Merge terminal difficulty parameters not configured, check your config"
);
}
let mut display_string = String::new();
if let Some(terminal_total_difficulty) = self.terminal_total_difficulty {
write!(
display_string,
"terminal_total_difficulty: {},",
terminal_total_difficulty
)?;
}
if let Some(terminal_block_hash) = self.terminal_block_hash {
write!(
display_string,
"terminal_block_hash: {},",
terminal_block_hash
)?;
}
if let Some(terminal_block_hash_epoch) = self.terminal_block_hash_epoch {
write!(
display_string,
"terminal_block_hash_epoch: {},",
terminal_block_hash_epoch
)?;
}
write!(f, "{}", display_string.trim_end_matches(','))?;
Ok(())
}
}
impl MergeConfig {
/// Instantiate `self` from the values in a `ChainSpec`.
pub fn from_chainspec(spec: &ChainSpec) -> Self {
let mut params = MergeConfig::default();
if spec.terminal_total_difficulty != Uint256::MAX {
params.terminal_total_difficulty = Some(spec.terminal_total_difficulty);
}
if spec.terminal_block_hash != ExecutionBlockHash::zero() {
params.terminal_block_hash = Some(spec.terminal_block_hash);
}
if spec.terminal_block_hash_activation_epoch != Epoch::max_value() {
params.terminal_block_hash_epoch = Some(spec.terminal_block_hash_activation_epoch);
}
params
}
}

/// Indicates if a node is ready for the Bellatrix upgrade and subsequent merge transition.
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
pub enum BellatrixReadiness {
/// The node is ready, as far as we can tell.
Ready {
config: MergeConfig,
#[serde(serialize_with = "serialize_uint256")]
current_difficulty: Option<Uint256>,
},
/// The EL can be reached and has the correct configuration, however it's not yet synced.
NotSynced,
/// The user has not configured this node to use an execution endpoint.
NoExecutionEndpoint,
}

impl fmt::Display for BellatrixReadiness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BellatrixReadiness::Ready {
config: params,
current_difficulty,
} => {
write!(
f,
"This node appears ready for Bellatrix \
Params: {}, current_difficulty: {:?}",
params, current_difficulty
)
}
BellatrixReadiness::NotSynced => write!(
f,
"The execution endpoint is connected and configured, \
however it is not yet synced"
),
BellatrixReadiness::NoExecutionEndpoint => write!(
f,
"The --execution-endpoint flag is not specified, this is a \
requirement for Bellatrix"
),
}
}
}

pub enum GenesisExecutionPayloadStatus {
Correct(ExecutionBlockHash),
BlockHashMismatch {
Expand All @@ -141,47 +24,6 @@ pub enum GenesisExecutionPayloadStatus {
}

impl<T: BeaconChainTypes> BeaconChain<T> {
/// Returns `true` if user has an EL configured, or if the Bellatrix fork has occurred or will
/// occur within `BELLATRIX_READINESS_PREPARATION_SECONDS`.
pub fn is_time_to_prepare_for_bellatrix(&self, current_slot: Slot) -> bool {
if let Some(bellatrix_epoch) = self.spec.bellatrix_fork_epoch {
let bellatrix_slot = bellatrix_epoch.start_slot(T::EthSpec::slots_per_epoch());
let bellatrix_readiness_preparation_slots =
BELLATRIX_READINESS_PREPARATION_SECONDS / self.spec.get_slot_duration().as_secs();

if self.execution_layer.is_some() {
// The user has already configured an execution layer, start checking for readiness
// right away.
true
} else {
// Return `true` if Bellatrix has happened or is within the preparation time.
current_slot + bellatrix_readiness_preparation_slots > bellatrix_slot
}
} else {
// The Bellatrix 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 Bellatrix.
pub async fn check_bellatrix_readiness(&self, current_slot: Slot) -> BellatrixReadiness {
if let Some(el) = self.execution_layer.as_ref() {
if !el.is_synced_for_notifier(current_slot).await {
// The EL is not synced.
return BellatrixReadiness::NotSynced;
}
let params = MergeConfig::from_chainspec(&self.spec);
let current_difficulty = el.get_current_difficulty().await.ok().flatten();
BellatrixReadiness::Ready {
config: params,
current_difficulty,
}
} else {
// There is no EL configured.
BellatrixReadiness::NoExecutionEndpoint
}
}

/// Check that the execution payload embedded in the genesis state matches the EL's genesis
/// block.
pub async fn check_genesis_execution_payload_is_correct(
Expand Down Expand Up @@ -223,14 +65,3 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
Ok(GenesisExecutionPayloadStatus::Correct(exec_block_hash))
}
}

/// Utility function to serialize a Uint256 as a decimal string.
fn serialize_uint256<S>(val: &Option<Uint256>, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match val {
Some(v) => v.to_string().serialize(s),
None => s.serialize_none(),
}
}
Loading
Loading