From 13130dfa4fa4ebcc2412721b883e152eacf69277 Mon Sep 17 00:00:00 2001 From: Mark Mackey Date: Tue, 27 Aug 2024 12:38:00 -0500 Subject: [PATCH] EIP-7732 Boiler Plate --- .../beacon_chain/src/attestation_rewards.rs | 3 +- .../beacon_chain/src/beacon_block_streamer.rs | 5 +- beacon_node/beacon_chain/src/beacon_chain.rs | 5 +- .../beacon_chain/src/execution_payload.rs | 11 +- beacon_node/beacon_chain/src/test_utils.rs | 12 +- .../execution_layer/src/engine_api/http.rs | 18 ++- .../src/engine_api/json_structures.rs | 3 + .../src/engine_api/new_payload_request.rs | 4 + beacon_node/execution_layer/src/lib.rs | 10 +- .../test_utils/execution_block_generator.rs | 2 + .../src/test_utils/mock_builder.rs | 12 ++ .../lighthouse_network/src/rpc/codec.rs | 22 ++- .../lighthouse_network/src/rpc/protocol.rs | 19 +++ .../lighthouse_network/src/types/pubsub.rs | 9 +- .../lighthouse_network/src/types/topics.rs | 1 + beacon_node/store/src/partial_beacon_state.rs | 63 +++++--- common/eth2/src/types.rs | 17 ++- consensus/fork_choice/src/fork_choice.rs | 3 +- .../common/get_attestation_participation.rs | 2 +- .../src/common/slash_validator.rs | 3 +- .../src/per_block_processing.rs | 3 + .../process_operations.rs | 3 + .../per_block_processing/signature_sets.rs | 11 +- .../verify_attestation.rs | 2 +- .../src/per_epoch_processing.rs | 3 +- consensus/types/src/beacon_block.rs | 134 +++++++++++++++++- consensus/types/src/beacon_block_body.rs | 121 +++++++++++++++- consensus/types/src/beacon_state.rs | 107 +++++++++++--- .../progressive_balances_cache.rs | 3 +- consensus/types/src/builder_bid.rs | 3 +- consensus/types/src/chain_spec.rs | 71 ++++++++-- consensus/types/src/dumb_macros.rs | 92 ++++++++++++ consensus/types/src/execution_bid.rs | 41 ++++++ consensus/types/src/execution_payload.rs | 27 +++- .../types/src/execution_payload_header.rs | 7 +- consensus/types/src/fork_context.rs | 7 + consensus/types/src/fork_name.rs | 32 ++++- consensus/types/src/lib.rs | 18 ++- consensus/types/src/light_client_bootstrap.rs | 4 + .../types/src/light_client_finality_update.rs | 3 + consensus/types/src/light_client_header.rs | 7 + .../src/light_client_optimistic_update.rs | 3 + consensus/types/src/light_client_update.rs | 7 +- consensus/types/src/payload.rs | 1 + consensus/types/src/signed_beacon_block.rs | 28 +++- testing/ef_tests/src/cases/common.rs | 13 -- .../ef_tests/src/cases/epoch_processing.rs | 18 ++- testing/ef_tests/src/cases/fork.rs | 9 +- .../src/cases/merkle_proof_validity.rs | 12 +- testing/ef_tests/src/cases/operations.rs | 16 ++- testing/ef_tests/src/cases/transition.rs | 8 ++ .../signing_method/src/web3signer.rs | 6 + 52 files changed, 891 insertions(+), 153 deletions(-) create mode 100644 consensus/types/src/dumb_macros.rs create mode 100644 consensus/types/src/execution_bid.rs diff --git a/beacon_node/beacon_chain/src/attestation_rewards.rs b/beacon_node/beacon_chain/src/attestation_rewards.rs index 87b7384ea6..4903c869cb 100644 --- a/beacon_node/beacon_chain/src/attestation_rewards.rs +++ b/beacon_node/beacon_chain/src/attestation_rewards.rs @@ -57,7 +57,8 @@ impl BeaconChain { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => self.compute_attestation_rewards_altair(state, validators), + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => self.compute_attestation_rewards_altair(state, validators), } } diff --git a/beacon_node/beacon_chain/src/beacon_block_streamer.rs b/beacon_node/beacon_chain/src/beacon_block_streamer.rs index b76dba88fd..9bc5a10beb 100644 --- a/beacon_node/beacon_chain/src/beacon_block_streamer.rs +++ b/beacon_node/beacon_chain/src/beacon_block_streamer.rs @@ -10,8 +10,8 @@ use tokio::sync::{ }; use tokio_stream::{wrappers::UnboundedReceiverStream, Stream}; use types::{ - ChainSpec, EthSpec, ExecPayload, ExecutionBlockHash, ForkName, Hash256, SignedBeaconBlock, - SignedBlindedBeaconBlock, Slot, + ChainSpec, EthSpec, ExecPayload, ExecutionBlockHash, ExecutionPayloadEIP7732, ForkName, + Hash256, SignedBeaconBlock, SignedBlindedBeaconBlock, Slot, }; use types::{ ExecutionPayload, ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadElectra, @@ -99,6 +99,7 @@ fn reconstruct_default_header_block( ForkName::Capella => ExecutionPayloadCapella::default().into(), ForkName::Deneb => ExecutionPayloadDeneb::default().into(), ForkName::Electra => ExecutionPayloadElectra::default().into(), + ForkName::EIP7732 => ExecutionPayloadEIP7732::default().into(), ForkName::Base | ForkName::Altair => { return Err(Error::PayloadReconstruction(format!( "Block with fork variant {} has execution payload", diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 80766d57b3..fcfa743952 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5322,7 +5322,8 @@ impl BeaconChain { BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => { let prepare_payload_handle = get_execution_payload( self.clone(), &state, @@ -5751,6 +5752,7 @@ impl BeaconChain { execution_payload_value, ) } + BeaconState::EIP7732(_) => todo!("EIP-7732 block production"), }; let block = SignedBeaconBlock::from_block( @@ -6069,7 +6071,6 @@ impl BeaconChain { payload_attributes } else { let prepare_slot_fork = self.spec.fork_name_at_slot::(prepare_slot); - let withdrawals = if prepare_slot_fork.capella_enabled() { let chain = self.clone(); self.spawn_blocking_handle( diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index f2420eea0d..b4aa2ff781 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -378,15 +378,18 @@ pub fn get_execution_payload( let latest_execution_payload_header_block_hash = state.latest_execution_payload_header()?.block_hash(); let withdrawals = match state { - &BeaconState::Capella(_) | &BeaconState::Deneb(_) | &BeaconState::Electra(_) => { - Some(get_expected_withdrawals(state, spec)?.0.into()) - } + &BeaconState::Capella(_) + | &BeaconState::Deneb(_) + | &BeaconState::Electra(_) + | &BeaconState::EIP7732(_) => Some(get_expected_withdrawals(state, spec)?.0.into()), &BeaconState::Bellatrix(_) => None, // These shouldn't happen but they're here to make the pattern irrefutable &BeaconState::Base(_) | &BeaconState::Altair(_) => None, }; let parent_beacon_block_root = match state { - BeaconState::Deneb(_) | BeaconState::Electra(_) => Some(parent_block_root), + BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::EIP7732(_) => { + Some(parent_block_root) + } BeaconState::Bellatrix(_) | BeaconState::Capella(_) => None, // These shouldn't happen but they're here to make the pattern irrefutable BeaconState::Base(_) | BeaconState::Altair(_) => None, diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 093ee0c44b..344a66acd1 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -918,9 +918,9 @@ where | SignedBeaconBlock::Altair(_) | SignedBeaconBlock::Bellatrix(_) | SignedBeaconBlock::Capella(_) => (signed_block, None), - SignedBeaconBlock::Deneb(_) | SignedBeaconBlock::Electra(_) => { - (signed_block, block_response.blob_items) - } + SignedBeaconBlock::Deneb(_) + | SignedBeaconBlock::Electra(_) + | SignedBeaconBlock::EIP7732(_) => (signed_block, block_response.blob_items), }; (block_contents, block_response.state) @@ -982,9 +982,9 @@ where | SignedBeaconBlock::Altair(_) | SignedBeaconBlock::Bellatrix(_) | SignedBeaconBlock::Capella(_) => (signed_block, None), - SignedBeaconBlock::Deneb(_) | SignedBeaconBlock::Electra(_) => { - (signed_block, block_response.blob_items) - } + SignedBeaconBlock::Deneb(_) + | SignedBeaconBlock::Electra(_) + | SignedBeaconBlock::EIP7732(_) => (signed_block, block_response.blob_items), }; (block_contents, pre_state) } diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index d4734be448..eaac313768 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -882,9 +882,14 @@ impl HttpJsonRpc { .try_into() .map_err(Error::BadResponse) } - ForkName::Base | ForkName::Altair | ForkName::Deneb | ForkName::Electra => Err( - Error::UnsupportedForkVariant(format!("called get_payload_v2 with {}", fork_name)), - ), + ForkName::Base + | ForkName::Altair + | ForkName::Deneb + | ForkName::Electra + | ForkName::EIP7732 => Err(Error::UnsupportedForkVariant(format!( + "called get_payload_v2 with {}", + fork_name + ))), } } @@ -912,7 +917,8 @@ impl HttpJsonRpc { | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella - | ForkName::Electra => Err(Error::UnsupportedForkVariant(format!( + | ForkName::Electra + | ForkName::EIP7732 => Err(Error::UnsupportedForkVariant(format!( "called get_payload_v3 with {}", fork_name ))), @@ -943,7 +949,8 @@ impl HttpJsonRpc { | ForkName::Altair | ForkName::Bellatrix | ForkName::Capella - | ForkName::Deneb => Err(Error::UnsupportedForkVariant(format!( + | ForkName::Deneb + | ForkName::EIP7732 => Err(Error::UnsupportedForkVariant(format!( "called get_payload_v4 with {}", fork_name ))), @@ -1249,6 +1256,7 @@ impl HttpJsonRpc { Err(Error::RequiredMethodUnsupported("engine_getPayloadv4")) } } + ForkName::EIP7732 => todo!("EIP-7732 Engine API get_payload"), ForkName::Base | ForkName::Altair => Err(Error::UnsupportedForkVariant(format!( "called get_payload with {}", fork_name 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 efd68f1023..7563c83608 100644 --- a/beacon_node/execution_layer/src/engine_api/json_structures.rs +++ b/beacon_node/execution_layer/src/engine_api/json_structures.rs @@ -219,6 +219,9 @@ 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::EIP7732(_payload) => { + todo!("EIP-7732 Engine API: JsonExecutionPayload conversion") + } } } } 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 318779b7f3..d19f52b7ca 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 @@ -187,6 +187,8 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> parent_beacon_block_root: block_ref.parent_root, execution_requests_list: &block_ref.body.execution_requests, })), + //TODO(EIP7732): Need new method of constructing NewPayloadRequest + BeaconBlockRef::EIP7732(_) => Err(Self::Error::IncorrectStateVariant), } } } @@ -206,6 +208,8 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<' })), ExecutionPayloadRef::Deneb(_) => Err(Self::Error::IncorrectStateVariant), ExecutionPayloadRef::Electra(_) => Err(Self::Error::IncorrectStateVariant), + //TODO(EIP7732): Probably time to just get rid of this + ExecutionPayloadRef::EIP7732(_) => Err(Self::Error::IncorrectStateVariant), } } } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 08a00d7bf8..43305cce13 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -49,13 +49,12 @@ use types::builder_bid::BuilderBid; use types::non_zero_usize::new_non_zero_usize; use types::payload::BlockProductionVersion; use types::{ - AbstractExecPayload, BlobsList, ExecutionPayloadDeneb, ExecutionRequests, KzgProofs, - SignedBlindedBeaconBlock, + AbstractExecPayload, BlobsList, ExecutionRequests, KzgProofs, SignedBlindedBeaconBlock, }; use types::{ BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix, - ExecutionPayloadCapella, ExecutionPayloadElectra, FullPayload, ProposerPreparationData, - PublicKeyBytes, Signature, Slot, + ExecutionPayloadCapella, ExecutionPayloadDeneb, ExecutionPayloadElectra, FullPayload, + ProposerPreparationData, PublicKeyBytes, Signature, Slot, }; mod block_hash; @@ -1833,6 +1832,9 @@ impl ExecutionLayer { ForkName::Base | ForkName::Altair => { return Err(Error::InvalidForkForPayload); } + ForkName::EIP7732 => { + return Err(Error::InvalidForkForPayload); + } }; return Ok(Some(payload)); } diff --git a/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs b/beacon_node/execution_layer/src/test_utils/execution_block_generator.rs index 4deb91e056..ce42d94ca2 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 @@ -800,6 +800,8 @@ pub fn generate_genesis_header( *header.transactions_root_mut() = empty_transactions_root; Some(header) } + // TODO(EIP-7732): need to look into this + ForkName::EIP7732 => None, } } 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 341daedbc8..606f6f92dc 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -348,6 +348,9 @@ pub fn serve( SignedBlindedBeaconBlock::Electra(block) => { block.message.body.execution_payload.tree_hash_root() } + SignedBlindedBeaconBlock::EIP7732(_) => { + return Err(reject("invalid fork EIP7732")); + } }; let payload = builder .el @@ -498,6 +501,9 @@ pub fn serve( // first to avoid polluting the execution block generator with invalid payload attributes // NOTE: this was part of an effort to add payload attribute uniqueness checks, // which was abandoned because it broke too many tests in subtle ways. + ForkName::EIP7732 => { + return Err(reject("invalid fork")); + } ForkName::Bellatrix | ForkName::Capella => PayloadAttributes::new( timestamp, *prev_randao, @@ -551,6 +557,9 @@ pub fn serve( ) = payload_response.into(); match fork { + ForkName::EIP7732 => { + return Err(reject("invalid fork")); + } ForkName::Electra => BuilderBid::Electra(BuilderBidElectra { header: payload .as_electra() @@ -603,6 +612,9 @@ pub fn serve( Option>, ) = payload_response.into(); match fork { + ForkName::EIP7732 => { + return Err(reject("invalid fork")); + } ForkName::Electra => BuilderBid::Electra(BuilderBidElectra { header: payload .as_electra() diff --git a/beacon_node/lighthouse_network/src/rpc/codec.rs b/beacon_node/lighthouse_network/src/rpc/codec.rs index 5d86936d41..6d07da4ba9 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec.rs @@ -20,7 +20,7 @@ use types::{ LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate, LightClientUpdate, RuntimeVariableList, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, - SignedBeaconBlockDeneb, SignedBeaconBlockElectra, + SignedBeaconBlockDeneb, SignedBeaconBlockEIP7732, SignedBeaconBlockElectra, }; use unsigned_varint::codec::Uvi; @@ -458,6 +458,9 @@ fn context_bytes( return match **ref_box_block { // NOTE: If you are adding another fork type here, be sure to modify the // `fork_context.to_context_bytes()` function to support it as well! + SignedBeaconBlock::EIP7732 { .. } => { + fork_context.to_context_bytes(ForkName::EIP7732) + } SignedBeaconBlock::Electra { .. } => { fork_context.to_context_bytes(ForkName::Electra) } @@ -682,7 +685,7 @@ fn handle_rpc_response( SignedBeaconBlock::Base(SignedBeaconBlockBase::from_ssz_bytes(decoded_buffer)?), )))), SupportedProtocol::BlobsByRangeV1 => match fork_name { - Some(ForkName::Deneb) | Some(ForkName::Electra) => { + Some(ForkName::Deneb) | Some(ForkName::Electra) | Some(ForkName::EIP7732) => { Ok(Some(RpcSuccessResponse::BlobsByRange(Arc::new( BlobSidecar::from_ssz_bytes(decoded_buffer)?, )))) @@ -703,7 +706,7 @@ fn handle_rpc_response( )), }, SupportedProtocol::BlobsByRootV1 => match fork_name { - Some(ForkName::Deneb) | Some(ForkName::Electra) => { + Some(ForkName::Deneb) | Some(ForkName::Electra) | Some(ForkName::EIP7732) => { Ok(Some(RpcSuccessResponse::BlobsByRoot(Arc::new( BlobSidecar::from_ssz_bytes(decoded_buffer)?, )))) @@ -864,6 +867,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::EIP7732) => Ok(Some(RpcSuccessResponse::BlocksByRange(Arc::new( + SignedBeaconBlock::EIP7732(SignedBeaconBlockEIP7732::from_ssz_bytes( + decoded_buffer, + )?), + )))), None => Err(RPCError::ErrorResponse( RpcErrorResponse::InvalidRequest, format!( @@ -897,6 +905,11 @@ fn handle_rpc_response( decoded_buffer, )?), )))), + Some(ForkName::EIP7732) => Ok(Some(RpcSuccessResponse::BlocksByRoot(Arc::new( + SignedBeaconBlock::EIP7732(SignedBeaconBlockEIP7732::from_ssz_bytes( + decoded_buffer, + )?), + )))), None => Err(RPCError::ErrorResponse( RpcErrorResponse::InvalidRequest, format!( @@ -948,12 +961,14 @@ mod tests { let capella_fork_epoch = Epoch::new(3); let deneb_fork_epoch = Epoch::new(4); let electra_fork_epoch = Epoch::new(5); + let eip7732_fork_epoch = Epoch::new(6); chain_spec.altair_fork_epoch = Some(altair_fork_epoch); chain_spec.bellatrix_fork_epoch = Some(bellatrix_fork_epoch); chain_spec.capella_fork_epoch = Some(capella_fork_epoch); chain_spec.deneb_fork_epoch = Some(deneb_fork_epoch); chain_spec.electra_fork_epoch = Some(electra_fork_epoch); + chain_spec.eip7732_fork_epoch = Some(eip7732_fork_epoch); let current_slot = match fork_name { ForkName::Base => Slot::new(0), @@ -962,6 +977,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::EIP7732 => eip7732_fork_epoch.start_slot(Spec::slots_per_epoch()), }; ForkContext::new::(current_slot, Hash256::zero(), &chain_spec) } diff --git a/beacon_node/lighthouse_network/src/rpc/protocol.rs b/beacon_node/lighthouse_network/src/rpc/protocol.rs index 57c2795b04..25a95d2c47 100644 --- a/beacon_node/lighthouse_network/src/rpc/protocol.rs +++ b/beacon_node/lighthouse_network/src/rpc/protocol.rs @@ -209,6 +209,11 @@ pub fn rpc_block_limits_by_fork(current_fork: ForkName) -> RpcLimits { *SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and bellatrix blocks *SIGNED_BEACON_BLOCK_ELECTRA_MAX, // Electra block is larger than Deneb block ), + // TODO(EIP7732): check this + ForkName::EIP7732 => RpcLimits::new( + *SIGNED_BEACON_BLOCK_BASE_MIN, // Base block is smaller than altair and bellatrix blocks + *SIGNED_BEACON_BLOCK_ELECTRA_MAX, // Electra block is larger than EIP7732 block + ), } } @@ -229,6 +234,9 @@ fn rpc_light_client_updates_by_range_limits_by_fork(current_fork: ForkName) -> R ForkName::Electra => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_ELECTRA_MAX) } + ForkName::EIP7732 => { + RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_UPDATES_BY_RANGE_ELECTRA_MAX) + } } } @@ -249,6 +257,10 @@ fn rpc_light_client_finality_update_limits_by_fork(current_fork: ForkName) -> Rp ForkName::Electra => { RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_ELECTRA_MAX) } + // TODO(EIP7732): check this + ForkName::EIP7732 => { + RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_FINALITY_UPDATE_ELECTRA_MAX) + } } } @@ -271,6 +283,11 @@ fn rpc_light_client_optimistic_update_limits_by_fork(current_fork: ForkName) -> altair_fixed_len, *LIGHT_CLIENT_OPTIMISTIC_UPDATE_ELECTRA_MAX, ), + // TODO(EIP7732): check this + ForkName::EIP7732 => RpcLimits::new( + altair_fixed_len, + *LIGHT_CLIENT_OPTIMISTIC_UPDATE_ELECTRA_MAX, + ), } } @@ -285,6 +302,8 @@ fn rpc_light_client_bootstrap_limits_by_fork(current_fork: ForkName) -> RpcLimit ForkName::Capella => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_CAPELLA_MAX), ForkName::Deneb => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_DENEB_MAX), ForkName::Electra => RpcLimits::new(altair_fixed_len, *LIGHT_CLIENT_BOOTSTRAP_ELECTRA_MAX), + // TODO(EIP7732): check this + ForkName::EIP7732 => 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 9f68278e28..d9067f88cd 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -13,8 +13,9 @@ use types::{ ProposerSlashing, SignedAggregateAndProof, SignedAggregateAndProofBase, SignedAggregateAndProofElectra, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, - SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBlsToExecutionChange, - SignedContributionAndProof, SignedVoluntaryExit, SubnetId, SyncCommitteeMessage, SyncSubnetId, + SignedBeaconBlockDeneb, SignedBeaconBlockEIP7732, SignedBeaconBlockElectra, + SignedBlsToExecutionChange, SignedContributionAndProof, SignedVoluntaryExit, SubnetId, + SyncCommitteeMessage, SyncSubnetId, }; #[derive(Debug, Clone, PartialEq)] @@ -242,6 +243,10 @@ impl PubsubMessage { SignedBeaconBlockElectra::from_ssz_bytes(data) .map_err(|e| format!("{:?}", e))?, ), + Some(ForkName::EIP7732) => SignedBeaconBlock::::EIP7732( + SignedBeaconBlockEIP7732::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?, + ), None => { return Err(format!( "Unknown gossipsub fork digest: {:?}", diff --git a/beacon_node/lighthouse_network/src/types/topics.rs b/beacon_node/lighthouse_network/src/types/topics.rs index 174787f999..0697d85be8 100644 --- a/beacon_node/lighthouse_network/src/types/topics.rs +++ b/beacon_node/lighthouse_network/src/types/topics.rs @@ -61,6 +61,7 @@ pub fn fork_core_topics(fork_name: &ForkName, spec: &ChainSpec) -> V deneb_topics } ForkName::Electra => vec![], + ForkName::EIP7732 => todo!("EIP-7732 core topics"), } } diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs index 2eb40f47b1..8a22fd1e42 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), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, EIP7732), 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))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] pub current_epoch_participation: List, // Finality @@ -80,13 +80,13 @@ where pub finalized_checkpoint: Checkpoint, // Inactivity - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] pub inactivity_scores: List, // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] pub next_sync_committee: Arc>, // Execution @@ -110,37 +110,39 @@ where partial_getter(rename = "latest_execution_payload_header_electra") )] pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, + #[superstruct(only(EIP7732), partial_getter(rename = "latest_execution_bid_eip7732"))] + pub latest_execution_bid: ExecutionBid, // Capella - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732))] pub next_withdrawal_validator_index: u64, #[ssz(skip_serializing, skip_deserializing)] - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732))] pub historical_summaries: Option>, // Electra - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub deposit_requests_start_index: u64, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub deposit_balance_to_consume: u64, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub exit_balance_to_consume: u64, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub earliest_exit_epoch: Epoch, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub consolidation_balance_to_consume: u64, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub earliest_consolidation_epoch: Epoch, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub pending_balance_deposits: List, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub pending_partial_withdrawals: List, - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub pending_consolidations: List, } @@ -409,6 +411,31 @@ impl TryInto> for PartialBeaconState { ], [historical_summaries] ), + PartialBeaconState::EIP7732(inner) => impl_try_into_beacon_state!( + inner, + EIP7732, + BeaconStateEIP7732, + [ + previous_epoch_participation, + current_epoch_participation, + current_sync_committee, + next_sync_committee, + inactivity_scores, + latest_execution_bid, + 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_balance_deposits, + pending_partial_withdrawals, + pending_consolidations + ], + [historical_summaries] + ), }; Ok(state) } diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index c187399ebd..0bf42f6400 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -1078,6 +1078,10 @@ impl ForkVersionDeserialize for SsePayloadAttributes { ForkName::Electra => serde_json::from_value(value) .map(Self::V3) .map_err(serde::de::Error::custom), + // TODO(EIP7732): check this + ForkName::EIP7732 => serde_json::from_value(value) + .map(Self::V3) + .map_err(serde::de::Error::custom), ForkName::Base | ForkName::Altair => Err(serde::de::Error::custom(format!( "SsePayloadAttributes deserialization for {fork_name} not implemented" ))), @@ -1883,7 +1887,9 @@ impl TryFrom>> for PublishBlockRequest { | SignedBeaconBlock::Altair(_) | SignedBeaconBlock::Bellatrix(_) | SignedBeaconBlock::Capella(_) => Ok(PublishBlockRequest::Block(block)), - SignedBeaconBlock::Deneb(_) | SignedBeaconBlock::Electra(_) => Err( + SignedBeaconBlock::Deneb(_) + | SignedBeaconBlock::Electra(_) + | SignedBeaconBlock::EIP7732(_) => Err( "post-Deneb block contents cannot be fully constructed from just the signed block", ), } @@ -1993,9 +1999,12 @@ impl ForkVersionDeserialize for FullPayloadContents { ForkName::Bellatrix | ForkName::Capella => serde_json::from_value(value) .map(Self::Payload) .map_err(serde::de::Error::custom), - ForkName::Deneb | ForkName::Electra => serde_json::from_value(value) - .map(Self::PayloadAndBlobs) - .map_err(serde::de::Error::custom), + // TODO(EIP7732): check this + ForkName::Deneb | ForkName::Electra | ForkName::EIP7732 => { + serde_json::from_value(value) + .map(Self::PayloadAndBlobs) + .map_err(serde::de::Error::custom) + } ForkName::Base | ForkName::Altair => Err(serde::de::Error::custom(format!( "FullPayloadContents deserialization for {fork_name} not implemented" ))), diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index 85704042df..1cea369719 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -756,7 +756,8 @@ where (parent_justified, parent_finalized) } else { let justification_and_finalization_state = match block { - BeaconBlockRef::Electra(_) + BeaconBlockRef::EIP7732(_) + | BeaconBlockRef::Electra(_) | BeaconBlockRef::Deneb(_) | BeaconBlockRef::Capella(_) | BeaconBlockRef::Bellatrix(_) diff --git a/consensus/state_processing/src/common/get_attestation_participation.rs b/consensus/state_processing/src/common/get_attestation_participation.rs index fc09dad1f4..5bc854b6e3 100644 --- a/consensus/state_processing/src/common/get_attestation_participation.rs +++ b/consensus/state_processing/src/common/get_attestation_participation.rs @@ -53,7 +53,7 @@ pub fn get_attestation_participation_flag_indices( participation_flag_indices.push(TIMELY_TARGET_FLAG_INDEX); } } - &BeaconState::Deneb(_) | &BeaconState::Electra(_) => { + &BeaconState::Deneb(_) | &BeaconState::Electra(_) | &BeaconState::EIP7732(_) => { if is_matching_target { // [Modified in Deneb:EIP7045] participation_flag_indices.push(TIMELY_TARGET_FLAG_INDEX); diff --git a/consensus/state_processing/src/common/slash_validator.rs b/consensus/state_processing/src/common/slash_validator.rs index 80d857cc00..6dda341314 100644 --- a/consensus/state_processing/src/common/slash_validator.rs +++ b/consensus/state_processing/src/common/slash_validator.rs @@ -61,7 +61,8 @@ pub fn slash_validator( | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => whistleblower_reward + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => whistleblower_reward .safe_mul(PROPOSER_WEIGHT)? .safe_div(WEIGHT_DENOMINATOR)?, }; diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index f289b6e081..33ee8c2099 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -462,6 +462,8 @@ pub fn is_merge_transition_complete(state: &BeaconState) -> bool .unwrap_or(false), BeaconState::Electra(_) | BeaconState::Deneb(_) | BeaconState::Capella(_) => true, BeaconState::Base(_) | BeaconState::Altair(_) => false, + // TODO(EIP7732): check this cause potuz modified this function for god knows what reason + BeaconState::EIP7732(_) => true, } } /// https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#is_merge_transition_block @@ -662,5 +664,6 @@ pub fn process_withdrawals>( } // these shouldn't even be encountered but they're here for completeness BeaconState::Base(_) | BeaconState::Altair(_) | BeaconState::Bellatrix(_) => Ok(()), + BeaconState::EIP7732(_) => todo!("implement potuz' changes to process_withdrawals()"), } } diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index a53dc15126..92d856bfe2 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -308,6 +308,9 @@ pub fn process_attestations>( spec, )?; } + BeaconBlockBodyRef::EIP7732(_) => { + todo!("EIP-7732 implement process_operations()"); + } } Ok(()) } diff --git a/consensus/state_processing/src/per_block_processing/signature_sets.rs b/consensus/state_processing/src/per_block_processing/signature_sets.rs index 2e00ee0341..668945cf7c 100644 --- a/consensus/state_processing/src/per_block_processing/signature_sets.rs +++ b/consensus/state_processing/src/per_block_processing/signature_sets.rs @@ -398,11 +398,12 @@ where state.genesis_validators_root(), ), // EIP-7044 - BeaconState::Deneb(_) | BeaconState::Electra(_) => spec.compute_domain( - Domain::VoluntaryExit, - spec.capella_fork_version, - state.genesis_validators_root(), - ), + BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::EIP7732(_) => spec + .compute_domain( + Domain::VoluntaryExit, + spec.capella_fork_version, + state.genesis_validators_root(), + ), }; let message = exit.signing_root(domain); diff --git a/consensus/state_processing/src/per_block_processing/verify_attestation.rs b/consensus/state_processing/src/per_block_processing/verify_attestation.rs index 6bfb51d475..aee9a4e5d7 100644 --- a/consensus/state_processing/src/per_block_processing/verify_attestation.rs +++ b/consensus/state_processing/src/per_block_processing/verify_attestation.rs @@ -46,7 +46,7 @@ pub fn verify_attestation_for_block_inclusion<'ctxt, E: EthSpec>( ); } // [Modified in Deneb:EIP7045] - BeaconState::Deneb(_) | BeaconState::Electra(_) => {} + BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::EIP7732(_) => {} } verify_attestation_for_state(state, attestation, ctxt, verify_signatures, spec) diff --git a/consensus/state_processing/src/per_epoch_processing.rs b/consensus/state_processing/src/per_epoch_processing.rs index 55e8853f3f..e01852705a 100644 --- a/consensus/state_processing/src/per_epoch_processing.rs +++ b/consensus/state_processing/src/per_epoch_processing.rs @@ -47,7 +47,8 @@ pub fn process_epoch( | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_epoch(state, spec), + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => altair::process_epoch(state, spec), } } diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index 801b7dd1c7..d8b1277fb7 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -16,7 +16,7 @@ use self::indexed_attestation::{IndexedAttestationBase, IndexedAttestationElectr /// A block of the `BeaconChain`. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, EIP7732), 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(EIP7732), partial_getter(rename = "body_eip7732"))] + pub body: BeaconBlockBodyEIP7732, } pub type BlindedBeaconBlock = BeaconBlock>; @@ -127,8 +129,9 @@ impl> BeaconBlock { /// Usually it's better to prefer `from_ssz_bytes` which will decode the correct variant based /// on the fork slot. pub fn any_from_ssz_bytes(bytes: &[u8]) -> Result { - BeaconBlockElectra::from_ssz_bytes(bytes) - .map(BeaconBlock::Electra) + BeaconBlockEIP7732::from_ssz_bytes(bytes) + .map(BeaconBlock::EIP7732) + .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)) .or_else(|_| BeaconBlockBellatrix::from_ssz_bytes(bytes).map(BeaconBlock::Bellatrix)) @@ -226,6 +229,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockRef<'a, E, Payl BeaconBlockRef::Capella { .. } => ForkName::Capella, BeaconBlockRef::Deneb { .. } => ForkName::Deneb, BeaconBlockRef::Electra { .. } => ForkName::Electra, + BeaconBlockRef::EIP7732 { .. } => ForkName::EIP7732, } } @@ -673,6 +677,77 @@ impl> BeaconBlockElectra } } +impl> BeaconBlockEIP7732 { + /// Return a Electra block where the block has maximum size. + pub fn full(spec: &ChainSpec) -> Self { + let base_block: BeaconBlockBase<_, Payload> = BeaconBlockBase::full(spec); + let indexed_attestation: IndexedAttestationElectra = IndexedAttestationElectra { + attesting_indices: VariableList::new(vec![0_u64; E::MaxValidatorsPerSlot::to_usize()]) + .unwrap(), + data: AttestationData::default(), + signature: AggregateSignature::empty(), + }; + let attester_slashings = vec![ + AttesterSlashingElectra { + attestation_1: indexed_attestation.clone(), + attestation_2: indexed_attestation, + }; + E::max_attester_slashings_electra() + ] + .into(); + let attestation = AttestationElectra { + aggregation_bits: BitList::with_capacity(E::MaxValidatorsPerSlot::to_usize()).unwrap(), + data: AttestationData::default(), + signature: AggregateSignature::empty(), + committee_bits: BitVector::new(), + }; + let mut attestations_electra = vec![]; + for _ in 0..E::MaxAttestationsElectra::to_usize() { + attestations_electra.push(attestation.clone()); + } + + let bls_to_execution_changes = vec![ + SignedBlsToExecutionChange { + message: BlsToExecutionChange { + validator_index: 0, + from_bls_pubkey: PublicKeyBytes::empty(), + to_execution_address: Address::zero(), + }, + signature: Signature::empty() + }; + E::max_bls_to_execution_changes() + ] + .into(); + let sync_aggregate = SyncAggregate { + sync_committee_signature: AggregateSignature::empty(), + sync_committee_bits: BitVector::default(), + }; + BeaconBlockEIP7732 { + slot: spec.genesis_slot, + proposer_index: 0, + parent_root: Hash256::zero(), + state_root: Hash256::zero(), + body: BeaconBlockBodyEIP7732 { + proposer_slashings: base_block.body.proposer_slashings, + attester_slashings, + attestations: attestations_electra.into(), + deposits: base_block.body.deposits, + voluntary_exits: base_block.body.voluntary_exits, + bls_to_execution_changes, + sync_aggregate, + randao_reveal: Signature::empty(), + eth1_data: Eth1Data { + deposit_root: Hash256::zero(), + block_hash: Hash256::zero(), + deposit_count: 0, + }, + graffiti: Graffiti::default(), + _phantom: PhantomData, + }, + } + } +} + impl> EmptyBlock for BeaconBlockElectra { /// Returns an empty Electra block to be used during genesis. fn empty(spec: &ChainSpec) -> Self { @@ -704,6 +779,35 @@ impl> EmptyBlock for BeaconBlockElec } } +impl> EmptyBlock for BeaconBlockEIP7732 { + /// Returns an empty Electra block to be used during genesis. + fn empty(spec: &ChainSpec) -> Self { + BeaconBlockEIP7732 { + slot: spec.genesis_slot, + proposer_index: 0, + parent_root: Hash256::zero(), + state_root: Hash256::zero(), + body: BeaconBlockBodyEIP7732 { + 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(), + bls_to_execution_changes: VariableList::empty(), + _phantom: PhantomData, + }, + } + } +} + // We can convert pre-Bellatrix blocks without payloads into blocks "with" payloads. impl From>> for BeaconBlockBase> @@ -749,6 +853,28 @@ impl From>> } } +impl From>> + for BeaconBlockEIP7732> +{ + fn from(block: BeaconBlockEIP7732>) -> Self { + let BeaconBlockEIP7732 { + slot, + proposer_index, + parent_root, + state_root, + body, + } = block; + + BeaconBlockEIP7732 { + slot, + proposer_index, + parent_root, + state_root, + body: body.into(), + } + } +} + // We can convert blocks with payloads to blocks without payloads, and an optional payload. macro_rules! impl_from { ($ty_name:ident, <$($from_params:ty),*>, <$($to_params:ty),*>, $body_expr:expr) => { @@ -785,6 +911,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!(BeaconBlockEIP7732, >, >, |body: BeaconBlockBodyEIP7732<_, _>| body.into()); // We can clone blocks with payloads to blocks without payloads, without cloning the payload. macro_rules! impl_clone_as_blinded { @@ -818,6 +945,7 @@ impl_clone_as_blinded!(BeaconBlockBellatrix, >, >, >); impl_clone_as_blinded!(BeaconBlockDeneb, >, >); impl_clone_as_blinded!(BeaconBlockElectra, >, >); +impl_clone_as_blinded!(BeaconBlockEIP7732, >, >); // A reference to a full beacon block can be cloned into a blinded beacon block, without cloning the // execution payload. diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index b896dc4693..e97341acec 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -30,7 +30,7 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11; /// /// This *superstruct* abstracts over the hard-fork. #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, EIP7732), variant_attributes( derive( Debug, @@ -58,6 +58,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))))), + EIP7732(metastruct(mappings(beacon_block_body_eip7732_fields(groups(fields))))), ), cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"), partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant") @@ -77,7 +78,10 @@ pub struct BeaconBlockBody = FullPay partial_getter(rename = "attester_slashings_base") )] pub attester_slashings: VariableList, E::MaxAttesterSlashings>, - #[superstruct(only(Electra), partial_getter(rename = "attester_slashings_electra"))] + #[superstruct( + only(Electra, EIP7732), + partial_getter(rename = "attester_slashings_electra") + )] pub attester_slashings: VariableList, E::MaxAttesterSlashingsElectra>, #[superstruct( @@ -85,11 +89,14 @@ pub struct BeaconBlockBody = FullPay partial_getter(rename = "attestations_base") )] pub attestations: VariableList, E::MaxAttestations>, - #[superstruct(only(Electra), partial_getter(rename = "attestations_electra"))] + #[superstruct( + only(Electra, EIP7732), + partial_getter(rename = "attestations_electra") + )] pub attestations: VariableList, E::MaxAttestationsElectra>, pub deposits: VariableList, pub voluntary_exits: VariableList, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] 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 @@ -109,14 +116,14 @@ pub struct BeaconBlockBody = FullPay #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] #[serde(flatten)] pub execution_payload: Payload::Electra, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732))] pub bls_to_execution_changes: VariableList, #[superstruct(only(Deneb, Electra))] pub blob_kzg_commitments: KzgCommitments, #[superstruct(only(Electra))] pub execution_requests: ExecutionRequests, - #[superstruct(only(Base, Altair))] + #[superstruct(only(Base, Altair, EIP7732))] #[metastruct(exclude_from(fields))] #[ssz(skip_serializing, skip_deserializing)] #[tree_hash(skip_hashing)] @@ -144,6 +151,8 @@ 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)), + // TOOD: idk if this is right there's no more execution payload + Self::EIP7732(_) => Err(Error::IncorrectStateVariant), } } @@ -174,6 +183,10 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, beacon_block_body_electra_fields!(body, |_, field| leaves .push(field.tree_hash_root())); } + Self::EIP7732(body) => { + beacon_block_body_eip7732_fields!(body, |_, field| leaves + .push(field.tree_hash_root())); + } } leaves } @@ -202,7 +215,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::Deneb(_) | Self::Electra(_) | Self::EIP7732(_) => { // 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 @@ -294,6 +307,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::EIP7732(body) => body.attestations.len(), } } @@ -305,6 +319,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::EIP7732(body) => body.attester_slashings.len(), } } @@ -316,6 +331,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::EIP7732(body) => Box::new(body.attestations.iter().map(AttestationRef::Electra)), } } @@ -351,6 +367,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, .iter() .map(AttesterSlashingRef::Electra), ), + Self::EIP7732(body) => Box::new( + body.attester_slashings + .iter() + .map(AttesterSlashingRef::Electra), + ), } } } @@ -376,6 +397,9 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRefMut<'a, Self::Electra(body) => { Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra)) } + Self::EIP7732(body) => { + Box::new(body.attestations.iter_mut().map(AttestationRefMut::Electra)) + } } } } @@ -390,6 +414,7 @@ impl> BeaconBlockBodyRef<'_, E, Payl BeaconBlockBodyRef::Capella { .. } => ForkName::Capella, BeaconBlockBodyRef::Deneb { .. } => ForkName::Deneb, BeaconBlockBodyRef::Electra { .. } => ForkName::Electra, + BeaconBlockBodyRef::EIP7732 { .. } => ForkName::EIP7732, } } } @@ -704,6 +729,81 @@ impl From>> } } +// We can convert post EIP-7732 bodies without payloads into block bodies "with" payloads. +impl From>> + for BeaconBlockBodyEIP7732> +{ + fn from(body: BeaconBlockBodyEIP7732>) -> Self { + let BeaconBlockBodyEIP7732 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + _phantom, + } = body; + + BeaconBlockBodyEIP7732 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + _phantom: PhantomData, + } + } +} + +impl From>> + for ( + BeaconBlockBodyEIP7732>, + Option>, + ) +{ + fn from(body: BeaconBlockBodyEIP7732>) -> Self { + let BeaconBlockBodyEIP7732 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + _phantom, + } = body; + + ( + BeaconBlockBodyEIP7732 { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + _phantom: PhantomData, + }, + None, + ) + } +} + // We can clone a full block into a blinded block, without cloning the payload. impl BeaconBlockBodyBase> { pub fn clone_as_blinded(&self) -> BeaconBlockBodyBase> { @@ -859,6 +959,13 @@ impl BeaconBlockBodyElectra> { } } +impl BeaconBlockBodyEIP7732> { + pub fn clone_as_blinded(&self) -> BeaconBlockBodyEIP7732> { + let (block_body, _payload) = self.clone().into(); + block_body + } +} + impl From>> for ( BeaconBlockBody>, diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index 833231dca3..d62f47c380 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -222,7 +222,7 @@ impl From for Hash256 { /// /// https://github.com/sigp/milhouse/issues/43 #[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, EIP7732), variant_attributes( derive( Derivative, @@ -325,6 +325,20 @@ impl From for Hash256 { groups(tree_lists) )), num_fields(all()), + )), + EIP7732(metastruct( + mappings( + map_beacon_state_eip7732_fields(), + map_beacon_state_eip7732_tree_list_fields(mutable, fallible, groups(tree_lists)), + map_beacon_state_eip7732_tree_list_fields_immutable(groups(tree_lists)), + ), + bimappings(bimap_beacon_state_eip7732_tree_list_fields( + other_type = "BeaconStateEIP7732", + self_mutable, + fallible, + groups(tree_lists) + )), + num_fields(all()), )) ), cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"), @@ -407,11 +421,11 @@ where // Participation (Altair and later) #[compare_fields(as_iter)] - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] #[test_random(default)] #[compare_fields(as_iter)] pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] #[test_random(default)] pub current_epoch_participation: List, @@ -431,15 +445,15 @@ where // Inactivity #[serde(with = "ssz_types::serde_utils::quoted_u64_var_list")] - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] #[test_random(default)] pub inactivity_scores: List, // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] #[metastruct(exclude_from(tree_lists))] pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra))] + #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, EIP7732))] #[metastruct(exclude_from(tree_lists))] pub next_sync_committee: Arc>, @@ -468,56 +482,59 @@ where )] #[metastruct(exclude_from(tree_lists))] pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, + #[superstruct(only(EIP7732), partial_getter(rename = "latest_execution_bid_eip7732"))] + #[metastruct(exclude_from(tree_lists))] + pub latest_execution_bid: ExecutionBid, // Capella - #[superstruct(only(Capella, Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] #[metastruct(exclude_from(tree_lists))] pub next_withdrawal_validator_index: u64, // Deep history valid from Capella onwards. - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732))] #[test_random(default)] pub historical_summaries: List, // Electra - #[superstruct(only(Electra), partial_getter(copy))] + #[superstruct(only(Electra, EIP7732), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub deposit_requests_start_index: u64, - #[superstruct(only(Electra), partial_getter(copy))] + #[superstruct(only(Electra, EIP7732), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub deposit_balance_to_consume: u64, - #[superstruct(only(Electra), partial_getter(copy))] + #[superstruct(only(Electra, EIP7732), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub exit_balance_to_consume: u64, - #[superstruct(only(Electra), partial_getter(copy))] + #[superstruct(only(Electra, EIP7732), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] pub earliest_exit_epoch: Epoch, - #[superstruct(only(Electra), partial_getter(copy))] + #[superstruct(only(Electra, EIP7732), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] #[serde(with = "serde_utils::quoted_u64")] pub consolidation_balance_to_consume: u64, - #[superstruct(only(Electra), partial_getter(copy))] + #[superstruct(only(Electra, EIP7732), partial_getter(copy))] #[metastruct(exclude_from(tree_lists))] pub earliest_consolidation_epoch: Epoch, #[compare_fields(as_iter)] #[test_random(default)] - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub pending_balance_deposits: List, #[compare_fields(as_iter)] #[test_random(default)] - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub pending_partial_withdrawals: List, #[compare_fields(as_iter)] #[test_random(default)] - #[superstruct(only(Electra))] + #[superstruct(only(Electra, EIP7732))] pub pending_consolidations: List, // Caching (not in the spec) @@ -658,6 +675,7 @@ impl BeaconState { BeaconState::Capella { .. } => ForkName::Capella, BeaconState::Deneb { .. } => ForkName::Deneb, BeaconState::Electra { .. } => ForkName::Electra, + BeaconState::EIP7732 { .. } => ForkName::EIP7732, } } @@ -947,6 +965,8 @@ impl BeaconState { BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRef::Electra( &state.latest_execution_payload_header, )), + // FIXME(EIP-7732): this is only to make the code compile, needs to be written later + BeaconState::EIP7732(_) => Err(Error::IncorrectStateVariant), } } @@ -967,6 +987,8 @@ impl BeaconState { BeaconState::Electra(state) => Ok(ExecutionPayloadHeaderRefMut::Electra( &mut state.latest_execution_payload_header, )), + // FIXME(EIP-7732): this is only to make the code compile, needs to be written later + BeaconState::EIP7732(_) => Err(Error::IncorrectStateVariant), } } @@ -1480,6 +1502,16 @@ impl BeaconState { &mut state.exit_cache, &mut state.epoch_cache, )), + BeaconState::EIP7732(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, + )), } } @@ -1644,10 +1676,13 @@ impl BeaconState { | BeaconState::Altair(_) | BeaconState::Bellatrix(_) | BeaconState::Capella(_) => self.get_validator_churn_limit(spec)?, - BeaconState::Deneb(_) | BeaconState::Electra(_) => std::cmp::min( - spec.max_per_epoch_activation_churn_limit, - self.get_validator_churn_limit(spec)?, - ), + // FIXME(EIP-7732): check this + BeaconState::Deneb(_) | BeaconState::Electra(_) | BeaconState::EIP7732(_) => { + std::cmp::min( + spec.max_per_epoch_activation_churn_limit, + self.get_validator_churn_limit(spec)?, + ) + } }) } @@ -1765,6 +1800,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::EIP7732(state) => Ok(&mut state.current_epoch_participation), } } else if epoch == previous_epoch { match self { @@ -1774,6 +1810,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::EIP7732(state) => Ok(&mut state.previous_epoch_participation), } } else { Err(BeaconStateError::EpochOutOfBounds) @@ -2040,6 +2077,14 @@ impl BeaconState { } ); } + Self::EIP7732(self_inner) => { + map_beacon_state_eip7732_tree_list_fields_immutable!( + self_inner, + |_, self_field| { + any_pending_mutations |= self_field.has_pending_updates(); + } + ); + } }; any_pending_mutations } @@ -2381,6 +2426,14 @@ impl BeaconState { ); } (Self::Electra(_), _) => (), + (Self::EIP7732(self_inner), Self::EIP7732(base_inner)) => { + bimap_beacon_state_eip7732_tree_list_fields!( + self_inner, + base_inner, + |_, self_field, base_field| { self_field.rebase_on(base_field) } + ); + } + (Self::EIP7732(_), _) => (), } // Use sync committees from `base` if they are equal. @@ -2453,6 +2506,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::EIP7732 => BeaconStateEIP7732::::NUM_FIELDS.next_power_of_two(), } } @@ -2501,6 +2555,9 @@ impl BeaconState { Self::Electra(inner) => { map_beacon_state_electra_tree_list_fields!(inner, |_, x| { x.apply_updates() }) } + Self::EIP7732(inner) => { + map_beacon_state_eip7732_tree_list_fields!(inner, |_, x| { x.apply_updates() }) + } } Ok(()) } @@ -2596,6 +2653,11 @@ impl BeaconState { leaves.push(field.tree_hash_root()); }); } + BeaconState::EIP7732(state) => { + map_beacon_state_eip7732_fields!(state, |_, field| { + leaves.push(field.tree_hash_root()); + }); + } }; leaves @@ -2653,6 +2715,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::EIP7732(x), BeaconState::EIP7732(y)) => x.compare_fields(y), _ => panic!("compare_fields: mismatched state variants",), } } diff --git a/consensus/types/src/beacon_state/progressive_balances_cache.rs b/consensus/types/src/beacon_state/progressive_balances_cache.rs index fd5e51313f..70d9690eb1 100644 --- a/consensus/types/src/beacon_state/progressive_balances_cache.rs +++ b/consensus/types/src/beacon_state/progressive_balances_cache.rs @@ -291,6 +291,7 @@ pub fn is_progressive_balances_enabled(state: &BeaconState) -> bo | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => true, + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => true, } } diff --git a/consensus/types/src/builder_bid.rs b/consensus/types/src/builder_bid.rs index 9885f78474..f6e1f22bae 100644 --- a/consensus/types/src/builder_bid.rs +++ b/consensus/types/src/builder_bid.rs @@ -85,7 +85,8 @@ 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::Base | ForkName::Altair => { + // FIXME(EIP-7732): Check this + ForkName::Base | ForkName::Altair | ForkName::EIP7732 => { return Err(serde::de::Error::custom(format!( "BuilderBid failed to deserialize: unsupported fork '{}'", fork_name diff --git a/consensus/types/src/chain_spec.rs b/consensus/types/src/chain_spec.rs index 79dcc65ea3..607e9d06b3 100644 --- a/consensus/types/src/chain_spec.rs +++ b/consensus/types/src/chain_spec.rs @@ -196,6 +196,12 @@ pub struct ChainSpec { pub number_of_columns: usize, pub samples_per_slot: u64, + /* + * EIP-7732 params + */ + pub eip7732_fork_version: [u8; 4], + pub eip7732_fork_epoch: Option, + /* * Networking */ @@ -308,17 +314,20 @@ impl ChainSpec { /// Returns the name of the fork which is active at `epoch`. pub fn fork_name_at_epoch(&self, epoch: Epoch) -> ForkName { - 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.eip7732_fork_epoch { + Some(fork_epoch) if epoch >= fork_epoch => ForkName::EIP7732, + _ => 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, + }, }, }, }, @@ -335,6 +344,7 @@ impl ChainSpec { ForkName::Capella => self.capella_fork_version, ForkName::Deneb => self.deneb_fork_version, ForkName::Electra => self.electra_fork_version, + ForkName::EIP7732 => self.eip7732_fork_version, } } @@ -347,6 +357,7 @@ impl ChainSpec { ForkName::Capella => self.capella_fork_epoch, ForkName::Deneb => self.deneb_fork_epoch, ForkName::Electra => self.electra_fork_epoch, + ForkName::EIP7732 => self.eip7732_fork_epoch, } } @@ -803,6 +814,12 @@ impl ChainSpec { number_of_columns: 128, samples_per_slot: 8, + /* + * EIP-7732 params + */ + eip7732_fork_version: [0x09, 0x00, 0x00, 0x00], + eip7732_fork_epoch: None, + /* * Network specific */ @@ -911,6 +928,9 @@ impl ChainSpec { .expect("calculation does not overflow"), // PeerDAS eip7594_fork_epoch: None, + // EIP-7732 + eip7732_fork_version: [0x09, 0x00, 0x00, 0x01], + eip7732_fork_epoch: None, // Other network_id: 2, // lighthouse testnet network id deposit_chain_id: 5, @@ -1116,6 +1136,13 @@ impl ChainSpec { data_column_sidecar_subnet_count: 128, number_of_columns: 128, samples_per_slot: 8, + + /* + * EIP-7732 params + */ + eip7732_fork_version: [0x09, 0x00, 0x00, 0x64], + eip7732_fork_epoch: None, + /* * Network specific */ @@ -1247,6 +1274,14 @@ pub struct Config { #[serde(deserialize_with = "deserialize_fork_epoch")] pub eip7594_fork_epoch: Option>, + #[serde(default = "default_eip7732_fork_version")] + #[serde(with = "serde_utils::bytes_4_hex")] + eip7732_fork_version: [u8; 4], + #[serde(default)] + #[serde(serialize_with = "serialize_fork_epoch")] + #[serde(deserialize_with = "deserialize_fork_epoch")] + pub eip7732_fork_epoch: Option>, + #[serde(with = "serde_utils::quoted_u64")] seconds_per_slot: u64, #[serde(with = "serde_utils::quoted_u64")] @@ -1375,6 +1410,11 @@ fn default_electra_fork_version() -> [u8; 4] { [0xff, 0xff, 0xff, 0xff] } +fn default_eip7732_fork_version() -> [u8; 4] { + // This value shouldn't be used. + [0xff, 0xff, 0xff, 0xff] +} + /// Placeholder value: 2^256-2^10 (115792089237316195423570985008687907853269984665640564039457584007913129638912). /// /// Taken from https://github.com/ethereum/consensus-specs/blob/d5e4828aecafaf1c57ef67a5f23c4ae7b08c5137/configs/mainnet.yaml#L15-L16 @@ -1638,6 +1678,11 @@ impl Config { .eip7594_fork_epoch .map(|epoch| MaybeQuoted { value: epoch }), + eip7732_fork_version: spec.eip7732_fork_version, + eip7732_fork_epoch: spec + .eip7732_fork_epoch + .map(|epoch| MaybeQuoted { value: epoch }), + seconds_per_slot: spec.seconds_per_slot, seconds_per_eth1_block: spec.seconds_per_eth1_block, min_validator_withdrawability_delay: spec.min_validator_withdrawability_delay, @@ -1716,6 +1761,8 @@ impl Config { electra_fork_epoch, electra_fork_version, eip7594_fork_epoch, + eip7732_fork_epoch, + eip7732_fork_version, seconds_per_slot, seconds_per_eth1_block, min_validator_withdrawability_delay, @@ -1778,6 +1825,8 @@ impl Config { electra_fork_epoch: electra_fork_epoch.map(|q| q.value), electra_fork_version, eip7594_fork_epoch: eip7594_fork_epoch.map(|q| q.value), + eip7732_fork_epoch: eip7732_fork_epoch.map(|q| q.value), + eip7732_fork_version, seconds_per_slot, seconds_per_eth1_block, min_validator_withdrawability_delay, diff --git a/consensus/types/src/dumb_macros.rs b/consensus/types/src/dumb_macros.rs new file mode 100644 index 0000000000..573fce6af6 --- /dev/null +++ b/consensus/types/src/dumb_macros.rs @@ -0,0 +1,92 @@ +// These would usually be created by superstuct but now there's no longer a 1:1 mapping between +// the variants for ExecutionPayload and the variants for +// - ExecutionPayloadHeader +// - FullPayload +// - BlindedPayload + +#[macro_export] +macro_rules! map_execution_payload_into_full_payload { + ($value:expr, $f:expr) => { + match $value { + ExecutionPayload::Bellatrix(inner) => { + let f: fn(ExecutionPayloadBellatrix<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Bellatrix) + } + ExecutionPayload::Capella(inner) => { + let f: fn(ExecutionPayloadCapella<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Capella) + } + ExecutionPayload::Deneb(inner) => { + let f: fn(ExecutionPayloadDeneb<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Deneb) + } + ExecutionPayload::Electra(inner) => { + let f: fn(ExecutionPayloadElectra<_>, fn(_) -> _) -> _ = $f; + f(inner, FullPayload::Electra) + } + ExecutionPayload::EIP7732(_) => panic!("FullPayload::EIP7732 does not exist!"), + } + }; +} + +#[macro_export] +macro_rules! map_execution_payload_into_blinded_payload { + ($value:expr, $f:expr) => { + match $value { + ExecutionPayload::Bellatrix(inner) => { + let f: fn(ExecutionPayloadBellatrix<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Bellatrix) + } + ExecutionPayload::Capella(inner) => { + let f: fn(ExecutionPayloadCapella<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Capella) + } + ExecutionPayload::Deneb(inner) => { + let f: fn(ExecutionPayloadDeneb<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Deneb) + } + ExecutionPayload::Electra(inner) => { + let f: fn(ExecutionPayloadElectra<_>, fn(_) -> _) -> _ = $f; + f(inner, BlindedPayload::Electra) + } + ExecutionPayload::EIP7732(_) => panic!("BlindedPayload::EIP7732 does not exist!"), + } + }; +} + +#[macro_export] +macro_rules! map_execution_payload_ref_into_execution_payload_header { + (&$lifetime:tt _, $value:expr, $f:expr) => { + match $value { + ExecutionPayloadRef::Bellatrix(inner) => { + let f: fn( + &$lifetime ExecutionPayloadBellatrix<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Bellatrix) + } + ExecutionPayloadRef::Capella(inner) => { + let f: fn( + &$lifetime ExecutionPayloadCapella<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Capella) + } + ExecutionPayloadRef::Deneb(inner) => { + let f: fn( + &$lifetime ExecutionPayloadDeneb<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Deneb) + } + ExecutionPayloadRef::Electra(inner) => { + let f: fn( + &$lifetime ExecutionPayloadElectra<_>, + fn(_) -> _, + ) -> _ = $f; + f(inner, ExecutionPayloadHeader::Electra) + } + ExecutionPayloadRef::EIP7732(_) => panic!("ExecutionPayloadHeader::EIP7732 does not exist!"), + } + } +} diff --git a/consensus/types/src/execution_bid.rs b/consensus/types/src/execution_bid.rs new file mode 100644 index 0000000000..0994079557 --- /dev/null +++ b/consensus/types/src/execution_bid.rs @@ -0,0 +1,41 @@ +use crate::{test_utils::TestRandom, *}; +use derivative::Derivative; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive( + arbitrary::Arbitrary, + Debug, + Clone, + PartialEq, + Serialize, + Encode, + Decode, + Deserialize, + TreeHash, + Derivative, + TestRandom, +)] +// This is what Potuz' spec calls an `ExecutionPayload` even though it's clearly a bid. +pub struct ExecutionBid { + parent_block_hash: ExecutionBlockHash, + parent_block_root: Hash256, + block_hash: ExecutionBlockHash, + #[serde(with = "serde_utils::quoted_u64")] + gas_limit: u64, + #[serde(with = "serde_utils::quoted_u64")] + builder_index: u64, + slot: Slot, + #[serde(with = "serde_utils::quoted_u64")] + value: u64, + blob_kzg_commitments_root: Hash256, +} + +#[cfg(test)] +mod tests { + use super::*; + + ssz_and_tree_hash_tests!(ExecutionBid); +} diff --git a/consensus/types/src/execution_payload.rs b/consensus/types/src/execution_payload.rs index 9f16b676a6..2a12b74f7b 100644 --- a/consensus/types/src/execution_payload.rs +++ b/consensus/types/src/execution_payload.rs @@ -15,7 +15,7 @@ pub type Transactions = VariableList< pub type Withdrawals = VariableList::MaxWithdrawalsPerPayload>; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra), + variants(Bellatrix, Capella, Deneb, Electra, EIP7732), variant_attributes( derive( Default, @@ -35,9 +35,7 @@ pub type Withdrawals = VariableList::MaxWithdrawal arbitrary(bound = "E: EthSpec") ), cast_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"), - partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant"), - map_into(FullPayload, BlindedPayload), - map_ref_into(ExecutionPayloadHeader) + partial_getter_error(ty = "Error", expr = "BeaconStateError::IncorrectStateVariant") )] #[derive( Debug, Clone, Serialize, Encode, Deserialize, TreeHash, Derivative, arbitrary::Arbitrary, @@ -82,12 +80,12 @@ pub struct ExecutionPayload { pub block_hash: ExecutionBlockHash, #[serde(with = "ssz_types::serde_utils::list_of_hex_var_list")] pub transactions: Transactions, - #[superstruct(only(Capella, Deneb, Electra))] + #[superstruct(only(Capella, Deneb, Electra, EIP7732))] pub withdrawals: Withdrawals, - #[superstruct(only(Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, EIP7732), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, EIP7732), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, } @@ -105,6 +103,7 @@ impl<'a, E: EthSpec> ExecutionPayloadRef<'a, E> { impl ExecutionPayload { pub fn from_ssz_bytes(bytes: &[u8], fork_name: ForkName) -> Result { match fork_name { + // FIXME(EIP7732): Check this ForkName::Base | ForkName::Altair => Err(ssz::DecodeError::BytesInvalid(format!( "unsupported fork for ExecutionPayload: {fork_name}", ))), @@ -114,6 +113,7 @@ impl ExecutionPayload { ForkName::Capella => ExecutionPayloadCapella::from_ssz_bytes(bytes).map(Self::Capella), ForkName::Deneb => ExecutionPayloadDeneb::from_ssz_bytes(bytes).map(Self::Deneb), ForkName::Electra => ExecutionPayloadElectra::from_ssz_bytes(bytes).map(Self::Electra), + ForkName::EIP7732 => ExecutionPayloadEIP7732::from_ssz_bytes(bytes).map(Self::EIP7732), } } @@ -166,6 +166,17 @@ impl ExecutionPayload { // Max size of variable length `withdrawals` field + (E::max_withdrawals_per_payload() * ::ssz_fixed_len()) } + + #[allow(clippy::arithmetic_side_effects)] + pub fn max_execution_payload_eip7732_size() -> usize { + // Fixed part + ExecutionPayloadEIP7732::::default().as_ssz_bytes().len() + + (E::max_extra_data_bytes() * ::ssz_fixed_len()) + // Max size of variable length `transactions` field + + (E::max_transactions_per_payload() * (ssz::BYTES_PER_LENGTH_OFFSET + E::max_bytes_per_transaction())) + // Max size of variable length `withdrawals` field + + (E::max_withdrawals_per_payload() * ::ssz_fixed_len()) + } } impl ForkVersionDeserialize for ExecutionPayload { @@ -184,6 +195,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::EIP7732 => Self::EIP7732(serde_json::from_value(value).map_err(convert_err)?), ForkName::Base | ForkName::Altair => { return Err(serde::de::Error::custom(format!( "ExecutionPayload failed to deserialize: unsupported fork '{}'", @@ -201,6 +213,7 @@ impl ExecutionPayload { ExecutionPayload::Capella(_) => ForkName::Capella, ExecutionPayload::Deneb(_) => ForkName::Deneb, ExecutionPayload::Electra(_) => ForkName::Electra, + ExecutionPayload::EIP7732(_) => ForkName::EIP7732, } } } diff --git a/consensus/types/src/execution_payload_header.rs b/consensus/types/src/execution_payload_header.rs index 4bfbfee9bf..5161921e6e 100644 --- a/consensus/types/src/execution_payload_header.rs +++ b/consensus/types/src/execution_payload_header.rs @@ -108,6 +108,9 @@ impl ExecutionPayloadHeader { ForkName::Electra => { ExecutionPayloadHeaderElectra::from_ssz_bytes(bytes).map(Self::Electra) } + ForkName::EIP7732 => Err(ssz::DecodeError::BytesInvalid(format!( + "unsupported fork for ExecutionPayloadHeader: {fork_name}", + ))), } } @@ -120,6 +123,7 @@ impl ExecutionPayloadHeader { // Max size of variable length `extra_data` field E::max_extra_data_bytes() * ::ssz_fixed_len() } + ForkName::EIP7732 => 0, } } @@ -423,7 +427,8 @@ 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::Base | ForkName::Altair => { + // FIXME(EIP7732): Check this + ForkName::Base | ForkName::Altair | ForkName::EIP7732 => { return Err(serde::de::Error::custom(format!( "ExecutionPayloadHeader failed to deserialize: unsupported fork '{}'", fork_name diff --git a/consensus/types/src/fork_context.rs b/consensus/types/src/fork_context.rs index 0f7f0eb769..eb6eb38e19 100644 --- a/consensus/types/src/fork_context.rs +++ b/consensus/types/src/fork_context.rs @@ -69,6 +69,13 @@ impl ForkContext { )); } + if spec.eip7732_fork_epoch.is_some() { + fork_to_digest.push(( + ForkName::EIP7732, + ChainSpec::compute_fork_digest(spec.eip7732_fork_version, genesis_validators_root), + )); + } + let fork_to_digest: HashMap = fork_to_digest.into_iter().collect(); let digest_to_fork = fork_to_digest diff --git a/consensus/types/src/fork_name.rs b/consensus/types/src/fork_name.rs index 51a5b3813b..7736b9cf48 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, + EIP7732, } impl ForkName { @@ -28,6 +29,7 @@ impl ForkName { ForkName::Capella, ForkName::Deneb, ForkName::Electra, + ForkName::EIP7732, ] } @@ -38,6 +40,7 @@ impl ForkName { (ForkName::Capella, spec.capella_fork_epoch), (ForkName::Deneb, spec.deneb_fork_epoch), (ForkName::Electra, spec.electra_fork_epoch), + (ForkName::EIP7732, spec.eip7732_fork_epoch), ] } @@ -57,6 +60,7 @@ impl ForkName { spec.capella_fork_epoch = None; spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7732_fork_epoch = None; spec } ForkName::Altair => { @@ -65,6 +69,7 @@ impl ForkName { spec.capella_fork_epoch = None; spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7732_fork_epoch = None; spec } ForkName::Bellatrix => { @@ -73,6 +78,7 @@ impl ForkName { spec.capella_fork_epoch = None; spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7732_fork_epoch = None; spec } ForkName::Capella => { @@ -81,6 +87,7 @@ impl ForkName { spec.capella_fork_epoch = Some(Epoch::new(0)); spec.deneb_fork_epoch = None; spec.electra_fork_epoch = None; + spec.eip7732_fork_epoch = None; spec } ForkName::Deneb => { @@ -89,6 +96,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.eip7732_fork_epoch = None; spec } ForkName::Electra => { @@ -97,6 +105,16 @@ 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.eip7732_fork_epoch = None; + spec + } + ForkName::EIP7732 => { + 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.eip7732_fork_epoch = Some(Epoch::new(0)); spec } } @@ -113,6 +131,7 @@ impl ForkName { ForkName::Capella => Some(ForkName::Bellatrix), ForkName::Deneb => Some(ForkName::Capella), ForkName::Electra => Some(ForkName::Deneb), + ForkName::EIP7732 => Some(ForkName::Electra), } } @@ -126,7 +145,8 @@ impl ForkName { ForkName::Bellatrix => Some(ForkName::Capella), ForkName::Capella => Some(ForkName::Deneb), ForkName::Deneb => Some(ForkName::Electra), - ForkName::Electra => None, + ForkName::Electra => Some(ForkName::EIP7732), + ForkName::EIP7732 => None, } } @@ -149,6 +169,10 @@ impl ForkName { pub fn electra_enabled(self) -> bool { self >= ForkName::Electra } + + pub fn eip7732_enabled(self) -> bool { + self >= ForkName::EIP7732 + } } /// Map a fork name into a fork-versioned superstruct type like `BeaconBlock`. @@ -200,6 +224,10 @@ macro_rules! map_fork_name_with { let (value, extra_data) = $body; ($t::Electra(value), extra_data) } + ForkName::EIP7732 => { + let (value, extra_data) = $body; + ($t::EIP7732(value), extra_data) + } } }; } @@ -215,6 +243,7 @@ impl FromStr for ForkName { "capella" => ForkName::Capella, "deneb" => ForkName::Deneb, "electra" => ForkName::Electra, + "eip7732" => ForkName::EIP7732, _ => return Err(format!("unknown fork name: {}", fork_name)), }) } @@ -229,6 +258,7 @@ impl Display for ForkName { ForkName::Capella => "capella".fmt(f), ForkName::Deneb => "deneb".fmt(f), ForkName::Electra => "electra".fmt(f), + ForkName::EIP7732 => "eip7732".fmt(f), } } } diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index eff5237834..0ce0c94974 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -35,9 +35,11 @@ pub mod deposit_data; pub mod deposit_message; pub mod deposit_request; pub mod deposit_tree_snapshot; +pub mod dumb_macros; pub mod enr_fork_id; pub mod eth1_data; pub mod eth_spec; +pub mod execution_bid; pub mod execution_block_hash; pub mod execution_payload; pub mod execution_payload_header; @@ -126,13 +128,13 @@ pub use crate::attester_slashing::{ }; pub use crate::beacon_block::{ BeaconBlock, BeaconBlockAltair, BeaconBlockBase, BeaconBlockBellatrix, BeaconBlockCapella, - BeaconBlockDeneb, BeaconBlockElectra, BeaconBlockRef, BeaconBlockRefMut, BlindedBeaconBlock, - BlockImportSource, EmptyBlock, + BeaconBlockDeneb, BeaconBlockEIP7732, BeaconBlockElectra, BeaconBlockRef, BeaconBlockRefMut, + BlindedBeaconBlock, BlockImportSource, EmptyBlock, }; pub use crate::beacon_block_body::{ BeaconBlockBody, BeaconBlockBodyAltair, BeaconBlockBodyBase, BeaconBlockBodyBellatrix, - BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconBlockBodyRef, - BeaconBlockBodyRefMut, + BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyEIP7732, BeaconBlockBodyElectra, + BeaconBlockBodyRef, BeaconBlockBodyRefMut, }; pub use crate::beacon_block_header::BeaconBlockHeader; pub use crate::beacon_committee::{BeaconCommittee, OwnedBeaconCommittee}; @@ -159,11 +161,13 @@ pub use crate::enr_fork_id::EnrForkId; pub use crate::epoch_cache::{EpochCache, EpochCacheError, EpochCacheKey}; pub use crate::eth1_data::Eth1Data; pub use crate::eth_spec::EthSpecId; +pub use crate::execution_bid::ExecutionBid; 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, ExecutionPayloadRef, Transaction, Transactions, Withdrawals, + ExecutionPayloadEIP7732, ExecutionPayloadElectra, ExecutionPayloadRef, Transaction, + Transactions, Withdrawals, }; pub use crate::execution_payload_header::{ ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, @@ -228,8 +232,8 @@ 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, - SignedBeaconBlockHash, SignedBlindedBeaconBlock, + SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockEIP7732, + SignedBeaconBlockElectra, SignedBeaconBlockHash, SignedBlindedBeaconBlock, }; pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader; pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange; diff --git a/consensus/types/src/light_client_bootstrap.rs b/consensus/types/src/light_client_bootstrap.rs index 21a7e5416f..3c76145eb0 100644 --- a/consensus/types/src/light_client_bootstrap.rs +++ b/consensus/types/src/light_client_bootstrap.rs @@ -102,6 +102,7 @@ impl LightClientBootstrap { "LightClientBootstrap decoding for {fork_name} not implemented" ))) } + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(bootstrap) @@ -117,6 +118,7 @@ impl LightClientBootstrap { ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; fixed_len + LightClientHeader::::ssz_max_var_len_for_fork(fork_name) } @@ -152,6 +154,7 @@ impl LightClientBootstrap { current_sync_committee, current_sync_committee_branch: current_sync_committee_branch.into(), }), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(light_client_bootstrap) @@ -192,6 +195,7 @@ impl LightClientBootstrap { current_sync_committee, current_sync_committee_branch: current_sync_committee_branch.into(), }), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(light_client_bootstrap) diff --git a/consensus/types/src/light_client_finality_update.rs b/consensus/types/src/light_client_finality_update.rs index ba2f2083cd..506432c6bc 100644 --- a/consensus/types/src/light_client_finality_update.rs +++ b/consensus/types/src/light_client_finality_update.rs @@ -135,6 +135,7 @@ impl LightClientFinalityUpdate { sync_aggregate, signature_slot, }), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), ForkName::Base => return Err(Error::AltairForkNotActive), }; @@ -178,6 +179,7 @@ impl LightClientFinalityUpdate { "LightClientFinalityUpdate decoding for {fork_name} not implemented" ))) } + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(finality_update) @@ -193,6 +195,7 @@ impl LightClientFinalityUpdate { ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; // `2 *` because there are two headers in the update fixed_size + 2 * LightClientHeader::::ssz_max_var_len_for_fork(fork_name) diff --git a/consensus/types/src/light_client_header.rs b/consensus/types/src/light_client_header.rs index 6655e0a093..cc99c09b67 100644 --- a/consensus/types/src/light_client_header.rs +++ b/consensus/types/src/light_client_header.rs @@ -92,6 +92,7 @@ impl LightClientHeader { ForkName::Electra => LightClientHeader::Electra( LightClientHeaderElectra::block_to_light_client_header(block)?, ), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(header) } @@ -115,6 +116,7 @@ impl LightClientHeader { "LightClientHeader decoding for {fork_name} not implemented" ))) } + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(header) @@ -129,6 +131,10 @@ impl LightClientHeader { } pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize { + if fork_name.eip7732_enabled() { + // TODO(EIP7732): check this + return 0; + } if fork_name.capella_enabled() { ExecutionPayloadHeader::::ssz_max_var_len_for_fork(fork_name) } else { @@ -301,6 +307,7 @@ impl ForkVersionDeserialize for LightClientHeader { ForkName::Electra => serde_json::from_value(value) .map(|light_client_header| Self::Electra(light_client_header)) .map_err(serde::de::Error::custom), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), ForkName::Base => Err(serde::de::Error::custom(format!( "LightClientHeader deserialization for {fork_name} not implemented" ))), diff --git a/consensus/types/src/light_client_optimistic_update.rs b/consensus/types/src/light_client_optimistic_update.rs index 209388af87..df65839b47 100644 --- a/consensus/types/src/light_client_optimistic_update.rs +++ b/consensus/types/src/light_client_optimistic_update.rs @@ -102,6 +102,7 @@ impl LightClientOptimisticUpdate { sync_aggregate, signature_slot, }), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), ForkName::Base => return Err(Error::AltairForkNotActive), }; @@ -160,6 +161,7 @@ impl LightClientOptimisticUpdate { "LightClientOptimisticUpdate decoding for {fork_name} not implemented" ))) } + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(optimistic_update) @@ -175,6 +177,7 @@ impl LightClientOptimisticUpdate { ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; 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 c3a50e71c1..25c5d8e08d 100644 --- a/consensus/types/src/light_client_update.rs +++ b/consensus/types/src/light_client_update.rs @@ -286,8 +286,9 @@ impl LightClientUpdate { signature_slot: block_slot, }) } // To add a new fork, just append the new fork variant on the latest fork. Forks that - // have a distinct execution header will need a new LightClientUpdate variant only - // if you need to test or support lightclient usages + // have a distinct execution header will need a new LightClientUpdate variant only + // if you need to test or support lightclient usages + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(light_client_update) @@ -306,6 +307,7 @@ impl LightClientUpdate { "LightClientUpdate decoding for {fork_name} not implemented" ))) } + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; Ok(update) @@ -445,6 +447,7 @@ impl LightClientUpdate { ForkName::Capella => as Encode>::ssz_fixed_len(), ForkName::Deneb => as Encode>::ssz_fixed_len(), ForkName::Electra => as Encode>::ssz_fixed_len(), + ForkName::EIP7732 => todo!("EIP-7732 light client not implemented"), }; 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 b82a897da5..6621a4f9a0 100644 --- a/consensus/types/src/payload.rs +++ b/consensus/types/src/payload.rs @@ -305,6 +305,7 @@ impl FullPayload { ForkName::Capella => Ok(FullPayloadCapella::default().into()), ForkName::Deneb => Ok(FullPayloadDeneb::default().into()), ForkName::Electra => Ok(FullPayloadElectra::default().into()), + ForkName::EIP7732 => Err(Error::IncorrectStateVariant), } } } diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index bb5e1ea34b..34037c1ca7 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), + variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, EIP7732), 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(EIP7732), partial_getter(rename = "message_eip7732"))] + pub message: BeaconBlockEIP7732, pub signature: Signature, } @@ -163,6 +165,9 @@ impl> SignedBeaconBlock BeaconBlock::Electra(message) => { SignedBeaconBlock::Electra(SignedBeaconBlockElectra { message, signature }) } + BeaconBlock::EIP7732(message) => { + SignedBeaconBlock::EIP7732(SignedBeaconBlockEIP7732 { message, signature }) + } } } @@ -570,6 +575,19 @@ impl SignedBeaconBlockElectra> { } } +// We can convert post-EIP7732 blocks without payloads into blocks "with" payloads. +impl From>> + for SignedBeaconBlockEIP7732> +{ + fn from(signed_block: SignedBeaconBlockEIP7732>) -> Self { + let SignedBeaconBlockEIP7732 { message, signature } = signed_block; + SignedBeaconBlockEIP7732 { + message: message.into(), + signature, + } + } +} + impl SignedBeaconBlock> { pub fn try_into_full_block( self, @@ -590,6 +608,7 @@ impl SignedBeaconBlock> { (SignedBeaconBlock::Electra(block), Some(ExecutionPayload::Electra(payload))) => { SignedBeaconBlock::Electra(block.into_full_block(payload)) } + (SignedBeaconBlock::EIP7732(block), _) => SignedBeaconBlock::EIP7732(block.into()), // avoid wildcard matching forks so that compiler will // direct us here when a new fork has been added (SignedBeaconBlock::Bellatrix(_), _) => return None, @@ -741,6 +760,9 @@ pub mod ssz_tagged_signed_beacon_block { ForkName::Electra => Ok(SignedBeaconBlock::Electra( SignedBeaconBlockElectra::from_ssz_bytes(body)?, )), + ForkName::EIP7732 => Ok(SignedBeaconBlock::EIP7732( + SignedBeaconBlockEIP7732::from_ssz_bytes(body)?, + )), } } } @@ -843,6 +865,10 @@ mod test { BeaconBlock::Electra(BeaconBlockElectra::empty(spec)), sig, ), + SignedBeaconBlock::from_block( + BeaconBlock::EIP7732(BeaconBlockEIP7732::empty(spec)), + sig, + ), ]; for block in blocks { diff --git a/testing/ef_tests/src/cases/common.rs b/testing/ef_tests/src/cases/common.rs index e16f5b257f..97eecb91bd 100644 --- a/testing/ef_tests/src/cases/common.rs +++ b/testing/ef_tests/src/cases/common.rs @@ -2,7 +2,6 @@ use serde::Deserialize; use ssz::Encode; use ssz_derive::{Decode, Encode}; use std::fmt::Debug; -use types::ForkName; /// Macro to wrap U128 and U256 so they deserialize correctly. macro_rules! uint_wrapper { @@ -57,18 +56,6 @@ impl SszStaticType for T where { } -/// Return the fork immediately prior to a fork. -pub fn previous_fork(fork_name: ForkName) -> ForkName { - match fork_name { - ForkName::Base => ForkName::Base, - ForkName::Altair => ForkName::Base, - ForkName::Bellatrix => ForkName::Altair, - ForkName::Capella => ForkName::Bellatrix, - ForkName::Deneb => ForkName::Capella, - ForkName::Electra => ForkName::Deneb, - } -} - #[macro_export] macro_rules! impl_bls_load_case { ($case_name:ident) => { diff --git a/testing/ef_tests/src/cases/epoch_processing.rs b/testing/ef_tests/src/cases/epoch_processing.rs index dfd782a22b..cd117864b6 100644 --- a/testing/ef_tests/src/cases/epoch_processing.rs +++ b/testing/ef_tests/src/cases/epoch_processing.rs @@ -117,7 +117,8 @@ impl EpochTransition for JustificationAndFinalization { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => { initialize_progressive_balances_cache(state, spec)?; let justification_and_finalization_state = altair::process_justification_and_finalization(state)?; @@ -140,7 +141,8 @@ impl EpochTransition for RewardsAndPenalties { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_rewards_and_penalties_slow(state, spec), + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => altair::process_rewards_and_penalties_slow(state, spec), } } } @@ -173,7 +175,8 @@ impl EpochTransition for Slashings { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => { process_slashings_slow(state, spec)?; } }; @@ -278,7 +281,8 @@ impl EpochTransition for SyncCommitteeUpdates { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_sync_committee_updates(state, spec), + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => altair::process_sync_committee_updates(state, spec), } } } @@ -291,7 +295,8 @@ impl EpochTransition for InactivityUpdates { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_inactivity_updates_slow(state, spec), + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => altair::process_inactivity_updates_slow(state, spec), } } } @@ -304,7 +309,8 @@ impl EpochTransition for ParticipationFlagUpdates { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => altair::process_participation_flag_updates(state), + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => altair::process_participation_flag_updates(state), } } } diff --git a/testing/ef_tests/src/cases/fork.rs b/testing/ef_tests/src/cases/fork.rs index 132cfb4c0a..f5b25793b0 100644 --- a/testing/ef_tests/src/cases/fork.rs +++ b/testing/ef_tests/src/cases/fork.rs @@ -1,6 +1,5 @@ use super::*; use crate::case_result::compare_beacon_state_results_without_caches; -use crate::cases::common::previous_fork; use crate::decode::{ssz_decode_state, yaml_decode_file}; use serde::Deserialize; use state_processing::upgrade::{ @@ -33,8 +32,11 @@ impl LoadCase for ForkTest { assert_eq!(metadata.fork_name(), fork_name); // Decode pre-state with previous fork. - let pre_spec = &previous_fork(fork_name).make_genesis_spec(E::default_spec()); - let pre = ssz_decode_state(&path.join("pre.ssz_snappy"), pre_spec)?; + let pre_spec = fork_name + .previous_fork() + .unwrap_or(ForkName::Base) + .make_genesis_spec(E::default_spec()); + let pre = ssz_decode_state(&path.join("pre.ssz_snappy"), &pre_spec)?; // Decode post-state with target fork. let post_spec = &fork_name.make_genesis_spec(E::default_spec()); @@ -69,6 +71,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::EIP7732 => todo!("upgrade_to_eip7732 not yet implemented"), }; compare_beacon_state_results_without_caches(&mut result, &mut expected) diff --git a/testing/ef_tests/src/cases/merkle_proof_validity.rs b/testing/ef_tests/src/cases/merkle_proof_validity.rs index 49c0719784..379dd190ea 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, BeaconState, FixedVector, FullPayload, Unsigned, + BeaconBlockBodyEIP7732, BeaconBlockBodyElectra, BeaconState, FixedVector, FullPayload, + Unsigned, }; #[derive(Debug, Clone, Deserialize)] @@ -131,6 +132,11 @@ impl LoadCase for KzgInclusionMerkleProofValidity { ssz_decode_file::>(&path.join("object.ssz_snappy"))? .into() } + // TODO(EIP7732): check this + ForkName::EIP7732 => { + ssz_decode_file::>(&path.join("object.ssz_snappy"))? + .into() + } }; let merkle_proof = yaml_decode_file(&path.join("proof.yaml"))?; // Metadata does not exist in these tests but it is left like this just in case. @@ -246,6 +252,10 @@ impl LoadCase for BeaconBlockBodyMerkleProofValidity { ssz_decode_file::>(&path.join("object.ssz_snappy"))? .into() } + ForkName::EIP7732 => { + ssz_decode_file::>(&path.join("object.ssz_snappy"))? + .into() + } }; let merkle_proof = yaml_decode_file(&path.join("proof.yaml"))?; // Metadata does not exist in these tests but it is left like this just in case. diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index 54ca52447f..6b0f096807 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -24,9 +24,9 @@ use state_processing::{ use std::fmt::Debug; use types::{ Attestation, AttesterSlashing, BeaconBlock, BeaconBlockBody, BeaconBlockBodyBellatrix, - BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyElectra, BeaconState, - BlindedPayload, ConsolidationRequest, Deposit, DepositRequest, ExecutionPayload, FullPayload, - ProposerSlashing, SignedBlsToExecutionChange, SignedVoluntaryExit, SyncAggregate, + BeaconBlockBodyCapella, BeaconBlockBodyDeneb, BeaconBlockBodyEIP7732, BeaconBlockBodyElectra, + BeaconState, BlindedPayload, ConsolidationRequest, Deposit, DepositRequest, ExecutionPayload, + FullPayload, ProposerSlashing, SignedBlsToExecutionChange, SignedVoluntaryExit, SyncAggregate, WithdrawalRequest, }; @@ -110,7 +110,8 @@ impl Operation for Attestation { | BeaconState::Bellatrix(_) | BeaconState::Capella(_) | BeaconState::Deneb(_) - | BeaconState::Electra(_) => { + | BeaconState::Electra(_) + | BeaconState::EIP7732(_) => { initialize_progressive_balances_cache(state, spec)?; altair_deneb::process_attestation( state, @@ -137,7 +138,7 @@ impl Operation for AttesterSlashing { | ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb => Self::Base(ssz_decode_file(path)?), - ForkName::Electra => Self::Electra(ssz_decode_file(path)?), + ForkName::Electra | ForkName::EIP7732 => Self::Electra(ssz_decode_file(path)?), }) } @@ -308,6 +309,7 @@ impl Operation for BeaconBlockBody> { ForkName::Capella => BeaconBlockBody::Capella(<_>::from_ssz_bytes(bytes)?), ForkName::Deneb => BeaconBlockBody::Deneb(<_>::from_ssz_bytes(bytes)?), ForkName::Electra => BeaconBlockBody::Electra(<_>::from_ssz_bytes(bytes)?), + ForkName::EIP7732 => BeaconBlockBody::EIP7732(<_>::from_ssz_bytes(bytes)?), _ => panic!(), }) }) @@ -363,6 +365,10 @@ impl Operation for BeaconBlockBody> { let inner = >>::from_ssz_bytes(bytes)?; BeaconBlockBody::Electra(inner.clone_as_blinded()) } + ForkName::EIP7732 => { + let inner = >>::from_ssz_bytes(bytes)?; + BeaconBlockBody::EIP7732(inner.clone_as_blinded()) + } _ => panic!(), }) }) diff --git a/testing/ef_tests/src/cases/transition.rs b/testing/ef_tests/src/cases/transition.rs index dc5029d53e..ce26d3eac4 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::EIP7732 => { + 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.eip7732_fork_epoch = Some(metadata.fork_epoch); + } } // Load blocks diff --git a/validator_client/signing_method/src/web3signer.rs b/validator_client/signing_method/src/web3signer.rs index 86e7015ad3..a9542189e5 100644 --- a/validator_client/signing_method/src/web3signer.rs +++ b/validator_client/signing_method/src/web3signer.rs @@ -29,6 +29,7 @@ pub enum ForkName { Capella, Deneb, Electra, + EIP7732, } #[derive(Debug, PartialEq, Serialize)] @@ -107,6 +108,11 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> Web3SignerObject<'a, E, Pa block: None, block_header: Some(block.block_header()), }), + BeaconBlock::EIP7732(_) => Ok(Web3SignerObject::BeaconBlock { + version: ForkName::EIP7732, + block: None, + block_header: Some(block.block_header()), + }), } }