diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index d5a2929301..ada7bc37ac 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -5727,15 +5727,12 @@ impl BeaconChain { ) } BeaconState::Gloas(_) => { - let ( - payload, - kzg_commitments, - maybe_blobs_and_proofs, - maybe_requests, - execution_payload_value, - ) = block_contents - .ok_or(BlockProductionError::MissingExecutionPayload)? - .deconstruct(); + // Gloas blocks contain execution bids, not execution payloads + let block_proposal_contents = + block_contents.ok_or(BlockProductionError::MissingExecutionBid)?; + let (signed_execution_bid, payload_attestations) = block_proposal_contents + .into_execution_bid() + .map_err(|_| BlockProductionError::InvalidPayloadFork)?; ( BeaconBlock::Gloas(BeaconBlockGloas { @@ -5754,18 +5751,15 @@ impl BeaconChain { voluntary_exits: voluntary_exits.into(), sync_aggregate: sync_aggregate .ok_or(BlockProductionError::MissingSyncAggregate)?, - execution_payload: payload - .try_into() - .map_err(|_| BlockProductionError::InvalidPayloadFork)?, bls_to_execution_changes: bls_to_execution_changes.into(), - blob_kzg_commitments: kzg_commitments - .ok_or(BlockProductionError::InvalidPayloadFork)?, - execution_requests: maybe_requests - .ok_or(BlockProductionError::MissingExecutionRequests)?, + // EIP-7732: Use actual execution bid data + signed_execution_payload_header: signed_execution_bid.clone(), + payload_attestations, + _phantom: PhantomData, }, }), - maybe_blobs_and_proofs, - execution_payload_value, + None, // blob commitments moved to `ExecutionPayloadEnvelope` + Uint256::ZERO, // No execution payload value for Gloas blocks, just bids value ) } }; diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index a1a0ec74f6..16d0faa303 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -292,6 +292,7 @@ pub enum BlockProductionError { MissingBlobs, MissingSyncAggregate, MissingExecutionPayload, + MissingExecutionBid, MissingKzgCommitment(String), TokioJoin(JoinError), BeaconChain(Box), diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index c9b84f25b8..4737d07f2e 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -3252,25 +3252,6 @@ pub fn generate_rand_block_and_blobs( message.body.blob_kzg_commitments = bundle.commitments.clone(); bundle } - SignedBeaconBlock::Gloas(SignedBeaconBlockGloas { - ref mut message, .. - }) => { - // Get either zero blobs or a random number of blobs between 1 and Max Blobs. - let payload: &mut FullPayloadGloas = &mut message.body.execution_payload; - let num_blobs = match num_blobs { - NumBlobs::Random => rng.random_range(1..=max_blobs), - NumBlobs::Number(n) => n, - NumBlobs::None => 0, - }; - let (bundle, transactions) = - execution_layer::test_utils::generate_blobs::(num_blobs, fork_name).unwrap(); - payload.execution_payload.transactions = <_>::default(); - for tx in Vec::from(transactions) { - payload.execution_payload.transactions.push(tx).unwrap(); - } - message.body.blob_kzg_commitments = bundle.commitments.clone(); - bundle - } _ => return (block, blob_sidecars), }; 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 aa5261c80b..9f5d38327e 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 @@ -177,7 +177,7 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> fn try_from(block: BeaconBlockRef<'a, E>) -> Result { match block { - BeaconBlockRef::Base(_) | BeaconBlockRef::Altair(_) => { + BeaconBlockRef::Base(_) | BeaconBlockRef::Altair(_) | BeaconBlockRef::Gloas(_) => { Err(Self::Error::IncorrectStateVariant) } BeaconBlockRef::Bellatrix(block_ref) => { @@ -220,17 +220,6 @@ impl<'a, E: EthSpec> TryFrom> for NewPayloadRequest<'a, E> parent_beacon_block_root: block_ref.parent_root, execution_requests: &block_ref.body.execution_requests, })), - BeaconBlockRef::Gloas(block_ref) => Ok(Self::Gloas(NewPayloadRequestGloas { - 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, - })), } } } diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index b53c4cde4e..796c34ffe0 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -51,7 +51,7 @@ use types::non_zero_usize::new_non_zero_usize; use types::payload::BlockProductionVersion; use types::{ AbstractExecPayload, BlobsList, ExecutionPayloadDeneb, ExecutionRequests, KzgProofs, - SignedBlindedBeaconBlock, + PayloadAttestation, SignedBlindedBeaconBlock, SignedExecutionBid, }; use types::{ BeaconStateError, BlindedPayload, ChainSpec, Epoch, ExecPayload, ExecutionPayloadBellatrix, @@ -219,6 +219,11 @@ pub enum BlockProposalContents> { // See: https://github.com/sigp/lighthouse/issues/6981 requests: Option>, }, + /// EIP-7732: Execution bid and payload attestations for Gloas fork + BidAndPayloadAttestations { + signed_execution_bid: SignedExecutionBid, + payload_attestations: VariableList, E::MaxPayloadAttestations>, + }, } impl From>> @@ -246,6 +251,13 @@ impl From>> blobs_and_proofs: None, requests, }, + BlockProposalContents::BidAndPayloadAttestations { + signed_execution_bid, + payload_attestations, + } => BlockProposalContents::BidAndPayloadAttestations { + signed_execution_bid, + payload_attestations, + }, } } } @@ -313,6 +325,28 @@ impl> BlockProposalContents { + panic!("Cannot deconstruct BidAndPayloadAttestations variant into execution payload components") + } + } + } + + /// Extract execution bid data for EIP-7732 Gloas blocks + pub fn into_execution_bid( + self, + ) -> Result< + ( + SignedExecutionBid, + VariableList, E::MaxPayloadAttestations>, + ), + &'static str, + > { + match self { + Self::BidAndPayloadAttestations { + signed_execution_bid, + payload_attestations, + } => Ok((signed_execution_bid, payload_attestations)), + _ => Err("Cannot extract execution bid from non-BidAndPayloadAttestations variant"), } } @@ -320,18 +354,27 @@ impl> BlockProposalContents payload, Self::PayloadAndBlobs { payload, .. } => payload, + Self::BidAndPayloadAttestations { .. } => { + panic!("BidAndPayloadAttestations variant does not contain execution payload") + } } } pub fn to_payload(self) -> Payload { match self { Self::Payload { payload, .. } => payload, Self::PayloadAndBlobs { payload, .. } => payload, + Self::BidAndPayloadAttestations { .. } => { + panic!("BidAndPayloadAttestations variant does not contain execution payload") + } } } pub fn block_value(&self) -> &Uint256 { match self { Self::Payload { block_value, .. } => block_value, Self::PayloadAndBlobs { block_value, .. } => block_value, + Self::BidAndPayloadAttestations { .. } => { + panic!("BidAndPayloadAttestations variant does not have block_value") + } } } } 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 516662b1d6..79ee1473e4 100644 --- a/beacon_node/execution_layer/src/test_utils/mock_builder.rs +++ b/beacon_node/execution_layer/src/test_utils/mock_builder.rs @@ -464,7 +464,9 @@ impl MockBuilder { block: SignedBlindedBeaconBlock, ) -> Result, String> { let root = match &block { - SignedBlindedBeaconBlock::Base(_) | types::SignedBeaconBlock::Altair(_) => { + SignedBlindedBeaconBlock::Base(_) + | SignedBlindedBeaconBlock::Altair(_) + | SignedBlindedBeaconBlock::Gloas(_) => { return Err("invalid fork".to_string()); } SignedBlindedBeaconBlock::Bellatrix(block) => { @@ -482,9 +484,6 @@ impl MockBuilder { SignedBlindedBeaconBlock::Fulu(block) => { block.message.body.execution_payload.tree_hash_root() } - SignedBlindedBeaconBlock::Gloas(block) => { - block.message.body.execution_payload.tree_hash_root() - } }; info!( block_hash = %root, diff --git a/consensus/types/src/beacon_block.rs b/consensus/types/src/beacon_block.rs index f4e4e36966..62401ebefe 100644 --- a/consensus/types/src/beacon_block.rs +++ b/consensus/types/src/beacon_block.rs @@ -672,10 +672,10 @@ impl> EmptyBlock for BeaconBlockGloa deposits: VariableList::empty(), voluntary_exits: VariableList::empty(), sync_aggregate: SyncAggregate::empty(), - execution_payload: Payload::Gloas::default(), bls_to_execution_changes: VariableList::empty(), - blob_kzg_commitments: VariableList::empty(), - execution_requests: ExecutionRequests::default(), + signed_execution_payload_header: SignedExecutionBid::empty(), + payload_attestations: VariableList::empty(), + _phantom: PhantomData, }, } } diff --git a/consensus/types/src/beacon_block_body.rs b/consensus/types/src/beacon_block_body.rs index 73d02dbe61..75fd303dfc 100644 --- a/consensus/types/src/beacon_block_body.rs +++ b/consensus/types/src/beacon_block_body.rs @@ -61,7 +61,11 @@ pub const BLOB_KZG_COMMITMENTS_INDEX: usize = 11; Deneb(metastruct(mappings(beacon_block_body_deneb_fields(groups(fields))))), Electra(metastruct(mappings(beacon_block_body_electra_fields(groups(fields))))), Fulu(metastruct(mappings(beacon_block_body_fulu_fields(groups(fields))))), - Gloas(metastruct(mappings(beacon_block_body_gloas_fields(groups(fields))))), +// we relax the trait bounds for gloas since it doesn't contain a Payload + Gloas( + derivative(PartialEq, Hash(bound = "E: EthSpec")), + metastruct(mappings(beacon_block_body_gloas_fields(groups(fields)))) + ), ), cast_error(ty = "Error", expr = "Error::IncorrectStateVariant"), partial_getter_error(ty = "Error", expr = "Error::IncorrectStateVariant") @@ -127,17 +131,21 @@ pub struct BeaconBlockBody = FullPay #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] #[serde(flatten)] pub execution_payload: Payload::Fulu, - #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] - #[serde(flatten)] - pub execution_payload: Payload::Gloas, + // execution_payload removed from Gloas, replaced with signed_execution_payload_header below #[superstruct(only(Capella, Deneb, Electra, Fulu, Gloas))] pub bls_to_execution_changes: VariableList, - #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + // blob_kzg_commitments removed from Gloas, moved to `ExecutionPayloadEnvelope` + #[superstruct(only(Deneb, Electra, Fulu))] pub blob_kzg_commitments: KzgCommitments, - #[superstruct(only(Electra, Fulu, Gloas))] + // execution_requests removed from Gloas, moved to `ExecutionPayloadEnvelope` + #[superstruct(only(Electra, Fulu))] pub execution_requests: ExecutionRequests, - #[superstruct(only(Base, Altair))] + #[superstruct(only(Gloas))] + pub signed_execution_payload_header: SignedExecutionBid, + #[superstruct(only(Gloas))] + pub payload_attestations: VariableList, E::MaxPayloadAttestations>, + #[superstruct(only(Base, Altair, Gloas))] #[metastruct(exclude_from(fields))] #[ssz(skip_serializing, skip_deserializing)] #[tree_hash(skip_hashing)] @@ -160,13 +168,12 @@ impl> BeaconBlockBody { impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, Payload> { pub fn execution_payload(&self) -> Result, Error> { match self { - Self::Base(_) | Self::Altair(_) => Err(Error::IncorrectStateVariant), + Self::Base(_) | Self::Altair(_) | Self::Gloas(_) => Err(Error::IncorrectStateVariant), Self::Bellatrix(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Capella(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Deneb(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Electra(body) => Ok(Payload::Ref::from(&body.execution_payload)), Self::Fulu(body) => Ok(Payload::Ref::from(&body.execution_payload)), - Self::Gloas(body) => Ok(Payload::Ref::from(&body.execution_payload)), } } @@ -230,10 +237,12 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> BeaconBlockBodyRef<'a, E, kzg_commitments_proof: &[Hash256], ) -> Result, Error> { match self { - Self::Base(_) | Self::Altair(_) | Self::Bellatrix(_) | Self::Capella(_) => { - Err(Error::IncorrectStateVariant) - } - Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) | Self::Gloas(_) => { + Self::Base(_) + | Self::Altair(_) + | Self::Bellatrix(_) + | Self::Capella(_) + | Self::Gloas(_) => Err(Error::IncorrectStateVariant), + Self::Deneb(_) | Self::Electra(_) | Self::Fulu(_) => { // We compute the branches by generating 2 merkle trees: // 1. Merkle tree for the `blob_kzg_commitments` List object // 2. Merkle tree for the `BeaconBlockBody` container @@ -512,6 +521,45 @@ impl From>> } } +// Post-Fulu block bodies without payloads can be converted into block bodies with payloads +impl From>> + for BeaconBlockBodyGloas> +{ + fn from(body: BeaconBlockBodyGloas>) -> Self { + let BeaconBlockBodyGloas { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + signed_execution_payload_header, + payload_attestations, + _phantom, + } = body; + + BeaconBlockBodyGloas { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings, + attester_slashings, + attestations, + deposits, + voluntary_exits, + sync_aggregate, + bls_to_execution_changes, + signed_execution_payload_header, + payload_attestations, + _phantom: PhantomData, + } + } +} + // Likewise bodies with payloads can be transformed into bodies without. impl From>> for ( @@ -822,10 +870,10 @@ impl From>> deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayloadGloas { execution_payload }, bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, + signed_execution_payload_header, + payload_attestations, + _phantom, } = body; ( @@ -839,14 +887,12 @@ impl From>> deposits, voluntary_exits, sync_aggregate, - execution_payload: BlindedPayloadGloas { - execution_payload_header: From::from(&execution_payload), - }, bls_to_execution_changes, - blob_kzg_commitments: blob_kzg_commitments.clone(), - execution_requests, + signed_execution_payload_header, + payload_attestations, + _phantom: PhantomData, }, - Some(execution_payload), + None, ) } } @@ -1046,39 +1092,8 @@ impl BeaconBlockBodyFulu> { impl BeaconBlockBodyGloas> { pub fn clone_as_blinded(&self) -> BeaconBlockBodyGloas> { - let BeaconBlockBodyGloas { - randao_reveal, - eth1_data, - graffiti, - proposer_slashings, - attester_slashings, - attestations, - deposits, - voluntary_exits, - sync_aggregate, - execution_payload: FullPayloadGloas { execution_payload }, - bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, - } = self; - - BeaconBlockBodyGloas { - randao_reveal: randao_reveal.clone(), - eth1_data: eth1_data.clone(), - graffiti: *graffiti, - proposer_slashings: proposer_slashings.clone(), - attester_slashings: attester_slashings.clone(), - attestations: attestations.clone(), - deposits: deposits.clone(), - voluntary_exits: voluntary_exits.clone(), - sync_aggregate: sync_aggregate.clone(), - execution_payload: BlindedPayloadGloas { - execution_payload_header: execution_payload.into(), - }, - bls_to_execution_changes: bls_to_execution_changes.clone(), - blob_kzg_commitments: blob_kzg_commitments.clone(), - execution_requests: execution_requests.clone(), - } + let (block_body, _payload) = self.clone().into(); + block_body } } diff --git a/consensus/types/src/signed_beacon_block.rs b/consensus/types/src/signed_beacon_block.rs index 979b91e30d..53d34a4351 100644 --- a/consensus/types/src/signed_beacon_block.rs +++ b/consensus/types/src/signed_beacon_block.rs @@ -6,6 +6,7 @@ use merkle_proof::MerkleTree; use serde::{Deserialize, Deserializer, Serialize}; use ssz_derive::{Decode, Encode}; use std::fmt; +use std::marker::PhantomData; use superstruct::superstruct; use test_random_derive::TestRandom; use tree_hash::TreeHash; @@ -648,10 +649,11 @@ impl SignedBeaconBlockFulu> { } } +/// Gloas doesn't support BlindedPayload, but we keep this impl for compatibility purposes of the SignedBeaconBlock type impl SignedBeaconBlockGloas> { pub fn into_full_block( self, - execution_payload: ExecutionPayloadGloas, + _execution_payload: ExecutionPayloadGloas, ) -> SignedBeaconBlockGloas> { let SignedBeaconBlockGloas { message: @@ -671,10 +673,10 @@ impl SignedBeaconBlockGloas> { deposits, voluntary_exits, sync_aggregate, - execution_payload: BlindedPayloadGloas { .. }, bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, + signed_execution_payload_header, + payload_attestations, + .. }, }, signature, @@ -695,10 +697,10 @@ impl SignedBeaconBlockGloas> { deposits, voluntary_exits, sync_aggregate, - execution_payload: FullPayloadGloas { execution_payload }, bls_to_execution_changes, - blob_kzg_commitments, - execution_requests, + signed_execution_payload_header, + payload_attestations, + _phantom: PhantomData, }, }, signature,