From e75eb4758c45d898528fc2b084d3ee53567e1b85 Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Thu, 30 Apr 2026 16:08:10 +0200 Subject: [PATCH] fix claude dummy --- .../src/block_production/gloas.rs | 195 ++++++++++-------- .../gossip_verified_bid.rs | 133 +++++++----- .../payload_bid_cache.rs | 54 +++-- .../src/payload_bid_verification/tests.rs | 47 +++-- .../payload_envelope_verification/import.rs | 7 +- .../lighthouse_network/src/types/pubsub.rs | 32 ++- .../gossip_methods.rs | 6 +- .../src/network_beacon_processor/mod.rs | 2 +- common/eth2/src/types.rs | 2 +- consensus/proto_array/src/proto_array.rs | 1 - .../execution/signed_execution_payload_bid.rs | 30 ++- 11 files changed, 296 insertions(+), 213 deletions(-) diff --git a/beacon_node/beacon_chain/src/block_production/gloas.rs b/beacon_node/beacon_chain/src/block_production/gloas.rs index ea58630d4e..3449e80980 100644 --- a/beacon_node/beacon_chain/src/block_production/gloas.rs +++ b/beacon_node/beacon_chain/src/block_production/gloas.rs @@ -32,9 +32,9 @@ use types::{ ExecutionBlockHash, ExecutionPayloadBidGloas, ExecutionPayloadBidHeze, ExecutionPayloadEnvelope, ExecutionPayloadGloas, ExecutionRequests, FullPayload, Graffiti, Hash256, PayloadAttestation, ProposerSlashing, RelativeEpoch, SignedBeaconBlock, - SignedBlsToExecutionChange, SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze, - SignedExecutionPayloadEnvelope, SignedVoluntaryExit, Slot, SyncAggregate, Withdrawal, - Withdrawals, + SignedBlsToExecutionChange, SignedExecutionPayloadBid, SignedExecutionPayloadBidGloas, + SignedExecutionPayloadBidHeze, SignedExecutionPayloadEnvelope, SignedVoluntaryExit, + Slot, SyncAggregate, Withdrawal, Withdrawals, }; use crate::pending_payload_envelopes::PendingEnvelopeData; @@ -513,7 +513,7 @@ impl BeaconChain { fn complete_partial_beacon_block_gloas( &self, partial_beacon_block: PartialBeaconBlock, - signed_execution_payload_bid: SignedExecutionPayloadBidGloas, + signed_execution_payload_bid: SignedExecutionPayloadBid, parent_execution_requests: ExecutionRequests, payload_data: Option>, mut state: BeaconState, @@ -548,44 +548,53 @@ impl BeaconChain { "complete_partial_beacon_block_gloas called with pre-Gloas state".to_owned(), )); } - BeaconState::Gloas(_) => BeaconBlock::Gloas(BeaconBlockGloas { - slot, - proposer_index, - parent_root, - state_root: Hash256::ZERO, - body: BeaconBlockBodyGloas { - randao_reveal, - eth1_data, - graffiti, - proposer_slashings: proposer_slashings - .try_into() - .map_err(BlockProductionError::SszTypesError)?, - attester_slashings: attester_slashings - .try_into() - .map_err(BlockProductionError::SszTypesError)?, - attestations: attestations - .try_into() - .map_err(BlockProductionError::SszTypesError)?, - deposits: deposits - .try_into() - .map_err(BlockProductionError::SszTypesError)?, - voluntary_exits: voluntary_exits - .try_into() - .map_err(BlockProductionError::SszTypesError)?, - sync_aggregate, - bls_to_execution_changes: bls_to_execution_changes - .try_into() - .map_err(BlockProductionError::SszTypesError)?, - parent_execution_requests, - signed_execution_payload_bid, - payload_attestations: payload_attestations - .try_into() - .map_err(BlockProductionError::SszTypesError)?, - _phantom: PhantomData::>, - }, - }), + BeaconState::Gloas(_) => { + let gloas_bid = match signed_execution_payload_bid { + SignedExecutionPayloadBid::Gloas(bid) => bid, + SignedExecutionPayloadBid::Heze(_) => { + return Err(BlockProductionError::GloasNotImplemented( + "Heze bid variant used with Gloas state".to_owned(), + )); + } + }; + BeaconBlock::Gloas(BeaconBlockGloas { + slot, + proposer_index, + parent_root, + state_root: Hash256::ZERO, + body: BeaconBlockBodyGloas { + randao_reveal, + eth1_data, + graffiti, + proposer_slashings: proposer_slashings + .try_into() + .map_err(BlockProductionError::SszTypesError)?, + attester_slashings: attester_slashings + .try_into() + .map_err(BlockProductionError::SszTypesError)?, + attestations: attestations + .try_into() + .map_err(BlockProductionError::SszTypesError)?, + deposits: deposits + .try_into() + .map_err(BlockProductionError::SszTypesError)?, + voluntary_exits: voluntary_exits + .try_into() + .map_err(BlockProductionError::SszTypesError)?, + sync_aggregate, + bls_to_execution_changes: bls_to_execution_changes + .try_into() + .map_err(BlockProductionError::SszTypesError)?, + parent_execution_requests, + signed_execution_payload_bid: gloas_bid, + payload_attestations: payload_attestations + .try_into() + .map_err(BlockProductionError::SszTypesError)?, + _phantom: PhantomData::>, + }, + }) + } BeaconState::Heze(_) => { - let gloas_bid = signed_execution_payload_bid; // Compute inclusion_list_bits for the previous slot's ILs let il_slot = slot.saturating_sub(1_u64); let inclusion_list_bits = state @@ -596,23 +605,28 @@ impl BeaconChain { .get_inclusion_list_bits(il_slot, &committee, false) }) .unwrap_or_default(); - let heze_bid = SignedExecutionPayloadBidHeze { - message: ExecutionPayloadBidHeze { - parent_block_hash: gloas_bid.message.parent_block_hash, - parent_block_root: gloas_bid.message.parent_block_root, - block_hash: gloas_bid.message.block_hash, - prev_randao: gloas_bid.message.prev_randao, - fee_recipient: gloas_bid.message.fee_recipient, - gas_limit: gloas_bid.message.gas_limit, - builder_index: gloas_bid.message.builder_index, - slot: gloas_bid.message.slot, - value: gloas_bid.message.value, - execution_payment: gloas_bid.message.execution_payment, - blob_kzg_commitments: gloas_bid.message.blob_kzg_commitments, - execution_requests_root: gloas_bid.message.execution_requests_root, - inclusion_list_bits, - }, - signature: gloas_bid.signature, + let heze_bid = match signed_execution_payload_bid { + SignedExecutionPayloadBid::Heze(bid) => bid, + SignedExecutionPayloadBid::Gloas(gloas_bid) => { + SignedExecutionPayloadBidHeze { + message: ExecutionPayloadBidHeze { + parent_block_hash: gloas_bid.message.parent_block_hash, + parent_block_root: gloas_bid.message.parent_block_root, + block_hash: gloas_bid.message.block_hash, + prev_randao: gloas_bid.message.prev_randao, + fee_recipient: gloas_bid.message.fee_recipient, + gas_limit: gloas_bid.message.gas_limit, + builder_index: gloas_bid.message.builder_index, + slot: gloas_bid.message.slot, + value: gloas_bid.message.value, + execution_payment: gloas_bid.message.execution_payment, + blob_kzg_commitments: gloas_bid.message.blob_kzg_commitments, + execution_requests_root: gloas_bid.message.execution_requests_root, + inclusion_list_bits, + }, + signature: gloas_bid.signature, + } + } }; BeaconBlock::Heze(BeaconBlockHeze { slot, @@ -781,7 +795,7 @@ impl BeaconChain { builder_index: BuilderIndex, ) -> Result< ( - SignedExecutionPayloadBidGloas, + SignedExecutionPayloadBid, BeaconState, LocalBuildResult, ), @@ -889,10 +903,10 @@ impl BeaconChain { }; Ok(( - SignedExecutionPayloadBidGloas { + SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas { message: bid, signature: Signature::infinity().map_err(BlockProductionError::BlsError)?, - }, + }), state, LocalBuildResult { payload_data, @@ -904,19 +918,24 @@ impl BeaconChain { /// Look up the highest gossip-verified bid for the `(slot, parent_block_hash, /// parent_block_root)` of the local bid, then choose the winner. + // TODO(focil): When the bid cache supports Heze-typed bids, validate that any external + // builder bid's `inclusion_list_bits` satisfies `is_inclusion_list_bits_inclusive` with + // `only_timely=False` before accepting it. Currently the cache is Gloas-typed so this + // check cannot be performed. + // See: https://github.com/ethereum/consensus-specs/blob/master/specs/heze/validator.md#signed-execution-payload-bid fn select_payload_bid( &self, - local_signed_bid: SignedExecutionPayloadBidGloas, + local_signed_bid: SignedExecutionPayloadBid, local_build: LocalBuildResult, builder_boost_factor: Option, ) -> ( - SignedExecutionPayloadBidGloas, + SignedExecutionPayloadBid, Option>, ) { let cached_bid = self.gossip_verified_payload_bid_cache.get_highest_bid( - local_signed_bid.message.slot, - local_signed_bid.message.parent_block_hash, - local_signed_bid.message.parent_block_root, + local_signed_bid.message().slot(), + local_signed_bid.message().parent_block_hash(), + local_signed_bid.message().parent_block_root(), ); select_payload_bid_pure( local_signed_bid, @@ -938,12 +957,12 @@ impl BeaconChain { /// /// `cached_bid.value` is in gwei (`u64`); `payload_value` is in wei (`Uint256`); compared in wei. pub(crate) fn select_payload_bid_pure( - local_signed_bid: SignedExecutionPayloadBidGloas, + local_signed_bid: SignedExecutionPayloadBid, local_build: LocalBuildResult, - cached_bid: Option>>, + cached_bid: Option>>, builder_boost_factor: Option, ) -> ( - SignedExecutionPayloadBidGloas, + SignedExecutionPayloadBid, Option>, ) { let LocalBuildResult { @@ -956,19 +975,19 @@ pub(crate) fn select_payload_bid_pure( return (local_signed_bid, Some(payload_data)); }; - let slot = local_signed_bid.message.slot; + let slot = local_signed_bid.message().slot(); if should_override_builder { debug!( %slot, - cached_bid_value = cached_bid.message.value, + cached_bid_value = cached_bid.message().value(), "Using local payload because EL signaled shouldOverrideBuilder" ); return (local_signed_bid, Some(payload_data)); } // Convert bid value (gwei) to wei for comparison with `payload_value` (wei). - let bid_value_wei = types::Uint256::from(cached_bid.message.value) + let bid_value_wei = types::Uint256::from(cached_bid.message().value()) .saturating_mul(types::Uint256::from(1_000_000_000u64)); let boosted_bid_wei = match builder_boost_factor { Some(factor) => { @@ -981,7 +1000,7 @@ pub(crate) fn select_payload_bid_pure( debug!( %slot, %payload_value, - cached_bid_value_gwei = cached_bid.message.value, + cached_bid_value_gwei = cached_bid.message().value(), ?builder_boost_factor, "Local payload is more profitable than cached builder bid" ); @@ -990,8 +1009,8 @@ pub(crate) fn select_payload_bid_pure( debug!( %slot, %payload_value, - cached_bid_value_gwei = cached_bid.message.value, - cached_bid_builder_index = cached_bid.message.builder_index, + cached_bid_value_gwei = cached_bid.message().value(), + cached_bid_builder_index = cached_bid.message().builder_index(), ?builder_boost_factor, "Including cached builder bid" ); @@ -1356,25 +1375,27 @@ mod tests { types::Uint256::from(n).saturating_mul(types::Uint256::from(1_000_000_000u64)) } - fn local_bid() -> SignedExecutionPayloadBidGloas { - SignedExecutionPayloadBidGloas { + fn local_bid() -> SignedExecutionPayloadBid { + SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas { message: ExecutionPayloadBidGloas { builder_index: BUILDER_INDEX_SELF_BUILD, ..Default::default() }, signature: Signature::empty(), - } + }) } - fn cached_bid(value_gwei: u64) -> Arc> { - Arc::new(SignedExecutionPayloadBidGloas { - message: ExecutionPayloadBidGloas { - builder_index: REMOTE_BUILDER, - value: value_gwei, - ..Default::default() + fn cached_bid(value_gwei: u64) -> Arc> { + Arc::new(SignedExecutionPayloadBid::Gloas( + SignedExecutionPayloadBidGloas { + message: ExecutionPayloadBidGloas { + builder_index: REMOTE_BUILDER, + value: value_gwei, + ..Default::default() + }, + signature: Signature::empty(), }, - signature: Signature::empty(), - }) + )) } fn local_build(payload_gwei: u64, should_override_builder: bool) -> LocalBuildResult { @@ -1410,7 +1431,7 @@ mod tests { let build = local_build(local_payload_gwei, should_override); let cache = cached_gwei.map(cached_bid); let (out, data) = select_payload_bid_pure::(local_bid(), build, cache, boost); - (out.message.builder_index, data.is_some()) + (out.message().builder_index(), data.is_some()) } #[test] diff --git a/beacon_node/beacon_chain/src/payload_bid_verification/gossip_verified_bid.rs b/beacon_node/beacon_chain/src/payload_bid_verification/gossip_verified_bid.rs index 80ffb72f26..0e66cc98df 100644 --- a/beacon_node/beacon_chain/src/payload_bid_verification/gossip_verified_bid.rs +++ b/beacon_node/beacon_chain/src/payload_bid_verification/gossip_verified_bid.rs @@ -13,51 +13,47 @@ use state_processing::signature_sets::{ }; use tracing::debug; use types::{ - BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidGloas, SignedExecutionPayloadBidGloas, - SignedExecutionPayloadBidRef, SignedProposerPreferences, Slot, + BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidRef, SignedExecutionPayloadBid, + SignedProposerPreferences, Slot, }; -/// Verify that an execution payload bid is consistent with the current chain state -/// and proposer preferences. pub(crate) fn verify_bid_consistency( - bid: &ExecutionPayloadBidGloas, + bid: ExecutionPayloadBidRef<'_, E>, current_slot: Slot, proposer_preferences: &SignedProposerPreferences, head_state: &BeaconState, spec: &ChainSpec, ) -> Result<(), PayloadBidError> { - let bid_slot = bid.slot; + let bid_slot = bid.slot(); if bid_slot != current_slot && bid_slot != current_slot.saturating_add(1u64) { return Err(PayloadBidError::InvalidBidSlot { bid_slot }); } - // Execution payments are used by off protocol builders. In protocol bids - // should always have this value set to zero. - if bid.execution_payment != 0 { + if bid.execution_payment() != 0 { return Err(PayloadBidError::ExecutionPaymentNonZero { - execution_payment: bid.execution_payment, + execution_payment: bid.execution_payment(), }); } - if bid.fee_recipient != proposer_preferences.message.fee_recipient { + if bid.fee_recipient() != proposer_preferences.message.fee_recipient { return Err(PayloadBidError::InvalidFeeRecipient); } - if bid.gas_limit != proposer_preferences.message.gas_limit { + if bid.gas_limit() != proposer_preferences.message.gas_limit { return Err(PayloadBidError::InvalidGasLimit); } let max_blobs_per_block = spec.max_blobs_per_block(bid_slot.epoch(E::slots_per_epoch())) as usize; - if bid.blob_kzg_commitments.len() > max_blobs_per_block { + if bid.blob_kzg_commitments().len() > max_blobs_per_block { return Err(PayloadBidError::InvalidBlobKzgCommitments { max_blobs_per_block, - blob_kzg_commitments_len: bid.blob_kzg_commitments.len(), + blob_kzg_commitments_len: bid.blob_kzg_commitments().len(), }); } - let builder_index = bid.builder_index; + let builder_index = bid.builder_index(); let is_active_builder = head_state .is_active_builder(builder_index, spec) @@ -67,10 +63,10 @@ pub(crate) fn verify_bid_consistency( return Err(PayloadBidError::InvalidBuilder { builder_index }); } - if !head_state.can_builder_cover_bid(builder_index, bid.value, spec)? { + if !head_state.can_builder_cover_bid(builder_index, bid.value(), spec)? { return Err(PayloadBidError::BuilderCantCoverBid { builder_index, - builder_bid: bid.value, + builder_bid: bid.value(), }); } @@ -85,47 +81,44 @@ pub struct GossipVerificationContext<'a, T: BeaconChainTypes> { pub spec: &'a ChainSpec, } -/// A wrapper around a `SignedExecutionPayloadBidGloas` that indicates it has been approved for re-gossiping on -/// the p2p network. #[derive(Educe)] #[educe( Debug(bound = "T: BeaconChainTypes"), Clone(bound = "T: BeaconChainTypes") )] pub struct GossipVerifiedPayloadBid { - pub signed_bid: Arc>, + pub signed_bid: Arc>, } impl GossipVerifiedPayloadBid { pub fn new( - signed_bid: Arc>, + signed_bid: Arc>, ctx: &GossipVerificationContext<'_, T>, ) -> Result { - let bid_slot = signed_bid.message.slot; - let bid_parent_block_hash = signed_bid.message.parent_block_hash; - let bid_parent_block_root = signed_bid.message.parent_block_root; - let bid_value = signed_bid.message.value; + let bid_msg = signed_bid.message(); + let bid_slot = bid_msg.slot(); + let bid_parent_block_hash = bid_msg.parent_block_hash(); + let bid_parent_block_root = bid_msg.parent_block_root(); + let bid_value = bid_msg.value(); if ctx .gossip_verified_payload_bid_cache - .seen_builder_index(&bid_slot, signed_bid.message.builder_index) + .seen_builder_index(&bid_slot, bid_msg.builder_index()) { return Err(PayloadBidError::BuilderAlreadySeen { - builder_index: signed_bid.message.builder_index, + builder_index: bid_msg.builder_index(), slot: bid_slot, }); } - // TODO(gloas): Extract into `bid_value_over_threshold` on the bid cache and potentially - // make this more sophisticate than just a <= check. if let Some(cached_bid) = ctx.gossip_verified_payload_bid_cache.get_highest_bid( bid_slot, bid_parent_block_hash, bid_parent_block_root, - ) && bid_value <= cached_bid.message.value + ) && bid_value <= cached_bid.message().value() { return Err(PayloadBidError::BidValueBelowCached { - cached_value: cached_bid.message.value, + cached_value: cached_bid.message().value(), incoming_value: bid_value, }); } @@ -146,14 +139,12 @@ impl GossipVerifiedPayloadBid { let fork_choice = ctx.canonical_head.fork_choice_read_lock(); - // TODO(gloas) reprocess bids whose parent_block_root becomes known & canonical after a reorg? if !fork_choice.contains_block(&bid_parent_block_root) { return Err(PayloadBidError::ParentBlockRootUnknown { parent_block_root: bid_parent_block_root, }); } - // TODO(gloas) reprocess bids whose parent_block_root becomes canonical after a reorg. let head_root = cached_head.head_block_root(); if !fork_choice.is_descendant(bid_parent_block_root, head_root) { return Err(PayloadBidError::ParentBlockRootNotCanonical { @@ -161,23 +152,20 @@ impl GossipVerifiedPayloadBid { }); } - // TODO(gloas) [IGNORE] bid.parent_block_hash is the block hash of a known execution payload in fork choice. - drop(fork_choice); verify_bid_consistency( - &signed_bid.message, + signed_bid.message(), current_slot, &proposer_preferences, head_state, ctx.spec, )?; - // Verify signature execution_payload_bid_signature_set( head_state, |i| get_builder_pubkey_from_state(head_state, i), - SignedExecutionPayloadBidRef::Gloas(&signed_bid), + signed_bid.to_ref(), ctx.spec, ) .map_err(|_| PayloadBidError::BadSignature)? @@ -199,7 +187,6 @@ impl GossipVerifiedPayloadBid { } impl BeaconChain { - /// Build a `GossipVerificationContext` from this `BeaconChain` for `GossipVerifiedPayloadBid`. pub fn payload_bid_gossip_verification_context(&self) -> GossipVerificationContext<'_, T> { GossipVerificationContext { canonical_head: &self.canonical_head, @@ -211,19 +198,14 @@ impl BeaconChain { } } - /// Returns `Ok(GossipVerifiedPayloadBid)` if the supplied `bid` should be forwarded onto the - /// gossip network and cached. - /// - /// ## Errors - /// - /// Returns an `Err` if the given bid was invalid, or an error was encountered during verification. pub fn verify_payload_bid_for_gossip( &self, - bid: Arc>, + bid: Arc>, ) -> Result, PayloadBidError> { - let slot = bid.message.slot; - let parent_block_root = bid.message.parent_block_root; - let parent_block_hash = bid.message.parent_block_hash; + let bid_msg = bid.message(); + let slot = bid_msg.slot(); + let parent_block_root = bid_msg.parent_block_root(); + let parent_block_hash = bid_msg.parent_block_hash(); let ctx = self.payload_bid_gossip_verification_context(); match GossipVerifiedPayloadBid::new(bid, &ctx) { @@ -269,8 +251,9 @@ mod tests { use kzg::KzgCommitment; use ssz_types::VariableList; use types::{ - Address, BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidGloas, MinimalEthSpec, - ProposerPreferences, SignedProposerPreferences, Slot, + Address, BeaconState, ChainSpec, EthSpec, ExecutionPayloadBidGloas, + ExecutionPayloadBidRef, MinimalEthSpec, ProposerPreferences, SignedProposerPreferences, + Slot, }; use super::verify_bid_consistency; @@ -312,7 +295,13 @@ mod tests { let bid = make_bid(Slot::new(5), Address::ZERO, 30_000_000); let prefs = make_preferences(Address::ZERO, 30_000_000); - let result = verify_bid_consistency::(&bid, current_slot, &prefs, &state, &spec); + let result = verify_bid_consistency::( + ExecutionPayloadBidRef::Gloas(&bid), + current_slot, + &prefs, + &state, + &spec, + ); assert!(matches!( result, Err(PayloadBidError::InvalidBidSlot { .. }) @@ -326,7 +315,13 @@ mod tests { let bid = make_bid(Slot::new(12), Address::ZERO, 30_000_000); let prefs = make_preferences(Address::ZERO, 30_000_000); - let result = verify_bid_consistency::(&bid, current_slot, &prefs, &state, &spec); + let result = verify_bid_consistency::( + ExecutionPayloadBidRef::Gloas(&bid), + current_slot, + &prefs, + &state, + &spec, + ); assert!(matches!( result, Err(PayloadBidError::InvalidBidSlot { .. }) @@ -341,7 +336,13 @@ mod tests { bid.execution_payment = 42; let prefs = make_preferences(Address::ZERO, 30_000_000); - let result = verify_bid_consistency::(&bid, current_slot, &prefs, &state, &spec); + let result = verify_bid_consistency::( + ExecutionPayloadBidRef::Gloas(&bid), + current_slot, + &prefs, + &state, + &spec, + ); assert!(matches!( result, Err(PayloadBidError::ExecutionPaymentNonZero { @@ -357,7 +358,13 @@ mod tests { let bid = make_bid(current_slot, Address::ZERO, 30_000_000); let prefs = make_preferences(Address::repeat_byte(0xaa), 30_000_000); - let result = verify_bid_consistency::(&bid, current_slot, &prefs, &state, &spec); + let result = verify_bid_consistency::( + ExecutionPayloadBidRef::Gloas(&bid), + current_slot, + &prefs, + &state, + &spec, + ); assert!(matches!(result, Err(PayloadBidError::InvalidFeeRecipient))); } @@ -374,7 +381,13 @@ mod tests { .collect(); bid.blob_kzg_commitments = VariableList::new(commitments).unwrap(); - let result = verify_bid_consistency::(&bid, current_slot, &prefs, &state, &spec); + let result = verify_bid_consistency::( + ExecutionPayloadBidRef::Gloas(&bid), + current_slot, + &prefs, + &state, + &spec, + ); assert!(matches!( result, Err(PayloadBidError::InvalidBlobKzgCommitments { .. }) @@ -388,7 +401,13 @@ mod tests { let bid = make_bid(current_slot, Address::ZERO, 30_000_000); let prefs = make_preferences(Address::ZERO, 50_000_000); - let result = verify_bid_consistency::(&bid, current_slot, &prefs, &state, &spec); + let result = verify_bid_consistency::( + ExecutionPayloadBidRef::Gloas(&bid), + current_slot, + &prefs, + &state, + &spec, + ); assert!(matches!(result, Err(PayloadBidError::InvalidGasLimit))); } } diff --git a/beacon_node/beacon_chain/src/payload_bid_verification/payload_bid_cache.rs b/beacon_node/beacon_chain/src/payload_bid_verification/payload_bid_cache.rs index bcf765dbf2..00b3ca15af 100644 --- a/beacon_node/beacon_chain/src/payload_bid_verification/payload_bid_cache.rs +++ b/beacon_node/beacon_chain/src/payload_bid_verification/payload_bid_cache.rs @@ -7,7 +7,7 @@ use crate::{ BeaconChainTypes, payload_bid_verification::gossip_verified_bid::GossipVerifiedPayloadBid, }; use parking_lot::RwLock; -use types::{BuilderIndex, ExecutionBlockHash, Hash256, SignedExecutionPayloadBidGloas, Slot}; +use types::{BuilderIndex, ExecutionBlockHash, Hash256, SignedExecutionPayloadBid, Slot}; type HighestBidMap = BTreeMap>>; @@ -27,38 +27,35 @@ impl Default for GossipVerifiedPayloadBidCache { } impl GossipVerifiedPayloadBidCache { - /// Get the cached bid for the tuple `(slot, parent_block_hash, parent_block_root)`. pub fn get_highest_bid( &self, slot: Slot, parent_block_hash: ExecutionBlockHash, parent_block_root: Hash256, - ) -> Option>> { + ) -> Option>> { self.highest_bid.read().get(&slot).and_then(|map| { map.get(&(parent_block_hash, parent_block_root)) .map(|b| b.signed_bid.clone()) }) } - /// Insert a bid for the tuple `(slot, parent_block_hash, parent_block_root)` only if - /// its value is higher than the currently cached bid for that tuple. pub fn insert_highest_bid(&self, bid: GossipVerifiedPayloadBid) { - let key = ( - bid.signed_bid.message.parent_block_hash, - bid.signed_bid.message.parent_block_root, - ); + let bid_msg = bid.signed_bid.message(); + let key = (bid_msg.parent_block_hash(), bid_msg.parent_block_root()); + let slot = bid_msg.slot(); + let value = bid_msg.value(); + let mut highest_bid = self.highest_bid.write(); - let slot_map = highest_bid.entry(bid.signed_bid.message.slot).or_default(); + let slot_map = highest_bid.entry(slot).or_default(); if let Some(existing) = slot_map.get(&key) - && existing.signed_bid.message.value >= bid.signed_bid.message.value + && existing.signed_bid.message().value() >= value { return; } slot_map.insert(key, bid); } - /// A gossip verified bid for `BuilderIndex` already exists at `slot` pub fn seen_builder_index(&self, slot: &Slot, builder_index: BuilderIndex) -> bool { self.seen_builder .read() @@ -66,16 +63,15 @@ impl GossipVerifiedPayloadBidCache { .is_some_and(|seen_builders| seen_builders.contains(&builder_index)) } - /// Insert a builder into the seen cache. pub fn insert_seen_builder(&self, bid: &GossipVerifiedPayloadBid) { + let bid_msg = bid.signed_bid.message(); let mut seen_builder = self.seen_builder.write(); seen_builder - .entry(bid.signed_bid.message.slot) + .entry(bid_msg.slot()) .or_default() - .insert(bid.signed_bid.message.builder_index); + .insert(bid_msg.builder_index()); } - /// Prune anything before `current_slot` pub fn prune(&self, current_slot: Slot) { self.highest_bid .write() @@ -94,7 +90,7 @@ mod tests { use bls::Signature; use types::{ ExecutionBlockHash, ExecutionPayloadBidGloas, Hash256, MinimalEthSpec, - SignedExecutionPayloadBidGloas, Slot, + SignedExecutionPayloadBid, Slot, }; use super::GossipVerifiedPayloadBidCache; @@ -114,17 +110,19 @@ mod tests { value: u64, ) -> GossipVerifiedPayloadBid { GossipVerifiedPayloadBid { - signed_bid: Arc::new(SignedExecutionPayloadBidGloas { - message: ExecutionPayloadBidGloas { - slot, - builder_index, - parent_block_hash, - parent_block_root, - value, - ..ExecutionPayloadBidGloas::default() + signed_bid: Arc::new(SignedExecutionPayloadBid::Gloas( + types::SignedExecutionPayloadBidGloas { + message: ExecutionPayloadBidGloas { + slot, + builder_index, + parent_block_hash, + parent_block_root, + value, + ..ExecutionPayloadBidGloas::default() + }, + signature: Signature::empty(), }, - signature: Signature::empty(), - }), + )), } } @@ -142,12 +140,10 @@ mod tests { cache.prune(Slot::new(8)); - // Slots 1-7 pruned from both maps. for slot in [1, 2, 3, 7] { assert!(cache.get_highest_bid(Slot::new(slot), hash, root).is_none()); assert!(!cache.seen_builder_index(&Slot::new(slot), slot)); } - // Slots 8-10 retained in both maps. for slot in [8, 9, 10] { assert!(cache.get_highest_bid(Slot::new(slot), hash, root).is_some()); assert!(cache.seen_builder_index(&Slot::new(slot), slot)); diff --git a/beacon_node/beacon_chain/src/payload_bid_verification/tests.rs b/beacon_node/beacon_chain/src/payload_bid_verification/tests.rs index 2d1fefa2c3..ccc6f0cf7c 100644 --- a/beacon_node/beacon_chain/src/payload_bid_verification/tests.rs +++ b/beacon_node/beacon_chain/src/payload_bid_verification/tests.rs @@ -15,7 +15,8 @@ use store::{HotColdDB, StoreConfig}; use types::{ Address, ChainSpec, Checkpoint, Domain, Epoch, EthSpec, ExecutionBlockHash, ExecutionPayloadBidGloas, Hash256, MinimalEthSpec, ProposerPreferences, SignedBeaconBlock, - SignedExecutionPayloadBidGloas, SignedProposerPreferences, SignedRoot, Slot, + SignedExecutionPayloadBid, SignedExecutionPayloadBidGloas, SignedProposerPreferences, + SignedRoot, Slot, }; use proto_array::{Block as ProtoBlock, ExecutionStatus, PayloadStatus}; @@ -154,7 +155,7 @@ impl TestContext { } } - fn sign_bid(&self, bid: ExecutionPayloadBidGloas) -> Arc> { + fn sign_bid(&self, bid: ExecutionPayloadBidGloas) -> Arc> { let head = self.canonical_head.cached_head(); let state = &head.snapshot.beacon_state; let domain = self.spec.get_domain( @@ -165,10 +166,10 @@ impl TestContext { ); let message = bid.signing_root(domain); let signature = self.keypairs[bid.builder_index as usize].sk.sign(message); - Arc::new(SignedExecutionPayloadBidGloas { + Arc::new(SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas { message: bid, signature, - }) + })) } fn gossip_ctx(&self) -> GossipVerificationContext<'_, T> { @@ -229,19 +230,21 @@ fn make_signed_bid( gas_limit: u64, value: u64, parent_block_root: Hash256, -) -> Arc> { - Arc::new(SignedExecutionPayloadBidGloas { - message: ExecutionPayloadBidGloas { - slot, - builder_index, - fee_recipient, - gas_limit, - value, - parent_block_root, - ..ExecutionPayloadBidGloas::default() +) -> Arc> { + Arc::new(SignedExecutionPayloadBid::Gloas( + SignedExecutionPayloadBidGloas { + message: ExecutionPayloadBidGloas { + slot, + builder_index, + fee_recipient, + gas_limit, + value, + parent_block_root, + ..ExecutionPayloadBidGloas::default() + }, + signature: Signature::empty(), }, - signature: Signature::empty(), - }) + )) } fn make_signed_preferences( @@ -420,7 +423,7 @@ fn execution_payment_nonzero() { let slot = Slot::new(0); seed_preferences(&ctx, slot, Address::ZERO, 30_000_000); - let bid = Arc::new(SignedExecutionPayloadBidGloas { + let bid = Arc::new(SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas { message: ExecutionPayloadBidGloas { slot, gas_limit: 30_000_000, @@ -429,7 +432,7 @@ fn execution_payment_nonzero() { ..ExecutionPayloadBidGloas::default() }, signature: Signature::empty(), - }); + })); let result = GossipVerifiedPayloadBid::new(bid, &gossip); assert!(matches!( result, @@ -576,7 +579,7 @@ fn invalid_blob_kzg_commitments() { .map(|_| KzgCommitment::empty_for_testing()) .collect(); - let bid = Arc::new(SignedExecutionPayloadBidGloas { + let bid = Arc::new(SignedExecutionPayloadBid::Gloas(SignedExecutionPayloadBidGloas { message: ExecutionPayloadBidGloas { slot, builder_index: 0, @@ -588,7 +591,7 @@ fn invalid_blob_kzg_commitments() { ..ExecutionPayloadBidGloas::default() }, signature: Signature::empty(), - }); + })); let result = GossipVerifiedPayloadBid::new(bid, &gossip); assert!(matches!( result, @@ -703,8 +706,8 @@ fn two_builders_coexist_in_cache() { .bid_cache .get_highest_bid(slot, ExecutionBlockHash::zero(), ctx.genesis_block_root) .expect("should have highest bid"); - assert_eq!(highest.message.value, 1); - assert_eq!(highest.message.builder_index, 1); + assert_eq!(highest.message().value(), 1); + assert_eq!(highest.message().builder_index(), 1); } #[test] 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 f74ff50b86..2f77319a1e 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs @@ -97,11 +97,11 @@ impl BeaconChain { // 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 { - if chain_ref + 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 @@ -129,7 +129,6 @@ impl BeaconChain { ); } } - } } match executed_envelope { diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index 03dfb2c4f4..257b16de96 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -15,7 +15,8 @@ use types::{ SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBeaconBlockHeze, - SignedBlsToExecutionChange, SignedContributionAndProof, SignedExecutionPayloadBidGloas, + SignedBlsToExecutionChange, SignedContributionAndProof, SignedExecutionPayloadBid, + SignedExecutionPayloadBidGloas, SignedExecutionPayloadBidHeze, SignedExecutionPayloadEnvelope, SignedInclusionList, SignedProposerPreferences, SignedVoluntaryExit, SingleAttestation, SubnetId, SyncCommitteeMessage, SyncSubnetId, }; @@ -49,7 +50,7 @@ pub enum PubsubMessage { /// Gossipsub message providing notification of a payload attestation message. PayloadAttestation(Box), /// Gossipsub message providing notification of a signed execution payload bid. - ExecutionPayloadBid(Box>), + ExecutionPayloadBid(Box>), /// Gossipsub message providing notification of signed proposer preferences. ProposerPreferences(Box), /// Gossipsub message providing notification of a light client finality update. @@ -379,9 +380,28 @@ impl PubsubMessage { ))) } GossipKind::ExecutionPayloadBid => { - let execution_payload_bid = - SignedExecutionPayloadBidGloas::from_ssz_bytes(data) - .map_err(|e| format!("{:?}", e))?; + let execution_payload_bid = match fork_context + .get_fork_from_context_bytes(gossip_topic.fork_digest) + { + Some(fork_name) if fork_name.heze_enabled() => { + SignedExecutionPayloadBid::Heze( + SignedExecutionPayloadBidHeze::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?, + ) + } + Some(fork_name) if fork_name.gloas_enabled() => { + SignedExecutionPayloadBid::Gloas( + SignedExecutionPayloadBidGloas::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?, + ) + } + _ => { + return Err(format!( + "execution_payload_bid topic invalid for given fork digest {:?}", + gossip_topic.fork_digest + )); + } + }; Ok(PubsubMessage::ExecutionPayloadBid(Box::new( execution_payload_bid, ))) @@ -596,7 +616,7 @@ impl std::fmt::Display for PubsubMessage { write!( f, "Execution payload bid: slot: {:?} value: {:?}", - data.message.slot, data.message.value + data.message().slot(), data.message().value() ) } PubsubMessage::ProposerPreferences(data) => { 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 616f300221..654c5813a8 100644 --- a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs @@ -58,7 +58,7 @@ use types::{ LightClientFinalityUpdate, LightClientOptimisticUpdate, PartialDataColumn, PartialDataColumnHeader, PayloadAttestationMessage, ProposerSlashing, SignedAggregateAndProof, SignedBeaconBlock, SignedBlsToExecutionChange, SignedContributionAndProof, - SignedExecutionPayloadBidGloas, SignedExecutionPayloadEnvelope, SignedInclusionList, + SignedExecutionPayloadBid, SignedExecutionPayloadEnvelope, SignedInclusionList, SignedProposerPreferences, SignedVoluntaryExit, SingleAttestation, Slot, SubnetId, SyncCommitteeMessage, SyncSubnetId, block::BlockImportSource, }; @@ -4073,13 +4073,13 @@ impl NetworkBeaconProcessor { parent = None, level = "debug", skip_all, - fields(parent_block_hash = ?bid.message.parent_block_hash, parent_block_root = ?bid.message.parent_block_root), + fields(parent_block_hash = ?bid.message().parent_block_hash(), parent_block_root = ?bid.message().parent_block_root()), )] pub fn process_gossip_execution_payload_bid( self: &Arc, message_id: MessageId, peer_id: PeerId, - bid: Arc>, + bid: Arc>, ) { let verification_result = self.chain.verify_payload_bid_for_gossip(bid.clone()); diff --git a/beacon_node/network/src/network_beacon_processor/mod.rs b/beacon_node/network/src/network_beacon_processor/mod.rs index f0d5d9f9bc..3c6f60b83c 100644 --- a/beacon_node/network/src/network_beacon_processor/mod.rs +++ b/beacon_node/network/src/network_beacon_processor/mod.rs @@ -506,7 +506,7 @@ impl NetworkBeaconProcessor { self: &Arc, message_id: MessageId, peer_id: PeerId, - execution_payload_bid: Box>, + execution_payload_bid: Box>, ) -> Result<(), Error> { let processor = self.clone(); let process_fn = move || { diff --git a/common/eth2/src/types.rs b/common/eth2/src/types.rs index bce603c96e..a588788eab 100644 --- a/common/eth2/src/types.rs +++ b/common/eth2/src/types.rs @@ -1180,7 +1180,7 @@ pub struct SseExtendedPayloadAttributesGeneric { pub type SseExtendedPayloadAttributes = SseExtendedPayloadAttributesGeneric; pub type VersionedSsePayloadAttributes = ForkVersionedResponse; pub type VersionedSseExecutionPayloadBid = - ForkVersionedResponse>; + ForkVersionedResponse>; pub type VersionedSsePayloadAttestationMessage = ForkVersionedResponse; impl<'de> ContextDeserialize<'de, ForkName> for SsePayloadAttributes { diff --git a/consensus/proto_array/src/proto_array.rs b/consensus/proto_array/src/proto_array.rs index b19b2071a2..4dc1232bc8 100644 --- a/consensus/proto_array/src/proto_array.rs +++ b/consensus/proto_array/src/proto_array.rs @@ -12,7 +12,6 @@ use ssz_derive::{Decode, Encode}; use std::collections::{HashMap, HashSet}; use std::time::Duration; use superstruct::superstruct; -use tracing::info; use typenum::U512; use types::{ AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256, diff --git a/consensus/types/src/execution/signed_execution_payload_bid.rs b/consensus/types/src/execution/signed_execution_payload_bid.rs index 49e04ca01b..fe9b03d7ed 100644 --- a/consensus/types/src/execution/signed_execution_payload_bid.rs +++ b/consensus/types/src/execution/signed_execution_payload_bid.rs @@ -3,9 +3,9 @@ use crate::state::BeaconStateError; use crate::test_utils::TestRandom; use crate::{EthSpec, ForkName}; use bls::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_derive::{Decode, Encode}; use superstruct::superstruct; use test_random_derive::TestRandom; @@ -111,6 +111,32 @@ impl SignedExecutionPayloadBidHeze { } } +impl<'de, E: EthSpec> ContextDeserialize<'de, ForkName> for SignedExecutionPayloadBid { + fn context_deserialize(deserializer: D, context: ForkName) -> Result + where + D: Deserializer<'de>, + { + let convert_err = |e| { + serde::de::Error::custom(format!( + "SignedExecutionPayloadBid 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!( + "SignedExecutionPayloadBid failed to deserialize: unsupported fork '{}'", + context + ))), + } + } +} + #[cfg(test)] mod tests { use super::*;