diff --git a/Makefile b/Makefile index f621f38a63..d58553fe88 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,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 fulu +FORKS=phase0 altair bellatrix capella deneb electra eip7805 fulu # Extra flags for Cargo CARGO_INSTALL_EXTRA_FLAGS?= diff --git a/beacon_node/beacon_chain/src/beacon_block_streamer.rs b/beacon_node/beacon_chain/src/beacon_block_streamer.rs index e37a69040d..5339b12826 100644 --- a/beacon_node/beacon_chain/src/beacon_block_streamer.rs +++ b/beacon_node/beacon_chain/src/beacon_block_streamer.rs @@ -15,8 +15,8 @@ use types::{ SignedBlindedBeaconBlock, Slot, }; use types::{ - ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadElectra, - ExecutionPayloadFulu, ExecutionPayloadHeader, + ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadEip7805, + ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadHeader, }; #[derive(PartialEq)] @@ -100,6 +100,7 @@ fn reconstruct_default_header_block( ForkName::Capella => ExecutionPayloadCapella::default().into(), ForkName::Deneb => ExecutionPayloadDeneb::default().into(), ForkName::Electra => ExecutionPayloadElectra::default().into(), + ForkName::Eip7805 => ExecutionPayloadEip7805::default().into(), ForkName::Fulu => ExecutionPayloadFulu::default().into(), ForkName::Base | ForkName::Altair => { return Err(Error::PayloadReconstruction(format!( @@ -717,12 +718,13 @@ mod tests { #[tokio::test] async fn check_all_blocks_from_altair_to_fulu() { let slots_per_epoch = MinimalEthSpec::slots_per_epoch() as usize; - let num_epochs = 12; + let num_epochs = 14; let bellatrix_fork_epoch = 2usize; let capella_fork_epoch = 4usize; let deneb_fork_epoch = 6usize; let electra_fork_epoch = 8usize; - let fulu_fork_epoch = 10usize; + let eip7805_fork_epoch = 10usize; + let fulu_fork_epoch = 12usize; let num_blocks_produced = num_epochs * slots_per_epoch; let mut spec = test_spec::(); @@ -731,6 +733,7 @@ mod tests { spec.capella_fork_epoch = Some(Epoch::new(capella_fork_epoch as u64)); spec.deneb_fork_epoch = Some(Epoch::new(deneb_fork_epoch as u64)); spec.electra_fork_epoch = Some(Epoch::new(electra_fork_epoch as u64)); + spec.eip7805_fork_epoch = Some(Epoch::new(eip7805_fork_epoch as u64)); spec.fulu_fork_epoch = Some(Epoch::new(fulu_fork_epoch as u64)); let spec = Arc::new(spec); diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index cf64c4086b..0f376c0ec4 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5912,6 +5912,48 @@ impl BeaconChain { execution_payload_value, ) } + BeaconState::Eip7805(_) => { + let ( + payload, + kzg_commitments, + maybe_blobs_and_proofs, + maybe_requests, + execution_payload_value, + ) = block_contents + .ok_or(BlockProductionError::MissingExecutionPayload)? + .deconstruct(); + + ( + BeaconBlock::Eip7805(BeaconBlockEip7805 { + slot, + proposer_index, + parent_root, + state_root: Hash256::zero(), + body: BeaconBlockBodyEip7805 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings: proposer_slashings.into(), + attester_slashings: attester_slashings_electra.into(), + attestations: attestations_electra.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::InvalidPayloadFork)?, + execution_requests: maybe_requests + .ok_or(BlockProductionError::MissingExecutionRequests)?, + }, + }), + maybe_blobs_and_proofs, + execution_payload_value, + ) + } BeaconState::Fulu(_) => { let ( payload, diff --git a/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs b/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs index 60ac165162..2134d78138 100644 --- a/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs +++ b/beacon_node/beacon_chain/src/beacon_fork_choice_store.rs @@ -15,11 +15,11 @@ use std::marker::PhantomData; use std::sync::Arc; use store::{Error as StoreError, HotColdDB, ItemStore}; use superstruct::superstruct; +use tracing::info; use types::{ AbstractExecPayload, BeaconBlockRef, BeaconState, BeaconStateError, Checkpoint, Epoch, EthSpec, FixedBytesExtended, Hash256, Slot, }; -use tracing::info; #[derive(Debug)] pub enum Error { diff --git a/beacon_node/beacon_chain/src/eip7805_readiness.rs b/beacon_node/beacon_chain/src/eip7805_readiness.rs new file mode 100644 index 0000000000..2250ab3281 --- /dev/null +++ b/beacon_node/beacon_chain/src/eip7805_readiness.rs @@ -0,0 +1,122 @@ +//! Provides tools for checking if a node is ready for the Electra upgrade and following merge +//! transition. + +use crate::{BeaconChain, BeaconChainTypes}; +use execution_layer::http::{ + ENGINE_GET_INCLUSION_LIST_V1, ENGINE_GET_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V4, +}; +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::time::Duration; +use types::*; + +/// The time before the eip7805 fork when we will start issuing warnings about preparation. +use super::bellatrix_readiness::SECONDS_IN_A_WEEK; +pub const EIP7805_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 Eip7805Readiness { + /// The execution engine is eip7805-enabled (as far as we can tell) + Ready, + /// We are connected to an execution engine which doesn't support the V4 engine api methods + V4MethodsNotSupported { 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 Eip7805Readiness { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Eip7805Readiness::Ready => { + write!(f, "This node appears ready for Eip7805.") + } + Eip7805Readiness::ExchangeCapabilitiesFailed { error } => write!( + f, + "Could not exchange capabilities with the \ + execution endpoint: {}", + error + ), + Eip7805Readiness::NoExecutionEndpoint => write!( + f, + "The --execution-endpoint flag is not specified, this is a \ + requirement post-merge" + ), + Eip7805Readiness::V4MethodsNotSupported { error } => write!( + f, + "Execution endpoint does not support eip7805 methods: {}", + error + ), + } + } +} + +impl BeaconChain { + /// Returns `true` if eip7805 epoch is set and Eip7805 fork has occurred or will + /// occur within `EIP7805_READINESS_PREPARATION_SECONDS` + pub fn is_time_to_prepare_for_eip7805(&self, current_slot: Slot) -> bool { + if let Some(eip7805_epoch) = self.spec.eip7805_fork_epoch { + let eip7805_slot = eip7805_epoch.start_slot(T::EthSpec::slots_per_epoch()); + let eip7805_readiness_preparation_slots = + EIP7805_READINESS_PREPARATION_SECONDS / self.spec.seconds_per_slot; + // Return `true` if eip7805 has happened or is within the preparation time. + current_slot + eip7805_readiness_preparation_slots > eip7805_slot + } else { + // The Electra 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 eip7805. + pub async fn check_eip7805_readiness(&self) -> Eip7805Readiness { + 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 + Eip7805Readiness::ExchangeCapabilitiesFailed { + error: format!("{:?}", e), + } + } + Ok(capabilities) => { + let mut missing_methods = String::from("Required Methods Unsupported:"); + let mut all_good = true; + if !capabilities.get_payload_v4 { + missing_methods.push(' '); + missing_methods.push_str(ENGINE_GET_PAYLOAD_V4); + all_good = false; + } + if !capabilities.new_payload_v4 { + missing_methods.push(' '); + missing_methods.push_str(ENGINE_NEW_PAYLOAD_V4); + all_good = false; + } + if !capabilities.get_inclusion_list_v1 { + missing_methods.push(' '); + missing_methods.push_str(ENGINE_GET_INCLUSION_LIST_V1); + all_good = false; + } + + if all_good { + Eip7805Readiness::Ready + } else { + Eip7805Readiness::V4MethodsNotSupported { + error: missing_methods, + } + } + } + } + } else { + Eip7805Readiness::NoExecutionEndpoint + } + } +} diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index c7c6f2dd58..8328726b21 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -24,7 +24,7 @@ use state_processing::per_block_processing::{ }; use std::sync::Arc; use tokio::task::JoinHandle; -use tracing::{debug, warn, info}; +use tracing::{debug, info, warn}; use tree_hash::TreeHash; use types::payload::BlockProductionVersion; use types::*; diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index fa29a6ea7d..1e87677634 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 eip7805_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 c67f4418f8..fb44587fe9 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -512,6 +512,10 @@ where spec.electra_fork_epoch.map(|epoch| { genesis_time + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() }); + mock.server.execution_block_generator().eip7805_time = + spec.eip7805_fork_epoch.map(|epoch| { + genesis_time + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() + }); mock.server.execution_block_generator().osaka_time = spec.fulu_fork_epoch.map(|epoch| { genesis_time + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() }); @@ -649,6 +653,9 @@ pub fn mock_execution_layer_from_parts( let prague_time = spec.electra_fork_epoch.map(|epoch| { HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() }); + let eip7805_time = spec.eip7805_fork_epoch.map(|epoch| { + HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() + }); let osaka_time = spec.fulu_fork_epoch.map(|epoch| { HARNESS_GENESIS_TIME + spec.seconds_per_slot * E::slots_per_epoch() * epoch.as_u64() }); @@ -661,6 +668,7 @@ pub fn mock_execution_layer_from_parts( shanghai_time, cancun_time, prague_time, + eip7805_time, osaka_time, Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), spec, diff --git a/beacon_node/beacon_chain/tests/block_verification.rs b/beacon_node/beacon_chain/tests/block_verification.rs index 3dc46be16e..a23aedde2e 100644 --- a/beacon_node/beacon_chain/tests/block_verification.rs +++ b/beacon_node/beacon_chain/tests/block_verification.rs @@ -801,6 +801,11 @@ async fn invalid_signature_attester_slashing() { .push(attester_slashing.as_electra().unwrap().clone()) .expect("should update attester slashing"); } + BeaconBlockBodyRefMut::Eip7805(ref mut blk) => { + blk.attester_slashings + .push(attester_slashing.as_electra().unwrap().clone()) + .expect("should update attester slashing"); + } BeaconBlockBodyRefMut::Fulu(ref mut blk) => { blk.attester_slashings .push(attester_slashing.as_electra().unwrap().clone()) @@ -861,6 +866,10 @@ async fn invalid_signature_attestation() { .attestations .get_mut(0) .map(|att| att.signature = junk_aggregate_signature()), + BeaconBlockBodyRefMut::Eip7805(ref mut blk) => blk + .attestations + .get_mut(0) + .map(|att| att.signature = junk_aggregate_signature()), BeaconBlockBodyRefMut::Fulu(ref mut blk) => blk .attestations .get_mut(0) diff --git a/beacon_node/beacon_chain/tests/store_tests.rs b/beacon_node/beacon_chain/tests/store_tests.rs index 38ff87d0c8..9cf628433f 100644 --- a/beacon_node/beacon_chain/tests/store_tests.rs +++ b/beacon_node/beacon_chain/tests/store_tests.rs @@ -166,6 +166,7 @@ async fn light_client_bootstrap_test() { LightClientBootstrap::Capella(lc_bootstrap) => lc_bootstrap.header.beacon.slot, LightClientBootstrap::Deneb(lc_bootstrap) => lc_bootstrap.header.beacon.slot, LightClientBootstrap::Electra(lc_bootstrap) => lc_bootstrap.header.beacon.slot, + LightClientBootstrap::Eip7805(lc_bootstrap) => lc_bootstrap.header.beacon.slot, LightClientBootstrap::Fulu(lc_bootstrap) => lc_bootstrap.header.beacon.slot, }; diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index d103d48dfb..ddfefdb970 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, + eip7805_readiness::Eip7805Readiness, electra_readiness::ElectraReadiness, fulu_readiness::FuluReadiness, BeaconChain, BeaconChainTypes, ExecutionStatus, @@ -314,6 +315,7 @@ pub fn spawn_notifier( capella_readiness_logging(current_slot, &beacon_chain).await; deneb_readiness_logging(current_slot, &beacon_chain).await; electra_readiness_logging(current_slot, &beacon_chain).await; + eip7805_readiness_logging(current_slot, &beacon_chain).await; fulu_readiness_logging(current_slot, &beacon_chain).await; } }; @@ -566,6 +568,59 @@ async fn electra_readiness_logging( } } +/// Provides some helpful logging to users to indicate if their node is ready for Eip7805. +async fn eip7805_readiness_logging( + current_slot: Slot, + beacon_chain: &BeaconChain, +) { + let eip7805_completed = beacon_chain + .canonical_head + .cached_head() + .snapshot + .beacon_state + .fork_name_unchecked() + .eip7805_enabled(); + + let has_execution_layer = beacon_chain.execution_layer.is_some(); + + if eip7805_completed && has_execution_layer + || !beacon_chain.is_time_to_prepare_for_electra(current_slot) + { + return; + } + + if eip7805_completed && !has_execution_layer { + // When adding a new fork, add a check for the next fork readiness here. + error!( + info = "you need a Eip7805 enabled execution engine to validate blocks.", + "Execution endpoint required" + ); + return; + } + + match beacon_chain.check_eip7805_readiness().await { + Eip7805Readiness::Ready => { + info!( + info = + "ensure the execution endpoint is updated to the latest eip7805 release", + "Ready for Eip7805" + ) + } + readiness @ Eip7805Readiness::ExchangeCapabilitiesFailed { error: _ } => { + error!( + hint = "the execution endpoint may be offline", + info = %readiness, + "Not ready for Eip7805Readiness" + ) + } + readiness => warn!( + hint = "try updating the execution endpoint", + info = %readiness, + "Not ready for Eip7805Readiness" + ), + } +} + /// Provides some helpful logging to users to indicate if their node is ready for Fulu. async fn fulu_readiness_logging( current_slot: Slot, diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 9d56588c83..11f62ee328 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -25,7 +25,8 @@ pub use types::{ }; use types::{ ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionRequests, KzgProofs, + ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionRequests, + KzgProofs, }; use types::{Graffiti, GRAFFITI_BYTES_LEN}; @@ -36,7 +37,8 @@ mod new_payload_request; pub use new_payload_request::{ NewPayloadRequest, NewPayloadRequestBellatrix, NewPayloadRequestCapella, - NewPayloadRequestDeneb, NewPayloadRequestElectra, NewPayloadRequestFulu, + NewPayloadRequestDeneb, NewPayloadRequestEip7805, NewPayloadRequestElectra, + NewPayloadRequestFulu, }; pub const LATEST_TAG: &str = "latest"; @@ -269,7 +271,7 @@ pub struct ProposeBlindedBlockResponse { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes(derive(Clone, Debug, PartialEq),), map_into(ExecutionPayload), map_ref_into(ExecutionPayloadRef), @@ -289,14 +291,16 @@ pub struct GetPayloadResponse { pub execution_payload: ExecutionPayloadDeneb, #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] pub execution_payload: ExecutionPayloadElectra, + #[superstruct(only(Eip7805), partial_getter(rename = "execution_payload_eip7805"))] + pub execution_payload: ExecutionPayloadEip7805, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload: ExecutionPayloadFulu, pub block_value: Uint256, - #[superstruct(only(Deneb, Electra, Fulu))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu))] pub blobs_bundle: BlobsBundle, - #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))] pub should_override_builder: bool, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub requests: ExecutionRequests, } @@ -364,6 +368,12 @@ impl From> Some(inner.blobs_bundle), Some(inner.requests), ), + GetPayloadResponse::Eip7805(inner) => ( + ExecutionPayload::Eip7805(inner.execution_payload), + inner.block_value, + Some(inner.blobs_bundle), + Some(inner.requests), + ), GetPayloadResponse::Fulu(inner) => ( ExecutionPayload::Fulu(inner.execution_payload), inner.block_value, @@ -503,6 +513,34 @@ impl ExecutionPayloadBodyV1 { )) } } + ExecutionPayloadHeader::Eip7805(header) => { + if let Some(withdrawals) = self.withdrawals { + Ok(ExecutionPayload::Eip7805(ExecutionPayloadEip7805 { + 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 + )) + } + } ExecutionPayloadHeader::Fulu(header) => { if let Some(withdrawals) = self.withdrawals { Ok(ExecutionPayload::Fulu(ExecutionPayloadFulu { diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index fd69987344..c848940502 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -849,23 +849,23 @@ impl HttpJsonRpc { Ok(response.into()) } - pub async fn new_payload_v5_fulu( + pub async fn new_payload_v5_eip7805( &self, - new_payload_request_fulu: NewPayloadRequestFulu<'_, E>, + new_payload_request_eip7805: NewPayloadRequestEip7805<'_, E>, ) -> Result { // TODO(focil) clean this up? let mut il_transactions = vec![]; - for transaction in new_payload_request_fulu.il_transactions { + for transaction in new_payload_request_eip7805.il_transactions { if let Ok(hex_tx) = String::from_utf8(transaction.into()).map(|v| format!("0x{}", v)) { il_transactions.push(hex_tx); } } let params = json!([ - JsonExecutionPayload::V5(new_payload_request_fulu.execution_payload.clone().into()), - new_payload_request_fulu.versioned_hashes, - new_payload_request_fulu.parent_beacon_block_root, - new_payload_request_fulu + JsonExecutionPayload::V5(new_payload_request_eip7805.execution_payload.clone().into()), + new_payload_request_eip7805.versioned_hashes, + new_payload_request_eip7805.parent_beacon_block_root, + new_payload_request_eip7805 .execution_requests .get_execution_requests_list(), il_transactions @@ -882,6 +882,40 @@ impl HttpJsonRpc { Ok(response.into()) } + pub async fn new_payload_v5_fulu( + &self, + new_payload_request_fulu: NewPayloadRequestFulu<'_, E>, + ) -> Result { + unreachable!("new payload fulu"); + // // TODO(focil) clean this up? + // let mut il_transactions = vec![]; + // for transaction in new_payload_request_fulu.il_transactions { + // if let Ok(hex_tx) = String::from_utf8(transaction.into()).map(|v| format!("0x{}", v)) { + // il_transactions.push(hex_tx); + // } + // } + + // let params = json!([ + // JsonExecutionPayload::V5(new_payload_request_fulu.execution_payload.clone().into()), + // new_payload_request_fulu.versioned_hashes, + // new_payload_request_fulu.parent_beacon_block_root, + // new_payload_request_fulu + // .execution_requests + // .get_execution_requests_list(), + // il_transactions + // ]); + + // let response: JsonPayloadStatusV1 = self + // .rpc_request( + // ENGINE_NEW_PAYLOAD_V5, + // params, + // ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier, + // ) + // .await?; + + // Ok(response.into()) + } + pub async fn get_payload_v1( &self, payload_id: PayloadId, @@ -1019,7 +1053,7 @@ impl HttpJsonRpc { let params = json!([JsonPayloadIdRequest::from(payload_id)]); match fork_name { - ForkName::Fulu => { + ForkName::Fulu | ForkName::Eip7805 => { let response: JsonGetPayloadResponseV5 = self .rpc_request( ENGINE_GET_PAYLOAD_V5, @@ -1305,6 +1339,14 @@ impl HttpJsonRpc { Err(Error::RequiredMethodUnsupported("engine_newPayloadV4")) } } + NewPayloadRequest::Eip7805(new_payload_request_eip7805) => { + if engine_capabilities.new_payload_v5 { + self.new_payload_v5_eip7805(new_payload_request_eip7805) + .await + } else { + Err(Error::RequiredMethodUnsupported("engine_newPayloadV5")) + } + } NewPayloadRequest::Fulu(new_payload_request_fulu) => { if engine_capabilities.new_payload_v5 { self.new_payload_v5_fulu(new_payload_request_fulu).await @@ -1347,6 +1389,13 @@ impl HttpJsonRpc { Err(Error::RequiredMethodUnsupported("engine_getPayloadv4")) } } + ForkName::Eip7805 => { + if engine_capabilities.get_payload_v5 { + self.get_payload_v5(fork_name, payload_id).await + } else { + Err(Error::RequiredMethodUnsupported("engine_getPayloadv5")) + } + } ForkName::Fulu => { // TODO(fulu): switch to v5 when the EL is ready if engine_capabilities.get_payload_v4 { 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 96615297d8..705bbf6ae2 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -214,8 +214,8 @@ impl From> for JsonExecutionPayloadV4 } } -impl From> for JsonExecutionPayloadV5 { - fn from(payload: ExecutionPayloadFulu) -> Self { +impl From> for JsonExecutionPayloadV5 { + fn from(payload: ExecutionPayloadEip7805) -> Self { JsonExecutionPayloadV5 { parent_hash: payload.parent_hash, fee_recipient: payload.fee_recipient, @@ -250,7 +250,8 @@ 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::Fulu(payload) => JsonExecutionPayload::V5(payload.into()), + ExecutionPayload::Eip7805(payload) => JsonExecutionPayload::V5(payload.into()), + ExecutionPayload::Fulu(_) => unreachable!("DONT USE FULU"), } } } @@ -360,9 +361,9 @@ impl From> for ExecutionPayloadElectra } } -impl From> for ExecutionPayloadFulu { +impl From> for ExecutionPayloadEip7805 { fn from(payload: JsonExecutionPayloadV5) -> Self { - ExecutionPayloadFulu { + ExecutionPayloadEip7805 { parent_hash: payload.parent_hash, fee_recipient: payload.fee_recipient, state_root: payload.state_root, @@ -396,7 +397,7 @@ impl From> for ExecutionPayload { JsonExecutionPayload::V2(payload) => ExecutionPayload::Capella(payload.into()), JsonExecutionPayload::V3(payload) => ExecutionPayload::Deneb(payload.into()), JsonExecutionPayload::V4(payload) => ExecutionPayload::Electra(payload.into()), - JsonExecutionPayload::V5(payload) => ExecutionPayload::Fulu(payload.into()), + JsonExecutionPayload::V5(payload) => ExecutionPayload::Eip7805(payload.into()), } } } @@ -549,7 +550,7 @@ impl TryFrom> for GetPayloadResponse { })) } JsonGetPayloadResponse::V5(response) => { - Ok(GetPayloadResponse::Fulu(GetPayloadResponseFulu { + Ok(GetPayloadResponse::Eip7805(GetPayloadResponseEip7805 { execution_payload: response.execution_payload.into(), block_value: response.block_value, blobs_bundle: response.blobs_bundle.into(), 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 c622d34855..c286dacda2 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, ExecutionPayloadFulu, ExecutionRequests, + ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionRequests, }; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes(derive(Clone, Debug, PartialEq),), map_into(ExecutionPayload), map_ref_into(ExecutionPayloadRef), @@ -39,15 +39,17 @@ 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(Eip7805), partial_getter(rename = "execution_payload_eip7805"))] + pub execution_payload: &'block ExecutionPayloadEip7805, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload: &'block ExecutionPayloadFulu, - #[superstruct(only(Deneb, Electra, Fulu))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu))] pub versioned_hashes: Vec, - #[superstruct(only(Deneb, Electra, Fulu))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu))] pub parent_beacon_block_root: Hash256, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub execution_requests: &'block ExecutionRequests, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Eip7805, Fulu))] pub il_transactions: InclusionListTransactions, } @@ -58,6 +60,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::Eip7805(payload) => payload.execution_payload.parent_hash, Self::Fulu(payload) => payload.execution_payload.parent_hash, } } @@ -68,6 +71,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::Eip7805(payload) => payload.execution_payload.block_hash, Self::Fulu(payload) => payload.execution_payload.block_hash, } } @@ -78,6 +82,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::Eip7805(payload) => payload.execution_payload.block_number, Self::Fulu(payload) => payload.execution_payload.block_number, } } @@ -88,6 +93,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::Eip7805(request) => ExecutionPayloadRef::Eip7805(request.execution_payload), Self::Fulu(request) => ExecutionPayloadRef::Fulu(request.execution_payload), } } @@ -100,6 +106,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::Eip7805(request) => ExecutionPayload::Eip7805(request.execution_payload.clone()), Self::Fulu(request) => ExecutionPayload::Fulu(request.execution_payload.clone()), } } @@ -204,6 +211,17 @@ impl<'a, E: EthSpec> NewPayloadRequest<'a, E> { .collect(), parent_beacon_block_root: block_ref.parent_root, execution_requests: &block_ref.body.execution_requests, + })), + BeaconBlockRef::Eip7805(block_ref) => Ok(Self::Eip7805(NewPayloadRequestEip7805 { + 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, + execution_requests: &block_ref.body.execution_requests, il_transactions, })), BeaconBlockRef::Fulu(block_ref) => Ok(Self::Fulu(NewPayloadRequestFulu { @@ -248,7 +266,6 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> .collect(), parent_beacon_block_root: block_ref.parent_root, })), - // TODO(focil) need to clean up this conversion BeaconBlockRef::Electra(block_ref) => Ok(Self::Electra(NewPayloadRequestElectra { execution_payload: &block_ref.body.execution_payload.execution_payload, versioned_hashes: block_ref @@ -259,6 +276,17 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> .collect(), parent_beacon_block_root: block_ref.parent_root, execution_requests: &block_ref.body.execution_requests, + })), + BeaconBlockRef::Eip7805(block_ref) => Ok(Self::Eip7805(NewPayloadRequestEip7805 { + 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, + execution_requests: &block_ref.body.execution_requests, il_transactions: vec![].into(), })), BeaconBlockRef::Fulu(block_ref) => Ok(Self::Fulu(NewPayloadRequestFulu { @@ -292,6 +320,7 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<' })), ExecutionPayloadRef::Deneb(_) => Err(Self::Error::IncorrectStateVariant), ExecutionPayloadRef::Electra(_) => Err(Self::Error::IncorrectStateVariant), + ExecutionPayloadRef::Eip7805(_) => Err(Self::Error::IncorrectStateVariant), ExecutionPayloadRef::Fulu(_) => Err(Self::Error::IncorrectStateVariant), } } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index ef60cca0f9..e2b3b125bf 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -55,8 +55,9 @@ use types::{ }; use types::{ BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix, - ExecutionPayloadCapella, ExecutionPayloadElectra, ExecutionPayloadFulu, FullPayload, - InclusionListTransactions, ProposerPreparationData, PublicKeyBytes, Signature, Slot, + ExecutionPayloadCapella, ExecutionPayloadEip7805, ExecutionPayloadElectra, + ExecutionPayloadFulu, FullPayload, InclusionListTransactions, ProposerPreparationData, + PublicKeyBytes, Signature, Slot, }; mod block_hash; @@ -124,6 +125,13 @@ impl TryFrom> for ProvenancedPayload BlockProposalContents::PayloadAndBlobs { + payload: ExecutionPayloadHeader::Eip7805(builder_bid.header).into(), + block_value: builder_bid.value, + kzg_commitments: builder_bid.blob_kzg_commitments, + blobs_and_proofs: None, + requests: Some(builder_bid.execution_requests), + }, BuilderBid::Fulu(builder_bid) => BlockProposalContents::PayloadAndBlobs { payload: ExecutionPayloadHeader::Fulu(builder_bid.header).into(), block_value: builder_bid.value, @@ -1832,6 +1840,7 @@ impl ExecutionLayer { ForkName::Capella => ExecutionPayloadCapella::default().into(), ForkName::Deneb => ExecutionPayloadDeneb::default().into(), ForkName::Electra => ExecutionPayloadElectra::default().into(), + ForkName::Eip7805 => ExecutionPayloadEip7805::default().into(), ForkName::Fulu => ExecutionPayloadFulu::default().into(), ForkName::Base | ForkName::Altair => { return Err(Error::InvalidForkForPayload); 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 81fb9bd7b8..d0b3c12885 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 @@ -19,9 +19,9 @@ use tree_hash::TreeHash; use tree_hash_derive::TreeHash; use types::{ Blob, ChainSpec, EthSpec, ExecutionBlockHash, ExecutionPayload, ExecutionPayloadBellatrix, - ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, - ExecutionPayloadHeader, FixedBytesExtended, ForkName, Hash256, Transaction, Transactions, - Uint256, + ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadEip7805, + ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadHeader, FixedBytesExtended, + ForkName, Hash256, Transaction, Transactions, Uint256, }; use super::DEFAULT_TERMINAL_BLOCK; @@ -147,6 +147,7 @@ pub struct ExecutionBlockGenerator { pub shanghai_time: Option, // capella pub cancun_time: Option, // deneb pub prague_time: Option, // electra + pub eip7805_time: Option, // eip7805 pub osaka_time: Option, // fulu /* * deneb stuff @@ -172,6 +173,7 @@ impl ExecutionBlockGenerator { shanghai_time: Option, cancun_time: Option, prague_time: Option, + eip7805_time: Option, osaka_time: Option, spec: Arc, kzg: Option>, @@ -190,6 +192,7 @@ impl ExecutionBlockGenerator { shanghai_time, cancun_time, prague_time, + eip7805_time, osaka_time, blobs_bundles: <_>::default(), kzg, @@ -242,13 +245,16 @@ impl ExecutionBlockGenerator { pub fn get_fork_at_timestamp(&self, timestamp: u64) -> ForkName { match self.osaka_time { Some(fork_time) if timestamp >= fork_time => ForkName::Fulu, - _ => match self.prague_time { - Some(fork_time) if timestamp >= fork_time => ForkName::Electra, - _ => match self.cancun_time { - Some(fork_time) if timestamp >= fork_time => ForkName::Deneb, - _ => match self.shanghai_time { - Some(fork_time) if timestamp >= fork_time => ForkName::Capella, - _ => ForkName::Bellatrix, + _ => match self.eip7805_time { + Some(fork_time) if timestamp >= fork_time => ForkName::Eip7805, + _ => match self.prague_time { + Some(fork_time) if timestamp >= fork_time => ForkName::Electra, + _ => match self.cancun_time { + Some(fork_time) if timestamp >= fork_time => ForkName::Deneb, + _ => match self.shanghai_time { + Some(fork_time) if timestamp >= fork_time => ForkName::Capella, + _ => ForkName::Bellatrix, + }, }, }, }, @@ -674,6 +680,25 @@ impl ExecutionBlockGenerator { blob_gas_used: 0, excess_blob_gas: 0, }), + ForkName::Eip7805 => ExecutionPayload::Eip7805(ExecutionPayloadEip7805 { + 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: DEFAULT_GAS_LIMIT, + gas_used: GAS_USED, + timestamp: pa.timestamp, + extra_data: mock_el_extra_data::(), + base_fee_per_gas: Uint256::from(1u64), + block_hash: ExecutionBlockHash::zero(), + transactions: vec![].into(), + withdrawals: pa.withdrawals.clone().into(), + blob_gas_used: 0, + excess_blob_gas: 0, + }), ForkName::Fulu => ExecutionPayload::Fulu(ExecutionPayloadFulu { parent_hash: head_block_hash, fee_recipient: pa.suggested_fee_recipient, @@ -844,6 +869,12 @@ pub fn generate_genesis_header( *header.transactions_root_mut() = empty_transactions_root; Some(header) } + ForkName::Eip7805 => { + let mut header = ExecutionPayloadHeader::Eip7805(<_>::default()); + *header.block_hash_mut() = genesis_block_hash.unwrap_or_default(); + *header.transactions_root_mut() = empty_transactions_root; + Some(header) + } ForkName::Fulu => { let mut header = ExecutionPayloadHeader::Fulu(<_>::default()); *header.block_hash_mut() = genesis_block_hash.unwrap_or_default(); @@ -923,6 +954,7 @@ mod test { None, None, None, + None, spec, None, ); 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 ba022b155f..9b997afb0a 100644 --- a/beacon_node/execution_layer/src/test_utils/handle_rpc.rs +++ b/beacon_node/execution_layer/src/test_utils/handle_rpc.rs @@ -229,6 +229,44 @@ pub async fn handle_rpc( )); } } + ForkName::Eip7805 => { + if method == ENGINE_NEW_PAYLOAD_V1 + || method == ENGINE_NEW_PAYLOAD_V2 + || method == ENGINE_NEW_PAYLOAD_V3 + { + return Err(( + format!("{} called after Electra fork!", method), + GENERIC_ERROR_CODE, + )); + } + if matches!(request, JsonExecutionPayload::V1(_)) { + return Err(( + format!( + "{} called with `ExecutionPayloadV1` after Electra fork!", + method + ), + GENERIC_ERROR_CODE, + )); + } + if matches!(request, JsonExecutionPayload::V2(_)) { + return Err(( + format!( + "{} called with `ExecutionPayloadV2` after Electra fork!", + method + ), + GENERIC_ERROR_CODE, + )); + } + if matches!(request, JsonExecutionPayload::V3(_)) { + return Err(( + format!( + "{} called with `ExecutionPayloadV3` after Electra fork!", + method + ), + GENERIC_ERROR_CODE, + )); + } + } ForkName::Fulu => { if method == ENGINE_NEW_PAYLOAD_V1 || method == ENGINE_NEW_PAYLOAD_V2 @@ -488,7 +526,23 @@ pub async fn handle_rpc( }) .unwrap() } - _ => unreachable!(), + JsonExecutionPayload::V4(execution_payload) => { + serde_json::to_value(JsonGetPayloadResponseV4 { + execution_payload, + block_value: Uint256::from(DEFAULT_MOCK_EL_PAYLOAD_VALUE_WEI), + blobs_bundle: maybe_blobs + .ok_or(( + "No blobs returned despite V4 Payload".to_string(), + GENERIC_ERROR_CODE, + ))? + .into(), + should_override_builder: false, + // TODO(electra): add EL requests in mock el + execution_requests: Default::default(), + }) + .unwrap() + } + other => unreachable!("check {:?}", other), }), _ => unreachable!(), } @@ -588,7 +642,7 @@ pub async fn handle_rpc( )); } } - ForkName::Deneb | ForkName::Electra | ForkName::Fulu => { + ForkName::Deneb | ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => { 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 fba34121a7..7a6298d6a9 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -26,8 +26,8 @@ use tokio_stream::StreamExt; use tracing::{debug, error, info, warn}; use tree_hash::TreeHash; use types::builder_bid::{ - BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidElectra, - BuilderBidFulu, SignedBuilderBid, + BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidEip7805, + BuilderBidElectra, BuilderBidFulu, SignedBuilderBid, }; use types::{ Address, BeaconState, ChainSpec, Epoch, EthSpec, ExecPayload, ExecutionPayload, @@ -112,6 +112,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.fee_recipient = fee_recipient; } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.fee_recipient = fee_recipient; + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.fee_recipient = fee_recipient; } @@ -132,6 +135,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.gas_limit = gas_limit; } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.gas_limit = gas_limit; + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.gas_limit = gas_limit; } @@ -156,6 +162,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.parent_hash = ExecutionBlockHash::from_root(parent_hash); } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.parent_hash = ExecutionBlockHash::from_root(parent_hash); + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.parent_hash = ExecutionBlockHash::from_root(parent_hash); } @@ -176,6 +185,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.prev_randao = prev_randao; } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.prev_randao = prev_randao; + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.prev_randao = prev_randao; } @@ -196,6 +208,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.block_number = block_number; } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.block_number = block_number; + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.block_number = block_number; } @@ -216,6 +231,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.timestamp = timestamp; } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.timestamp = timestamp; + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.timestamp = timestamp; } @@ -236,6 +254,9 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.withdrawals_root = withdrawals_root; } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.withdrawals_root = withdrawals_root; + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.withdrawals_root = withdrawals_root; } @@ -268,6 +289,10 @@ impl BidStuff for BuilderBid { header.extra_data = extra_data; header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root()); } + ExecutionPayloadHeaderRefMut::Eip7805(header) => { + header.extra_data = extra_data; + header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root()); + } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.extra_data = extra_data; header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root()); @@ -454,6 +479,9 @@ impl MockBuilder { SignedBlindedBeaconBlock::Electra(block) => { block.message.body.execution_payload.tree_hash_root() } + SignedBlindedBeaconBlock::Eip7805(block) => { + block.message.body.execution_payload.tree_hash_root() + } SignedBlindedBeaconBlock::Fulu(block) => { block.message.body.execution_payload.tree_hash_root() } @@ -552,6 +580,18 @@ impl MockBuilder { pubkey: self.builder_sk.public_key().compress(), execution_requests: maybe_requests.unwrap_or_default(), }), + ForkName::Eip7805 => BuilderBid::Eip7805(BuilderBidEip7805 { + header: payload + .as_eip7805() + .map_err(|_| "incorrect payload variant".to_string())? + .into(), + blob_kzg_commitments: maybe_blobs_bundle + .map(|b| b.commitments) + .unwrap_or_default(), + value: self.get_bid_value(value), + pubkey: self.builder_sk.public_key().compress(), + execution_requests: maybe_requests.unwrap_or_default(), + }), ForkName::Electra => BuilderBid::Electra(BuilderBidElectra { header: payload .as_electra() @@ -845,13 +885,15 @@ impl MockBuilder { expected_withdrawals, None, ), - ForkName::Deneb | ForkName::Electra | ForkName::Fulu => PayloadAttributes::new( - timestamp, - *prev_randao, - fee_recipient, - expected_withdrawals, - Some(head_block_root), - ), + ForkName::Deneb | ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => { + PayloadAttributes::new( + timestamp, + *prev_randao, + fee_recipient, + expected_withdrawals, + Some(head_block_root), + ) + } ForkName::Base | ForkName::Altair => { return Err("invalid fork".to_string()); } diff --git a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs index cbe5e3ae98..ed27cff9ab 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_execution_layer.rs @@ -29,6 +29,7 @@ impl MockExecutionLayer { None, None, None, + None, Some(JwtKey::from_slice(&DEFAULT_JWT_SECRET).unwrap()), Arc::new(spec), None, @@ -42,6 +43,7 @@ impl MockExecutionLayer { shanghai_time: Option, cancun_time: Option, prague_time: Option, + eip7805_time: Option, osaka_time: Option, jwt_key: Option, spec: Arc, @@ -59,6 +61,7 @@ impl MockExecutionLayer { shanghai_time, cancun_time, prague_time, + eip7805_time, osaka_time, spec.clone(), kzg, diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 342b313bbb..7978c60069 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -86,6 +86,7 @@ pub struct MockExecutionConfig { pub shanghai_time: Option, pub cancun_time: Option, pub prague_time: Option, + pub eip7805_time: Option, pub osaka_time: Option, } @@ -100,6 +101,7 @@ impl Default for MockExecutionConfig { shanghai_time: None, cancun_time: None, prague_time: None, + eip7805_time: None, osaka_time: None, } } @@ -123,6 +125,7 @@ impl MockServer { None, // FIXME(capella): should this be the default? None, // FIXME(deneb): should this be the default? None, // FIXME(electra): should this be the default? + None, None, // FIXME(fulu): should this be the default? chain_spec, None, @@ -145,6 +148,7 @@ impl MockServer { shanghai_time, cancun_time, prague_time, + eip7805_time, osaka_time, } = config; let last_echo_request = Arc::new(RwLock::new(None)); @@ -156,6 +160,7 @@ impl MockServer { shanghai_time, cancun_time, prague_time, + eip7805_time, osaka_time, spec, kzg, @@ -220,6 +225,7 @@ impl MockServer { shanghai_time: Option, cancun_time: Option, prague_time: Option, + eip7805_time: Option, osaka_time: Option, spec: Arc, kzg: Option>, @@ -235,6 +241,7 @@ impl MockServer { shanghai_time, cancun_time, prague_time, + eip7805_time, osaka_time, }, spec, diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index dca5fd00e9..828b1613a7 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -7420,6 +7420,7 @@ async fn create_signed_inclusion_lists() { config.spec.capella_fork_epoch = Some(Epoch::new(0)); config.spec.deneb_fork_epoch = Some(Epoch::new(0)); config.spec.electra_fork_epoch = Some(Epoch::new(0)); + config.spec.eip7805_fork_epoch = Some(Epoch::new(0)); ApiTester::new_from_config(config) .await .test_create_inclusion_lists() @@ -7434,6 +7435,7 @@ async fn test_post_validator_duties_inclusion_list() { config.spec.capella_fork_epoch = Some(Epoch::new(0)); config.spec.deneb_fork_epoch = Some(Epoch::new(0)); config.spec.electra_fork_epoch = Some(Epoch::new(0)); + config.spec.eip7805_fork_epoch = Some(Epoch::new(0)); ApiTester::new_from_config(config) .await .test_post_validator_duties_inclusion_list() diff --git a/beacon_node/lighthouse_network/src/rpc/codec.rs b/beacon_node/lighthouse_network/src/rpc/codec.rs index a6c8efd6a6..6e6c6a1dd3 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec.rs @@ -20,7 +20,8 @@ use types::{ LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate, LightClientUpdate, RuntimeVariableList, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, - SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBeaconBlockFulu, + SignedBeaconBlockDeneb, SignedBeaconBlockEip7805, SignedBeaconBlockElectra, + SignedBeaconBlockFulu, }; use unsigned_varint::codec::Uvi; @@ -462,6 +463,9 @@ fn context_bytes( SignedBeaconBlock::Fulu { .. } => { fork_context.to_context_bytes(ForkName::Fulu) } + SignedBeaconBlock::Eip7805 { .. } => { + fork_context.to_context_bytes(ForkName::Eip7805) + } SignedBeaconBlock::Electra { .. } => { fork_context.to_context_bytes(ForkName::Electra) } @@ -858,6 +862,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::Eip7805) => Ok(Some(RpcSuccessResponse::BlocksByRange(Arc::new( + SignedBeaconBlock::Eip7805(SignedBeaconBlockEip7805::from_ssz_bytes( + decoded_buffer, + )?), + )))), Some(ForkName::Fulu) => Ok(Some(RpcSuccessResponse::BlocksByRange(Arc::new( SignedBeaconBlock::Fulu(SignedBeaconBlockFulu::from_ssz_bytes(decoded_buffer)?), )))), @@ -894,6 +903,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::Eip7805) => Ok(Some(RpcSuccessResponse::BlocksByRoot(Arc::new( + SignedBeaconBlock::Eip7805(SignedBeaconBlockEip7805::from_ssz_bytes( + decoded_buffer, + )?), + )))), Some(ForkName::Fulu) => Ok(Some(RpcSuccessResponse::BlocksByRoot(Arc::new( SignedBeaconBlock::Fulu(SignedBeaconBlockFulu::from_ssz_bytes(decoded_buffer)?), )))), @@ -949,13 +963,15 @@ mod tests { let capella_fork_epoch = Epoch::new(3); let deneb_fork_epoch = Epoch::new(4); let electra_fork_epoch = Epoch::new(5); - let fulu_fork_epoch = Epoch::new(6); + let eip7805_fork_epoch = Epoch::new(6); + let fulu_fork_epoch = Epoch::new(7); 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.eip7805_fork_epoch = Some(eip7805_fork_epoch); chain_spec.fulu_fork_epoch = Some(fulu_fork_epoch); let current_slot = match fork_name { @@ -965,6 +981,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::Eip7805 => eip7805_fork_epoch.start_slot(Spec::slots_per_epoch()), ForkName::Fulu => fulu_fork_epoch.start_slot(Spec::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) @@ -1445,6 +1462,16 @@ mod tests { Ok(Some(RpcSuccessResponse::BlobsByRoot(empty_blob_sidecar()))), ); + assert_eq!( + encode_then_decode_response( + SupportedProtocol::BlobsByRootV1, + RpcResponse::Success(RpcSuccessResponse::BlobsByRoot(empty_blob_sidecar())), + ForkName::Eip7805, + &chain_spec + ), + Ok(Some(RpcSuccessResponse::BlobsByRoot(empty_blob_sidecar()))), + ); + assert_eq!( encode_then_decode_response( SupportedProtocol::BlobsByRootV1, @@ -1483,6 +1510,20 @@ mod tests { ))), ); + assert_eq!( + encode_then_decode_response( + SupportedProtocol::DataColumnsByRangeV1, + RpcResponse::Success(RpcSuccessResponse::DataColumnsByRange( + empty_data_column_sidecar() + )), + ForkName::Eip7805, + &chain_spec + ), + Ok(Some(RpcSuccessResponse::DataColumnsByRange( + empty_data_column_sidecar() + ))), + ); + assert_eq!( encode_then_decode_response( SupportedProtocol::DataColumnsByRangeV1, @@ -1525,6 +1566,20 @@ mod tests { ))), ); + assert_eq!( + encode_then_decode_response( + SupportedProtocol::DataColumnsByRootV1, + RpcResponse::Success(RpcSuccessResponse::DataColumnsByRoot( + empty_data_column_sidecar() + )), + ForkName::Eip7805, + &chain_spec + ), + Ok(Some(RpcSuccessResponse::DataColumnsByRoot( + empty_data_column_sidecar() + ))), + ); + assert_eq!( encode_then_decode_response( SupportedProtocol::DataColumnsByRootV1, diff --git a/beacon_node/lighthouse_network/src/rpc/protocol.rs b/beacon_node/lighthouse_network/src/rpc/protocol.rs index eac7d67490..524a639538 100644 --- a/beacon_node/lighthouse_network/src/rpc/protocol.rs +++ b/beacon_node/lighthouse_network/src/rpc/protocol.rs @@ -167,7 +167,7 @@ fn rpc_light_client_updates_by_range_limits_by_fork(current_fork: ForkName) -> R ForkName::Deneb => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_DENEB_MAX) } - ForkName::Electra | ForkName::Fulu => { + ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_ELECTRA_MAX) } } @@ -187,7 +187,7 @@ fn rpc_light_client_finality_update_limits_by_fork(current_fork: ForkName) -> Rp ForkName::Deneb => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_DENEB_MAX) } - ForkName::Electra | ForkName::Fulu => { + ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_ELECTRA_MAX) } } @@ -208,7 +208,7 @@ fn rpc_light_client_optimistic_update_limits_by_fork(current_fork: ForkName) -> ForkName::Deneb => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_OPTIMISTIC_UPDATE_DENEB_MAX) } - ForkName::Electra | ForkName::Fulu => RpcLimits::new( + ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => RpcLimits::new( altair_fixed_len, *LIGHT_CLIENT_OPTIMISTIC_UPDATE_ELECTRA_MAX, ), @@ -225,7 +225,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 | ForkName::Fulu => { + ForkName::Electra | ForkName::Eip7805 | ForkName::Fulu => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_ELECTRA_MAX) } } diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index fd734c36c9..57a22caba5 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -12,10 +12,10 @@ use types::{ LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing, SignedAggregateAndProof, SignedAggregateAndProofBase, SignedAggregateAndProofElectra, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, - SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, - SignedBeaconBlockFulu, SignedBlsToExecutionChange, SignedContributionAndProof, - SignedInclusionList, SignedVoluntaryExit, SingleAttestation, SubnetId, SyncCommitteeMessage, - SyncSubnetId, + SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockEip7805, + SignedBeaconBlockElectra, SignedBeaconBlockFulu, SignedBlsToExecutionChange, + SignedContributionAndProof, SignedInclusionList, SignedVoluntaryExit, SingleAttestation, + SubnetId, SyncCommitteeMessage, SyncSubnetId, }; #[derive(Debug, Clone, PartialEq)] @@ -251,6 +251,10 @@ impl PubsubMessage { SignedBeaconBlockElectra::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, ), + Some(ForkName::Eip7805) => SignedBeaconBlock::::Eip7805( + SignedBeaconBlockEip7805::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?, + ), Some(ForkName::Fulu) => SignedBeaconBlock::::Fulu( SignedBeaconBlockFulu::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, diff --git a/beacon_node/lighthouse_network/tests/common.rs b/beacon_node/lighthouse_network/tests/common.rs index d686885ff7..42624c4731 100644 --- a/beacon_node/lighthouse_network/tests/common.rs +++ b/beacon_node/lighthouse_network/tests/common.rs @@ -26,13 +26,15 @@ 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 fulu_fork_epoch = Epoch::new(6); + let eip7805_fork_epoch = Epoch::new(6); + let fulu_fork_epoch = Epoch::new(7); 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.eip7805_fork_epoch = Some(eip7805_fork_epoch); chain_spec.fulu_fork_epoch = Some(fulu_fork_epoch); let current_slot = match fork_name { @@ -42,6 +44,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::Eip7805 => eip7805_fork_epoch.start_slot(E::slots_per_epoch()), ForkName::Fulu => fulu_fork_epoch.start_slot(E::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) diff --git a/beacon_node/src/lib.rs b/beacon_node/src/lib.rs index a7f92434ce..2275470bfc 100644 --- a/beacon_node/src/lib.rs +++ b/beacon_node/src/lib.rs @@ -228,6 +228,7 @@ mod test { spec.bellatrix_fork_epoch = Some(Epoch::new(256)); spec.deneb_fork_epoch = Some(Epoch::new(257)); spec.electra_fork_epoch = None; + spec.eip7805_fork_epoch = None; spec.fulu_fork_epoch = None; let result = validator_fork_epochs(&spec); assert_eq!( diff --git a/beacon_node/store/src/impls/execution_payload.rs b/beacon_node/store/src/impls/execution_payload.rs index 097b069a66..b832324d86 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::{ EthSpec, ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, - ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, + ExecutionPayloadDeneb, ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, }; 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!(ExecutionPayloadEip7805); impl_store_item!(ExecutionPayloadFulu); /// This fork-agnostic implementation should be only used for writing. @@ -45,17 +46,21 @@ impl StoreItem for ExecutionPayload { ExecutionPayloadFulu::from_ssz_bytes(bytes) .map(Self::Fulu) .or_else(|_| { - ExecutionPayloadElectra::from_ssz_bytes(bytes) - .map(Self::Electra) + ExecutionPayloadEip7805::from_ssz_bytes(bytes) + .map(Self::Eip7805) .or_else(|_| { - ExecutionPayloadDeneb::from_ssz_bytes(bytes) - .map(Self::Deneb) + ExecutionPayloadElectra::from_ssz_bytes(bytes) + .map(Self::Electra) .or_else(|_| { - ExecutionPayloadCapella::from_ssz_bytes(bytes) - .map(Self::Capella) + ExecutionPayloadDeneb::from_ssz_bytes(bytes) + .map(Self::Deneb) .or_else(|_| { - ExecutionPayloadBellatrix::from_ssz_bytes(bytes) - .map(Self::Bellatrix) + ExecutionPayloadCapella::from_ssz_bytes(bytes) + .map(Self::Capella) + .or_else(|_| { + ExecutionPayloadBellatrix::from_ssz_bytes(bytes) + .map(Self::Bellatrix) + }) }) }) }) diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index d209512159..2e8082517f 100644 --- a/beacon_node/store/src/partial_beacon_state.rs +++ b/beacon_node/store/src/partial_beacon_state.rs @@ -16,7 +16,7 @@ use types::*; /// /// This can be deleted once schema versions prior to V22 are no longer supported. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes(derive(Debug, PartialEq, Clone, Encode, Decode)) )] #[derive(Debug, PartialEq, Clone, Encode)] @@ -68,9 +68,9 @@ where pub current_epoch_attestations: List, E::MaxPendingAttestations>, // Participation (Altair and later) - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] pub current_epoch_participation: List, // Finality @@ -80,13 +80,13 @@ where pub finalized_checkpoint: Checkpoint, // Inactivity - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] pub inactivity_scores: List, // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] pub next_sync_committee: Arc>, // Execution @@ -110,6 +110,11 @@ where partial_getter(rename = "latest_execution_payload_header_electra") )] pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, + #[superstruct( + only(Eip7805), + partial_getter(rename = "latest_execution_payload_header_eip7805") + )] + pub latest_execution_payload_header: ExecutionPayloadHeaderEip7805, #[superstruct( only(Fulu), partial_getter(rename = "latest_execution_payload_header_fulu") @@ -117,35 +122,35 @@ where pub latest_execution_payload_header: ExecutionPayloadHeaderFulu, // Capella - #[superstruct(only(Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu))] pub next_withdrawal_validator_index: u64, #[ssz(skip_serializing, skip_deserializing)] - #[superstruct(only(Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu))] pub historical_summaries: Option>, // Electra - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub deposit_requests_start_index: u64, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub deposit_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub exit_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub earliest_exit_epoch: Epoch, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub consolidation_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub earliest_consolidation_epoch: Epoch, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub pending_deposits: List, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub pending_partial_withdrawals: List, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub pending_consolidations: List, } @@ -423,6 +428,31 @@ impl TryInto> for PartialBeaconState { ], [historical_summaries] ), + PartialBeaconState::Eip7805(inner) => impl_try_into_beacon_state!( + inner, + Eip7805, + BeaconStateEip7805, + [ + 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, + deposit_requests_start_index, + deposit_balance_to_consume, + exit_balance_to_consume, + earliest_exit_epoch, + consolidation_balance_to_consume, + earliest_consolidation_epoch, + pending_deposits, + pending_partial_withdrawals, + pending_consolidations + ], + [historical_summaries] + ), PartialBeaconState::Fulu(inner) => impl_try_into_beacon_state!( inner, Fulu, diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index 716288be72..4cffbb776c 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -1071,6 +1071,9 @@ impl ForkVersionDeserialize for SsePayloadAttributes { ForkName::Electra => serde_json::from_value(value) .map(Self::V3) .map_err(serde::de::Error::custom), + ForkName::Eip7805 => serde_json::from_value(value) + .map(Self::V3) + .map_err(serde::de::Error::custom), ForkName::Fulu => serde_json::from_value(value) .map(Self::V3) .map_err(serde::de::Error::custom), 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 9ff5a16198..c986b1f496 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 @@ -44,6 +44,9 @@ DENEB_FORK_EPOCH: 889856 # 2024-03-11T18:30:20.000Z # Electra ELECTRA_FORK_VERSION: 0x05000064 ELECTRA_FORK_EPOCH: 18446744073709551615 +# eip7805 +EIP7805_FORK_VERSION: 0x06000000 +EIP7805_FORK_EPOCH: 18446744073709551615 # Fulu FULU_FORK_VERSION: 0x06000064 FULU_FORK_EPOCH: 18446744073709551615 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 74fe727867..5f25bb936a 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 @@ -50,6 +50,9 @@ DENEB_FORK_EPOCH: 269568 # March 13, 2024, 01:55:35pm UTC # Electra ELECTRA_FORK_VERSION: 0x05000000 ELECTRA_FORK_EPOCH: 18446744073709551615 +# eip7805 +EIP7805_FORK_VERSION: 0x06000000 +EIP7805_FORK_EPOCH: 18446744073709551615 # Fulu FULU_FORK_VERSION: 0x06000000 FULU_FORK_EPOCH: 18446744073709551615 diff --git a/consensus/proto_array/src/proto_array.rs b/consensus/proto_array/src/proto_array.rs index 2d05941eb6..ec08006a8e 100644 --- a/consensus/proto_array/src/proto_array.rs +++ b/consensus/proto_array/src/proto_array.rs @@ -6,11 +6,11 @@ use ssz::Encode; use ssz_derive::{Decode, Encode}; use std::collections::{HashMap, HashSet}; use superstruct::superstruct; +use tracing::info; use types::{ AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, FixedBytesExtended, Hash256, Slot, }; -use tracing::info; // Define a "legacy" implementation of `Option` which uses four bytes for encoding the union // selector. diff --git a/consensus/state_processing/src/genesis.rs b/consensus/state_processing/src/genesis.rs index 10723ecc51..40e3995ecd 100644 --- a/consensus/state_processing/src/genesis.rs +++ b/consensus/state_processing/src/genesis.rs @@ -2,6 +2,7 @@ use super::per_block_processing::{ errors::BlockProcessingError, process_operations::apply_deposit, }; use crate::common::DepositDataTree; +use crate::upgrade::eip7805::upgrade_state_to_eip7805; use crate::upgrade::electra::upgrade_state_to_electra; use crate::upgrade::{ upgrade_to_altair, upgrade_to_bellatrix, upgrade_to_capella, upgrade_to_deneb, upgrade_to_fulu, @@ -140,6 +141,34 @@ pub fn initialize_beacon_state_from_eth1( } } + // Upgrade to eip7805 if configured from genesis. + if spec + .eip7805_fork_epoch + .is_some_and(|fork_epoch| fork_epoch == E::genesis_epoch()) + { + let post = upgrade_state_to_eip7805(&mut state, Epoch::new(0), Epoch::new(0), spec)?; + state = post; + + // Remove intermediate Deneb fork from `state.fork`. + state.fork_mut().previous_version = spec.electra_fork_version; + + // TODO(electra): think about this more and determine the best way to + // do this. The spec tests will expect that the sync committees are + // calculated using the electra value for MAX_EFFECTIVE_BALANCE when + // calling `initialize_beacon_state_from_eth1()`. But the sync committees + // are actually calcuated back in `upgrade_to_altair()`. We need to + // re-calculate the sync committees here now that the state is `Electra` + let sync_committee = Arc::new(state.get_next_sync_committee(spec)?); + *state.current_sync_committee_mut()? = sync_committee.clone(); + *state.next_sync_committee_mut()? = sync_committee; + + // Override latest execution payload header. + // See https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#testing + if let Some(ExecutionPayloadHeader::Eip7805(ref header)) = execution_payload_header { + *state.latest_execution_payload_header_eip7805_mut()? = header.clone(); + } + } + // Upgrade to fulu if configured from genesis. if spec .fulu_fork_epoch diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index ef4799c245..79b92972a0 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -444,6 +444,12 @@ pub fn process_execution_payload>( _ => return Err(BlockProcessingError::IncorrectStateType), } } + ExecutionPayloadHeaderRefMut::Eip7805(header_mut) => { + match payload.to_execution_payload_header() { + ExecutionPayloadHeader::Eip7805(header) => *header_mut = header, + _ => return Err(BlockProcessingError::IncorrectStateType), + } + } ExecutionPayloadHeaderRefMut::Fulu(header_mut) => { match payload.to_execution_payload_header() { ExecutionPayloadHeader::Fulu(header) => *header_mut = header, diff --git a/consensus/state_processing/src/per_slot_processing.rs b/consensus/state_processing/src/per_slot_processing.rs index af1cce602c..e5091db179 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_fulu, + upgrade_to_eip7805, upgrade_to_electra, upgrade_to_fulu, }; 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)?; } + // Eip7805. + if spec.eip7805_fork_epoch == Some(state.current_epoch()) { + upgrade_to_eip7805(state, spec)?; + } // Fulu. if spec.fulu_fork_epoch == Some(state.current_epoch()) { diff --git a/consensus/state_processing/src/upgrade.rs b/consensus/state_processing/src/upgrade.rs index 88bc87849f..286b982bc7 100644 --- a/consensus/state_processing/src/upgrade.rs +++ b/consensus/state_processing/src/upgrade.rs @@ -2,6 +2,7 @@ pub mod altair; pub mod bellatrix; pub mod capella; pub mod deneb; +pub mod eip7805; pub mod electra; pub mod fulu; @@ -9,5 +10,6 @@ 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 eip7805::upgrade_to_eip7805; pub use electra::upgrade_to_electra; pub use fulu::upgrade_to_fulu; diff --git a/consensus/state_processing/src/upgrade/eip7805.rs b/consensus/state_processing/src/upgrade/eip7805.rs new file mode 100644 index 0000000000..1a675ad343 --- /dev/null +++ b/consensus/state_processing/src/upgrade/eip7805.rs @@ -0,0 +1,173 @@ +use bls::Signature; +use itertools::Itertools; +use safe_arith::SafeArith; +use std::mem; +use types::{ + BeaconState, BeaconStateEip7805, BeaconStateError as Error, ChainSpec, Epoch, EpochCache, + EthSpec, Fork, PendingDeposit, +}; + +/// Transform a `Deneb` state into an `Electra` state. +pub fn upgrade_to_eip7805( + pre_state: &mut BeaconState, + spec: &ChainSpec, +) -> Result<(), Error> { + let epoch = pre_state.current_epoch(); + + let activation_exit_epoch = spec.compute_activation_exit_epoch(epoch)?; + let earliest_exit_epoch = pre_state + .validators() + .iter() + .filter(|v| v.exit_epoch != spec.far_future_epoch) + .map(|v| v.exit_epoch) + .max() + .unwrap_or(activation_exit_epoch) + .max(activation_exit_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)?; + let earliest_consolidation_epoch = spec.compute_activation_exit_epoch(epoch)?; + + let mut post = upgrade_state_to_eip7805( + pre_state, + earliest_exit_epoch, + earliest_consolidation_epoch, + spec, + )?; + + *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 pre_activation = validators + .iter() + .enumerate() + .filter(|(_, validator)| validator.activation_epoch == spec.far_future_epoch) + .sorted_by_key(|(index, validator)| (validator.activation_eligibility_epoch, *index)) + .map(|(index, _)| index) + .collect::>(); + + // Process validators to queue entire balance and reset them + for index in pre_activation { + let balance = post + .balances_mut() + .get_mut(index) + .ok_or(Error::UnknownValidator(index))?; + let balance_copy = *balance; + *balance = 0_u64; + + let validator = post + .validators_mut() + .get_mut(index) + .ok_or(Error::UnknownValidator(index))?; + validator.effective_balance = 0; + validator.activation_eligibility_epoch = spec.far_future_epoch; + let pubkey = validator.pubkey; + let withdrawal_credentials = validator.withdrawal_credentials; + + post.pending_deposits_mut()? + .push(PendingDeposit { + pubkey, + withdrawal_credentials, + amount: balance_copy, + signature: Signature::infinity()?.into(), + slot: spec.genesis_slot, + }) + .map_err(Error::MilhouseError)?; + } + + // Ensure early adopters of compounding credentials go through the activation churn + let validators = post.validators().clone(); + 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(()) +} + +pub fn upgrade_state_to_eip7805( + pre_state: &mut BeaconState, + earliest_exit_epoch: Epoch, + earliest_consolidation_epoch: Epoch, + spec: &ChainSpec, +) -> Result, Error> { + let epoch = pre_state.current_epoch(); + let pre = pre_state.as_electra_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 post = BeaconState::Eip7805(BeaconStateEip7805 { + // 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.electra_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_eip7805(), + // Capella + next_withdrawal_index: pre.next_withdrawal_index, + next_withdrawal_validator_index: pre.next_withdrawal_validator_index, + historical_summaries: pre.historical_summaries.clone(), + // Electra + deposit_requests_start_index: spec.unset_deposit_requests_start_index, + deposit_balance_to_consume: 0, + exit_balance_to_consume: 0, + earliest_exit_epoch, + consolidation_balance_to_consume: 0, + earliest_consolidation_epoch, + pending_deposits: Default::default(), + pending_partial_withdrawals: Default::default(), + pending_consolidations: Default::default(), + // 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(), + }); + Ok(post) +} diff --git a/consensus/state_processing/src/upgrade/fulu.rs b/consensus/state_processing/src/upgrade/fulu.rs index 6e0cd3fa9d..6a25d30104 100644 --- a/consensus/state_processing/src/upgrade/fulu.rs +++ b/consensus/state_processing/src/upgrade/fulu.rs @@ -20,7 +20,7 @@ pub fn upgrade_state_to_fulu( spec: &ChainSpec, ) -> Result, Error> { let epoch = pre_state.current_epoch(); - let pre = pre_state.as_electra_mut()?; + let pre = pre_state.as_eip7805_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`. // diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 6ea897cf1a..0c215ed1c9 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -16,7 +16,7 @@ use self::indexed_attestation::IndexedAttestationBase; /// A block of the `BeaconChain`. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Debug, @@ -75,6 +75,8 @@ pub struct BeaconBlock = FullPayload pub body: BeaconBlockBodyDeneb, #[superstruct(only(Electra), partial_getter(rename = "body_electra"))] pub body: BeaconBlockBodyElectra, + #[superstruct(only(Eip7805), partial_getter(rename = "body_eip7805"))] + pub body: BeaconBlockBodyEip7805, #[superstruct(only(Fulu), partial_getter(rename = "body_fulu"))] pub body: BeaconBlockBodyFulu, } @@ -131,6 +133,7 @@ impl> BeaconBlock { pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result { BeaconBlockFulu::from_ssz_bytes(bytes) .map(BeaconBlock::Fulu) + .or_else(|_| BeaconBlockEip7805::from_ssz_bytes(bytes).map(BeaconBlock::Eip7805)) .or_else(|_| BeaconBlockElectra::from_ssz_bytes(bytes).map(BeaconBlock::Electra)) .or_else(|_| BeaconBlockDeneb::from_ssz_bytes(bytes).map(BeaconBlock::Deneb)) .or_else(|_| BeaconBlockCapella::from_ssz_bytes(bytes).map(BeaconBlock::Capella)) @@ -229,6 +232,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockRef<'a, E, Payl BeaconBlockRef::Capella { .. } => ForkName::Capella, BeaconBlockRef::Deneb { .. } => ForkName::Deneb, BeaconBlockRef::Electra { .. } => ForkName::Electra, + BeaconBlockRef::Eip7805 { .. } => ForkName::Eip7805, BeaconBlockRef::Fulu { .. } => ForkName::Fulu, } } @@ -589,6 +593,37 @@ impl> EmptyBlock for BeaconBlockElec } } +impl> EmptyBlock for BeaconBlockEip7805 { + /// Returns an empty Electra block to be used during genesis. + fn empty(spec: &ChainSpec) -> Self { + BeaconBlockEip7805 { + slot: spec.genesis_slot, + proposer_index: 0, + parent_root: Hash256::zero(), + state_root: Hash256::zero(), + body: BeaconBlockBodyEip7805 { + 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::Eip7805::default(), + bls_to_execution_changes: VariableList::empty(), + blob_kzg_commitments: VariableList::empty(), + execution_requests: ExecutionRequests::default(), + }, + } + } +} + impl> EmptyBlock for BeaconBlockFulu { /// Returns an empty Fulu block to be used during genesis. fn empty(spec: &ChainSpec) -> Self { @@ -701,6 +736,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!(BeaconBlockEip7805, >, >, |body: BeaconBlockBodyEip7805<_, _>| body.into()); impl_from!(BeaconBlockFulu, >, >, |body: BeaconBlockBodyFulu<_, _>| body.into()); // We can clone blocks with payloads to blocks without payloads, without cloning the payload. @@ -735,6 +771,7 @@ impl_clone_as_blinded!(BeaconBlockBellatrix, >, >, >); impl_clone_as_blinded!(BeaconBlockDeneb, >, >); impl_clone_as_blinded!(BeaconBlockElectra, >, >); +impl_clone_as_blinded!(BeaconBlockEip7805, >, >); impl_clone_as_blinded!(BeaconBlockFulu, >, >); // A reference to a full beacon block can be cloned into a blinded beacon block, without cloning the @@ -906,6 +943,26 @@ mod tests { }); } + #[test] + fn roundtrip_eip7805_block() { + let rng = &mut XorShiftRng::from_seed([42; 16]); + let spec = &ForkName::Eip7805.make_genesis_spec(MainnetEthSpec::default_spec()); + + let inner_block = BeaconBlockEip7805 { + slot: Slot::random_for_test(rng), + proposer_index: u64::random_for_test(rng), + parent_root: Hash256::random_for_test(rng), + state_root: Hash256::random_for_test(rng), + body: BeaconBlockBodyEip7805::random_for_test(rng), + }; + + let block = BeaconBlock::Eip7805(inner_block.clone()); + + test_ssz_tree_hash_pair_with(&block, &inner_block, |bytes| { + BeaconBlock::from_ssz_bytes(bytes, spec) + }); + } + #[test] fn roundtrip_fulu_block() { let rng = &mut XorShiftRng::from_seed([42; 16]); @@ -945,13 +1002,16 @@ mod tests { let deneb_slot = deneb_epoch.start_slot(E::slots_per_epoch()); let electra_epoch = deneb_epoch + 1; let electra_slot = electra_epoch.start_slot(E::slots_per_epoch()); - let fulu_epoch = electra_epoch + 1; + let eip7805_epoch = electra_epoch + 1; + let eip7805_slot = eip7805_epoch.start_slot(E::slots_per_epoch()); + let fulu_epoch = eip7805_epoch + 1; let fulu_slot = fulu_epoch.start_slot(E::slots_per_epoch()); spec.altair_fork_epoch = Some(altair_epoch); spec.capella_fork_epoch = Some(capella_epoch); spec.deneb_fork_epoch = Some(deneb_epoch); spec.electra_fork_epoch = Some(electra_epoch); + spec.eip7805_fork_epoch = Some(eip7805_epoch); spec.fulu_fork_epoch = Some(fulu_epoch); // BeaconBlockBase @@ -1064,6 +1124,28 @@ mod tests { .expect_err("bad electra block cannot be decoded"); } + // BeaconBlockEip7805 + { + let good_block = BeaconBlock::Eip7805(BeaconBlockEip7805 { + slot: eip7805_slot, + ..<_>::random_for_test(rng) + }); + // It's invalid to have an Electra block with a epoch lower than the fork epoch. + let bad_block = { + let mut bad = good_block.clone(); + *bad.slot_mut() = deneb_slot; + bad + }; + + assert_eq!( + BeaconBlock::from_ssz_bytes(&good_block.as_ssz_bytes(), &spec) + .expect("good eip7805 block can be decoded"), + good_block + ); + BeaconBlock::from_ssz_bytes(&bad_block.as_ssz_bytes(), &spec) + .expect_err("bad eip7805 block cannot be decoded"); + } + // BeaconBlockFulu { let good_block = BeaconBlock::Fulu(BeaconBlockFulu { diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index 10c1a11ede..6bb8b4bd7d 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -28,7 +28,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11; /// /// This *superstruct* abstracts over the hard-fork. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Debug, @@ -56,6 +56,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11; Capella(metastruct(mappings(beacon_block_body_capella_fields(groups(fields))))), Deneb(metastruct(mappings(beacon_block_body_deneb_fields(groups(fields))))), Electra(metastruct(mappings(beacon_block_body_electra_fields(groups(fields))))), + Eip7805(metastruct(mappings(beacon_block_body_eip7805_fields(groups(fields))))), Fulu(metastruct(mappings(beacon_block_body_fulu_fields(groups(fields))))) ), cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"), @@ -77,7 +78,7 @@ pub struct BeaconBlockBody = FullPay )] pub attester_slashings: VariableList, E::MaxAttesterSlashings>, #[superstruct( - only(Electra, Fulu), + only(Electra, Eip7805, Fulu), partial_getter(rename = "attester_slashings_electra") )] pub attester_slashings: @@ -87,11 +88,14 @@ pub struct BeaconBlockBody = FullPay partial_getter(rename = "attestations_base") )] pub attestations: VariableList, E::MaxAttestations>, - #[superstruct(only(Electra, Fulu), partial_getter(rename = "attestations_electra"))] + #[superstruct( + only(Electra, Eip7805, Fulu), + partial_getter(rename = "attestations_electra") + )] pub attestations: VariableList, E::MaxAttestationsElectra>, pub deposits: VariableList, pub voluntary_exits: VariableList, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] 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 @@ -111,15 +115,18 @@ pub struct BeaconBlockBody = FullPay #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] #[serde(flatten)] pub execution_payload: Payload::Electra, + #[superstruct(only(Eip7805), partial_getter(rename = "execution_payload_eip7805"))] + #[serde(flatten)] + pub execution_payload: Payload::Eip7805, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] #[serde(flatten)] pub execution_payload: Payload::Fulu, - #[superstruct(only(Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu))] pub bls_to_execution_changes: VariableList, - #[superstruct(only(Deneb, Electra, Fulu))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu))] pub blob_kzg_commitments: KzgCommitments, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub execution_requests: ExecutionRequests, #[superstruct(only(Base, Altair))] #[metastruct(exclude_from(fields))] @@ -149,6 +156,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::Eip7805(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Fulu(body) => Ok(Payload::Ref::from(&body.execution_payload)), } } @@ -180,6 +188,10 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, beacon_block_body_electra_fields!(body, |_, field| leaves .push(field.tree_hash_root())); } + Self::Eip7805(body) => { + beacon_block_body_eip7805_fields!(body, |_, field| leaves + .push(field.tree_hash_root())); + } Self::Fulu(body) => { beacon_block_body_fulu_fields!(body, |_, field| leaves .push(field.tree_hash_root())); @@ -212,7 +224,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Base(_) | Self::Altair(_) | Self::Bellatrix(_) | Self::Capella(_) => { Err(Error::IncorrectStateVariant) } - Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) => { + Self::Deneb(_) | Self::Electra(_) | Self::Eip7805(_) | Self::Fulu(_) => { // 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 @@ -304,6 +316,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Capella(body) => body.attestations.len(), Self::Deneb(body) => body.attestations.len(), Self::Electra(body) => body.attestations.len(), + Self::Eip7805(body) => body.attestations.len(), Self::Fulu(body) => body.attestations.len(), } } @@ -316,6 +329,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Capella(body) => body.attester_slashings.len(), Self::Deneb(body) => body.attester_slashings.len(), Self::Electra(body) => body.attester_slashings.len(), + Self::Eip7805(body) => body.attester_slashings.len(), Self::Fulu(body) => body.attester_slashings.len(), } } @@ -328,6 +342,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Self::Capella(body) => Box::new(body.attestations.iter().map(AttestationRef::Base)), Self::Deneb(body) => Box::new(body.attestations.iter().map(AttestationRef::Base)), Self::Electra(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), + Self::Eip7805(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), Self::Fulu(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), } } @@ -364,6 +379,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, .iter() .map(AttesterSlashingRef::Electra), ), + Self::Eip7805(body) => Box::new( + body.attester_slashings + .iter() + .map(AttesterSlashingRef::Electra), + ), Self::Fulu(body) => Box::new( body.attester_slashings .iter() @@ -394,6 +414,9 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRefMut<'a, Self::Electra(body) => { Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra)) } + Self::Eip7805(body) => { + Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra)) + } Self::Fulu(body) => { Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra)) } @@ -411,6 +434,7 @@ impl> BeaconBlockBodyRef<'_, E, Payl BeaconBlockBodyRef::Capella { .. } => ForkName::Capella, BeaconBlockBodyRef::Deneb { .. } => ForkName::Deneb, BeaconBlockBodyRef::Electra { .. } => ForkName::Electra, + BeaconBlockBodyRef::Eip7805 { .. } => ForkName::Eip7805, BeaconBlockBodyRef::Fulu { .. } => ForkName::Fulu, } } @@ -726,6 +750,52 @@ impl From>> } } +impl From>> + for ( + BeaconBlockBodyEip7805>, + Option>, + ) +{ + fn from(body: BeaconBlockBodyEip7805>) -> Self { + let BeaconBlockBodyEip7805 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadEip7805 { execution_payload }, + bls_to_execution_changes, + blob_kzg_commitments, + execution_requests, + } = body; + + ( + BeaconBlockBodyEip7805 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: BlindedPayloadEip7805 { + execution_payload_header: From::from(&execution_payload), + }, + bls_to_execution_changes, + blob_kzg_commitments: blob_kzg_commitments.clone(), + execution_requests, + }, + Some(execution_payload), + ) + } +} + impl From>> for ( BeaconBlockBodyFulu>, @@ -927,6 +997,44 @@ impl BeaconBlockBodyElectra> { } } +impl BeaconBlockBodyEip7805> { + pub fn clone_as_blinded(&self) -> BeaconBlockBodyEip7805> { + let BeaconBlockBodyEip7805 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadEip7805 { execution_payload }, + bls_to_execution_changes, + blob_kzg_commitments, + execution_requests, + } = self; + + BeaconBlockBodyEip7805 { + 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: BlindedPayloadEip7805 { + execution_payload_header: execution_payload.into(), + }, + bls_to_execution_changes: bls_to_execution_changes.clone(), + blob_kzg_commitments: blob_kzg_commitments.clone(), + execution_requests: execution_requests.clone(), + } + } +} + impl BeaconBlockBodyFulu> { pub fn clone_as_blinded(&self) -> BeaconBlockBodyFulu> { let BeaconBlockBodyFulu { diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 3d6f51a990..2bb5f6dfff 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -227,7 +227,7 @@ impl From for Hash256 { /// /// https://github.com/sigp/milhouse/issues/43 #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Derivative, @@ -331,6 +331,20 @@ impl From for Hash256 { )), num_fields(all()), )), + Eip7805(metastruct( + mappings( + map_beacon_state_eip7805_fields(), + map_beacon_state_eip7805_tree_list_fields(mutable, fallible, groups(tree_lists)), + map_beacon_state_eip7805_tree_list_fields_immutable(groups(tree_lists)), + ), + bimappings(bimap_beacon_state_eip7805_tree_list_fields( + other_type = "BeaconStateEip7805", + self_mutable, + fallible, + groups(tree_lists) + )), + num_fields(all()), + )), Fulu(metastruct( mappings( map_beacon_state_fulu_fields(), @@ -426,11 +440,11 @@ where // Participation (Altair and later) #[compare_fields(as_iter)] - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] #[test_random(default)] #[compare_fields(as_iter)] pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] #[test_random(default)] pub current_epoch_participation: List, @@ -450,15 +464,15 @@ where // Inactivity #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] #[test_random(default)] pub inactivity_scores: List, // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] #[metastruct(exclude_from(tree_lists))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Fulu))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu))] #[metastruct(exclude_from(tree_lists))] pub next_sync_committee: Arc>, @@ -487,6 +501,12 @@ where )] #[metastruct(exclude_from(tree_lists))] pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, + #[superstruct( + only(Eip7805), + partial_getter(rename = "latest_execution_payload_header_eip7805") + )] + #[metastruct(exclude_from(tree_lists))] + pub latest_execution_payload_header: ExecutionPayloadHeaderEip7805, #[superstruct( only(Fulu), partial_getter(rename = "latest_execution_payload_header_fulu") @@ -495,54 +515,54 @@ where pub latest_execution_payload_header: ExecutionPayloadHeaderFulu, // Capella - #[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu), 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, Fulu))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu))] #[test_random(default)] pub historical_summaries: List, // Electra - #[superstruct(only(Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Electra, Eip7805, Fulu), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub deposit_requests_start_index: u64, - #[superstruct(only(Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Electra, Eip7805, Fulu), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub deposit_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Electra, Eip7805, Fulu), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub exit_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Electra, Eip7805, Fulu), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] pub earliest_exit_epoch: Epoch, - #[superstruct(only(Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Electra, Eip7805, Fulu), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub consolidation_balance_to_consume: u64, - #[superstruct(only(Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Electra, Eip7805, Fulu), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] pub earliest_consolidation_epoch: Epoch, #[compare_fields(as_iter)] #[test_random(default)] - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub pending_deposits: List, #[compare_fields(as_iter)] #[test_random(default)] - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub pending_partial_withdrawals: List, #[compare_fields(as_iter)] #[test_random(default)] - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub pending_consolidations: List, // Caching (not in the spec) @@ -683,6 +703,7 @@ impl BeaconState { BeaconState::Capella { .. } => ForkName::Capella, BeaconState::Deneb { .. } => ForkName::Deneb, BeaconState::Electra { .. } => ForkName::Electra, + BeaconState::Eip7805 { .. } => ForkName::Eip7805, BeaconState::Fulu { .. } => ForkName::Fulu, } } @@ -1063,6 +1084,9 @@ impl BeaconState { BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRef::Electra( &state.latest_execution_payload_header, )), + BeaconState::Eip7805(state) => Ok(ExecutionPayloadHeaderRef::Eip7805( + &state.latest_execution_payload_header, + )), BeaconState::Fulu(state) => Ok(ExecutionPayloadHeaderRef::Fulu( &state.latest_execution_payload_header, )), @@ -1086,6 +1110,9 @@ impl BeaconState { BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRefMut::Electra( &mut state.latest_execution_payload_header, )), + BeaconState::Eip7805(state) => Ok(ExecutionPayloadHeaderRefMut::Eip7805( + &mut state.latest_execution_payload_header, + )), BeaconState::Fulu(state) => Ok(ExecutionPayloadHeaderRefMut::Fulu( &mut state.latest_execution_payload_header, )), @@ -1607,6 +1634,16 @@ impl BeaconState { &mut state.exit_cache, &mut state.epoch_cache, )), + BeaconState::Eip7805(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, + )), BeaconState::Fulu(state) => Ok(( &mut state.validators, &mut state.balances, @@ -1798,12 +1835,13 @@ impl BeaconState { | BeaconState::Altair(_) | BeaconState::Bellatrix(_) | BeaconState::Capella(_) => self.get_validator_churn_limit(spec)?, - BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::Fulu(_) => { - std::cmp::min( - spec.max_per_epoch_activation_churn_limit, - self.get_validator_churn_limit(spec)?, - ) - } + BeaconState::Deneb(_) + | BeaconState::Electra(_) + | BeaconState::Eip7805(_) + | BeaconState::Fulu(_) => std::cmp::min( + spec.max_per_epoch_activation_churn_limit, + self.get_validator_churn_limit(spec)?, + ), }) } @@ -1944,6 +1982,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::Eip7805(state) => Ok(&mut state.current_epoch_participation), BeaconState::Fulu(state) => Ok(&mut state.current_epoch_participation), } } else if epoch == previous_epoch { @@ -1954,6 +1993,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::Eip7805(state) => Ok(&mut state.previous_epoch_participation), BeaconState::Fulu(state) => Ok(&mut state.previous_epoch_participation), } } else { @@ -2208,6 +2248,14 @@ impl BeaconState { } ); } + Self::Eip7805(self_inner) => { + map_beacon_state_eip7805_tree_list_fields_immutable!( + self_inner, + |_, self_field| { + any_pending_mutations |= self_field.has_pending_updates(); + } + ); + } Self::Fulu(self_inner) => { map_beacon_state_fulu_tree_list_fields_immutable!(self_inner, |_, self_field| { any_pending_mutations |= self_field.has_pending_updates(); @@ -2412,7 +2460,7 @@ impl BeaconState { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) => Err(Error::IncorrectStateVariant), - BeaconState::Electra(_) | BeaconState::Fulu(_) => { + BeaconState::Electra(_) | BeaconState::Eip7805(_) | BeaconState::Fulu(_) => { // Consume the balance and update state variables *self.exit_balance_to_consume_mut()? = exit_balance_to_consume.safe_sub(exit_balance)?; @@ -2459,7 +2507,7 @@ impl BeaconState { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) => Err(Error::IncorrectStateVariant), - BeaconState::Electra(_) | BeaconState::Fulu(_) => { + BeaconState::Electra(_) | BeaconState::Eip7805(_) | BeaconState::Fulu(_) => { // Consume the balance and update state variables. *self.consolidation_balance_to_consume_mut()? = consolidation_balance_to_consume.safe_sub(consolidation_balance)?; @@ -2522,6 +2570,14 @@ impl BeaconState { ); } (Self::Electra(_), _) => (), + (Self::Eip7805(self_inner), Self::Eip7805(base_inner)) => { + bimap_beacon_state_eip7805_tree_list_fields!( + self_inner, + base_inner, + |_, self_field, base_field| { self_field.rebase_on(base_field) } + ); + } + (Self::Eip7805(_), _) => (), (Self::Fulu(self_inner), Self::Fulu(base_inner)) => { bimap_beacon_state_fulu_tree_list_fields!( self_inner, @@ -2602,6 +2658,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::Eip7805 => BeaconStateEip7805::::NUM_FIELDS.next_power_of_two(), ForkName::Fulu => BeaconStateFulu::::NUM_FIELDS.next_power_of_two(), } } @@ -2651,6 +2708,9 @@ impl BeaconState { Self::Electra(inner) => { map_beacon_state_electra_tree_list_fields!(inner, |_, x| { x.apply_updates() }) } + Self::Eip7805(inner) => { + map_beacon_state_eip7805_tree_list_fields!(inner, |_, x| { x.apply_updates() }) + } Self::Fulu(inner) => { map_beacon_state_fulu_tree_list_fields!(inner, |_, x| { x.apply_updates() }) } @@ -2762,6 +2822,11 @@ impl BeaconState { leaves.push(field.tree_hash_root()); }); } + BeaconState::Eip7805(state) => { + map_beacon_state_eip7805_fields!(state, |_, field| { + leaves.push(field.tree_hash_root()); + }); + } BeaconState::Fulu(state) => { map_beacon_state_fulu_fields!(state, |_, field| { leaves.push(field.tree_hash_root()); @@ -2824,6 +2889,7 @@ impl CompareFields for BeaconState { (BeaconState::Capella(x), BeaconState::Capella(y)) => x.compare_fields(y), (BeaconState::Deneb(x), BeaconState::Deneb(y)) => x.compare_fields(y), (BeaconState::Electra(x), BeaconState::Electra(y)) => x.compare_fields(y), + (BeaconState::Eip7805(x), BeaconState::Eip7805(y)) => x.compare_fields(y), (BeaconState::Fulu(x), BeaconState::Fulu(y)) => x.compare_fields(y), _ => panic!("compare_fields: mismatched state variants",), } diff --git a/consensus/types/src/builder_bid.rs b/consensus/types/src/builder_bid.rs index 49911c3909..b20dc0f316 100644 --- a/consensus/types/src/builder_bid.rs +++ b/consensus/types/src/builder_bid.rs @@ -1,9 +1,9 @@ use crate::beacon_block_body::KzgCommitments; use crate::{ ChainSpec, EthSpec, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, - ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, ExecutionRequests, ForkName, - ForkVersionDecode, ForkVersionDeserialize, SignedRoot, Uint256, + ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7805, ExecutionPayloadHeaderElectra, + ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, + ExecutionRequests, ForkName, ForkVersionDecode, ForkVersionDeserialize, SignedRoot, Uint256, }; use bls::PublicKeyBytes; use bls::Signature; @@ -14,7 +14,7 @@ use superstruct::superstruct; use tree_hash_derive::TreeHash; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( PartialEq, @@ -44,11 +44,13 @@ pub struct BuilderBid { pub header: ExecutionPayloadHeaderDeneb, #[superstruct(only(Electra), partial_getter(rename = "header_electra"))] pub header: ExecutionPayloadHeaderElectra, + #[superstruct(only(Eip7805), partial_getter(rename = "header_eip7805"))] + pub header: ExecutionPayloadHeaderEip7805, #[superstruct(only(Fulu), partial_getter(rename = "header_fulu"))] pub header: ExecutionPayloadHeaderFulu, - #[superstruct(only(Deneb, Electra, Fulu))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu))] pub blob_kzg_commitments: KzgCommitments, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] pub execution_requests: ExecutionRequests, #[serde(with = "serde_utils::quoted_u256")] pub value: Uint256, @@ -92,6 +94,7 @@ impl ForkVersionDecode for BuilderBid { ForkName::Capella => BuilderBid::Capella(BuilderBidCapella::from_ssz_bytes(bytes)?), ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb::from_ssz_bytes(bytes)?), ForkName::Electra => BuilderBid::Electra(BuilderBidElectra::from_ssz_bytes(bytes)?), + ForkName::Eip7805 => BuilderBid::Eip7805(BuilderBidEip7805::from_ssz_bytes(bytes)?), ForkName::Fulu => BuilderBid::Fulu(BuilderBidFulu::from_ssz_bytes(bytes)?), }; Ok(builder_bid) @@ -140,6 +143,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::Eip7805 => Self::Eip7805(serde_json::from_value(value).map_err(convert_err)?), ForkName::Fulu => Self::Fulu(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index b62f425c8c..fc2d5aa724 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -199,6 +199,7 @@ pub struct ChainSpec { pub domain_inclusion_list_committee: u32, pub inclusion_list_committee_size: u64, pub eip7805_fork_epoch: Option, + pub eip7805_fork_version: [u8; 4], /* * Fulu hard fork params @@ -334,17 +335,21 @@ impl ChainSpec { pub fn fork_name_at_epoch(&self, epoch: Epoch) -> ForkName { match self.fulu_fork_epoch { Some(fork_epoch) if epoch >= fork_epoch => ForkName::Fulu, - _ => match self.electra_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Electra, - _ => match self.deneb_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Deneb, - _ => match self.capella_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Capella, - _ => match self.bellatrix_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Bellatrix, - _ => match self.altair_fork_epoch { - Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair, - _ => ForkName::Base, + _ => match self.eip7805_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Eip7805, + + _ => match self.electra_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Electra, + _ => match self.deneb_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Deneb, + _ => match self.capella_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Capella, + _ => match self.bellatrix_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Bellatrix, + _ => match self.altair_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::Altair, + _ => ForkName::Base, + }, }, }, }, @@ -362,6 +367,7 @@ impl ChainSpec { ForkName::Capella => self.capella_fork_version, ForkName::Deneb => self.deneb_fork_version, ForkName::Electra => self.electra_fork_version, + ForkName::Eip7805 => self.eip7805_fork_version, ForkName::Fulu => self.fulu_fork_version, } } @@ -375,6 +381,7 @@ impl ChainSpec { ForkName::Capella => self.capella_fork_epoch, ForkName::Deneb => self.deneb_fork_epoch, ForkName::Electra => self.electra_fork_epoch, + ForkName::Eip7805 => self.eip7805_fork_epoch, ForkName::Fulu => self.fulu_fork_epoch, } } @@ -936,6 +943,7 @@ impl ChainSpec { domain_inclusion_list_committee: 13, inclusion_list_committee_size: 16, eip7805_fork_epoch: None, + eip7805_fork_version: [0x06, 0x00, 0x00, 0x00], /* * Fulu hard fork params @@ -1064,6 +1072,7 @@ impl ChainSpec { .expect("calculation does not overflow"), // FOCIL eip7805_fork_epoch: None, + eip7805_fork_version: [0x06, 0x00, 0x00, 0x00], // Fulu fulu_fork_version: [0x06, 0x00, 0x00, 0x01], fulu_fork_epoch: None, @@ -1275,6 +1284,7 @@ impl ChainSpec { domain_inclusion_list_committee: 13, inclusion_list_committee_size: 16, eip7805_fork_epoch: None, + eip7805_fork_version: [0x06, 0x00, 0x00, 0x00], /* * Fulu hard fork params @@ -1429,6 +1439,9 @@ pub struct Config { #[serde(deserialize_with = "deserialize_fork_epoch")] pub fulu_fork_epoch: Option>, + #[serde(default = "default_eip7805_fork_version")] + #[serde(with = "serde_utils::bytes_4_hex")] + eip7805_fork_version: [u8; 4], #[serde(default)] #[serde(serialize_with = "serialize_fork_epoch")] #[serde(deserialize_with = "deserialize_fork_epoch")] @@ -1581,6 +1594,11 @@ fn default_electra_fork_version() -> [u8; 4] { [0xff, 0xff, 0xff, 0xff] } +fn default_eip7805_fork_version() -> [u8; 4] { + // This value shouldn't be used. + [0xff, 0xff, 0xff, 0xff] +} + fn default_fulu_fork_version() -> [u8; 4] { // This value shouldn't be used. [0xff, 0xff, 0xff, 0xff] @@ -1876,6 +1894,7 @@ impl Config { .fulu_fork_epoch .map(|epoch| MaybeQuoted { value: epoch }), + eip7805_fork_version: spec.eip7805_fork_version, eip7805_fork_epoch: spec .eip7805_fork_epoch .map(|epoch| MaybeQuoted { value: epoch }), @@ -1964,6 +1983,7 @@ impl Config { deneb_fork_version, electra_fork_epoch, electra_fork_version, + eip7805_fork_version, eip7805_fork_epoch, fulu_fork_epoch, fulu_fork_version, @@ -2034,6 +2054,7 @@ impl Config { deneb_fork_version, electra_fork_epoch: electra_fork_epoch.map(|q| q.value), electra_fork_version, + eip7805_fork_version, eip7805_fork_epoch: eip7805_fork_epoch.map(|q| q.value), fulu_fork_epoch: fulu_fork_epoch.map(|q| q.value), fulu_fork_version, diff --git a/consensus/types/src/config_and_preset.rs b/consensus/types/src/config_and_preset.rs index 235bf20238..0533db79c6 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(Deneb, Electra, Fulu), + variants(Deneb, Electra, Eip7805, Fulu), variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone)) )] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] @@ -31,7 +31,7 @@ pub struct ConfigAndPreset { pub capella_preset: CapellaPreset, #[serde(flatten)] pub deneb_preset: DenebPreset, - #[superstruct(only(Electra, Fulu))] + #[superstruct(only(Electra, Eip7805, Fulu))] #[serde(flatten)] pub electra_preset: ElectraPreset, #[superstruct(only(Fulu))] diff --git a/consensus/types/src/execution_payload.rs b/consensus/types/src/execution_payload.rs index 5d756c8529..8fb29f2457 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, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Default, @@ -82,12 +82,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, Fulu))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu))] pub withdrawals: Withdrawals, - #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, } @@ -115,6 +115,7 @@ impl ForkVersionDecode for 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::Eip7805 => ExecutionPayloadEip7805::from_ssz_bytes(bytes).map(Self::Eip7805), ForkName::Fulu => ExecutionPayloadFulu::from_ssz_bytes(bytes).map(Self::Fulu), } } @@ -149,6 +150,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::Eip7805 => Self::Eip7805(serde_json::from_value(value).map_err(convert_err)?), ForkName::Fulu => Self::Fulu(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( @@ -167,6 +169,7 @@ impl ExecutionPayload { ExecutionPayload::Capella(_) => ForkName::Capella, ExecutionPayload::Deneb(_) => ForkName::Deneb, ExecutionPayload::Electra(_) => ForkName::Electra, + ExecutionPayload::Eip7805(_) => ForkName::Eip7805, ExecutionPayload::Fulu(_) => ForkName::Fulu, } } diff --git a/consensus/types/src/execution_payload_header.rs b/consensus/types/src/execution_payload_header.rs index 3012041b8b..2ede858fd5 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, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Default, @@ -78,12 +78,12 @@ pub struct ExecutionPayloadHeader { pub block_hash: ExecutionBlockHash, #[superstruct(getter(copy))] pub transactions_root: Hash256, - #[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Eip7805, Fulu), partial_getter(copy))] pub withdrawals_root: Hash256, - #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Eip7805, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, } @@ -108,6 +108,9 @@ impl ExecutionPayloadHeader { ForkName::Electra => { ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra) } + ForkName::Eip7805 => { + ExecutionPayloadHeaderEip7805::from_ssz_bytes(bytes).map(Self::Eip7805) + } ForkName::Fulu => ExecutionPayloadHeaderFulu::from_ssz_bytes(bytes).map(Self::Fulu), } } @@ -129,6 +132,7 @@ impl ExecutionPayloadHeader { ExecutionPayloadHeader::Capella(_) => ForkName::Capella, ExecutionPayloadHeader::Deneb(_) => ForkName::Deneb, ExecutionPayloadHeader::Electra(_) => ForkName::Electra, + ExecutionPayloadHeader::Eip7805(_) => ForkName::Eip7805, ExecutionPayloadHeader::Fulu(_) => ForkName::Fulu, } } @@ -214,6 +218,30 @@ impl ExecutionPayloadHeaderDeneb { } impl ExecutionPayloadHeaderElectra { + pub fn upgrade_to_eip7805(&self) -> ExecutionPayloadHeaderEip7805 { + ExecutionPayloadHeaderEip7805 { + 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 ExecutionPayloadHeaderEip7805 { pub fn upgrade_to_fulu(&self) -> ExecutionPayloadHeaderFulu { ExecutionPayloadHeaderFulu { parent_hash: self.parent_hash, @@ -328,6 +356,30 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadElectra> for ExecutionPayloadHe } } +impl<'a, E: EthSpec> From<&'a ExecutionPayloadEip7805> for ExecutionPayloadHeaderEip7805 { + fn from(payload: &'a ExecutionPayloadEip7805) -> 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, + } + } +} + impl<'a, E: EthSpec> From<&'a ExecutionPayloadFulu> for ExecutionPayloadHeaderFulu { fn from(payload: &'a ExecutionPayloadFulu) -> Self { Self { @@ -378,6 +430,12 @@ impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderElectra { } } +impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderEip7805 { + fn from(payload: &'a Self) -> Self { + payload.clone() + } +} + impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderFulu { fn from(payload: &'a Self) -> Self { payload.clone() @@ -442,6 +500,9 @@ impl ExecutionPayloadHeaderRefMut<'_, E> { ExecutionPayloadHeaderRefMut::Electra(mut_ref) => { *mut_ref = header.try_into()?; } + ExecutionPayloadHeaderRefMut::Eip7805(mut_ref) => { + *mut_ref = header.try_into()?; + } ExecutionPayloadHeaderRefMut::Fulu(mut_ref) => { *mut_ref = header.try_into()?; } @@ -462,6 +523,18 @@ impl TryFrom> for ExecutionPayloadHeaderEl } } +impl TryFrom> for ExecutionPayloadHeaderEip7805 { + type Error = BeaconStateError; + fn try_from(header: ExecutionPayloadHeader) -> Result { + match header { + ExecutionPayloadHeader::Eip7805(execution_payload_header) => { + Ok(execution_payload_header) + } + _ => Err(BeaconStateError::IncorrectStateVariant), + } + } +} + impl TryFrom> for ExecutionPayloadHeaderFulu { type Error = BeaconStateError; fn try_from(header: ExecutionPayloadHeader) -> Result { @@ -491,6 +564,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::Eip7805 => Self::Eip7805(serde_json::from_value(value).map_err(convert_err)?), ForkName::Fulu => Self::Fulu(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( diff --git a/consensus/types/src/fork_name.rs b/consensus/types/src/fork_name.rs index e92db49485..13e95a46f4 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, + Eip7805, Fulu, } @@ -29,6 +30,7 @@ impl ForkName { ForkName::Capella, ForkName::Deneb, ForkName::Electra, + ForkName::Eip7805, ForkName::Fulu, ] } @@ -65,6 +67,7 @@ impl ForkName { spec.capella_fork_epoch = None; spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7805_fork_epoch = None; spec.fulu_fork_epoch = None; spec } @@ -74,6 +77,7 @@ impl ForkName { spec.capella_fork_epoch = None; spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7805_fork_epoch = None; spec.fulu_fork_epoch = None; spec } @@ -83,6 +87,7 @@ impl ForkName { spec.capella_fork_epoch = None; spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7805_fork_epoch = None; spec.fulu_fork_epoch = None; spec } @@ -92,6 +97,7 @@ impl ForkName { spec.capella_fork_epoch = Some(Epoch::new(0)); spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7805_fork_epoch = None; spec.fulu_fork_epoch = None; spec } @@ -101,6 +107,7 @@ impl ForkName { spec.capella_fork_epoch = Some(Epoch::new(0)); spec.deneb_fork_epoch = Some(Epoch::new(0)); spec.electra_fork_epoch = None; + spec.eip7805_fork_epoch = None; spec.fulu_fork_epoch = None; spec } @@ -110,6 +117,17 @@ impl ForkName { spec.capella_fork_epoch = Some(Epoch::new(0)); spec.deneb_fork_epoch = Some(Epoch::new(0)); spec.electra_fork_epoch = Some(Epoch::new(0)); + spec.eip7805_fork_epoch = None; + spec.fulu_fork_epoch = None; + spec + } + ForkName::Eip7805 => { + 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.electra_fork_epoch = Some(Epoch::new(0)); + spec.eip7805_fork_epoch = Some(Epoch::new(0)); spec.fulu_fork_epoch = None; spec } @@ -119,6 +137,7 @@ impl ForkName { spec.capella_fork_epoch = Some(Epoch::new(0)); spec.deneb_fork_epoch = Some(Epoch::new(0)); spec.electra_fork_epoch = Some(Epoch::new(0)); + spec.eip7805_fork_epoch = Some(Epoch::new(0)); spec.fulu_fork_epoch = Some(Epoch::new(0)); spec } @@ -136,7 +155,8 @@ impl ForkName { ForkName::Capella => Some(ForkName::Bellatrix), ForkName::Deneb => Some(ForkName::Capella), ForkName::Electra => Some(ForkName::Deneb), - ForkName::Fulu => Some(ForkName::Electra), + ForkName::Eip7805 => Some(ForkName::Electra), + ForkName::Fulu => Some(ForkName::Eip7805), } } @@ -150,7 +170,8 @@ impl ForkName { ForkName::Bellatrix => Some(ForkName::Capella), ForkName::Capella => Some(ForkName::Deneb), ForkName::Deneb => Some(ForkName::Electra), - ForkName::Electra => Some(ForkName::Fulu), + ForkName::Electra => Some(ForkName::Eip7805), + ForkName::Eip7805 => Some(ForkName::Fulu), ForkName::Fulu => None, } } @@ -175,6 +196,10 @@ impl ForkName { self >= ForkName::Electra } + pub fn eip7805_enabled(self) -> bool { + self >= ForkName::Eip7805 + } + pub fn fulu_enabled(self) -> bool { self >= ForkName::Fulu } @@ -229,6 +254,10 @@ macro_rules! map_fork_name_with { let (value, extra_data) = $body; ($t::Electra(value), extra_data) } + ForkName::Eip7805 => { + let (value, extra_data) = $body; + ($t::Eip7805(value), extra_data) + } ForkName::Fulu => { let (value, extra_data) = $body; ($t::Fulu(value), extra_data) @@ -248,6 +277,7 @@ impl FromStr for ForkName { "capella" => ForkName::Capella, "deneb" => ForkName::Deneb, "electra" => ForkName::Electra, + "eip7805" => ForkName::Eip7805, "fulu" => ForkName::Fulu, _ => return Err(format!("unknown fork name: {}", fork_name)), }) @@ -263,6 +293,7 @@ impl Display for ForkName { ForkName::Capella => "capella".fmt(f), ForkName::Deneb => "deneb".fmt(f), ForkName::Electra => "electra".fmt(f), + ForkName::Eip7805 => "eip7805".fmt(f), ForkName::Fulu => "fulu".fmt(f), } } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index 4e88b6da77..847d1bc7b1 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -131,13 +131,13 @@ pub use crate::attester_slashing::{ }; pub use crate::beacon_block::{ BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BeaconBlockCapella, - BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockRef, BeaconBlockRefMut, - BlindedBeaconBlock, BlockImportSource, EmptyBlock, + BeaconBlockDeneb, BeaconBlockEip7805, BeaconBlockElectra, BeaconBlockFulu, BeaconBlockRef, + BeaconBlockRefMut, BlindedBeaconBlock, BlockImportSource, EmptyBlock, }; pub use crate::beacon_block_body::{ BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix, - BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyFulu, - BeaconBlockBodyRef, BeaconBlockBodyRefMut, + BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyEip7805, BeaconBlockBodyElectra, + BeaconBlockBodyFulu, BeaconBlockBodyRef, BeaconBlockBodyRefMut, }; pub use crate::beacon_block_header::BeaconBlockHeader; pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee}; @@ -168,13 +168,13 @@ pub use crate::execution_block_hash::ExecutionBlockHash; pub use crate::execution_block_header::{EncodableExecutionBlockHeader, ExecutionBlockHeader}; pub use crate::execution_payload::{ ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadRef, Transaction, Transactions, - Withdrawals, + ExecutionPayloadEip7805, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadRef, + Transaction, Transactions, Withdrawals, }; pub use crate::execution_payload_header::{ ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, - ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, + ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderEip7805, ExecutionPayloadHeaderElectra, + ExecutionPayloadHeaderFulu, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, }; pub use crate::execution_requests::{ExecutionRequests, RequestType}; pub use crate::fork::Fork; @@ -218,17 +218,18 @@ pub use crate::light_client_update::{ pub use crate::participation_flags::ParticipationFlags; pub use crate::payload::{ AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella, - BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadRef, BlockType, - ExecPayload, FullPayload, FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb, - FullPayloadElectra, FullPayloadFulu, FullPayloadRef, OwnedExecPayload, + BlindedPayloadDeneb, BlindedPayloadEip7805, BlindedPayloadElectra, BlindedPayloadFulu, + BlindedPayloadRef, BlockType, ExecPayload, FullPayload, FullPayloadBellatrix, + FullPayloadCapella, FullPayloadDeneb, FullPayloadEip7805, FullPayloadElectra, FullPayloadFulu, + FullPayloadRef, OwnedExecPayload, }; pub use crate::pending_attestation::PendingAttestation; pub use crate::pending_consolidation::PendingConsolidation; pub use crate::pending_deposit::PendingDeposit; pub use crate::pending_partial_withdrawal::PendingPartialWithdrawal; pub use crate::preset::{ - AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset, ElectraPreset, - FuluPreset, + AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, DenebPreset, Eip7805Preset, + ElectraPreset, FuluPreset, }; pub use crate::proposer_preparation_data::ProposerPreparationData; pub use crate::proposer_slashing::ProposerSlashing; @@ -243,8 +244,9 @@ pub use crate::signed_aggregate_and_proof::{ pub use crate::signed_beacon_block::{ ssz_tagged_signed_beacon_block, ssz_tagged_signed_beacon_block_arc, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, - SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, - SignedBeaconBlockFulu, SignedBeaconBlockHash, SignedBlindedBeaconBlock, + SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockEip7805, + SignedBeaconBlockElectra, SignedBeaconBlockFulu, 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 aa0d8836d1..cfd8aab225 100644 --- a/consensus/types/src/light_client_bootstrap.rs +++ b/consensus/types/src/light_client_bootstrap.rs @@ -99,7 +99,9 @@ impl LightClientBootstrap { } ForkName::Capella => Self::Capella(LightClientBootstrapCapella::from_ssz_bytes(bytes)?), ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?), - ForkName::Electra => Self::Electra(LightClientBootstrapElectra::from_ssz_bytes(bytes)?), + ForkName::Electra | ForkName::Eip7805 => { + Self::Electra(LightClientBootstrapElectra::from_ssz_bytes(bytes)?) + } ForkName::Fulu => Self::Fulu(LightClientBootstrapFulu::from_ssz_bytes(bytes)?), ForkName::Base => { return Err(ssz::DecodeError::BytesInvalid(format!( @@ -120,7 +122,9 @@ impl LightClientBootstrap { } ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), - ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::Electra | ForkName::Eip7805 => { + as Encode>::ssz_fixed_len() + } ForkName::Fulu => as Encode>::ssz_fixed_len(), }; fixed_len + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) @@ -152,7 +156,7 @@ impl LightClientBootstrap { current_sync_committee, current_sync_committee_branch: current_sync_committee_branch.into(), }), - ForkName::Electra => Self::Electra(LightClientBootstrapElectra { + ForkName::Electra | ForkName::Eip7805 => Self::Electra(LightClientBootstrapElectra { header: LightClientHeaderElectra::block_to_light_client_header(block)?, current_sync_committee, current_sync_committee_branch: current_sync_committee_branch.into(), @@ -197,7 +201,7 @@ impl LightClientBootstrap { current_sync_committee, current_sync_committee_branch: current_sync_committee_branch.into(), }), - ForkName::Electra => Self::Electra(LightClientBootstrapElectra { + ForkName::Electra | ForkName::Eip7805 => Self::Electra(LightClientBootstrapElectra { header: LightClientHeaderElectra::block_to_light_client_header(block)?, current_sync_committee, current_sync_committee_branch: current_sync_committee_branch.into(), diff --git a/consensus/types/src/light_client_finality_update.rs b/consensus/types/src/light_client_finality_update.rs index ee3b53c853..99c77e1272 100644 --- a/consensus/types/src/light_client_finality_update.rs +++ b/consensus/types/src/light_client_finality_update.rs @@ -131,17 +131,19 @@ impl LightClientFinalityUpdate { sync_aggregate, signature_slot, }), - ForkName::Electra => Self::Electra(LightClientFinalityUpdateElectra { - attested_header: LightClientHeaderElectra::block_to_light_client_header( - attested_block, - )?, - finalized_header: LightClientHeaderElectra::block_to_light_client_header( - finalized_block, - )?, - finality_branch: finality_branch.into(), - sync_aggregate, - signature_slot, - }), + ForkName::Electra | ForkName::Eip7805 => { + Self::Electra(LightClientFinalityUpdateElectra { + attested_header: LightClientHeaderElectra::block_to_light_client_header( + attested_block, + )?, + finalized_header: LightClientHeaderElectra::block_to_light_client_header( + finalized_block, + )?, + finality_branch: finality_branch.into(), + sync_aggregate, + signature_slot, + }) + } ForkName::Fulu => Self::Fulu(LightClientFinalityUpdateFulu { attested_header: LightClientHeaderFulu::block_to_light_client_header( attested_block, @@ -189,7 +191,7 @@ impl LightClientFinalityUpdate { Self::Capella(LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?) } ForkName::Deneb => Self::Deneb(LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?), - ForkName::Electra => { + ForkName::Electra | ForkName::Eip7805 => { Self::Electra(LightClientFinalityUpdateElectra::from_ssz_bytes(bytes)?) } ForkName::Fulu => Self::Fulu(LightClientFinalityUpdateFulu::from_ssz_bytes(bytes)?), @@ -212,7 +214,9 @@ impl LightClientFinalityUpdate { } ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), - ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::Electra | ForkName::Eip7805 => { + as Encode>::ssz_fixed_len() + } ForkName::Fulu => as Encode>::ssz_fixed_len(), }; // `2 *` because there are two headers in the update diff --git a/consensus/types/src/light_client_header.rs b/consensus/types/src/light_client_header.rs index 0be26a7036..111b1fbb6e 100644 --- a/consensus/types/src/light_client_header.rs +++ b/consensus/types/src/light_client_header.rs @@ -92,7 +92,7 @@ impl LightClientHeader { ForkName::Deneb => LightClientHeader::Deneb( LightClientHeaderDeneb::block_to_light_client_header(block)?, ), - ForkName::Electra => LightClientHeader::Electra( + ForkName::Electra | ForkName::Eip7805 => LightClientHeader::Electra( LightClientHeaderElectra::block_to_light_client_header(block)?, ), ForkName::Fulu => { @@ -113,7 +113,7 @@ impl LightClientHeader { ForkName::Deneb => { LightClientHeader::Deneb(LightClientHeaderDeneb::from_ssz_bytes(bytes)?) } - ForkName::Electra => { + ForkName::Electra | ForkName::Eip7805 => { LightClientHeader::Electra(LightClientHeaderElectra::from_ssz_bytes(bytes)?) } ForkName::Fulu => { @@ -349,7 +349,7 @@ impl ForkVersionDeserialize for LightClientHeader { ForkName::Deneb => serde_json::from_value(value) .map(|light_client_header| Self::Deneb(light_client_header)) .map_err(serde::de::Error::custom), - ForkName::Electra => serde_json::from_value(value) + ForkName::Electra | ForkName::Eip7805 => serde_json::from_value(value) .map(|light_client_header| Self::Electra(light_client_header)) .map_err(serde::de::Error::custom), ForkName::Fulu => serde_json::from_value(value) diff --git a/consensus/types/src/light_client_optimistic_update.rs b/consensus/types/src/light_client_optimistic_update.rs index fcf357757b..d373b2334d 100644 --- a/consensus/types/src/light_client_optimistic_update.rs +++ b/consensus/types/src/light_client_optimistic_update.rs @@ -98,13 +98,15 @@ impl LightClientOptimisticUpdate { sync_aggregate, signature_slot, }), - ForkName::Electra => Self::Electra(LightClientOptimisticUpdateElectra { - attested_header: LightClientHeaderElectra::block_to_light_client_header( - attested_block, - )?, - sync_aggregate, - signature_slot, - }), + ForkName::Electra | ForkName::Eip7805 => { + Self::Electra(LightClientOptimisticUpdateElectra { + attested_header: LightClientHeaderElectra::block_to_light_client_header( + attested_block, + )?, + sync_aggregate, + signature_slot, + }) + } ForkName::Fulu => Self::Fulu(LightClientOptimisticUpdateFulu { attested_header: LightClientHeaderFulu::block_to_light_client_header( attested_block, @@ -163,7 +165,7 @@ impl LightClientOptimisticUpdate { ForkName::Deneb => { Self::Deneb(LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?) } - ForkName::Electra => { + ForkName::Electra | ForkName::Eip7805 => { Self::Electra(LightClientOptimisticUpdateElectra::from_ssz_bytes(bytes)?) } ForkName::Fulu => Self::Fulu(LightClientOptimisticUpdateFulu::from_ssz_bytes(bytes)?), @@ -186,7 +188,9 @@ impl LightClientOptimisticUpdate { } ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), - ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::Electra | ForkName::Eip7805 => { + as Encode>::ssz_fixed_len() + } ForkName::Fulu => as Encode>::ssz_fixed_len(), }; 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 e1fce47975..4f339d2857 100644 --- a/consensus/types/src/light_client_update.rs +++ b/consensus/types/src/light_client_update.rs @@ -285,7 +285,7 @@ impl LightClientUpdate { signature_slot: block_slot, }) } - fork_name @ ForkName::Electra => { + fork_name @ ForkName::Electra | fork_name @ ForkName::Eip7805 => { let attested_header = LightClientHeaderElectra::block_to_light_client_header(attested_block)?; @@ -347,7 +347,9 @@ impl LightClientUpdate { } ForkName::Capella => Self::Capella(LightClientUpdateCapella::from_ssz_bytes(bytes)?), ForkName::Deneb => Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?), - ForkName::Electra => Self::Electra(LightClientUpdateElectra::from_ssz_bytes(bytes)?), + ForkName::Electra | ForkName::Eip7805 => { + Self::Electra(LightClientUpdateElectra::from_ssz_bytes(bytes)?) + } ForkName::Fulu => Self::Fulu(LightClientUpdateFulu::from_ssz_bytes(bytes)?), ForkName::Base => { return Err(ssz::DecodeError::BytesInvalid(format!( @@ -494,7 +496,9 @@ impl LightClientUpdate { ForkName::Altair => as Encode>::ssz_fixed_len(), ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), - ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::Electra | ForkName::Eip7805 => { + as Encode>::ssz_fixed_len() + } ForkName::Fulu => as Encode>::ssz_fixed_len(), }; fixed_len + 2 * LightClientHeader::::ssz_max_var_len_for_fork(fork_name) diff --git a/consensus/types/src/payload.rs b/consensus/types/src/payload.rs index abc9afd34c..02bbaeb22f 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -84,6 +84,7 @@ pub trait AbstractExecPayload: + TryInto + TryInto + TryInto + + TryInto + TryInto { type Ref<'a>: ExecPayload @@ -92,6 +93,7 @@ pub trait AbstractExecPayload: + From<&'a Self::Capella> + From<&'a Self::Deneb> + From<&'a Self::Electra> + + From<&'a Self::Eip7805> + From<&'a Self::Fulu>; type Bellatrix: OwnedExecPayload @@ -110,6 +112,10 @@ pub trait AbstractExecPayload: + Into + for<'a> From>> + TryFrom>; + type Eip7805: OwnedExecPayload + + Into + + for<'a> From>> + + TryFrom>; type Fulu: OwnedExecPayload + Into + for<'a> From>> @@ -117,7 +123,7 @@ pub trait AbstractExecPayload: } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Debug, @@ -163,6 +169,8 @@ pub struct FullPayload { pub execution_payload: ExecutionPayloadDeneb, #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] pub execution_payload: ExecutionPayloadElectra, + #[superstruct(only(Eip7805), partial_getter(rename = "execution_payload_eip7805"))] + pub execution_payload: ExecutionPayloadEip7805, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload: ExecutionPayloadFulu, } @@ -281,6 +289,9 @@ impl ExecPayload for FullPayload { FullPayload::Electra(ref inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } + FullPayload::Eip7805(ref inner) => { + Ok(inner.execution_payload.withdrawals.tree_hash_root()) + } FullPayload::Fulu(ref inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } @@ -294,6 +305,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::Eip7805(ref inner) => Ok(inner.execution_payload.blob_gas_used), FullPayload::Fulu(ref inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -325,6 +337,7 @@ impl FullPayload { ForkName::Capella => Ok(FullPayloadCapella::default().into()), ForkName::Deneb => Ok(FullPayloadDeneb::default().into()), ForkName::Electra => Ok(FullPayloadElectra::default().into()), + ForkName::Eip7805 => Ok(FullPayloadEip7805::default().into()), ForkName::Fulu => Ok(FullPayloadFulu::default().into()), } } @@ -425,6 +438,9 @@ impl ExecPayload for FullPayloadRef<'_, E> { FullPayloadRef::Electra(inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } + FullPayloadRef::Eip7805(inner) => { + Ok(inner.execution_payload.withdrawals.tree_hash_root()) + } FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), } } @@ -436,6 +452,7 @@ impl ExecPayload for FullPayloadRef<'_, E> { } FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayloadRef::Electra(inner) => Ok(inner.execution_payload.blob_gas_used), + FullPayloadRef::Eip7805(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -459,6 +476,7 @@ impl AbstractExecPayload for FullPayload { type Capella = FullPayloadCapella; type Deneb = FullPayloadDeneb; type Electra = FullPayloadElectra; + type Eip7805 = FullPayloadEip7805; type Fulu = FullPayloadFulu; } @@ -478,7 +496,7 @@ impl TryFrom> for FullPayload { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Debug, @@ -523,6 +541,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(Eip7805), partial_getter(rename = "execution_payload_eip7805"))] + pub execution_payload_header: ExecutionPayloadHeaderEip7805, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload_header: ExecutionPayloadHeaderFulu, } @@ -617,6 +637,9 @@ impl ExecPayload for BlindedPayload { BlindedPayload::Electra(ref inner) => { Ok(inner.execution_payload_header.withdrawals_root) } + BlindedPayload::Eip7805(ref inner) => { + Ok(inner.execution_payload_header.withdrawals_root) + } BlindedPayload::Fulu(ref inner) => Ok(inner.execution_payload_header.withdrawals_root), } } @@ -628,6 +651,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::Eip7805(ref inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayload::Fulu(ref inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -727,6 +751,9 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { BlindedPayloadRef::Electra(inner) => { Ok(inner.execution_payload_header.withdrawals_root) } + BlindedPayloadRef::Eip7805(inner) => { + Ok(inner.execution_payload_header.withdrawals_root) + } BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.withdrawals_root), } } @@ -738,6 +765,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::Eip7805(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -1042,6 +1070,14 @@ impl_exec_payload_for_fork!( ExecutionPayloadElectra, Electra ); + +impl_exec_payload_for_fork!( + BlindedPayloadEip7805, + FullPayloadEip7805, + ExecutionPayloadHeaderEip7805, + ExecutionPayloadEip7805, + Eip7805 +); impl_exec_payload_for_fork!( BlindedPayloadFulu, FullPayloadFulu, @@ -1056,6 +1092,7 @@ impl AbstractExecPayload for BlindedPayload { type Capella = BlindedPayloadCapella; type Deneb = BlindedPayloadDeneb; type Electra = BlindedPayloadElectra; + type Eip7805 = BlindedPayloadEip7805; type Fulu = BlindedPayloadFulu; } @@ -1093,6 +1130,11 @@ impl From> for BlindedPayload { execution_payload_header, }) } + ExecutionPayloadHeader::Eip7805(execution_payload_header) => { + Self::Eip7805(BlindedPayloadEip7805 { + execution_payload_header, + }) + } ExecutionPayloadHeader::Fulu(execution_payload_header) => { Self::Fulu(BlindedPayloadFulu { execution_payload_header, @@ -1117,6 +1159,9 @@ impl From> for ExecutionPayloadHeader { BlindedPayload::Electra(blinded_payload) => { ExecutionPayloadHeader::Electra(blinded_payload.execution_payload_header) } + BlindedPayload::Eip7805(blinded_payload) => { + ExecutionPayloadHeader::Eip7805(blinded_payload.execution_payload_header) + } BlindedPayload::Fulu(blinded_payload) => { ExecutionPayloadHeader::Fulu(blinded_payload.execution_payload_header) } diff --git a/consensus/types/src/preset.rs b/consensus/types/src/preset.rs index 707d2d4697..98fa46029f 100644 --- a/consensus/types/src/preset.rs +++ b/consensus/types/src/preset.rs @@ -273,6 +273,59 @@ impl ElectraPreset { } } +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(rename_all = "UPPERCASE")] +pub struct Eip7805Preset { + #[serde(with = "serde_utils::quoted_u64")] + pub min_activation_balance: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_effective_balance_electra: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub min_slashing_penalty_quotient_electra: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub whistleblower_reward_quotient_electra: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_pending_partials_per_withdrawals_sweep: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub pending_deposits_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub pending_partial_withdrawals_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub pending_consolidations_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_consolidation_requests_per_payload: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_deposit_requests_per_payload: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_attester_slashings_electra: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_attestations_electra: u64, + #[serde(with = "serde_utils::quoted_u64")] + pub max_withdrawal_requests_per_payload: u64, +} + +impl Eip7805Preset { + pub fn from_chain_spec(spec: &ChainSpec) -> Self { + Self { + min_activation_balance: spec.min_activation_balance, + max_effective_balance_electra: spec.max_effective_balance_electra, + min_slashing_penalty_quotient_electra: spec.min_slashing_penalty_quotient_electra, + whistleblower_reward_quotient_electra: spec.whistleblower_reward_quotient_electra, + max_pending_partials_per_withdrawals_sweep: spec + .max_pending_partials_per_withdrawals_sweep, + pending_deposits_limit: E::pending_deposits_limit() as u64, + pending_partial_withdrawals_limit: E::pending_partial_withdrawals_limit() as u64, + pending_consolidations_limit: E::pending_consolidations_limit() as u64, + max_consolidation_requests_per_payload: E::max_consolidation_requests_per_payload() + as u64, + max_deposit_requests_per_payload: E::max_deposit_requests_per_payload() as u64, + max_attester_slashings_electra: E::max_attester_slashings_electra() as u64, + max_attestations_electra: E::max_attestations_electra() as u64, + max_withdrawal_requests_per_payload: E::max_withdrawal_requests_per_payload() as u64, + } + } +} + #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] #[serde(rename_all = "UPPERCASE")] pub struct FuluPreset { @@ -340,6 +393,9 @@ mod test { let electra: ElectraPreset = preset_from_file(&preset_name, "electra.yaml"); assert_eq!(electra, ElectraPreset::from_chain_spec::(&spec)); + let eip7805: Eip7805Preset = preset_from_file(&preset_name, "eip7805.yaml"); + assert_eq!(eip7805, Eip7805Preset::from_chain_spec::(&spec)); + let fulu: FuluPreset = preset_from_file(&preset_name, "fulu.yaml"); assert_eq!(fulu, FuluPreset::from_chain_spec::(&spec)); } diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index eb5925a29b..1d059ab3b3 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -38,7 +38,7 @@ impl From for Hash256 { /// A `BeaconBlock` and a signature from its proposer. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Fulu), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Eip7805, Fulu), variant_attributes( derive( Debug, @@ -81,6 +81,8 @@ pub struct SignedBeaconBlock = FullP pub message: BeaconBlockDeneb, #[superstruct(only(Electra), partial_getter(rename = "message_electra"))] pub message: BeaconBlockElectra, + #[superstruct(only(Eip7805), partial_getter(rename = "message_eip7805"))] + pub message: BeaconBlockEip7805, #[superstruct(only(Fulu), partial_getter(rename = "message_fulu"))] pub message: BeaconBlockFulu, pub signature: Signature, @@ -166,6 +168,9 @@ impl> SignedBeaconBlock BeaconBlock::Electra(message) => { SignedBeaconBlock::Electra(SignedBeaconBlockElectra { message, signature }) } + BeaconBlock::Eip7805(message) => { + SignedBeaconBlock::Eip7805(SignedBeaconBlockEip7805 { message, signature }) + } BeaconBlock::Fulu(message) => { SignedBeaconBlock::Fulu(SignedBeaconBlockFulu { message, signature }) } @@ -576,6 +581,64 @@ impl SignedBeaconBlockElectra> { } } +impl SignedBeaconBlockEip7805> { + pub fn into_full_block( + self, + execution_payload: ExecutionPayloadEip7805, + ) -> SignedBeaconBlockEip7805> { + let SignedBeaconBlockEip7805 { + message: + BeaconBlockEip7805 { + slot, + proposer_index, + parent_root, + state_root, + body: + BeaconBlockBodyEip7805 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: BlindedPayloadEip7805 { .. }, + bls_to_execution_changes, + blob_kzg_commitments, + execution_requests, + }, + }, + signature, + } = self; + SignedBeaconBlockEip7805 { + message: BeaconBlockEip7805 { + slot, + proposer_index, + parent_root, + state_root, + body: BeaconBlockBodyEip7805 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + execution_payload: FullPayloadEip7805 { execution_payload }, + bls_to_execution_changes, + blob_kzg_commitments, + execution_requests, + }, + }, + signature, + } + } +} + impl SignedBeaconBlockFulu> { pub fn into_full_block( self, @@ -654,6 +717,9 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Electra(block), Some(ExecutionPayload::Electra(payload))) => { SignedBeaconBlock::Electra(block.into_full_block(payload)) } + (SignedBeaconBlock::Eip7805(block), Some(ExecutionPayload::Eip7805(payload))) => { + SignedBeaconBlock::Eip7805(block.into_full_block(payload)) + } (SignedBeaconBlock::Fulu(block), Some(ExecutionPayload::Fulu(payload))) => { SignedBeaconBlock::Fulu(block.into_full_block(payload)) } @@ -663,6 +729,7 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Capella(_), _) => return None, (SignedBeaconBlock::Deneb(_), _) => return None, (SignedBeaconBlock::Electra(_), _) => return None, + (SignedBeaconBlock::Eip7805(_), _) => return None, (SignedBeaconBlock::Fulu(_), _) => return None, }; Some(full_block) @@ -806,6 +873,9 @@ pub mod ssz_tagged_signed_beacon_block { ForkName::Deneb => Ok(SignedBeaconBlock::Deneb( SignedBeaconBlockDeneb::from_ssz_bytes(body)?, )), + ForkName::Eip7805 => Ok(SignedBeaconBlock::Eip7805( + SignedBeaconBlockEip7805::from_ssz_bytes(body)?, + )), ForkName::Electra => Ok(SignedBeaconBlock::Electra( SignedBeaconBlockElectra::from_ssz_bytes(body)?, )), @@ -914,6 +984,10 @@ mod test { BeaconBlock::Electra(BeaconBlockElectra::empty(spec)), sig.clone(), ), + SignedBeaconBlock::from_block( + BeaconBlock::Eip7805(BeaconBlockEip7805::empty(spec)), + sig.clone(), + ), SignedBeaconBlock::from_block(BeaconBlock::Fulu(BeaconBlockFulu::empty(spec)), sig), ]; diff --git a/lcli/src/mock_el.rs b/lcli/src/mock_el.rs index 2e2c27a2db..b77f37a59f 100644 --- a/lcli/src/mock_el.rs +++ b/lcli/src/mock_el.rs @@ -20,6 +20,7 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< let shanghai_time = parse_required(matches, "shanghai-time")?; let cancun_time = parse_optional(matches, "cancun-time")?; let prague_time = parse_optional(matches, "prague-time")?; + let eip7805_time = parse_optional(matches, "eip7805-time")?; let osaka_time = parse_optional(matches, "osaka-time")?; let handle = env.core_context().executor.handle().unwrap(); @@ -37,6 +38,7 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< terminal_block: DEFAULT_TERMINAL_BLOCK, terminal_block_hash: spec.terminal_block_hash, shanghai_time: Some(shanghai_time), + eip7805_time, cancun_time, prague_time, osaka_time, diff --git a/testing/ef_tests/src/cases/common.rs b/testing/ef_tests/src/cases/common.rs index 62f834820f..9364a35ba4 100644 --- a/testing/ef_tests/src/cases/common.rs +++ b/testing/ef_tests/src/cases/common.rs @@ -66,7 +66,8 @@ pub fn previous_fork(fork_name: ForkName) -> ForkName { ForkName::Capella => ForkName::Bellatrix, ForkName::Deneb => ForkName::Capella, ForkName::Electra => ForkName::Deneb, - ForkName::Fulu => ForkName::Electra, + ForkName::Eip7805 => ForkName::Electra, + ForkName::Fulu => ForkName::Eip7805, } } diff --git a/testing/ef_tests/src/cases/fork.rs b/testing/ef_tests/src/cases/fork.rs index 85301e22f6..d40d57af3b 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_fulu, + upgrade_to_eip7805, upgrade_to_electra, upgrade_to_fulu, }; 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::Eip7805 => upgrade_to_eip7805(&mut result_state, spec).map(|_| result_state), ForkName::Fulu => upgrade_to_fulu(&mut result_state, spec).map(|_| result_state), }; diff --git a/testing/ef_tests/src/cases/merkle_proof_validity.rs b/testing/ef_tests/src/cases/merkle_proof_validity.rs index 711974dd43..8f9b0b0381 100644 --- a/testing/ef_tests/src/cases/merkle_proof_validity.rs +++ b/testing/ef_tests/src/cases/merkle_proof_validity.rs @@ -4,7 +4,8 @@ use serde::Deserialize; use tree_hash::Hash256; use types::{ light_client_update, BeaconBlockBody, BeaconBlockBodyCapella, BeaconBlockBodyDeneb, - BeaconBlockBodyElectra, BeaconBlockBodyFulu, BeaconState, FixedVector, FullPayload, Unsigned, + BeaconBlockBodyEip7805, BeaconBlockBodyElectra, BeaconBlockBodyFulu, BeaconState, FixedVector, + FullPayload, Unsigned, }; #[derive(Debug, Clone, Deserialize)] @@ -168,6 +169,10 @@ impl LoadCase for KzgInclusionMerkleProofValidity { ssz_decode_file::>(&path.join("object.ssz_snappy"))? .into() } + ForkName::Eip7805 => { + ssz_decode_file::>(&path.join("object.ssz_snappy"))? + .into() + } ForkName::Fulu => { ssz_decode_file::>(&path.join("object.ssz_snappy"))?.into() } @@ -286,6 +291,10 @@ impl LoadCase for BeaconBlockBodyMerkleProofValidity { ssz_decode_file::>(&path.join("object.ssz_snappy"))? .into() } + ForkName::Eip7805 => { + ssz_decode_file::>(&path.join("object.ssz_snappy"))? + .into() + } ForkName::Fulu => { ssz_decode_file::>(&path.join("object.ssz_snappy"))?.into() } diff --git a/testing/ef_tests/src/cases/transition.rs b/testing/ef_tests/src/cases/transition.rs index 6d037dae87..0a21fe3fbc 100644 --- a/testing/ef_tests/src/cases/transition.rs +++ b/testing/ef_tests/src/cases/transition.rs @@ -60,6 +60,14 @@ impl LoadCase for TransitionTest { spec.deneb_fork_epoch = Some(Epoch::new(0)); spec.electra_fork_epoch = Some(metadata.fork_epoch); } + ForkName::Eip7805 => { + 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.electra_fork_epoch = Some(Epoch::new(0)); + spec.eip7805_fork_epoch = Some(metadata.fork_epoch); + } ForkName::Fulu => { spec.altair_fork_epoch = Some(Epoch::new(0)); spec.bellatrix_fork_epoch = Some(Epoch::new(0)); diff --git a/validator_client/signing_method/src/web3signer.rs b/validator_client/signing_method/src/web3signer.rs index 885b53683f..25a5fa4136 100644 --- a/validator_client/signing_method/src/web3signer.rs +++ b/validator_client/signing_method/src/web3signer.rs @@ -30,6 +30,7 @@ pub enum ForkName { Capella, Deneb, Electra, + Eip7805, Fulu, } @@ -110,6 +111,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> Web3SignerObject<'a, E, Pa block: None, block_header: Some(block.block_header()), }), + BeaconBlock::Eip7805(_) => Ok(Web3SignerObject::BeaconBlock { + version: ForkName::Eip7805, + block: None, + block_header: Some(block.block_header()), + }), BeaconBlock::Fulu(_) => Ok(Web3SignerObject::BeaconBlock { version: ForkName::Fulu, block: None,