Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EIP-7594 boilerplate #5734

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ PROFILE ?= release

# List of all hard forks. This list is used to set env variables for several tests so that
# they run for different forks.
FORKS=phase0 altair bellatrix capella deneb electra
FORKS=phase0 altair bellatrix capella deneb electra eip7594

# Extra flags for Cargo
CARGO_INSTALL_EXTRA_FLAGS?=
Expand Down
3 changes: 2 additions & 1 deletion beacon_node/beacon_chain/src/attestation_rewards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
| BeaconState::Bellatrix(_)
| BeaconState::Capella(_)
| BeaconState::Deneb(_)
| BeaconState::Electra(_) => self.compute_attestation_rewards_altair(state, validators),
| BeaconState::Electra(_)
| BeaconState::Eip7594(_) => self.compute_attestation_rewards_altair(state, validators),
}
}

Expand Down
2 changes: 1 addition & 1 deletion beacon_node/beacon_chain/src/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@ pub fn verify_propagation_slot_range<S: SlotClock, E: EthSpec>(
one_epoch_prior
}
// EIP-7045
ForkName::Deneb | ForkName::Electra => one_epoch_prior
ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => one_epoch_prior
.epoch(E::slots_per_epoch())
.start_slot(E::slots_per_epoch()),
};
Expand Down
5 changes: 3 additions & 2 deletions beacon_node/beacon_chain/src/beacon_block_streamer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use types::{
SignedBlindedBeaconBlock, Slot,
};
use types::{
ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadElectra,
ExecutionPayloadHeader,
ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadEip7594,
ExecutionPayloadElectra, ExecutionPayloadHeader,
};

#[derive(PartialEq)]
Expand Down Expand Up @@ -99,6 +99,7 @@ fn reconstruct_default_header_block<E: EthSpec>(
ForkName::Capella => ExecutionPayloadCapella::default().into(),
ForkName::Deneb => ExecutionPayloadDeneb::default().into(),
ForkName::Electra => ExecutionPayloadElectra::default().into(),
ForkName::Eip7594 => ExecutionPayloadEip7594::default().into(),
ForkName::Base | ForkName::Altair => {
return Err(Error::PayloadReconstruction(format!(
"Block with fork variant {} has execution payload",
Expand Down
48 changes: 44 additions & 4 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5005,7 +5005,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
BeaconState::Bellatrix(_)
| BeaconState::Capella(_)
| BeaconState::Deneb(_)
| BeaconState::Electra(_) => {
| BeaconState::Electra(_)
| BeaconState::Eip7594(_) => {
let prepare_payload_handle = get_execution_payload(
self.clone(),
&state,
Expand Down Expand Up @@ -5399,6 +5400,44 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
execution_payload_value,
)
}
BeaconState::Eip7594(_) => {
let (payload, kzg_commitments, maybe_blobs_and_proofs, execution_payload_value) =
block_contents
.ok_or(BlockProductionError::MissingExecutionPayload)?
.deconstruct();

(
BeaconBlock::Eip7594(BeaconBlockEip7594 {
slot,
proposer_index,
parent_root,
state_root: Hash256::zero(),
body: BeaconBlockBodyEip7594 {
randao_reveal,
eth1_data,
graffiti,
proposer_slashings: proposer_slashings.into(),
attester_slashings: attester_slashings.into(),
attestations: attestations.into(),
deposits: deposits.into(),
voluntary_exits: voluntary_exits.into(),
sync_aggregate: sync_aggregate
.ok_or(BlockProductionError::MissingSyncAggregate)?,
execution_payload: payload
.try_into()
.map_err(|_| BlockProductionError::InvalidPayloadFork)?,
bls_to_execution_changes: bls_to_execution_changes.into(),
blob_kzg_commitments: kzg_commitments.ok_or(
BlockProductionError::MissingKzgCommitment(
"Kzg commitments missing from block contents".to_string(),
),
)?,
},
}),
maybe_blobs_and_proofs,
execution_payload_value,
)
}
};

let block = SignedBeaconBlock::from_block(
Expand Down Expand Up @@ -5721,7 +5760,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let prepare_slot_fork = self.spec.fork_name_at_slot::<T::EthSpec>(prepare_slot);
let withdrawals = match prepare_slot_fork {
ForkName::Base | ForkName::Altair | ForkName::Bellatrix => None,
ForkName::Capella | ForkName::Deneb | ForkName::Electra => {
ForkName::Capella | ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => {
let chain = self.clone();
self.spawn_blocking_handle(
move || {
Expand All @@ -5736,7 +5775,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {

let parent_beacon_block_root = match prepare_slot_fork {
ForkName::Base | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella => None,
ForkName::Deneb | ForkName::Electra => {
ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => {
Some(pre_payload_attributes.parent_beacon_block_root)
}
};
Expand Down Expand Up @@ -6781,7 +6820,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
| ForkName::Bellatrix
| ForkName::Capella
| ForkName::Deneb
| ForkName::Electra => {
| ForkName::Electra
| ForkName::Eip7594 => {
LightClientBootstrap::from_beacon_state(&mut state, &block, &self.spec)
.map(|bootstrap| Some((bootstrap, fork_name)))
.map_err(Error::LightClientError)
Expand Down
123 changes: 123 additions & 0 deletions beacon_node/beacon_chain/src/eip7594_readiness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//! Provides tools for checking if a node is ready for the Eip7594 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 Eip7594 fork when we will start issuing warnings about preparation.
use super::bellatrix_readiness::SECONDS_IN_A_WEEK;
pub const EIP7594_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 Eip7594Readiness {
/// The execution engine is eip7594-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 Eip7594Readiness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Eip7594Readiness::Ready => {
write!(f, "This node appears ready for Eip7594.")
}
Eip7594Readiness::ExchangeCapabilitiesFailed { error } => write!(
f,
"Could not exchange capabilities with the \
execution endpoint: {}",
error
),
Eip7594Readiness::NoExecutionEndpoint => write!(
f,
"The --execution-endpoint flag is not specified, this is a \
requirement post-merge"
),
Eip7594Readiness::V3MethodsNotSupported { error } => write!(
f,
"Execution endpoint does not support Eip7594 methods: {}",
error
),
}
}
}

impl<T: BeaconChainTypes> BeaconChain<T> {
/// Returns `true` if eip7594 epoch is set and Eip7594 fork has occurred or will
/// occur within `EIP7594_READINESS_PREPARATION_SECONDS`
pub fn is_time_to_prepare_for_eip7594(&self, current_slot: Slot) -> bool {
if let Some(eip7594_epoch) = self.spec.eip7594_fork_epoch {
let eip7594_slot = eip7594_epoch.start_slot(T::EthSpec::slots_per_epoch());
let eip7594_readiness_preparation_slots =
EIP7594_READINESS_PREPARATION_SECONDS / self.spec.seconds_per_slot;
// Return `true` if Eip7594 has happened or is within the preparation time.
current_slot + eip7594_readiness_preparation_slots > eip7594_slot
} else {
// The Eip7594 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 eip7594.
pub async fn check_eip7594_readiness(&self) -> Eip7594Readiness {
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
Eip7594Readiness::ExchangeCapabilitiesFailed {
error: format!("{:?}", e),
}
}
Ok(capabilities) => {
// TODO(eip7594): 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 {
Eip7594Readiness::Ready
} else {
Eip7594Readiness::V3MethodsNotSupported {
error: missing_methods,
}
}
}
}
} else {
Eip7594Readiness::NoExecutionEndpoint
}
}
}
11 changes: 7 additions & 4 deletions beacon_node/beacon_chain/src/execution_payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -412,15 +412,18 @@ pub fn get_execution_payload<T: BeaconChainTypes>(
let latest_execution_payload_header_block_hash =
state.latest_execution_payload_header()?.block_hash();
let withdrawals = match state {
&BeaconState::Capella(_) | &BeaconState::Deneb(_) | &BeaconState::Electra(_) => {
Some(get_expected_withdrawals(state, spec)?.into())
}
&BeaconState::Capella(_)
| &BeaconState::Deneb(_)
| &BeaconState::Electra(_)
| &BeaconState::Eip7594(_) => Some(get_expected_withdrawals(state, spec)?.into()),
&BeaconState::Bellatrix(_) => None,
// These shouldn't happen but they're here to make the pattern irrefutable
&BeaconState::Base(_) | &BeaconState::Altair(_) => None,
};
let parent_beacon_block_root = match state {
BeaconState::Deneb(_) | BeaconState::Electra(_) => Some(parent_block_root),
BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::Eip7594(_) => {
Some(parent_block_root)
}
BeaconState::Bellatrix(_) | BeaconState::Capella(_) => None,
// These shouldn't happen but they're here to make the pattern irrefutable
BeaconState::Base(_) | BeaconState::Altair(_) => None,
Expand Down
1 change: 1 addition & 0 deletions beacon_node/beacon_chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod data_availability_checker;
pub mod data_column_verification;
pub mod deneb_readiness;
mod early_attester_cache;
pub mod eip7594_readiness;
pub mod electra_readiness;
mod errors;
pub mod eth1_chain;
Expand Down
12 changes: 6 additions & 6 deletions beacon_node/beacon_chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -882,9 +882,9 @@ where
| SignedBeaconBlock::Altair(_)
| SignedBeaconBlock::Bellatrix(_)
| SignedBeaconBlock::Capella(_) => (signed_block, None),
SignedBeaconBlock::Deneb(_) | SignedBeaconBlock::Electra(_) => {
(signed_block, block_response.blob_items)
}
SignedBeaconBlock::Deneb(_)
| SignedBeaconBlock::Electra(_)
| SignedBeaconBlock::Eip7594(_) => (signed_block, block_response.blob_items),
};

(block_contents, block_response.state)
Expand Down Expand Up @@ -946,9 +946,9 @@ where
| SignedBeaconBlock::Altair(_)
| SignedBeaconBlock::Bellatrix(_)
| SignedBeaconBlock::Capella(_) => (signed_block, None),
SignedBeaconBlock::Deneb(_) | SignedBeaconBlock::Electra(_) => {
(signed_block, block_response.blob_items)
}
SignedBeaconBlock::Deneb(_)
| SignedBeaconBlock::Electra(_)
| SignedBeaconBlock::Eip7594(_) => (signed_block, block_response.blob_items),
};
(block_contents, pre_state)
}
Expand Down
2 changes: 1 addition & 1 deletion beacon_node/beacon_chain/tests/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ impl GossipTester {
E::slots_per_epoch() + 1
}
// EIP-7045
ForkName::Deneb | ForkName::Electra => {
ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => {
let epoch_slot_offset = (self.slot() % E::slots_per_epoch()).as_u64();
if epoch_slot_offset != 0 {
E::slots_per_epoch() + epoch_slot_offset
Expand Down
53 changes: 53 additions & 0 deletions beacon_node/client/src/notifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use beacon_chain::{
bellatrix_readiness::{BellatrixReadiness, GenesisExecutionPayloadStatus, MergeConfig},
capella_readiness::CapellaReadiness,
deneb_readiness::DenebReadiness,
eip7594_readiness::Eip7594Readiness,
electra_readiness::ElectraReadiness,
BeaconChain, BeaconChainTypes, ExecutionStatus,
};
Expand Down Expand Up @@ -323,6 +324,7 @@ pub fn spawn_notifier<T: BeaconChainTypes>(
capella_readiness_logging(current_slot, &beacon_chain, &log).await;
deneb_readiness_logging(current_slot, &beacon_chain, &log).await;
electra_readiness_logging(current_slot, &beacon_chain, &log).await;
eip7594_readiness_logging(current_slot, &beacon_chain, &log).await;
}
};

Expand Down Expand Up @@ -603,6 +605,57 @@ async fn electra_readiness_logging<T: BeaconChainTypes>(
),
}
}
/// Provides some helpful logging to users to indicate if their node is ready for Eip7594.
async fn eip7594_readiness_logging<T: BeaconChainTypes>(
current_slot: Slot,
beacon_chain: &BeaconChain<T>,
log: &Logger,
) {
// TODO(das): update check here
let eip7594_completed = true;

let has_execution_layer = beacon_chain.execution_layer.is_some();

if eip7594_completed && has_execution_layer
|| !beacon_chain.is_time_to_prepare_for_eip7594(current_slot)
{
return;
}

if eip7594_completed && !has_execution_layer {
// When adding a new fork, add a check for the next fork readiness here.
error!(
log,
"Execution endpoint required";
"info" => "you need a Eip7594 enabled execution engine to validate blocks."
);
return;
}

match beacon_chain.check_eip7594_readiness().await {
Eip7594Readiness::Ready => {
info!(
log,
"Ready for Eip7594";
"info" => "ensure the execution endpoint is updated to the latest Eip7594/Prague release"
)
}
readiness @ Eip7594Readiness::ExchangeCapabilitiesFailed { error: _ } => {
error!(
log,
"Not ready for Eip7594";
"hint" => "the execution endpoint may be offline",
"info" => %readiness,
)
}
readiness => warn!(
log,
"Not ready for Eip7594";
"hint" => "try updating the execution endpoint",
"info" => %readiness,
),
}
}

async fn genesis_execution_payload_logging<T: BeaconChainTypes>(
beacon_chain: &BeaconChain<T>,
Expand Down
Loading
Loading