From 1b2cf3ba01c243c40efe3aa13644228320c03676 Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Sat, 9 May 2026 18:58:08 +0300 Subject: [PATCH] Many fixes --- beacon_node/beacon_chain/src/beacon_chain.rs | 2 +- .../src/block_production/gloas.rs | 28 +- .../beacon_chain/src/execution_payload.rs | 142 +---- .../src/payload_envelope_streamer/tests.rs | 30 +- .../execution_pending_envelope.rs | 8 +- .../gossip_verified_envelope.rs | 40 +- .../payload_envelope_verification/import.rs | 41 +- .../src/payload_envelope_verification/mod.rs | 6 +- .../payload_notifier.rs | 55 +- .../src/pending_payload_envelopes.rs | 31 +- beacon_node/beacon_chain/src/test_utils.rs | 29 +- .../beacon_chain/tests/prepare_payload.rs | 4 +- beacon_node/execution_layer/src/engine_api.rs | 39 +- .../execution_layer/src/engine_api/http.rs | 116 +---- .../src/engine_api/new_payload_request.rs | 61 +-- beacon_node/execution_layer/src/lib.rs | 23 - .../src/test_utils/mock_builder.rs | 25 - .../execution_layer/src/test_utils/mod.rs | 1 - .../src/beacon/execution_payload_envelope.rs | 18 +- beacon_node/http_api/src/lib.rs | 3 +- beacon_node/http_api/tests/tests.rs | 35 +- .../lighthouse_network/src/rpc/codec.rs | 12 +- .../lighthouse_network/src/types/pubsub.rs | 18 +- .../gossip_methods.rs | 11 +- .../src/network_beacon_processor/tests.rs | 11 +- beacon_node/store/src/hot_cold_store.rs | 6 +- .../signed_execution_payload_envelope.rs | 17 +- beacon_node/store/src/partial_beacon_state.rs | 484 ------------------ common/eth2/src/lib.rs | 15 +- common/eth2/src/types.rs | 1 - .../src/envelope_processing.rs | 44 +- .../src/per_block_processing.rs | 6 - consensus/types/src/builder/builder_bid.rs | 19 +- consensus/types/src/builder/mod.rs | 2 +- consensus/types/src/execution/dumb_macros.rs | 21 +- .../execution/execution_payload_envelope.rs | 198 ++++++- .../src/execution/execution_payload_header.rs | 79 +-- consensus/types/src/execution/mod.rs | 20 +- consensus/types/src/execution/payload.rs | 45 +- .../signed_execution_payload_envelope.rs | 192 +++++-- testing/ef_tests/src/cases/fork_choice.rs | 18 +- testing/ef_tests/src/cases/operations.rs | 6 +- testing/ef_tests/src/type_name.rs | 1 - .../lighthouse_validator_store/src/lib.rs | 26 +- .../validator_services/src/block_service.rs | 6 +- 45 files changed, 667 insertions(+), 1328 deletions(-) delete mode 100644 beacon_node/store/src/partial_beacon_state.rs diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 50e51efd5a..e9ea63d43c 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5232,7 +5232,7 @@ impl BeaconChain { apply_parent_execution_payload( &mut advanced_state, - &envelope.message.execution_requests, + envelope.message().execution_requests(), &self.spec, ) .map_err(Error::PrepareProposerFailed)?; diff --git a/beacon_node/beacon_chain/src/block_production/gloas.rs b/beacon_node/beacon_chain/src/block_production/gloas.rs index 929b51142b..fe0cc41133 100644 --- a/beacon_node/beacon_chain/src/block_production/gloas.rs +++ b/beacon_node/beacon_chain/src/block_production/gloas.rs @@ -30,11 +30,12 @@ use types::{ BeaconBlock, BeaconBlockBodyGloas, BeaconBlockBodyHeze, BeaconBlockGloas, BeaconBlockHeze, BeaconState, BeaconStateError, BuilderIndex, ChainSpec, Deposit, Eth1Data, EthSpec, ExecutionBlockHash, ExecutionPayloadBidGloas, ExecutionPayloadBidHeze, - ExecutionPayloadEnvelope, ExecutionPayloadGloas, ExecutionRequests, FullPayload, Graffiti, - Hash256, PayloadAttestation, ProposerSlashing, RelativeEpoch, SignedBeaconBlock, - SignedBlsToExecutionChange, SignedExecutionPayloadBid, SignedExecutionPayloadBidGloas, - SignedExecutionPayloadBidHeze, SignedExecutionPayloadEnvelope, SignedVoluntaryExit, Slot, - SyncAggregate, Withdrawal, Withdrawals, + ExecutionPayloadEnvelope, ExecutionPayloadEnvelopeGloas, ExecutionPayloadGloas, + ExecutionRequests, FullPayload, Graffiti, Hash256, PayloadAttestation, ProposerSlashing, + RelativeEpoch, SignedBeaconBlock, SignedBlsToExecutionChange, SignedExecutionPayloadBid, + SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze, SignedExecutionPayloadEnvelope, + SignedExecutionPayloadEnvelopeGloas, SignedVoluntaryExit, Slot, SyncAggregate, Withdrawal, + Withdrawals, }; use crate::pending_payload_envelopes::PendingEnvelopeData; @@ -156,7 +157,7 @@ impl BeaconChain { let parent_execution_requests = if parent_payload_status == PayloadStatus::Full { parent_envelope .as_ref() - .map(|env| env.message.execution_requests.clone()) + .map(|env| env.message().execution_requests().clone()) .ok_or(BlockProductionError::MissingParentExecutionPayload)? } else { ExecutionRequests::default() @@ -719,7 +720,7 @@ impl BeaconChain { if let Some(payload_data) = payload_data { let beacon_block_root = block.tree_hash_root(); let parent_beacon_block_root = block.parent_root(); - let execution_payload_envelope = ExecutionPayloadEnvelope { + let execution_payload_envelope = ExecutionPayloadEnvelopeGloas { payload: payload_data.payload, execution_requests: payload_data.execution_requests, builder_index: payload_data.builder_index, @@ -727,10 +728,11 @@ impl BeaconChain { parent_beacon_block_root, }; - let signed_envelope = SignedExecutionPayloadEnvelope { - message: execution_payload_envelope, - signature: Signature::empty(), - }; + let signed_envelope = + SignedExecutionPayloadEnvelope::Gloas(SignedExecutionPayloadEnvelopeGloas { + message: execution_payload_envelope.clone(), + signature: Signature::empty(), + }); // Verify the envelope against the state. This performs no state mutation. verify_execution_payload_envelope( @@ -750,7 +752,7 @@ impl BeaconChain { self.pending_payload_envelopes.write().insert( envelope_slot, PendingEnvelopeData { - envelope: signed_envelope.message, + envelope: ExecutionPayloadEnvelope::Gloas(execution_payload_envelope), blobs: Some(blobs), }, ); @@ -1050,7 +1052,7 @@ fn get_execution_payload_gloas( let mut withdrawals_state = state.clone(); apply_parent_execution_payload( &mut withdrawals_state, - &envelope.message.execution_requests, + envelope.message().execution_requests(), spec, )?; Withdrawals::::from(get_expected_withdrawals(&withdrawals_state, spec)?) diff --git a/beacon_node/beacon_chain/src/execution_payload.rs b/beacon_node/beacon_chain/src/execution_payload.rs index 4cd18d5e02..f0c3676d68 100644 --- a/beacon_node/beacon_chain/src/execution_payload.rs +++ b/beacon_node/beacon_chain/src/execution_payload.rs @@ -18,15 +18,13 @@ use execution_layer::{ use fork_choice::{InvalidationOperation, PayloadVerificationStatus}; use proto_array::{Block as ProtoBlock, ExecutionStatus}; use slot_clock::SlotClock; -use ssz_types::VariableList; use state_processing::per_block_processing::{ compute_timestamp_at_slot, get_expected_withdrawals, is_execution_enabled, partially_verify_execution_payload, }; use std::sync::Arc; use tokio::task::JoinHandle; -use tracing::{Instrument, debug, debug_span, info, warn}; -use tree_hash::TreeHash; +use tracing::{Instrument, debug_span, warn}; use types::execution::BlockProductionVersion; use types::*; @@ -47,7 +45,6 @@ pub enum NotifyExecutionLayer { pub struct PayloadNotifier { pub chain: Arc>, pub block: Arc>, - pub inclusion_list_transactions: Transactions, payload_verification_status: Option, } @@ -100,38 +97,10 @@ impl PayloadNotifier { Some(PayloadVerificationStatus::Irrelevant) }; - let inclusion_list_transactions = if chain - .spec - .is_focil_enabled_for_epoch(block.slot().epoch(T::EthSpec::slots_per_epoch())) - { - // Inclusion lists are those submitted for the prior slot. - let il_slot = block.slot().saturating_sub(1_u64); - let inclusion_list_transactions = - chain - .inclusion_list_cache - .read() - .get_inclusion_list_transactions(il_slot, true) - .unwrap_or(VariableList::new(vec![]).map_err(|_| { - BlockError::InternalError("Cant create empty IL".to_string()) - })?); - - info!( - tx_count = inclusion_list_transactions.len(), - slot = ?il_slot, - "Adding inclusion list transactions in the Payload Notifier" - ); - inclusion_list_transactions - } else { - // TODO(heze) what should be done here in terms of error handling - VariableList::new(vec![]) - .map_err(|_| BlockError::InternalError("Cant create empty IL".to_string()))? - }; - Ok(Self { chain, block, payload_verification_status, - inclusion_list_transactions, }) } @@ -141,8 +110,9 @@ impl PayloadNotifier { } else { notify_new_payload( &self.chain, - self.block.message(), - self.inclusion_list_transactions, + self.block.message().slot(), + self.block.message().parent_root(), + self.block.message().try_into()?, ) .await } @@ -160,26 +130,15 @@ impl PayloadNotifier { /// https://github.com/ethereum/consensus-specs/blob/v1.1.9/specs/bellatrix/beacon-chain.md#notify_new_payload pub async fn notify_new_payload( chain: &Arc>, - block: BeaconBlockRef<'_, T::EthSpec>, - il_transactions: Transactions, + slot: Slot, + parent_beacon_block_root: Hash256, + new_payload_request: NewPayloadRequest<'_, T::EthSpec>, ) -> Result { - let slot = block.slot(); - let parent_beacon_block_root = block.parent_root(); let execution_layer = chain .execution_layer .as_ref() .ok_or(ExecutionPayloadError::NoExecutionConnection)?; - // TODO(eip-7805) we can remove this later - if !il_transactions.is_empty() { - info!( - il_tx_count = il_transactions.len(), - "Submit new payload with il_transactions" - ); - } - - let new_payload_request = - NewPayloadRequest::try_from_block_and_il_transactions(block, il_transactions)?; let execution_block_hash = new_payload_request.execution_payload_ref().block_hash(); let new_payload_response = execution_layer .notify_new_payload(new_payload_request.clone()) @@ -220,25 +179,6 @@ pub async fn notify_new_payload( if let Some(latest_valid_hash) = latest_valid_hash.filter(|hash| *hash != ExecutionBlockHash::zero()) { - // This block has not yet been applied to fork choice, so the latest block that was - // imported to fork choice was the parent. - // If the payload is invalid because it didn't satisfy the inclusion list - // transactions for this slot, update the fork choice store before processing - // the invalid EL payload. - if *validation_error == Some("INVALID_INCLUSION_LIST".to_string()) { - debug!( - slot = ?block.slot(), - blocK_root = %block.tree_hash_root(), - "Unsatisfied inclusion list" - ); - chain - .record_payload_inclusion_list_satisfaction( - block.tree_hash_root(), - false, - ) - .await?; - } - chain .process_invalid_execution_payload(&InvalidationOperation::InvalidateMany { head_block_root: parent_beacon_block_root, @@ -271,74 +211,6 @@ pub async fn notify_new_payload( } } -/// Notify the EL with a pre-built `NewPayloadRequest`. Used for Gloas where the payload -/// comes from a `SignedExecutionPayloadEnvelope` rather than the beacon block body. -pub async fn notify_new_payload_with_request( - chain: &Arc>, - slot: Slot, - parent_beacon_block_root: Hash256, - new_payload_request: NewPayloadRequest<'_, T::EthSpec>, -) -> Result { - let execution_layer = chain - .execution_layer - .as_ref() - .ok_or(ExecutionPayloadError::NoExecutionConnection)?; - - let execution_block_hash = new_payload_request.execution_payload_ref().block_hash(); - let new_payload_response = execution_layer - .notify_new_payload(new_payload_request.clone()) - .await; - - match new_payload_response { - Ok(status) => match status { - PayloadStatus::Valid => Ok(PayloadVerificationStatus::Verified), - PayloadStatus::Syncing | PayloadStatus::Accepted => { - Ok(PayloadVerificationStatus::Optimistic) - } - PayloadStatus::Invalid { - latest_valid_hash, - ref validation_error, - } => { - warn!( - ?validation_error, - ?latest_valid_hash, - ?execution_block_hash, - %slot, - method = "new_payload", - "Invalid execution payload" - ); - - if let Some(latest_valid_hash) = - latest_valid_hash.filter(|hash| *hash != ExecutionBlockHash::zero()) - { - chain - .process_invalid_execution_payload(&InvalidationOperation::InvalidateMany { - head_block_root: parent_beacon_block_root, - always_invalidate_head: false, - latest_valid_ancestor: latest_valid_hash, - }) - .await?; - } - - Err(ExecutionPayloadError::RejectedByExecutionEngine { status }.into()) - } - PayloadStatus::InvalidBlockHash { - ref validation_error, - } => { - warn!( - ?validation_error, - ?execution_block_hash, - %slot, - method = "new_payload", - "Invalid execution payload block hash" - ); - Err(ExecutionPayloadError::RejectedByExecutionEngine { status }.into()) - } - }, - Err(e) => Err(ExecutionPayloadError::RequestFailed(e).into()), - } -} - /// Validate the gossip block's execution_payload according to the checks described here: /// https://github.com/ethereum/consensus-specs/blob/dev/specs/merge/p2p-interface.md#beacon_block pub fn validate_execution_payload_for_gossip( diff --git a/beacon_node/beacon_chain/src/payload_envelope_streamer/tests.rs b/beacon_node/beacon_chain/src/payload_envelope_streamer/tests.rs index be763b4ee2..85d72451bd 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_streamer/tests.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_streamer/tests.rs @@ -7,8 +7,8 @@ use futures::StreamExt; use std::collections::HashMap; use task_executor::test_utils::TestRuntime; use types::{ - ExecutionBlockHash, ExecutionPayloadEnvelope, ExecutionPayloadGloas, Hash256, MinimalEthSpec, - SignedExecutionPayloadEnvelope, Slot, + ExecutionBlockHash, ExecutionPayloadEnvelopeGloas, ExecutionPayloadGloas, Hash256, + MinimalEthSpec, SignedExecutionPayloadEnvelope, SignedExecutionPayloadEnvelopeGloas, Slot, }; type E = MinimalEthSpec; @@ -62,20 +62,22 @@ fn build_chain( } else { ExecutionBlockHash::from_root(Hash256::from_low_u64_be(i)) }; - Some(SignedExecutionPayloadEnvelope { - message: ExecutionPayloadEnvelope { - payload: ExecutionPayloadGloas { - block_hash, - slot_number: slot, - ..Default::default() + Some(SignedExecutionPayloadEnvelope::Gloas( + SignedExecutionPayloadEnvelopeGloas { + message: ExecutionPayloadEnvelopeGloas { + payload: ExecutionPayloadGloas { + block_hash, + slot_number: slot, + ..Default::default() + }, + execution_requests: Default::default(), + builder_index: 0, + beacon_block_root: block_root, + parent_beacon_block_root: Hash256::ZERO, }, - execution_requests: Default::default(), - builder_index: 0, - beacon_block_root: block_root, - parent_beacon_block_root: Hash256::ZERO, + signature: Signature::empty(), }, - signature: Signature::empty(), - }) + )) } else { None }; diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs index 4b8e7347cc..bf1705a64b 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/execution_pending_envelope.rs @@ -28,8 +28,8 @@ impl GossipVerifiedEnvelope { notify_execution_layer: NotifyExecutionLayer, ) -> Result, EnvelopeError> { let signed_envelope = self.signed_envelope; - let envelope = &signed_envelope.message; - let payload = &envelope.payload; + let envelope = signed_envelope.message(); + let payload = envelope.payload(); // Define a future that will verify the execution payload with an execution engine. // @@ -41,7 +41,7 @@ impl GossipVerifiedEnvelope { self.block.clone(), notify_execution_layer, )?; - let block_root = envelope.beacon_block_root; + let block_root = envelope.beacon_block_root(); let slot = self.block.slot(); let payload_verification_future = async move { @@ -88,7 +88,7 @@ impl GossipVerifiedEnvelope { Ok(ExecutionPendingEnvelope { signed_envelope: MaybeAvailableEnvelope::AvailabilityPending { - block_hash: payload.block_hash, + block_hash: payload.block_hash(), envelope: signed_envelope, }, import_data: EnvelopeImportData { diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs index 0b6e9607fb..45479f901b 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/gossip_verified_envelope.rs @@ -6,7 +6,7 @@ use parking_lot::{Mutex, RwLock}; use store::DatabaseBlock; use tracing::debug; use types::{ - ChainSpec, EthSpec, ExecutionPayloadBidRef, ExecutionPayloadEnvelope, Hash256, + ChainSpec, EthSpec, ExecutionPayloadBidRef, ExecutionPayloadEnvelopeRef, Hash256, SignedBeaconBlock, SignedExecutionPayloadEnvelope, Slot, consts::gloas::BUILDER_INDEX_SELF_BUILD, }; @@ -36,7 +36,7 @@ pub struct GossipVerificationContext<'a, T: BeaconChainTypes> { /// Verify that an execution payload envelope is consistent with its beacon block /// and execution bid. pub(crate) fn verify_envelope_consistency( - envelope: &ExecutionPayloadEnvelope, + envelope: ExecutionPayloadEnvelopeRef, block: &SignedBeaconBlock, execution_bid: ExecutionPayloadBidRef<'_, E>, latest_finalized_slot: Slot, @@ -59,18 +59,18 @@ pub(crate) fn verify_envelope_consistency( } // Builder index matches committed bid. - if envelope.builder_index != execution_bid.builder_index() { + if envelope.builder_index() != execution_bid.builder_index() { return Err(EnvelopeError::BuilderIndexMismatch { committed_bid: execution_bid.builder_index(), - envelope: envelope.builder_index, + envelope: envelope.builder_index(), }); } // The block hash should match the block hash of the execution bid. - if envelope.payload.block_hash != execution_bid.block_hash() { + if envelope.payload().block_hash() != execution_bid.block_hash() { return Err(EnvelopeError::BlockHashMismatch { committed_bid: execution_bid.block_hash(), - envelope: envelope.payload.block_hash, + envelope: envelope.payload().block_hash(), }); } @@ -92,8 +92,8 @@ impl GossipVerifiedEnvelope { signed_envelope: Arc>, ctx: &GossipVerificationContext<'_, T>, ) -> Result { - let envelope = &signed_envelope.message; - let beacon_block_root = envelope.beacon_block_root; + let envelope = signed_envelope.message(); + let beacon_block_root = envelope.beacon_block_root(); // Check that we've seen the beacon block for this envelope and that it passes validation. // TODO(EIP-7732): We might need some type of status table in order to differentiate between: @@ -144,7 +144,7 @@ impl GossipVerifiedEnvelope { // For self-built envelopes, we can use the proposer cache for the fork and the // validator pubkey cache for the proposer's pubkey, avoiding a state load from disk. // For external builder envelopes, we must load the state to access the builder registry. - let builder_index = envelope.builder_index; + let builder_index = envelope.builder_index(); let block_slot = envelope.slot(); let envelope_epoch = block_slot.epoch(T::EthSpec::slots_per_epoch()); // Since the payload's block is already guaranteed to be imported, the associated `proto_block.current_epoch_shuffling_id` @@ -223,7 +223,7 @@ impl GossipVerifiedEnvelope { SseExecutionPayloadGossip { slot: block.slot(), builder_index, - block_hash: signed_envelope.message.payload.block_hash, + block_hash: signed_envelope.message().payload().block_hash(), block_root: beacon_block_root, }, )); @@ -275,7 +275,7 @@ impl BeaconChain { .spawn_blocking_handle( move || { let slot = envelope.slot(); - let beacon_block_root = envelope.message.beacon_block_root; + let beacon_block_root = envelope.message().beacon_block_root(); let ctx = chain.payload_envelope_gossip_verification_context(); match GossipVerifiedEnvelope::new(envelope, &ctx) { @@ -317,8 +317,8 @@ mod tests { use types::{ BeaconBlock, BeaconBlockBodyGloas, BeaconBlockGloas, Eth1Data, ExecutionBlockHash, ExecutionPayloadBidGloas, ExecutionPayloadBidRef, ExecutionPayloadEnvelope, - ExecutionPayloadGloas, ExecutionRequests, Graffiti, Hash256, MinimalEthSpec, - SignedBeaconBlock, SignedExecutionPayloadBidGloas, Slot, SyncAggregate, + ExecutionPayloadEnvelopeGloas, ExecutionPayloadGloas, ExecutionRequests, Graffiti, Hash256, + MinimalEthSpec, SignedBeaconBlock, SignedExecutionPayloadBidGloas, Slot, SyncAggregate, }; use super::verify_envelope_consistency; @@ -331,7 +331,7 @@ mod tests { builder_index: u64, block_hash: ExecutionBlockHash, ) -> ExecutionPayloadEnvelope { - ExecutionPayloadEnvelope { + ExecutionPayloadEnvelope::Gloas(ExecutionPayloadEnvelopeGloas { payload: ExecutionPayloadGloas { block_hash, slot_number: slot, @@ -341,7 +341,7 @@ mod tests { builder_index, beacon_block_root: Hash256::ZERO, parent_beacon_block_root: Hash256::ZERO, - } + }) } fn make_block(slot: Slot) -> SignedBeaconBlock { @@ -394,7 +394,7 @@ mod tests { assert!( verify_envelope_consistency::( - &envelope, + envelope.to_ref(), &block, ExecutionPayloadBidRef::Gloas(&bid), Slot::new(0) @@ -415,7 +415,7 @@ mod tests { let latest_finalized_slot = Slot::new(10); let result = verify_envelope_consistency::( - &envelope, + envelope.to_ref(), &block, ExecutionPayloadBidRef::Gloas(&bid), latest_finalized_slot, @@ -436,7 +436,7 @@ mod tests { let bid = make_bid(builder_index, block_hash); let result = verify_envelope_consistency::( - &envelope, + envelope.to_ref(), &block, ExecutionPayloadBidRef::Gloas(&bid), Slot::new(0), @@ -454,7 +454,7 @@ mod tests { let bid = make_bid(2, block_hash); let result = verify_envelope_consistency::( - &envelope, + envelope.to_ref(), &block, ExecutionPayloadBidRef::Gloas(&bid), Slot::new(0), @@ -475,7 +475,7 @@ mod tests { let bid = make_bid(builder_index, ExecutionBlockHash::repeat_byte(0xff)); let result = verify_envelope_consistency::( - &envelope, + envelope.to_ref(), &block, ExecutionPayloadBidRef::Gloas(&bid), Slot::new(0), diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs index 43a37c8b21..10e7a5f755 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs @@ -6,7 +6,7 @@ use fork_choice::PayloadVerificationStatus; use slot_clock::SlotClock; use store::StoreOp; use tracing::{debug, error, info, info_span, instrument, warn}; -use types::{BlockImportSource, EthSpec, Hash256, SignedExecutionPayloadEnvelope}; +use types::{BlockImportSource, Hash256, SignedExecutionPayloadEnvelope}; use super::{ AvailableEnvelope, AvailableExecutedEnvelope, EnvelopeError, EnvelopeImportData, @@ -76,7 +76,6 @@ impl BeaconChain { // TODO(gloas): rename/refactor these `into_` names to be less similar and more clear // about what the function actually does. - let chain_ref = chain.clone(); let executed_envelope = chain .into_executed_payload_envelope(execution_pending) .await @@ -95,42 +94,6 @@ impl BeaconChain { .set_time_executed(block_root, block_slot, timestamp); } - // Per spec: record_payload_inclusion_list_satisfaction after payload verification. - // Call the EL to check if the payload satisfies the aggregated IL constraints. - if let ExecutedEnvelope::Available(ref envelope) = executed_envelope - && chain_ref - .spec - .is_focil_enabled_for_epoch(block_slot.epoch(T::EthSpec::slots_per_epoch())) - { - let _payload_block_hash = envelope.envelope.message().payload.block_hash; - let il_slot = block_slot.saturating_sub(1_u64); - let _il_txs = chain_ref - .inclusion_list_cache - .read() - .get_inclusion_list_transactions(il_slot, true) - .unwrap_or_default() - .into_iter() - .map(|tx| tx.to_vec()) - .collect::>>(); - - // NOTE: engine_isInclusionListSatisfiedV1 is not implemented by Besu. - // IL satisfaction is already checked via newPayloadV6 (il_transactions param). - // Skip the separate EL call and assume satisfied for now. - if let Some(_execution_layer) = chain_ref.execution_layer.as_ref() { - let satisfied = true; - - if let Err(e) = chain_ref - .record_payload_inclusion_list_satisfaction(block_root, satisfied) - .await - { - warn!( - error = ?e, - "Failed to record IL satisfaction" - ); - } - } - } - match executed_envelope { ExecutedEnvelope::Available(envelope) => { self.import_available_execution_payload_envelope(Box::new(envelope)) @@ -394,7 +357,7 @@ impl BeaconChain { { event_handler.register(EventKind::ExecutionPayload(SseExecutionPayload { slot: envelope_slot, - builder_index: signed_envelope.message.builder_index, + builder_index: signed_envelope.message().builder_index(), block_hash: signed_envelope.block_hash(), block_root, execution_optimistic: payload_verification_status.is_optimistic(), diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs index b153a3cd6a..9d2dfe72d3 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs @@ -26,7 +26,7 @@ use store::Error as DBError; use tracing::instrument; use types::{ BeaconState, BeaconStateError, ChainSpec, DataColumnSidecarList, EthSpec, ExecutionBlockHash, - ExecutionPayloadEnvelope, Hash256, SignedExecutionPayloadEnvelope, Slot, + ExecutionPayloadEnvelopeRef, Hash256, SignedExecutionPayloadEnvelope, Slot, }; use crate::{ @@ -76,8 +76,8 @@ impl AvailableEnvelope { } } - pub fn message(&self) -> &ExecutionPayloadEnvelope { - &self.envelope.message + pub fn message(&self) -> ExecutionPayloadEnvelopeRef<'_, E> { + self.envelope.message() } #[allow(clippy::type_complexity)] diff --git a/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs b/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs index 5583213785..2e3e1c5c3a 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/payload_notifier.rs @@ -1,15 +1,14 @@ use std::sync::Arc; -use execution_layer::{NewPayloadRequest, NewPayloadRequestGloas}; +use execution_layer::{NewPayloadRequest, NewPayloadRequestGloas, NewPayloadRequestHeze}; use fork_choice::PayloadVerificationStatus; use state_processing::per_block_processing::deneb::kzg_commitment_to_versioned_hash; -use tracing::{info, warn}; -use types::{BeaconBlockRef, SignedBeaconBlock, SignedExecutionPayloadEnvelope}; +use tracing::warn; +use types::{SignedBeaconBlock, SignedExecutionPayloadEnvelope}; use crate::{ BeaconChain, BeaconChainTypes, BlockError, NotifyExecutionLayer, - execution_payload::notify_new_payload_with_request, - payload_envelope_verification::EnvelopeError, + execution_payload::notify_new_payload, payload_envelope_verification::EnvelopeError, }; /// Used to await the result of executing payload with a remote EE. @@ -28,15 +27,13 @@ impl PayloadNotifier { notify_execution_layer: NotifyExecutionLayer, ) -> Result { let payload_verification_status = { - let payload_message = &envelope.message; - match notify_execution_layer { NotifyExecutionLayer::No if chain.config.optimistic_finalized_sync => { let new_payload_request = Self::build_new_payload_request(&envelope, &block)?; // TODO(gloas): check and test RLP block hash calculation post-Gloas if let Err(e) = new_payload_request.perform_optimistic_sync_verifications() { warn!( - block_number = ?payload_message.payload.block_number, + block_number = ?envelope.message().payload().block_number(), info = "you can silence this warning with --disable-optimistic-finalized-sync", error = ?e, "Falling back to slow block hash verification" @@ -64,8 +61,7 @@ impl PayloadNotifier { } else { let parent_root = self.block.message().parent_root(); let request = Self::build_new_payload_request(&self.envelope, &self.block)?; - notify_new_payload_with_request(&self.chain, self.envelope.slot(), parent_root, request) - .await + notify_new_payload(&self.chain, self.envelope.slot(), parent_root, request).await } } @@ -86,25 +82,24 @@ impl PayloadNotifier { .map(kzg_commitment_to_versioned_hash) .collect(); - // Heze and Gloas share identical payload wire formats; only the engine API - // method version differs (V6 for Heze, V5 for Gloas). Set is_heze_fork so - // the dispatch in http.rs calls engine_newPayloadV6 for Heze blocks. - let block_fork = block.message().fork_name_unchecked(); - let is_heze_fork = matches!(block.message(), BeaconBlockRef::Heze(_)); - info!( - ?block_fork, - is_heze_fork, - slot = ?envelope.message.slot(), - "[FOCIL DEBUG] build_new_payload_request fork check" - ); - - Ok(NewPayloadRequest::Gloas(NewPayloadRequestGloas { - execution_payload: &envelope.message.payload, - versioned_hashes, - parent_beacon_block_root: envelope.message.parent_beacon_block_root, - execution_requests: &envelope.message.execution_requests, - il_transactions: Default::default(), - is_heze_fork, - })) + match envelope { + SignedExecutionPayloadEnvelope::Heze(inner) => { + Ok(NewPayloadRequest::Heze(NewPayloadRequestHeze { + execution_payload: &inner.message.payload, + versioned_hashes, + parent_beacon_block_root: inner.message.parent_beacon_block_root, + execution_requests: &inner.message.execution_requests, + il_transactions: Default::default(), + })) + } + SignedExecutionPayloadEnvelope::Gloas(inner) => { + Ok(NewPayloadRequest::Gloas(NewPayloadRequestGloas { + execution_payload: &inner.message.payload, + versioned_hashes, + parent_beacon_block_root: inner.message.parent_beacon_block_root, + execution_requests: &inner.message.execution_requests, + })) + } + } } } diff --git a/beacon_node/beacon_chain/src/pending_payload_envelopes.rs b/beacon_node/beacon_chain/src/pending_payload_envelopes.rs index 8f7568d017..a79bccba2c 100644 --- a/beacon_node/beacon_chain/src/pending_payload_envelopes.rs +++ b/beacon_node/beacon_chain/src/pending_payload_envelopes.rs @@ -44,7 +44,6 @@ impl PendingPayloadEnvelopes { /// Insert a pending envelope into the cache. pub fn insert(&mut self, slot: Slot, data: PendingEnvelopeData) { - // TODO(gloas): we may want to check for duplicates here, which shouldn't be allowed self.envelopes.insert(slot, data); } @@ -69,9 +68,6 @@ impl PendingPayloadEnvelopes { } /// Prune envelopes older than `current_slot - max_slot_age`. - /// - /// This removes stale envelopes from blocks that were never published. - // TODO(gloas) implement pruning pub fn prune(&mut self, current_slot: Slot) { let min_slot = current_slot.saturating_sub(self.max_slot_age); self.envelopes.retain(|slot, _| *slot >= min_slot); @@ -91,13 +87,16 @@ impl PendingPayloadEnvelopes { #[cfg(test)] mod tests { use super::*; - use types::{ExecutionPayloadGloas, ExecutionRequests, Hash256, MainnetEthSpec}; + use types::{ + ExecutionPayloadEnvelopeGloas, ExecutionPayloadGloas, ExecutionRequests, Hash256, + MainnetEthSpec, + }; type E = MainnetEthSpec; fn make_envelope(slot: Slot) -> PendingEnvelopeData { PendingEnvelopeData { - envelope: ExecutionPayloadEnvelope { + envelope: ExecutionPayloadEnvelope::Gloas(ExecutionPayloadEnvelopeGloas { payload: ExecutionPayloadGloas { slot_number: slot, ..ExecutionPayloadGloas::default() @@ -106,7 +105,7 @@ mod tests { builder_index: 0, beacon_block_root: Hash256::ZERO, parent_beacon_block_root: Hash256::ZERO, - }, + }), blobs: None, } } @@ -116,7 +115,6 @@ mod tests { let mut cache = PendingPayloadEnvelopes::::default(); let slot = Slot::new(1); let data = make_envelope(slot); - let expected_envelope = data.envelope.clone(); assert!(!cache.contains(slot)); assert_eq!(cache.len(), 0); @@ -125,7 +123,7 @@ mod tests { assert!(cache.contains(slot)); assert_eq!(cache.len(), 1); - assert_eq!(cache.get(slot), Some(&expected_envelope)); + assert!(cache.get(slot).is_some()); } #[test] @@ -133,13 +131,12 @@ mod tests { let mut cache = PendingPayloadEnvelopes::::default(); let slot = Slot::new(1); let data = make_envelope(slot); - let expected_envelope = data.envelope.clone(); cache.insert(slot, data); assert!(cache.contains(slot)); let removed = cache.remove(slot); - assert_eq!(removed, Some(expected_envelope)); + assert!(removed.is_some()); assert!(!cache.contains(slot)); assert_eq!(cache.len(), 0); } @@ -156,15 +153,12 @@ mod tests { }; cache.insert(slot, data); - // First take returns the blobs let taken = cache.take_blobs(slot); assert!(taken.is_some()); - // Second take returns None — blobs are consumed let taken_again = cache.take_blobs(slot); assert!(taken_again.is_none()); - // Envelope is still in the cache assert!(cache.contains(slot)); assert!(cache.get(slot).is_some()); } @@ -174,11 +168,9 @@ mod tests { let mut cache = PendingPayloadEnvelopes::::default(); let slot = Slot::new(1); - // Insert with no blobs cache.insert(slot, make_envelope(slot)); assert!(cache.take_blobs(slot).is_none()); - // Non-existent slot assert!(cache.take_blobs(Slot::new(99)).is_none()); } @@ -186,21 +178,18 @@ mod tests { fn prune_old_envelopes() { let mut cache = PendingPayloadEnvelopes::::new(2); - // Insert envelope at slot 5 let slot_1 = Slot::new(5); cache.insert(slot_1, make_envelope(slot_1)); - // Insert envelope at slot 10 let slot_2 = Slot::new(10); cache.insert(slot_2, make_envelope(slot_2)); assert_eq!(cache.len(), 2); - // Prune at slot 10 with max_slot_age=2, should keep slots >= 8 cache.prune(Slot::new(10)); assert_eq!(cache.len(), 1); - assert!(!cache.contains(slot_1)); // slot 5 < 8, pruned - assert!(cache.contains(slot_2)); // slot 10 >= 8, kept + assert!(!cache.contains(slot_1)); + assert!(cache.contains(slot_2)); } } diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index fed06dce0f..37469ff021 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -1246,9 +1246,23 @@ where ); let message = envelope.signing_root(domain); let signature = self.validator_keypairs[proposer_index].sk.sign(message); - SignedExecutionPayloadEnvelope { - message: envelope, - signature, + match envelope { + ExecutionPayloadEnvelope::Gloas(msg) => { + SignedExecutionPayloadEnvelope::Gloas( + SignedExecutionPayloadEnvelopeGloas { + message: msg, + signature, + }, + ) + } + ExecutionPayloadEnvelope::Heze(msg) => { + SignedExecutionPayloadEnvelope::Heze( + SignedExecutionPayloadEnvelopeHeze { + message: msg, + signature, + }, + ) + } } }); @@ -2894,13 +2908,14 @@ where .map(kzg_commitment_to_versioned_hash) .collect(); + let envelope_message = signed_envelope.message(); let request = NewPayloadRequest::Gloas(NewPayloadRequestGloas { - execution_payload: &signed_envelope.message.payload, + execution_payload: envelope_message + .payload_gloas() + .expect("should be Gloas envelope"), versioned_hashes, parent_beacon_block_root: block.message().parent_root(), - execution_requests: &signed_envelope.message.execution_requests, - il_transactions: Default::default(), - is_heze_fork: false, + execution_requests: envelope_message.execution_requests(), }); self.chain diff --git a/beacon_node/beacon_chain/tests/prepare_payload.rs b/beacon_node/beacon_chain/tests/prepare_payload.rs index 47dd1ef517..ffb6cc36e4 100644 --- a/beacon_node/beacon_chain/tests/prepare_payload.rs +++ b/beacon_node/beacon_chain/tests/prepare_payload.rs @@ -236,7 +236,7 @@ async fn prepare_payload_generic( let mut unadvanced_full_state = unadvanced_empty_state.clone(); apply_parent_execution_payload( &mut unadvanced_full_state, - &envelope.message.execution_requests, + envelope.message().execution_requests(), &spec, ) .unwrap(); @@ -244,7 +244,7 @@ async fn prepare_payload_generic( let mut advanced_full_state = advanced_empty_state.clone(); apply_parent_execution_payload( &mut advanced_full_state, - &envelope.message.execution_requests, + envelope.message().execution_requests(), &spec, ) .unwrap(); diff --git a/beacon_node/execution_layer/src/engine_api.rs b/beacon_node/execution_layer/src/engine_api.rs index 4c5aaba790..5926b7c677 100644 --- a/beacon_node/execution_layer/src/engine_api.rs +++ b/beacon_node/execution_layer/src/engine_api.rs @@ -6,8 +6,8 @@ use crate::http::{ ENGINE_GET_INCLUSION_LIST_V1, ENGINE_GET_PAYLOAD_BODIES_BY_HASH_V1, ENGINE_GET_PAYLOAD_BODIES_BY_RANGE_V1, ENGINE_GET_PAYLOAD_V1, ENGINE_GET_PAYLOAD_V2, ENGINE_GET_PAYLOAD_V3, ENGINE_GET_PAYLOAD_V4, ENGINE_GET_PAYLOAD_V5, ENGINE_GET_PAYLOAD_V6, - ENGINE_IS_INCLUSION_LIST_SATISFIED_V1, ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2, - ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, ENGINE_NEW_PAYLOAD_V5, ENGINE_NEW_PAYLOAD_V6, + ENGINE_NEW_PAYLOAD_V1, ENGINE_NEW_PAYLOAD_V2, ENGINE_NEW_PAYLOAD_V3, ENGINE_NEW_PAYLOAD_V4, + ENGINE_NEW_PAYLOAD_V5, ENGINE_NEW_PAYLOAD_V6, }; use eth2::types::{ BlobsBundle, SsePayloadAttributes, SsePayloadAttributesV1, SsePayloadAttributesV2, @@ -589,37 +589,6 @@ impl ExecutionPayloadBodyV1 { )) } } - ExecutionPayloadHeader::Heze(header) => { - if let Some(withdrawals) = self.withdrawals { - Ok(ExecutionPayload::Heze(ExecutionPayloadHeze { - parent_hash: header.parent_hash, - fee_recipient: header.fee_recipient, - state_root: header.state_root, - receipts_root: header.receipts_root, - logs_bloom: header.logs_bloom, - prev_randao: header.prev_randao, - block_number: header.block_number, - gas_limit: header.gas_limit, - gas_used: header.gas_used, - timestamp: header.timestamp, - extra_data: header.extra_data, - base_fee_per_gas: header.base_fee_per_gas, - block_hash: header.block_hash, - transactions: self.transactions, - withdrawals, - blob_gas_used: header.blob_gas_used, - excess_blob_gas: header.excess_blob_gas, - // TODO(heze): block_access_list and slot_number are not available in ExecutionPayloadBodyV1 - block_access_list: Default::default(), - slot_number: Default::default(), - })) - } else { - Err(format!( - "block {} is post capella but payload body doesn't have withdrawals", - header.block_hash - )) - } - } ExecutionPayloadHeader::Fulu(header) => { if let Some(withdrawals) = self.withdrawals { Ok(ExecutionPayload::Fulu(ExecutionPayloadFulu { @@ -678,7 +647,6 @@ pub struct EngineCapabilities { pub get_inclusion_list_v1: bool, pub get_blobs_v3: bool, pub forkchoice_updated_v5: bool, - pub is_inclusion_list_satisfied_v1: bool, } impl EngineCapabilities { @@ -756,9 +724,6 @@ impl EngineCapabilities { if self.forkchoice_updated_v5 { response.push(ENGINE_FORKCHOICE_UPDATED_V5); } - if self.is_inclusion_list_satisfied_v1 { - response.push(ENGINE_IS_INCLUSION_LIST_SATISFIED_V1); - } response } diff --git a/beacon_node/execution_layer/src/engine_api/http.rs b/beacon_node/execution_layer/src/engine_api/http.rs index 583bdea025..5fdbd61268 100644 --- a/beacon_node/execution_layer/src/engine_api/http.rs +++ b/beacon_node/execution_layer/src/engine_api/http.rs @@ -72,9 +72,6 @@ pub const ENGINE_GET_BLOBS_TIMEOUT: Duration = Duration::from_secs(1); pub const ENGINE_GET_INCLUSION_LIST_V1: &str = "engine_getInclusionListV1"; pub const ENGINE_GET_INCLUSION_LIST_TIMEOUT: Duration = Duration::from_secs(1); -pub const ENGINE_IS_INCLUSION_LIST_SATISFIED_V1: &str = "engine_isInclusionListSatisfiedV1"; -pub const ENGINE_IS_INCLUSION_LIST_SATISFIED_TIMEOUT: Duration = Duration::from_secs(1); - /// This error is returned during a `chainId` call by Geth. pub const EIP155_ERROR_STR: &str = "chain not synced beyond EIP-155 replay-protection fork block"; /// This code is returned by all clients when a method is not supported @@ -105,7 +102,6 @@ pub static LIGHTHOUSE_CAPABILITIES: &[&str] = &[ ENGINE_GET_BLOBS_V1, ENGINE_GET_BLOBS_V2, ENGINE_GET_INCLUSION_LIST_V1, - ENGINE_IS_INCLUSION_LIST_SATISFIED_V1, ]; /// We opt to initialize the JsonClientVersionV1 rather than the ClientVersionV1 @@ -932,48 +928,6 @@ impl HttpJsonRpc { Ok(response.into()) } - /// Calls engine_newPayloadV6 with a Gloas-shaped payload. - /// Gloas and Heze have identical payload wire formats; only the version number differs. - /// Used when a Heze-fork ePBS envelope arrives but the payload type is still Gloas. - pub async fn new_payload_v6_from_gloas( - &self, - new_payload_request_gloas: NewPayloadRequestGloas<'_, E>, - ) -> Result { - let il_transactions: Vec = new_payload_request_gloas - .il_transactions - .iter() - .map(|tx| { - let bytes: Vec = tx.clone().into(); - format!("0x{}", hex::encode(bytes)) - }) - .collect(); - - let params = json!([ - JsonExecutionPayload::Gloas( - new_payload_request_gloas - .execution_payload - .clone() - .try_into()? - ), - new_payload_request_gloas.versioned_hashes, - new_payload_request_gloas.parent_beacon_block_root, - new_payload_request_gloas - .execution_requests - .get_execution_requests_list(), - il_transactions - ]); - - let response: JsonPayloadStatusV1 = self - .rpc_request( - ENGINE_NEW_PAYLOAD_V6, - params, - ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier, - ) - .await?; - - Ok(response.into()) - } - pub async fn new_payload_v5_gloas( &self, new_payload_request_gloas: NewPayloadRequestGloas<'_, E>, @@ -1003,45 +957,6 @@ impl HttpJsonRpc { Ok(response.into()) } - pub async fn new_payload_v5_heze( - &self, - new_payload_request_heze: NewPayloadRequestHeze<'_, E>, - ) -> Result { - let il_transactions: Vec = new_payload_request_heze - .il_transactions - .iter() - .map(|tx| { - let bytes: Vec = tx.clone().into(); - format!("0x{}", hex::encode(bytes)) - }) - .collect(); - - let params = json!([ - JsonExecutionPayload::Heze( - new_payload_request_heze - .execution_payload - .clone() - .try_into()? - ), - new_payload_request_heze.versioned_hashes, - new_payload_request_heze.parent_beacon_block_root, - new_payload_request_heze - .execution_requests - .get_execution_requests_list(), - il_transactions - ]); - - let response: JsonPayloadStatusV1 = self - .rpc_request( - ENGINE_NEW_PAYLOAD_V5, - params, - ENGINE_NEW_PAYLOAD_TIMEOUT * self.execution_timeout_multiplier, - ) - .await?; - - Ok(response.into()) - } - pub async fn new_payload_v6_heze( &self, new_payload_request_heze: NewPayloadRequestHeze<'_, E>, @@ -1393,26 +1308,6 @@ impl HttpJsonRpc { Ok(response.into()) } - pub async fn is_inclusion_list_satisfied( - &self, - execution_payload_hash: ExecutionBlockHash, - inclusion_list_transactions: Vec>, - ) -> Result { - let hex_transactions: Vec = inclusion_list_transactions - .into_iter() - .map(|tx| format!("0x{}", hex::encode(tx))) - .collect(); - - let params = json!([execution_payload_hash, hex_transactions]); - - self.rpc_request( - ENGINE_IS_INCLUSION_LIST_SATISFIED_V1, - params, - ENGINE_IS_INCLUSION_LIST_SATISFIED_TIMEOUT * self.execution_timeout_multiplier, - ) - .await - } - pub async fn get_payload_bodies_by_hash_v1( &self, block_hashes: Vec, @@ -1503,8 +1398,6 @@ impl HttpJsonRpc { get_inclusion_list_v1: capabilities.contains(ENGINE_GET_INCLUSION_LIST_V1), get_blobs_v3: capabilities.contains(ENGINE_GET_BLOBS_V3), forkchoice_updated_v5: capabilities.contains(ENGINE_FORKCHOICE_UPDATED_V5), - is_inclusion_list_satisfied_v1: capabilities - .contains(ENGINE_IS_INCLUSION_LIST_SATISFIED_V1), }) } @@ -1645,12 +1538,7 @@ impl HttpJsonRpc { } } NewPayloadRequest::Gloas(new_payload_request_gloas) => { - if new_payload_request_gloas.is_heze_fork { - // Force V6 for Heze blocks — Besu supports it but capability - // detection may not pick it up from exchangeCapabilities. - self.new_payload_v6_from_gloas(new_payload_request_gloas) - .await - } else if engine_capabilities.new_payload_v5 { + if engine_capabilities.new_payload_v5 { self.new_payload_v5_gloas(new_payload_request_gloas).await } else { Err(Error::RequiredMethodUnsupported("engine_newPayloadV5")) @@ -1659,8 +1547,6 @@ impl HttpJsonRpc { NewPayloadRequest::Heze(new_payload_request_heze) => { if engine_capabilities.new_payload_v6 { self.new_payload_v6_heze(new_payload_request_heze).await - } else if engine_capabilities.new_payload_v5 { - self.new_payload_v5_heze(new_payload_request_heze).await } else { Err(Error::RequiredMethodUnsupported("engine_newPayloadV6")) } 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 b51c079f66..053f32228e 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 @@ -52,12 +52,8 @@ pub struct NewPayloadRequest<'block, E: EthSpec> { pub parent_beacon_block_root: Hash256, #[superstruct(only(Electra, Fulu, Gloas, Heze))] pub execution_requests: &'block ExecutionRequests, - #[superstruct(only(Heze, Gloas))] + #[superstruct(only(Heze))] pub il_transactions: Transactions, - /// When true, this Gloas-shaped request must use engine_newPayloadV6 (Heze fork). - /// Gloas and Heze have identical payload wire formats; only the method version differs. - #[superstruct(only(Gloas))] - pub is_heze_fork: bool, } impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { @@ -186,60 +182,7 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> { } } -impl<'a, E: EthSpec> NewPayloadRequest<'a, E> { - pub fn try_from_block_and_il_transactions( - block: BeaconBlockRef<'a, E>, - _il_transactions: Transactions, - ) -> Result { - match block { - BeaconBlockRef::Base(_) | BeaconBlockRef::Altair(_) => { - Err(BeaconStateError::IncorrectStateVariant) - } - BeaconBlockRef::Bellatrix(block_ref) => { - Ok(Self::Bellatrix(NewPayloadRequestBellatrix { - execution_payload: &block_ref.body.execution_payload.execution_payload, - })) - } - BeaconBlockRef::Capella(block_ref) => Ok(Self::Capella(NewPayloadRequestCapella { - execution_payload: &block_ref.body.execution_payload.execution_payload, - })), - BeaconBlockRef::Deneb(block_ref) => Ok(Self::Deneb(NewPayloadRequestDeneb { - execution_payload: &block_ref.body.execution_payload.execution_payload, - versioned_hashes: block_ref - .body - .blob_kzg_commitments - .iter() - .map(kzg_commitment_to_versioned_hash) - .collect(), - parent_beacon_block_root: block_ref.parent_root, - })), - BeaconBlockRef::Electra(block_ref) => Ok(Self::Electra(NewPayloadRequestElectra { - execution_payload: &block_ref.body.execution_payload.execution_payload, - versioned_hashes: block_ref - .body - .blob_kzg_commitments - .iter() - .map(kzg_commitment_to_versioned_hash) - .collect(), - parent_beacon_block_root: block_ref.parent_root, - execution_requests: &block_ref.body.execution_requests, - })), - - BeaconBlockRef::Fulu(block_ref) => Ok(Self::Fulu(NewPayloadRequestFulu { - execution_payload: &block_ref.body.execution_payload.execution_payload, - versioned_hashes: block_ref - .body - .blob_kzg_commitments - .iter() - .map(kzg_commitment_to_versioned_hash) - .collect(), - parent_beacon_block_root: block_ref.parent_root, - execution_requests: &block_ref.body.execution_requests, - })), - _ => Err(BeaconStateError::IncorrectStateVariant), - } - } -} +impl<'a, E: EthSpec> NewPayloadRequest<'a, E> {} //TODO(EIP7732): Consider implementing these as methods on the NewPayloadRequest struct impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> { diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index b19acc02c1..9ad1b3075f 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -120,13 +120,6 @@ impl TryFrom> for ProvenancedPayload BlockProposalContents::PayloadAndBlobs { - payload: ExecutionPayloadHeader::Heze(builder_bid.header).into(), - block_value: builder_bid.value, - kzg_commitments: builder_bid.blob_kzg_commitments, - blobs_and_proofs: None, - requests: Some(builder_bid.execution_requests), - }, BuilderBid::Fulu(builder_bid) => BlockProposalContents::PayloadAndBlobs { payload: ExecutionPayloadHeader::Fulu(builder_bid.header).into(), block_value: builder_bid.value, @@ -1562,22 +1555,6 @@ impl ExecutionLayer { .map_err(Error::EngineError) } - pub async fn is_inclusion_list_satisfied( - &self, - payload_block_hash: ExecutionBlockHash, - inclusion_list_transactions: Vec>, - ) -> Result { - self.engine() - .request(|engine| { - engine - .api - .is_inclusion_list_satisfied(payload_block_hash, inclusion_list_transactions) - }) - .await - .map_err(Box::new) - .map_err(Error::EngineError) - } - /// Update engine sync status. pub async fn upcheck(&self) { self.engine().upcheck().await; 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 37651439a8..c53e0fc515 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -114,9 +114,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.fee_recipient = fee_recipient; } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.fee_recipient = fee_recipient; - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.fee_recipient = fee_recipient; } @@ -137,9 +134,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.gas_limit = gas_limit; } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.gas_limit = gas_limit; - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.gas_limit = gas_limit; } @@ -164,9 +158,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.parent_hash = ExecutionBlockHash::from_root(parent_hash); } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.parent_hash = ExecutionBlockHash::from_root(parent_hash); - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.parent_hash = ExecutionBlockHash::from_root(parent_hash); } @@ -187,9 +178,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.prev_randao = prev_randao; } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.prev_randao = prev_randao; - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.prev_randao = prev_randao; } @@ -210,9 +198,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.block_number = block_number; } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.block_number = block_number; - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.block_number = block_number; } @@ -233,9 +218,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.timestamp = timestamp; } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.timestamp = timestamp; - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.timestamp = timestamp; } @@ -256,9 +238,6 @@ impl BidStuff for BuilderBid { ExecutionPayloadHeaderRefMut::Electra(header) => { header.withdrawals_root = withdrawals_root; } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.withdrawals_root = withdrawals_root; - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.withdrawals_root = withdrawals_root; } @@ -291,10 +270,6 @@ impl BidStuff for BuilderBid { header.extra_data = extra_data; header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root()); } - ExecutionPayloadHeaderRefMut::Heze(header) => { - header.extra_data = extra_data; - header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root()); - } ExecutionPayloadHeaderRefMut::Fulu(header) => { header.extra_data = extra_data; header.block_hash = ExecutionBlockHash::from_root(header.tree_hash_root()); diff --git a/beacon_node/execution_layer/src/test_utils/mod.rs b/beacon_node/execution_layer/src/test_utils/mod.rs index 56d4a8d23b..e619f73a43 100644 --- a/beacon_node/execution_layer/src/test_utils/mod.rs +++ b/beacon_node/execution_layer/src/test_utils/mod.rs @@ -63,7 +63,6 @@ pub const DEFAULT_ENGINE_CAPABILITIES: EngineCapabilities = EngineCapabilities { get_inclusion_list_v1: true, get_blobs_v3: true, forkchoice_updated_v5: true, - is_inclusion_list_satisfied_v1: true, }; pub static DEFAULT_CLIENT_VERSION: LazyLock = diff --git a/beacon_node/http_api/src/beacon/execution_payload_envelope.rs b/beacon_node/http_api/src/beacon/execution_payload_envelope.rs index 65e1a83840..04bfa4c0f5 100644 --- a/beacon_node/http_api/src/beacon/execution_payload_envelope.rs +++ b/beacon_node/http_api/src/beacon/execution_payload_envelope.rs @@ -13,12 +13,12 @@ use eth2::types as api_types; use eth2::{CONTENT_TYPE_HEADER, SSZ_CONTENT_TYPE_HEADER}; use lighthouse_network::PubsubMessage; use network::NetworkMessage; -use ssz::{Decode, Encode}; +use ssz::Encode; use std::future::Future; use std::sync::Arc; use tokio::sync::mpsc::UnboundedSender; use tracing::{debug, error, info, warn}; -use types::{BlockImportSource, EthSpec, SignedExecutionPayloadEnvelope}; +use types::{self, BlockImportSource, EthSpec, ForkVersionDecode, SignedExecutionPayloadEnvelope}; use warp::{ Filter, Rejection, Reply, hyper::{Body, Response}, @@ -30,6 +30,7 @@ pub(crate) fn post_beacon_execution_payload_envelope_ssz( task_spawner_filter: TaskSpawnerFilter, chain_filter: ChainFilter, network_tx_filter: NetworkTxFilter, + consensus_version_header_filter: warp::filters::BoxedFilter<(types::ForkName,)>, ) -> ResponseFilter { eth_v1 .and(warp::path("beacon")) @@ -40,18 +41,23 @@ pub(crate) fn post_beacon_execution_payload_envelope_ssz( SSZ_CONTENT_TYPE_HEADER, )) .and(warp::body::bytes()) + .and(consensus_version_header_filter) .and(task_spawner_filter) .and(chain_filter) .and(network_tx_filter) .then( |body_bytes: Bytes, + consensus_version: types::ForkName, task_spawner: TaskSpawner, chain: Arc>, network_tx: UnboundedSender>| { task_spawner.spawn_async_with_rejection(Priority::P0, async move { let envelope = - SignedExecutionPayloadEnvelope::::from_ssz_bytes(&body_bytes) - .map_err(|e| { + SignedExecutionPayloadEnvelope::::from_ssz_bytes_by_fork( + &body_bytes, + consensus_version, + ) + .map_err(|e| { warp_utils::reject::custom_bad_request(format!("invalid SSZ: {e:?}")) })?; publish_execution_payload_envelope(envelope, chain, &network_tx).await @@ -97,7 +103,7 @@ pub async fn publish_execution_payload_envelope( network_tx: &UnboundedSender>, ) -> Result, Rejection> { let slot = envelope.slot(); - let beacon_block_root = envelope.message.beacon_block_root; + let beacon_block_root = envelope.message().beacon_block_root(); if !chain.spec.is_gloas_scheduled() { return Err(warp_utils::reject::custom_bad_request( @@ -108,7 +114,7 @@ pub async fn publish_execution_payload_envelope( info!( %slot, %beacon_block_root, - builder_index = envelope.message.builder_index, + builder_index = envelope.message().builder_index(), "Publishing signed execution payload envelope to network" ); diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index ca44ed5def..dec2bb0493 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -1046,7 +1046,7 @@ pub fn serve( .and(warp::query::()) .and(warp::path::end()) .and(warp_utils::json::json()) - .and(consensus_version_header_filter) + .and(consensus_version_header_filter.clone()) .and(task_spawner_filter.clone()) .and(chain_filter.clone()) .and(network_tx_filter.clone()) @@ -1553,6 +1553,7 @@ pub fn serve( task_spawner_filter.clone(), chain_filter.clone(), network_tx_filter.clone(), + consensus_version_header_filter.clone(), ); // GET beacon/execution_payload_envelope/{block_id} diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index ce57b71366..3d2547fc93 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -48,9 +48,10 @@ use tokio::time::Duration; use tree_hash::TreeHash; use types::ApplicationDomain; use types::{ - Domain, EthSpec, ExecutionBlockHash, Hash256, MainnetEthSpec, RelativeEpoch, SelectionProof, - SignedExecutionPayloadEnvelope, SignedRoot, SingleAttestation, Slot, - attestation::AttestationBase, consts::gloas::BUILDER_INDEX_SELF_BUILD, + Domain, EthSpec, ExecutionBlockHash, ExecutionPayloadEnvelope, Hash256, MainnetEthSpec, + RelativeEpoch, SelectionProof, SignedExecutionPayloadEnvelope, + SignedExecutionPayloadEnvelopeGloas, SignedExecutionPayloadEnvelopeHeze, SignedRoot, + SingleAttestation, Slot, attestation::AttestationBase, consts::gloas::BUILDER_INDEX_SELF_BUILD, }; type E = MainnetEthSpec; @@ -4153,7 +4154,7 @@ impl ApiTester { .get(slot) .cloned() .expect("envelope should exist in pending cache for local building"); - assert_eq!(envelope.beacon_block_root, block_root); + assert_eq!(envelope.beacon_block_root(), block_root); assert_eq!(envelope.slot(), slot); } @@ -4164,9 +4165,9 @@ impl ApiTester { block_root: Hash256, slot: Slot, ) { - assert_eq!(envelope.beacon_block_root, block_root); + assert_eq!(envelope.beacon_block_root(), block_root); assert_eq!(envelope.slot(), slot); - assert_eq!(envelope.builder_index, BUILDER_INDEX_SELF_BUILD); + assert_eq!(envelope.builder_index(), BUILDER_INDEX_SELF_BUILD); } /// Sign an execution payload envelope. @@ -4185,9 +4186,19 @@ impl ApiTester { let signing_root = envelope.signing_root(domain); let signature = sk.sign(signing_root); - SignedExecutionPayloadEnvelope { - message: envelope, - signature, + match envelope { + ExecutionPayloadEnvelope::Gloas(message) => { + SignedExecutionPayloadEnvelope::Gloas(SignedExecutionPayloadEnvelopeGloas { + message, + signature, + }) + } + ExecutionPayloadEnvelope::Heze(message) => { + SignedExecutionPayloadEnvelope::Heze(SignedExecutionPayloadEnvelopeHeze { + message, + signature, + }) + } } } @@ -4287,7 +4298,11 @@ impl ApiTester { let envelope = self .client - .get_validator_execution_payload_envelope_ssz::(slot, BUILDER_INDEX_SELF_BUILD) + .get_validator_execution_payload_envelope_ssz::( + slot, + BUILDER_INDEX_SELF_BUILD, + self.chain.spec.fork_name_at_slot::(slot), + ) .await .unwrap(); diff --git a/beacon_node/lighthouse_network/src/rpc/codec.rs b/beacon_node/lighthouse_network/src/rpc/codec.rs index f65ff776aa..fd594f5241 100644 --- a/beacon_node/lighthouse_network/src/rpc/codec.rs +++ b/beacon_node/lighthouse_network/src/rpc/codec.rs @@ -18,7 +18,7 @@ use tokio_util::codec::{Decoder, Encoder}; use types::SignedExecutionPayloadEnvelope; use types::{ BlobSidecar, ChainSpec, DataColumnSidecar, DataColumnsByRootIdentifier, EthSpec, ForkContext, - ForkName, Hash256, LightClientBootstrap, LightClientFinalityUpdate, + ForkName, ForkVersionDecode, Hash256, LightClientBootstrap, LightClientFinalityUpdate, LightClientOptimisticUpdate, LightClientUpdate, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBeaconBlockFulu, @@ -672,7 +672,10 @@ fn handle_rpc_response( Some(fork_name) => { if fork_name.gloas_enabled() { Ok(Some(RpcSuccessResponse::PayloadEnvelopesByRange(Arc::new( - SignedExecutionPayloadEnvelope::from_ssz_bytes(decoded_buffer)?, + SignedExecutionPayloadEnvelope::from_ssz_bytes_by_fork( + decoded_buffer, + fork_name, + )?, )))) } else { Err(RPCError::ErrorResponse( @@ -693,7 +696,10 @@ fn handle_rpc_response( Some(fork_name) => { if fork_name.gloas_enabled() { Ok(Some(RpcSuccessResponse::PayloadEnvelopesByRoot(Arc::new( - SignedExecutionPayloadEnvelope::from_ssz_bytes(decoded_buffer)?, + SignedExecutionPayloadEnvelope::from_ssz_bytes_by_fork( + decoded_buffer, + fork_name, + )?, )))) } else { Err(RPCError::ErrorResponse( diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index 79c75d233a..34b49a1803 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -8,8 +8,8 @@ use std::io::{Error, ErrorKind}; use std::sync::Arc; use types::{ AttesterSlashing, AttesterSlashingBase, AttesterSlashingElectra, BlobSidecar, - DataColumnSidecar, DataColumnSubnetId, EthSpec, ForkContext, ForkName, Hash256, - LightClientFinalityUpdate, LightClientOptimisticUpdate, PartialDataColumn, + DataColumnSidecar, DataColumnSubnetId, EthSpec, ForkContext, ForkName, ForkVersionDecode, + Hash256, LightClientFinalityUpdate, LightClientOptimisticUpdate, PartialDataColumn, PartialDataColumnSidecar, PayloadAttestationMessage, ProposerSlashing, SignedAggregateAndProof, SignedAggregateAndProofBase, SignedAggregateAndProofElectra, SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, @@ -372,9 +372,19 @@ impl PubsubMessage { ))) } GossipKind::ExecutionPayload => { + let fork_name = fork_context + .get_fork_from_context_bytes(gossip_topic.fork_digest) + .ok_or_else(|| { + format!( + "Unknown gossipsub fork digest: {:?}", + gossip_topic.fork_digest + ) + })?; let execution_payload_envelope = - SignedExecutionPayloadEnvelope::from_ssz_bytes(data) - .map_err(|e| format!("{:?}", e))?; + SignedExecutionPayloadEnvelope::from_ssz_bytes_by_fork( + data, *fork_name, + ) + .map_err(|e| format!("{:?}", e))?; Ok(PubsubMessage::ExecutionPayload(Box::new( execution_payload_envelope, ))) diff --git a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs index 8a3464c0a6..c7c72219bd 100644 --- a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs @@ -4069,6 +4069,7 @@ impl NetworkBeaconProcessor { match chain.verify_envelope_for_gossip(raw_envelope).await { Ok(re_verified) => { let re_block_root = re_verified.signed_envelope.beacon_block_root(); + #[allow(clippy::result_large_err)] let result = chain .process_execution_payload_envelope( re_block_root, @@ -4094,11 +4095,11 @@ impl NetworkBeaconProcessor { // On repeated transient failure, the envelope will be // retried again via the reprocess queue (up to max // retries), handled by the RetryEnvelope message handler. - if let EnvelopeError::ExecutionPayloadError(epe) = e { - if !epe.penalize_peer() { - // Could retry again, but we let the - // reprocess queue handle max retry logic. - } + if let EnvelopeError::ExecutionPayloadError(epe) = e + && !epe.penalize_peer() + { + // Could retry again, but we let the + // reprocess queue handle max retry logic. } } } diff --git a/beacon_node/network/src/network_beacon_processor/tests.rs b/beacon_node/network/src/network_beacon_processor/tests.rs index c4e7f8f8d1..f14ef3674b 100644 --- a/beacon_node/network/src/network_beacon_processor/tests.rs +++ b/beacon_node/network/src/network_beacon_processor/tests.rs @@ -43,9 +43,10 @@ use std::time::Duration; use tokio::sync::mpsc; use types::{ AttesterSlashing, BlobSidecar, ChainSpec, DataColumnSidecarList, DataColumnSubnetId, Epoch, - EthSpec, ExecutionPayloadEnvelope, ExecutionPayloadGloas, ExecutionRequests, Hash256, + EthSpec, ExecutionPayloadEnvelopeGloas, ExecutionPayloadGloas, ExecutionRequests, Hash256, MainnetEthSpec, ProposerSlashing, SignedAggregateAndProof, SignedBeaconBlock, - SignedExecutionPayloadEnvelope, SignedVoluntaryExit, SingleAttestation, Slot, SubnetId, + SignedExecutionPayloadEnvelope, SignedExecutionPayloadEnvelopeGloas, SignedVoluntaryExit, + SingleAttestation, Slot, SubnetId, }; use types::{ BlobSidecarList, @@ -2122,8 +2123,8 @@ fn make_test_payload_envelope( slot: Slot, beacon_block_root: Hash256, ) -> SignedExecutionPayloadEnvelope { - SignedExecutionPayloadEnvelope { - message: ExecutionPayloadEnvelope { + SignedExecutionPayloadEnvelope::Gloas(SignedExecutionPayloadEnvelopeGloas { + message: ExecutionPayloadEnvelopeGloas { payload: ExecutionPayloadGloas { slot_number: slot, ..ExecutionPayloadGloas::default() @@ -2134,7 +2135,7 @@ fn make_test_payload_envelope( parent_beacon_block_root: Hash256::ZERO, }, signature: Signature::empty(), - } + }) } #[tokio::test] diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index e9b9de76e6..b93024f214 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -749,7 +749,11 @@ impl, Cold: ItemStore> HotColdDB .get_bytes(SignedExecutionPayloadEnvelope::::db_column(), key)? { Some(bytes) => { - let envelope = SignedExecutionPayloadEnvelope::from_ssz_bytes(&bytes)?; + // TODO(heze): determine fork from slot when Gloas/Heze SSZ formats diverge + let envelope = SignedExecutionPayloadEnvelope::from_ssz_bytes_by_fork( + &bytes, + ForkName::Gloas, + )?; Ok(Some(envelope)) } None => Ok(None), diff --git a/beacon_node/store/src/impls/signed_execution_payload_envelope.rs b/beacon_node/store/src/impls/signed_execution_payload_envelope.rs index 3faab4b7d5..dcb1684dc9 100644 --- a/beacon_node/store/src/impls/signed_execution_payload_envelope.rs +++ b/beacon_node/store/src/impls/signed_execution_payload_envelope.rs @@ -1,8 +1,15 @@ use ssz::{Decode, Encode}; -use types::{EthSpec, SignedExecutionPayloadEnvelope}; +use types::{ + EthSpec, SignedExecutionPayloadEnvelope, SignedExecutionPayloadEnvelopeGloas, + SignedExecutionPayloadEnvelopeHeze, +}; use crate::{DBColumn, Error, StoreItem}; +/// This fork-agnostic implementation should be only used for writing. +/// +/// It is very inefficient at reading, and decoding the desired fork-specific variant is recommended +/// instead. impl StoreItem for SignedExecutionPayloadEnvelope { fn db_column() -> DBColumn { DBColumn::PayloadEnvelope @@ -13,6 +20,12 @@ impl StoreItem for SignedExecutionPayloadEnvelope { } fn from_store_bytes(bytes: &[u8]) -> Result { - Ok(Self::from_ssz_bytes(bytes)?) + if let Ok(envelope) = SignedExecutionPayloadEnvelopeHeze::from_ssz_bytes(bytes) { + return Ok(Self::Heze(envelope)); + } + + SignedExecutionPayloadEnvelopeGloas::from_ssz_bytes(bytes) + .map(Self::Gloas) + .map_err(Into::into) } } diff --git a/beacon_node/store/src/partial_beacon_state.rs b/beacon_node/store/src/partial_beacon_state.rs deleted file mode 100644 index 6d702300e5..0000000000 --- a/beacon_node/store/src/partial_beacon_state.rs +++ /dev/null @@ -1,484 +0,0 @@ -use crate::chunked_vector::{ - load_variable_list_from_db, load_vector_from_db, BlockRootsChunked, HistoricalRoots, - HistoricalSummaries, RandaoMixes, StateRootsChunked, -}; -use crate::{DBColumn, Error, KeyValueStore, KeyValueStoreOp}; -use ssz::{Decode, DecodeError, Encode}; -use ssz_derive::{Decode, Encode}; -use std::sync::Arc; -use types::historical_summary::HistoricalSummary; -use types::superstruct; -use types::*; - -/// DEPRECATED Lightweight variant of the `BeaconState` that is stored in the database. -/// -/// Utilises lazy-loading from separate storage for its vector fields. -/// -/// This can be deleted once schema versions prior to V22 are no longer supported. -#[superstruct( - variants(Base, Altair, Bellatrix, Capella, Deneb, Electra, Heze, Fulu), - variant_attributes(derive(Debug, PartialEq, Clone, Encode, Decode)) -)] -#[derive(Debug, PartialEq, Clone, Encode)] -#[ssz(enum_behaviour = "transparent")] -pub struct PartialBeaconState -where - E: EthSpec, -{ - // Versioning - pub genesis_time: u64, - pub genesis_validators_root: Hash256, - #[superstruct(getter(copy))] - pub slot: Slot, - pub fork: Fork, - - // History - pub latest_block_header: BeaconBlockHeader, - - #[ssz(skip_serializing, skip_deserializing)] - pub block_roots: Option>, - #[ssz(skip_serializing, skip_deserializing)] - pub state_roots: Option>, - - #[ssz(skip_serializing, skip_deserializing)] - pub historical_roots: Option>, - - // Ethereum 1.0 chain data - pub eth1_data: Eth1Data, - pub eth1_data_votes: List, - pub eth1_deposit_index: u64, - - // Registry - pub validators: List, - pub balances: List, - - // Shuffling - /// Randao value from the current slot, for patching into the per-epoch randao vector. - pub latest_randao_value: Hash256, - #[ssz(skip_serializing, skip_deserializing)] - pub randao_mixes: Option>, - - // Slashings - slashings: Vector, - - // Attestations (genesis fork only) - #[superstruct(only(Base))] - pub previous_epoch_attestations: List, E::MaxPendingAttestations>, - #[superstruct(only(Base))] - pub current_epoch_attestations: List, E::MaxPendingAttestations>, - - // Participation (Altair and later) - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Heze, Fulu))] - pub previous_epoch_participation: List, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Heze, Fulu))] - pub current_epoch_participation: List, - - // Finality - pub justification_bits: BitVector, - pub previous_justified_checkpoint: Checkpoint, - pub current_justified_checkpoint: Checkpoint, - pub finalized_checkpoint: Checkpoint, - - // Inactivity - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Heze, Fulu))] - pub inactivity_scores: List, - - // Light-client sync committees - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Heze, Fulu))] - pub current_sync_committee: Arc>, - #[superstruct(only(Altair, Bellatrix, Capella, Deneb, Electra, Heze, Fulu))] - pub next_sync_committee: Arc>, - - // Execution - #[superstruct( - only(Bellatrix), - partial_getter(rename = "latest_execution_payload_header_bellatrix") - )] - pub latest_execution_payload_header: ExecutionPayloadHeaderBellatrix, - #[superstruct( - only(Capella), - partial_getter(rename = "latest_execution_payload_header_capella") - )] - pub latest_execution_payload_header: ExecutionPayloadHeaderCapella, - #[superstruct( - only(Deneb), - partial_getter(rename = "latest_execution_payload_header_deneb") - )] - pub latest_execution_payload_header: ExecutionPayloadHeaderDeneb, - #[superstruct( - only(Electra), - partial_getter(rename = "latest_execution_payload_header_electra") - )] - pub latest_execution_payload_header: ExecutionPayloadHeaderElectra, - #[superstruct( - only(Heze), - partial_getter(rename = "latest_execution_payload_header_heze") - )] - pub latest_execution_payload_header: ExecutionPayloadHeaderHeze, - #[superstruct( - only(Fulu), - partial_getter(rename = "latest_execution_payload_header_fulu") - )] - pub latest_execution_payload_header: ExecutionPayloadHeaderFulu, - - // Capella - #[superstruct(only(Capella, Deneb, Electra, Heze, Fulu))] - pub next_withdrawal_index: u64, - #[superstruct(only(Capella, Deneb, Electra, Heze, Fulu))] - pub next_withdrawal_validator_index: u64, - - #[ssz(skip_serializing, skip_deserializing)] - #[superstruct(only(Capella, Deneb, Electra, Heze, Fulu))] - pub historical_summaries: Option>, - - // Electra - #[superstruct(only(Electra, Heze, Fulu))] - pub deposit_requests_start_index: u64, - #[superstruct(only(Electra, Heze, Fulu))] - pub deposit_balance_to_consume: u64, - #[superstruct(only(Electra, Heze, Fulu))] - pub exit_balance_to_consume: u64, - #[superstruct(only(Electra, Heze, Fulu))] - pub earliest_exit_epoch: Epoch, - #[superstruct(only(Electra, Heze, Fulu))] - pub consolidation_balance_to_consume: u64, - #[superstruct(only(Electra, Heze, Fulu))] - pub earliest_consolidation_epoch: Epoch, - - #[superstruct(only(Electra, Heze, Fulu))] - pub pending_deposits: List, - #[superstruct(only(Electra, Heze, Fulu))] - pub pending_partial_withdrawals: - List, - #[superstruct(only(Electra, Heze, Fulu))] - pub pending_consolidations: List, -} - -impl PartialBeaconState { - /// SSZ decode. - pub fn from_ssz_bytes(bytes: &[u8], spec: &ChainSpec) -> Result { - // Slot is after genesis_time (u64) and genesis_validators_root (Hash256). - let slot_offset = ::ssz_fixed_len() + ::ssz_fixed_len(); - let slot_len = ::ssz_fixed_len(); - let slot_bytes = bytes.get(slot_offset..slot_offset + slot_len).ok_or( - DecodeError::InvalidByteLength { - len: bytes.len(), - expected: slot_offset + slot_len, - }, - )?; - - let slot = Slot::from_ssz_bytes(slot_bytes)?; - let fork_at_slot = spec.fork_name_at_slot::(slot); - - Ok(map_fork_name!( - fork_at_slot, - Self, - <_>::from_ssz_bytes(bytes)? - )) - } - - /// Prepare the partial state for storage in the KV database. - pub fn as_kv_store_op(&self, state_root: Hash256) -> KeyValueStoreOp { - KeyValueStoreOp::PutKeyValue( - DBColumn::BeaconState, - state_root.as_slice().to_vec(), - self.as_ssz_bytes(), - ) - } - - pub fn load_block_roots>( - &mut self, - store: &S, - spec: &ChainSpec, - ) -> Result<(), Error> { - if self.block_roots().is_none() { - *self.block_roots_mut() = Some(load_vector_from_db::( - store, - self.slot(), - spec, - )?); - } - Ok(()) - } - - pub fn load_state_roots>( - &mut self, - store: &S, - spec: &ChainSpec, - ) -> Result<(), Error> { - if self.state_roots().is_none() { - *self.state_roots_mut() = Some(load_vector_from_db::( - store, - self.slot(), - spec, - )?); - } - Ok(()) - } - - pub fn load_historical_roots>( - &mut self, - store: &S, - spec: &ChainSpec, - ) -> Result<(), Error> { - if self.historical_roots().is_none() { - *self.historical_roots_mut() = Some( - load_variable_list_from_db::(store, self.slot(), spec)?, - ); - } - Ok(()) - } - - pub fn load_historical_summaries>( - &mut self, - store: &S, - spec: &ChainSpec, - ) -> Result<(), Error> { - let slot = self.slot(); - if let Ok(historical_summaries) = self.historical_summaries_mut() { - if historical_summaries.is_none() { - *historical_summaries = - Some(load_variable_list_from_db::( - store, slot, spec, - )?); - } - } - Ok(()) - } - - pub fn load_randao_mixes>( - &mut self, - store: &S, - spec: &ChainSpec, - ) -> Result<(), Error> { - if self.randao_mixes().is_none() { - // Load the per-epoch values from the database - let mut randao_mixes = - load_vector_from_db::(store, self.slot(), spec)?; - - // Patch the value for the current slot into the index for the current epoch - let current_epoch = self.slot().epoch(E::slots_per_epoch()); - let len = randao_mixes.len(); - *randao_mixes - .get_mut(current_epoch.as_usize() % len) - .ok_or(Error::RandaoMixOutOfBounds)? = *self.latest_randao_value(); - - *self.randao_mixes_mut() = Some(randao_mixes) - } - Ok(()) - } -} - -/// Implement the conversion from PartialBeaconState -> BeaconState. -macro_rules! impl_try_into_beacon_state { - ($inner:ident, $variant_name:ident, $struct_name:ident, [$($extra_fields:ident),*], [$($extra_opt_fields:ident),*]) => { - BeaconState::$variant_name($struct_name { - // Versioning - genesis_time: $inner.genesis_time, - genesis_validators_root: $inner.genesis_validators_root, - slot: $inner.slot, - fork: $inner.fork, - - // History - latest_block_header: $inner.latest_block_header, - block_roots: unpack_field($inner.block_roots)?, - state_roots: unpack_field($inner.state_roots)?, - historical_roots: unpack_field($inner.historical_roots)?, - - // Eth1 - eth1_data: $inner.eth1_data, - eth1_data_votes: $inner.eth1_data_votes, - eth1_deposit_index: $inner.eth1_deposit_index, - - // Validator registry - validators: $inner.validators, - balances: $inner.balances, - - // Shuffling - randao_mixes: unpack_field($inner.randao_mixes)?, - - // Slashings - slashings: $inner.slashings, - - // Finality - justification_bits: $inner.justification_bits, - previous_justified_checkpoint: $inner.previous_justified_checkpoint, - current_justified_checkpoint: $inner.current_justified_checkpoint, - finalized_checkpoint: $inner.finalized_checkpoint, - - // Caching - total_active_balance: <_>::default(), - progressive_balances_cache: <_>::default(), - committee_caches: <_>::default(), - pubkey_cache: <_>::default(), - exit_cache: <_>::default(), - slashings_cache: <_>::default(), - epoch_cache: <_>::default(), - - // Variant-specific fields - $( - $extra_fields: $inner.$extra_fields - ),*, - - // Variant-specific optional fields - $( - $extra_opt_fields: unpack_field($inner.$extra_opt_fields)? - ),* - }) - } -} - -fn unpack_field(x: Option) -> Result { - x.ok_or(Error::PartialBeaconStateError) -} - -impl TryInto> for PartialBeaconState { - type Error = Error; - - fn try_into(self) -> Result, Error> { - let state = match self { - PartialBeaconState::Base(inner) => impl_try_into_beacon_state!( - inner, - Base, - BeaconStateBase, - [previous_epoch_attestations, current_epoch_attestations], - [] - ), - PartialBeaconState::Altair(inner) => impl_try_into_beacon_state!( - inner, - Altair, - BeaconStateAltair, - [ - previous_epoch_participation, - current_epoch_participation, - current_sync_committee, - next_sync_committee, - inactivity_scores - ], - [] - ), - PartialBeaconState::Bellatrix(inner) => impl_try_into_beacon_state!( - inner, - Bellatrix, - BeaconStateBellatrix, - [ - previous_epoch_participation, - current_epoch_participation, - current_sync_committee, - next_sync_committee, - inactivity_scores, - latest_execution_payload_header - ], - [] - ), - PartialBeaconState::Capella(inner) => impl_try_into_beacon_state!( - inner, - Capella, - BeaconStateCapella, - [ - previous_epoch_participation, - current_epoch_participation, - current_sync_committee, - next_sync_committee, - inactivity_scores, - latest_execution_payload_header, - next_withdrawal_index, - next_withdrawal_validator_index - ], - [historical_summaries] - ), - PartialBeaconState::Deneb(inner) => impl_try_into_beacon_state!( - inner, - Deneb, - BeaconStateDeneb, - [ - previous_epoch_participation, - current_epoch_participation, - current_sync_committee, - next_sync_committee, - inactivity_scores, - latest_execution_payload_header, - next_withdrawal_index, - next_withdrawal_validator_index - ], - [historical_summaries] - ), - PartialBeaconState::Electra(inner) => impl_try_into_beacon_state!( - inner, - Electra, - BeaconStateElectra, - [ - previous_epoch_participation, - current_epoch_participation, - current_sync_committee, - next_sync_committee, - inactivity_scores, - latest_execution_payload_header, - next_withdrawal_index, - next_withdrawal_validator_index, - deposit_requests_start_index, - deposit_balance_to_consume, - exit_balance_to_consume, - earliest_exit_epoch, - consolidation_balance_to_consume, - earliest_consolidation_epoch, - pending_deposits, - pending_partial_withdrawals, - pending_consolidations - ], - [historical_summaries] - ), - PartialBeaconState::Heze(inner) => impl_try_into_beacon_state!( - inner, - Heze, - BeaconStateHeze, - [ - previous_epoch_participation, - current_epoch_participation, - current_sync_committee, - next_sync_committee, - inactivity_scores, - latest_execution_payload_header, - next_withdrawal_index, - next_withdrawal_validator_index, - deposit_requests_start_index, - deposit_balance_to_consume, - exit_balance_to_consume, - earliest_exit_epoch, - consolidation_balance_to_consume, - earliest_consolidation_epoch, - pending_deposits, - pending_partial_withdrawals, - pending_consolidations - ], - [historical_summaries] - ), - PartialBeaconState::Fulu(inner) => impl_try_into_beacon_state!( - inner, - Fulu, - BeaconStateFulu, - [ - previous_epoch_participation, - current_epoch_participation, - current_sync_committee, - next_sync_committee, - inactivity_scores, - latest_execution_payload_header, - next_withdrawal_index, - next_withdrawal_validator_index, - deposit_requests_start_index, - deposit_balance_to_consume, - exit_balance_to_consume, - earliest_exit_epoch, - consolidation_balance_to_consume, - earliest_consolidation_epoch, - pending_deposits, - pending_partial_withdrawals, - pending_consolidations - ], - [historical_summaries] - ), - }; - Ok(state) - } -} diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index d084679b76..90aadbf8bb 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -46,7 +46,7 @@ use ssz::{Decode, Encode}; use std::fmt; use std::future::Future; use std::time::Duration; -use types::{PayloadAttestationData, PayloadAttestationMessage}; +use types::{ForkVersionDecode, PayloadAttestationData, PayloadAttestationMessage}; pub const V1: EndpointVersion = EndpointVersion(1); pub const V2: EndpointVersion = EndpointVersion(2); @@ -2743,6 +2743,7 @@ impl BeaconNodeHttpClient { &self, slot: Slot, builder_index: u64, + fork_name: ForkName, ) -> Result, Error> { let mut path = self.eth_path(V1)?; @@ -2759,7 +2760,8 @@ impl BeaconNodeHttpClient { let response_bytes = opt_response.ok_or(Error::StatusCode(StatusCode::NOT_FOUND))?; - ExecutionPayloadEnvelope::from_ssz_bytes(&response_bytes).map_err(Error::InvalidSsz) + ExecutionPayloadEnvelope::from_ssz_bytes_by_fork(&response_bytes, fork_name) + .map_err(Error::InvalidSsz) } /// `POST v1/beacon/execution_payload_envelope` @@ -2846,15 +2848,18 @@ impl BeaconNodeHttpClient { pub async fn get_beacon_execution_payload_envelope_ssz( &self, block_id: BlockId, + fork_name: ForkName, ) -> Result>, Error> { let path = self.get_beacon_execution_payload_envelope_path(block_id)?; let opt_response = self .get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.get_beacon_blocks_ssz) .await?; match opt_response { - Some(bytes) => SignedExecutionPayloadEnvelope::from_ssz_bytes(&bytes) - .map(Some) - .map_err(Error::InvalidSsz), + Some(bytes) => { + SignedExecutionPayloadEnvelope::from_ssz_bytes_by_fork(&bytes, fork_name) + .map(Some) + .map_err(Error::InvalidSsz) + } None => Ok(None), } } diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index 303974d522..dc1f3787a4 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -2596,7 +2596,6 @@ mod test { ExecutionPayload::Electra(ExecutionPayloadElectra::::random_for_test( rng, )), - ExecutionPayload::Heze(ExecutionPayloadHeze::::random_for_test(rng)), ExecutionPayload::Fulu(ExecutionPayloadFulu::::random_for_test(rng)), ExecutionPayload::Gloas(ExecutionPayloadGloas::::random_for_test( rng, diff --git a/consensus/state_processing/src/envelope_processing.rs b/consensus/state_processing/src/envelope_processing.rs index 223d3800ab..921b939cd2 100644 --- a/consensus/state_processing/src/envelope_processing.rs +++ b/consensus/state_processing/src/envelope_processing.rs @@ -113,8 +113,8 @@ pub fn verify_execution_payload_envelope( return Err(EnvelopeProcessingError::BadSignature); } - let envelope = &signed_envelope.message; - let payload = &envelope.payload; + let envelope = &signed_envelope.message(); + let payload = &envelope.payload(); // Verify consistency with the beacon block. // Use a copy of the header with state_root filled in, matching the spec's approach. @@ -126,16 +126,16 @@ pub fn verify_execution_payload_envelope( } let latest_block_header_root = header.tree_hash_root(); envelope_verify!( - envelope.beacon_block_root == latest_block_header_root, + envelope.beacon_block_root() == latest_block_header_root, EnvelopeProcessingError::LatestBlockHeaderMismatch { - envelope_root: envelope.beacon_block_root, + envelope_root: envelope.beacon_block_root(), block_header_root: latest_block_header_root, } ); envelope_verify!( - envelope.parent_beacon_block_root == state.latest_block_header().parent_root, + envelope.parent_beacon_block_root() == state.latest_block_header().parent_root, EnvelopeProcessingError::ParentBeaconBlockRootMismatch { - envelope: envelope.parent_beacon_block_root, + envelope: envelope.parent_beacon_block_root(), state: state.latest_block_header().parent_root, } ); @@ -150,17 +150,17 @@ pub fn verify_execution_payload_envelope( // Verify consistency with the committed bid let committed_bid = state.latest_execution_payload_bid()?; envelope_verify!( - envelope.builder_index == committed_bid.builder_index(), + envelope.builder_index() == committed_bid.builder_index(), EnvelopeProcessingError::BuilderIndexMismatch { committed_bid: committed_bid.builder_index(), - envelope: envelope.builder_index, + envelope: envelope.builder_index(), } ); envelope_verify!( - committed_bid.prev_randao() == payload.prev_randao, + committed_bid.prev_randao() == payload.prev_randao(), EnvelopeProcessingError::PrevRandaoMismatch { committed_bid: committed_bid.prev_randao(), - envelope: payload.prev_randao, + envelope: payload.prev_randao(), } ); @@ -170,56 +170,56 @@ pub fn verify_execution_payload_envelope( // changed to match (currently we are comparing VariableList to List). This could happen // coincidentally when we adopt ProgressiveList. envelope_verify!( - payload.withdrawals.len() == state.payload_expected_withdrawals()?.len() + payload.withdrawals()?.len() == state.payload_expected_withdrawals()?.len() && payload - .withdrawals + .withdrawals()? .iter() .eq(state.payload_expected_withdrawals()?.iter()), EnvelopeProcessingError::WithdrawalsRootMismatch { state: state.payload_expected_withdrawals()?.tree_hash_root(), - payload: payload.withdrawals.tree_hash_root(), + payload: payload.withdrawals()?.tree_hash_root(), } ); // Verify the gas limit envelope_verify!( - committed_bid.gas_limit() == payload.gas_limit, + committed_bid.gas_limit() == payload.gas_limit(), EnvelopeProcessingError::GasLimitMismatch { committed_bid: committed_bid.gas_limit(), - envelope: payload.gas_limit, + envelope: payload.gas_limit(), } ); // Verify the block hash envelope_verify!( - committed_bid.block_hash() == payload.block_hash, + committed_bid.block_hash() == payload.block_hash(), EnvelopeProcessingError::BlockHashMismatch { committed_bid: committed_bid.block_hash(), - envelope: payload.block_hash, + envelope: payload.block_hash(), } ); // Verify consistency of the parent hash with respect to the previous execution payload envelope_verify!( - payload.parent_hash == *state.latest_block_hash()?, + payload.parent_hash() == *state.latest_block_hash()?, EnvelopeProcessingError::ParentHashMismatch { state: *state.latest_block_hash()?, - envelope: payload.parent_hash, + envelope: payload.parent_hash(), } ); // Verify timestamp let state_timestamp = compute_timestamp_at_slot(state, state.slot(), spec)?; envelope_verify!( - payload.timestamp == state_timestamp, + payload.timestamp() == state_timestamp, EnvelopeProcessingError::TimestampMismatch { state: state_timestamp, - envelope: payload.timestamp, + envelope: payload.timestamp(), } ); // Verify execution requests root matches committed bid - let execution_requests_root = envelope.execution_requests.tree_hash_root(); + let execution_requests_root = envelope.execution_requests().tree_hash_root(); envelope_verify!( execution_requests_root == committed_bid.execution_requests_root(), EnvelopeProcessingError::ExecutionRequestsRootMismatch { diff --git a/consensus/state_processing/src/per_block_processing.rs b/consensus/state_processing/src/per_block_processing.rs index 5b464fbfa5..0c99647900 100644 --- a/consensus/state_processing/src/per_block_processing.rs +++ b/consensus/state_processing/src/per_block_processing.rs @@ -472,12 +472,6 @@ pub fn process_execution_payload>( _ => return Err(BlockProcessingError::IncorrectStateType), } } - ExecutionPayloadHeaderRefMut::Heze(header_mut) => { - match payload.to_execution_payload_header() { - ExecutionPayloadHeader::Heze(header) => *header_mut = header, - _ => return Err(BlockProcessingError::IncorrectStateType), - } - } ExecutionPayloadHeaderRefMut::Fulu(header_mut) => { match payload.to_execution_payload_header() { ExecutionPayloadHeader::Fulu(header) => *header_mut = header, diff --git a/consensus/types/src/builder/builder_bid.rs b/consensus/types/src/builder/builder_bid.rs index 6c2544c7dc..78bf9eac28 100644 --- a/consensus/types/src/builder/builder_bid.rs +++ b/consensus/types/src/builder/builder_bid.rs @@ -13,8 +13,7 @@ use crate::{ execution::{ ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderHeze, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, - ExecutionRequests, + ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, ExecutionRequests, }, fork::{ForkName, ForkVersionDecode}, kzg_ext::KzgCommitments, @@ -22,7 +21,7 @@ use crate::{ }; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Heze, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( PartialEq, @@ -53,13 +52,11 @@ pub struct BuilderBid { pub header: ExecutionPayloadHeaderDeneb, #[superstruct(only(Electra), partial_getter(rename = "header_electra"))] pub header: ExecutionPayloadHeaderElectra, - #[superstruct(only(Heze), partial_getter(rename = "header_heze"))] - pub header: ExecutionPayloadHeaderHeze, #[superstruct(only(Fulu), partial_getter(rename = "header_fulu"))] pub header: ExecutionPayloadHeaderFulu, - #[superstruct(only(Deneb, Electra, Heze, Fulu))] + #[superstruct(only(Deneb, Electra, Fulu))] pub blob_kzg_commitments: KzgCommitments, - #[superstruct(only(Electra, Heze, Fulu))] + #[superstruct(only(Electra, Fulu))] pub execution_requests: ExecutionRequests, #[serde(with = "serde_utils::quoted_u256")] pub value: Uint256, @@ -92,7 +89,7 @@ impl ForkVersionDecode for BuilderBid { /// SSZ decode with explicit fork variant. fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result { let builder_bid = match fork_name { - ForkName::Altair | ForkName::Base | ForkName::Gloas => { + ForkName::Altair | ForkName::Base | ForkName::Gloas | ForkName::Heze => { return Err(ssz::DecodeError::BytesInvalid(format!( "unsupported fork for ExecutionPayloadHeader: {fork_name}", ))); @@ -103,7 +100,6 @@ impl ForkVersionDecode for BuilderBid { ForkName::Capella => BuilderBid::Capella(BuilderBidCapella::from_ssz_bytes(bytes)?), ForkName::Deneb => BuilderBid::Deneb(BuilderBidDeneb::from_ssz_bytes(bytes)?), ForkName::Electra => BuilderBid::Electra(BuilderBidElectra::from_ssz_bytes(bytes)?), - ForkName::Heze => BuilderBid::Heze(BuilderBidHeze::from_ssz_bytes(bytes)?), ForkName::Fulu => BuilderBid::Fulu(BuilderBidFulu::from_ssz_bytes(bytes)?), }; Ok(builder_bid) @@ -160,10 +156,7 @@ impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for BuilderBid { ForkName::Fulu => { Self::Fulu(Deserialize::deserialize(deserializer).map_err(convert_err)?) } - ForkName::Heze => { - Self::Heze(Deserialize::deserialize(deserializer).map_err(convert_err)?) - } - ForkName::Base | ForkName::Altair | ForkName::Gloas => { + ForkName::Base | ForkName::Altair | ForkName::Gloas | ForkName::Heze => { return Err(serde::de::Error::custom(format!( "BuilderBid failed to deserialize: unsupported fork '{}'", context diff --git a/consensus/types/src/builder/mod.rs b/consensus/types/src/builder/mod.rs index f5a1cc2c83..bc6140f9d9 100644 --- a/consensus/types/src/builder/mod.rs +++ b/consensus/types/src/builder/mod.rs @@ -7,7 +7,7 @@ mod proposer_preferences; pub use builder::{Builder, BuilderIndex}; pub use builder_bid::{ BuilderBid, BuilderBidBellatrix, BuilderBidCapella, BuilderBidDeneb, BuilderBidElectra, - BuilderBidFulu, BuilderBidHeze, SignedBuilderBid, + BuilderBidFulu, SignedBuilderBid, }; pub use builder_pending_payment::BuilderPendingPayment; pub use builder_pending_withdrawal::BuilderPendingWithdrawal; diff --git a/consensus/types/src/execution/dumb_macros.rs b/consensus/types/src/execution/dumb_macros.rs index 8b4a773cba..153ed9d5c6 100644 --- a/consensus/types/src/execution/dumb_macros.rs +++ b/consensus/types/src/execution/dumb_macros.rs @@ -29,10 +29,8 @@ macro_rules! map_execution_payload_into_full_payload { let f: fn(ExecutionPayloadFulu<_>, fn(_) -> _) -> _ = $f; f(inner, FullPayload::Fulu) } - ExecutionPayload::Gloas(_) => panic!("FullPayload::Gloas does not exist!"), - ExecutionPayload::Heze(inner) => { - let f: fn(ExecutionPayloadHeze<_>, fn(_) -> _) -> _ = $f; - f(inner, FullPayload::Heze) + ExecutionPayload::Gloas(_) | ExecutionPayload::Heze(_) => { + panic!("FullPayload::Gloas does not exist!") } } }; @@ -62,10 +60,8 @@ macro_rules! map_execution_payload_into_blinded_payload { let f: fn(ExecutionPayloadFulu<_>, fn(_) -> _) -> _ = $f; f(inner, BlindedPayload::Fulu) } - ExecutionPayload::Gloas(_) => panic!("BlindedPayload::Gloas does not exist!"), - ExecutionPayload::Heze(inner) => { - let f: fn(ExecutionPayloadHeze<_>, fn(_) -> _) -> _ = $f; - f(inner, BlindedPayload::Heze) + ExecutionPayload::Gloas(_) | ExecutionPayload::Heze(_) => { + panic!("BlindedPayload::Gloas does not exist!") } } }; @@ -110,14 +106,7 @@ macro_rules! map_execution_payload_ref_into_execution_payload_header { ) -> _ = $f; f(inner, ExecutionPayloadHeader::Fulu) } - ExecutionPayloadRef::Gloas(_) => panic!("ExecutionPayloadHeader::Gloas does not exist!"), - ExecutionPayloadRef::Heze(inner) => { - let f: fn( - &$lifetime ExecutionPayloadHeze<_>, - fn(_) -> _, - ) -> _ = $f; - f(inner, ExecutionPayloadHeader::Heze) - } + ExecutionPayloadRef::Gloas(_) | ExecutionPayloadRef::Heze(_) => panic!("ExecutionPayloadHeader::Gloas does not exist!"), } } } diff --git a/consensus/types/src/execution/execution_payload_envelope.rs b/consensus/types/src/execution/execution_payload_envelope.rs index a6d123bd21..70795dbdb1 100644 --- a/consensus/types/src/execution/execution_payload_envelope.rs +++ b/consensus/types/src/execution/execution_payload_envelope.rs @@ -1,56 +1,135 @@ -use crate::execution::{ExecutionPayloadGloas, ExecutionRequests}; +use crate::execution::{ + ExecutionPayloadGloas, ExecutionPayloadHeze, ExecutionPayloadRef, ExecutionRequests, +}; +use crate::fork::ForkVersionDecode; +use crate::state::BeaconStateError; use crate::test_utils::TestRandom; use crate::{EthSpec, ForkName, Hash256, SignedRoot, Slot}; -use context_deserialize::context_deserialize; +use context_deserialize::{ContextDeserialize, context_deserialize}; use educe::Educe; -use fixed_bytes::FixedBytesExtended; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use ssz::{BYTES_PER_LENGTH_OFFSET, Encode as SszEncode}; use ssz_derive::{Decode, Encode}; +use superstruct::superstruct; use test_random_derive::TestRandom; use tree_hash_derive::TreeHash; -#[derive(Debug, Clone, Serialize, Encode, Decode, Deserialize, TestRandom, TreeHash, Educe)] +#[superstruct( + variants(Gloas, Heze), + variant_attributes( + derive( + Default, + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TreeHash, + TestRandom, + Educe, + ), + educe(PartialEq, Hash(bound(E: EthSpec))), + serde(bound = "E: EthSpec", deny_unknown_fields), + cfg_attr( + feature = "arbitrary", + derive(arbitrary::Arbitrary), + arbitrary(bound = "E: EthSpec"), + ), + context_deserialize(ForkName), + ), + ref_attributes( + derive(PartialEq, TreeHash, Debug), + tree_hash(enum_behaviour = "transparent") + ), + cast_error( + ty = "BeaconStateError", + expr = "BeaconStateError::IncorrectStateVariant" + ), + partial_getter_error( + ty = "BeaconStateError", + expr = "BeaconStateError::IncorrectStateVariant" + ), +)] +#[cfg_attr( + feature = "arbitrary", + derive(arbitrary::Arbitrary), + arbitrary(bound = "E: EthSpec") +)] +#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Educe)] #[educe(PartialEq, Hash(bound(E: EthSpec)))] -#[context_deserialize(ForkName)] -#[serde(bound = "E: EthSpec")] +#[serde(bound = "E: EthSpec", untagged)] +#[tree_hash(enum_behaviour = "transparent")] +#[ssz(enum_behaviour = "transparent")] pub struct ExecutionPayloadEnvelope { + #[superstruct(only(Gloas), partial_getter(rename = "payload_gloas"))] pub payload: ExecutionPayloadGloas, + #[superstruct(only(Heze), partial_getter(rename = "payload_heze"))] + pub payload: ExecutionPayloadHeze, pub execution_requests: ExecutionRequests, #[serde(with = "serde_utils::quoted_u64")] + #[superstruct(getter(copy))] pub builder_index: u64, + #[superstruct(getter(copy))] pub beacon_block_root: Hash256, + #[superstruct(getter(copy))] pub parent_beacon_block_root: Hash256, } impl ExecutionPayloadEnvelope { - /// Returns an empty envelope with all fields zeroed. Used for SSZ size calculations. + pub fn slot(&self) -> Slot { + match self { + Self::Gloas(env) => env.payload.slot_number, + Self::Heze(env) => env.payload.slot_number, + } + } + + pub fn payload(&self) -> ExecutionPayloadRef<'_, E> { + match self { + Self::Gloas(env) => ExecutionPayloadRef::Gloas(&env.payload), + Self::Heze(env) => ExecutionPayloadRef::Heze(&env.payload), + } + } +} + +impl<'a, E: EthSpec> ExecutionPayloadEnvelopeRef<'a, E> { + pub fn slot(&self) -> Slot { + match self { + Self::Gloas(env) => env.payload.slot_number, + Self::Heze(env) => env.payload.slot_number, + } + } + + pub fn payload(&self) -> ExecutionPayloadRef<'_, E> { + match self { + Self::Gloas(env) => ExecutionPayloadRef::Gloas(&env.payload), + Self::Heze(env) => ExecutionPayloadRef::Heze(&env.payload), + } + } +} + +impl ExecutionPayloadEnvelopeGloas { pub fn empty() -> Self { Self { payload: ExecutionPayloadGloas::default(), execution_requests: ExecutionRequests::default(), builder_index: 0, - beacon_block_root: Hash256::zero(), - parent_beacon_block_root: Hash256::zero(), + beacon_block_root: Hash256::ZERO, + parent_beacon_block_root: Hash256::ZERO, } } - /// Returns the minimum SSZ-encoded size (all variable-length fields empty). pub fn min_size() -> usize { Self::empty().as_ssz_bytes().len() } - /// Returns the maximum SSZ-encoded size. #[allow(clippy::arithmetic_side_effects)] pub fn max_size() -> usize { Self::min_size() - // ExecutionPayloadGloas variable-length fields: + (E::max_extra_data_bytes() * ::ssz_fixed_len()) + (E::max_transactions_per_payload() * (BYTES_PER_LENGTH_OFFSET + E::max_bytes_per_transaction())) - + (E::max_withdrawals_per_payload() - * ::ssz_fixed_len()) - // ExecutionRequests variable-length fields: + + (E::max_withdrawals_per_payload() * ::ssz_fixed_len()) + (E::max_deposit_requests_per_payload() * ::ssz_fixed_len()) + (E::max_withdrawal_requests_per_payload() @@ -58,18 +137,99 @@ impl ExecutionPayloadEnvelope { + (E::max_consolidation_requests_per_payload() * ::ssz_fixed_len()) } +} - pub fn slot(&self) -> Slot { - self.payload.slot_number +impl ExecutionPayloadEnvelopeHeze { + pub fn empty() -> Self { + Self { + payload: ExecutionPayloadHeze::default(), + execution_requests: ExecutionRequests::default(), + builder_index: 0, + beacon_block_root: Hash256::ZERO, + parent_beacon_block_root: Hash256::ZERO, + } + } + + pub fn min_size() -> usize { + Self::empty().as_ssz_bytes().len() + } + + #[allow(clippy::arithmetic_side_effects)] + pub fn max_size() -> usize { + Self::min_size() + + (E::max_extra_data_bytes() * ::ssz_fixed_len()) + + (E::max_transactions_per_payload() + * (BYTES_PER_LENGTH_OFFSET + E::max_bytes_per_transaction())) + + (E::max_withdrawals_per_payload() * ::ssz_fixed_len()) + + (E::max_deposit_requests_per_payload() + * ::ssz_fixed_len()) + + (E::max_withdrawal_requests_per_payload() + * ::ssz_fixed_len()) + + (E::max_consolidation_requests_per_payload() + * ::ssz_fixed_len()) + } +} + +impl ForkVersionDecode for ExecutionPayloadEnvelope { + fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result { + match fork_name { + ForkName::Gloas => { + as ssz::Decode>::from_ssz_bytes(bytes) + .map(Self::Gloas) + } + ForkName::Heze => { + as ssz::Decode>::from_ssz_bytes(bytes) + .map(Self::Heze) + } + _ => Err(ssz::DecodeError::BytesInvalid(format!( + "unsupported fork for ExecutionPayloadEnvelope: {fork_name}", + ))), + } } } impl SignedRoot for ExecutionPayloadEnvelope {} +impl SignedRoot for ExecutionPayloadEnvelopeGloas {} +impl SignedRoot for ExecutionPayloadEnvelopeHeze {} +impl<'a, E: EthSpec> SignedRoot for ExecutionPayloadEnvelopeRef<'a, E> {} + +impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for ExecutionPayloadEnvelope { + fn context_deserialize(deserializer: D, context: ForkName) -> Result + where + D: Deserializer<'de>, + { + let convert_err = |e| { + serde::de::Error::custom(format!( + "ExecutionPayloadEnvelope failed to deserialize: {:?}", + e + )) + }; + match context { + ForkName::Heze => Ok(Self::Heze( + Deserialize::deserialize(deserializer).map_err(convert_err)?, + )), + ForkName::Gloas => Ok(Self::Gloas( + Deserialize::deserialize(deserializer).map_err(convert_err)?, + )), + _ => Err(serde::de::Error::custom(format!( + "ExecutionPayloadEnvelope failed to deserialize: unsupported fork '{}'", + context + ))), + } + } +} #[cfg(test)] mod tests { use super::*; use crate::MainnetEthSpec; - ssz_and_tree_hash_tests!(ExecutionPayloadEnvelope); + mod gloas { + use super::*; + ssz_and_tree_hash_tests!(ExecutionPayloadEnvelopeGloas); + } + mod heze { + use super::*; + ssz_and_tree_hash_tests!(ExecutionPayloadEnvelopeHeze); + } } diff --git a/consensus/types/src/execution/execution_payload_header.rs b/consensus/types/src/execution/execution_payload_header.rs index 8f46f6d323..27619a3022 100644 --- a/consensus/types/src/execution/execution_payload_header.rs +++ b/consensus/types/src/execution/execution_payload_header.rs @@ -14,8 +14,7 @@ use crate::{ core::{Address, EthSpec, ExecutionBlockHash, Hash256, Uint256}, execution::{ ExecutionPayloadBellatrix, ExecutionPayloadCapella, ExecutionPayloadDeneb, - ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadHeze, ExecutionPayloadRef, - Transactions, + ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadRef, Transactions, }, fork::ForkName, map_execution_payload_ref_into_execution_payload_header, @@ -24,7 +23,7 @@ use crate::{ }; #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Heze, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Default, @@ -106,12 +105,12 @@ pub struct ExecutionPayloadHeader { pub block_hash: ExecutionBlockHash, #[superstruct(getter(copy))] pub transactions_root: Hash256, - #[superstruct(only(Capella, Deneb, Electra, Heze, Fulu), partial_getter(copy))] + #[superstruct(only(Capella, Deneb, Electra, Fulu), partial_getter(copy))] pub withdrawals_root: Hash256, - #[superstruct(only(Deneb, Electra, Heze, Fulu), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub blob_gas_used: u64, - #[superstruct(only(Deneb, Electra, Heze, Fulu), partial_getter(copy))] + #[superstruct(only(Deneb, Electra, Fulu), partial_getter(copy))] #[serde(with = "serde_utils::quoted_u64")] pub excess_blob_gas: u64, } @@ -166,7 +165,6 @@ impl ExecutionPayloadHeader { ExecutionPayloadHeader::Capella(_) => ForkName::Capella, ExecutionPayloadHeader::Deneb(_) => ForkName::Deneb, ExecutionPayloadHeader::Electra(_) => ForkName::Electra, - ExecutionPayloadHeader::Heze(_) => ForkName::Heze, ExecutionPayloadHeader::Fulu(_) => ForkName::Fulu, } } @@ -251,30 +249,6 @@ impl ExecutionPayloadHeaderDeneb { } } -impl ExecutionPayloadHeaderFulu { - pub fn upgrade_to_heze(&self) -> ExecutionPayloadHeaderHeze { - ExecutionPayloadHeaderHeze { - parent_hash: self.parent_hash, - fee_recipient: self.fee_recipient, - state_root: self.state_root, - receipts_root: self.receipts_root, - logs_bloom: self.logs_bloom.clone(), - prev_randao: self.prev_randao, - block_number: self.block_number, - gas_limit: self.gas_limit, - gas_used: self.gas_used, - timestamp: self.timestamp, - extra_data: self.extra_data.clone(), - base_fee_per_gas: self.base_fee_per_gas, - block_hash: self.block_hash, - transactions_root: self.transactions_root, - withdrawals_root: self.withdrawals_root, - blob_gas_used: self.blob_gas_used, - excess_blob_gas: self.excess_blob_gas, - } - } -} - impl ExecutionPayloadHeaderElectra { pub fn upgrade_to_fulu(&self) -> ExecutionPayloadHeaderFulu { ExecutionPayloadHeaderFulu { @@ -390,30 +364,6 @@ impl<'a, E: EthSpec> From<&'a ExecutionPayloadElectra> for ExecutionPayloadHe } } -impl<'a, E: EthSpec> From<&'a ExecutionPayloadHeze> for ExecutionPayloadHeaderHeze { - fn from(payload: &'a ExecutionPayloadHeze) -> Self { - Self { - parent_hash: payload.parent_hash, - fee_recipient: payload.fee_recipient, - state_root: payload.state_root, - receipts_root: payload.receipts_root, - logs_bloom: payload.logs_bloom.clone(), - prev_randao: payload.prev_randao, - block_number: payload.block_number, - gas_limit: payload.gas_limit, - gas_used: payload.gas_used, - timestamp: payload.timestamp, - extra_data: payload.extra_data.clone(), - base_fee_per_gas: payload.base_fee_per_gas, - block_hash: payload.block_hash, - transactions_root: payload.transactions.tree_hash_root(), - withdrawals_root: payload.withdrawals.tree_hash_root(), - blob_gas_used: payload.blob_gas_used, - excess_blob_gas: payload.excess_blob_gas, - } - } -} - impl<'a, E: EthSpec> From<&'a ExecutionPayloadFulu> for ExecutionPayloadHeaderFulu { fn from(payload: &'a ExecutionPayloadFulu) -> Self { Self { @@ -464,12 +414,6 @@ impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderElectra { } } -impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderHeze { - fn from(payload: &'a Self) -> Self { - payload.clone() - } -} - impl<'a, E: EthSpec> From<&'a Self> for ExecutionPayloadHeaderFulu { fn from(payload: &'a Self) -> Self { payload.clone() @@ -534,9 +478,6 @@ impl ExecutionPayloadHeaderRefMut<'_, E> { ExecutionPayloadHeaderRefMut::Electra(mut_ref) => { *mut_ref = header.try_into()?; } - ExecutionPayloadHeaderRefMut::Heze(mut_ref) => { - *mut_ref = header.try_into()?; - } ExecutionPayloadHeaderRefMut::Fulu(mut_ref) => { *mut_ref = header.try_into()?; } @@ -557,16 +498,6 @@ impl TryFrom> for ExecutionPayloadHeaderEl } } -impl TryFrom> for ExecutionPayloadHeaderHeze { - type Error = BeaconStateError; - fn try_from(header: ExecutionPayloadHeader) -> Result { - match header { - ExecutionPayloadHeader::Heze(execution_payload_header) => Ok(execution_payload_header), - _ => Err(BeaconStateError::IncorrectStateVariant), - } - } -} - impl TryFrom> for ExecutionPayloadHeaderFulu { type Error = BeaconStateError; fn try_from(header: ExecutionPayloadHeader) -> Result { diff --git a/consensus/types/src/execution/mod.rs b/consensus/types/src/execution/mod.rs index 1bed51cf18..5216b4187d 100644 --- a/consensus/types/src/execution/mod.rs +++ b/consensus/types/src/execution/mod.rs @@ -25,11 +25,14 @@ pub use execution_payload::{ pub use execution_payload_bid::{ ExecutionPayloadBid, ExecutionPayloadBidGloas, ExecutionPayloadBidHeze, ExecutionPayloadBidRef, }; -pub use execution_payload_envelope::ExecutionPayloadEnvelope; +pub use execution_payload_envelope::{ + ExecutionPayloadEnvelope, ExecutionPayloadEnvelopeGloas, ExecutionPayloadEnvelopeHeze, + ExecutionPayloadEnvelopeRef, +}; pub use execution_payload_header::{ ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderHeze, ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, + ExecutionPayloadHeaderRef, ExecutionPayloadHeaderRefMut, }; pub use execution_requests::{ ConsolidationRequests, DepositRequests, ExecutionRequests, RequestType, WithdrawalRequests, @@ -39,14 +42,17 @@ pub use inclusion_list::{ }; pub use payload::{ AbstractExecPayload, BlindedPayload, BlindedPayloadBellatrix, BlindedPayloadCapella, - BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadHeze, - BlindedPayloadRef, BlockProductionVersion, BlockType, ExecPayload, FullPayload, - FullPayloadBellatrix, FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, - FullPayloadFulu, FullPayloadHeze, FullPayloadRef, OwnedExecPayload, + BlindedPayloadDeneb, BlindedPayloadElectra, BlindedPayloadFulu, BlindedPayloadRef, + BlockProductionVersion, BlockType, ExecPayload, FullPayload, FullPayloadBellatrix, + FullPayloadCapella, FullPayloadDeneb, FullPayloadElectra, FullPayloadFulu, FullPayloadRef, + OwnedExecPayload, }; pub use signed_bls_to_execution_change::SignedBlsToExecutionChange; pub use signed_execution_payload_bid::{ SignedExecutionPayloadBid, SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze, SignedExecutionPayloadBidRef, }; -pub use signed_execution_payload_envelope::SignedExecutionPayloadEnvelope; +pub use signed_execution_payload_envelope::{ + SignedExecutionPayloadEnvelope, SignedExecutionPayloadEnvelopeGloas, + SignedExecutionPayloadEnvelopeHeze, SignedExecutionPayloadEnvelopeRef, +}; diff --git a/consensus/types/src/execution/payload.rs b/consensus/types/src/execution/payload.rs index 8b5b5fadaa..71f9f43a88 100644 --- a/consensus/types/src/execution/payload.rs +++ b/consensus/types/src/execution/payload.rs @@ -17,7 +17,7 @@ use crate::{ ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionPayloadHeader, ExecutionPayloadHeaderBellatrix, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderFulu, - ExecutionPayloadHeaderHeze, ExecutionPayloadHeze, ExecutionPayloadRef, Transactions, + ExecutionPayloadRef, Transactions, }, fork::ForkName, map_execution_payload_into_blinded_payload, map_execution_payload_into_full_payload, @@ -119,7 +119,6 @@ pub trait AbstractExecPayload: + TryInto + TryInto + TryInto - + TryInto + Sync { type Ref<'a>: ExecPayload @@ -128,8 +127,7 @@ pub trait AbstractExecPayload: + From<&'a Self::Capella> + From<&'a Self::Deneb> + From<&'a Self::Electra> - + From<&'a Self::Fulu> - + From<&'a Self::Heze>; + + From<&'a Self::Fulu>; type Bellatrix: OwnedExecPayload + Into @@ -156,15 +154,10 @@ pub trait AbstractExecPayload: + for<'a> From>> + TryFrom> + Sync; - type Heze: OwnedExecPayload - + Into - + for<'a> From>> - + TryFrom> - + Sync; } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Heze, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Debug, @@ -223,8 +216,6 @@ pub struct FullPayload { pub execution_payload: ExecutionPayloadDeneb, #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] pub execution_payload: ExecutionPayloadElectra, - #[superstruct(only(Heze), partial_getter(rename = "execution_payload_heze"))] - pub execution_payload: ExecutionPayloadHeze, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload: ExecutionPayloadFulu, } @@ -338,7 +329,6 @@ impl ExecPayload for FullPayload { FullPayload::Deneb(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), FullPayload::Electra(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), FullPayload::Fulu(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), - FullPayload::Heze(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), } } @@ -350,7 +340,6 @@ impl ExecPayload for FullPayload { FullPayload::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayload::Electra(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayload::Fulu(inner) => Ok(inner.execution_payload.blob_gas_used), - FullPayload::Heze(inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -482,7 +471,6 @@ impl ExecPayload for FullPayloadRef<'_, E> { FullPayloadRef::Electra(inner) => { Ok(inner.execution_payload.withdrawals.tree_hash_root()) } - FullPayloadRef::Heze(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.withdrawals.tree_hash_root()), } } @@ -494,7 +482,6 @@ impl ExecPayload for FullPayloadRef<'_, E> { } FullPayloadRef::Deneb(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayloadRef::Electra(inner) => Ok(inner.execution_payload.blob_gas_used), - FullPayloadRef::Heze(inner) => Ok(inner.execution_payload.blob_gas_used), FullPayloadRef::Fulu(inner) => Ok(inner.execution_payload.blob_gas_used), } } @@ -518,7 +505,6 @@ impl AbstractExecPayload for FullPayload { type Capella = FullPayloadCapella; type Deneb = FullPayloadDeneb; type Electra = FullPayloadElectra; - type Heze = FullPayloadHeze; type Fulu = FullPayloadFulu; } @@ -538,7 +524,7 @@ impl TryFrom> for FullPayload { } #[superstruct( - variants(Bellatrix, Capella, Deneb, Electra, Heze, Fulu), + variants(Bellatrix, Capella, Deneb, Electra, Fulu), variant_attributes( derive( Debug, @@ -596,8 +582,6 @@ pub struct BlindedPayload { pub execution_payload_header: ExecutionPayloadHeaderDeneb, #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] pub execution_payload_header: ExecutionPayloadHeaderElectra, - #[superstruct(only(Heze), partial_getter(rename = "execution_payload_heze"))] - pub execution_payload_header: ExecutionPayloadHeaderHeze, #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] pub execution_payload_header: ExecutionPayloadHeaderFulu, } @@ -689,7 +673,6 @@ impl ExecPayload for BlindedPayload { BlindedPayload::Deneb(inner) => Ok(inner.execution_payload_header.withdrawals_root), BlindedPayload::Electra(inner) => Ok(inner.execution_payload_header.withdrawals_root), BlindedPayload::Fulu(inner) => Ok(inner.execution_payload_header.withdrawals_root), - BlindedPayload::Heze(inner) => Ok(inner.execution_payload_header.withdrawals_root), } } @@ -701,7 +684,6 @@ impl ExecPayload for BlindedPayload { BlindedPayload::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayload::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayload::Fulu(inner) => Ok(inner.execution_payload_header.blob_gas_used), - BlindedPayload::Heze(inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -800,7 +782,6 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { BlindedPayloadRef::Electra(inner) => { Ok(inner.execution_payload_header.withdrawals_root) } - BlindedPayloadRef::Heze(inner) => Ok(inner.execution_payload_header.withdrawals_root), BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.withdrawals_root), } } @@ -812,7 +793,6 @@ impl<'b, E: EthSpec> ExecPayload for BlindedPayloadRef<'b, E> { } BlindedPayloadRef::Deneb(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayloadRef::Electra(inner) => Ok(inner.execution_payload_header.blob_gas_used), - BlindedPayloadRef::Heze(inner) => Ok(inner.execution_payload_header.blob_gas_used), BlindedPayloadRef::Fulu(inner) => Ok(inner.execution_payload_header.blob_gas_used), } } @@ -1118,14 +1098,6 @@ impl_exec_payload_for_fork!( ExecutionPayloadElectra, Electra ); - -impl_exec_payload_for_fork!( - BlindedPayloadHeze, - FullPayloadHeze, - ExecutionPayloadHeaderHeze, - ExecutionPayloadHeze, - Heze -); impl_exec_payload_for_fork!( BlindedPayloadFulu, FullPayloadFulu, @@ -1140,7 +1112,6 @@ impl AbstractExecPayload for BlindedPayload { type Capella = BlindedPayloadCapella; type Deneb = BlindedPayloadDeneb; type Electra = BlindedPayloadElectra; - type Heze = BlindedPayloadHeze; type Fulu = BlindedPayloadFulu; } @@ -1178,11 +1149,6 @@ impl From> for BlindedPayload { execution_payload_header, }) } - ExecutionPayloadHeader::Heze(execution_payload_header) => { - Self::Heze(BlindedPayloadHeze { - execution_payload_header, - }) - } ExecutionPayloadHeader::Fulu(execution_payload_header) => { Self::Fulu(BlindedPayloadFulu { execution_payload_header, @@ -1207,9 +1173,6 @@ impl From> for ExecutionPayloadHeader { BlindedPayload::Electra(blinded_payload) => { ExecutionPayloadHeader::Electra(blinded_payload.execution_payload_header) } - BlindedPayload::Heze(blinded_payload) => { - ExecutionPayloadHeader::Heze(blinded_payload.execution_payload_header) - } BlindedPayload::Fulu(blinded_payload) => { ExecutionPayloadHeader::Fulu(blinded_payload.execution_payload_header) } diff --git a/consensus/types/src/execution/signed_execution_payload_envelope.rs b/consensus/types/src/execution/signed_execution_payload_envelope.rs index 522c8b3f54..afe9eeb560 100644 --- a/consensus/types/src/execution/signed_execution_payload_envelope.rs +++ b/consensus/types/src/execution/signed_execution_payload_envelope.rs @@ -1,48 +1,97 @@ +use crate::execution::{ + ExecutionPayloadEnvelopeGloas, ExecutionPayloadEnvelopeHeze, ExecutionPayloadEnvelopeRef, +}; +use crate::fork::ForkVersionDecode; +use crate::state::BeaconStateError; use crate::test_utils::TestRandom; use crate::{ - BeaconState, BeaconStateError, ChainSpec, Domain, Epoch, EthSpec, ExecutionBlockHash, - ExecutionPayloadEnvelope, Fork, ForkName, Hash256, SignedRoot, Slot, - consts::gloas::BUILDER_INDEX_SELF_BUILD, + BeaconState, ChainSpec, Domain, Epoch, EthSpec, ExecutionBlockHash, Fork, ForkName, Hash256, + SignedRoot, Slot, consts::gloas::BUILDER_INDEX_SELF_BUILD, }; use bls::{PublicKey, Signature}; -use context_deserialize::context_deserialize; +use context_deserialize::{ContextDeserialize, context_deserialize}; use educe::Educe; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use ssz::Encode; use ssz_derive::{Decode, Encode}; +use superstruct::superstruct; use test_random_derive::TestRandom; use tree_hash_derive::TreeHash; -#[derive(Debug, Clone, Serialize, Encode, Decode, Deserialize, TestRandom, TreeHash, Educe)] -#[educe(PartialEq, Hash(bound(E: EthSpec)))] -#[serde(bound = "E: EthSpec")] -#[context_deserialize(ForkName)] +#[superstruct( + variants(Gloas, Heze), + variant_attributes( + derive( + Debug, + Clone, + Serialize, + Deserialize, + Encode, + Decode, + TestRandom, + TreeHash, + Educe, + ), + educe(PartialEq, Hash(bound(E: EthSpec))), + context_deserialize(ForkName), + serde(bound = "E: EthSpec"), + cfg_attr( + feature = "arbitrary", + derive(arbitrary::Arbitrary), + arbitrary(bound = "E: EthSpec"), + ), + ), + cast_error( + ty = "BeaconStateError", + expr = "BeaconStateError::IncorrectStateVariant" + ), + partial_getter_error( + ty = "BeaconStateError", + expr = "BeaconStateError::IncorrectStateVariant" + ), + map_ref_into(ExecutionPayloadEnvelopeRef) +)] +#[cfg_attr( + feature = "arbitrary", + derive(arbitrary::Arbitrary), + arbitrary(bound = "E: EthSpec") +)] +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash)] +#[serde(untagged)] +#[tree_hash(enum_behaviour = "transparent")] +#[ssz(enum_behaviour = "transparent")] +#[serde(bound = "E: EthSpec", deny_unknown_fields)] pub struct SignedExecutionPayloadEnvelope { + #[superstruct(flatten)] pub message: ExecutionPayloadEnvelope, pub signature: Signature, } impl SignedExecutionPayloadEnvelope { - /// Returns the minimum SSZ-encoded size (all variable-length fields empty). - pub fn min_size() -> usize { - Self { - message: ExecutionPayloadEnvelope::empty(), - signature: Signature::empty(), + pub fn message(&self) -> ExecutionPayloadEnvelopeRef<'_, E> { + match self { + Self::Gloas(inner) => ExecutionPayloadEnvelopeRef::Gloas(&inner.message), + Self::Heze(inner) => ExecutionPayloadEnvelopeRef::Heze(&inner.message), } - .as_ssz_bytes() - .len() } - /// Returns the maximum SSZ-encoded size. + pub fn min_size() -> usize { + SignedExecutionPayloadEnvelopeGloas::::empty() + .as_ssz_bytes() + .len() + } + #[allow(clippy::arithmetic_side_effects)] pub fn max_size() -> usize { - // Signature is fixed-size, so the variable-length delta is entirely from the envelope. - Self::min_size() + ExecutionPayloadEnvelope::::max_size() - - ExecutionPayloadEnvelope::::min_size() + Self::min_size() + ExecutionPayloadEnvelopeGloas::::max_size() + - ExecutionPayloadEnvelopeGloas::::min_size() } pub fn slot(&self) -> Slot { - self.message.slot() + match self { + Self::Gloas(inner) => inner.message.payload.slot_number, + Self::Heze(inner) => inner.message.payload.slot_number, + } } pub fn epoch(&self) -> Epoch { @@ -50,11 +99,24 @@ impl SignedExecutionPayloadEnvelope { } pub fn beacon_block_root(&self) -> Hash256 { - self.message.beacon_block_root + match self { + Self::Gloas(inner) => inner.message.beacon_block_root, + Self::Heze(inner) => inner.message.beacon_block_root, + } } pub fn block_hash(&self) -> ExecutionBlockHash { - self.message.payload.block_hash + match self { + Self::Gloas(inner) => inner.message.payload.block_hash, + Self::Heze(inner) => inner.message.payload.block_hash, + } + } + + pub fn builder_index(&self) -> u64 { + match self { + Self::Gloas(inner) => inner.message.builder_index, + Self::Heze(inner) => inner.message.builder_index, + } } /// Verify `self.signature`. @@ -65,8 +127,6 @@ impl SignedExecutionPayloadEnvelope { genesis_validators_root: Hash256, spec: &ChainSpec, ) -> bool { - // Signed envelopes using the new BeaconBuilder domain per the spec: - // https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.1/specs/gloas/beacon-chain.md#new-verify_execution_payload_envelope_signature let domain = spec.get_domain( self.epoch(), Domain::BeaconBuilder, @@ -74,9 +134,8 @@ impl SignedExecutionPayloadEnvelope { genesis_validators_root, ); - let message = self.message.signing_root(domain); - - self.signature.verify(pubkey, message) + let message = self.message().signing_root(domain); + self.signature().verify(pubkey, message) } /// Verify `self.signature` using keys drawn from the beacon state. @@ -85,7 +144,7 @@ impl SignedExecutionPayloadEnvelope { state: &BeaconState, spec: &ChainSpec, ) -> Result { - let builder_index = self.message.builder_index; + let builder_index = self.builder_index(); let pubkey_bytes = if builder_index == BUILDER_INDEX_SELF_BUILD { let validator_index = state.latest_block_header().proposer_index; @@ -94,12 +153,8 @@ impl SignedExecutionPayloadEnvelope { state.get_builder(builder_index)?.pubkey }; - // TODO(gloas): Could use pubkey cache on state here, but it probably isn't worth - // it because this function is rarely used. Almost always the envelope should be signature - // verified prior to consensus code running. let pubkey = pubkey_bytes.decompress()?; - // Ensure the state's epoch matches the message's epoch before determining the Fork. if self.epoch() != state.current_epoch() { return Err(BeaconStateError::SignedEnvelopeIncorrectEpoch { state_epoch: state.current_epoch(), @@ -116,10 +171,79 @@ impl SignedExecutionPayloadEnvelope { } } +impl SignedExecutionPayloadEnvelopeGloas { + pub fn empty() -> Self { + Self { + message: ExecutionPayloadEnvelopeGloas::empty(), + signature: Signature::empty(), + } + } +} + +impl SignedExecutionPayloadEnvelopeHeze { + pub fn empty() -> Self { + Self { + message: ExecutionPayloadEnvelopeHeze::empty(), + signature: Signature::empty(), + } + } +} + +impl ForkVersionDecode for SignedExecutionPayloadEnvelope { + fn from_ssz_bytes_by_fork(bytes: &[u8], fork_name: ForkName) -> Result { + match fork_name { + ForkName::Gloas => { + as ssz::Decode>::from_ssz_bytes(bytes) + .map(Self::Gloas) + } + ForkName::Heze => { + as ssz::Decode>::from_ssz_bytes(bytes) + .map(Self::Heze) + } + _ => Err(ssz::DecodeError::BytesInvalid(format!( + "unsupported fork for SignedExecutionPayloadEnvelope: {fork_name}", + ))), + } + } +} + +impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for SignedExecutionPayloadEnvelope { + fn context_deserialize(deserializer: D, context: ForkName) -> Result + where + D: Deserializer<'de>, + { + let convert_err = |e| { + serde::de::Error::custom(format!( + "SignedExecutionPayloadEnvelope failed to deserialize: {:?}", + e + )) + }; + match context { + ForkName::Heze => Ok(Self::Heze( + Deserialize::deserialize(deserializer).map_err(convert_err)?, + )), + ForkName::Gloas => Ok(Self::Gloas( + Deserialize::deserialize(deserializer).map_err(convert_err)?, + )), + _ => Err(serde::de::Error::custom(format!( + "SignedExecutionPayloadEnvelope failed to deserialize: unsupported fork '{}'", + context + ))), + } + } +} + #[cfg(test)] mod tests { use super::*; use crate::MainnetEthSpec; - ssz_and_tree_hash_tests!(SignedExecutionPayloadEnvelope); + mod gloas { + use super::*; + ssz_and_tree_hash_tests!(SignedExecutionPayloadEnvelopeGloas); + } + mod heze { + use super::*; + ssz_and_tree_hash_tests!(SignedExecutionPayloadEnvelopeHeze); + } } diff --git a/testing/ef_tests/src/cases/fork_choice.rs b/testing/ef_tests/src/cases/fork_choice.rs index 8b0b74d256..edae712fb9 100644 --- a/testing/ef_tests/src/cases/fork_choice.rs +++ b/testing/ef_tests/src/cases/fork_choice.rs @@ -33,9 +33,9 @@ use std::time::Duration; use types::{ Attestation, AttestationRef, AttesterSlashing, AttesterSlashingRef, BeaconBlock, BeaconState, BlobSidecar, BlobsList, BlockImportSource, Checkpoint, DataColumnSidecar, - DataColumnSidecarList, DataColumnSubnetId, ExecutionBlockHash, Hash256, IndexedAttestation, - KzgProof, ProposerPreparationData, SignedBeaconBlock, SignedExecutionPayloadEnvelope, Slot, - Uint256, + DataColumnSidecarList, DataColumnSubnetId, ExecutionBlockHash, ForkVersionDecode, Hash256, + IndexedAttestation, KzgProof, ProposerPreparationData, SignedBeaconBlock, + SignedExecutionPayloadEnvelope, Slot, Uint256, }; // When set to true, cache any states fetched from the db. @@ -294,8 +294,12 @@ impl LoadCase for ForkChoiceTest { execution_payload, valid, } => { - let envelope = - ssz_decode_file(&path.join(format!("{execution_payload}.ssz_snappy")))?; + let envelope = ssz_decode_file_with( + &path.join(format!("{execution_payload}.ssz_snappy")), + |bytes| { + SignedExecutionPayloadEnvelope::from_ssz_bytes_by_fork(bytes, fork_name) + }, + )?; Ok(Step::OnExecutionPayload { execution_payload: envelope, valid, @@ -990,8 +994,8 @@ impl Tester { signed_envelope: &SignedExecutionPayloadEnvelope, valid: bool, ) -> Result<(), Error> { - let block_root = signed_envelope.message.beacon_block_root; - let block_hash = signed_envelope.message.payload.block_hash; + let block_root = signed_envelope.message().beacon_block_root(); + let block_hash = signed_envelope.message().payload().block_hash(); let store = &self.harness.chain.store; let spec = &self.harness.chain.spec; diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index f5c999920d..e40a5efc4e 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -496,8 +496,10 @@ impl Operation for SignedExecutionPayloadEnvelope { false } - fn decode(path: &Path, _: ForkName, _spec: &ChainSpec) -> Result { - ssz_decode_file(path) + fn decode(path: &Path, fork_name: ForkName, _spec: &ChainSpec) -> Result { + ssz_decode_file_with(path, |bytes| { + SignedExecutionPayloadEnvelope::from_ssz_bytes_by_fork(bytes, fork_name) + }) } fn apply_to( diff --git a/testing/ef_tests/src/type_name.rs b/testing/ef_tests/src/type_name.rs index 22e469aa08..aaddd5d0c4 100644 --- a/testing/ef_tests/src/type_name.rs +++ b/testing/ef_tests/src/type_name.rs @@ -92,7 +92,6 @@ type_name_generic!(ExecutionPayloadHeaderCapella, "ExecutionPayloadHeader"); type_name_generic!(ExecutionPayloadHeaderDeneb, "ExecutionPayloadHeader"); type_name_generic!(ExecutionPayloadHeaderElectra, "ExecutionPayloadHeader"); type_name_generic!(ExecutionPayloadHeaderFulu, "ExecutionPayloadHeader"); -type_name_generic!(ExecutionPayloadHeaderHeze, "ExecutionPayloadHeader"); type_name_generic!(ExecutionPayloadBid); type_name_generic!(SignedExecutionPayloadBidGloas, "SignedExecutionPayloadBid"); type_name_generic!(ExecutionRequests); diff --git a/validator_client/lighthouse_validator_store/src/lib.rs b/validator_client/lighthouse_validator_store/src/lib.rs index 989624db3b..84fb48bcc6 100644 --- a/validator_client/lighthouse_validator_store/src/lib.rs +++ b/validator_client/lighthouse_validator_store/src/lib.rs @@ -23,10 +23,12 @@ use types::{ ChainSpec, ContributionAndProof, Domain, Epoch, EthSpec, ExecutionPayloadEnvelope, Fork, FullPayload, Graffiti, Hash256, InclusionList, PayloadAttestationData, PayloadAttestationMessage, SelectionProof, SignedAggregateAndProof, SignedBeaconBlock, - SignedContributionAndProof, SignedExecutionPayloadEnvelope, SignedInclusionList, SignedRoot, - SignedValidatorRegistrationData, SignedVoluntaryExit, Slot, SyncAggregatorSelectionData, - SyncCommitteeContribution, SyncCommitteeMessage, SyncSelectionProof, SyncSubnetId, - ValidatorRegistrationData, VoluntaryExit, graffiti::GraffitiString, + SignedContributionAndProof, SignedExecutionPayloadEnvelope, + SignedExecutionPayloadEnvelopeGloas, SignedExecutionPayloadEnvelopeHeze, SignedInclusionList, + SignedRoot, SignedValidatorRegistrationData, SignedVoluntaryExit, Slot, + SyncAggregatorSelectionData, SyncCommitteeContribution, SyncCommitteeMessage, + SyncSelectionProof, SyncSubnetId, ValidatorRegistrationData, VoluntaryExit, + graffiti::GraffitiString, }; use validator_store::{ AggregateToSign, AttestationToSign, ContributionToSign, DoppelgangerStatus, @@ -1504,9 +1506,19 @@ impl ValidatorStore for LighthouseValidatorS .await .map_err(Error::SpecificError)?; - Ok(SignedExecutionPayloadEnvelope { - message: envelope, - signature, + Ok(match envelope { + ExecutionPayloadEnvelope::Gloas(message) => { + SignedExecutionPayloadEnvelope::Gloas(SignedExecutionPayloadEnvelopeGloas { + message, + signature, + }) + } + ExecutionPayloadEnvelope::Heze(message) => { + SignedExecutionPayloadEnvelope::Heze(SignedExecutionPayloadEnvelopeHeze { + message, + signature, + }) + } }) } } diff --git a/validator_client/validator_services/src/block_service.rs b/validator_client/validator_services/src/block_service.rs index 99e53b0100..356655b7e0 100644 --- a/validator_client/validator_services/src/block_service.rs +++ b/validator_client/validator_services/src/block_service.rs @@ -654,6 +654,7 @@ impl BlockService { // Fetch the envelope from the beacon node. Use builder_index=BUILDER_INDEX_SELF_BUILD for local building. // TODO(gloas): Use proposer_fallback once multi-BN is supported. + let fork_name = self.chain_spec.fork_name_at_slot::(slot); let envelope = self .beacon_nodes .first_success(|beacon_node| async move { @@ -661,6 +662,7 @@ impl BlockService { .get_validator_execution_payload_envelope_ssz::( slot, BUILDER_INDEX_SELF_BUILD, + fork_name, ) .await .map_err(|e| { @@ -674,7 +676,7 @@ impl BlockService { info!( slot = slot.as_u64(), - beacon_block_root = %envelope.beacon_block_root, + beacon_block_root = %envelope.beacon_block_root(), "Received execution payload envelope, signing" ); @@ -718,7 +720,7 @@ impl BlockService { info!( slot = slot.as_u64(), - beacon_block_root = %signed_envelope.message.beacon_block_root, + beacon_block_root = %signed_envelope.message().beacon_block_root(), "Successfully published signed execution payload envelope" );