From 3480d6227a0bccd579167fe53f015aaca3e183a1 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 7 May 2024 17:27:34 +1000 Subject: [PATCH] Add EIP-7594 boilerplate code. --- Makefile | 2 +- .../beacon_chain/src/attestation_rewards.rs | 3 +- .../src/attestation_verification.rs | 2 +- .../beacon_chain/src/beacon_block_streamer.rs | 5 +- beacon_node/beacon_chain/src/beacon_chain.rs | 48 ++++- .../beacon_chain/src/eip7594_readiness.rs | 123 ++++++++++++ .../beacon_chain/src/execution_payload.rs | 11 +- beacon_node/beacon_chain/src/lib.rs | 1 + beacon_node/beacon_chain/src/test_utils.rs | 12 +- .../tests/attestation_verification.rs | 2 +- beacon_node/client/src/notifier.rs | 53 ++++++ beacon_node/execution_layer/src/engine_api.rs | 68 ++++++- .../execution_layer/src/engine_api/http.rs | 60 +++++- .../src/engine_api/json_structures.rs | 59 ++++++ .../src/engine_api/new_payload_request.rs | 26 ++- beacon_node/execution_layer/src/lib.rs | 40 +++- .../test_utils/execution_block_generator.rs | 32 +++- .../src/test_utils/handle_rpc.rs | 33 +++- .../src/test_utils/mock_builder.rs | 84 +++++++-- .../http_api/src/build_block_contents.rs | 2 +- beacon_node/http_api/src/publish_blocks.rs | 4 +- beacon_node/lighthouse_network/src/config.rs | 3 +- .../lighthouse_network/src/rpc/codec/base.rs | 3 + .../src/rpc/codec/ssz_snappy.rs | 19 +- .../lighthouse_network/src/rpc/protocol.rs | 27 ++- .../lighthouse_network/src/types/pubsub.rs | 13 +- .../lighthouse_network/src/types/topics.rs | 1 + .../lighthouse_network/tests/common.rs | 3 + .../network_beacon_processor/rpc_methods.rs | 2 +- .../network/src/sync/range_sync/range.rs | 2 +- .../store/src/impls/execution_payload.rs | 3 +- beacon_node/store/src/partial_beacon_state.rs | 56 +++++- common/eth2/src/types.rs | 27 ++- .../chiado/config.yaml | 3 + .../gnosis/config.yaml | 4 +- .../holesky/config.yaml | 3 + .../mainnet/config.yaml | 6 +- consensus/fork_choice/src/fork_choice.rs | 3 +- .../common/get_attestation_participation.rs | 2 +- .../src/common/slash_validator.rs | 3 +- consensus/state_processing/src/genesis.rs | 21 ++- .../src/per_block_processing.rs | 16 +- .../process_operations.rs | 3 +- .../per_block_processing/signature_sets.rs | 11 +- .../verify_attestation.rs | 2 +- .../src/per_epoch_processing.rs | 3 +- .../src/per_slot_processing.rs | 6 +- consensus/state_processing/src/upgrade.rs | 2 + .../state_processing/src/upgrade/eip7594.rs | 126 +++++++++++++ consensus/types/presets/gnosis/deneb.yaml | 9 - consensus/types/presets/gnosis/eip7594.yaml | 10 + consensus/types/presets/mainnet/deneb.yaml | 9 - consensus/types/presets/mainnet/eip7594.yaml | 10 + consensus/types/presets/minimal/deneb.yaml | 9 - consensus/types/presets/minimal/eip7594.yaml | 10 + consensus/types/src/beacon_block.rs | 38 +++- consensus/types/src/beacon_block_body.rs | 176 +++++++++++++++++- consensus/types/src/beacon_state.rs | 93 +++++++-- .../progressive_balances_cache.rs | 3 +- consensus/types/src/builder_bid.rs | 12 +- consensus/types/src/chain_spec.rs | 14 +- consensus/types/src/config_and_preset.rs | 7 +- consensus/types/src/eth_spec.rs | 11 +- consensus/types/src/execution_payload.rs | 24 ++- .../types/src/execution_payload_header.rs | 82 +++++++- consensus/types/src/fork_context.rs | 7 + consensus/types/src/fork_name.rs | 18 ++ consensus/types/src/lib.rs | 25 +-- consensus/types/src/light_client_bootstrap.rs | 17 +- .../types/src/light_client_finality_update.rs | 7 +- consensus/types/src/light_client_header.rs | 14 +- .../src/light_client_optimistic_update.rs | 21 ++- consensus/types/src/light_client_update.rs | 4 +- consensus/types/src/payload.rs | 50 ++++- consensus/types/src/preset.rs | 27 ++- consensus/types/src/signed_beacon_block.rs | 70 ++++++- consensus/types/src/voluntary_exit.rs | 4 +- lcli/src/create_payload_header.rs | 12 +- lcli/src/main.rs | 11 +- lcli/src/new_testnet.rs | 6 +- lcli/src/parse_ssz.rs | 8 + testing/ef_tests/src/cases/common.rs | 1 + .../ef_tests/src/cases/epoch_processing.rs | 27 ++- testing/ef_tests/src/cases/fork.rs | 3 +- .../src/cases/merkle_proof_validity.rs | 7 +- testing/ef_tests/src/cases/operations.rs | 3 +- testing/ef_tests/src/cases/transition.rs | 7 + testing/ef_tests/src/handler.rs | 2 +- validator_client/src/beacon_node_fallback.rs | 8 + .../src/signing_method/web3signer.rs | 6 + validator_client/src/validator_store.rs | 2 +- 91 files changed, 1685 insertions(+), 242 deletions(-) create mode 100644 beacon_node/beacon_chain/src/eip7594_readiness.rs create mode 100644 consensus/state_processing/src/upgrade/eip7594.rs create mode 100644 consensus/types/presets/gnosis/eip7594.yaml create mode 100644 consensus/types/presets/mainnet/eip7594.yaml create mode 100644 consensus/types/presets/minimal/eip7594.yaml diff --git a/Makefile b/Makefile index 12d33cc3a8b..34692ef7b2e 100644 --- a/Makefile +++ b/Makefile @@ -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?= diff --git a/beacon_node/beacon_chain/src/attestation_rewards.rs b/beacon_node/beacon_chain/src/attestation_rewards.rs index d48a83130e6..958ce2e786f 100644 --- a/beacon_node/beacon_chain/src/attestation_rewards.rs +++ b/beacon_node/beacon_chain/src/attestation_rewards.rs @@ -57,7 +57,8 @@ impl BeaconChain { | 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), } } diff --git a/beacon_node/beacon_chain/src/attestation_verification.rs b/beacon_node/beacon_chain/src/attestation_verification.rs index 471c43d94f8..03420314d10 100644 --- a/beacon_node/beacon_chain/src/attestation_verification.rs +++ b/beacon_node/beacon_chain/src/attestation_verification.rs @@ -1067,7 +1067,7 @@ pub fn verify_propagation_slot_range( 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()), }; diff --git a/beacon_node/beacon_chain/src/beacon_block_streamer.rs b/beacon_node/beacon_chain/src/beacon_block_streamer.rs index 0c92b7c1f62..22e720c942b 100644 --- a/beacon_node/beacon_chain/src/beacon_block_streamer.rs +++ b/beacon_node/beacon_chain/src/beacon_block_streamer.rs @@ -14,8 +14,8 @@ use types::{ SignedBlindedBeaconBlock, Slot, }; use types::{ - ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadElectra, - ExecutionPayloadHeader, + ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadEip7594, + ExecutionPayloadElectra, ExecutionPayloadHeader, }; #[derive(PartialEq)] @@ -99,6 +99,7 @@ fn reconstruct_default_header_block( 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", diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index e6028b80e67..861bf13a874 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5005,7 +5005,8 @@ impl BeaconChain { BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => { let prepare_payload_handle = get_execution_payload( self.clone(), &state, @@ -5399,6 +5400,44 @@ impl BeaconChain { 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( @@ -5721,7 +5760,7 @@ impl BeaconChain { let prepare_slot_fork = self.spec.fork_name_at_slot::(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 || { @@ -5736,7 +5775,7 @@ impl BeaconChain { 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) } }; @@ -6781,7 +6820,8 @@ impl BeaconChain { | 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) diff --git a/beacon_node/beacon_chain/src/eip7594_readiness.rs b/beacon_node/beacon_chain/src/eip7594_readiness.rs new file mode 100644 index 00000000000..d0162472698 --- /dev/null +++ b/beacon_node/beacon_chain/src/eip7594_readiness.rs @@ -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 BeaconChain { + /// 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 + } + } +} diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index cbffe363422..26050d05626 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -412,15 +412,18 @@ pub fn get_execution_payload( 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, diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 2fcde392fdc..008586993b1 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -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; diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index b7db2462ca9..8dc59e22f6e 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -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) @@ -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) } diff --git a/beacon_node/beacon_chain/tests/attestation_verification.rs b/beacon_node/beacon_chain/tests/attestation_verification.rs index 1463d1c5c15..6da160671d4 100644 --- a/beacon_node/beacon_chain/tests/attestation_verification.rs +++ b/beacon_node/beacon_chain/tests/attestation_verification.rs @@ -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 diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index a6fd07789d8..6bbca1ee0eb 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -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, }; @@ -323,6 +324,7 @@ pub fn spawn_notifier( 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; } }; @@ -603,6 +605,57 @@ async fn electra_readiness_logging( ), } } +/// Provides some helpful logging to users to indicate if their node is ready for Eip7594. +async fn eip7594_readiness_logging( + current_slot: Slot, + beacon_chain: &BeaconChain, + 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( beacon_chain: &BeaconChain, diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index ce1e0fec5dd..4d9a48aa98e 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -26,7 +26,7 @@ pub use types::{ }; use types::{ ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, KzgProofs, + ExecutionPayloadEip7594, ExecutionPayloadElectra, KzgProofs, }; use types::{Graffiti, GRAFFITI_BYTES_LEN}; @@ -37,7 +37,7 @@ mod new_payload_request; pub use new_payload_request::{ NewPayloadRequest, NewPayloadRequestBellatrix, NewPayloadRequestCapella, - NewPayloadRequestDeneb, NewPayloadRequestElectra, + NewPayloadRequestDeneb, NewPayloadRequestEip7594, NewPayloadRequestElectra, }; pub const LATEST_TAG: &str = "latest"; @@ -155,7 +155,7 @@ pub struct ExecutionBlock { /// Representation of an execution block with enough detail to reconstruct a payload. #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive(Clone, Debug, PartialEq, Serialize, Deserialize,), serde(bound = "E: EthSpec", rename_all = "camelCase"), @@ -189,12 +189,12 @@ pub struct ExecutionBlockWithTransactions { #[serde(rename = "hash")] pub block_hash: ExecutionBlockHash, pub transactions: Vec, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] pub withdrawals: Vec, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Deneb, Electra, Eip7594))] #[serde(with = "serde_utils::u64_hex_be")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Deneb, Electra, Eip7594))] #[serde(with = "serde_utils::u64_hex_be")] pub excess_blob_gas: u64, } @@ -306,6 +306,34 @@ impl TryFrom> for ExecutionBlockWithTransactions excess_blob_gas: block.excess_blob_gas, }) } + ExecutionPayload::Eip7594(block) => { + Self::Eip7594(ExecutionBlockWithTransactionsEip7594 { + parent_hash: block.parent_hash, + fee_recipient: block.fee_recipient, + state_root: block.state_root, + receipts_root: block.receipts_root, + logs_bloom: block.logs_bloom, + prev_randao: block.prev_randao, + block_number: block.block_number, + gas_limit: block.gas_limit, + gas_used: block.gas_used, + timestamp: block.timestamp, + extra_data: block.extra_data, + base_fee_per_gas: block.base_fee_per_gas, + block_hash: block.block_hash, + transactions: block + .transactions + .iter() + .map(|tx| Transaction::decode(&Rlp::new(tx))) + .collect::, _>>()?, + withdrawals: Vec::from(block.withdrawals) + .into_iter() + .map(|withdrawal| withdrawal.into()) + .collect(), + blob_gas_used: block.blob_gas_used, + excess_blob_gas: block.excess_blob_gas, + }) + } }; Ok(json_payload) } @@ -643,6 +671,34 @@ impl ExecutionPayloadBodyV1 { )) } } + ExecutionPayloadHeader::Eip7594(header) => { + if let Some(withdrawals) = self.withdrawals { + Ok(ExecutionPayload::Eip7594(ExecutionPayloadEip7594 { + parent_hash: header.parent_hash, + fee_recipient: header.fee_recipient, + state_root: header.state_root, + receipts_root: header.receipts_root, + logs_bloom: header.logs_bloom, + prev_randao: header.prev_randao, + block_number: header.block_number, + gas_limit: header.gas_limit, + gas_used: header.gas_used, + timestamp: header.timestamp, + extra_data: header.extra_data, + base_fee_per_gas: header.base_fee_per_gas, + block_hash: header.block_hash, + transactions: self.transactions, + withdrawals, + blob_gas_used: header.blob_gas_used, + excess_blob_gas: header.excess_blob_gas, + })) + } else { + Err(format!( + "block {} is post-capella but payload body doesn't have withdrawals", + header.block_hash + )) + } + } } } } diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index 93705a16925..b288e76ba7a 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -769,6 +769,14 @@ impl HttpJsonRpc { ) .await?, ), + ForkName::Eip7594 => ExecutionBlockWithTransactions::Eip7594( + self.rpc_request( + ETH_GET_BLOCK_BY_HASH, + params, + ETH_GET_BLOCK_BY_HASH_TIMEOUT * self.execution_timeout_multiplier, + ) + .await?, + ), ForkName::Base | ForkName::Altair => { return Err(Error::UnsupportedForkVariant(format!( "called get_block_by_hash_with_txns with fork {:?}", @@ -833,6 +841,27 @@ impl HttpJsonRpc { Ok(response.into()) } + pub async fn new_payload_v3_eip7594( + &self, + new_payload_request_eip7594: NewPayloadRequestEip7594<'_, E>, + ) -> Result { + let params = json!([ + JsonExecutionPayload::V3(new_payload_request_eip7594.execution_payload.clone().into()), + new_payload_request_eip7594.versioned_hashes, + new_payload_request_eip7594.parent_beacon_block_root, + ]); + + let response: JsonPayloadStatusV1 = self + .rpc_request( + ENGINE_NEW_PAYLOAD_V3, + params, + ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier, + ) + .await?; + + Ok(response.into()) + } + pub async fn new_payload_v3_electra( &self, new_payload_request_electra: NewPayloadRequestElectra<'_, E>, @@ -905,9 +934,14 @@ impl HttpJsonRpc { .await?; Ok(JsonGetPayloadResponse::V2(response).into()) } - ForkName::Base | ForkName::Altair | ForkName::Deneb | ForkName::Electra => Err( - Error::UnsupportedForkVariant(format!("called get_payload_v2 with {}", fork_name)), - ), + ForkName::Base + | ForkName::Altair + | ForkName::Deneb + | ForkName::Electra + | ForkName::Eip7594 => Err(Error::UnsupportedForkVariant(format!( + "called get_payload_v2 with {}", + fork_name + ))), } } @@ -939,6 +973,16 @@ impl HttpJsonRpc { .await?; Ok(JsonGetPayloadResponse::V4(response).into()) } + ForkName::Eip7594 => { + let response: JsonGetPayloadResponseV3 = self + .rpc_request( + ENGINE_GET_PAYLOAD_V3, + params, + ENGINE_GET_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier, + ) + .await?; + Ok(JsonGetPayloadResponse::V3(response).into()) + } ForkName::Base | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella => Err( Error::UnsupportedForkVariant(format!("called get_payload_v3 with {}", fork_name)), ), @@ -1206,6 +1250,14 @@ impl HttpJsonRpc { Err(Error::RequiredMethodUnsupported("engine_newPayloadV3")) } } + NewPayloadRequest::Eip7594(new_payload_request_eip7594) => { + if engine_capabilities.new_payload_v3 { + self.new_payload_v3_eip7594(new_payload_request_eip7594) + .await + } else { + Err(Error::RequiredMethodUnsupported("engine_newPayloadV3")) + } + } } } @@ -1227,7 +1279,7 @@ impl HttpJsonRpc { Err(Error::RequiredMethodUnsupported("engine_getPayload")) } } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { if engine_capabilities.get_payload_v3 { self.get_payload_v3(fork_name, payload_id).await } else { diff --git a/beacon_node/execution_layer/src/engine_api/json_structures.rs b/beacon_node/execution_layer/src/engine_api/json_structures.rs index 50d3519e129..7066fb6db77 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -207,6 +207,35 @@ impl From> for JsonExecutionPayloadV4 } } +impl From> for JsonExecutionPayloadV3 { + fn from(payload: ExecutionPayloadEip7594) -> Self { + JsonExecutionPayloadV3 { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom, + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data, + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions: payload.transactions, + withdrawals: payload + .withdrawals + .into_iter() + .map(Into::into) + .collect::>() + .into(), + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + } + } +} + impl From> for JsonExecutionPayload { fn from(execution_payload: ExecutionPayload) -> Self { match execution_payload { @@ -214,6 +243,7 @@ impl From> for JsonExecutionPayload { ExecutionPayload::Capella(payload) => JsonExecutionPayload::V2(payload.into()), ExecutionPayload::Deneb(payload) => JsonExecutionPayload::V3(payload.into()), ExecutionPayload::Electra(payload) => JsonExecutionPayload::V4(payload.into()), + ExecutionPayload::Eip7594(payload) => JsonExecutionPayload::V3(payload.into()), } } } @@ -326,6 +356,35 @@ impl From> for ExecutionPayloadElectra } } +impl From> for ExecutionPayloadEip7594 { + fn from(payload: JsonExecutionPayloadV3) -> Self { + ExecutionPayloadEip7594 { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom, + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data, + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions: payload.transactions, + withdrawals: payload + .withdrawals + .into_iter() + .map(Into::into) + .collect::>() + .into(), + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + } + } +} + impl From> for ExecutionPayload { fn from(json_execution_payload: JsonExecutionPayload) -> Self { match json_execution_payload { diff --git a/beacon_node/execution_layer/src/engine_api/new_payload_request.rs b/beacon_node/execution_layer/src/engine_api/new_payload_request.rs index 8d2e3d5ad06..cbbf2ddc8ff 100644 --- a/beacon_node/execution_layer/src/engine_api/new_payload_request.rs +++ b/beacon_node/execution_layer/src/engine_api/new_payload_request.rs @@ -9,11 +9,11 @@ use types::{ }; use types::{ ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, + ExecutionPayloadEip7594, ExecutionPayloadElectra, }; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes(derive(Clone, Debug, PartialEq),), map_into(ExecutionPayload), map_ref_into(ExecutionPayloadRef), @@ -39,9 +39,11 @@ pub struct NewPayloadRequest<'block, E: EthSpec> { pub execution_payload: &'block ExecutionPayloadDeneb, #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] pub execution_payload: &'block ExecutionPayloadElectra, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Eip7594), partial_getter(rename = "execution_payload_eip7594"))] + pub execution_payload: &'block ExecutionPayloadEip7594, + #[superstruct(only(Deneb, Electra, Eip7594))] pub versioned_hashes: Vec, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Deneb, Electra, Eip7594))] pub parent_beacon_block_root: Hash256, } @@ -52,6 +54,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Capella(payload) => payload.execution_payload.parent_hash, Self::Deneb(payload) => payload.execution_payload.parent_hash, Self::Electra(payload) => payload.execution_payload.parent_hash, + Self::Eip7594(payload) => payload.execution_payload.parent_hash, } } @@ -61,6 +64,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Capella(payload) => payload.execution_payload.block_hash, Self::Deneb(payload) => payload.execution_payload.block_hash, Self::Electra(payload) => payload.execution_payload.block_hash, + Self::Eip7594(payload) => payload.execution_payload.block_hash, } } @@ -70,6 +74,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Capella(payload) => payload.execution_payload.block_number, Self::Deneb(payload) => payload.execution_payload.block_number, Self::Electra(payload) => payload.execution_payload.block_number, + Self::Eip7594(payload) => payload.execution_payload.block_number, } } @@ -79,6 +84,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Capella(request) => ExecutionPayloadRef::Capella(request.execution_payload), Self::Deneb(request) => ExecutionPayloadRef::Deneb(request.execution_payload), Self::Electra(request) => ExecutionPayloadRef::Electra(request.execution_payload), + Self::Eip7594(request) => ExecutionPayloadRef::Eip7594(request.execution_payload), } } @@ -90,6 +96,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { Self::Capella(request) => ExecutionPayload::Capella(request.execution_payload.clone()), Self::Deneb(request) => ExecutionPayload::Deneb(request.execution_payload.clone()), Self::Electra(request) => ExecutionPayload::Electra(request.execution_payload.clone()), + Self::Eip7594(request) => ExecutionPayload::Eip7594(request.execution_payload.clone()), } } @@ -184,6 +191,16 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> .collect(), parent_beacon_block_root: block_ref.parent_root, })), + BeaconBlockRef::Eip7594(block_ref) => Ok(Self::Eip7594(NewPayloadRequestEip7594 { + execution_payload: &block_ref.body.execution_payload.execution_payload, + versioned_hashes: block_ref + .body + .blob_kzg_commitments + .iter() + .map(kzg_commitment_to_versioned_hash) + .collect(), + parent_beacon_block_root: block_ref.parent_root, + })), } } } @@ -203,6 +220,7 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<' })), ExecutionPayloadRef::Deneb(_) => Err(Self::Error::IncorrectStateVariant), ExecutionPayloadRef::Electra(_) => Err(Self::Error::IncorrectStateVariant), + ExecutionPayloadRef::Eip7594(_) => Err(Self::Error::IncorrectStateVariant), } } } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index d441596edda..648d57b4db2 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -47,7 +47,8 @@ use types::builder_bid::BuilderBid; use types::non_zero_usize::new_non_zero_usize; use types::payload::BlockProductionVersion; use types::{ - AbstractExecPayload, BlobsList, ExecutionPayloadDeneb, KzgProofs, SignedBlindedBeaconBlock, + AbstractExecPayload, BlobsList, ExecutionPayloadDeneb, ExecutionPayloadEip7594, KzgProofs, + SignedBlindedBeaconBlock, }; use types::{ BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix, @@ -118,6 +119,12 @@ impl TryFrom> for ProvenancedPayload BlockProposalContents::PayloadAndBlobs { + payload: ExecutionPayloadHeader::Eip7594(builder_bid.header).into(), + block_value: builder_bid.value, + kzg_commitments: builder_bid.blob_kzg_commitments, + blobs_and_proofs: None, + }, }; Ok(ProvenancedPayload::Builder( BlockProposalContentsType::Blinded(block_proposal_contents), @@ -1808,6 +1815,7 @@ impl ExecutionLayer { 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::InvalidForkForPayload); } @@ -1877,6 +1885,7 @@ impl ExecutionLayer { ForkName::Capella => Ok(Some(ExecutionPayloadCapella::default().into())), ForkName::Deneb => Ok(Some(ExecutionPayloadDeneb::default().into())), ForkName::Electra => Ok(Some(ExecutionPayloadElectra::default().into())), + ForkName::Eip7594 => Ok(Some(ExecutionPayloadEip7594::default().into())), ForkName::Base | ForkName::Altair => Err(ApiError::UnsupportedForkVariant( format!("called get_payload_by_hash_from_engine with {}", fork), )), @@ -2010,6 +2019,35 @@ impl ExecutionLayer { withdrawal_requests: <_>::default(), }) } + ExecutionBlockWithTransactions::Eip7594(eip7594_block) => { + let withdrawals = VariableList::new( + eip7594_block + .withdrawals + .into_iter() + .map(Into::into) + .collect(), + ) + .map_err(ApiError::DeserializeWithdrawals)?; + ExecutionPayload::Eip7594(ExecutionPayloadEip7594 { + parent_hash: eip7594_block.parent_hash, + fee_recipient: eip7594_block.fee_recipient, + state_root: eip7594_block.state_root, + receipts_root: eip7594_block.receipts_root, + logs_bloom: eip7594_block.logs_bloom, + prev_randao: eip7594_block.prev_randao, + block_number: eip7594_block.block_number, + gas_limit: eip7594_block.gas_limit, + gas_used: eip7594_block.gas_used, + timestamp: eip7594_block.timestamp, + extra_data: eip7594_block.extra_data, + base_fee_per_gas: eip7594_block.base_fee_per_gas, + block_hash: eip7594_block.block_hash, + transactions: convert_transactions(eip7594_block.transactions)?, + withdrawals, + blob_gas_used: eip7594_block.blob_gas_used, + excess_blob_gas: eip7594_block.excess_blob_gas, + }) + } }; Ok(Some(payload)) diff --git a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs index e80c6b23705..78ea17bf6cc 100644 --- a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs +++ b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs @@ -22,8 +22,9 @@ use tree_hash::TreeHash; use tree_hash_derive::TreeHash; use types::{ Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix, - ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, - ExecutionPayloadHeader, ForkName, Hash256, Transaction, Transactions, Uint256, + ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadEip7594, + ExecutionPayloadElectra, ExecutionPayloadHeader, ForkName, Hash256, Transaction, Transactions, + Uint256, }; use super::DEFAULT_TERMINAL_BLOCK; @@ -662,13 +663,32 @@ impl ExecutionBlockGenerator { deposit_receipts: vec![].into(), withdrawal_requests: vec![].into(), }), + ForkName::Eip7594 => ExecutionPayload::Eip7594(ExecutionPayloadEip7594 { + parent_hash: head_block_hash, + fee_recipient: pa.suggested_fee_recipient, + receipts_root: Hash256::repeat_byte(42), + state_root: Hash256::repeat_byte(43), + logs_bloom: vec![0; 256].into(), + prev_randao: pa.prev_randao, + block_number: parent.block_number() + 1, + gas_limit: GAS_LIMIT, + gas_used: GAS_USED, + timestamp: pa.timestamp, + extra_data: "block gen was here".as_bytes().to_vec().into(), + base_fee_per_gas: Uint256::one(), + block_hash: ExecutionBlockHash::zero(), + transactions: vec![].into(), + withdrawals: pa.withdrawals.clone().into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), _ => unreachable!(), }, }; match execution_payload.fork_name() { ForkName::Base | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella => {} - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { // get random number between 0 and Max Blobs let mut rng = self.rng.lock(); let num_blobs = rng.gen::() % (E::max_blobs_per_block() + 1); @@ -812,6 +832,12 @@ pub fn generate_genesis_header( *header.transactions_root_mut() = empty_transactions_root; Some(header) } + ForkName::Eip7594 => { + let mut header = ExecutionPayloadHeader::Eip7594(<_>::default()); + *header.block_hash_mut() = genesis_block_hash.unwrap_or_default(); + *header.transactions_root_mut() = empty_transactions_root; + Some(header) + } } } diff --git a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs index 1dc8f0ab83e..7ff2837877a 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -224,6 +224,32 @@ pub async fn handle_rpc( )); } } + ForkName::Eip7594 => { + if method == ENGINE_NEW_PAYLOAD_V1 || method == ENGINE_NEW_PAYLOAD_V2 { + return Err(( + format!("{} called after Eip7594 fork!", method), + GENERIC_ERROR_CODE, + )); + } + if matches!(request, JsonExecutionPayload::V1(_)) { + return Err(( + format!( + "{} called with `ExecutionPayloadV1` after Eip7594 fork!", + method + ), + GENERIC_ERROR_CODE, + )); + } + if matches!(request, JsonExecutionPayload::V2(_)) { + return Err(( + format!( + "{} called with `ExecutionPayloadV2` after Eip7594 fork!", + method + ), + GENERIC_ERROR_CODE, + )); + } + } _ => unreachable!(), }; @@ -400,7 +426,10 @@ pub async fn handle_rpc( .map(|opt| opt.map(JsonPayloadAttributes::V1)) .transpose() } - ForkName::Capella | ForkName::Deneb | ForkName::Electra => { + ForkName::Capella + | ForkName::Deneb + | ForkName::Electra + | ForkName::Eip7594 => { get_param::>(params, 1) .map(|opt| opt.map(JsonPayloadAttributes::V2)) .transpose() @@ -464,7 +493,7 @@ pub async fn handle_rpc( )); } } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { if method == ENGINE_FORKCHOICE_UPDATED_V1 { return Err(( format!("{} called after Deneb fork!", method), diff --git a/beacon_node/execution_layer/src/test_utils/mock_builder.rs b/beacon_node/execution_layer/src/test_utils/mock_builder.rs index c9ae1e60cdc..cfa295a6321 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -15,8 +15,8 @@ use task_executor::TaskExecutor; use tempfile::NamedTempFile; use tree_hash::TreeHash; use types::builder_bid::{ - BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidElectra, - SignedBuilderBid, + BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidEip7594, + BuilderBidElectra, SignedBuilderBid, }; use types::{ Address, BeaconState, ChainSpec, EthSpec, ExecPayload, ExecutionPayload, @@ -89,6 +89,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.fee_recipient = fee_recipient; } + ExecutionPayloadHeaderRefMut::Eip7594(header) => { + header.fee_recipient = fee_recipient; + } } } @@ -106,6 +109,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.gas_limit = gas_limit; } + ExecutionPayloadHeaderRefMut::Eip7594(header) => { + header.gas_limit = gas_limit; + } } } @@ -127,6 +133,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.parent_hash = ExecutionBlockHash::from_root(parent_hash); } + ExecutionPayloadHeaderRefMut::Eip7594(header) => { + header.parent_hash = ExecutionBlockHash::from_root(parent_hash); + } } } @@ -144,6 +153,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.prev_randao = prev_randao; } + ExecutionPayloadHeaderRefMut::Eip7594(header) => { + header.prev_randao = prev_randao; + } } } @@ -161,6 +173,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.block_number = block_number; } + ExecutionPayloadHeaderRefMut::Eip7594(header) => { + header.block_number = block_number; + } } } @@ -178,6 +193,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.timestamp = timestamp; } + ExecutionPayloadHeaderRefMut::Eip7594(header) => { + header.timestamp = timestamp; + } } } @@ -195,6 +213,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.withdrawals_root = withdrawals_root; } + ExecutionPayloadHeaderRefMut::Eip7594(header) => { + header.withdrawals_root = withdrawals_root; + } } } @@ -348,6 +369,9 @@ pub fn serve( SignedBlindedBeaconBlock::Electra(block) => { block.message.body.execution_payload.tree_hash_root() } + SignedBlindedBeaconBlock::Eip7594(block) => { + block.message.body.execution_payload.tree_hash_root() + } }; let payload = builder .el @@ -481,14 +505,16 @@ pub fn serve( .map_err(|_| reject("couldn't get prev randao"))?; let expected_withdrawals = match fork { ForkName::Base | ForkName::Altair | ForkName::Bellatrix => None, - ForkName::Capella | ForkName::Deneb | ForkName::Electra => Some( - builder - .beacon_client - .get_expected_withdrawals(&StateId::Head) - .await - .unwrap() - .data, - ), + ForkName::Capella | ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + Some( + builder + .beacon_client + .get_expected_withdrawals(&StateId::Head) + .await + .unwrap() + .data, + ) + } }; let payload_attributes = match fork { @@ -503,13 +529,15 @@ pub fn serve( expected_withdrawals, None, ), - ForkName::Deneb | ForkName::Electra => PayloadAttributes::new( - timestamp, - *prev_randao, - fee_recipient, - expected_withdrawals, - Some(head_block_root), - ), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + PayloadAttributes::new( + timestamp, + *prev_randao, + fee_recipient, + expected_withdrawals, + Some(head_block_root), + ) + } ForkName::Base | ForkName::Altair => { return Err(reject("invalid fork")); } @@ -558,6 +586,17 @@ pub fn serve( value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI), pubkey: builder.builder_sk.public_key().compress(), }), + ForkName::Eip7594 => BuilderBid::Eip7594(BuilderBidEip7594 { + header: payload + .as_eip7594() + .map_err(|_| reject("incorrect payload variant"))? + .into(), + blob_kzg_commitments: maybe_blobs_bundle + .map(|b| b.commitments) + .unwrap_or_default(), + value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI), + pubkey: builder.builder_sk.public_key().compress(), + }), ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb { header: payload .as_deneb() @@ -608,6 +647,17 @@ pub fn serve( value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI), pubkey: builder.builder_sk.public_key().compress(), }), + ForkName::Eip7594 => BuilderBid::Eip7594(BuilderBidEip7594 { + header: payload + .as_eip7594() + .map_err(|_| reject("incorrect payload variant"))? + .into(), + blob_kzg_commitments: maybe_blobs_bundle + .map(|b| b.commitments) + .unwrap_or_default(), + value: Uint256::from(DEFAULT_BUILDER_PAYLOAD_VALUE_WEI), + pubkey: builder.builder_sk.public_key().compress(), + }), ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb { header: payload .as_deneb() diff --git a/beacon_node/http_api/src/build_block_contents.rs b/beacon_node/http_api/src/build_block_contents.rs index 05a6735b327..7d6a0b63d50 100644 --- a/beacon_node/http_api/src/build_block_contents.rs +++ b/beacon_node/http_api/src/build_block_contents.rs @@ -15,7 +15,7 @@ pub fn build_block_contents( ForkName::Base | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella => Ok( ProduceBlockV3Response::Full(FullBlockContents::Block(block.block)), ), - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { let BeaconBlockResponse { block, state: _, diff --git a/beacon_node/http_api/src/publish_blocks.rs b/beacon_node/http_api/src/publish_blocks.rs index 067136919e7..6b8b5a9e3ee 100644 --- a/beacon_node/http_api/src/publish_blocks.rs +++ b/beacon_node/http_api/src/publish_blocks.rs @@ -105,7 +105,9 @@ pub async fn publish_block { + SignedBeaconBlock::Deneb(_) + | SignedBeaconBlock::Electra(_) + | SignedBeaconBlock::Eip7594(_) => { let mut pubsub_messages = vec![PubsubMessage::BeaconBlock(block)]; if let Some(blob_sidecars) = blobs_opt { // Publish blob sidecars diff --git a/beacon_node/lighthouse_network/src/config.rs b/beacon_node/lighthouse_network/src/config.rs index 30f35064586..d97c558ac9c 100644 --- a/beacon_node/lighthouse_network/src/config.rs +++ b/beacon_node/lighthouse_network/src/config.rs @@ -445,7 +445,8 @@ pub fn gossipsub_config( | ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb - | ForkName::Electra => { + | ForkName::Electra + | ForkName::Eip7594 => { let topic_len_bytes = topic_bytes.len().to_le_bytes(); let mut vec = Vec::with_capacity( prefix.len() + topic_len_bytes.len() + topic_bytes.len() + message.data.len(), diff --git a/beacon_node/lighthouse_network/src/rpc/codec/base.rs b/beacon_node/lighthouse_network/src/rpc/codec/base.rs index 42a31d3480a..023c38accbc 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec/base.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec/base.rs @@ -188,12 +188,14 @@ mod tests { let capella_fork_epoch = Epoch::new(3); let deneb_fork_epoch = Epoch::new(4); let electra_fork_epoch = Epoch::new(5); + let eip7594_fork_epoch = Epoch::new(6); chain_spec.altair_fork_epoch = Some(altair_fork_epoch); chain_spec.bellatrix_fork_epoch = Some(bellatrix_fork_epoch); chain_spec.capella_fork_epoch = Some(capella_fork_epoch); chain_spec.deneb_fork_epoch = Some(deneb_fork_epoch); chain_spec.electra_fork_epoch = Some(electra_fork_epoch); + chain_spec.eip7594_fork_epoch = Some(eip7594_fork_epoch); let current_slot = match fork_name { ForkName::Base => Slot::new(0), @@ -202,6 +204,7 @@ mod tests { ForkName::Capella => capella_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Deneb => deneb_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Electra => electra_fork_epoch.start_slot(Spec::slots_per_epoch()), + ForkName::Eip7594 => eip7594_fork_epoch.start_slot(Spec::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) } diff --git a/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs b/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs index e0f14ee1401..eb01830c39b 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec/ssz_snappy.rs @@ -20,7 +20,7 @@ use types::{ LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate, RuntimeVariableList, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, SignedBeaconBlockDeneb, - SignedBeaconBlockElectra, + SignedBeaconBlockEip7594, SignedBeaconBlockElectra, }; use unsigned_varint::codec::Uvi; @@ -397,6 +397,9 @@ fn context_bytes( return match **ref_box_block { // NOTE: If you are adding another fork type here, be sure to modify the // `fork_context.to_context_bytes()` function to support it as well! + SignedBeaconBlock::Eip7594 { .. } => { + fork_context.to_context_bytes(ForkName::Eip7594) + } SignedBeaconBlock::Electra { .. } => { fork_context.to_context_bytes(ForkName::Electra) } @@ -421,6 +424,7 @@ fn context_bytes( | RPCResponse::BlobsByRoot(_) | RPCResponse::DataColumnsByRoot(_) => { // TODO(electra) + // TODO(das) return fork_context.to_context_bytes(ForkName::Deneb); } RPCResponse::LightClientBootstrap(lc_bootstrap) => { @@ -707,6 +711,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::Eip7594) => Ok(Some(RPCResponse::BlocksByRange(Arc::new( + SignedBeaconBlock::Eip7594(SignedBeaconBlockEip7594::from_ssz_bytes( + decoded_buffer, + )?), + )))), None => Err(RPCError::ErrorResponse( RPCResponseErrorCode::InvalidRequest, format!( @@ -740,6 +749,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::Eip7594) => Ok(Some(RPCResponse::BlocksByRoot(Arc::new( + SignedBeaconBlock::Eip7594(SignedBeaconBlockEip7594::from_ssz_bytes( + decoded_buffer, + )?), + )))), None => Err(RPCError::ErrorResponse( RPCResponseErrorCode::InvalidRequest, format!( @@ -790,12 +804,14 @@ mod tests { let capella_fork_epoch = Epoch::new(3); let deneb_fork_epoch = Epoch::new(4); let electra_fork_epoch = Epoch::new(5); + let eip7594_fork_epoch = Epoch::new(6); chain_spec.altair_fork_epoch = Some(altair_fork_epoch); chain_spec.bellatrix_fork_epoch = Some(bellatrix_fork_epoch); chain_spec.capella_fork_epoch = Some(capella_fork_epoch); chain_spec.deneb_fork_epoch = Some(deneb_fork_epoch); chain_spec.electra_fork_epoch = Some(electra_fork_epoch); + chain_spec.eip7594_fork_epoch = Some(eip7594_fork_epoch); let current_slot = match fork_name { ForkName::Base => Slot::new(0), @@ -804,6 +820,7 @@ mod tests { ForkName::Capella => capella_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Deneb => deneb_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Electra => electra_fork_epoch.start_slot(Spec::slots_per_epoch()), + ForkName::Eip7594 => eip7594_fork_epoch.start_slot(Spec::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) } diff --git a/beacon_node/lighthouse_network/src/rpc/protocol.rs b/beacon_node/lighthouse_network/src/rpc/protocol.rs index 946db6459e7..8b63f7e781b 100644 --- a/beacon_node/lighthouse_network/src/rpc/protocol.rs +++ b/beacon_node/lighthouse_network/src/rpc/protocol.rs @@ -93,7 +93,14 @@ lazy_static! { + ssz::BYTES_PER_LENGTH_OFFSET // Adding the additional offsets for the `ExecutionPayload` + (::ssz_fixed_len() * ::max_blobs_per_block()) + ssz::BYTES_PER_LENGTH_OFFSET; // Length offset for the blob commitments field. - // + + // TODO(das): update blob count + pub static ref SIGNED_BEACON_BLOCK_EIP7594_MAX: usize = *SIGNED_BEACON_BLOCK_CAPELLA_MAX_WITHOUT_PAYLOAD + + types::ExecutionPayload::::max_execution_payload_eip7594_size() // adding max size of execution payload (~16gb) + + ssz::BYTES_PER_LENGTH_OFFSET // Adding the additional offsets for the `ExecutionPayload` + + (::ssz_fixed_len() * ::max_blobs_per_block()) + + ssz::BYTES_PER_LENGTH_OFFSET; // Length offset for the blob commitments field. + pub static ref SIGNED_BEACON_BLOCK_ELECTRA_MAX: usize = *SIGNED_BEACON_BLOCK_ELECTRA_MAX_WITHOUT_PAYLOAD + types::ExecutionPayload::::max_execution_payload_electra_size() // adding max size of execution payload (~16gb) + ssz::BYTES_PER_LENGTH_OFFSET // Adding the additional ssz offset for the `ExecutionPayload` field @@ -115,13 +122,16 @@ lazy_static! { pub static ref LIGHT_CLIENT_FINALITY_UPDATE_CAPELLA_MAX: usize = LightClientFinalityUpdate::::ssz_max_len_for_fork(ForkName::Capella); pub static ref LIGHT_CLIENT_FINALITY_UPDATE_DENEB_MAX: usize = LightClientFinalityUpdate::::ssz_max_len_for_fork(ForkName::Deneb); - pub static ref LIGHT_CLIENT_FINALITY_UPDATE_ELECTRA_MAX: usize = LightClientFinalityUpdate::::ssz_max_len_for_fork(ForkName::Electra); + pub static ref LIGHT_CLIENT_FINALITY_UPDATE_EIP7594_MAX: usize = LightClientFinalityUpdate::::ssz_max_len_for_fork(ForkName::Electra); + pub static ref LIGHT_CLIENT_FINALITY_UPDATE_ELECTRA_MAX: usize = LightClientFinalityUpdate::::ssz_max_len_for_fork(ForkName::Eip7594); pub static ref LIGHT_CLIENT_OPTIMISTIC_UPDATE_CAPELLA_MAX: usize = LightClientOptimisticUpdate::::ssz_max_len_for_fork(ForkName::Capella); pub static ref LIGHT_CLIENT_OPTIMISTIC_UPDATE_DENEB_MAX: usize = LightClientOptimisticUpdate::::ssz_max_len_for_fork(ForkName::Deneb); pub static ref LIGHT_CLIENT_OPTIMISTIC_UPDATE_ELECTRA_MAX: usize = LightClientOptimisticUpdate::::ssz_max_len_for_fork(ForkName::Electra); + pub static ref LIGHT_CLIENT_OPTIMISTIC_UPDATE_EIP7594_MAX: usize = LightClientOptimisticUpdate::::ssz_max_len_for_fork(ForkName::Eip7594); pub static ref LIGHT_CLIENT_BOOTSTRAP_CAPELLA_MAX: usize = LightClientBootstrap::::ssz_max_len_for_fork(ForkName::Capella); pub static ref LIGHT_CLIENT_BOOTSTRAP_DENEB_MAX: usize = LightClientBootstrap::::ssz_max_len_for_fork(ForkName::Deneb); pub static ref LIGHT_CLIENT_BOOTSTRAP_ELECTRA_MAX: usize = LightClientBootstrap::::ssz_max_len_for_fork(ForkName::Electra); + pub static ref LIGHT_CLIENT_BOOTSTRAP_EIP7594_MAX: usize = LightClientBootstrap::::ssz_max_len_for_fork(ForkName::Eip7594); } /// The protocol prefix the RPC protocol id. @@ -138,6 +148,7 @@ pub fn max_rpc_size(fork_context: &ForkContext, max_chunk_size: usize) -> usize ForkName::Capella => max_chunk_size, ForkName::Deneb => max_chunk_size, ForkName::Electra => max_chunk_size, + ForkName::Eip7594 => max_chunk_size, } } @@ -170,6 +181,10 @@ pub fn rpc_block_limits_by_fork(current_fork: ForkName) -> RpcLimits { *SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and bellatrix blocks *SIGNED_BEACON_BLOCK_ELECTRA_MAX, // Electra block is larger than Deneb block ), + ForkName::Eip7594 => RpcLimits::new( + *SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and bellatrix blocks + *SIGNED_BEACON_BLOCK_EIP7594_MAX, // Eip7594 block is larger than all prior fork blocks + ), } } @@ -190,6 +205,9 @@ fn rpc_light_client_finality_update_limits_by_fork(current_fork: ForkName) -> Rp ForkName::Electra => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_ELECTRA_MAX) } + ForkName::Eip7594 => { + RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_EIP7594_MAX) + } } } @@ -212,6 +230,10 @@ fn rpc_light_client_optimistic_update_limits_by_fork(current_fork: ForkName) -> altair_fixed_len, *LIGHT_CLIENT_OPTIMISTIC_UPDATE_ELECTRA_MAX, ), + ForkName::Eip7594 => RpcLimits::new( + altair_fixed_len, + *LIGHT_CLIENT_OPTIMISTIC_UPDATE_EIP7594_MAX, + ), } } @@ -226,6 +248,7 @@ fn rpc_light_client_bootstrap_limits_by_fork(current_fork: ForkName) -> RpcLimit ForkName::Capella => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_CAPELLA_MAX), ForkName::Deneb => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_DENEB_MAX), ForkName::Electra => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_ELECTRA_MAX), + ForkName::Eip7594 => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_EIP7594_MAX), } } diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index 8a2fb58240c..fa5f140cf3a 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -11,8 +11,9 @@ use types::{ ForkContext, ForkName, LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing, SignedAggregateAndProof, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, - SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBlsToExecutionChange, - SignedContributionAndProof, SignedVoluntaryExit, SubnetId, SyncCommitteeMessage, SyncSubnetId, + SignedBeaconBlockDeneb, SignedBeaconBlockEip7594, SignedBeaconBlockElectra, + SignedBlsToExecutionChange, SignedContributionAndProof, SignedVoluntaryExit, SubnetId, + SyncCommitteeMessage, SyncSubnetId, }; #[derive(Debug, Clone, PartialEq)] @@ -200,6 +201,10 @@ impl PubsubMessage { SignedBeaconBlockElectra::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, ), + Some(ForkName::Eip7594) => SignedBeaconBlock::::Eip7594( + SignedBeaconBlockEip7594::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?, + ), None => { return Err(format!( "Unknown gossipsub fork digest: {:?}", @@ -211,7 +216,7 @@ impl PubsubMessage { } GossipKind::BlobSidecar(blob_index) => { match fork_context.from_context_bytes(gossip_topic.fork_digest) { - Some(ForkName::Deneb | ForkName::Electra) => { + Some(ForkName::Deneb | ForkName::Electra | ForkName::Eip7594) => { let blob_sidecar = Arc::new( BlobSidecar::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, @@ -235,7 +240,7 @@ impl PubsubMessage { } GossipKind::DataColumnSidecar(subnet_id) => { match fork_context.from_context_bytes(gossip_topic.fork_digest) { - Some(ForkName::Deneb | ForkName::Electra) => { + Some(ForkName::Deneb | ForkName::Electra | ForkName::Eip7594) => { let col_sidecar = Arc::new( DataColumnSidecar::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, diff --git a/beacon_node/lighthouse_network/src/types/topics.rs b/beacon_node/lighthouse_network/src/types/topics.rs index 174787f999c..6d78956b49b 100644 --- a/beacon_node/lighthouse_network/src/types/topics.rs +++ b/beacon_node/lighthouse_network/src/types/topics.rs @@ -61,6 +61,7 @@ pub fn fork_core_topics(fork_name: &ForkName, spec: &ChainSpec) -> V deneb_topics } ForkName::Electra => vec![], + ForkName::Eip7594 => vec![], } } diff --git a/beacon_node/lighthouse_network/tests/common.rs b/beacon_node/lighthouse_network/tests/common.rs index 32e3a034666..70a4988723b 100644 --- a/beacon_node/lighthouse_network/tests/common.rs +++ b/beacon_node/lighthouse_network/tests/common.rs @@ -25,12 +25,14 @@ pub fn fork_context(fork_name: ForkName) -> ForkContext { let capella_fork_epoch = Epoch::new(3); let deneb_fork_epoch = Epoch::new(4); let electra_fork_epoch = Epoch::new(5); + let eip7594_fork_epoch = Epoch::new(6); chain_spec.altair_fork_epoch = Some(altair_fork_epoch); chain_spec.bellatrix_fork_epoch = Some(bellatrix_fork_epoch); chain_spec.capella_fork_epoch = Some(capella_fork_epoch); chain_spec.deneb_fork_epoch = Some(deneb_fork_epoch); chain_spec.electra_fork_epoch = Some(electra_fork_epoch); + chain_spec.eip7594_fork_epoch = Some(eip7594_fork_epoch); let current_slot = match fork_name { ForkName::Base => Slot::new(0), @@ -39,6 +41,7 @@ pub fn fork_context(fork_name: ForkName) -> ForkContext { ForkName::Capella => capella_fork_epoch.start_slot(E::slots_per_epoch()), ForkName::Deneb => deneb_fork_epoch.start_slot(E::slots_per_epoch()), ForkName::Electra => electra_fork_epoch.start_slot(E::slots_per_epoch()), + ForkName::Eip7594 => eip7594_fork_epoch.start_slot(E::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) } diff --git a/beacon_node/network/src/network_beacon_processor/rpc_methods.rs b/beacon_node/network/src/network_beacon_processor/rpc_methods.rs index 065a6797e29..beb8881b807 100644 --- a/beacon_node/network/src/network_beacon_processor/rpc_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/rpc_methods.rs @@ -549,7 +549,7 @@ impl NetworkBeaconProcessor { .epoch() .map_or(self.chain.spec.max_request_blocks, |epoch| { match self.chain.spec.fork_name_at_epoch(epoch) { - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { self.chain.spec.max_request_blocks_deneb } ForkName::Base diff --git a/beacon_node/network/src/sync/range_sync/range.rs b/beacon_node/network/src/sync/range_sync/range.rs index fe48db35b45..f6c03d2893b 100644 --- a/beacon_node/network/src/sync/range_sync/range.rs +++ b/beacon_node/network/src/sync/range_sync/range.rs @@ -529,7 +529,7 @@ mod tests { panic!("Should have sent a batch request to the peer") }; let blob_req_id = match fork_name { - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { if let Ok(NetworkMessage::SendRequest { peer_id, request: _, diff --git a/beacon_node/store/src/impls/execution_payload.rs b/beacon_node/store/src/impls/execution_payload.rs index 14fc10ad6de..6f798b9437d 100644 --- a/beacon_node/store/src/impls/execution_payload.rs +++ b/beacon_node/store/src/impls/execution_payload.rs @@ -2,7 +2,7 @@ use crate::{DBColumn, Error, StoreItem}; use ssz::{Decode, Encode}; use types::{ BlobSidecarList, EthSpec, ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, - ExecutionPayloadDeneb, ExecutionPayloadElectra, + ExecutionPayloadDeneb, ExecutionPayloadEip7594, ExecutionPayloadElectra, }; macro_rules! impl_store_item { @@ -26,6 +26,7 @@ impl_store_item!(ExecutionPayloadBellatrix); impl_store_item!(ExecutionPayloadCapella); impl_store_item!(ExecutionPayloadDeneb); impl_store_item!(ExecutionPayloadElectra); +impl_store_item!(ExecutionPayloadEip7594); impl_store_item!(BlobSidecarList); /// This fork-agnostic implementation should be only used for writing. diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index e56d0580ac2..5e8632f4f0c 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -14,7 +14,7 @@ use types::*; /// /// Utilises lazy-loading from separate storage for its vector fields. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes(derive(Debug, PartialEq, Clone, Encode, Decode)) )] #[derive(Debug, PartialEq, Clone, Encode)] @@ -66,9 +66,9 @@ where pub current_epoch_attestations: List, E::MaxPendingAttestations>, // Participation (Altair and later) - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] pub current_epoch_participation: List, // Finality @@ -78,13 +78,13 @@ where pub finalized_checkpoint: Checkpoint, // Inactivity - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] pub inactivity_scores: List, // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] pub next_sync_committee: Arc>, // Execution @@ -108,15 +108,20 @@ where partial_getter(rename = "latest_execution_payload_header_electra") )] pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, + #[superstruct( + only(Eip7594), + partial_getter(rename = "latest_execution_payload_header_eip7594") + )] + pub latest_execution_payload_header: ExecutionPayloadHeaderEip7594, // Capella - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] pub next_withdrawal_validator_index: u64, #[ssz(skip_serializing, skip_deserializing)] - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] pub historical_summaries: Option>, // Electra @@ -297,6 +302,23 @@ impl PartialBeaconState { ], [historical_summaries] ), + BeaconState::Eip7594(s) => impl_from_state_forgetful!( + s, + outer, + Eip7594, + PartialBeaconStateEip7594, + [ + previous_epoch_participation, + current_epoch_participation, + current_sync_committee, + next_sync_committee, + inactivity_scores, + latest_execution_payload_header, + next_withdrawal_index, + next_withdrawal_validator_index + ], + [historical_summaries] + ), } } @@ -570,6 +592,22 @@ impl TryInto> for PartialBeaconState { ], [historical_summaries] ), + PartialBeaconState::Eip7594(inner) => impl_try_into_beacon_state!( + inner, + Eip7594, + BeaconStateEip7594, + [ + previous_epoch_participation, + current_epoch_participation, + current_sync_committee, + next_sync_committee, + inactivity_scores, + latest_execution_payload_header, + next_withdrawal_index, + next_withdrawal_validator_index + ], + [historical_summaries] + ), }; Ok(state) } diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index b15246e7fdb..212edb498b0 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -1035,6 +1035,9 @@ impl ForkVersionDeserialize for SsePayloadAttributes { ForkName::Electra => serde_json::from_value(value) .map(Self::V3) .map_err(serde::de::Error::custom), + ForkName::Eip7594 => serde_json::from_value(value) + .map(Self::V3) + .map_err(serde::de::Error::custom), ForkName::Base | ForkName::Altair => Err(serde::de::Error::custom(format!( "SsePayloadAttributes deserialization for {fork_name} not implemented" ))), @@ -1622,7 +1625,7 @@ impl FullBlockContents { BeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name) .map(|block| FullBlockContents::Block(block)) } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { let mut builder = ssz::SszDecoderBuilder::new(bytes); builder.register_anonymous_variable_length_item()?; @@ -1683,9 +1686,11 @@ impl ForkVersionDeserialize for FullBlockContents { BeaconBlock::deserialize_by_fork::<'de, D>(value, fork_name)?, )) } - ForkName::Deneb | ForkName::Electra => Ok(FullBlockContents::BlockContents( - BlockContents::deserialize_by_fork::<'de, D>(value, fork_name)?, - )), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + Ok(FullBlockContents::BlockContents( + BlockContents::deserialize_by_fork::<'de, D>(value, fork_name)?, + )) + } } } } @@ -1782,7 +1787,7 @@ impl PublishBlockRequest { SignedBeaconBlock::from_ssz_bytes_for_fork(bytes, fork_name) .map(|block| PublishBlockRequest::Block(Arc::new(block))) } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { let mut builder = ssz::SszDecoderBuilder::new(bytes); builder.register_anonymous_variable_length_item()?; builder.register_type::>()?; @@ -1866,7 +1871,9 @@ impl TryFrom>> for PublishBlockRequest { | SignedBeaconBlock::Altair(_) | SignedBeaconBlock::Bellatrix(_) | SignedBeaconBlock::Capella(_) => Ok(PublishBlockRequest::Block(block)), - SignedBeaconBlock::Deneb(_) | SignedBeaconBlock::Electra(_) => Err( + SignedBeaconBlock::Deneb(_) + | SignedBeaconBlock::Electra(_) + | SignedBeaconBlock::Eip7594(_) => Err( "post-Deneb block contents cannot be fully constructed from just the signed block", ), } @@ -1976,9 +1983,11 @@ impl ForkVersionDeserialize for FullPayloadContents { ForkName::Bellatrix | ForkName::Capella => serde_json::from_value(value) .map(Self::Payload) .map_err(serde::de::Error::custom), - ForkName::Deneb | ForkName::Electra => serde_json::from_value(value) - .map(Self::PayloadAndBlobs) - .map_err(serde::de::Error::custom), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + serde_json::from_value(value) + .map(Self::PayloadAndBlobs) + .map_err(serde::de::Error::custom) + } ForkName::Base | ForkName::Altair => Err(serde::de::Error::custom(format!( "FullPayloadContents deserialization for {fork_name} not implemented" ))), diff --git a/common/eth2_network_config/built_in_network_configs/chiado/config.yaml b/common/eth2_network_config/built_in_network_configs/chiado/config.yaml index c869d9cfc83..1cc670bd7bd 100644 --- a/common/eth2_network_config/built_in_network_configs/chiado/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/chiado/config.yaml @@ -49,6 +49,9 @@ DENEB_FORK_EPOCH: 516608 # Wed Jan 31 2024 18:15:40 GMT+0000 # Electra ELECTRA_FORK_VERSION: 0x0500006f ELECTRA_FORK_EPOCH: 18446744073709551615 +# Eip7594 +EIP7594_FORK_VERSION: 0x0600006f +EIP7594_FORK_EPOCH: 18446744073709551615 # Time parameters # --------------------------------------------------------------- diff --git a/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml b/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml index 50a5fcc3a50..b439d075ef8 100644 --- a/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/gnosis/config.yaml @@ -45,7 +45,9 @@ DENEB_FORK_EPOCH: 889856 # 2024-03-11T18:30:20.000Z # Electra ELECTRA_FORK_VERSION: 0x05000064 ELECTRA_FORK_EPOCH: 18446744073709551615 - +# Eip7594 +EIP7594_FORK_VERSION: 0x06000064 +EIP7594_FORK_EPOCH: 18446744073709551615 # Time parameters # --------------------------------------------------------------- diff --git a/common/eth2_network_config/built_in_network_configs/holesky/config.yaml b/common/eth2_network_config/built_in_network_configs/holesky/config.yaml index 6a399b957d2..400eda77051 100644 --- a/common/eth2_network_config/built_in_network_configs/holesky/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/holesky/config.yaml @@ -37,6 +37,9 @@ DENEB_FORK_EPOCH: 29696 # Electra ELECTRA_FORK_VERSION: 0x06017000 ELECTRA_FORK_EPOCH: 18446744073709551615 +# Eip7594 +EIP7594_FORK_VERSION: 0x07017000 +EIP7594_FORK_EPOCH: 18446744073709551615 # Time parameters # --------------------------------------------------------------- diff --git a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml index 8c3d71d6748..0ca0382c68e 100644 --- a/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml +++ b/common/eth2_network_config/built_in_network_configs/mainnet/config.yaml @@ -53,9 +53,11 @@ DENEB_FORK_EPOCH: 269568 # March 13, 2024, 01:55:35pm UTC # Electra ELECTRA_FORK_VERSION: 0x05000000 ELECTRA_FORK_EPOCH: 18446744073709551615 -# PeerDAS +# PeerDAS TODO(das): remove PEER_DAS_EPOCH: 18446744073709551615 - +# Eip7594 +EIP7594_FORK_VERSION: 0x06000000 +EIP7594_FORK_EPOCH: 18446744073709551615 # Time parameters # --------------------------------------------------------------- diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index 2846a0112cd..6a366df39d0 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -748,7 +748,8 @@ where (parent_justified, parent_finalized) } else { let justification_and_finalization_state = match block { - BeaconBlockRef::Electra(_) + BeaconBlockRef::Eip7594(_) + | BeaconBlockRef::Electra(_) | BeaconBlockRef::Deneb(_) | BeaconBlockRef::Capella(_) | BeaconBlockRef::Bellatrix(_) diff --git a/consensus/state_processing/src/common/get_attestation_participation.rs b/consensus/state_processing/src/common/get_attestation_participation.rs index fc09dad1f4e..4f8e4ce9d34 100644 --- a/consensus/state_processing/src/common/get_attestation_participation.rs +++ b/consensus/state_processing/src/common/get_attestation_participation.rs @@ -53,7 +53,7 @@ pub fn get_attestation_participation_flag_indices( participation_flag_indices.push(TIMELY_TARGET_FLAG_INDEX); } } - &BeaconState::Deneb(_) | &BeaconState::Electra(_) => { + &BeaconState::Deneb(_) | &BeaconState::Electra(_) | &BeaconState::Eip7594(_) => { if is_matching_target { // [Modified in Deneb:EIP7045] participation_flag_indices.push(TIMELY_TARGET_FLAG_INDEX); diff --git a/consensus/state_processing/src/common/slash_validator.rs b/consensus/state_processing/src/common/slash_validator.rs index 520b58a8af3..c64a90d8c5a 100644 --- a/consensus/state_processing/src/common/slash_validator.rs +++ b/consensus/state_processing/src/common/slash_validator.rs @@ -61,7 +61,8 @@ pub fn slash_validator( | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => whistleblower_reward + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => whistleblower_reward .safe_mul(PROPOSER_WEIGHT)? .safe_div(WEIGHT_DENOMINATOR)?, }; diff --git a/consensus/state_processing/src/genesis.rs b/consensus/state_processing/src/genesis.rs index a84f359389c..e4da9c5f87a 100644 --- a/consensus/state_processing/src/genesis.rs +++ b/consensus/state_processing/src/genesis.rs @@ -4,7 +4,7 @@ use super::per_block_processing::{ use crate::common::DepositDataTree; use crate::upgrade::{ upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_deneb, - upgrade_to_electra, + upgrade_to_eip7594, upgrade_to_electra, }; use safe_arith::{ArithError, SafeArith}; use tree_hash::TreeHash; @@ -122,11 +122,28 @@ pub fn initialize_beacon_state_from_eth1( // Override latest execution payload header. // See https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#testing - if let Some(ExecutionPayloadHeader::Electra(header)) = execution_payload_header { + if let Some(ExecutionPayloadHeader::Electra(ref header)) = execution_payload_header { *state.latest_execution_payload_header_electra_mut()? = header.clone(); } } + // Upgrade to eip7594 if configured from genesis. + if spec + .eip7594_fork_epoch + .map_or(false, |fork_epoch| fork_epoch == E::genesis_epoch()) + { + upgrade_to_eip7594(&mut state, spec)?; + + // Remove intermediate Deneb fork from `state.fork`. + state.fork_mut().previous_version = spec.eip7594_fork_version; + + // Override latest execution payload header. + // See https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#testing + if let Some(ExecutionPayloadHeader::Eip7594(ref header)) = execution_payload_header { + *state.latest_execution_payload_header_eip7594_mut()? = header.clone(); + } + } + // Now that we have our validators, initialize the caches (including the committees) state.build_caches(spec)?; diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index 98671f82b9f..ffb7b435ac8 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -442,6 +442,12 @@ pub fn process_execution_payload>( _ => return Err(BlockProcessingError::IncorrectStateType), } } + ExecutionPayloadHeaderRefMut::Eip7594(header_mut) => { + match payload.to_execution_payload_header() { + ExecutionPayloadHeader::Eip7594(header) => *header_mut = header, + _ => return Err(BlockProcessingError::IncorrectStateType), + } + } } Ok(()) @@ -460,7 +466,10 @@ pub fn is_merge_transition_complete(state: &BeaconState) -> bool .latest_execution_payload_header() .map(|header| !header.is_default_with_zero_roots()) .unwrap_or(false), - BeaconState::Electra(_) | BeaconState::Deneb(_) | BeaconState::Capella(_) => true, + BeaconState::Electra(_) + | BeaconState::Deneb(_) + | BeaconState::Capella(_) + | BeaconState::Eip7594(_) => true, BeaconState::Base(_) | BeaconState::Altair(_) => false, } } @@ -559,7 +568,10 @@ pub fn process_withdrawals>( ) -> Result<(), BlockProcessingError> { match state { BeaconState::Bellatrix(_) => Ok(()), - BeaconState::Capella(_) | BeaconState::Deneb(_) | BeaconState::Electra(_) => { + BeaconState::Capella(_) + | BeaconState::Deneb(_) + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => { let expected_withdrawals = get_expected_withdrawals(state, spec)?; let expected_root = expected_withdrawals.tree_hash_root(); let withdrawals_root = payload.withdrawals_root()?; diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index 3aefcf8a9c5..768ea38aa99 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -276,7 +276,8 @@ pub fn process_attestations>( | BeaconBlockBodyRef::Bellatrix(_) | BeaconBlockBodyRef::Capella(_) | BeaconBlockBodyRef::Deneb(_) - | BeaconBlockBodyRef::Electra(_) => { + | BeaconBlockBodyRef::Electra(_) + | BeaconBlockBodyRef::Eip7594(_) => { altair_deneb::process_attestations( state, block_body.attestations(), diff --git a/consensus/state_processing/src/per_block_processing/signature_sets.rs b/consensus/state_processing/src/per_block_processing/signature_sets.rs index 9468893f762..5ee6b6ba0df 100644 --- a/consensus/state_processing/src/per_block_processing/signature_sets.rs +++ b/consensus/state_processing/src/per_block_processing/signature_sets.rs @@ -398,11 +398,12 @@ where state.genesis_validators_root(), ), // EIP-7044 - BeaconState::Deneb(_) | BeaconState::Electra(_) => spec.compute_domain( - Domain::VoluntaryExit, - spec.capella_fork_version, - state.genesis_validators_root(), - ), + BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::Eip7594(_) => spec + .compute_domain( + Domain::VoluntaryExit, + spec.capella_fork_version, + state.genesis_validators_root(), + ), }; let message = exit.signing_root(domain); diff --git a/consensus/state_processing/src/per_block_processing/verify_attestation.rs b/consensus/state_processing/src/per_block_processing/verify_attestation.rs index c904ba55f0a..ecb725d3dee 100644 --- a/consensus/state_processing/src/per_block_processing/verify_attestation.rs +++ b/consensus/state_processing/src/per_block_processing/verify_attestation.rs @@ -46,7 +46,7 @@ pub fn verify_attestation_for_block_inclusion<'ctxt, E: EthSpec>( ); } // [Modified in Deneb:EIP7045] - BeaconState::Deneb(_) | BeaconState::Electra(_) => {} + BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::Eip7594(_) => {} } verify_attestation_for_state(state, attestation, ctxt, verify_signatures, spec) diff --git a/consensus/state_processing/src/per_epoch_processing.rs b/consensus/state_processing/src/per_epoch_processing.rs index 55e8853f3f8..d01aa1c022f 100644 --- a/consensus/state_processing/src/per_epoch_processing.rs +++ b/consensus/state_processing/src/per_epoch_processing.rs @@ -47,7 +47,8 @@ pub fn process_epoch( | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_epoch(state, spec), + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => altair::process_epoch(state, spec), } } diff --git a/consensus/state_processing/src/per_slot_processing.rs b/consensus/state_processing/src/per_slot_processing.rs index 6554423199f..c03e59c6475 100644 --- a/consensus/state_processing/src/per_slot_processing.rs +++ b/consensus/state_processing/src/per_slot_processing.rs @@ -1,6 +1,6 @@ use crate::upgrade::{ upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_deneb, - upgrade_to_electra, + upgrade_to_eip7594, upgrade_to_electra, }; use crate::{per_epoch_processing::EpochProcessingSummary, *}; use safe_arith::{ArithError, SafeArith}; @@ -70,6 +70,10 @@ pub fn per_slot_processing( if spec.electra_fork_epoch == Some(state.current_epoch()) { upgrade_to_electra(state, spec)?; } + // Eip7594. + if spec.eip7594_fork_epoch == Some(state.current_epoch()) { + upgrade_to_eip7594(state, spec)?; + } // Additionally build all caches so that all valid states that are advanced always have // committee caches built, and we don't have to worry about initialising them at higher diff --git a/consensus/state_processing/src/upgrade.rs b/consensus/state_processing/src/upgrade.rs index 93cafa73d03..d6a2dd3601a 100644 --- a/consensus/state_processing/src/upgrade.rs +++ b/consensus/state_processing/src/upgrade.rs @@ -2,10 +2,12 @@ pub mod altair; pub mod bellatrix; pub mod capella; pub mod deneb; +pub mod eip7594; pub mod electra; pub use altair::upgrade_to_altair; pub use bellatrix::upgrade_to_bellatrix; pub use capella::upgrade_to_capella; pub use deneb::upgrade_to_deneb; +pub use eip7594::upgrade_to_eip7594; pub use electra::upgrade_to_electra; diff --git a/consensus/state_processing/src/upgrade/eip7594.rs b/consensus/state_processing/src/upgrade/eip7594.rs new file mode 100644 index 00000000000..2216b9efcd6 --- /dev/null +++ b/consensus/state_processing/src/upgrade/eip7594.rs @@ -0,0 +1,126 @@ +use safe_arith::SafeArith; +use std::mem; +use types::{ + BeaconState, BeaconStateEip7594, BeaconStateError as Error, ChainSpec, EpochCache, EthSpec, + Fork, +}; + +/// Transform a `Deneb` state into an `Eip7594` state. +pub fn upgrade_to_eip7594( + pre_state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { + let epoch = pre_state.current_epoch(); + + pre_state + .validators() + .iter() + .filter(|v| v.exit_epoch != spec.far_future_epoch) + .map(|v| v.exit_epoch) + .max() + .unwrap_or(epoch) + .safe_add(1)?; + + // The total active balance cache must be built before the consolidation churn limit + // is calculated. + pre_state.build_total_active_balance_cache(spec)?; + spec.compute_activation_exit_epoch(epoch)?; + + let pre = pre_state.as_deneb_mut()?; + // Where possible, use something like `mem::take` to move fields from behind the &mut + // reference. For other fields that don't have a good default value, use `clone`. + // + // Fixed size vectors get cloned because replacing them would require the same size + // allocation as cloning. + let mut post = BeaconState::Eip7594(BeaconStateEip7594 { + // Versioning + genesis_time: pre.genesis_time, + genesis_validators_root: pre.genesis_validators_root, + slot: pre.slot, + fork: Fork { + previous_version: pre.fork.current_version, + current_version: spec.eip7594_fork_version, + epoch, + }, + // History + latest_block_header: pre.latest_block_header.clone(), + block_roots: pre.block_roots.clone(), + state_roots: pre.state_roots.clone(), + historical_roots: mem::take(&mut pre.historical_roots), + // Eth1 + eth1_data: pre.eth1_data.clone(), + eth1_data_votes: mem::take(&mut pre.eth1_data_votes), + eth1_deposit_index: pre.eth1_deposit_index, + // Registry + validators: mem::take(&mut pre.validators), + balances: mem::take(&mut pre.balances), + // Randomness + randao_mixes: pre.randao_mixes.clone(), + // Slashings + slashings: pre.slashings.clone(), + // `Participation + previous_epoch_participation: mem::take(&mut pre.previous_epoch_participation), + current_epoch_participation: mem::take(&mut pre.current_epoch_participation), + // Finality + justification_bits: pre.justification_bits.clone(), + previous_justified_checkpoint: pre.previous_justified_checkpoint, + current_justified_checkpoint: pre.current_justified_checkpoint, + finalized_checkpoint: pre.finalized_checkpoint, + // Inactivity + inactivity_scores: mem::take(&mut pre.inactivity_scores), + // Sync committees + current_sync_committee: pre.current_sync_committee.clone(), + next_sync_committee: pre.next_sync_committee.clone(), + // Execution + latest_execution_payload_header: pre.latest_execution_payload_header.upgrade_to_eip7594(), + // Capella + next_withdrawal_index: pre.next_withdrawal_index, + next_withdrawal_validator_index: pre.next_withdrawal_validator_index, + historical_summaries: pre.historical_summaries.clone(), + // Caches + total_active_balance: pre.total_active_balance, + progressive_balances_cache: mem::take(&mut pre.progressive_balances_cache), + committee_caches: mem::take(&mut pre.committee_caches), + pubkey_cache: mem::take(&mut pre.pubkey_cache), + exit_cache: mem::take(&mut pre.exit_cache), + slashings_cache: mem::take(&mut pre.slashings_cache), + epoch_cache: EpochCache::default(), + }); + *post.exit_balance_to_consume_mut()? = post.get_activation_exit_churn_limit(spec)?; + *post.consolidation_balance_to_consume_mut()? = post.get_consolidation_churn_limit(spec)?; + + // Add validators that are not yet active to pending balance deposits + let validators = post.validators().clone(); + let mut pre_activation = validators + .iter() + .enumerate() + .filter(|(_, validator)| validator.activation_epoch == spec.far_future_epoch) + .collect::>(); + + // Sort the indices by activation_eligibility_epoch and then by index + pre_activation.sort_by(|(index_a, val_a), (index_b, val_b)| { + if val_a.activation_eligibility_epoch == val_b.activation_eligibility_epoch { + index_a.cmp(index_b) + } else { + val_a + .activation_eligibility_epoch + .cmp(&val_b.activation_eligibility_epoch) + } + }); + + // Process validators to queue entire balance and reset them + for (index, _) in pre_activation { + post.queue_entire_balance_and_reset_validator(index, spec)?; + } + + // Ensure early adopters of compounding credentials go through the activation churn + for (index, validator) in validators.iter().enumerate() { + if validator.has_compounding_withdrawal_credential(spec) { + post.queue_excess_active_balance(index, spec)?; + } + } + + *pre_state = post; + + Ok(()) +} diff --git a/consensus/types/presets/gnosis/deneb.yaml b/consensus/types/presets/gnosis/deneb.yaml index bef51470e89..d2d7d0abed3 100644 --- a/consensus/types/presets/gnosis/deneb.yaml +++ b/consensus/types/presets/gnosis/deneb.yaml @@ -12,12 +12,3 @@ MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096 MAX_BLOBS_PER_BLOCK: 6 # `floorlog2(BLOB_KZG_COMMITMENTS_GINDEX) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK)` = 4 + 1 + 12 = 17 KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 17 - -# EIP-7594 (temporary in Deneb for the purpose of prototyping) -# --------------------------------------------------------------- -# `uint64(2**6)` (= 64) -FIELD_ELEMENTS_PER_CELL: 64 -# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) -KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4 -# `uint64((FIELD_ELEMENTS_PER_BLOB * 2) // FIELD_ELEMENTS_PER_CELL)` (= 128) -NUMBER_OF_COLUMNS: 128 \ No newline at end of file diff --git a/consensus/types/presets/gnosis/eip7594.yaml b/consensus/types/presets/gnosis/eip7594.yaml new file mode 100644 index 00000000000..af03d2d6b6b --- /dev/null +++ b/consensus/types/presets/gnosis/eip7594.yaml @@ -0,0 +1,10 @@ +# Mainnet preset - EIP7594 + +# Misc +# --------------------------------------------------------------- +# `uint64(2**6)` (= 64) +FIELD_ELEMENTS_PER_CELL: 64 +# `uint64(2 * 4096)` (= 8192) +FIELD_ELEMENTS_PER_EXT_BLOB: 8192 +# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) +KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4 \ No newline at end of file diff --git a/consensus/types/presets/mainnet/deneb.yaml b/consensus/types/presets/mainnet/deneb.yaml index 44bc5034294..0f56b8bdfac 100644 --- a/consensus/types/presets/mainnet/deneb.yaml +++ b/consensus/types/presets/mainnet/deneb.yaml @@ -10,12 +10,3 @@ MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096 MAX_BLOBS_PER_BLOCK: 6 # `floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK)` = 4 + 1 + 12 = 17 KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 17 - -# EIP-7594 (temporary in Deneb for the purpose of prototyping) -# --------------------------------------------------------------- -# `uint64(2**6)` (= 64) -FIELD_ELEMENTS_PER_CELL: 64 -# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) -KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4 -# `uint64((FIELD_ELEMENTS_PER_BLOB * 2) // FIELD_ELEMENTS_PER_CELL)` (= 128) -NUMBER_OF_COLUMNS: 128 \ No newline at end of file diff --git a/consensus/types/presets/mainnet/eip7594.yaml b/consensus/types/presets/mainnet/eip7594.yaml new file mode 100644 index 00000000000..af03d2d6b6b --- /dev/null +++ b/consensus/types/presets/mainnet/eip7594.yaml @@ -0,0 +1,10 @@ +# Mainnet preset - EIP7594 + +# Misc +# --------------------------------------------------------------- +# `uint64(2**6)` (= 64) +FIELD_ELEMENTS_PER_CELL: 64 +# `uint64(2 * 4096)` (= 8192) +FIELD_ELEMENTS_PER_EXT_BLOB: 8192 +# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) +KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4 \ No newline at end of file diff --git a/consensus/types/presets/minimal/deneb.yaml b/consensus/types/presets/minimal/deneb.yaml index 8bb3e0b66bd..be2b9fadfa5 100644 --- a/consensus/types/presets/minimal/deneb.yaml +++ b/consensus/types/presets/minimal/deneb.yaml @@ -10,12 +10,3 @@ MAX_BLOB_COMMITMENTS_PER_BLOCK: 16 MAX_BLOBS_PER_BLOCK: 6 # [customized] `floorlog2(BLOB_KZG_COMMITMENTS_GINDEX) + 1 + ceillog2(MAX_BLOB_COMMITMENTS_PER_BLOCK)` = 4 + 1 + 4 = 9 KZG_COMMITMENT_INCLUSION_PROOF_DEPTH: 9 - -# EIP-7594 (temporary in Deneb for the purpose of prototyping) -# --------------------------------------------------------------- -# `uint64(2**6)` (= 64) -FIELD_ELEMENTS_PER_CELL: 64 -# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) -KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4 -# `uint64((FIELD_ELEMENTS_PER_BLOB * 2) // FIELD_ELEMENTS_PER_CELL)` (= 128) -NUMBER_OF_COLUMNS: 128 \ No newline at end of file diff --git a/consensus/types/presets/minimal/eip7594.yaml b/consensus/types/presets/minimal/eip7594.yaml new file mode 100644 index 00000000000..63eaf5fd930 --- /dev/null +++ b/consensus/types/presets/minimal/eip7594.yaml @@ -0,0 +1,10 @@ +# Minimal preset - EIP7594 + +# Misc +# --------------------------------------------------------------- +# `uint64(2**6)` (= 64) +FIELD_ELEMENTS_PER_CELL: 64 +# `uint64(2 * 4096)` (= 8192) +FIELD_ELEMENTS_PER_EXT_BLOB: 8192 +# uint64(floorlog2(get_generalized_index(BeaconBlockBody, 'blob_kzg_commitments')) +KZG_COMMITMENTS_INCLUSION_PROOF_DEPTH: 4 \ No newline at end of file diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 81491d65056..7ccce72df4f 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -1,3 +1,4 @@ +use crate::beacon_block_body::BeaconBlockBodyEip7594; use crate::test_utils::TestRandom; use crate::*; use derivative::Derivative; @@ -12,7 +13,7 @@ use tree_hash_derive::TreeHash; /// A block of the `BeaconChain`. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Debug, @@ -71,6 +72,8 @@ pub struct BeaconBlock = FullPayload pub body: BeaconBlockBodyDeneb, #[superstruct(only(Electra), partial_getter(rename = "body_electra"))] pub body: BeaconBlockBodyElectra, + #[superstruct(only(Eip7594), partial_getter(rename = "body_eip7594"))] + pub body: BeaconBlockBodyEip7594, } pub type BlindedBeaconBlock = BeaconBlock>; @@ -225,6 +228,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockRef<'a, E, Payl BeaconBlockRef::Capella { .. } => ForkName::Capella, BeaconBlockRef::Deneb { .. } => ForkName::Deneb, BeaconBlockRef::Electra { .. } => ForkName::Electra, + BeaconBlockRef::Eip7594 { .. } => ForkName::Eip7594, } } @@ -676,6 +680,36 @@ impl> EmptyBlock for BeaconBlockElec } } +impl> EmptyBlock for BeaconBlockEip7594 { + /// Returns an empty Eip7594 block to be used during genesis. + fn empty(spec: &ChainSpec) -> Self { + BeaconBlockEip7594 { + slot: spec.genesis_slot, + proposer_index: 0, + parent_root: Hash256::zero(), + state_root: Hash256::zero(), + body: BeaconBlockBodyEip7594 { + randao_reveal: Signature::empty(), + eth1_data: Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + deposit_count: 0, + }, + graffiti: Graffiti::default(), + proposer_slashings: VariableList::empty(), + attester_slashings: VariableList::empty(), + attestations: VariableList::empty(), + deposits: VariableList::empty(), + voluntary_exits: VariableList::empty(), + sync_aggregate: SyncAggregate::empty(), + execution_payload: Payload::Eip7594::default(), + bls_to_execution_changes: VariableList::empty(), + blob_kzg_commitments: VariableList::empty(), + }, + } + } +} + // We can convert pre-Bellatrix blocks without payloads into blocks "with" payloads. impl From>> for BeaconBlockBase> @@ -757,6 +791,7 @@ impl_from!(BeaconBlockBellatrix, >, >, |b impl_from!(BeaconBlockCapella, >, >, |body: BeaconBlockBodyCapella<_, _>| body.into()); impl_from!(BeaconBlockDeneb, >, >, |body: BeaconBlockBodyDeneb<_, _>| body.into()); impl_from!(BeaconBlockElectra, >, >, |body: BeaconBlockBodyElectra<_, _>| body.into()); +impl_from!(BeaconBlockEip7594, >, >, |body: BeaconBlockBodyEip7594<_, _>| body.into()); // We can clone blocks with payloads to blocks without payloads, without cloning the payload. macro_rules! impl_clone_as_blinded { @@ -790,6 +825,7 @@ impl_clone_as_blinded!(BeaconBlockBellatrix, >, >, >); impl_clone_as_blinded!(BeaconBlockDeneb, >, >); impl_clone_as_blinded!(BeaconBlockElectra, >, >); +impl_clone_as_blinded!(BeaconBlockEip7594, >, >); // A reference to a full beacon block can be cloned into a blinded beacon block, without cloning the // execution payload. diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index 4a6a5c46015..3dddcbf8805 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -29,7 +29,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11; /// /// This *superstruct* abstracts over the hard-fork. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Debug, @@ -67,7 +67,7 @@ pub struct BeaconBlockBody = FullPay pub attestations: VariableList, E::MaxAttestations>, pub deposits: VariableList, pub voluntary_exits: VariableList, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] pub sync_aggregate: SyncAggregate, // We flatten the execution payload so that serde can use the name of the inner type, // either `execution_payload` for full payloads, or `execution_payload_header` for blinded @@ -87,10 +87,13 @@ pub struct BeaconBlockBody = FullPay #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] #[serde(flatten)] pub execution_payload: Payload::Electra, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Eip7594), partial_getter(rename = "execution_payload_eip7594"))] + #[serde(flatten)] + pub execution_payload: Payload::Eip7594, + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] pub bls_to_execution_changes: VariableList, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Deneb, Electra, Eip7594))] pub blob_kzg_commitments: KzgCommitments, #[superstruct(only(Base, Altair))] #[ssz(skip_serializing, skip_deserializing)] @@ -114,6 +117,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Capella(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Deneb(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)), + Self::Eip7594(body) => Ok(Payload::Ref::from(&body.execution_payload)), } } @@ -245,6 +249,67 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, // Join the proofs for the subtree and the main tree proof.append(&mut proof_body); + debug_assert_eq!(proof.len(), E::kzg_proof_inclusion_proof_depth()); + Ok(proof.into()) + } + // TODO(das): De-duplicate proof computation. + Self::Eip7594(body) => { + // We compute the branches by generating 2 merkle trees: + // 1. Merkle tree for the `blob_kzg_commitments` List object + // 2. Merkle tree for the `BeaconBlockBody` container + // We then merge the branches for both the trees all the way up to the root. + + // Part1 (Branches for the subtree rooted at `blob_kzg_commitments`) + // + // Branches for `blob_kzg_commitments` without length mix-in + let depth = E::max_blob_commitments_per_block() + .next_power_of_two() + .ilog2(); + let leaves: Vec<_> = body + .blob_kzg_commitments + .iter() + .map(|commitment| commitment.tree_hash_root()) + .collect(); + let tree = MerkleTree::create(&leaves, depth as usize); + let (_, mut proof) = tree + .generate_proof(index, depth as usize) + .map_err(Error::MerkleTreeError)?; + + // Add the branch corresponding to the length mix-in. + let length = body.blob_kzg_commitments.len(); + let usize_len = std::mem::size_of::(); + let mut length_bytes = [0; BYTES_PER_CHUNK]; + length_bytes + .get_mut(0..usize_len) + .ok_or(Error::MerkleTreeError(MerkleTreeError::PleaseNotifyTheDevs))? + .copy_from_slice(&length.to_le_bytes()); + let length_root = Hash256::from_slice(length_bytes.as_slice()); + proof.push(length_root); + + // Part 2 + // Branches for `BeaconBlockBody` container + let leaves = [ + body.randao_reveal.tree_hash_root(), + body.eth1_data.tree_hash_root(), + body.graffiti.tree_hash_root(), + body.proposer_slashings.tree_hash_root(), + body.attester_slashings.tree_hash_root(), + body.attestations.tree_hash_root(), + body.deposits.tree_hash_root(), + body.voluntary_exits.tree_hash_root(), + body.sync_aggregate.tree_hash_root(), + body.execution_payload.tree_hash_root(), + body.bls_to_execution_changes.tree_hash_root(), + body.blob_kzg_commitments.tree_hash_root(), + ]; + let beacon_block_body_depth = leaves.len().next_power_of_two().ilog2() as usize; + let tree = MerkleTree::create(&leaves, beacon_block_body_depth); + let (_, mut proof_body) = tree + .generate_proof(BLOB_KZG_COMMITMENTS_INDEX, beacon_block_body_depth) + .map_err(Error::MerkleTreeError)?; + // Join the proofs for the subtree and the main tree + proof.append(&mut proof_body); + debug_assert_eq!(proof.len(), E::kzg_proof_inclusion_proof_depth()); Ok(proof.into()) } @@ -303,6 +368,28 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, .map_err(Error::MerkleTreeError)?; Ok(proof.into()) } + Self::Eip7594(body) => { + let leaves = [ + body.randao_reveal.tree_hash_root(), + body.eth1_data.tree_hash_root(), + body.graffiti.tree_hash_root(), + body.proposer_slashings.tree_hash_root(), + body.attester_slashings.tree_hash_root(), + body.attestations.tree_hash_root(), + body.deposits.tree_hash_root(), + body.voluntary_exits.tree_hash_root(), + body.sync_aggregate.tree_hash_root(), + body.execution_payload.tree_hash_root(), + body.bls_to_execution_changes.tree_hash_root(), + body.blob_kzg_commitments.tree_hash_root(), + ]; + let beacon_block_body_depth = leaves.len().next_power_of_two().ilog2() as usize; + let tree = MerkleTree::create(&leaves, beacon_block_body_depth); + let (_, proof) = tree + .generate_proof(BLOB_KZG_COMMITMENTS_INDEX, beacon_block_body_depth) + .map_err(Error::MerkleTreeError)?; + Ok(proof.into()) + } } } @@ -323,6 +410,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, BeaconBlockBodyRef::Capella { .. } => ForkName::Capella, BeaconBlockBodyRef::Deneb { .. } => ForkName::Deneb, BeaconBlockBodyRef::Electra { .. } => ForkName::Electra, + BeaconBlockBodyRef::Eip7594 { .. } => ForkName::Eip7594, } } } @@ -635,6 +723,50 @@ impl From>> } } +impl From>> + for ( + BeaconBlockBodyEip7594>, + Option>, + ) +{ + fn from(body: BeaconBlockBodyEip7594>) -> Self { + let BeaconBlockBodyEip7594 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadEip7594 { execution_payload }, + bls_to_execution_changes, + blob_kzg_commitments, + } = body; + + ( + BeaconBlockBodyEip7594 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: BlindedPayloadEip7594 { + execution_payload_header: From::from(&execution_payload), + }, + bls_to_execution_changes, + blob_kzg_commitments, + }, + Some(execution_payload), + ) + } +} + // We can clone a full block into a blinded block, without cloning the payload. impl BeaconBlockBodyBase> { pub fn clone_as_blinded(&self) -> BeaconBlockBodyBase> { @@ -788,6 +920,42 @@ impl BeaconBlockBodyElectra> { } } +impl BeaconBlockBodyEip7594> { + pub fn clone_as_blinded(&self) -> BeaconBlockBodyEip7594> { + let BeaconBlockBodyEip7594 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadEip7594 { execution_payload }, + bls_to_execution_changes, + blob_kzg_commitments, + } = self; + + BeaconBlockBodyEip7594 { + randao_reveal: randao_reveal.clone(), + eth1_data: eth1_data.clone(), + graffiti: *graffiti, + proposer_slashings: proposer_slashings.clone(), + attester_slashings: attester_slashings.clone(), + attestations: attestations.clone(), + deposits: deposits.clone(), + voluntary_exits: voluntary_exits.clone(), + sync_aggregate: sync_aggregate.clone(), + execution_payload: BlindedPayloadEip7594 { + execution_payload_header: execution_payload.into(), + }, + bls_to_execution_changes: bls_to_execution_changes.clone(), + blob_kzg_commitments: blob_kzg_commitments.clone(), + } + } +} + impl From>> for ( BeaconBlockBody>, diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 577f282a556..1d5a5f4ca95 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -29,6 +29,7 @@ pub use crate::beacon_state::balance::Balance; pub use crate::beacon_state::exit_cache::ExitCache; pub use crate::beacon_state::progressive_balances_cache::*; pub use crate::beacon_state::slashings_cache::SlashingsCache; +use crate::execution_payload_header::ExecutionPayloadHeaderEip7594; pub use eth_spec::*; pub use iter::BlockRootsIter; pub use milhouse::{interface::Interface, List, Vector}; @@ -206,7 +207,7 @@ impl From for Hash256 { /// The state of the `BeaconChain` at some slot. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Derivative, @@ -309,6 +310,20 @@ impl From for Hash256 { groups(tree_lists) )), num_fields(all()), + )), + Eip7594(metastruct( + mappings( + map_beacon_state_eip7594_fields(), + map_beacon_state_eip7594_tree_list_fields(mutable, fallible, groups(tree_lists)), + map_beacon_state_eip7594_tree_list_fields_immutable(groups(tree_lists)), + ), + bimappings(bimap_beacon_state_eip7594_tree_list_fields( + other_type = "BeaconStateEip7594", + self_mutable, + fallible, + groups(tree_lists) + )), + num_fields(all()), )) ), cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"), @@ -392,10 +407,10 @@ where pub current_epoch_attestations: List, E::MaxPendingAttestations>, // Participation (Altair and later) - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] #[test_random(default)] pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] #[test_random(default)] pub current_epoch_participation: List, @@ -415,15 +430,15 @@ where // Inactivity #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] #[test_random(default)] pub inactivity_scores: List, // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] #[metastruct(exclude_from(tree_lists))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7594))] #[metastruct(exclude_from(tree_lists))] pub next_sync_committee: Arc>, @@ -452,18 +467,24 @@ where )] #[metastruct(exclude_from(tree_lists))] pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, + #[superstruct( + only(Eip7594), + partial_getter(rename = "latest_execution_payload_header_eip7594") + )] + #[metastruct(exclude_from(tree_lists))] + pub latest_execution_payload_header: ExecutionPayloadHeaderEip7594, // Capella - #[superstruct(only(Capella, Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] pub next_withdrawal_validator_index: u64, // Deep history valid from Capella onwards. - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] #[test_random(default)] pub historical_summaries: List, @@ -639,6 +660,7 @@ impl BeaconState { BeaconState::Capella { .. } => ForkName::Capella, BeaconState::Deneb { .. } => ForkName::Deneb, BeaconState::Electra { .. } => ForkName::Electra, + BeaconState::Eip7594 { .. } => ForkName::Eip7594, } } @@ -930,6 +952,9 @@ impl BeaconState { BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRef::Electra( &state.latest_execution_payload_header, )), + BeaconState::Eip7594(state) => Ok(ExecutionPayloadHeaderRef::Eip7594( + &state.latest_execution_payload_header, + )), } } @@ -950,6 +975,9 @@ impl BeaconState { BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRefMut::Electra( &mut state.latest_execution_payload_header, )), + BeaconState::Eip7594(state) => Ok(ExecutionPayloadHeaderRefMut::Eip7594( + &mut state.latest_execution_payload_header, + )), } } @@ -1464,6 +1492,16 @@ impl BeaconState { &mut state.exit_cache, &mut state.epoch_cache, )), + BeaconState::Eip7594(state) => Ok(( + &mut state.validators, + &mut state.balances, + &state.previous_epoch_participation, + &state.current_epoch_participation, + &mut state.inactivity_scores, + &mut state.progressive_balances_cache, + &mut state.exit_cache, + &mut state.epoch_cache, + )), } } @@ -1591,10 +1629,12 @@ impl BeaconState { | BeaconState::Altair(_) | BeaconState::Bellatrix(_) | BeaconState::Capella(_) => self.get_validator_churn_limit(spec)?, - BeaconState::Deneb(_) | BeaconState::Electra(_) => std::cmp::min( - spec.max_per_epoch_activation_churn_limit, - self.get_validator_churn_limit(spec)?, - ), + BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::Eip7594(_) => { + std::cmp::min( + spec.max_per_epoch_activation_churn_limit, + self.get_validator_churn_limit(spec)?, + ) + } }) } @@ -1712,6 +1752,7 @@ impl BeaconState { BeaconState::Capella(state) => Ok(&mut state.current_epoch_participation), BeaconState::Deneb(state) => Ok(&mut state.current_epoch_participation), BeaconState::Electra(state) => Ok(&mut state.current_epoch_participation), + BeaconState::Eip7594(state) => Ok(&mut state.current_epoch_participation), } } else if epoch == previous_epoch { match self { @@ -1721,6 +1762,7 @@ impl BeaconState { BeaconState::Capella(state) => Ok(&mut state.previous_epoch_participation), BeaconState::Deneb(state) => Ok(&mut state.previous_epoch_participation), BeaconState::Electra(state) => Ok(&mut state.previous_epoch_participation), + BeaconState::Eip7594(state) => Ok(&mut state.previous_epoch_participation), } } else { Err(BeaconStateError::EpochOutOfBounds) @@ -1987,6 +2029,14 @@ impl BeaconState { } ); } + Self::Eip7594(self_inner) => { + map_beacon_state_eip7594_tree_list_fields_immutable!( + self_inner, + |_, self_field| { + any_pending_mutations |= self_field.has_pending_updates(); + } + ); + } }; any_pending_mutations } @@ -2322,6 +2372,14 @@ impl BeaconState { ); } (Self::Electra(_), _) => (), + (Self::Eip7594(self_inner), Self::Eip7594(base_inner)) => { + bimap_beacon_state_eip7594_tree_list_fields!( + self_inner, + base_inner, + |_, self_field, base_field| { self_field.rebase_on(base_field) } + ); + } + (Self::Eip7594(_), _) => (), } // Use sync committees from `base` if they are equal. @@ -2394,6 +2452,7 @@ impl BeaconState { ForkName::Capella => BeaconStateCapella::::NUM_FIELDS.next_power_of_two(), ForkName::Deneb => BeaconStateDeneb::::NUM_FIELDS.next_power_of_two(), ForkName::Electra => BeaconStateElectra::::NUM_FIELDS.next_power_of_two(), + ForkName::Eip7594 => BeaconStateEip7594::::NUM_FIELDS.next_power_of_two(), } } @@ -2442,6 +2501,9 @@ impl BeaconState { Self::Electra(inner) => { map_beacon_state_electra_tree_list_fields!(inner, |_, x| { x.apply_updates() }) } + Self::Eip7594(inner) => { + map_beacon_state_eip7594_tree_list_fields!(inner, |_, x| { x.apply_updates() }) + } } Ok(()) } @@ -2506,6 +2568,11 @@ impl BeaconState { leaves.push(field.tree_hash_root()); }); } + BeaconState::Eip7594(state) => { + map_beacon_state_eip7594_fields!(state, |_, field| { + leaves.push(field.tree_hash_root()); + }); + } }; // 3. Make deposit tree. diff --git a/consensus/types/src/beacon_state/progressive_balances_cache.rs b/consensus/types/src/beacon_state/progressive_balances_cache.rs index fd5e51313f7..843b495aa3b 100644 --- a/consensus/types/src/beacon_state/progressive_balances_cache.rs +++ b/consensus/types/src/beacon_state/progressive_balances_cache.rs @@ -291,6 +291,7 @@ pub fn is_progressive_balances_enabled(state: &BeaconState) -> bo | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => true, + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => true, } } diff --git a/consensus/types/src/builder_bid.rs b/consensus/types/src/builder_bid.rs index 9885f78474f..09d1c948c88 100644 --- a/consensus/types/src/builder_bid.rs +++ b/consensus/types/src/builder_bid.rs @@ -1,8 +1,9 @@ use crate::beacon_block_body::KzgCommitments; use crate::{ ChainSpec, EthSpec, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, - ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderRef, - ExecutionPayloadHeaderRefMut, ForkName, ForkVersionDeserialize, SignedRoot, Uint256, + ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7594, ExecutionPayloadHeaderElectra, + ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, ForkName, ForkVersionDeserialize, + SignedRoot, Uint256, }; use bls::PublicKeyBytes; use bls::Signature; @@ -11,7 +12,7 @@ use superstruct::superstruct; use tree_hash_derive::TreeHash; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive(PartialEq, Debug, Serialize, Deserialize, TreeHash, Clone), serde(bound = "E: EthSpec", deny_unknown_fields) @@ -31,7 +32,9 @@ pub struct BuilderBid { pub header: ExecutionPayloadHeaderDeneb, #[superstruct(only(Electra), partial_getter(rename = "header_electra"))] pub header: ExecutionPayloadHeaderElectra, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Eip7594), partial_getter(rename = "header_eip7594"))] + pub header: ExecutionPayloadHeaderEip7594, + #[superstruct(only(Deneb, Electra, Eip7594))] pub blob_kzg_commitments: KzgCommitments, #[serde(with = "serde_utils::quoted_u256")] pub value: Uint256, @@ -85,6 +88,7 @@ impl ForkVersionDeserialize for BuilderBid { ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?), ForkName::Deneb => Self::Deneb(serde_json::from_value(value).map_err(convert_err)?), ForkName::Electra => Self::Electra(serde_json::from_value(value).map_err(convert_err)?), + ForkName::Eip7594 => Self::Eip7594(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( "BuilderBid failed to deserialize: unsupported fork '{}'", diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index b2e6e3da7e3..e8a1ebf2aea 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -192,8 +192,10 @@ pub struct ChainSpec { pub max_per_epoch_activation_exit_churn_limit: u64, /* - * DAS params + * DAS EIP-7594 hard fork params */ + pub eip7594_fork_version: [u8; 4], + pub eip7594_fork_epoch: Option, pub peer_das_epoch: Option, pub custody_requirement: u64, @@ -340,6 +342,7 @@ impl ChainSpec { ForkName::Capella => self.capella_fork_version, ForkName::Deneb => self.deneb_fork_version, ForkName::Electra => self.electra_fork_version, + ForkName::Eip7594 => self.eip7594_fork_version, } } @@ -352,6 +355,7 @@ impl ChainSpec { ForkName::Capella => self.capella_fork_epoch, ForkName::Deneb => self.deneb_fork_epoch, ForkName::Electra => self.electra_fork_epoch, + ForkName::Eip7594 => self.eip7594_fork_epoch, } } @@ -764,6 +768,8 @@ impl ChainSpec { /* * DAS params */ + eip7594_fork_version: [0x06, 00, 00, 00], + eip7594_fork_epoch: None, peer_das_epoch: None, custody_requirement: 1, @@ -871,7 +877,9 @@ impl ChainSpec { electra_fork_epoch: None, max_pending_partials_per_withdrawals_sweep: u64::checked_pow(2, 0) .expect("pow does not overflow"), - // PeerDAS + // PeerDAS (EIP-7594) + eip7594_fork_version: [0x06, 0x00, 0x00, 0x01], + eip7594_fork_epoch: None, peer_das_epoch: None, // Other network_id: 2, // lighthouse testnet network id @@ -1077,6 +1085,8 @@ impl ChainSpec { /* * DAS params */ + eip7594_fork_version: [0x06, 0x00, 0x00, 0x64], + eip7594_fork_epoch: None, peer_das_epoch: None, custody_requirement: 1, /* diff --git a/consensus/types/src/config_and_preset.rs b/consensus/types/src/config_and_preset.rs index 6fc6e0642ea..9932ca05d7e 100644 --- a/consensus/types/src/config_and_preset.rs +++ b/consensus/types/src/config_and_preset.rs @@ -12,7 +12,7 @@ use superstruct::superstruct; /// /// Mostly useful for the API. #[superstruct( - variants(Capella, Deneb, Electra), + variants(Capella, Deneb, Electra, Eip7594), variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone)) )] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -29,12 +29,15 @@ pub struct ConfigAndPreset { pub bellatrix_preset: BellatrixPreset, #[serde(flatten)] pub capella_preset: CapellaPreset, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Deneb, Electra, Eip7594))] #[serde(flatten)] pub deneb_preset: DenebPreset, #[superstruct(only(Electra))] #[serde(flatten)] pub electra_preset: ElectraPreset, + #[superstruct(only(Eip7594))] + #[serde(flatten)] + pub eip7594_preset: ElectraPreset, /// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks. #[serde(flatten)] pub extra_fields: HashMap, diff --git a/consensus/types/src/eth_spec.rs b/consensus/types/src/eth_spec.rs index 640faeec07e..c0f5d86fdf4 100644 --- a/consensus/types/src/eth_spec.rs +++ b/consensus/types/src/eth_spec.rs @@ -110,12 +110,13 @@ pub trait EthSpec: type MaxBlobsPerBlock: Unsigned + Clone + Sync + Send + Debug + PartialEq + Unpin; type MaxBlobCommitmentsPerBlock: Unsigned + Clone + Sync + Send + Debug + PartialEq + Unpin; type FieldElementsPerBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq; - type FieldElementsPerCell: Unsigned + Clone + Sync + Send + Debug + PartialEq; type BytesPerFieldElement: Unsigned + Clone + Sync + Send + Debug + PartialEq; type KzgCommitmentInclusionProofDepth: Unsigned + Clone + Sync + Send + Debug + PartialEq; /* * New in PeerDAS */ + type FieldElementsPerCell: Unsigned + Clone + Sync + Send + Debug + PartialEq; + type FieldElementsPerExtBlob: Unsigned + Clone + Sync + Send + Debug + PartialEq; type MinCustodyRequirement: Unsigned + Clone + Sync + Send + Debug + PartialEq; type DataColumnSubnetCount: Unsigned + Clone + Sync + Send + Debug + PartialEq; type DataColumnCount: Unsigned + Clone + Sync + Send + Debug + PartialEq; @@ -291,6 +292,11 @@ pub trait EthSpec: Self::FieldElementsPerBlob::to_usize() } + /// Returns the `FIELD_ELEMENTS_PER_EXT_BLOB` constant for this specification. + fn field_elements_per_ext_blob() -> usize { + Self::FieldElementsPerExtBlob::to_usize() + } + /// Returns the `FIELD_ELEMENTS_PER_CELL` constant for this specification. fn field_elements_per_cell() -> usize { Self::FieldElementsPerCell::to_usize() @@ -409,6 +415,7 @@ impl EthSpec for MainnetEthSpec { type BytesPerFieldElement = U32; type FieldElementsPerBlob = U4096; type FieldElementsPerCell = U64; + type FieldElementsPerExtBlob = U8192; type BytesPerBlob = U131072; type KzgCommitmentInclusionProofDepth = U17; type MinCustodyRequirement = U1; @@ -456,6 +463,7 @@ impl EthSpec for MinimalEthSpec { type MaxWithdrawalsPerPayload = U4; type FieldElementsPerBlob = U4096; type FieldElementsPerCell = U64; + type FieldElementsPerExtBlob = U8192; type BytesPerBlob = U131072; type MaxBlobCommitmentsPerBlock = U16; type KzgCommitmentInclusionProofDepth = U9; @@ -545,6 +553,7 @@ impl EthSpec for GnosisEthSpec { type MaxBlobCommitmentsPerBlock = U4096; type FieldElementsPerBlob = U4096; type FieldElementsPerCell = U64; + type FieldElementsPerExtBlob = U8192; type BytesPerFieldElement = U32; type BytesPerBlob = U131072; type KzgCommitmentInclusionProofDepth = U17; diff --git a/consensus/types/src/execution_payload.rs b/consensus/types/src/execution_payload.rs index 0946b9ecffa..3eab3fd96ba 100644 --- a/consensus/types/src/execution_payload.rs +++ b/consensus/types/src/execution_payload.rs @@ -15,7 +15,7 @@ pub type Transactions = VariableList< pub type Withdrawals = VariableList::MaxWithdrawalsPerPayload>; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Default, @@ -81,12 +81,12 @@ pub struct ExecutionPayload { pub block_hash: ExecutionBlockHash, #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] pub withdrawals: Withdrawals, - #[superstruct(only(Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Eip7594), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Eip7594), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, #[superstruct(only(Electra))] @@ -118,6 +118,7 @@ impl ExecutionPayload { ForkName::Capella => ExecutionPayloadCapella::from_ssz_bytes(bytes).map(Self::Capella), ForkName::Deneb => ExecutionPayloadDeneb::from_ssz_bytes(bytes).map(Self::Deneb), ForkName::Electra => ExecutionPayloadElectra::from_ssz_bytes(bytes).map(Self::Electra), + ForkName::Eip7594 => ExecutionPayloadEip7594::from_ssz_bytes(bytes).map(Self::Eip7594), } } @@ -170,6 +171,19 @@ impl ExecutionPayload { // Max size of variable length `withdrawals` field + (E::max_withdrawals_per_payload() * ::ssz_fixed_len()) } + + #[allow(clippy::arithmetic_side_effects)] + /// Returns the maximum size of an execution payload. + pub fn max_execution_payload_eip7594_size() -> usize { + // Fixed part + ExecutionPayloadEip7594::::default().as_ssz_bytes().len() + // Max size of variable length `extra_data` field + + (E::max_extra_data_bytes() * ::ssz_fixed_len()) + // Max size of variable length `transactions` field + + (E::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + E::max_bytes_per_transaction())) + // Max size of variable length `withdrawals` field + + (E::max_withdrawals_per_payload() * ::ssz_fixed_len()) + } } impl ForkVersionDeserialize for ExecutionPayload { @@ -188,6 +202,7 @@ impl ForkVersionDeserialize for ExecutionPayload { ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?), ForkName::Deneb => Self::Deneb(serde_json::from_value(value).map_err(convert_err)?), ForkName::Electra => Self::Electra(serde_json::from_value(value).map_err(convert_err)?), + ForkName::Eip7594 => Self::Eip7594(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( "ExecutionPayload failed to deserialize: unsupported fork '{}'", @@ -205,6 +220,7 @@ impl ExecutionPayload { ExecutionPayload::Capella(_) => ForkName::Capella, ExecutionPayload::Deneb(_) => ForkName::Deneb, ExecutionPayload::Electra(_) => ForkName::Electra, + ExecutionPayload::Eip7594(_) => ForkName::Eip7594, } } } diff --git a/consensus/types/src/execution_payload_header.rs b/consensus/types/src/execution_payload_header.rs index 324d7b97472..48518afe1b5 100644 --- a/consensus/types/src/execution_payload_header.rs +++ b/consensus/types/src/execution_payload_header.rs @@ -8,7 +8,7 @@ use tree_hash::TreeHash; use tree_hash_derive::TreeHash; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Default, @@ -77,14 +77,14 @@ pub struct ExecutionPayloadHeader { pub block_hash: ExecutionBlockHash, #[superstruct(getter(copy))] pub transactions_root: Hash256, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, Eip7594))] #[superstruct(getter(copy))] pub withdrawals_root: Hash256, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Deneb, Electra, Eip7594))] #[serde(with = "serde_utils::quoted_u64")] #[superstruct(getter(copy))] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra))] + #[superstruct(only(Deneb, Electra, Eip7594))] #[serde(with = "serde_utils::quoted_u64")] #[superstruct(getter(copy))] pub excess_blob_gas: u64, @@ -114,6 +114,9 @@ impl ExecutionPayloadHeader { ForkName::Electra => { ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra) } + ForkName::Eip7594 => { + ExecutionPayloadHeaderEip7594::from_ssz_bytes(bytes).map(Self::Eip7594) + } } } @@ -127,7 +130,8 @@ impl ExecutionPayloadHeader { | ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb - | ForkName::Electra => { + | ForkName::Electra + | ForkName::Eip7594 => { // Max size of variable length `extra_data` field E::max_extra_data_bytes() * ::ssz_fixed_len() } @@ -214,6 +218,28 @@ impl ExecutionPayloadHeaderDeneb { withdrawal_requests_root: Hash256::zero(), } } + + pub fn upgrade_to_eip7594(&self) -> ExecutionPayloadHeaderEip7594 { + ExecutionPayloadHeaderEip7594 { + parent_hash: self.parent_hash, + fee_recipient: self.fee_recipient, + state_root: self.state_root, + receipts_root: self.receipts_root, + logs_bloom: self.logs_bloom.clone(), + prev_randao: self.prev_randao, + block_number: self.block_number, + gas_limit: self.gas_limit, + gas_used: self.gas_used, + timestamp: self.timestamp, + extra_data: self.extra_data.clone(), + base_fee_per_gas: self.base_fee_per_gas, + block_hash: self.block_hash, + transactions_root: self.transactions_root, + withdrawals_root: self.withdrawals_root, + blob_gas_used: self.blob_gas_used, + excess_blob_gas: self.excess_blob_gas, + } + } } impl<'a, E: EthSpec> From<&'a ExecutionPayloadBellatrix> for ExecutionPayloadHeaderBellatrix { @@ -309,6 +335,30 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadElectra> for ExecutionPayloadHe } } +impl<'a, E: EthSpec> From<&'a ExecutionPayloadEip7594> for ExecutionPayloadHeaderEip7594 { + fn from(payload: &'a ExecutionPayloadEip7594) -> Self { + Self { + parent_hash: payload.parent_hash, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: payload.logs_bloom.clone(), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: payload.extra_data.clone(), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash, + transactions_root: payload.transactions.tree_hash_root(), + withdrawals_root: payload.withdrawals.tree_hash_root(), + blob_gas_used: payload.blob_gas_used, + excess_blob_gas: payload.excess_blob_gas, + } + } +} + // These impls are required to work around an inelegance in `to_execution_payload_header`. // They only clone headers so they should be relatively cheap. impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderBellatrix { @@ -335,6 +385,12 @@ impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderElectra { } } +impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderEip7594 { + fn from(payload: &'a Self) -> Self { + payload.clone() + } +} + impl<'a, E: EthSpec> From> for ExecutionPayloadHeader { fn from(payload: ExecutionPayloadRef<'a, E>) -> Self { map_execution_payload_ref_into_execution_payload_header!( @@ -393,6 +449,9 @@ impl<'a, E: EthSpec> ExecutionPayloadHeaderRefMut<'a, E> { ExecutionPayloadHeaderRefMut::Electra(mut_ref) => { *mut_ref = header.try_into()?; } + ExecutionPayloadHeaderRefMut::Eip7594(mut_ref) => { + *mut_ref = header.try_into()?; + } } Ok(()) } @@ -410,6 +469,18 @@ impl TryFrom> for ExecutionPayloadHeaderEl } } +impl TryFrom> for ExecutionPayloadHeaderEip7594 { + type Error = BeaconStateError; + fn try_from(header: ExecutionPayloadHeader) -> Result { + match header { + ExecutionPayloadHeader::Eip7594(execution_payload_header) => { + Ok(execution_payload_header) + } + _ => Err(BeaconStateError::IncorrectStateVariant), + } + } +} + impl ForkVersionDeserialize for ExecutionPayloadHeader { fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>( value: serde_json::value::Value, @@ -429,6 +500,7 @@ impl ForkVersionDeserialize for ExecutionPayloadHeader { ForkName::Capella => Self::Capella(serde_json::from_value(value).map_err(convert_err)?), ForkName::Deneb => Self::Deneb(serde_json::from_value(value).map_err(convert_err)?), ForkName::Electra => Self::Electra(serde_json::from_value(value).map_err(convert_err)?), + ForkName::Eip7594 => Self::Eip7594(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( "ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'", diff --git a/consensus/types/src/fork_context.rs b/consensus/types/src/fork_context.rs index 0f7f0eb769e..05656e40a44 100644 --- a/consensus/types/src/fork_context.rs +++ b/consensus/types/src/fork_context.rs @@ -69,6 +69,13 @@ impl ForkContext { )); } + if spec.eip7594_fork_epoch.is_some() { + fork_to_digest.push(( + ForkName::Eip7594, + ChainSpec::compute_fork_digest(spec.eip7594_fork_version, genesis_validators_root), + )); + } + let fork_to_digest: HashMap = fork_to_digest.into_iter().collect(); let digest_to_fork = fork_to_digest diff --git a/consensus/types/src/fork_name.rs b/consensus/types/src/fork_name.rs index 5cc66214733..32f5f9324e2 100644 --- a/consensus/types/src/fork_name.rs +++ b/consensus/types/src/fork_name.rs @@ -17,6 +17,7 @@ pub enum ForkName { Capella, Deneb, Electra, + Eip7594, } impl ForkName { @@ -89,6 +90,15 @@ impl ForkName { spec.electra_fork_epoch = Some(Epoch::new(0)); spec } + ForkName::Eip7594 => { + spec.altair_fork_epoch = Some(Epoch::new(0)); + spec.bellatrix_fork_epoch = Some(Epoch::new(0)); + spec.capella_fork_epoch = Some(Epoch::new(0)); + spec.deneb_fork_epoch = Some(Epoch::new(0)); + spec.eip7594_fork_epoch = Some(Epoch::new(0)); + spec.electra_fork_epoch = None; + spec + } } } @@ -103,6 +113,7 @@ impl ForkName { ForkName::Capella => Some(ForkName::Bellatrix), ForkName::Deneb => Some(ForkName::Capella), ForkName::Electra => Some(ForkName::Deneb), + ForkName::Eip7594 => Some(ForkName::Deneb), } } @@ -117,6 +128,7 @@ impl ForkName { ForkName::Capella => Some(ForkName::Deneb), ForkName::Deneb => Some(ForkName::Electra), ForkName::Electra => None, + ForkName::Eip7594 => None, } } } @@ -170,6 +182,10 @@ macro_rules! map_fork_name_with { let (value, extra_data) = $body; ($t::Electra(value), extra_data) } + ForkName::Eip7594 => { + let (value, extra_data) = $body; + ($t::Eip7594(value), extra_data) + } } }; } @@ -185,6 +201,7 @@ impl FromStr for ForkName { "capella" => ForkName::Capella, "deneb" => ForkName::Deneb, "electra" => ForkName::Electra, + "eip7594" => ForkName::Eip7594, _ => return Err(format!("unknown fork name: {}", fork_name)), }) } @@ -199,6 +216,7 @@ impl Display for ForkName { ForkName::Capella => "capella".fmt(f), ForkName::Deneb => "deneb".fmt(f), ForkName::Electra => "electra".fmt(f), + ForkName::Eip7594 => "eip7594".fmt(f), } } } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index 66e8cdd2914..41eebba2687 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -123,13 +123,13 @@ pub use crate::attestation_duty::AttestationDuty; pub use crate::attester_slashing::AttesterSlashing; pub use crate::beacon_block::{ BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BeaconBlockCapella, - BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, - EmptyBlock, + BeaconBlockDeneb, BeaconBlockEip7594, BeaconBlockElectra, BeaconBlockRef, BeaconBlockRefMut, + BlindedBeaconBlock, EmptyBlock, }; pub use crate::beacon_block_body::{ BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix, - BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyRef, - BeaconBlockBodyRefMut, + BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyEip7594, BeaconBlockBodyElectra, + BeaconBlockBodyRef, BeaconBlockBodyRefMut, }; pub use crate::beacon_block_header::BeaconBlockHeader; pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee}; @@ -159,12 +159,13 @@ pub use crate::execution_block_header::ExecutionBlockHeader; pub use crate::execution_layer_withdrawal_request::ExecutionLayerWithdrawalRequest; pub use crate::execution_payload::{ ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, ExecutionPayloadRef, Transaction, Transactions, Withdrawals, + ExecutionPayloadEip7594, ExecutionPayloadElectra, ExecutionPayloadRef, Transaction, + Transactions, Withdrawals, }; pub use crate::execution_payload_header::{ ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, - ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderRef, - ExecutionPayloadHeaderRefMut, + ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7594, ExecutionPayloadHeaderElectra, + ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, }; pub use crate::fork::Fork; pub use crate::fork_context::ForkContext; @@ -197,9 +198,9 @@ pub use crate::participation_flags::ParticipationFlags; pub use crate::participation_list::ParticipationList; pub use crate::payload::{ AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella, - BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadRef, BlockType, ExecPayload, - FullPayload, FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, - FullPayloadRef, OwnedExecPayload, + BlindedPayloadDeneb, BlindedPayloadEip7594, BlindedPayloadElectra, BlindedPayloadRef, + BlockType, ExecPayload, FullPayload, FullPayloadBellatrix, FullPayloadCapella, + FullPayloadDeneb, FullPayloadEip7594, FullPayloadElectra, FullPayloadRef, OwnedExecPayload, }; pub use crate::pending_attestation::PendingAttestation; pub use crate::pending_balance_deposit::PendingBalanceDeposit; @@ -218,8 +219,8 @@ pub use crate::signed_aggregate_and_proof::SignedAggregateAndProof; pub use crate::signed_beacon_block::{ ssz_tagged_signed_beacon_block, ssz_tagged_signed_beacon_block_arc, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, - SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, - SignedBeaconBlockHash, SignedBlindedBeaconBlock, + SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockEip7594, + SignedBeaconBlockElectra, SignedBeaconBlockHash, SignedBlindedBeaconBlock, }; pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader; pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange; diff --git a/consensus/types/src/light_client_bootstrap.rs b/consensus/types/src/light_client_bootstrap.rs index 61da0e1b117..5105c06fe21 100644 --- a/consensus/types/src/light_client_bootstrap.rs +++ b/consensus/types/src/light_client_bootstrap.rs @@ -82,7 +82,7 @@ impl LightClientBootstrap { Self::Altair(LightClientBootstrapAltair::from_ssz_bytes(bytes)?) } ForkName::Capella => Self::Capella(LightClientBootstrapCapella::from_ssz_bytes(bytes)?), - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?) } ForkName::Base => { @@ -104,7 +104,8 @@ impl LightClientBootstrap { | ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb - | ForkName::Electra => { + | ForkName::Electra + | ForkName::Eip7594 => { as Encode>::ssz_fixed_len() + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } @@ -138,11 +139,13 @@ impl LightClientBootstrap { current_sync_committee, current_sync_committee_branch, }), - ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientBootstrapDeneb { - header: LightClientHeaderDeneb::block_to_light_client_header(block)?, - current_sync_committee, - current_sync_committee_branch, - }), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + Self::Deneb(LightClientBootstrapDeneb { + header: LightClientHeaderDeneb::block_to_light_client_header(block)?, + current_sync_committee, + current_sync_committee_branch, + }) + } }; Ok(light_client_bootstrap) diff --git a/consensus/types/src/light_client_finality_update.rs b/consensus/types/src/light_client_finality_update.rs index 29c526e2916..1cfb8ef4163 100644 --- a/consensus/types/src/light_client_finality_update.rs +++ b/consensus/types/src/light_client_finality_update.rs @@ -107,7 +107,7 @@ impl LightClientFinalityUpdate { }; Self::Capella(finality_update) } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { let finality_update = LightClientFinalityUpdateDeneb { attested_header: LightClientHeaderDeneb::block_to_light_client_header( attested_block, @@ -153,7 +153,7 @@ impl LightClientFinalityUpdate { ForkName::Capella => { Self::Capella(LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?) } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { Self::Deneb(LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?) } ForkName::Base => { @@ -175,7 +175,8 @@ impl LightClientFinalityUpdate { | ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb - | ForkName::Electra => { + | ForkName::Electra + | ForkName::Eip7594 => { as Encode>::ssz_fixed_len() + 2 * LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } diff --git a/consensus/types/src/light_client_header.rs b/consensus/types/src/light_client_header.rs index 213ec90f955..6b4e4e55057 100644 --- a/consensus/types/src/light_client_header.rs +++ b/consensus/types/src/light_client_header.rs @@ -81,7 +81,7 @@ impl LightClientHeader { ForkName::Capella => LightClientHeader::Capella( LightClientHeaderCapella::block_to_light_client_header(block)?, ), - ForkName::Deneb | ForkName::Electra => LightClientHeader::Deneb( + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => LightClientHeader::Deneb( LightClientHeaderDeneb::block_to_light_client_header(block)?, ), }; @@ -96,7 +96,7 @@ impl LightClientHeader { ForkName::Capella => { LightClientHeader::Capella(LightClientHeaderCapella::from_ssz_bytes(bytes)?) } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { LightClientHeader::Deneb(LightClientHeaderDeneb::from_ssz_bytes(bytes)?) } ForkName::Base => { @@ -120,7 +120,7 @@ impl LightClientHeader { pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize { match fork_name { ForkName::Base | ForkName::Altair | ForkName::Bellatrix => 0, - ForkName::Capella | ForkName::Deneb | ForkName::Electra => { + ForkName::Capella | ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { ExecutionPayloadHeader::::ssz_max_var_len_for_fork(fork_name) } } @@ -204,9 +204,11 @@ impl ForkVersionDeserialize for LightClientHeader { ForkName::Capella => serde_json::from_value(value) .map(|light_client_header| Self::Capella(light_client_header)) .map_err(serde::de::Error::custom), - ForkName::Deneb | ForkName::Electra => serde_json::from_value(value) - .map(|light_client_header| Self::Deneb(light_client_header)) - .map_err(serde::de::Error::custom), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + serde_json::from_value(value) + .map(|light_client_header| Self::Deneb(light_client_header)) + .map_err(serde::de::Error::custom) + } ForkName::Base => Err(serde::de::Error::custom(format!( "LightClientHeader deserialization for {fork_name} not implemented" ))), diff --git a/consensus/types/src/light_client_optimistic_update.rs b/consensus/types/src/light_client_optimistic_update.rs index 4727673f6c0..45c23bcbc0d 100644 --- a/consensus/types/src/light_client_optimistic_update.rs +++ b/consensus/types/src/light_client_optimistic_update.rs @@ -86,13 +86,15 @@ impl LightClientOptimisticUpdate { sync_aggregate, signature_slot, }), - ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientOptimisticUpdateDeneb { - attested_header: LightClientHeaderDeneb::block_to_light_client_header( - attested_block, - )?, - sync_aggregate, - signature_slot, - }), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + Self::Deneb(LightClientOptimisticUpdateDeneb { + attested_header: LightClientHeaderDeneb::block_to_light_client_header( + attested_block, + )?, + sync_aggregate, + signature_slot, + }) + } ForkName::Base => return Err(Error::AltairForkNotActive), }; @@ -139,7 +141,7 @@ impl LightClientOptimisticUpdate { ForkName::Capella => { Self::Capella(LightClientOptimisticUpdateCapella::from_ssz_bytes(bytes)?) } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { Self::Deneb(LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?) } ForkName::Base => { @@ -161,7 +163,8 @@ impl LightClientOptimisticUpdate { | ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb - | ForkName::Electra => { + | ForkName::Electra + | ForkName::Eip7594 => { as Encode>::ssz_fixed_len() + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } diff --git a/consensus/types/src/light_client_update.rs b/consensus/types/src/light_client_update.rs index 002fbea2d37..abe3b57bbfd 100644 --- a/consensus/types/src/light_client_update.rs +++ b/consensus/types/src/light_client_update.rs @@ -221,7 +221,7 @@ impl LightClientUpdate { signature_slot: block.slot(), }) } - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { let attested_header = LightClientHeaderDeneb::block_to_light_client_header(attested_block)?; let finalized_header = @@ -247,7 +247,7 @@ impl LightClientUpdate { Self::Altair(LightClientUpdateAltair::from_ssz_bytes(bytes)?) } ForkName::Capella => Self::Capella(LightClientUpdateCapella::from_ssz_bytes(bytes)?), - ForkName::Deneb | ForkName::Electra => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?) } ForkName::Base => { diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index 80a70c171f5..61e5d3319eb 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -83,13 +83,15 @@ pub trait AbstractExecPayload: + TryInto + TryInto + TryInto + + TryInto { type Ref<'a>: ExecPayload + Copy + From<&'a Self::Bellatrix> + From<&'a Self::Capella> + From<&'a Self::Deneb> - + From<&'a Self::Electra>; + + From<&'a Self::Electra> + + From<&'a Self::Eip7594>; type Bellatrix: OwnedExecPayload + Into @@ -107,10 +109,14 @@ pub trait AbstractExecPayload: + Into + for<'a> From>> + TryFrom>; + type Eip7594: OwnedExecPayload + + Into + + for<'a> From>> + + TryFrom>; } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Debug, @@ -156,6 +162,8 @@ pub struct FullPayload { pub execution_payload: ExecutionPayloadDeneb, #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] pub execution_payload: ExecutionPayloadElectra, + #[superstruct(only(Eip7594), partial_getter(rename = "execution_payload_eip7594"))] + pub execution_payload: ExecutionPayloadEip7594, } impl From> for ExecutionPayload { @@ -265,6 +273,9 @@ impl ExecPayload for FullPayload { FullPayload::Electra(ref inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } + FullPayload::Eip7594(ref inner) => { + Ok(inner.execution_payload.withdrawals.tree_hash_root()) + } } } @@ -275,6 +286,7 @@ impl ExecPayload for FullPayload { } FullPayload::Deneb(ref inner) => Ok(inner.execution_payload.blob_gas_used), FullPayload::Electra(ref inner) => Ok(inner.execution_payload.blob_gas_used), + FullPayload::Eip7594(ref inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -305,6 +317,7 @@ impl FullPayload { ForkName::Capella => Ok(FullPayloadCapella::default().into()), ForkName::Deneb => Ok(FullPayloadDeneb::default().into()), ForkName::Electra => Ok(FullPayloadElectra::default().into()), + ForkName::Eip7594 => Ok(FullPayloadEip7594::default().into()), } } } @@ -397,6 +410,9 @@ impl<'b, E: EthSpec> ExecPayload for FullPayloadRef<'b, E> { FullPayloadRef::Electra(inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } + FullPayloadRef::Eip7594(inner) => { + Ok(inner.execution_payload.withdrawals.tree_hash_root()) + } } } @@ -407,6 +423,7 @@ impl<'b, E: EthSpec> ExecPayload for FullPayloadRef<'b, E> { } FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayloadRef::Electra(inner) => Ok(inner.execution_payload.blob_gas_used), + FullPayloadRef::Eip7594(inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -429,6 +446,7 @@ impl AbstractExecPayload for FullPayload { type Capella = FullPayloadCapella; type Deneb = FullPayloadDeneb; type Electra = FullPayloadElectra; + type Eip7594 = FullPayloadEip7594; } impl From> for FullPayload { @@ -447,7 +465,7 @@ impl TryFrom> for FullPayload { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Debug, @@ -492,6 +510,8 @@ pub struct BlindedPayload { pub execution_payload_header: ExecutionPayloadHeaderDeneb, #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] pub execution_payload_header: ExecutionPayloadHeaderElectra, + #[superstruct(only(Eip7594), partial_getter(rename = "execution_payload_eip7594"))] + pub execution_payload_header: ExecutionPayloadHeaderEip7594, } impl<'a, E: EthSpec> From> for BlindedPayload { @@ -577,6 +597,9 @@ impl ExecPayload for BlindedPayload { BlindedPayload::Electra(ref inner) => { Ok(inner.execution_payload_header.withdrawals_root) } + BlindedPayload::Eip7594(ref inner) => { + Ok(inner.execution_payload_header.withdrawals_root) + } } } @@ -587,6 +610,7 @@ impl ExecPayload for BlindedPayload { } BlindedPayload::Deneb(ref inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayload::Electra(ref inner) => Ok(inner.execution_payload_header.blob_gas_used), + BlindedPayload::Eip7594(ref inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -678,6 +702,9 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { BlindedPayloadRef::Electra(inner) => { Ok(inner.execution_payload_header.withdrawals_root) } + BlindedPayloadRef::Eip7594(inner) => { + Ok(inner.execution_payload_header.withdrawals_root) + } } } @@ -688,6 +715,7 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { } BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayloadRef::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used), + BlindedPayloadRef::Eip7594(inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -987,6 +1015,13 @@ impl_exec_payload_for_fork!( ExecutionPayloadElectra, Electra ); +impl_exec_payload_for_fork!( + BlindedPayloadEip7594, + FullPayloadEip7594, + ExecutionPayloadHeaderEip7594, + ExecutionPayloadEip7594, + Eip7594 +); impl AbstractExecPayload for BlindedPayload { type Ref<'a> = BlindedPayloadRef<'a, E>; @@ -994,6 +1029,7 @@ impl AbstractExecPayload for BlindedPayload { type Capella = BlindedPayloadCapella; type Deneb = BlindedPayloadDeneb; type Electra = BlindedPayloadElectra; + type Eip7594 = BlindedPayloadEip7594; } impl From> for BlindedPayload { @@ -1030,6 +1066,11 @@ impl From> for BlindedPayload { execution_payload_header, }) } + ExecutionPayloadHeader::Eip7594(execution_payload_header) => { + Self::Eip7594(BlindedPayloadEip7594 { + execution_payload_header, + }) + } } } } @@ -1049,6 +1090,9 @@ impl From> for ExecutionPayloadHeader { BlindedPayload::Electra(blinded_payload) => { ExecutionPayloadHeader::Electra(blinded_payload.execution_payload_header) } + BlindedPayload::Eip7594(blinded_payload) => { + ExecutionPayloadHeader::Eip7594(blinded_payload.execution_payload_header) + } } } } diff --git a/consensus/types/src/preset.rs b/consensus/types/src/preset.rs index a0cd61e0251..04e14ef56bd 100644 --- a/consensus/types/src/preset.rs +++ b/consensus/types/src/preset.rs @@ -214,13 +214,6 @@ pub struct DenebPreset { pub max_blob_commitments_per_block: u64, #[serde(with = "serde_utils::quoted_u64")] pub field_elements_per_blob: u64, - // EIP-7594 DAS presets - to be moved to the next fork - #[serde(with = "serde_utils::quoted_u64")] - pub field_elements_per_cell: u64, - #[serde(with = "serde_utils::quoted_u64")] - pub kzg_commitments_inclusion_proof_depth: u64, - #[serde(with = "serde_utils::quoted_u64")] - pub number_of_columns: u64, } impl DenebPreset { @@ -229,10 +222,28 @@ impl DenebPreset { max_blobs_per_block: E::max_blobs_per_block() as u64, max_blob_commitments_per_block: E::max_blob_commitments_per_block() as u64, field_elements_per_blob: E::field_elements_per_blob() as u64, + } + } +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub struct Eip7594Preset { + #[serde(with = "serde_utils::quoted_u64")] + pub field_elements_per_cell: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub field_elements_per_ext_blob: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub kzg_commitments_inclusion_proof_depth: u64, +} + +impl Eip7594Preset { + pub fn from_chain_spec(_spec: &ChainSpec) -> Self { + Self { field_elements_per_cell: E::field_elements_per_cell() as u64, + field_elements_per_ext_blob: E::field_elements_per_blob() as u64, kzg_commitments_inclusion_proof_depth: E::kzg_commitments_inclusion_proof_depth() as u64, - number_of_columns: E::number_of_columns() as u64, } } } diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index 4d3279a7f77..ea78262b951 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -37,7 +37,7 @@ impl From for Hash256 { /// A `BeaconBlock` and a signature from its proposer. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7594), variant_attributes( derive( Debug, @@ -80,6 +80,8 @@ pub struct SignedBeaconBlock = FullP pub message: BeaconBlockDeneb, #[superstruct(only(Electra), partial_getter(rename = "message_electra"))] pub message: BeaconBlockElectra, + #[superstruct(only(Eip7594), partial_getter(rename = "message_eip7594"))] + pub message: BeaconBlockEip7594, pub signature: Signature, } @@ -162,6 +164,9 @@ impl> SignedBeaconBlock BeaconBlock::Electra(message) => { SignedBeaconBlock::Electra(SignedBeaconBlockElectra { message, signature }) } + BeaconBlock::Eip7594(message) => { + SignedBeaconBlock::Eip7594(SignedBeaconBlockEip7594 { message, signature }) + } } } @@ -528,6 +533,62 @@ impl SignedBeaconBlockElectra> { } } +impl SignedBeaconBlockEip7594> { + pub fn into_full_block( + self, + execution_payload: ExecutionPayloadEip7594, + ) -> SignedBeaconBlockEip7594> { + let SignedBeaconBlockEip7594 { + message: + BeaconBlockEip7594 { + slot, + proposer_index, + parent_root, + state_root, + body: + BeaconBlockBodyEip7594 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: BlindedPayloadEip7594 { .. }, + bls_to_execution_changes, + blob_kzg_commitments, + }, + }, + signature, + } = self; + SignedBeaconBlockEip7594 { + message: BeaconBlockEip7594 { + slot, + proposer_index, + parent_root, + state_root, + body: BeaconBlockBodyEip7594 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadEip7594 { execution_payload }, + bls_to_execution_changes, + blob_kzg_commitments, + }, + }, + signature, + } + } +} + impl SignedBeaconBlock> { pub fn try_into_full_block( self, @@ -548,12 +609,16 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Electra(block), Some(ExecutionPayload::Electra(payload))) => { SignedBeaconBlock::Electra(block.into_full_block(payload)) } + (SignedBeaconBlock::Eip7594(block), Some(ExecutionPayload::Eip7594(payload))) => { + SignedBeaconBlock::Eip7594(block.into_full_block(payload)) + } // avoid wildcard matching forks so that compiler will // direct us here when a new fork has been added (SignedBeaconBlock::Bellatrix(_), _) => return None, (SignedBeaconBlock::Capella(_), _) => return None, (SignedBeaconBlock::Deneb(_), _) => return None, (SignedBeaconBlock::Electra(_), _) => return None, + (SignedBeaconBlock::Eip7594(_), _) => return None, }; Some(full_block) } @@ -699,6 +764,9 @@ pub mod ssz_tagged_signed_beacon_block { ForkName::Electra => Ok(SignedBeaconBlock::Electra( SignedBeaconBlockElectra::from_ssz_bytes(body)?, )), + ForkName::Eip7594 => Ok(SignedBeaconBlock::Eip7594( + SignedBeaconBlockEip7594::from_ssz_bytes(body)?, + )), } } } diff --git a/consensus/types/src/voluntary_exit.rs b/consensus/types/src/voluntary_exit.rs index 4c7c16757ed..c1c3f1dfa96 100644 --- a/consensus/types/src/voluntary_exit.rs +++ b/consensus/types/src/voluntary_exit.rs @@ -46,7 +46,9 @@ impl VoluntaryExit { spec.fork_version_for_name(fork_name) } // EIP-7044 - ForkName::Deneb | ForkName::Electra => spec.fork_version_for_name(ForkName::Capella), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { + spec.fork_version_for_name(ForkName::Capella) + } }; let domain = spec.compute_domain(Domain::VoluntaryExit, fork_version, genesis_validators_root); diff --git a/lcli/src/create_payload_header.rs b/lcli/src/create_payload_header.rs index 974a34591f0..6960452d952 100644 --- a/lcli/src/create_payload_header.rs +++ b/lcli/src/create_payload_header.rs @@ -6,8 +6,8 @@ use std::io::Write; use std::time::{SystemTime, UNIX_EPOCH}; use types::{ EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, - ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, - ForkName, + ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7594, + ExecutionPayloadHeaderElectra, ForkName, }; pub fn run(matches: &ArgMatches) -> Result<(), String> { @@ -57,6 +57,14 @@ pub fn run(matches: &ArgMatches) -> Result<(), String> { prev_randao: eth1_block_hash.into_root(), ..ExecutionPayloadHeaderElectra::default() }), + ForkName::Eip7594 => ExecutionPayloadHeader::Eip7594(ExecutionPayloadHeaderEip7594 { + gas_limit, + base_fee_per_gas, + timestamp: genesis_time, + block_hash: eth1_block_hash, + prev_randao: eth1_block_hash.into_root(), + ..ExecutionPayloadHeaderEip7594::default() + }), }; let mut file = File::create(file_name).map_err(|_| "Unable to create file".to_string())?; diff --git a/lcli/src/main.rs b/lcli/src/main.rs index 7b5c1598c9e..baa99422cf6 100644 --- a/lcli/src/main.rs +++ b/lcli/src/main.rs @@ -433,7 +433,7 @@ fn main() { .takes_value(true) .default_value("bellatrix") .help("The fork for which the execution payload header should be created.") - .possible_values(&["bellatrix", "capella", "deneb", "electra"]) + .possible_values(&["bellatrix", "capella", "deneb", "electra", "eip7594"]) ) ) .subcommand( @@ -627,6 +627,15 @@ fn main() { "The epoch at which to enable the Electra hard fork", ), ) + .arg( + Arg::with_name("eip7594-fork-epoch") + .long("eip7594-fork-epoch") + .value_name("EPOCH") + .takes_value(true) + .help( + "The epoch at which to enable the Eip7594 hard fork", + ), + ) .arg( Arg::with_name("ttd") .long("ttd") diff --git a/lcli/src/new_testnet.rs b/lcli/src/new_testnet.rs index f6bfb2ac013..fb3148d27df 100644 --- a/lcli/src/new_testnet.rs +++ b/lcli/src/new_testnet.rs @@ -18,13 +18,13 @@ use std::io::Read; use std::path::PathBuf; use std::str::FromStr; use std::time::{SystemTime, UNIX_EPOCH}; -use types::ExecutionBlockHash; use types::{ test_utils::generate_deterministic_keypairs, Address, BeaconState, ChainSpec, Config, Epoch, Eth1Data, EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ForkName, Hash256, Keypair, PublicKey, Validator, }; +use types::{ExecutionBlockHash, ExecutionPayloadHeaderEip7594}; pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> { let deposit_contract_address: Address = parse_required(matches, "deposit-contract-address")?; @@ -130,6 +130,10 @@ pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Resul ExecutionPayloadHeaderElectra::::from_ssz_bytes(bytes.as_slice()) .map(ExecutionPayloadHeader::Electra) } + ForkName::Eip7594 => { + ExecutionPayloadHeaderEip7594::::from_ssz_bytes(bytes.as_slice()) + .map(ExecutionPayloadHeader::Eip7594) + } } .map_err(|e| format!("SSZ decode failed: {:?}", e)) }) diff --git a/lcli/src/parse_ssz.rs b/lcli/src/parse_ssz.rs index e86ffb73dc2..416bec3c9fb 100644 --- a/lcli/src/parse_ssz.rs +++ b/lcli/src/parse_ssz.rs @@ -88,6 +88,11 @@ pub fn run_parse_ssz( SignedBeaconBlockElectra::::from_ssz_bytes, format, )?, + "SignedBeaconBlockEip7594" => decode_and_print( + &bytes, + SignedBeaconBlockEip7594::::from_ssz_bytes, + format, + )?, "BeaconState" => decode_and_print::>( &bytes, |bytes| BeaconState::from_ssz_bytes(bytes, spec), @@ -111,6 +116,9 @@ pub fn run_parse_ssz( "BeaconStateElectra" => { decode_and_print(&bytes, BeaconStateElectra::::from_ssz_bytes, format)? } + "BeaconStateEip7594" => { + decode_and_print(&bytes, BeaconStateEip7594::::from_ssz_bytes, format)? + } "BlobSidecar" => decode_and_print(&bytes, BlobSidecar::::from_ssz_bytes, format)?, other => return Err(format!("Unknown type: {}", other)), }; diff --git a/testing/ef_tests/src/cases/common.rs b/testing/ef_tests/src/cases/common.rs index 6763edbe22b..d59e6c1f2bc 100644 --- a/testing/ef_tests/src/cases/common.rs +++ b/testing/ef_tests/src/cases/common.rs @@ -67,6 +67,7 @@ pub fn previous_fork(fork_name: ForkName) -> ForkName { ForkName::Capella => ForkName::Bellatrix, ForkName::Deneb => ForkName::Capella, ForkName::Electra => ForkName::Deneb, + ForkName::Eip7594 => ForkName::Deneb, } } diff --git a/testing/ef_tests/src/cases/epoch_processing.rs b/testing/ef_tests/src/cases/epoch_processing.rs index c4c592e4cf2..f985cfc0bdc 100644 --- a/testing/ef_tests/src/cases/epoch_processing.rs +++ b/testing/ef_tests/src/cases/epoch_processing.rs @@ -108,7 +108,8 @@ impl EpochTransition for JustificationAndFinalization { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => { initialize_progressive_balances_cache(state, spec)?; let justification_and_finalization_state = altair::process_justification_and_finalization(state)?; @@ -131,7 +132,8 @@ impl EpochTransition for RewardsAndPenalties { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_rewards_and_penalties_slow(state, spec), + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => altair::process_rewards_and_penalties_slow(state, spec), } } } @@ -164,7 +166,8 @@ impl EpochTransition for Slashings { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => { process_slashings_slow(state, spec)?; } }; @@ -214,9 +217,10 @@ impl EpochTransition for HistoricalRootsUpdate { impl EpochTransition for HistoricalSummariesUpdate { fn run(state: &mut BeaconState, _spec: &ChainSpec) -> Result<(), EpochProcessingError> { match state { - BeaconState::Capella(_) | BeaconState::Deneb(_) | BeaconState::Electra(_) => { - process_historical_summaries_update(state) - } + BeaconState::Capella(_) + | BeaconState::Deneb(_) + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => process_historical_summaries_update(state), _ => Ok(()), } } @@ -240,7 +244,8 @@ impl EpochTransition for SyncCommitteeUpdates { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_sync_committee_updates(state, spec), + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => altair::process_sync_committee_updates(state, spec), } } } @@ -253,7 +258,8 @@ impl EpochTransition for InactivityUpdates { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_inactivity_updates_slow(state, spec), + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => altair::process_inactivity_updates_slow(state, spec), } } } @@ -266,7 +272,8 @@ impl EpochTransition for ParticipationFlagUpdates { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_participation_flag_updates(state), + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => altair::process_participation_flag_updates(state), } } } @@ -317,7 +324,7 @@ impl> Case for EpochProcessing { T::name() != "participation_record_updates" && T::name() != "historical_summaries_update" } - ForkName::Capella | ForkName::Deneb | ForkName::Electra => { + ForkName::Capella | ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => { T::name() != "participation_record_updates" && T::name() != "historical_roots_update" } diff --git a/testing/ef_tests/src/cases/fork.rs b/testing/ef_tests/src/cases/fork.rs index 132cfb4c0ae..8b2c9c0a793 100644 --- a/testing/ef_tests/src/cases/fork.rs +++ b/testing/ef_tests/src/cases/fork.rs @@ -5,7 +5,7 @@ use crate::decode::{ssz_decode_state, yaml_decode_file}; use serde::Deserialize; use state_processing::upgrade::{ upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_deneb, - upgrade_to_electra, + upgrade_to_eip7594, upgrade_to_electra, }; use types::BeaconState; @@ -69,6 +69,7 @@ impl Case for ForkTest { ForkName::Capella => upgrade_to_capella(&mut result_state, spec).map(|_| result_state), ForkName::Deneb => upgrade_to_deneb(&mut result_state, spec).map(|_| result_state), ForkName::Electra => upgrade_to_electra(&mut result_state, spec).map(|_| result_state), + ForkName::Eip7594 => upgrade_to_eip7594(&mut result_state, spec).map(|_| result_state), }; compare_beacon_state_results_without_caches(&mut result, &mut expected) diff --git a/testing/ef_tests/src/cases/merkle_proof_validity.rs b/testing/ef_tests/src/cases/merkle_proof_validity.rs index 8d5c0687753..9925bee8828 100644 --- a/testing/ef_tests/src/cases/merkle_proof_validity.rs +++ b/testing/ef_tests/src/cases/merkle_proof_validity.rs @@ -3,7 +3,8 @@ use crate::decode::{ssz_decode_file, ssz_decode_state, yaml_decode_file}; use serde::Deserialize; use tree_hash::Hash256; use types::{ - BeaconBlockBody, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconState, FullPayload, + BeaconBlockBody, BeaconBlockBodyDeneb, BeaconBlockBodyEip7594, BeaconBlockBodyElectra, + BeaconState, FullPayload, }; #[derive(Debug, Clone, Deserialize)] @@ -105,6 +106,10 @@ impl LoadCase for KzgInclusionMerkleProofValidity { ssz_decode_file::>(&path.join("object.ssz_snappy"))? .into() } + ForkName::Eip7594 => { + ssz_decode_file::>(&path.join("object.ssz_snappy"))? + .into() + } }; let merkle_proof = yaml_decode_file(&path.join("proof.yaml"))?; // Metadata does not exist in these tests but it is left like this just in case. diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index 158f2334dc3..b993203883a 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -102,7 +102,8 @@ impl Operation for Attestation { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::Eip7594(_) => { initialize_progressive_balances_cache(state, spec)?; altair_deneb::process_attestation( state, diff --git a/testing/ef_tests/src/cases/transition.rs b/testing/ef_tests/src/cases/transition.rs index dc5029d53e7..460ec60d9e8 100644 --- a/testing/ef_tests/src/cases/transition.rs +++ b/testing/ef_tests/src/cases/transition.rs @@ -60,6 +60,13 @@ impl LoadCase for TransitionTest { spec.deneb_fork_epoch = Some(Epoch::new(0)); spec.electra_fork_epoch = Some(metadata.fork_epoch); } + ForkName::Eip7594 => { + spec.altair_fork_epoch = Some(Epoch::new(0)); + spec.bellatrix_fork_epoch = Some(Epoch::new(0)); + spec.capella_fork_epoch = Some(Epoch::new(0)); + spec.deneb_fork_epoch = Some(Epoch::new(0)); + spec.eip7594_fork_epoch = Some(metadata.fork_epoch); + } } // Load blocks diff --git a/testing/ef_tests/src/handler.rs b/testing/ef_tests/src/handler.rs index 2d5ea4149ef..85d035bd226 100644 --- a/testing/ef_tests/src/handler.rs +++ b/testing/ef_tests/src/handler.rs @@ -22,7 +22,7 @@ pub trait Handler { // unspecified forks. // TODO(electra): Enable Electra once spec tests are available. fn disabled_forks(&self) -> Vec { - vec![ForkName::Electra] + vec![ForkName::Electra, ForkName::Eip7594] } fn is_enabled_for_fork(&self, fork_name: ForkName) -> bool { diff --git a/validator_client/src/beacon_node_fallback.rs b/validator_client/src/beacon_node_fallback.rs index 4467b807865..eab4594c281 100644 --- a/validator_client/src/beacon_node_fallback.rs +++ b/validator_client/src/beacon_node_fallback.rs @@ -314,6 +314,14 @@ impl CandidateBeaconNode { "endpoint_electra_fork_epoch" => ?beacon_node_spec.electra_fork_epoch, "hint" => UPDATE_REQUIRED_LOG_HINT, ); + } else if beacon_node_spec.eip7594_fork_epoch != spec.eip7594_fork_epoch { + warn!( + log, + "Beacon node has mismatched EIP7594 fork epoch"; + "endpoint" => %self.beacon_node, + "eip7594_fork_epoch" => ?beacon_node_spec.eip7594_fork_epoch, + "hint" => UPDATE_REQUIRED_LOG_HINT, + ); } Ok(()) diff --git a/validator_client/src/signing_method/web3signer.rs b/validator_client/src/signing_method/web3signer.rs index 8ad37a1620a..b95b6e2e185 100644 --- a/validator_client/src/signing_method/web3signer.rs +++ b/validator_client/src/signing_method/web3signer.rs @@ -29,6 +29,7 @@ pub enum ForkName { Capella, Deneb, Electra, + Eip7594, } #[derive(Debug, PartialEq, Serialize)] @@ -107,6 +108,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> Web3SignerObject<'a, E, Pa block: None, block_header: Some(block.block_header()), }), + BeaconBlock::Eip7594(_) => Ok(Web3SignerObject::BeaconBlock { + version: ForkName::Eip7594, + block: None, + block_header: Some(block.block_header()), + }), } } diff --git a/validator_client/src/validator_store.rs b/validator_client/src/validator_store.rs index f3bdc2c0f69..928cab7bb9b 100644 --- a/validator_client/src/validator_store.rs +++ b/validator_client/src/validator_store.rs @@ -369,7 +369,7 @@ impl ValidatorStore { } } // EIP-7044 - ForkName::Deneb | ForkName::Electra => SigningContext { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7594 => SigningContext { domain, epoch: signing_epoch, fork: Fork {