Skip to content

Commit

Permalink
Add EIP-7594 boilerplate code.
Browse files Browse the repository at this point in the history
  • Loading branch information
jimmygchen committed May 7, 2024
1 parent a857546 commit 3480d62
Show file tree
Hide file tree
Showing 91 changed files with 1,685 additions and 242 deletions.
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

0 comments on commit 3480d62

Please sign in to comment.