From 6323cd3827b596080fa43add5b09a7adc91fd58e Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Sun, 26 Apr 2026 01:51:02 +0200 Subject: [PATCH 01/12] Fix builder exit signature batch verification logic and small refactor (#9173) We had a bug when performing batch builder exit signature verification. The EF spec tests cover this case, but the EF tests only calls individual signature verification (which is a separate code path). This PR unifies the two code paths. We should probably spend some time reviewing EF test code coverage and make sure we don't have separate code paths that do similar things. Co-Authored-By: Eitan Seri-Levi --- .../process_operations.rs | 27 +++++++++---------- .../per_block_processing/signature_sets.rs | 18 ++++++++++--- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index f1de284fc8..422e0afe06 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -8,6 +8,7 @@ use crate::per_block_processing::builder::{ convert_validator_index_to_builder_index, is_builder_index, }; use crate::per_block_processing::errors::{BlockProcessingError, ExitInvalid, IntoWithIndex}; +use crate::per_block_processing::signature_sets::{exit_signature_set, get_pubkey_from_state}; use crate::per_block_processing::verify_payload_attestation::verify_payload_attestation; use bls::{PublicKeyBytes, SignatureBytes}; use ssz_types::FixedVector; @@ -547,7 +548,8 @@ fn process_builder_voluntary_exit( let builder_index = convert_validator_index_to_builder_index(signed_exit.message.validator_index); - let builder = state + // Verify builder is known + state .builders()? .get(builder_index as usize) .cloned() @@ -570,22 +572,17 @@ fn process_builder_voluntary_exit( )); } - // Verify signature (using EIP-7044 domain: capella_fork_version for Deneb+) if verify_signatures.is_true() { - let pubkey = builder.pubkey; - let domain = spec.compute_domain( - Domain::VoluntaryExit, - spec.capella_fork_version, - state.genesis_validators_root(), + verify!( + exit_signature_set( + state, + |i| get_pubkey_from_state(state, i), + signed_exit, + spec + )? + .verify(), + ExitInvalid::BadSignature ); - let message = signed_exit.message.signing_root(domain); - // TODO(gloas): use builder pubkey cache once available - let bls_pubkey = pubkey - .decompress() - .map_err(|_| BlockOperationError::invalid(ExitInvalid::BadSignature))?; - if !signed_exit.signature.verify(&bls_pubkey, message) { - return Err(BlockOperationError::invalid(ExitInvalid::BadSignature)); - } } // Initiate builder exit diff --git a/consensus/state_processing/src/per_block_processing/signature_sets.rs b/consensus/state_processing/src/per_block_processing/signature_sets.rs index 5c1767f227..0686c4d605 100644 --- a/consensus/state_processing/src/per_block_processing/signature_sets.rs +++ b/consensus/state_processing/src/per_block_processing/signature_sets.rs @@ -2,6 +2,7 @@ //! validated individually, or alongside in others in a potentially cheaper bulk operation. //! //! This module exposes one function to extract each type of `SignatureSet` from a `BeaconBlock`. +use super::builder::{convert_validator_index_to_builder_index, is_builder_index}; use bls::{AggregateSignature, PublicKey, PublicKeyBytes, Signature, SignatureSet}; use ssz::DecodeError; use std::borrow::Cow; @@ -503,7 +504,7 @@ pub fn deposit_pubkey_signature_message( } /// Returns a signature set that is valid if the `SignedVoluntaryExit` was signed by the indicated -/// validator. +/// validator (or builder, in the case of a builder exit). pub fn exit_signature_set<'a, E, F>( state: &'a BeaconState, get_pubkey: F, @@ -515,7 +516,18 @@ where F: Fn(usize) -> Option>, { let exit = &signed_exit.message; - let proposer_index = exit.validator_index as usize; + let validator_index = exit.validator_index; + + let is_builder_exit = + state.fork_name_unchecked().gloas_enabled() && is_builder_index(validator_index); + + let pubkey = if is_builder_exit { + let builder_index = convert_validator_index_to_builder_index(validator_index); + get_builder_pubkey_from_state(state, builder_index) + .ok_or(Error::ValidatorUnknown(validator_index))? + } else { + get_pubkey(validator_index as usize).ok_or(Error::ValidatorUnknown(validator_index))? + }; let domain = if state.fork_name_unchecked().deneb_enabled() { // EIP-7044 @@ -537,7 +549,7 @@ where Ok(SignatureSet::single_pubkey( &signed_exit.signature, - get_pubkey(proposer_index).ok_or(Error::ValidatorUnknown(proposer_index as u64))?, + pubkey, message, )) } From 276c4d5ff353fe93db306668fca7f8639a1e2ab1 Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Sun, 26 Apr 2026 15:40:22 +0200 Subject: [PATCH 02/12] Gloas set `AttestationData.index` (#9100) For gloas `attestation.data.index` should be set to 1 if we are attesting to a block whose slot is not the attestation duty slot and slot payload_status is `FULL` Co-Authored-By: Eitan Seri- Levi Co-Authored-By: Eitan Seri-Levi Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> --- beacon_node/beacon_chain/src/beacon_chain.rs | 26 +++ .../beacon_chain/src/early_attester_cache.rs | 13 ++ beacon_node/beacon_chain/src/test_utils.rs | 2 + .../tests/attestation_production.rs | 179 +++++++++++++++--- .../types/src/attestation/attestation.rs | 11 +- .../src/attestation_service.rs | 1 + 6 files changed, 209 insertions(+), 23 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 98dc9cd7fd..b556e6d849 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -1956,6 +1956,7 @@ impl BeaconChain { let beacon_block_root; let beacon_state_root; let target; + let is_same_slot_attestation; let current_epoch_attesting_info: Option<(Checkpoint, usize)>; let head_timer = metrics::start_timer(&metrics::ATTESTATION_PRODUCTION_HEAD_SCRAPE_SECONDS); let head_span = debug_span!("attestation_production_head_scrape").entered(); @@ -1996,11 +1997,20 @@ impl BeaconChain { // When attesting to the head slot or later, always use the head of the chain. beacon_block_root = head.beacon_block_root; beacon_state_root = head.beacon_state_root(); + is_same_slot_attestation = request_slot == head.beacon_block.slot(); } else { // Permit attesting to slots *prior* to the current head. This is desirable when // the VC and BN are out-of-sync due to time issues or overloading. beacon_block_root = *head_state.get_block_root(request_slot)?; beacon_state_root = *head_state.get_state_root(request_slot)?; + + // Fetch the previous block root. If the previous block root equals + // the block root being attested to, the `request_slot` is a skipped slot + // and this is not a same slot attestation. + let prior_slot_root = head_state + .get_block_root(request_slot.saturating_sub(1u64)) + .ok(); + is_same_slot_attestation = prior_slot_root != Some(&beacon_block_root); }; let target_slot = request_epoch.start_slot(T::EthSpec::slots_per_epoch()); @@ -2090,6 +2100,21 @@ impl BeaconChain { ) }; + // For gloas the attestation data index indicates payload presence: + // `payload_present=false` for same-slot attestations or when payload not received. + // `payload_present=true` when attesting to a prior slot whose payload has been received. + let payload_present = if self + .spec + .fork_name_at_slot::(request_slot) + .gloas_enabled() + && !is_same_slot_attestation + { + self.canonical_head + .block_has_canonical_payload(&beacon_block_root, &self.spec)? + } else { + false + }; + Ok(Attestation::::empty_for_signing( request_index, committee_len, @@ -2097,6 +2122,7 @@ impl BeaconChain { beacon_block_root, justified_checkpoint, target, + payload_present, &self.spec, )?) } diff --git a/beacon_node/beacon_chain/src/early_attester_cache.rs b/beacon_node/beacon_chain/src/early_attester_cache.rs index 752e4d1a96..e3a83f9374 100644 --- a/beacon_node/beacon_chain/src/early_attester_cache.rs +++ b/beacon_node/beacon_chain/src/early_attester_cache.rs @@ -165,6 +165,12 @@ impl EarlyAttesterCache { /// - There is a cache `item` present. /// - If `request_slot` is in the same epoch as `item.epoch`. /// - If `request_index` does not exceed `item.committee_count`. + /// + /// Post gloas an additional condition must be met: + /// - `request_slot` is the same slot as `item.block.slot` (i.e. a same slot attestation). + /// + /// Non-same-slot Gloas attestations need `data.index` set from the canonical payload + /// status, which the cache doesn't track. Returning `None` falls through to fork choice. #[instrument(skip_all, fields(%request_slot, %request_index), level = "debug")] pub fn try_attest( &self, @@ -197,6 +203,12 @@ impl EarlyAttesterCache { item.committee_lengths .get_committee_length::(request_slot, request_index, spec)?; + let is_same_slot_attestation = request_slot == item.block.slot(); + if spec.fork_name_at_slot::(request_slot).gloas_enabled() && !is_same_slot_attestation { + return Ok(None); + } + let payload_present = false; + let attestation = Attestation::empty_for_signing( request_index, committee_len, @@ -204,6 +216,7 @@ impl EarlyAttesterCache { item.beacon_block_root, item.source, item.target, + payload_present, spec, ) .map_err(Error::AttestationError)?; diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index b657f81b1f..274f41d1cb 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -1451,6 +1451,7 @@ where epoch, root: target_root, }, + false, &self.spec, )?; @@ -1560,6 +1561,7 @@ where epoch, root: target_root, }, + false, &self.spec, )?) } diff --git a/beacon_node/beacon_chain/tests/attestation_production.rs b/beacon_node/beacon_chain/tests/attestation_production.rs index a3ab959d12..1b87fc041a 100644 --- a/beacon_node/beacon_chain/tests/attestation_production.rs +++ b/beacon_node/beacon_chain/tests/attestation_production.rs @@ -2,7 +2,9 @@ use beacon_chain::attestation_simulator::produce_unaggregated_attestation; use beacon_chain::custody_context::NodeCustodyType; -use beacon_chain::test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy}; +use beacon_chain::test_utils::{ + AttestationStrategy, BeaconChainHarness, BlockStrategy, fork_name_from_env, +}; use beacon_chain::validator_monitor::UNAGGREGATED_ATTESTATION_LAG_SLOTS; use beacon_chain::{StateSkipConfig, WhenSlotSkipped, metrics}; use bls::{AggregateSignature, Keypair}; @@ -206,7 +208,15 @@ async fn produces_attestations() { &AggregateSignature::infinity(), "bad signature" ); - assert_eq!(data.index, index, "bad index"); + if harness + .spec + .fork_name_at_slot::(data.slot) + .gloas_enabled() + { + assert!(data.index <= 1, "invalid index"); + } else { + assert_eq!(data.index, index, "bad index"); + } assert_eq!(data.slot, slot, "bad slot"); assert_eq!(data.beacon_block_root, block_root, "bad block root"); assert_eq!( @@ -226,27 +236,35 @@ async fn produces_attestations() { .build_range_sync_block_from_store_blobs(Some(block_root), Arc::new(block.clone())); let available_block = range_sync_block.into_available_block(); - let early_attestation = { - let proto_block = chain - .canonical_head - .fork_choice_read_lock() - .get_block(&block_root) - .unwrap(); - chain - .early_attester_cache - .add_head_block(block_root, &available_block, proto_block, &state) - .unwrap(); - chain - .early_attester_cache - .try_attest(slot, index, &chain.spec) - .unwrap() - .unwrap() - }; + // For Gloas non-same-slot attestations, the early attester cache returns None. + let is_same_slot_attestation = slot == block_slot; + let is_gloas = harness + .spec + .fork_name_at_slot::(slot) + .gloas_enabled(); + if !is_gloas || is_same_slot_attestation { + let early_attestation = { + let proto_block = chain + .canonical_head + .fork_choice_read_lock() + .get_block(&block_root) + .unwrap(); + chain + .early_attester_cache + .add_head_block(block_root, &available_block, proto_block, &state) + .unwrap(); + chain + .early_attester_cache + .try_attest(slot, index, &chain.spec) + .unwrap() + .unwrap() + }; - assert_eq!( - attestation, early_attestation, - "early attester cache inconsistent" - ); + assert_eq!( + attestation, early_attestation, + "early attester cache inconsistent" + ); + } } } } @@ -313,3 +331,120 @@ async fn early_attester_cache_old_request() { .unwrap(); assert_eq!(attested_block.slot(), attest_slot); } + +/// Verify that `produce_unaggregated_attestation` sets `data.index = 1` (payload_present) +/// when a gloas validator attests to a prior slot whose block+envelope have been received. +/// +/// Setup: build a chain at gloas genesis, produce a block with envelope at slot N, +/// then advance the clock to slot N+1 without producing a block (skipped slot). +/// Attesting at slot N+1 should target the block at slot N with payload_present = true. +#[tokio::test] +async fn gloas_attestation_index_payload_present() { + if fork_name_from_env().is_some_and(|f| !f.gloas_enabled()) { + return; + } + + let harness = BeaconChainHarness::builder(MainnetEthSpec) + .default_spec() + .keypairs(KEYPAIRS[..].to_vec()) + .fresh_ephemeral_store() + .mock_execution_layer() + .build(); + + let chain = &harness.chain; + + // Build a few blocks so the chain is established (slots 1..=3). + harness.advance_slot(); + harness + .extend_chain( + 3, + BlockStrategy::OnCanonicalHead, + AttestationStrategy::AllValidators, + ) + .await; + + let head = chain.head_snapshot(); + assert_eq!(head.beacon_block.slot(), Slot::new(3)); + + // Advance clock to slot 4 without producing a block (skipped slot). + harness.advance_slot(); + let attest_slot = chain.slot().unwrap(); + assert_eq!(attest_slot, Slot::new(4)); + + // Attest at slot 4 — this should target the block at slot 3 whose payload was received. + let attestation = chain + .produce_unaggregated_attestation(attest_slot, 0) + .expect("should produce attestation"); + + assert_eq!(attestation.data().slot, attest_slot); + assert_eq!( + attestation.data().index, + 1, + "gloas attestation to prior slot with payload should have index=1 (payload_present)" + ); +} + +/// Verify that `produce_unaggregated_attestation` sets `data.index = 0` (payload NOT present) +/// when a gloas validator attests to a prior slot whose block was imported but whose +/// payload envelope was never received. +/// +/// Setup: build a chain at gloas genesis through slot 2, then at slot 3 import only the +/// beacon block (no envelope), advance to slot 4 (skipped), and attest. +#[tokio::test] +async fn gloas_attestation_index_payload_absent() { + if fork_name_from_env().is_some_and(|f| !f.gloas_enabled()) { + return; + } + + let harness = BeaconChainHarness::builder(MainnetEthSpec) + .default_spec() + .keypairs(KEYPAIRS[..].to_vec()) + .fresh_ephemeral_store() + .mock_execution_layer() + .build(); + + let chain = &harness.chain; + + // Build slots 1..=2 normally (with envelopes). + harness.advance_slot(); + harness + .extend_chain( + 2, + BlockStrategy::OnCanonicalHead, + AttestationStrategy::AllValidators, + ) + .await; + + assert_eq!(chain.head_snapshot().beacon_block.slot(), Slot::new(2)); + + // Slot 3: produce and import the beacon block but do NOT process the envelope. + harness.advance_slot(); + let state = harness.get_current_state(); + let (block_contents, _envelope, _new_state) = + harness.make_block_with_envelope(state, Slot::new(3)).await; + + let block_root = block_contents.0.canonical_root(); + harness + .process_block(Slot::new(3), block_root, block_contents) + .await + .expect("block should import without envelope"); + + assert_eq!(chain.head_snapshot().beacon_block.slot(), Slot::new(3)); + + // Advance clock to slot 4 without producing a block (skipped slot). + harness.advance_slot(); + let attest_slot = chain.slot().unwrap(); + assert_eq!(attest_slot, Slot::new(4)); + + // Attest at slot 4 — targets slot 3 whose payload was NOT received. + let attestation = chain + .produce_unaggregated_attestation(attest_slot, 0) + .expect("should produce attestation"); + + assert_eq!(attestation.data().slot, attest_slot); + assert_eq!( + attestation.data().index, + 0, + "gloas attestation to prior slot without payload should have index=0 (payload_absent)" + ); +} diff --git a/consensus/types/src/attestation/attestation.rs b/consensus/types/src/attestation/attestation.rs index 693b5889f5..28059efee6 100644 --- a/consensus/types/src/attestation/attestation.rs +++ b/consensus/types/src/attestation/attestation.rs @@ -102,6 +102,7 @@ impl Hash for Attestation { impl Attestation { /// Produces an attestation with empty signature. + #[allow(clippy::too_many_arguments)] pub fn empty_for_signing( committee_index: u64, committee_length: usize, @@ -109,6 +110,7 @@ impl Attestation { beacon_block_root: Hash256, source: Checkpoint, target: Checkpoint, + payload_present: bool, spec: &ChainSpec, ) -> Result { if spec.fork_name_at_slot::(slot).electra_enabled() { @@ -116,12 +118,19 @@ impl Attestation { committee_bits .set(committee_index as usize, true) .map_err(|_| Error::InvalidCommitteeIndex)?; + // Gloas attestation data index now indicates payload presence. + // Pre-gloas index is always 0. + let index = if spec.fork_name_at_slot::(slot).gloas_enabled() && payload_present { + 1u64 + } else { + 0u64 + }; Ok(Attestation::Electra(AttestationElectra { aggregation_bits: BitList::with_capacity(committee_length) .map_err(|_| Error::InvalidCommitteeLength)?, data: AttestationData { slot, - index: 0u64, + index, beacon_block_root, source, target, diff --git a/validator_client/validator_services/src/attestation_service.rs b/validator_client/validator_services/src/attestation_service.rs index dc5fc27a4f..3ffe602892 100644 --- a/validator_client/validator_services/src/attestation_service.rs +++ b/validator_client/validator_services/src/attestation_service.rs @@ -546,6 +546,7 @@ impl AttestationService attestation, From fae7941b2d13dc9cd1ba8282aefe2798a70c7c74 Mon Sep 17 00:00:00 2001 From: Shane K Moore <41407272+shane-moore@users.noreply.github.com> Date: Sun, 26 Apr 2026 08:25:00 -0700 Subject: [PATCH 03/12] Gloas ptc duties beacon node response (#8415) Co-Authored-By: shane-moore Co-Authored-By: Eitan Seri-Levi Co-Authored-By: Eitan Seri-Levi Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> --- beacon_node/beacon_chain/src/beacon_chain.rs | 44 ++++- beacon_node/http_api/src/lib.rs | 10 + beacon_node/http_api/src/ptc_duties.rs | 182 +++++++++++++++++++ beacon_node/http_api/src/validator/mod.rs | 38 +++- beacon_node/http_api/tests/tests.rs | 120 +++++++++++- consensus/types/src/state/beacon_state.rs | 21 +++ 6 files changed, 411 insertions(+), 4 deletions(-) create mode 100644 beacon_node/http_api/src/ptc_duties.rs diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index b556e6d849..bfe1b404e0 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -84,8 +84,8 @@ use crate::{ use bls::{PublicKey, PublicKeyBytes, Signature}; use eth2::beacon_response::ForkVersionedResponse; use eth2::types::{ - EventKind, SseBlobSidecar, SseBlock, SseDataColumnSidecar, SseExtendedPayloadAttributes, - SseHead, + EventKind, PtcDuty, SseBlobSidecar, SseBlock, SseDataColumnSidecar, + SseExtendedPayloadAttributes, SseHead, }; use execution_layer::{ BlockProposalContents, BlockProposalContentsType, BuilderParams, ChainHealth, ExecutionLayer, @@ -1719,6 +1719,46 @@ impl BeaconChain { Ok((duties, dependent_root, execution_status)) } + /// Get PTC duties for validators at a given epoch. + /// + /// TODO(gloas): per-validator `get_ptc_assignment` makes this O(N * slots_per_epoch * PTCSize). + /// A future ptc cache (or a single-pass `ptc_window` walk) can drop this to + /// O(slots_per_epoch * PTCSize + N). + pub fn compute_ptc_duties( + &self, + state: &BeaconState, + epoch: Epoch, + validator_indices: &[u64], + dependent_block_root: Hash256, + ) -> Result<(Vec>, Hash256), Error> { + // The ptc_window only covers previous, current, and next epochs. + let relative_epoch = RelativeEpoch::from_epoch(state.current_epoch(), epoch) + .map_err(Error::IncorrectStateForAttestation)?; + + let dependent_root = + state.attester_shuffling_decision_root(dependent_block_root, relative_epoch)?; + + let pubkey_cache = self.validator_pubkey_cache.read(); + + let duties = validator_indices + .iter() + .map(|&validator_index| -> Result, Error> { + let Some(&pubkey) = pubkey_cache.get_pubkey_bytes(validator_index as usize) else { + return Ok(None); + }; + let slot_opt = + state.get_ptc_assignment(validator_index as usize, epoch, &self.spec)?; + Ok(slot_opt.map(|slot| PtcDuty { + validator_index, + slot, + pubkey, + })) + }) + .collect::, _>>()?; + + Ok((duties, dependent_root)) + } + pub fn get_aggregated_attestation( &self, attestation: AttestationRef, diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 0be631c057..bd80dd1e82 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -19,6 +19,7 @@ mod metrics; mod peer; mod produce_block; mod proposer_duties; +mod ptc_duties; mod publish_attestations; mod publish_blocks; mod standard_block_rewards; @@ -2560,6 +2561,14 @@ pub fn serve( task_spawner_filter.clone(), ); + // POST validator/duties/ptc/{epoch} + let post_validator_duties_ptc = post_validator_duties_ptc( + eth_v1.clone(), + chain_filter.clone(), + not_while_syncing_filter.clone(), + task_spawner_filter.clone(), + ); + // POST validator/duties/sync/{epoch} let post_validator_duties_sync = post_validator_duties_sync( eth_v1.clone(), @@ -3410,6 +3419,7 @@ pub fn serve( .uor(post_beacon_rewards_attestations) .uor(post_beacon_rewards_sync_committee) .uor(post_validator_duties_attester) + .uor(post_validator_duties_ptc) .uor(post_validator_duties_sync) .uor(post_validator_aggregate_and_proofs) .uor(post_validator_contribution_and_proofs) diff --git a/beacon_node/http_api/src/ptc_duties.rs b/beacon_node/http_api/src/ptc_duties.rs new file mode 100644 index 0000000000..f727b84004 --- /dev/null +++ b/beacon_node/http_api/src/ptc_duties.rs @@ -0,0 +1,182 @@ +//! Contains the handler for the `POST validator/duties/ptc/{epoch}` endpoint. + +use crate::state_id::StateId; +use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes}; +use eth2::types::{self as api_types, PtcDuty}; +use slot_clock::SlotClock; +use state_processing::state_advance::partial_state_advance; +use types::{BeaconState, ChainSpec, Epoch, EthSpec, Hash256}; + +type ApiDuties = api_types::DutiesResponse>; + +pub fn ptc_duties( + request_epoch: Epoch, + request_indices: &[u64], + chain: &BeaconChain, +) -> Result { + let current_epoch = chain + .slot_clock + .now_or_genesis() + .map(|slot| slot.epoch(T::EthSpec::slots_per_epoch())) + .ok_or(BeaconChainError::UnableToReadSlot) + .map_err(warp_utils::reject::unhandled_error)?; + + let tolerant_current_epoch = if chain.slot_clock.is_prior_to_genesis().unwrap_or(true) { + current_epoch + } else { + chain + .slot_clock + .now_with_future_tolerance(chain.spec.maximum_gossip_clock_disparity()) + .ok_or_else(|| { + warp_utils::reject::custom_server_error("unable to read slot clock".into()) + })? + .epoch(T::EthSpec::slots_per_epoch()) + }; + + let is_within_clock_tolerance = request_epoch == current_epoch + || request_epoch == current_epoch + 1 + || request_epoch == tolerant_current_epoch + 1; + + if is_within_clock_tolerance { + let head_epoch = chain + .canonical_head + .cached_head() + .snapshot + .beacon_state + .current_epoch(); + + let head_can_serve_request = request_epoch == head_epoch || request_epoch == head_epoch + 1; + + if head_can_serve_request { + compute_ptc_duties_from_cached_head(request_epoch, request_indices, chain) + } else { + compute_ptc_duties_from_state(request_epoch, request_indices, chain) + } + } else if request_epoch > current_epoch + 1 { + Err(warp_utils::reject::custom_bad_request(format!( + "request epoch {} is more than one epoch past the current epoch {}", + request_epoch, current_epoch + ))) + } else { + compute_ptc_duties_from_state(request_epoch, request_indices, chain) + } +} + +fn compute_ptc_duties_from_cached_head( + request_epoch: Epoch, + request_indices: &[u64], + chain: &BeaconChain, +) -> Result { + let (cached_head, execution_status) = chain + .canonical_head + .head_and_execution_status() + .map_err(warp_utils::reject::unhandled_error)?; + let state = &cached_head.snapshot.beacon_state; + let head_block_root = cached_head.head_block_root(); + + let (duties, dependent_root) = chain + .compute_ptc_duties(state, request_epoch, request_indices, head_block_root) + .map_err(warp_utils::reject::unhandled_error)?; + + convert_to_api_response( + duties, + dependent_root, + execution_status.is_optimistic_or_invalid(), + ) +} + +fn compute_ptc_duties_from_state( + request_epoch: Epoch, + request_indices: &[u64], + chain: &BeaconChain, +) -> Result { + let state_opt = { + let (cached_head, execution_status) = chain + .canonical_head + .head_and_execution_status() + .map_err(warp_utils::reject::unhandled_error)?; + let head = &cached_head.snapshot; + + if head.beacon_state.current_epoch() <= request_epoch { + Some(( + head.beacon_state_root(), + head.beacon_state.clone(), + execution_status.is_optimistic_or_invalid(), + )) + } else { + None + } + }; + + let (state, execution_optimistic) = + if let Some((state_root, mut state, execution_optimistic)) = state_opt { + ensure_state_knows_ptc_duties_for_epoch( + &mut state, + state_root, + request_epoch, + &chain.spec, + )?; + (state, execution_optimistic) + } else { + let (state, execution_optimistic, _finalized) = + StateId::from_slot(request_epoch.start_slot(T::EthSpec::slots_per_epoch())) + .state(chain)?; + (state, execution_optimistic) + }; + + if !(state.current_epoch() == request_epoch || state.current_epoch() + 1 == request_epoch) { + return Err(warp_utils::reject::custom_server_error(format!( + "state epoch {} not suitable for request epoch {}", + state.current_epoch(), + request_epoch + ))); + } + + let (duties, dependent_root) = chain + .compute_ptc_duties( + &state, + request_epoch, + request_indices, + chain.genesis_block_root, + ) + .map_err(warp_utils::reject::unhandled_error)?; + + convert_to_api_response(duties, dependent_root, execution_optimistic) +} + +fn ensure_state_knows_ptc_duties_for_epoch( + state: &mut BeaconState, + state_root: Hash256, + target_epoch: Epoch, + spec: &ChainSpec, +) -> Result<(), warp::reject::Rejection> { + if state.current_epoch() > target_epoch { + return Err(warp_utils::reject::custom_server_error(format!( + "state epoch {} is later than target epoch {}", + state.current_epoch(), + target_epoch + ))); + } else if state.current_epoch() + 1 < target_epoch { + let target_slot = target_epoch + .saturating_sub(1_u64) + .start_slot(E::slots_per_epoch()); + + partial_state_advance(state, Some(state_root), target_slot, spec) + .map_err(BeaconChainError::from) + .map_err(warp_utils::reject::unhandled_error)?; + } + + Ok(()) +} + +fn convert_to_api_response( + duties: Vec>, + dependent_root: Hash256, + execution_optimistic: bool, +) -> Result { + Ok(api_types::DutiesResponse { + dependent_root, + execution_optimistic: Some(execution_optimistic), + data: duties.into_iter().flatten().collect(), + }) +} diff --git a/beacon_node/http_api/src/validator/mod.rs b/beacon_node/http_api/src/validator/mod.rs index 7349aa4db0..27fe5de6e7 100644 --- a/beacon_node/http_api/src/validator/mod.rs +++ b/beacon_node/http_api/src/validator/mod.rs @@ -7,7 +7,7 @@ use crate::utils::{ ResponseFilter, TaskSpawnerFilter, ValidatorSubscriptionTxFilter, publish_network_message, }; use crate::version::{V1, V2, V3, unsupported_version_rejection}; -use crate::{StateId, attester_duties, proposer_duties, sync_committees}; +use crate::{StateId, attester_duties, proposer_duties, ptc_duties, sync_committees}; use beacon_chain::attestation_verification::VerifiedAttestation; use beacon_chain::{AttestationError, BeaconChain, BeaconChainError, BeaconChainTypes}; use bls::PublicKeyBytes; @@ -168,6 +168,42 @@ pub fn post_validator_duties_attester( .boxed() } +// POST validator/duties/ptc/{epoch} +pub fn post_validator_duties_ptc( + eth_v1: EthV1Filter, + chain_filter: ChainFilter, + not_while_syncing_filter: NotWhileSyncingFilter, + task_spawner_filter: TaskSpawnerFilter, +) -> ResponseFilter { + eth_v1 + .and(warp::path("validator")) + .and(warp::path("duties")) + .and(warp::path("ptc")) + .and(warp::path::param::().or_else(|_| async { + Err(warp_utils::reject::custom_bad_request( + "Invalid epoch".to_string(), + )) + })) + .and(warp::path::end()) + .and(not_while_syncing_filter.clone()) + .and(warp_utils::json::json()) + .and(task_spawner_filter.clone()) + .and(chain_filter.clone()) + .then( + |epoch: Epoch, + not_synced_filter: Result<(), Rejection>, + indices: ValidatorIndexData, + task_spawner: TaskSpawner, + chain: Arc>| { + task_spawner.blocking_json_task(Priority::P0, move || { + not_synced_filter?; + ptc_duties::ptc_duties(epoch, &indices.0, &chain) + }) + }, + ) + .boxed() +} + // GET validator/aggregate_attestation?attestation_data_root,slot pub fn get_validator_aggregate_attestation( any_version: AnyVersionFilter, diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index 2dd4c28040..aac3384fbd 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -3474,7 +3474,6 @@ impl ApiTester { self } - // TODO(EIP-7732): Add test_get_validator_duties_ptc function to test PTC duties endpoint pub async fn test_get_validator_duties_proposer_v2(self) -> Self { let current_epoch = self.chain.epoch().unwrap(); @@ -3598,6 +3597,17 @@ impl ApiTester { "should not get attester duties outside of tolerance" ); + assert_eq!( + self.client + .post_validator_duties_ptc(next_epoch, &[0]) + .await + .unwrap_err() + .status() + .map(Into::into), + Some(400), + "should not get ptc duties outside of tolerance" + ); + self.chain.slot_clock.set_current_time( current_epoch_start - self.chain.spec.maximum_gossip_clock_disparity(), ); @@ -3621,6 +3631,88 @@ impl ApiTester { .await .expect("should get attester duties within tolerance"); + self.client + .post_validator_duties_ptc(next_epoch, &[0]) + .await + .expect("should get ptc duties within tolerance"); + + self + } + + pub async fn test_get_validator_duties_ptc(self) -> Self { + let current_epoch = self.chain.epoch().unwrap().as_u64(); + + let half = current_epoch / 2; + let first = current_epoch - half; + let last = current_epoch + half; + + for epoch in first..=last { + for indices in self.interesting_validator_indices() { + let epoch = Epoch::from(epoch); + + // The endpoint does not allow getting duties past the next epoch. + if epoch > current_epoch + 1 { + assert_eq!( + self.client + .post_validator_duties_ptc(epoch, indices.as_slice()) + .await + .unwrap_err() + .status() + .map(Into::into), + Some(400) + ); + continue; + } + + let results = self + .client + .post_validator_duties_ptc(epoch, indices.as_slice()) + .await + .unwrap(); + + let dependent_root = self + .chain + .block_root_at_slot( + (epoch - 1).start_slot(E::slots_per_epoch()) - 1, + WhenSlotSkipped::Prev, + ) + .unwrap() + .unwrap_or(self.chain.head_beacon_block_root()); + + assert_eq!(results.dependent_root, dependent_root); + + let result_duties = results.data; + + let state = self + .chain + .state_at_slot( + epoch.start_slot(E::slots_per_epoch()), + StateSkipConfig::WithStateRoots, + ) + .unwrap(); + + let expected_duties: Vec = indices + .iter() + .filter_map(|&validator_index| { + let validator = state.validators().get(validator_index as usize)?; + let slot = state + .get_ptc_assignment(validator_index as usize, epoch, &self.chain.spec) + .unwrap()?; + Some(PtcDuty { + pubkey: validator.pubkey, + validator_index, + slot, + }) + }) + .collect(); + + assert_eq!( + result_duties, expected_duties, + "ptc duties should exactly match state assignments" + ); + } + } + self } @@ -7871,6 +7963,9 @@ async fn get_light_client_finality_update() { #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn get_validator_duties_early() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } ApiTester::new() .await .test_get_validator_duties_early() @@ -7936,6 +8031,29 @@ async fn get_validator_duties_proposer_v2_with_skip_slots() { .await; } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn get_validator_duties_ptc() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + ApiTester::new_with_hard_forks() + .await + .test_get_validator_duties_ptc() + .await; +} + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn get_validator_duties_ptc_with_skip_slots() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + ApiTester::new_with_hard_forks() + .await + .skip_slots(E::slots_per_epoch() * 2) + .test_get_validator_duties_ptc() + .await; +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn block_production() { ApiTester::new().await.test_block_production().await; diff --git a/consensus/types/src/state/beacon_state.rs b/consensus/types/src/state/beacon_state.rs index 7e2b3096a8..7ed3121d6e 100644 --- a/consensus/types/src/state/beacon_state.rs +++ b/consensus/types/src/state/beacon_state.rs @@ -3198,6 +3198,27 @@ impl BeaconState { Ok(hash(&preimage)) } + /// Find the first slot in the given epoch where the validator is assigned to the PTC. + /// + /// Returns `Ok(Some(slot))` if the validator is in the PTC for any slot in the epoch, + /// `Ok(None)` if the validator is not in the PTC for this epoch. + /// + /// This iterates through all slots in the epoch, so it's O(slots_per_epoch) per validator. + pub fn get_ptc_assignment( + &self, + validator_index: usize, + epoch: Epoch, + spec: &ChainSpec, + ) -> Result, BeaconStateError> { + for slot in epoch.slot_iter(E::slots_per_epoch()) { + let ptc = self.get_ptc(slot, spec)?; + if ptc.0.contains(&validator_index) { + return Ok(Some(slot)); + } + } + Ok(None) + } + /// Return size indices sampled by effective balance, using indices as candidates. /// /// If shuffle_indices is True, candidate indices are themselves sampled from indices From 6ab48a76f0aab997dd7a818d8b02541d197e1746 Mon Sep 17 00:00:00 2001 From: hopinheimer <48147533+hopinheimer@users.noreply.github.com> Date: Mon, 27 Apr 2026 05:51:20 -0400 Subject: [PATCH 04/12] Gloas `PayloadAttestation` gossip verification (#9145) Co-Authored-By: hopinheimer Co-Authored-By: hopinheimer <48147533+hopinheimer@users.noreply.github.com> Co-Authored-By: Eitan Seri-Levi Co-Authored-By: Jimmy Chen --- beacon_node/beacon_chain/src/beacon_chain.rs | 22 +- beacon_node/beacon_chain/src/builder.rs | 1 + beacon_node/beacon_chain/src/lib.rs | 1 + beacon_node/beacon_chain/src/metrics.rs | 21 + .../beacon_chain/src/observed_attesters.rs | 42 ++ .../gossip_verified_payload_attestation.rs | 255 +++++++++++ .../payload_attestation_verification/mod.rs | 110 +++++ .../payload_attestation_verification/tests.rs | 422 ++++++++++++++++++ .../gossip_methods.rs | 152 ++++++- .../src/network_beacon_processor/mod.rs | 2 +- consensus/fork_choice/src/fork_choice.rs | 2 +- 11 files changed, 1014 insertions(+), 16 deletions(-) create mode 100644 beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs create mode 100644 beacon_node/beacon_chain/src/payload_attestation_verification/mod.rs create mode 100644 beacon_node/beacon_chain/src/payload_attestation_verification/tests.rs diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index bfe1b404e0..cf5afb089a 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -53,7 +53,8 @@ use crate::observed_aggregates::{ Error as AttestationObservationError, ObservedAggregateAttestations, ObservedSyncContributions, }; use crate::observed_attesters::{ - ObservedAggregators, ObservedAttesters, ObservedSyncAggregators, ObservedSyncContributors, + ObservedAggregators, ObservedAttesters, ObservedPayloadAttesters, ObservedSyncAggregators, + ObservedSyncContributors, }; use crate::observed_block_producers::ObservedBlockProducers; use crate::observed_data_sidecars::ObservedDataSidecars; @@ -418,6 +419,9 @@ pub struct BeaconChain { /// Maintains a record of which validators have been seen to create `SignedContributionAndProofs` /// in recent epochs. pub(crate) observed_sync_aggregators: RwLock>, + /// Maintains a record of which validators have sent payload attestation messages + /// in recent slots. + pub(crate) observed_payload_attesters: RwLock>, /// Maintains a record of which validators have proposed blocks for each slot. pub observed_block_producers: RwLock>, /// Maintains a record of blob sidecars seen over the gossip network. @@ -2308,6 +2312,22 @@ impl BeaconChain { }) } + pub fn apply_payload_attestation_to_fork_choice( + &self, + indexed_payload_attestation: &IndexedPayloadAttestation, + ptc: &PTC, + ) -> Result<(), Error> { + self.canonical_head + .fork_choice_write_lock() + .on_payload_attestation( + self.slot()?, + indexed_payload_attestation, + AttestationFromBlock::False, + &ptc.0, + ) + .map_err(Into::into) + } + /// Accepts some `SyncCommitteeMessage` from the network and attempts to verify it, returning `Ok(_)` if /// it is valid to be (re)broadcast on the gossip network. pub fn verify_sync_committee_message_for_gossip( diff --git a/beacon_node/beacon_chain/src/builder.rs b/beacon_node/beacon_chain/src/builder.rs index 19eb1aa877..d70561db9b 100644 --- a/beacon_node/beacon_chain/src/builder.rs +++ b/beacon_node/beacon_chain/src/builder.rs @@ -1015,6 +1015,7 @@ where observed_aggregators: <_>::default(), // TODO: allow for persisting and loading the pool from disk. observed_sync_aggregators: <_>::default(), + observed_payload_attesters: <_>::default(), // TODO: allow for persisting and loading the pool from disk. observed_block_producers: <_>::default(), observed_column_sidecars: RwLock::new(ObservedDataSidecars::new(self.spec.clone())), diff --git a/beacon_node/beacon_chain/src/lib.rs b/beacon_node/beacon_chain/src/lib.rs index 7631e6b904..d70fc1b3ec 100644 --- a/beacon_node/beacon_chain/src/lib.rs +++ b/beacon_node/beacon_chain/src/lib.rs @@ -44,6 +44,7 @@ pub mod observed_data_sidecars; pub mod observed_operations; mod observed_slashable; pub mod partial_data_column_assembler; +pub mod payload_attestation_verification; pub mod payload_bid_verification; pub mod payload_envelope_streamer; pub mod payload_envelope_verification; diff --git a/beacon_node/beacon_chain/src/metrics.rs b/beacon_node/beacon_chain/src/metrics.rs index ce136ef3fc..43c3337bc9 100644 --- a/beacon_node/beacon_chain/src/metrics.rs +++ b/beacon_node/beacon_chain/src/metrics.rs @@ -1468,6 +1468,27 @@ pub static SYNC_MESSAGE_GOSSIP_VERIFICATION_TIMES: LazyLock> = "Full runtime of sync contribution gossip verification", ) }); +pub static PAYLOAD_ATTESTATION_PROCESSING_REQUESTS: LazyLock> = + LazyLock::new(|| { + try_create_int_counter( + "beacon_payload_attestation_processing_requests_total", + "Count of all payload attestation messages submitted for processing", + ) + }); +pub static PAYLOAD_ATTESTATION_PROCESSING_SUCCESSES: LazyLock> = + LazyLock::new(|| { + try_create_int_counter( + "beacon_payload_attestation_processing_successes_total", + "Number of payload attestation messages verified for gossip", + ) + }); +pub static PAYLOAD_ATTESTATION_GOSSIP_VERIFICATION_TIMES: LazyLock> = + LazyLock::new(|| { + try_create_histogram( + "beacon_payload_attestation_gossip_verification_seconds", + "Full runtime of payload attestation gossip verification", + ) + }); pub static SYNC_MESSAGE_EQUIVOCATIONS: LazyLock> = LazyLock::new(|| { try_create_int_counter( "sync_message_equivocations_total", diff --git a/beacon_node/beacon_chain/src/observed_attesters.rs b/beacon_node/beacon_chain/src/observed_attesters.rs index 277bf38ffc..4bb536880c 100644 --- a/beacon_node/beacon_chain/src/observed_attesters.rs +++ b/beacon_node/beacon_chain/src/observed_attesters.rs @@ -42,6 +42,8 @@ pub type ObservedSyncContributors = pub type ObservedAggregators = AutoPruningEpochContainer; pub type ObservedSyncAggregators = AutoPruningSlotContainer; +pub type ObservedPayloadAttesters = + AutoPruningSlotContainer, E>; #[derive(Debug, PartialEq)] pub enum Error { @@ -255,6 +257,46 @@ impl Item<()> for SyncAggregatorSlotHashSet { } } +/// Stores a `HashSet` of validator indices that have sent a payload attestation gossip +/// message during a slot. +pub struct PayloadAttesterSlotHashSet { + set: HashSet, + phantom: PhantomData, +} + +impl Item<()> for PayloadAttesterSlotHashSet { + fn with_capacity(capacity: usize) -> Self { + Self { + set: HashSet::with_capacity(capacity), + phantom: PhantomData, + } + } + + /// Defaults to `PTC_SIZE`, the maximum number of payload attesters per slot. + fn default_capacity() -> usize { + E::ptc_size() + } + + fn len(&self) -> usize { + self.set.len() + } + + fn validator_count(&self) -> usize { + self.set.len() + } + + /// Inserts the `validator_index` in the set. Returns `true` if the `validator_index` was + /// already in the set. + fn insert(&mut self, validator_index: usize, _value: ()) -> bool { + !self.set.insert(validator_index) + } + + /// Returns `true` if the `validator_index` is in the set. + fn get(&self, validator_index: usize) -> Option<()> { + self.set.contains(&validator_index).then_some(()) + } +} + /// A container that stores some number of `T` items. /// /// This container is "auto-pruning" since it gets an idea of the current slot by which diff --git a/beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs b/beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs new file mode 100644 index 0000000000..2d9fce812e --- /dev/null +++ b/beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs @@ -0,0 +1,255 @@ +use super::Error; +use crate::beacon_chain::BeaconStore; +use crate::canonical_head::CanonicalHead; +use crate::observed_attesters::ObservedPayloadAttesters; +use crate::validator_pubkey_cache::ValidatorPubkeyCache; +use crate::{BeaconChain, BeaconChainError, BeaconChainTypes, metrics}; +use bls::AggregateSignature; +use educe::Educe; +use parking_lot::RwLock; +use safe_arith::SafeArith; +use slot_clock::SlotClock; +use state_processing::per_block_processing::signature_sets::indexed_payload_attestation_signature_set; +use state_processing::state_advance::partial_state_advance; +use std::borrow::Cow; +use types::{ChainSpec, EthSpec, IndexedPayloadAttestation, PTC, PayloadAttestationMessage, Slot}; + +pub struct GossipVerificationContext<'a, T: BeaconChainTypes> { + pub slot_clock: &'a T::SlotClock, + pub spec: &'a ChainSpec, + pub observed_payload_attesters: &'a RwLock>, + pub canonical_head: &'a CanonicalHead, + pub validator_pubkey_cache: &'a RwLock>, + pub store: &'a BeaconStore, +} + +/// A `PayloadAttestationMessage` that has been verified for propagation on the gossip network. +#[derive(Educe)] +#[educe(Clone, Debug)] +pub struct VerifiedPayloadAttestationMessage { + payload_attestation_message: PayloadAttestationMessage, + indexed_payload_attestation: IndexedPayloadAttestation, + ptc: PTC, +} + +impl VerifiedPayloadAttestationMessage { + pub fn new( + payload_attestation_message: PayloadAttestationMessage, + ctx: &GossipVerificationContext<'_, T>, + ) -> Result { + let slot = payload_attestation_message.data.slot; + let validator_index = payload_attestation_message.validator_index; + + // [IGNORE] `data.slot` is within the `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance. + verify_propagation_slot_range(ctx.slot_clock, slot, ctx.spec)?; + + // [IGNORE] There has been no other valid payload attestation message for this + // validator index. + if ctx + .observed_payload_attesters + .read() + .validator_has_been_observed(slot, validator_index as usize) + .map_err(BeaconChainError::from)? + { + return Err(Error::PriorPayloadAttestationMessageKnown { + validator_index, + slot, + }); + } + + // [IGNORE] `data.beacon_block_root` has been seen + // [REJECT] `data.beacon_block_root` passes validation. + // + // TODO(gloas): These two conditions are conflated. We need a status table to + // differentiate between: + // 1. Blocks we haven't seen (IGNORE), and + // 2. Blocks we've seen that are invalid (REJECT). + // Presently both cases return IGNORE. + let beacon_block_root = payload_attestation_message.data.beacon_block_root; + if ctx + .canonical_head + .fork_choice_read_lock() + .get_block(&beacon_block_root) + .is_none() + { + return Err(Error::UnknownHeadBlock { beacon_block_root }); + } + + // Get head state for PTC computation. If the cached head state is too stale + // (e.g. during liveness failures with many skipped slots), fall back to loading + // a more recent state from the store and advancing it if necessary. + let head = ctx.canonical_head.cached_head(); + let head_state = &head.snapshot.beacon_state; + + let message_epoch = slot.epoch(T::EthSpec::slots_per_epoch()); + let state_epoch = head_state.current_epoch(); + + // get_ptc can serve epochs in [state_epoch - 1, state_epoch + min_seed_lookahead]. + // If the message epoch is beyond that range, the head state is stale. + let advanced_state = if message_epoch + > state_epoch + .safe_add(ctx.spec.min_seed_lookahead) + .map_err(BeaconChainError::from)? + { + let head_block_root = head.head_block_root(); + let target_slot = message_epoch.start_slot(T::EthSpec::slots_per_epoch()); + + let (state_root, mut state) = ctx + .store + .get_advanced_hot_state( + head_block_root, + target_slot, + head.snapshot.beacon_state_root(), + ) + .map_err(BeaconChainError::from)? + .ok_or(BeaconChainError::MissingBeaconState( + head.snapshot.beacon_state_root(), + ))?; + + if state + .current_epoch() + .safe_add(ctx.spec.min_seed_lookahead) + .map_err(BeaconChainError::from)? + < message_epoch + { + partial_state_advance(&mut state, Some(state_root), target_slot, ctx.spec) + .map_err(BeaconChainError::from)?; + } + + Some(state) + } else { + None + }; + + let state = advanced_state.as_ref().unwrap_or(head_state); + + // [REJECT] `validator_index` is within `get_ptc(state, data.slot)`. + let ptc = state.get_ptc(slot, ctx.spec)?; + if !ptc.0.contains(&(validator_index as usize)) { + return Err(Error::NotInPTC { + validator_index, + slot, + }); + } + + // Build the indexed form for signature verification and downstream fork choice. + let indexed_payload_attestation = IndexedPayloadAttestation { + attesting_indices: vec![validator_index] + .try_into() + .map_err(|_| Error::UnknownValidatorIndex(validator_index))?, + data: payload_attestation_message.data.clone(), + signature: AggregateSignature::from(&payload_attestation_message.signature), + }; + + { + // [REJECT] The signature is valid with respect to the `validator_index`. + let pubkey_cache = ctx.validator_pubkey_cache.read(); + let signature_set = indexed_payload_attestation_signature_set( + state, + |validator_index| pubkey_cache.get(validator_index).map(Cow::Borrowed), + &indexed_payload_attestation.signature, + &indexed_payload_attestation, + ctx.spec, + ) + .map_err(|_| Error::UnknownValidatorIndex(validator_index))?; + + if !signature_set.verify() { + return Err(Error::InvalidSignature); + } + } + + // Record that we have received a valid payload attestation message from this + // validator. Double check with the write lock to handle race conditions. + if ctx + .observed_payload_attesters + .write() + .observe_validator(slot, validator_index as usize, ()) + .map_err(BeaconChainError::from)? + { + return Err(Error::PriorPayloadAttestationMessageKnown { + validator_index, + slot, + }); + } + + Ok(Self { + payload_attestation_message, + indexed_payload_attestation, + ptc, + }) + } + + pub fn payload_attestation_message(&self) -> &PayloadAttestationMessage { + &self.payload_attestation_message + } + + pub fn indexed_payload_attestation(&self) -> &IndexedPayloadAttestation { + &self.indexed_payload_attestation + } + + pub fn ptc(&self) -> &PTC { + &self.ptc + } + + pub fn into_payload_attestation_message(self) -> PayloadAttestationMessage { + self.payload_attestation_message + } +} + +impl BeaconChain { + pub fn payload_attestation_gossip_context(&self) -> GossipVerificationContext<'_, T> { + GossipVerificationContext { + slot_clock: &self.slot_clock, + spec: &self.spec, + observed_payload_attesters: &self.observed_payload_attesters, + canonical_head: &self.canonical_head, + validator_pubkey_cache: &self.validator_pubkey_cache, + store: &self.store, + } + } + + pub fn verify_payload_attestation_message_for_gossip( + &self, + payload_attestation_message: PayloadAttestationMessage, + ) -> Result, Error> { + metrics::inc_counter(&metrics::PAYLOAD_ATTESTATION_PROCESSING_REQUESTS); + let _timer = metrics::start_timer(&metrics::PAYLOAD_ATTESTATION_GOSSIP_VERIFICATION_TIMES); + + let ctx = self.payload_attestation_gossip_context(); + VerifiedPayloadAttestationMessage::new(payload_attestation_message, &ctx).inspect(|_| { + metrics::inc_counter(&metrics::PAYLOAD_ATTESTATION_PROCESSING_SUCCESSES); + }) + } +} + +/// Verify that the `slot` is within the acceptable gossip propagation range, with reference +/// to the current slot of the clock. +/// +/// Accounts for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`. +fn verify_propagation_slot_range( + slot_clock: &S, + message_slot: Slot, + spec: &ChainSpec, +) -> Result<(), Error> { + let latest_permissible_slot = slot_clock + .now_with_future_tolerance(spec.maximum_gossip_clock_disparity()) + .ok_or(BeaconChainError::UnableToReadSlot)?; + if message_slot > latest_permissible_slot { + return Err(Error::FutureSlot { + message_slot, + latest_permissible_slot, + }); + } + + let earliest_permissible_slot = slot_clock + .now_with_past_tolerance(spec.maximum_gossip_clock_disparity()) + .ok_or(BeaconChainError::UnableToReadSlot)?; + if message_slot < earliest_permissible_slot { + return Err(Error::PastSlot { + message_slot, + earliest_permissible_slot, + }); + } + + Ok(()) +} diff --git a/beacon_node/beacon_chain/src/payload_attestation_verification/mod.rs b/beacon_node/beacon_chain/src/payload_attestation_verification/mod.rs new file mode 100644 index 0000000000..477527c0aa --- /dev/null +++ b/beacon_node/beacon_chain/src/payload_attestation_verification/mod.rs @@ -0,0 +1,110 @@ +//! Provides verification for `PayloadAttestationMessage` received from the gossip network. +//! +//! ```ignore +//! types::PayloadAttestationMessage +//! | +//! ▼ +//! VerifiedPayloadAttestationMessage +//! ``` + +use crate::BeaconChainError; +use strum::AsRefStr; +use types::{BeaconStateError, Hash256, Slot}; + +pub mod gossip_verified_payload_attestation; + +pub use gossip_verified_payload_attestation::{ + GossipVerificationContext, VerifiedPayloadAttestationMessage, +}; + +/// Returned when a payload attestation message was not successfully verified. It might not have +/// been verified for two reasons: +/// +/// - The message is malformed or inappropriate for the context (indicated by all variants +/// other than `BeaconChainError`). +/// - The application encountered an internal error whilst attempting to determine validity +/// (the `BeaconChainError` variant) +#[derive(Debug, AsRefStr)] +pub enum Error { + /// The payload attestation message is from a slot that is later than the current slot + /// (with respect to the gossip clock disparity). + /// + /// ## Peer scoring + /// + /// Assuming the local clock is correct, the peer has sent an invalid message. + FutureSlot { + message_slot: Slot, + latest_permissible_slot: Slot, + }, + /// The payload attestation message is from a slot that is prior to the earliest + /// permissible slot (with respect to the gossip clock disparity). + /// + /// ## Peer scoring + /// + /// Assuming the local clock is correct, the peer has sent an invalid message. + PastSlot { + message_slot: Slot, + earliest_permissible_slot: Slot, + }, + /// We have already observed a valid payload attestation message from this validator + /// for this slot. + /// + /// ## Peer scoring + /// + /// The peer is not necessarily faulty. + PriorPayloadAttestationMessageKnown { validator_index: u64, slot: Slot }, + /// The beacon block referenced by the payload attestation message is not known. + /// + /// ## Peer scoring + /// + /// The attestation points to a block we have not yet imported. It's unclear if the + /// attestation is valid or not. + UnknownHeadBlock { beacon_block_root: Hash256 }, + /// The validator index is not a member of the PTC for this slot. + /// + /// ## Peer scoring + /// + /// The peer has sent an invalid message. + NotInPTC { validator_index: u64, slot: Slot }, + /// The validator index is unknown. + /// + /// ## Peer scoring + /// + /// The peer has sent an invalid message. + UnknownValidatorIndex(u64), + /// The signature on the payload attestation message is invalid. + /// + /// ## Peer scoring + /// + /// The peer has sent an invalid message. + InvalidSignature, + /// There was an error whilst processing the payload attestation message. It is not known + /// if it is valid or invalid. + /// + /// ## Peer scoring + /// + /// We were unable to process this message due to an internal error. It's unclear if the + /// message is valid. + BeaconChainError(Box), + /// An error reading beacon state. + /// + /// ## Peer scoring + /// + /// We were unable to process this message due to an internal error. + BeaconStateError(BeaconStateError), +} + +impl From for Error { + fn from(e: BeaconChainError) -> Self { + Error::BeaconChainError(Box::new(e)) + } +} + +impl From for Error { + fn from(e: BeaconStateError) -> Self { + Error::BeaconStateError(e) + } +} + +#[cfg(test)] +mod tests; diff --git a/beacon_node/beacon_chain/src/payload_attestation_verification/tests.rs b/beacon_node/beacon_chain/src/payload_attestation_verification/tests.rs new file mode 100644 index 0000000000..7faad98e55 --- /dev/null +++ b/beacon_node/beacon_chain/src/payload_attestation_verification/tests.rs @@ -0,0 +1,422 @@ +use std::sync::Arc; +use std::time::Duration; + +use bls::{Keypair, Signature}; +use fork_choice::ForkChoice; +use genesis::{generate_deterministic_keypairs, interop_genesis_state}; +use parking_lot::RwLock; +use proto_array::PayloadStatus; +use slot_clock::{SlotClock, TestingSlotClock}; +use state_processing::AllCaches; +use state_processing::genesis::genesis_block; +use store::{HotColdDB, StoreConfig}; +use types::{ + ChainSpec, Checkpoint, Domain, Epoch, EthSpec, Hash256, MinimalEthSpec, PayloadAttestationData, + PayloadAttestationMessage, SignedBeaconBlock, SignedRoot, Slot, +}; + +use crate::{ + beacon_fork_choice_store::BeaconForkChoiceStore, + beacon_snapshot::BeaconSnapshot, + canonical_head::CanonicalHead, + observed_attesters::ObservedPayloadAttesters, + payload_attestation_verification::{ + Error as PayloadAttestationError, + gossip_verified_payload_attestation::{ + GossipVerificationContext, VerifiedPayloadAttestationMessage, + }, + }, + test_utils::{BeaconChainHarness, EphemeralHarnessType, fork_name_from_env, test_spec}, + validator_pubkey_cache::ValidatorPubkeyCache, +}; + +type E = MinimalEthSpec; +type T = EphemeralHarnessType; + +const NUM_VALIDATORS: usize = 64; + +struct TestContext { + canonical_head: CanonicalHead, + observed_payload_attesters: RwLock>, + validator_pubkey_cache: RwLock>, + slot_clock: TestingSlotClock, + keypairs: Vec, + spec: ChainSpec, + genesis_block_root: Hash256, + store: Arc, store::MemoryStore>>, +} + +impl TestContext { + fn new() -> Self { + let spec = test_spec::(); + let store = Arc::new( + HotColdDB::open_ephemeral(StoreConfig::default(), Arc::new(spec.clone())) + .expect("should open ephemeral store"), + ); + + let keypairs = generate_deterministic_keypairs(NUM_VALIDATORS); + + let mut state = + interop_genesis_state::(&keypairs, 0, Hash256::repeat_byte(0x42), None, &spec) + .expect("should build genesis state"); + + *state.finalized_checkpoint_mut() = Checkpoint { + epoch: Epoch::new(1), + root: Hash256::ZERO, + }; + + let mut block = genesis_block(&state, &spec).expect("should build genesis block"); + *block.state_root_mut() = state + .update_tree_hash_cache() + .expect("should hash genesis state"); + let signed_block = SignedBeaconBlock::from_block(block, Signature::empty()); + let block_root = signed_block.canonical_root(); + + let snapshot = BeaconSnapshot::new( + Arc::new(signed_block.clone()), + None, + block_root, + state.clone(), + ); + + let fc_store = BeaconForkChoiceStore::get_forkchoice_store(store.clone(), snapshot.clone()) + .expect("should create fork choice store"); + let fork_choice = + ForkChoice::from_anchor(fc_store, block_root, &signed_block, &state, None, &spec) + .expect("should create fork choice"); + + let canonical_head = + CanonicalHead::new(fork_choice, Arc::new(snapshot), PayloadStatus::Pending); + + let slot_clock = TestingSlotClock::new( + Slot::new(0), + Duration::from_secs(0), + spec.get_slot_duration(), + ); + // Advance past genesis so `now_with_past_tolerance` doesn't underflow. + slot_clock.set_current_time(spec.get_slot_duration()); + + let validator_pubkey_cache = + ValidatorPubkeyCache::new(&state, store.clone()).expect("should create pubkey cache"); + + Self { + canonical_head, + observed_payload_attesters: RwLock::new(ObservedPayloadAttesters::default()), + validator_pubkey_cache: RwLock::new(validator_pubkey_cache), + slot_clock, + keypairs, + spec, + genesis_block_root: block_root, + store, + } + } + + fn gossip_ctx(&self) -> GossipVerificationContext<'_, T> { + GossipVerificationContext { + slot_clock: &self.slot_clock, + spec: &self.spec, + observed_payload_attesters: &self.observed_payload_attesters, + canonical_head: &self.canonical_head, + validator_pubkey_cache: &self.validator_pubkey_cache, + store: &self.store, + } + } + + fn ptc_members(&self, slot: Slot) -> Vec { + let head = self.canonical_head.cached_head(); + let state = &head.snapshot.beacon_state; + let ptc = state.get_ptc(slot, &self.spec).expect("should get PTC"); + ptc.0.to_vec() + } + + fn sign_payload_attestation( + &self, + data: PayloadAttestationData, + validator_index: u64, + ) -> PayloadAttestationMessage { + let head = self.canonical_head.cached_head(); + let state = &head.snapshot.beacon_state; + let domain = self.spec.get_domain( + data.slot.epoch(E::slots_per_epoch()), + Domain::PTCAttester, + &state.fork(), + state.genesis_validators_root(), + ); + let message = data.signing_root(domain); + let signature = self.keypairs[validator_index as usize].sk.sign(message); + PayloadAttestationMessage { + validator_index, + data, + signature, + } + } +} + +fn make_payload_attestation( + slot: Slot, + validator_index: u64, + beacon_block_root: Hash256, +) -> PayloadAttestationMessage { + PayloadAttestationMessage { + validator_index, + data: PayloadAttestationData { + beacon_block_root, + slot, + payload_present: true, + blob_data_available: true, + }, + signature: Signature::empty(), + } +} + +#[test] +fn future_slot() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + let ctx = TestContext::new(); + let gossip = ctx.gossip_ctx(); + + let future_slot = Slot::new(5); + let msg = make_payload_attestation(future_slot, 0, ctx.genesis_block_root); + let result = VerifiedPayloadAttestationMessage::new(msg, &gossip); + assert!(matches!( + result, + Err(PayloadAttestationError::FutureSlot { .. }) + )); +} + +#[test] +fn past_slot() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + let ctx = TestContext::new(); + ctx.slot_clock.set_slot(5); + let gossip = ctx.gossip_ctx(); + + let msg = make_payload_attestation(Slot::new(0), 0, ctx.genesis_block_root); + let result = VerifiedPayloadAttestationMessage::new(msg, &gossip); + assert!(matches!( + result, + Err(PayloadAttestationError::PastSlot { .. }) + )); +} + +#[test] +fn unknown_head_block() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + let ctx = TestContext::new(); + let gossip = ctx.gossip_ctx(); + + let unknown_root = Hash256::repeat_byte(0xff); + let msg = make_payload_attestation(Slot::new(1), 0, unknown_root); + let result = VerifiedPayloadAttestationMessage::new(msg, &gossip); + assert!( + matches!( + result, + Err(PayloadAttestationError::UnknownHeadBlock { .. }) + ), + "expected UnknownHeadBlock, got: {:?}", + result + ); +} + +#[test] +fn not_in_ptc() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + let ctx = TestContext::new(); + let gossip = ctx.gossip_ctx(); + let slot = Slot::new(1); + + let ptc_members = ctx.ptc_members(slot); + let non_ptc_validator = (0..NUM_VALIDATORS as u64) + .find(|&i| !ptc_members.contains(&(i as usize))) + .expect("should find non-PTC validator"); + + let msg = make_payload_attestation(slot, non_ptc_validator, ctx.genesis_block_root); + let result = VerifiedPayloadAttestationMessage::new(msg, &gossip); + assert!(matches!( + result, + Err(PayloadAttestationError::NotInPTC { .. }) + )); +} + +#[test] +fn invalid_signature() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + let ctx = TestContext::new(); + let gossip = ctx.gossip_ctx(); + let slot = Slot::new(1); + + let ptc_members = ctx.ptc_members(slot); + let validator_index = ptc_members[0] as u64; + + let msg = make_payload_attestation(slot, validator_index, ctx.genesis_block_root); + let result = VerifiedPayloadAttestationMessage::new(msg, &gossip); + assert!(matches!( + result, + Err(PayloadAttestationError::InvalidSignature) + )); +} + +#[test] +fn valid_payload_attestation() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + let ctx = TestContext::new(); + let gossip = ctx.gossip_ctx(); + let slot = Slot::new(1); + + let ptc_members = ctx.ptc_members(slot); + let validator_index = ptc_members[0] as u64; + + let data = PayloadAttestationData { + beacon_block_root: ctx.genesis_block_root, + slot, + payload_present: true, + blob_data_available: true, + }; + let msg = ctx.sign_payload_attestation(data, validator_index); + let result = VerifiedPayloadAttestationMessage::new(msg, &gossip); + assert!( + result.is_ok(), + "expected Ok, got: {:?}", + result.unwrap_err() + ); +} + +#[test] +fn duplicate_after_valid() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + let ctx = TestContext::new(); + let gossip = ctx.gossip_ctx(); + let slot = Slot::new(1); + + let ptc_members = ctx.ptc_members(slot); + let validator_index = ptc_members[0] as u64; + + let data = PayloadAttestationData { + beacon_block_root: ctx.genesis_block_root, + slot, + payload_present: true, + blob_data_available: true, + }; + + let msg1 = ctx.sign_payload_attestation(data.clone(), validator_index); + let result1 = VerifiedPayloadAttestationMessage::new(msg1, &gossip); + assert!( + result1.is_ok(), + "first message should pass: {:?}", + result1.unwrap_err() + ); + + let msg2 = ctx.sign_payload_attestation(data, validator_index); + let result2 = VerifiedPayloadAttestationMessage::new(msg2, &gossip); + assert!(matches!( + result2, + Err(PayloadAttestationError::PriorPayloadAttestationMessageKnown { .. }) + )); +} + +/// Exercises the `partial_state_advance` fallback in gossip verification when +/// the head state is too stale to compute PTC membership (e.g., during a +/// network liveness failure with many missed slots). +#[tokio::test] +async fn stale_head_with_partial_advance() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + + let slots_per_epoch = E::slots_per_epoch(); + // Head at epoch 1, message at epoch 5 — 4 epochs of missed slots. + // This exceeds min_seed_lookahead (1), triggering the fallback path: + // get_advanced_hot_state loads the stored state, then partial_state_advance + // advances it through epoch boundaries to populate ptc_window. + let head_slot = Slot::new(slots_per_epoch); + let missed_epochs = 4; + let target_slot = Slot::new(slots_per_epoch * (1 + missed_epochs)); + let target_epoch = target_slot.epoch(slots_per_epoch); + + // GIVEN a chain with blocks through epoch 1 (so the store has states). + let harness = BeaconChainHarness::builder(E::default()) + .default_spec() + .deterministic_keypairs(64) + .fresh_ephemeral_store() + .mock_execution_layer() + .build(); + harness.extend_to_slot(head_slot).await; + + let head = harness.chain.canonical_head.cached_head(); + let head_epoch = head.snapshot.beacon_state.current_epoch(); + assert!( + target_epoch > head_epoch + harness.spec.min_seed_lookahead, + "precondition: message epoch must exceed head + min_seed_lookahead to trigger fallback" + ); + + // GIVEN a slot clock advanced to epoch 5 without producing blocks + // (simulating missed slots during a liveness failure). + harness.chain.slot_clock.set_slot(target_slot.as_u64()); + + // Advance a reference state to compute the PTC at the target slot. + let mut reference_state = head.snapshot.beacon_state.clone(); + state_processing::state_advance::partial_state_advance( + &mut reference_state, + Some(head.snapshot.beacon_state_root()), + target_slot, + &harness.spec, + ) + .expect("should advance reference state"); + reference_state + .build_all_caches(&harness.spec) + .expect("should build caches"); + + let ptc = reference_state + .get_ptc(target_slot, &harness.spec) + .expect("should get PTC from reference state"); + let validator_index = *ptc.0.first().expect("PTC should have at least one member") as u64; + + // WHEN a properly-signed payload attestation from a PTC member is verified. + let domain = harness.spec.get_domain( + target_epoch, + Domain::PTCAttester, + &reference_state.fork(), + reference_state.genesis_validators_root(), + ); + let data = PayloadAttestationData { + beacon_block_root: head.head_block_root(), + slot: target_slot, + payload_present: true, + blob_data_available: true, + }; + let message = data.signing_root(domain); + let signature = harness.validator_keypairs[validator_index as usize] + .sk + .sign(message); + let msg = PayloadAttestationMessage { + validator_index, + data, + signature, + }; + + // THEN verification succeeds despite the head being 4 epochs stale. + let result = harness + .chain + .verify_payload_attestation_message_for_gossip(msg); + assert!( + result.is_ok(), + "expected Ok (head epoch {}, message epoch {}), got: {:?}", + head_epoch, + target_epoch, + result.unwrap_err() + ); +} 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 ea1a2286a0..4083b1a3af 100644 --- a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs @@ -21,6 +21,9 @@ use beacon_chain::{ light_client_finality_update_verification::Error as LightClientFinalityUpdateError, light_client_optimistic_update_verification::Error as LightClientOptimisticUpdateError, observed_operations::ObservationOutcome, + payload_attestation_verification::{ + Error as PayloadAttestationError, VerifiedPayloadAttestationMessage, + }, sync_committee_verification::{self, Error as SyncCommitteeError}, validator_monitor::{get_block_delay_ms, get_slot_delay_ms}, }; @@ -137,6 +140,11 @@ struct RejectedAggregate { error: AttnError, } +struct RejectedPayloadAttestation { + payload_attestation_message: Box, + error: PayloadAttestationError, +} + /// Data for an aggregated or unaggregated attestation that failed verification. enum FailedAtt { Unaggregate { @@ -4088,25 +4096,143 @@ impl NetworkBeaconProcessor { } } - // TODO(gloas) dont forget to add tracing instrumentation + #[instrument( + level = "trace", + skip_all, + fields( + peer_id = %peer_id, + slot = %payload_attestation_message.data.slot, + validator_index = payload_attestation_message.validator_index, + ) + )] pub fn process_gossip_payload_attestation( self: &Arc, message_id: MessageId, peer_id: PeerId, - payload_attestation_message: PayloadAttestationMessage, + payload_attestation_message: Box, ) { - // TODO(EIP-7732): Implement proper payload attestation message gossip processing. - // This should integrate with a payload_attestation_verification.rs module once it's implemented. + let result = match self + .chain + .verify_payload_attestation_message_for_gossip(*payload_attestation_message.clone()) + { + Ok(verified) => Ok(verified), + Err(error) => Err(RejectedPayloadAttestation { + payload_attestation_message: payload_attestation_message.clone(), + error, + }), + }; - trace!( - %peer_id, - validator_index = payload_attestation_message.validator_index, - slot = %payload_attestation_message.data.slot, - beacon_block_root = %payload_attestation_message.data.beacon_block_root, - "Processing payload attestation message" - ); + self.process_gossip_payload_attestation_result(result, message_id, peer_id); + } - // For now, ignore all payload attestation messages since verification is not implemented - self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + fn process_gossip_payload_attestation_result( + self: &Arc, + result: Result, RejectedPayloadAttestation>, + message_id: MessageId, + peer_id: PeerId, + ) { + match result { + Ok(verified) => { + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Accept); + + if let Err(e) = self.chain.apply_payload_attestation_to_fork_choice( + verified.indexed_payload_attestation(), + verified.ptc(), + ) { + match e { + BeaconChainError::ForkChoiceError( + ForkChoiceError::InvalidPayloadAttestation(e), + ) => { + debug!( + reason = ?e, + %peer_id, + "Payload attestation invalid for fork choice" + ) + } + e => error!( + reason = ?e, + %peer_id, + "Error applying payload attestation to fork choice" + ), + } + } + } + Err(RejectedPayloadAttestation { + payload_attestation_message, + error, + }) => { + self.handle_payload_attestation_verification_failure( + peer_id, + message_id, + error, + payload_attestation_message.data.slot, + ); + } + } + } + + fn handle_payload_attestation_verification_failure( + &self, + peer_id: PeerId, + message_id: MessageId, + error: PayloadAttestationError, + message_slot: Slot, + ) { + match &error { + PayloadAttestationError::FutureSlot { .. } => { + self.gossip_penalize_peer( + peer_id, + PeerAction::HighToleranceError, + "payload_attn_future_slot", + ); + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + } + PayloadAttestationError::PastSlot { .. } + | PayloadAttestationError::PriorPayloadAttestationMessageKnown { .. } => { + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + } + PayloadAttestationError::UnknownHeadBlock { .. } => { + debug!( + %peer_id, + %message_slot, + "Payload attestation references unknown block" + ); + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + } + PayloadAttestationError::NotInPTC { .. } => { + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Reject); + self.gossip_penalize_peer( + peer_id, + PeerAction::LowToleranceError, + "payload_attn_not_in_ptc", + ); + } + PayloadAttestationError::UnknownValidatorIndex(_) => { + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Reject); + self.gossip_penalize_peer( + peer_id, + PeerAction::LowToleranceError, + "payload_attn_unknown_validator", + ); + } + PayloadAttestationError::InvalidSignature => { + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Reject); + self.gossip_penalize_peer( + peer_id, + PeerAction::LowToleranceError, + "payload_attn_invalid_sig", + ); + } + PayloadAttestationError::BeaconChainError(_) + | PayloadAttestationError::BeaconStateError(_) => { + debug!( + %peer_id, + %message_slot, + ?error, + "Internal error verifying payload attestation" + ); + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + } + } } } diff --git a/beacon_node/network/src/network_beacon_processor/mod.rs b/beacon_node/network/src/network_beacon_processor/mod.rs index 015b6a616e..bfcff2088b 100644 --- a/beacon_node/network/src/network_beacon_processor/mod.rs +++ b/beacon_node/network/src/network_beacon_processor/mod.rs @@ -511,7 +511,7 @@ impl NetworkBeaconProcessor { processor.process_gossip_payload_attestation( message_id, peer_id, - *payload_attestation_message, + payload_attestation_message, ) }; diff --git a/consensus/fork_choice/src/fork_choice.rs b/consensus/fork_choice/src/fork_choice.rs index f9d779fd24..a9e62dbe94 100644 --- a/consensus/fork_choice/src/fork_choice.rs +++ b/consensus/fork_choice/src/fork_choice.rs @@ -1351,7 +1351,7 @@ where let ptc_indices: Vec = attestation .attesting_indices .iter() - .filter_map(|vi| ptc.iter().position(|&p| p == *vi as usize)) + .filter_map(|validator_index| ptc.iter().position(|&p| p == *validator_index as usize)) .collect(); // Check that all the attesters are in the PTC From 028b5a42a9715c31f416d45db70add39d9934b12 Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Mon, 27 Apr 2026 17:13:35 +0200 Subject: [PATCH 05/12] Add payload attestation validator duty (#9178) Co-Authored-By: Eitan Seri-Levi Co-Authored-By: Jimmy Chen --- beacon_node/http_api/src/beacon/pool.rs | 149 ++++++++++- beacon_node/http_api/src/lib.rs | 21 +- beacon_node/http_api/tests/tests.rs | 96 +++++++ common/eth2/src/lib.rs | 44 +++- .../lighthouse_validator_store/src/lib.rs | 42 +++- validator_client/signing_method/src/lib.rs | 5 + .../signing_method/src/web3signer.rs | 3 + validator_client/src/lib.rs | 19 ++ .../validator_services/src/lib.rs | 1 + .../src/payload_attestation_service.rs | 238 ++++++++++++++++++ validator_client/validator_store/src/lib.rs | 16 +- 11 files changed, 618 insertions(+), 16 deletions(-) create mode 100644 validator_client/validator_services/src/payload_attestation_service.rs diff --git a/beacon_node/http_api/src/beacon/pool.rs b/beacon_node/http_api/src/beacon/pool.rs index 059573c317..c6b8a69643 100644 --- a/beacon_node/http_api/src/beacon/pool.rs +++ b/beacon_node/http_api/src/beacon/pool.rs @@ -1,24 +1,31 @@ use crate::task_spawner::{Priority, TaskSpawner}; -use crate::utils::{NetworkTxFilter, OptionalConsensusVersionHeaderFilter, ResponseFilter}; +use crate::utils::{ + ChainFilter, EthV1Filter, NetworkTxFilter, OptionalConsensusVersionHeaderFilter, + ResponseFilter, TaskSpawnerFilter, +}; use crate::version::{ ResponseIncludesVersion, V1, V2, add_consensus_version_header, beacon_response, unsupported_version_rejection, }; use crate::{sync_committees, utils}; use beacon_chain::observed_operations::ObservationOutcome; +use beacon_chain::payload_attestation_verification::Error as PayloadAttestationError; use beacon_chain::{BeaconChain, BeaconChainTypes}; +use bytes::Bytes; use eth2::types::{AttestationPoolQuery, EndpointVersion, Failure, GenericResponse}; use lighthouse_network::PubsubMessage; use network::NetworkMessage; use operation_pool::ReceivedPreCapella; use slot_clock::SlotClock; +use ssz::{Decode, Encode}; use std::collections::HashSet; use std::sync::Arc; use tokio::sync::mpsc::UnboundedSender; -use tracing::{debug, info, warn}; +use tracing::{debug, error, info, warn}; use types::{ - Attestation, AttestationData, AttesterSlashing, ForkName, ProposerSlashing, - SignedBlsToExecutionChange, SignedVoluntaryExit, SingleAttestation, SyncCommitteeMessage, + Attestation, AttestationData, AttesterSlashing, ForkName, PayloadAttestationMessage, + ProposerSlashing, SignedBlsToExecutionChange, SignedVoluntaryExit, SingleAttestation, + SyncCommitteeMessage, }; use warp::filters::BoxedFilter; use warp::{Filter, Reply}; @@ -520,3 +527,137 @@ pub fn post_beacon_pool_attestations_v2( ) .boxed() } + +/// POST beacon/pool/payload_attestations (JSON) +pub fn post_beacon_pool_payload_attestations( + network_tx_filter: &NetworkTxFilter, + optional_consensus_version_header_filter: OptionalConsensusVersionHeaderFilter, + beacon_pool_path: &BeaconPoolPathFilter, +) -> ResponseFilter { + beacon_pool_path + .clone() + .and(warp::path("payload_attestations")) + .and(warp::path::end()) + .and(warp_utils::json::json()) + .and(optional_consensus_version_header_filter) + .and(network_tx_filter.clone()) + .then( + |task_spawner: TaskSpawner, + chain: Arc>, + messages: Vec, + _fork_name: Option, + network_tx: UnboundedSender>| { + task_spawner.blocking_json_task(Priority::P0, move || { + publish_payload_attestation_messages(&chain, &network_tx, messages) + }) + }, + ) + .boxed() +} + +/// POST beacon/pool/payload_attestations (SSZ) +pub fn post_beacon_pool_payload_attestations_ssz( + eth_v1: EthV1Filter, + task_spawner_filter: TaskSpawnerFilter, + chain_filter: ChainFilter, + network_tx_filter: NetworkTxFilter, +) -> ResponseFilter { + eth_v1 + .and(warp::path("beacon")) + .and(warp::path("pool")) + .and(warp::path("payload_attestations")) + .and(warp::path::end()) + .and(warp::body::bytes()) + .and(task_spawner_filter) + .and(chain_filter) + .and(network_tx_filter) + .then( + |body_bytes: Bytes, + task_spawner: TaskSpawner, + chain: Arc>, + network_tx: UnboundedSender>| { + task_spawner.blocking_json_task(Priority::P0, move || { + let item_len = ::ssz_fixed_len(); + if !body_bytes.len().is_multiple_of(item_len) { + return Err(warp_utils::reject::custom_bad_request(format!( + "SSZ body length {} is not a multiple of PayloadAttestationMessage size {}", + body_bytes.len(), + item_len, + ))); + } + let messages: Vec = body_bytes + .chunks(item_len) + .map(|chunk| { + PayloadAttestationMessage::from_ssz_bytes(chunk).map_err(|e| { + warp_utils::reject::custom_bad_request(format!( + "invalid SSZ: {e:?}" + )) + }) + }) + .collect::>()?; + + publish_payload_attestation_messages(&chain, &network_tx, messages) + }) + }, + ) + .boxed() +} + +fn publish_payload_attestation_messages( + chain: &BeaconChain, + network_tx: &UnboundedSender>, + messages: Vec, +) -> Result<(), warp::Rejection> { + let mut failures = vec![]; + let mut num_already_known = 0; + + for (index, message) in messages.into_iter().enumerate() { + match chain.verify_payload_attestation_message_for_gossip(message.clone()) { + Ok(verified) => { + utils::publish_pubsub_message( + network_tx, + PubsubMessage::PayloadAttestation(Box::new(message)), + )?; + + if let Err(e) = chain.apply_payload_attestation_to_fork_choice( + verified.indexed_payload_attestation(), + verified.ptc(), + ) { + warn!( + error = ?e, + request_index = index, + "Payload attestation invalid for fork choice" + ); + } + } + Err(PayloadAttestationError::PriorPayloadAttestationMessageKnown { .. }) => { + num_already_known += 1; + } + // TODO(gloas): requeue for reprocessing like attestations do. + Err(e) => { + error!( + error = ?e, + request_index = index, + "Failure verifying payload attestation for gossip" + ); + failures.push(Failure::new(index, format!("{e:?}"))); + } + } + } + + if num_already_known > 0 { + debug!( + count = num_already_known, + "Some payload attestations already known" + ); + } + + if failures.is_empty() { + Ok(()) + } else { + Err(warp_utils::reject::indexed_bad_request( + "error processing payload attestations".to_string(), + failures, + )) + } +} diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index bd80dd1e82..b2d069f384 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -1454,7 +1454,7 @@ pub fn serve( let post_beacon_pool_attestations_v2 = post_beacon_pool_attestations_v2( &network_tx_filter, - optional_consensus_version_header_filter, + optional_consensus_version_header_filter.clone(), &beacon_pool_path_v2, ); @@ -1487,6 +1487,21 @@ pub fn serve( let post_beacon_pool_sync_committees = post_beacon_pool_sync_committees(&network_tx_filter, &beacon_pool_path); + // POST beacon/pool/payload_attestations + let post_beacon_pool_payload_attestations = post_beacon_pool_payload_attestations( + &network_tx_filter, + optional_consensus_version_header_filter, + &beacon_pool_path, + ); + + // POST beacon/pool/payload_attestations (SSZ) + let post_beacon_pool_payload_attestations_ssz = post_beacon_pool_payload_attestations_ssz( + eth_v1.clone(), + task_spawner_filter.clone(), + chain_filter.clone(), + network_tx_filter.clone(), + ); + // GET beacon/pool/bls_to_execution_changes let get_beacon_pool_bls_to_execution_changes = get_beacon_pool_bls_to_execution_changes(&beacon_pool_path); @@ -3400,7 +3415,8 @@ pub fn serve( .uor(post_beacon_blocks_v2_ssz) .uor(post_beacon_blinded_blocks_ssz) .uor(post_beacon_blinded_blocks_v2_ssz) - .uor(post_beacon_execution_payload_envelope_ssz), + .uor(post_beacon_execution_payload_envelope_ssz) + .uor(post_beacon_pool_payload_attestations_ssz), ) .uor(post_beacon_blocks) .uor(post_beacon_blinded_blocks) @@ -3411,6 +3427,7 @@ pub fn serve( .uor(post_beacon_pool_proposer_slashings) .uor(post_beacon_pool_voluntary_exits) .uor(post_beacon_pool_sync_committees) + .uor(post_beacon_pool_payload_attestations) .uor(post_beacon_pool_bls_to_execution_changes) .uor(post_beacon_execution_payload_envelope) .uor(post_beacon_state_validators) diff --git a/beacon_node/http_api/tests/tests.rs b/beacon_node/http_api/tests/tests.rs index aac3384fbd..b8326f4495 100644 --- a/beacon_node/http_api/tests/tests.rs +++ b/beacon_node/http_api/tests/tests.rs @@ -2793,6 +2793,89 @@ impl ApiTester { self } + fn make_valid_payload_attestation_message( + &self, + ptc_offset: usize, + ) -> PayloadAttestationMessage { + let head = self.chain.head_snapshot(); + let head_slot = head.beacon_block.slot(); + let head_root = head.beacon_block_root; + let fork = head.beacon_state.fork(); + let genesis_validators_root = self.chain.genesis_validators_root; + + let ptc = head + .beacon_state + .get_ptc(head_slot, &self.chain.spec) + .expect("should get PTC"); + + // Find distinct validator indices in the PTC (may contain duplicates due to + // weighted sampling with a small validator set). + let mut seen = std::collections::HashSet::new(); + let distinct_indices: Vec = ptc + .0 + .iter() + .copied() + .filter(|idx| seen.insert(*idx)) + .collect(); + let validator_index = distinct_indices[ptc_offset % distinct_indices.len()]; + + let data = PayloadAttestationData { + beacon_block_root: head_root, + slot: head_slot, + payload_present: true, + blob_data_available: true, + }; + + let epoch = head_slot.epoch(E::slots_per_epoch()); + let domain = + self.chain + .spec + .get_domain(epoch, Domain::PTCAttester, &fork, genesis_validators_root); + let signing_root = data.signing_root(domain); + let sk = &self.validator_keypairs()[validator_index].sk; + let signature = sk.sign(signing_root); + + PayloadAttestationMessage { + validator_index: validator_index as u64, + data, + signature, + } + } + + pub async fn test_post_beacon_pool_payload_attestations_valid(mut self) -> Self { + let message = self.make_valid_payload_attestation_message(0); + let fork_name = self.chain.spec.fork_name_at_slot::(message.data.slot); + + self.client + .post_beacon_pool_payload_attestations(&[message], fork_name) + .await + .unwrap(); + + assert!( + self.network_rx.network_recv.recv().await.is_some(), + "valid payload attestation should be sent to network" + ); + + self + } + + pub async fn test_post_beacon_pool_payload_attestations_valid_ssz(mut self) -> Self { + let message = self.make_valid_payload_attestation_message(1); + let fork_name = self.chain.spec.fork_name_at_slot::(message.data.slot); + + self.client + .post_beacon_pool_payload_attestations_ssz(&[message], fork_name) + .await + .unwrap(); + + assert!( + self.network_rx.network_recv.recv().await.is_some(), + "valid payload attestation (SSZ) should be sent to network" + ); + + self + } + pub async fn test_get_config_fork_schedule(self) -> Self { let result = self.client.get_config_fork_schedule().await.unwrap().data; @@ -8246,6 +8329,19 @@ async fn get_validator_payload_attestation_data_pre_gloas() { .await; } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn post_beacon_pool_payload_attestations_valid() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + ApiTester::new() + .await + .test_post_beacon_pool_payload_attestations_valid() + .await + .test_post_beacon_pool_payload_attestations_valid_ssz() + .await; +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn get_validator_aggregate_attestation_v1() { ApiTester::new() diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index 4ec75468a2..e866547b9f 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; +use types::{PayloadAttestationData, PayloadAttestationMessage}; pub const V1: EndpointVersion = EndpointVersion(1); pub const V2: EndpointVersion = EndpointVersion(2); @@ -1789,6 +1789,48 @@ impl BeaconNodeHttpClient { Ok(()) } + /// `POST beacon/pool/payload_attestations` (JSON) + pub async fn post_beacon_pool_payload_attestations( + &self, + messages: &[PayloadAttestationMessage], + fork_name: ForkName, + ) -> Result<(), Error> { + let mut path = self.eth_path(V1)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("beacon") + .push("pool") + .push("payload_attestations"); + + self.post_generic_with_consensus_version(path, &messages, None, fork_name) + .await?; + + Ok(()) + } + + /// `POST beacon/pool/payload_attestations` (SSZ) + pub async fn post_beacon_pool_payload_attestations_ssz( + &self, + messages: &[PayloadAttestationMessage], + fork_name: ForkName, + ) -> Result<(), Error> { + let mut path = self.eth_path(V1)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("beacon") + .push("pool") + .push("payload_attestations"); + + let ssz_body: Vec = messages.iter().flat_map(|m| m.as_ssz_bytes()).collect(); + + self.post_generic_with_consensus_version_and_ssz_body(path, ssz_body, None, fork_name) + .await?; + + Ok(()) + } + /// `POST beacon/pool/bls_to_execution_changes` pub async fn post_beacon_pool_bls_to_execution_changes( &self, diff --git a/validator_client/lighthouse_validator_store/src/lib.rs b/validator_client/lighthouse_validator_store/src/lib.rs index c5bcd88eb1..1b32777678 100644 --- a/validator_client/lighthouse_validator_store/src/lib.rs +++ b/validator_client/lighthouse_validator_store/src/lib.rs @@ -21,11 +21,12 @@ use tracing::{Instrument, debug, error, info, info_span, instrument, warn}; use types::{ AbstractExecPayload, Address, AggregateAndProof, Attestation, BeaconBlock, BlindedPayload, ChainSpec, ContributionAndProof, Domain, Epoch, EthSpec, ExecutionPayloadEnvelope, Fork, - FullPayload, Graffiti, Hash256, SelectionProof, SignedAggregateAndProof, SignedBeaconBlock, - SignedContributionAndProof, SignedExecutionPayloadEnvelope, SignedRoot, - SignedValidatorRegistrationData, SignedVoluntaryExit, Slot, SyncAggregatorSelectionData, - SyncCommitteeContribution, SyncCommitteeMessage, SyncSelectionProof, SyncSubnetId, - ValidatorRegistrationData, VoluntaryExit, graffiti::GraffitiString, + FullPayload, Graffiti, Hash256, PayloadAttestationData, PayloadAttestationMessage, + SelectionProof, SignedAggregateAndProof, SignedBeaconBlock, SignedContributionAndProof, + SignedExecutionPayloadEnvelope, SignedRoot, SignedValidatorRegistrationData, + SignedVoluntaryExit, Slot, SyncAggregatorSelectionData, SyncCommitteeContribution, + SyncCommitteeMessage, SyncSelectionProof, SyncSubnetId, ValidatorRegistrationData, + VoluntaryExit, graffiti::GraffitiString, }; use validator_store::{ AggregateToSign, AttestationToSign, ContributionToSign, DoppelgangerStatus, @@ -1423,6 +1424,37 @@ impl ValidatorStore for LighthouseValidatorS }) } + async fn sign_payload_attestation( + &self, + validator_pubkey: PublicKeyBytes, + data: PayloadAttestationData, + ) -> Result { + let signing_context = + self.signing_context(Domain::PTCAttester, data.slot.epoch(E::slots_per_epoch())); + + let validator_index = self + .validator_index(&validator_pubkey) + .ok_or(ValidatorStoreError::UnknownPubkey(validator_pubkey))?; + + let signing_method = self.doppelganger_bypassed_signing_method(validator_pubkey)?; + + let signature = signing_method + .get_signature::>( + SignableMessage::PayloadAttestationData(&data), + signing_context, + &self.spec, + &self.task_executor, + ) + .await + .map_err(Error::SpecificError)?; + + Ok(PayloadAttestationMessage { + validator_index, + data, + signature, + }) + } + /// Sign an `ExecutionPayloadEnvelope` for Gloas (local building). /// The proposer acts as the builder and signs with the BeaconBuilder domain. async fn sign_execution_payload_envelope( diff --git a/validator_client/signing_method/src/lib.rs b/validator_client/signing_method/src/lib.rs index c132d86c17..2f80fa5761 100644 --- a/validator_client/signing_method/src/lib.rs +++ b/validator_client/signing_method/src/lib.rs @@ -50,6 +50,7 @@ pub enum SignableMessage<'a, E: EthSpec, Payload: AbstractExecPayload = FullP ValidatorRegistration(&'a ValidatorRegistrationData), VoluntaryExit(&'a VoluntaryExit), ExecutionPayloadEnvelope(&'a ExecutionPayloadEnvelope), + PayloadAttestationData(&'a PayloadAttestationData), } impl> SignableMessage<'_, E, Payload> { @@ -72,6 +73,7 @@ impl> SignableMessage<'_, E, Payload SignableMessage::ValidatorRegistration(v) => v.signing_root(domain), SignableMessage::VoluntaryExit(exit) => exit.signing_root(domain), SignableMessage::ExecutionPayloadEnvelope(e) => e.signing_root(domain), + SignableMessage::PayloadAttestationData(d) => d.signing_root(domain), } } } @@ -238,6 +240,9 @@ impl SigningMethod { SignableMessage::ExecutionPayloadEnvelope(e) => { Web3SignerObject::ExecutionPayloadEnvelope(e) } + SignableMessage::PayloadAttestationData(d) => { + Web3SignerObject::PayloadAttestationData(d) + } }; // Determine the Web3Signer message type. diff --git a/validator_client/signing_method/src/web3signer.rs b/validator_client/signing_method/src/web3signer.rs index e6fc8f3ba2..c2b7e06f92 100644 --- a/validator_client/signing_method/src/web3signer.rs +++ b/validator_client/signing_method/src/web3signer.rs @@ -21,6 +21,7 @@ pub enum MessageType { ValidatorRegistration, // TODO(gloas) verify w/ web3signer specs ExecutionPayloadEnvelope, + PayloadAttestation, } #[derive(Debug, PartialEq, Copy, Clone, Serialize)] @@ -78,6 +79,7 @@ pub enum Web3SignerObject<'a, E: EthSpec, Payload: AbstractExecPayload> { ContributionAndProof(&'a ContributionAndProof), ValidatorRegistration(&'a ValidatorRegistrationData), ExecutionPayloadEnvelope(&'a ExecutionPayloadEnvelope), + PayloadAttestationData(&'a PayloadAttestationData), } impl<'a, E: EthSpec, Payload: AbstractExecPayload> Web3SignerObject<'a, E, Payload> { @@ -144,6 +146,7 @@ impl<'a, E: EthSpec, Payload: AbstractExecPayload> Web3SignerObject<'a, E, Pa } Web3SignerObject::ValidatorRegistration(_) => MessageType::ValidatorRegistration, Web3SignerObject::ExecutionPayloadEnvelope(_) => MessageType::ExecutionPayloadEnvelope, + Web3SignerObject::PayloadAttestationData(_) => MessageType::PayloadAttestation, } } } diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index e26d5c3d30..b412db45f6 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -45,6 +45,7 @@ use validator_services::{ block_service::{BlockService, BlockServiceBuilder}, duties_service::{self, DutiesService, DutiesServiceBuilder}, latency_service, + payload_attestation_service::PayloadAttestationService, preparation_service::{PreparationService, PreparationServiceBuilder}, sync_committee_service::SyncCommitteeService, }; @@ -83,6 +84,7 @@ pub struct ProductionValidatorClient { block_service: BlockService, SystemTimeSlotClock>, attestation_service: AttestationService, SystemTimeSlotClock>, sync_committee_service: SyncCommitteeService, SystemTimeSlotClock>, + payload_attestation_service: PayloadAttestationService, SystemTimeSlotClock>, doppelganger_service: Option>, preparation_service: PreparationService, SystemTimeSlotClock>, validator_store: Arc>, @@ -552,12 +554,22 @@ impl ProductionValidatorClient { context.executor.clone(), ); + let payload_attestation_service = PayloadAttestationService::new( + duties_service.clone(), + validator_store.clone(), + slot_clock.clone(), + beacon_nodes.clone(), + context.executor.clone(), + context.eth2_config.spec.clone(), + ); + Ok(Self { context, duties_service, block_service, attestation_service, sync_committee_service, + payload_attestation_service, doppelganger_service, preparation_service, validator_store, @@ -629,6 +641,13 @@ impl ProductionValidatorClient { .start_update_service(&self.context.eth2_config.spec) .map_err(|e| format!("Unable to start sync committee service: {}", e))?; + if self.context.eth2_config.spec.is_gloas_scheduled() { + self.payload_attestation_service + .clone() + .start_update_service() + .map_err(|e| format!("Unable to start payload attestation service: {}", e))?; + } + self.preparation_service .clone() .start_update_service(&self.context.eth2_config.spec) diff --git a/validator_client/validator_services/src/lib.rs b/validator_client/validator_services/src/lib.rs index 3b8bd9ae14..0169335a7f 100644 --- a/validator_client/validator_services/src/lib.rs +++ b/validator_client/validator_services/src/lib.rs @@ -3,6 +3,7 @@ pub mod block_service; pub mod duties_service; pub mod latency_service; pub mod notifier_service; +pub mod payload_attestation_service; pub mod preparation_service; pub mod sync; pub mod sync_committee_service; diff --git a/validator_client/validator_services/src/payload_attestation_service.rs b/validator_client/validator_services/src/payload_attestation_service.rs new file mode 100644 index 0000000000..2f3ca8bed2 --- /dev/null +++ b/validator_client/validator_services/src/payload_attestation_service.rs @@ -0,0 +1,238 @@ +use crate::duties_service::DutiesService; +use beacon_node_fallback::BeaconNodeFallback; +use logging::crit; +use slot_clock::SlotClock; +use std::ops::Deref; +use std::sync::Arc; +use task_executor::TaskExecutor; +use tokio::time::sleep; +use tracing::{debug, error, info}; +use types::{ChainSpec, EthSpec}; +use validator_store::ValidatorStore; + +pub struct Inner { + duties_service: Arc>, + validator_store: Arc, + slot_clock: T, + beacon_nodes: Arc>, + executor: TaskExecutor, + chain_spec: Arc, +} + +pub struct PayloadAttestationService { + inner: Arc>, +} + +impl Clone for PayloadAttestationService { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} + +impl Deref for PayloadAttestationService { + type Target = Inner; + + fn deref(&self) -> &Self::Target { + self.inner.deref() + } +} + +impl PayloadAttestationService { + pub fn new( + duties_service: Arc>, + validator_store: Arc, + slot_clock: T, + beacon_nodes: Arc>, + executor: TaskExecutor, + chain_spec: Arc, + ) -> Self { + Self { + inner: Arc::new(Inner { + duties_service, + validator_store, + slot_clock, + beacon_nodes, + executor, + chain_spec, + }), + } + } + + pub fn start_update_service(self) -> Result<(), String> { + let slot_duration = self.chain_spec.get_slot_duration(); + let payload_attestation_due = self.chain_spec.get_payload_attestation_due(); + + info!( + payload_attestation_due_ms = payload_attestation_due.as_millis(), + "Payload attestation service started" + ); + + let executor = self.executor.clone(); + + let interval_fut = async move { + loop { + let Some(duration_to_next_slot) = self.slot_clock.duration_to_next_slot() else { + error!("Failed to read slot clock"); + sleep(slot_duration).await; + continue; + }; + + let Some(current_slot) = self.slot_clock.now() else { + error!("Failed to read slot clock after trigger"); + continue; + }; + + if !self + .chain_spec + .fork_name_at_slot::(current_slot) + .gloas_enabled() + { + let duration_to_next_epoch = self + .slot_clock + .duration_to_next_epoch(S::E::slots_per_epoch()) + .unwrap_or_else(|| { + self.chain_spec.get_slot_duration() * S::E::slots_per_epoch() as u32 + }); + sleep(duration_to_next_epoch).await; + continue; + } + + sleep(duration_to_next_slot + payload_attestation_due).await; + + let service = self.clone(); + self.executor.spawn( + async move { + service.produce_and_publish(current_slot).await; + }, + "payload_attestation_producer", + ); + } + }; + + executor.spawn(interval_fut, "payload_attestation_service"); + Ok(()) + } + + async fn produce_and_publish(&self, slot: types::Slot) { + let duties = self.duties_service.get_ptc_duties_for_slot(slot); + + if duties.is_empty() { + return; + } + + debug!( + %slot, + duty_count = duties.len(), + "Producing payload attestations" + ); + + let attestation_data = match self + .beacon_nodes + .first_success(|beacon_node| async move { + beacon_node + .get_validator_payload_attestation_data(slot) + .await + .map_err(|e| format!("Failed to get payload attestation data: {e:?}")) + .map(|resp| resp.into_data()) + }) + .await + { + Ok(data) => data, + Err(e) => { + crit!( + error = %e, + %slot, + "Failed to produce payload attestation data" + ); + return; + } + }; + + debug!( + %slot, + beacon_block_root = ?attestation_data.beacon_block_root, + payload_present = attestation_data.payload_present, + "Received payload attestation data" + ); + + let mut messages = Vec::with_capacity(duties.len()); + + for duty in &duties { + match self + .validator_store + .sign_payload_attestation(duty.pubkey, attestation_data.clone()) + .await + { + Ok(message) => { + messages.push(message); + } + Err(e) => { + crit!( + error = ?e, + validator = ?duty.pubkey, + %slot, + "Failed to sign payload attestation" + ); + } + } + } + + if messages.is_empty() { + return; + } + + let count = messages.len(); + let fork_name = self.chain_spec.fork_name_at_slot::(slot); + let result = self + .beacon_nodes + .first_success(|beacon_node| { + let messages = messages.clone(); + async move { + beacon_node + .post_beacon_pool_payload_attestations_ssz(&messages, fork_name) + .await + .map_err(|e| format!("Failed to publish payload attestations (SSZ): {e:?}")) + } + }) + .await; + + let result = match result { + Ok(()) => Ok(()), + Err(_) => { + debug!(%slot, "SSZ publish failed, falling back to JSON"); + self.beacon_nodes + .first_success(|beacon_node| { + let messages = messages.clone(); + async move { + beacon_node + .post_beacon_pool_payload_attestations(&messages, fork_name) + .await + .map_err(|e| { + format!("Failed to publish payload attestations (JSON): {e:?}") + }) + } + }) + .await + } + }; + + match result { + Ok(()) => { + info!( + %slot, + %count, + "Successfully published payload attestations" + ); + } + Err(e) => { + crit!( + error = %e, + %slot, + "Failed to publish payload attestations" + ); + } + } + } +} diff --git a/validator_client/validator_store/src/lib.rs b/validator_client/validator_store/src/lib.rs index da0b33de18..4e5b415a41 100644 --- a/validator_client/validator_store/src/lib.rs +++ b/validator_client/validator_store/src/lib.rs @@ -7,10 +7,11 @@ use std::future::Future; use std::sync::Arc; use types::{ Address, Attestation, AttestationError, BlindedBeaconBlock, Epoch, EthSpec, - ExecutionPayloadEnvelope, Graffiti, Hash256, SelectionProof, SignedAggregateAndProof, - SignedBlindedBeaconBlock, SignedContributionAndProof, SignedExecutionPayloadEnvelope, - SignedValidatorRegistrationData, Slot, SyncCommitteeContribution, SyncCommitteeMessage, - SyncSelectionProof, SyncSubnetId, ValidatorRegistrationData, + ExecutionPayloadEnvelope, Graffiti, Hash256, PayloadAttestationData, PayloadAttestationMessage, + SelectionProof, SignedAggregateAndProof, SignedBlindedBeaconBlock, SignedContributionAndProof, + SignedExecutionPayloadEnvelope, SignedValidatorRegistrationData, Slot, + SyncCommitteeContribution, SyncCommitteeMessage, SyncSelectionProof, SyncSubnetId, + ValidatorRegistrationData, }; #[derive(Debug, PartialEq, Clone)] @@ -205,6 +206,13 @@ pub trait ValidatorStore: Send + Sync { envelope: ExecutionPayloadEnvelope, ) -> impl Future, Error>> + Send; + /// Sign a `PayloadAttestationData` for the PTC. + fn sign_payload_attestation( + &self, + validator_pubkey: PublicKeyBytes, + data: PayloadAttestationData, + ) -> impl Future>> + Send; + /// Returns `ProposalData` for the provided `pubkey` if it exists in `InitializedValidators`. /// `ProposalData` fields include defaulting logic described in `get_fee_recipient_defaulting`, /// `get_gas_limit_defaulting`, and `get_builder_proposals_defaulting`. From 949c027dfd37408784216b2c4e5e727e6ad571fe Mon Sep 17 00:00:00 2001 From: Mac L Date: Tue, 28 Apr 2026 11:01:13 +0400 Subject: [PATCH 06/12] Add method to `Hash256` to display shortened hashes (#9118) #6689 Inspired by the initial implementation of #9108, credit to @chong-he. This adds an extension trait to `Hash256` and add a `short` method to provide smaller formatted hashes for logging. Co-Authored-By: Mac L --- beacon_node/client/src/notifier.rs | 6 ++--- .../types/src/core/execution_block_hash.rs | 13 ++++------ consensus/types/src/core/mod.rs | 26 +++++++++++++++++++ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/beacon_node/client/src/notifier.rs b/beacon_node/client/src/notifier.rs index 0d73a6bf7a..bdb4228765 100644 --- a/beacon_node/client/src/notifier.rs +++ b/beacon_node/client/src/notifier.rs @@ -360,7 +360,7 @@ pub fn spawn_notifier( let block_info = if current_slot > head_slot { " … empty".to_string() } else { - head_root.to_string() + head_root.short().to_string() }; let block_hash = match beacon_chain.canonical_head.head_execution_status() { @@ -393,7 +393,7 @@ pub fn spawn_notifier( info!( peers = peer_count_pretty(connected_peer_count), exec_hash = block_hash, - finalized_root = %finalized_checkpoint.root, + finalized_root = %finalized_checkpoint.root.short(), finalized_epoch = %finalized_checkpoint.epoch, epoch = %current_epoch, block = block_info, @@ -404,7 +404,7 @@ pub fn spawn_notifier( metrics::set_gauge(&metrics::IS_SYNCED, 0); info!( peers = peer_count_pretty(connected_peer_count), - finalized_root = %finalized_checkpoint.root, + finalized_root = %finalized_checkpoint.root.short(), finalized_epoch = %finalized_checkpoint.epoch, %head_slot, %current_slot, diff --git a/consensus/types/src/core/execution_block_hash.rs b/consensus/types/src/core/execution_block_hash.rs index cbacf7cf74..71e63727ee 100644 --- a/consensus/types/src/core/execution_block_hash.rs +++ b/consensus/types/src/core/execution_block_hash.rs @@ -5,7 +5,10 @@ use rand::RngCore; use serde::{Deserialize, Serialize}; use ssz::{Decode, DecodeError, Encode}; -use crate::{core::Hash256, test_utils::TestRandom}; +use crate::{ + core::{Hash256, Hash256Ext}, + test_utils::TestRandom, +}; #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Default, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)] @@ -20,13 +23,7 @@ impl fmt::Debug for ExecutionBlockHash { impl fmt::Display for ExecutionBlockHash { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let hash = format!("{}", self.0); - write!( - f, - "{}…{}", - &hash[..6], - &hash[hash.len().saturating_sub(4)..] - ) + self.0.short().fmt(f) } } diff --git a/consensus/types/src/core/mod.rs b/consensus/types/src/core/mod.rs index 4e583fbc67..f722ac5191 100644 --- a/consensus/types/src/core/mod.rs +++ b/consensus/types/src/core/mod.rs @@ -49,3 +49,29 @@ pub type Hash64 = alloy_primitives::B64; pub type Address = alloy_primitives::Address; pub type VersionedHash = Hash256; pub type MerkleProof = Vec; + +/// Extension trait for `Hash256` to allow us to implement additional methods on it. +pub trait Hash256Ext { + fn short(&self) -> ShortenedHash<'_>; +} + +impl Hash256Ext for Hash256 { + fn short(&self) -> ShortenedHash<'_> { + ShortenedHash(self) + } +} + +pub struct ShortenedHash<'a>(&'a Hash256); + +impl<'a> std::fmt::Display for ShortenedHash<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let hash: &[u8; 32] = self.0.as_ref(); + write!( + f, + // Format as hex, padded to 2 digits per byte. + // This outputs a consistent "0x1234...abcd" format. + "0x{:02x}{:02x}…{:02x}{:02x}", + hash[0], hash[1], hash[30], hash[31] + ) + } +} From 919c996c18911a541493bb2c30571aa54a69aeae Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 28 Apr 2026 10:15:10 +0200 Subject: [PATCH 07/12] Fix spurious re-org logs on ePBS payload status changes (#9191) Co-Authored-By: Jimmy Chen --- beacon_node/beacon_chain/src/canonical_head.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/beacon_node/beacon_chain/src/canonical_head.rs b/beacon_node/beacon_chain/src/canonical_head.rs index 04c18c88e0..0e6515ebbd 100644 --- a/beacon_node/beacon_chain/src/canonical_head.rs +++ b/beacon_node/beacon_chain/src/canonical_head.rs @@ -796,9 +796,9 @@ impl BeaconChain { let new_snapshot = &new_cached_head.snapshot; let old_snapshot = &old_cached_head.snapshot; - // If the head changed, perform some updates. - if (new_snapshot.beacon_block_root != old_snapshot.beacon_block_root - || new_payload_status != old_payload_status) + // Only run on head *block* changes - payload status changes only need the + // `cached_head` update above, not re-org detection or event emission. + if new_snapshot.beacon_block_root != old_snapshot.beacon_block_root && let Err(e) = self.after_new_head(&old_cached_head, &new_cached_head, new_head_proto_block) { From 280e2f1d53fde00955f9868a328f4183289420cb Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 28 Apr 2026 10:59:01 +0200 Subject: [PATCH 08/12] Wire up ePBS SSE events and fix envelope availability (#9199) Co-Authored-By: Jimmy Chen --- .../gossip_verified_payload_attestation.rs | 22 ++- .../gossip_verified_bid.rs | 14 ++ .../payload_envelope_verification/import.rs | 16 +- .../src/payload_envelope_verification/mod.rs | 32 +++- beacon_node/beacon_chain/tests/events.rs | 178 +++++++++++++++++- 5 files changed, 251 insertions(+), 11 deletions(-) diff --git a/beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs b/beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs index 2d9fce812e..c36c73b344 100644 --- a/beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs +++ b/beacon_node/beacon_chain/src/payload_attestation_verification/gossip_verified_payload_attestation.rs @@ -6,6 +6,7 @@ use crate::validator_pubkey_cache::ValidatorPubkeyCache; use crate::{BeaconChain, BeaconChainError, BeaconChainTypes, metrics}; use bls::AggregateSignature; use educe::Educe; +use eth2::types::{EventKind, ForkVersionedResponse}; use parking_lot::RwLock; use safe_arith::SafeArith; use slot_clock::SlotClock; @@ -216,9 +217,24 @@ impl BeaconChain { let _timer = metrics::start_timer(&metrics::PAYLOAD_ATTESTATION_GOSSIP_VERIFICATION_TIMES); let ctx = self.payload_attestation_gossip_context(); - VerifiedPayloadAttestationMessage::new(payload_attestation_message, &ctx).inspect(|_| { - metrics::inc_counter(&metrics::PAYLOAD_ATTESTATION_PROCESSING_SUCCESSES); - }) + VerifiedPayloadAttestationMessage::new(payload_attestation_message, &ctx).inspect( + |verified| { + metrics::inc_counter(&metrics::PAYLOAD_ATTESTATION_PROCESSING_SUCCESSES); + + if let Some(event_handler) = self.event_handler.as_ref() + && event_handler.has_payload_attestation_message_subscribers() + { + let msg = verified.payload_attestation_message(); + event_handler.register(EventKind::PayloadAttestationMessage(Box::new( + ForkVersionedResponse { + version: self.spec.fork_name_at_slot::(msg.data.slot), + metadata: Default::default(), + data: msg.clone(), + }, + ))); + } + }, + ) } } 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 91945896df..1f3f074598 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 @@ -6,6 +6,7 @@ use crate::{ proposer_preferences_verification::proposer_preference_cache::GossipVerifiedProposerPreferenceCache, }; use educe::Educe; +use eth2::types::{EventKind, ForkVersionedResponse}; use slot_clock::SlotClock; use state_processing::signature_sets::{ execution_payload_bid_signature_set, get_builder_pubkey_from_state, @@ -233,6 +234,19 @@ impl BeaconChain { %parent_block_root, "Successfully verified gossip payload bid" ); + + if let Some(event_handler) = self.event_handler.as_ref() + && event_handler.has_execution_payload_bid_subscribers() + { + event_handler.register(EventKind::ExecutionPayloadBid(Box::new( + ForkVersionedResponse { + version: self.spec.fork_name_at_slot::(slot), + metadata: Default::default(), + data: (*verified.signed_bid).clone(), + }, + ))); + } + Ok(verified) } Err(e) => { 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 5a6d3a1b7d..b40e8337fb 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/import.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use std::time::Duration; -use eth2::types::{EventKind, SseExecutionPayload}; +use eth2::types::{EventKind, SseExecutionPayload, SseExecutionPayloadAvailable}; use fork_choice::PayloadVerificationStatus; use slot_clock::SlotClock; use store::StoreOp; @@ -182,6 +182,7 @@ impl BeaconChain { signed_envelope, import_data, payload_verification_outcome, + self.spec.clone(), )) } @@ -362,5 +363,18 @@ impl BeaconChain { execution_optimistic: payload_verification_status.is_optimistic(), })); } + + // TODO(gloas): once the DA checker handles envelopes, this event should also be + // emitted from the DA resolution path (similar to `process_availability` for blocks). + if let Some(event_handler) = self.event_handler.as_ref() + && event_handler.has_execution_payload_available_subscribers() + { + event_handler.register(EventKind::ExecutionPayloadAvailable( + SseExecutionPayloadAvailable { + slot: envelope_slot, + block_root, + }, + )); + } } } 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 51fc3f235d..b153a3cd6a 100644 --- a/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs +++ b/beacon_node/beacon_chain/src/payload_envelope_verification/mod.rs @@ -60,6 +60,22 @@ pub struct AvailableEnvelope { } impl AvailableEnvelope { + pub fn new( + execution_block_hash: ExecutionBlockHash, + envelope: Arc>, + columns: DataColumnSidecarList, + columns_available_timestamp: Option, + spec: Arc, + ) -> Self { + Self { + execution_block_hash, + envelope, + columns, + columns_available_timestamp, + spec, + } + } + pub fn message(&self) -> &ExecutionPayloadEnvelope { &self.envelope.message } @@ -104,9 +120,10 @@ pub struct EnvelopeProcessingSnapshot { /// fully available. /// 2. `AvailabilityPending`: This envelope hasn't received all required blobs to consider it /// fully available. +#[allow(dead_code)] pub enum ExecutedEnvelope { Available(AvailableExecutedEnvelope), - // TODO(gloas) implement availability pending + // TODO(gloas): check data column availability via DA checker AvailabilityPending(), } @@ -115,6 +132,7 @@ impl ExecutedEnvelope { envelope: MaybeAvailableEnvelope, import_data: EnvelopeImportData, payload_verification_outcome: PayloadVerificationOutcome, + spec: Arc, ) -> Self { match envelope { MaybeAvailableEnvelope::Available(available_envelope) => { @@ -124,11 +142,15 @@ impl ExecutedEnvelope { payload_verification_outcome, )) } - // TODO(gloas) implement availability pending + // TODO(gloas): check data column availability via DA checker MaybeAvailableEnvelope::AvailabilityPending { - block_hash: _, - envelope: _, - } => Self::AvailabilityPending(), + block_hash, + envelope, + } => Self::Available(AvailableExecutedEnvelope::new( + AvailableEnvelope::new(block_hash, envelope, vec![], None, spec), + import_data, + payload_verification_outcome, + )), } } } diff --git a/beacon_node/beacon_chain/tests/events.rs b/beacon_node/beacon_chain/tests/events.rs index 5305965f0f..e943514c4e 100644 --- a/beacon_node/beacon_chain/tests/events.rs +++ b/beacon_node/beacon_chain/tests/events.rs @@ -10,8 +10,8 @@ use std::sync::Arc; use types::data::FixedBlobSidecarList; use types::test_utils::TestRandom; use types::{ - BlobSidecar, DataColumnSidecar, DataColumnSidecarFulu, DataColumnSidecarGloas, EthSpec, - MinimalEthSpec, Slot, + BlobSidecar, DataColumnSidecar, DataColumnSidecarFulu, DataColumnSidecarGloas, Domain, EthSpec, + MinimalEthSpec, PayloadAttestationData, PayloadAttestationMessage, SignedRoot, Slot, }; type E = MinimalEthSpec; @@ -258,3 +258,177 @@ async fn head_event_on_block_import() { panic!("Expected Head event, got {:?}", head_event); } } + +/// Verifies that `execution_payload_gossip` fires at gossip verification time, and +/// `execution_payload` + `execution_payload_available` fire at import time. +#[tokio::test] +async fn execution_payload_envelope_events() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + + let harness = BeaconChainHarness::builder(E::default()) + .default_spec() + .deterministic_keypairs(64) + .fresh_ephemeral_store() + .mock_execution_layer() + .build(); + + harness.extend_to_slot(Slot::new(1)).await; + + let state = harness.get_current_state(); + let target_slot = Slot::new(2); + harness.advance_slot(); + let (block_contents, opt_envelope, _new_state) = + harness.make_block_with_envelope(state, target_slot).await; + + let block_root = block_contents.0.canonical_root(); + + harness + .process_block(target_slot, block_root, block_contents) + .await + .expect("block should be processed"); + + let signed_envelope = opt_envelope.expect("Gloas block should produce an envelope"); + + let event_handler = harness.chain.event_handler.as_ref().unwrap(); + let mut gossip_receiver = event_handler.subscribe_execution_payload_gossip(); + let mut payload_receiver = event_handler.subscribe_execution_payload(); + let mut available_receiver = event_handler.subscribe_execution_payload_available(); + + // Stage 1: gossip verification fires execution_payload_gossip only. + let gossip_verified = harness + .chain + .verify_envelope_for_gossip(Arc::new(signed_envelope)) + .await + .expect("envelope gossip verification should succeed"); + + let gossip_event = gossip_receiver + .try_recv() + .expect("should receive execution_payload_gossip after gossip verification"); + if let EventKind::ExecutionPayloadGossip(sse) = gossip_event { + assert_eq!(sse.slot, target_slot); + assert_eq!(sse.block_root, block_root); + } else { + panic!( + "Expected ExecutionPayloadGossip event, got {:?}", + gossip_event + ); + } + assert!(payload_receiver.try_recv().is_err()); + assert!(available_receiver.try_recv().is_err()); + + // Stage 2: import fires execution_payload and execution_payload_available. + harness + .chain + .process_execution_payload_envelope( + block_root, + gossip_verified, + beacon_chain::NotifyExecutionLayer::Yes, + types::BlockImportSource::Gossip, + #[allow(clippy::result_large_err)] + || Ok(()), + ) + .await + .expect("envelope import should succeed"); + + let payload_event = payload_receiver + .try_recv() + .expect("should receive execution_payload after import"); + if let EventKind::ExecutionPayload(sse) = payload_event { + assert_eq!(sse.slot, target_slot); + assert_eq!(sse.block_root, block_root); + } else { + panic!("Expected ExecutionPayload event, got {:?}", payload_event); + } + + let available_event = available_receiver + .try_recv() + .expect("should receive execution_payload_available after import"); + if let EventKind::ExecutionPayloadAvailable(sse) = available_event { + assert_eq!(sse.slot, target_slot); + assert_eq!(sse.block_root, block_root); + } else { + panic!( + "Expected ExecutionPayloadAvailable event, got {:?}", + available_event + ); + } + + assert!( + gossip_receiver.try_recv().is_err(), + "no extra gossip events should fire during import" + ); +} + +/// Verifies that a `payload_attestation_message` event is emitted when a payload attestation +/// message passes gossip verification. +#[tokio::test] +async fn payload_attestation_message_event_on_gossip_verification() { + if !fork_name_from_env().is_some_and(|f| f.gloas_enabled()) { + return; + } + + let harness = BeaconChainHarness::builder(E::default()) + .default_spec() + .deterministic_keypairs(64) + .fresh_ephemeral_store() + .mock_execution_layer() + .build(); + + // Advance chain to have a valid head block. + let target_slot = Slot::new(1); + harness.extend_to_slot(target_slot).await; + + let head = harness.chain.canonical_head.cached_head(); + let head_state = &head.snapshot.beacon_state; + + // Get a PTC member for this slot. + let ptc = head_state + .get_ptc(target_slot, &harness.spec) + .expect("should get PTC"); + let validator_index = *ptc.0.first().expect("PTC should have at least one member") as u64; + + // Sign a payload attestation. + let target_epoch = target_slot.epoch(E::slots_per_epoch()); + let domain = harness.spec.get_domain( + target_epoch, + Domain::PTCAttester, + &head_state.fork(), + head_state.genesis_validators_root(), + ); + let data = PayloadAttestationData { + beacon_block_root: head.head_block_root(), + slot: target_slot, + payload_present: true, + blob_data_available: true, + }; + let message = data.signing_root(domain); + let signature = harness.validator_keypairs[validator_index as usize] + .sk + .sign(message); + let msg = PayloadAttestationMessage { + validator_index, + data: data.clone(), + signature: signature.clone(), + }; + + // Subscribe before verification. + let event_handler = harness.chain.event_handler.as_ref().unwrap(); + let mut receiver = event_handler.subscribe_payload_attestation_message(); + + // Verify the attestation through the gossip path. + harness + .chain + .verify_payload_attestation_message_for_gossip(msg) + .expect("verification should succeed"); + + // Assert the event was emitted. + let event = receiver.try_recv().expect("should receive event"); + if let EventKind::PayloadAttestationMessage(versioned) = event { + assert_eq!(versioned.data.validator_index, validator_index); + assert_eq!(versioned.data.data, data); + } else { + panic!("Expected PayloadAttestationMessage event, got {:?}", event); + } +} From e35a67130341af2005f009cdfc253fb4cc40ae73 Mon Sep 17 00:00:00 2001 From: Mac L Date: Tue, 28 Apr 2026 12:59:07 +0400 Subject: [PATCH 09/12] Fix validator manager compilation (#9187) Currently, running `cargo check -p validator_manager` fails due to missing features. Although the `validator_manager` will almost always be called through the Lighthouse binary which will enable the required features, it is still good hygiene to ensure all workspace crates can compile standalone. Add the `lighthouse` feature to the `eth2` dependency in `validator_manager` Co-Authored-By: Mac L --- validator_manager/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validator_manager/Cargo.toml b/validator_manager/Cargo.toml index d0155698b4..7dabd5445c 100644 --- a/validator_manager/Cargo.toml +++ b/validator_manager/Cargo.toml @@ -11,7 +11,7 @@ clap = { workspace = true } clap_utils = { workspace = true } educe = { workspace = true } environment = { workspace = true } -eth2 = { workspace = true } +eth2 = { workspace = true, features = ["lighthouse"] } eth2_network_config = { workspace = true } eth2_wallet = { workspace = true } ethereum_serde_utils = { workspace = true } From d8790f66772e05b49a1a4d815810de121d6af094 Mon Sep 17 00:00:00 2001 From: Jimmy Chen Date: Tue, 28 Apr 2026 12:49:28 +0200 Subject: [PATCH 10/12] Add payload attestation to op pool and pack into block (#9180) Store gossip-verified `PayloadAttestationMessage`s in the operation pool and pack them into the block body at during block production. Built on top of #9145. Co-Authored-By: Jimmy Chen --- beacon_node/beacon_chain/src/beacon_chain.rs | 12 + .../src/block_production/gloas.rs | 42 ++- .../gossip_methods.rs | 37 +- beacon_node/operation_pool/src/lib.rs | 315 +++++++++++++++++- beacon_node/operation_pool/src/persistence.rs | 1 + .../src/payload_attestation_service.rs | 7 +- 6 files changed, 386 insertions(+), 28 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index cf5afb089a..9da64888c2 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -61,6 +61,7 @@ use crate::observed_data_sidecars::ObservedDataSidecars; use crate::observed_operations::{ObservationOutcome, ObservedOperations}; use crate::observed_slashable::ObservedSlashable; use crate::partial_data_column_assembler::PartialMergeResult; +use crate::payload_attestation_verification::VerifiedPayloadAttestationMessage; use crate::payload_bid_verification::payload_bid_cache::GossipVerifiedPayloadBidCache; #[cfg(not(test))] use crate::payload_envelope_streamer::{EnvelopeRequestSource, launch_payload_envelope_stream}; @@ -2328,6 +2329,17 @@ impl BeaconChain { .map_err(Into::into) } + /// Add a verified payload attestation message to the operation pool for block inclusion. + pub fn add_payload_attestation_to_pool( + &self, + verified: &VerifiedPayloadAttestationMessage, + ) -> Result<(), Error> { + self.op_pool + .insert_payload_attestation_message(verified.payload_attestation_message().clone()) + .map_err(Error::OpPoolError)?; + Ok(()) + } + /// Accepts some `SyncCommitteeMessage` from the network and attempts to verify it, returning `Ok(_)` if /// it is valid to be (re)broadcast on the gossip network. pub fn verify_sync_committee_message_for_gossip( diff --git a/beacon_node/beacon_chain/src/block_production/gloas.rs b/beacon_node/beacon_chain/src/block_production/gloas.rs index 9b3fc2806e..4bc4b9862c 100644 --- a/beacon_node/beacon_chain/src/block_production/gloas.rs +++ b/beacon_node/beacon_chain/src/block_production/gloas.rs @@ -9,9 +9,10 @@ use execution_layer::{ use fork_choice::PayloadStatus; use operation_pool::CompactAttestationRef; use ssz::Encode; -use state_processing::common::get_attesting_indices_from_state; +use state_processing::common::{get_attesting_indices_from_state, get_indexed_payload_attestation}; use state_processing::envelope_processing::verify_execution_payload_envelope; use state_processing::epoch_cache::initialize_epoch_cache; +use state_processing::per_block_processing::is_valid_indexed_payload_attestation; use state_processing::per_block_processing::{ apply_parent_execution_payload, compute_timestamp_at_slot, get_expected_withdrawals, verify_attestation_for_block_inclusion, @@ -319,6 +320,11 @@ impl BeaconChain { .map_err(BlockProductionError::OpPoolError)? }; + let mut payload_attestations = self + .op_pool + .get_payload_attestations(&state, parent_root, &self.spec) + .map_err(BlockProductionError::OpPoolError)?; + // If paranoid mode is enabled re-check the signatures of every included message. // This will be a lot slower but guards against bugs in block production and can be // quickly rolled out without a release. @@ -343,6 +349,35 @@ impl BeaconChain { .is_ok() }); + payload_attestations.retain(|att| { + match get_indexed_payload_attestation(&state, att, &self.spec) { + Ok(indexed) => is_valid_indexed_payload_attestation( + &state, + &indexed, + VerifySignatures::True, + &self.spec, + ) + .map_err(|e| { + warn!( + err = ?e, + block_slot = %state.slot(), + ?att, + "Attempted to include a payload attestation with invalid signature" + ); + }) + .is_ok(), + Err(e) => { + warn!( + err = ?e, + block_slot = %state.slot(), + ?att, + "Failed to index payload attestation for verification" + ); + false + } + } + }); + proposer_slashings.retain(|slashing| { slashing .clone() @@ -386,8 +421,6 @@ impl BeaconChain { }) .is_ok() }); - - // TODO(gloas) verify payload attestation signature here as well } let attester_slashings = attester_slashings @@ -434,8 +467,7 @@ impl BeaconChain { deposits, voluntary_exits, sync_aggregate, - // TODO(gloas) need to implement payload attestations - payload_attestations: vec![], + payload_attestations, bls_to_execution_changes, }, state, 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 4083b1a3af..29306c198d 100644 --- a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs @@ -140,11 +140,6 @@ struct RejectedAggregate { error: AttnError, } -struct RejectedPayloadAttestation { - payload_attestation_message: Box, - error: PayloadAttestationError, -} - /// Data for an aggregated or unaggregated attestation that failed verification. enum FailedAtt { Unaggregate { @@ -4111,25 +4106,20 @@ impl NetworkBeaconProcessor { peer_id: PeerId, payload_attestation_message: Box, ) { - let result = match self + let message_slot = payload_attestation_message.data.slot; + let result = self .chain - .verify_payload_attestation_message_for_gossip(*payload_attestation_message.clone()) - { - Ok(verified) => Ok(verified), - Err(error) => Err(RejectedPayloadAttestation { - payload_attestation_message: payload_attestation_message.clone(), - error, - }), - }; + .verify_payload_attestation_message_for_gossip(*payload_attestation_message); - self.process_gossip_payload_attestation_result(result, message_id, peer_id); + self.process_gossip_payload_attestation_result(result, message_id, peer_id, message_slot); } fn process_gossip_payload_attestation_result( self: &Arc, - result: Result, RejectedPayloadAttestation>, + result: Result, PayloadAttestationError>, message_id: MessageId, peer_id: PeerId, + message_slot: Slot, ) { match result { Ok(verified) => { @@ -4156,16 +4146,21 @@ impl NetworkBeaconProcessor { ), } } + + if let Err(e) = self.chain.add_payload_attestation_to_pool(&verified) { + warn!( + reason = ?e, + %peer_id, + "Failed to add payload attestation to pool" + ); + } } - Err(RejectedPayloadAttestation { - payload_attestation_message, - error, - }) => { + Err(error) => { self.handle_payload_attestation_verification_failure( peer_id, message_id, error, - payload_attestation_message.data.slot, + message_slot, ); } } diff --git a/beacon_node/operation_pool/src/lib.rs b/beacon_node/operation_pool/src/lib.rs index 4b815704d9..de5fe9a098 100644 --- a/beacon_node/operation_pool/src/lib.rs +++ b/beacon_node/operation_pool/src/lib.rs @@ -23,10 +23,12 @@ use crate::attestation_storage::{AttestationMap, CheckpointKey}; use crate::bls_to_execution_changes::BlsToExecutionChanges; use crate::sync_aggregate_id::SyncAggregateId; use attester_slashing::AttesterSlashingMaxCover; +use bls::AggregateSignature; use max_cover::maximum_cover; use parking_lot::{RwLock, RwLockWriteGuard}; use rand::rng; use rand::seq::SliceRandom; +use ssz::BitVector; use state_processing::per_block_processing::errors::AttestationValidationError; use state_processing::per_block_processing::{ VerifySignatures, get_slashable_indices_modular, verify_exit, @@ -38,7 +40,8 @@ use std::ptr; use typenum::Unsigned; use types::{ AbstractExecPayload, Attestation, AttestationData, AttesterSlashing, BeaconState, - BeaconStateError, ChainSpec, Epoch, EthSpec, ProposerSlashing, SignedBeaconBlock, + BeaconStateError, ChainSpec, Epoch, EthSpec, Hash256, PayloadAttestation, + PayloadAttestationData, PayloadAttestationMessage, ProposerSlashing, SignedBeaconBlock, SignedBlsToExecutionChange, SignedVoluntaryExit, Slot, SyncAggregate, SyncAggregateError, SyncCommitteeContribution, Validator, }; @@ -59,6 +62,9 @@ pub struct OperationPool { voluntary_exits: RwLock>>, /// Map from credential changing validator to their position in the queue. bls_to_execution_changes: RwLock>, + /// Map from payload attestation data to individual messages for aggregation at block production. + payload_attestation_messages: + RwLock>>, /// Reward cache for accelerating attestation packing. reward_cache: RwLock, _phantom: PhantomData, @@ -78,6 +84,8 @@ pub enum OpPoolError { IncorrectOpPoolVariant, EpochCacheNotInitialized, EpochCacheError(EpochCacheError), + GetPtcError(BeaconStateError), + PayloadAttestationBitError, } #[derive(Default)] @@ -193,6 +201,100 @@ impl OperationPool { }); } + /// Insert a validated `PayloadAttestationMessage` into the pool. + pub fn insert_payload_attestation_message( + &self, + message: PayloadAttestationMessage, + ) -> Result<(), OpPoolError> { + let mut messages = self.payload_attestation_messages.write(); + let entry = messages.entry(message.data.clone()).or_default(); + if !entry + .iter() + .any(|m| m.validator_index == message.validator_index) + { + entry.push(message); + } + Ok(()) + } + + /// Build `PayloadAttestation`s from stored messages for block production. + /// + /// `parent_block_root` is the root of the parent block (the block PTC members attested to). + /// Returns one `PayloadAttestation` per distinct `PayloadAttestationData`. With two boolean + /// fields this yields at most 4, capped to `MaxPayloadAttestations`. + pub fn get_payload_attestations( + &self, + state: &BeaconState, + parent_block_root: Hash256, + spec: &ChainSpec, + ) -> Result>, OpPoolError> { + let target_slot = state.slot().saturating_sub(1u64); + + let ptc = state + .get_ptc(target_slot, spec) + .map_err(OpPoolError::GetPtcError)?; + + let messages = self.payload_attestation_messages.read(); + let mut result = Vec::new(); + + for (data, msgs) in messages.iter() { + if data.slot != target_slot || data.beacon_block_root != parent_block_root { + continue; + } + + let mut aggregation_bits = BitVector::new(); + let mut aggregate_sig = AggregateSignature::infinity(); + + for msg in msgs { + if let Some(pos) = ptc + .0 + .iter() + .position(|&idx| idx == msg.validator_index as usize) + && !aggregation_bits.get(pos).unwrap_or(false) + { + aggregation_bits + .set(pos, true) + .map_err(|_| OpPoolError::PayloadAttestationBitError)?; + aggregate_sig.add_assign(&msg.signature); + } + } + + if aggregation_bits.num_set_bits() > 0 { + result.push(PayloadAttestation { + aggregation_bits, + data: data.clone(), + signature: aggregate_sig, + }); + } + } + + // Prefer most participation and cap by `max_payload_attestations` + result.sort_by(|a, b| { + b.aggregation_bits + .num_set_bits() + .cmp(&a.aggregation_bits.num_set_bits()) + }); + result.truncate(E::max_payload_attestations()); + + Ok(result) + } + + /// Remove payload attestation messages that are too old for block inclusion. + pub fn prune_payload_attestation_messages(&self, current_slot: Slot) { + self.payload_attestation_messages + .write() + .retain(|data, _| current_slot <= data.slot.saturating_add(Slot::new(1))); + } + + /// Total number of payload attestation messages in the pool. + pub fn num_payload_attestation_messages(&self) -> usize { + self.payload_attestation_messages + .read() + .values() + .map(|msgs| msgs.len()) + .sum() + } + /// Insert an attestation into the pool, aggregating it with existing attestations if possible. /// /// ## Note @@ -646,6 +748,7 @@ impl OperationPool { ) { self.prune_attestations(current_epoch); self.prune_sync_contributions(head_state.slot()); + self.prune_payload_attestation_messages(head_state.slot()); self.prune_proposer_slashings(finalized_state); self.prune_attester_slashings(finalized_state); self.prune_voluntary_exits(finalized_state, spec); @@ -2075,4 +2178,214 @@ mod release_tests { op_pool.prune_attester_slashings(&electra_head.beacon_state); assert_eq!(op_pool.attester_slashings.read().len(), 1); } + + fn make_payload_attestation_message( + slot: Slot, + validator_index: u64, + beacon_block_root: Hash256, + ) -> PayloadAttestationMessage { + make_payload_attestation_message_with_flags( + slot, + validator_index, + beacon_block_root, + true, + true, + ) + } + + fn make_payload_attestation_message_with_flags( + slot: Slot, + validator_index: u64, + beacon_block_root: Hash256, + payload_present: bool, + blob_data_available: bool, + ) -> PayloadAttestationMessage { + PayloadAttestationMessage { + validator_index, + data: PayloadAttestationData { + beacon_block_root, + slot, + payload_present, + blob_data_available, + }, + signature: bls::Signature::empty(), + } + } + + #[test] + fn payload_attestation_insert_and_dedup() { + let op_pool = OperationPool::::new(); + let root = Hash256::repeat_byte(0xaa); + let slot = Slot::new(1); + + let msg1 = make_payload_attestation_message(slot, 0, root); + let msg2 = make_payload_attestation_message(slot, 1, root); + let msg1_dup = make_payload_attestation_message(slot, 0, root); + + op_pool.insert_payload_attestation_message(msg1).unwrap(); + op_pool.insert_payload_attestation_message(msg2).unwrap(); + op_pool + .insert_payload_attestation_message(msg1_dup) + .unwrap(); + + assert_eq!(op_pool.num_payload_attestation_messages(), 2); + } + + #[test] + fn payload_attestation_prune() { + let op_pool = OperationPool::::new(); + let root = Hash256::repeat_byte(0xaa); + + let msg_slot1 = make_payload_attestation_message(Slot::new(1), 0, root); + let msg_slot2 = make_payload_attestation_message(Slot::new(2), 1, root); + let msg_slot3 = make_payload_attestation_message(Slot::new(3), 2, root); + + op_pool + .insert_payload_attestation_message(msg_slot1) + .unwrap(); + op_pool + .insert_payload_attestation_message(msg_slot2) + .unwrap(); + op_pool + .insert_payload_attestation_message(msg_slot3) + .unwrap(); + + assert_eq!(op_pool.num_payload_attestation_messages(), 3); + + op_pool.prune_payload_attestation_messages(Slot::new(3)); + assert_eq!(op_pool.num_payload_attestation_messages(), 2); + + op_pool.prune_payload_attestation_messages(Slot::new(4)); + assert_eq!(op_pool.num_payload_attestation_messages(), 1); + + op_pool.prune_payload_attestation_messages(Slot::new(5)); + assert_eq!(op_pool.num_payload_attestation_messages(), 0); + } + + #[tokio::test] + async fn payload_attestation_packs_bits_from_ptc_positions() { + let spec = test_spec::(); + if spec.gloas_fork_epoch.is_none() { + return; + }; + + let num_validators = 64; + let harness = get_harness::(num_validators, Some(spec.clone())); + + harness + .add_attested_blocks_at_slots( + harness.get_current_state(), + Hash256::zero(), + &[Slot::new(1)], + (0..num_validators).collect::>().as_slice(), + ) + .await; + + let head = harness.chain.canonical_head.cached_head(); + let state = &head.snapshot.beacon_state; + assert_eq!(state.slot(), Slot::new(1)); + + let target_slot = Slot::new(1); + let parent_root = head.head_block_root(); + let ptc = state.get_ptc(target_slot, &spec).unwrap(); + let ptc_member_0 = ptc.0[0] as u64; + let ptc_member_1 = ptc.0[1] as u64; + + let op_pool = OperationPool::::new(); + + let msg0 = make_payload_attestation_message(target_slot, ptc_member_0, parent_root); + let msg1 = make_payload_attestation_message(target_slot, ptc_member_1, parent_root); + op_pool.insert_payload_attestation_message(msg0).unwrap(); + op_pool.insert_payload_attestation_message(msg1).unwrap(); + + // Advance state to slot 2 so get_payload_attestations looks at slot 1. + let mut advanced_state = state.clone(); + state_processing::state_advance::complete_state_advance( + &mut advanced_state, + None, + Slot::new(2), + &spec, + ) + .unwrap(); + + let attestations = op_pool + .get_payload_attestations(&advanced_state, parent_root, &spec) + .unwrap(); + + assert_eq!(attestations.len(), 1); + assert_eq!(attestations[0].aggregation_bits.num_set_bits(), 2); + assert!(attestations[0].aggregation_bits.get(0).unwrap()); + assert!(attestations[0].aggregation_bits.get(1).unwrap()); + assert!(attestations[0].data.payload_present); + } + + #[tokio::test] + async fn payload_attestation_multiple_data_combos_capped() { + let spec = test_spec::(); + if spec.gloas_fork_epoch.is_none() { + return; + }; + + let num_validators = 64; + let harness = get_harness::(num_validators, Some(spec.clone())); + + harness + .add_attested_blocks_at_slots( + harness.get_current_state(), + Hash256::zero(), + &[Slot::new(1)], + (0..num_validators).collect::>().as_slice(), + ) + .await; + + let head = harness.chain.canonical_head.cached_head(); + let state = &head.snapshot.beacon_state; + let target_slot = Slot::new(1); + let parent_root = head.head_block_root(); + let ptc = state.get_ptc(target_slot, &spec).unwrap(); + + let op_pool = OperationPool::::new(); + + // Given: PTC members vote with all 4 boolean combos, with varying participation. + let combos: [(bool, bool, &[usize]); 4] = [ + (true, true, &[0, 1, 2]), + (true, false, &[3, 4]), + (false, true, &[5]), + (false, false, &[6]), + ]; + for (payload_present, blob_available, positions) in &combos { + for &pos in *positions { + let validator_index = ptc.0[pos] as u64; + let msg = make_payload_attestation_message_with_flags( + target_slot, + validator_index, + parent_root, + *payload_present, + *blob_available, + ); + op_pool.insert_payload_attestation_message(msg).unwrap(); + } + } + + // When: we pack attestations for block production at slot 2. + let mut advanced_state = state.clone(); + state_processing::state_advance::complete_state_advance( + &mut advanced_state, + None, + Slot::new(2), + &spec, + ) + .unwrap(); + let attestations = op_pool + .get_payload_attestations(&advanced_state, parent_root, &spec) + .unwrap(); + + // Then: one attestation per combo, sorted by participation (most first). + assert_eq!(attestations.len(), 4); + let bit_counts: Vec<_> = attestations + .iter() + .map(|a| a.aggregation_bits.num_set_bits()) + .collect(); + assert_eq!(bit_counts, vec![3, 2, 1, 1]); + } } diff --git a/beacon_node/operation_pool/src/persistence.rs b/beacon_node/operation_pool/src/persistence.rs index 241b5fec53..56aafc27fe 100644 --- a/beacon_node/operation_pool/src/persistence.rs +++ b/beacon_node/operation_pool/src/persistence.rs @@ -209,6 +209,7 @@ impl PersistedOperationPool { proposer_slashings, voluntary_exits, bls_to_execution_changes: RwLock::new(bls_to_execution_changes), + payload_attestation_messages: Default::default(), reward_cache: Default::default(), _phantom: Default::default(), }; diff --git a/validator_client/validator_services/src/payload_attestation_service.rs b/validator_client/validator_services/src/payload_attestation_service.rs index 2f3ca8bed2..24949edc1f 100644 --- a/validator_client/validator_services/src/payload_attestation_service.rs +++ b/validator_client/validator_services/src/payload_attestation_service.rs @@ -101,10 +101,15 @@ impl PayloadAttestationServ sleep(duration_to_next_slot + payload_attestation_due).await; + let Some(attestation_slot) = self.slot_clock.now() else { + error!("Failed to read slot clock after sleep"); + continue; + }; + let service = self.clone(); self.executor.spawn( async move { - service.produce_and_publish(current_slot).await; + service.produce_and_publish(attestation_slot).await; }, "payload_attestation_producer", ); From 4415cf050693a8205dd12e1cbd61b394bebb3e4e Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Tue, 28 Apr 2026 14:45:03 +0200 Subject: [PATCH 11/12] Gloas filter conflicting voluntary exits (#9183) Parent envelope execution requests can invalidate voluntary exits. We should filter out any conflicting voluntary exits during block production to avoid triggering failures. Spec change: https://github.com/ethereum/consensus-specs/pull/5176 Co-Authored-By: Eitan Seri-Levi Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> --- .../src/block_production/gloas.rs | 211 ++++++++++++++++-- 1 file changed, 198 insertions(+), 13 deletions(-) diff --git a/beacon_node/beacon_chain/src/block_production/gloas.rs b/beacon_node/beacon_chain/src/block_production/gloas.rs index 4bc4b9862c..a6ebc2fefa 100644 --- a/beacon_node/beacon_chain/src/block_production/gloas.rs +++ b/beacon_node/beacon_chain/src/block_production/gloas.rs @@ -1,8 +1,8 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use std::marker::PhantomData; use std::sync::Arc; -use bls::Signature; +use bls::{PublicKeyBytes, Signature}; use execution_layer::{ BlockProposalContentsGloas, BuilderParams, PayloadAttributes, PayloadParameters, }; @@ -28,7 +28,7 @@ use types::consts::gloas::BUILDER_INDEX_SELF_BUILD; use types::{ Address, Attestation, AttestationElectra, AttesterSlashing, AttesterSlashingElectra, BeaconBlock, BeaconBlockBodyGloas, BeaconBlockGloas, BeaconState, BeaconStateError, - BuilderIndex, Deposit, Eth1Data, EthSpec, ExecutionBlockHash, ExecutionPayloadBid, + BuilderIndex, ChainSpec, Deposit, Eth1Data, EthSpec, ExecutionBlockHash, ExecutionPayloadBid, ExecutionPayloadEnvelope, ExecutionPayloadGloas, ExecutionRequests, FullPayload, Graffiti, Hash256, PayloadAttestation, ProposerSlashing, RelativeEpoch, SignedBeaconBlock, SignedBlsToExecutionChange, SignedExecutionPayloadBid, SignedExecutionPayloadEnvelope, @@ -137,6 +137,16 @@ impl BeaconChain { graffiti_settings: GraffitiSettings, verification: ProduceBlockVerification, ) -> Result, BlockProductionError> { + // Extract the parent's execution requests from the envelope (if parent was full). + let parent_execution_requests = if parent_payload_status == PayloadStatus::Full { + parent_envelope + .as_ref() + .map(|env| env.message.execution_requests.clone()) + .ok_or(BlockProductionError::MissingParentExecutionPayload)? + } else { + ExecutionRequests::default() + }; + // Part 1/3 (blocking) // // Perform the state advance and block-packing functions. @@ -145,6 +155,7 @@ impl BeaconChain { .graffiti_calculator .get_graffiti(graffiti_settings) .await; + let parent_execution_requests_ref = parent_execution_requests.clone(); let (partial_beacon_block, state) = self .task_executor .spawn_blocking_handle( @@ -155,6 +166,7 @@ impl BeaconChain { produce_at_slot, randao_reveal, graffiti, + &parent_execution_requests_ref, ) }, "produce_partial_beacon_block_gloas", @@ -163,16 +175,6 @@ impl BeaconChain { .await .map_err(BlockProductionError::TokioJoin)??; - // Extract the parent's execution requests from the envelope (if parent was full). - let parent_execution_requests = if parent_payload_status == PayloadStatus::Full { - parent_envelope - .as_ref() - .map(|env| env.message.execution_requests.clone()) - .ok_or(BlockProductionError::MissingParentExecutionPayload)? - } else { - ExecutionRequests::default() - }; - // Part 2/3 (async) // // Produce the execution payload bid. @@ -223,6 +225,7 @@ impl BeaconChain { produce_at_slot: Slot, randao_reveal: Signature, graffiti: Graffiti, + parent_execution_requests: &ExecutionRequests, ) -> Result<(PartialBeaconBlock, BeaconState), BlockProductionError> { // It is invalid to try to produce a block using a state from a future slot. @@ -257,6 +260,13 @@ impl BeaconChain { let (mut proposer_slashings, mut attester_slashings, mut voluntary_exits) = self.op_pool.get_slashings_and_exits(&state, &self.spec); + filter_voluntary_exits_for_parent_execution_requests( + &mut voluntary_exits, + parent_execution_requests, + |idx| state.validators().get(idx as usize).map(|v| v.pubkey), + &self.spec, + ); + drop(slashings_and_exits_span); let eth1_data = state.eth1_data().clone(); @@ -958,3 +968,178 @@ where Ok(block_contents) } + +/// Drop voluntary exits whose target validators will be exited by the parent envelope's +/// execution requests. +/// +/// In Gloas the parent execution payload is processed before voluntary exits during block +/// processing. EL-triggered withdrawal-full-exit requests (EIP-7002) and cross-pubkey +/// consolidation requests (EIP-7251) call `initiate_validator_exit`, setting the target's +/// `exit_epoch`. A voluntary exit for the same validator would then fail with `AlreadyExited`. +fn filter_voluntary_exits_for_parent_execution_requests( + voluntary_exits: &mut Vec, + parent_execution_requests: &ExecutionRequests, + pubkey_at_index: impl Fn(u64) -> Option, + spec: &ChainSpec, +) { + let mut exited_pubkeys = HashSet::with_capacity( + parent_execution_requests.withdrawals.len() + + parent_execution_requests.consolidations.len(), + ); + for req in &parent_execution_requests.withdrawals { + if req.amount == spec.full_exit_request_amount { + exited_pubkeys.insert(req.validator_pubkey); + } + } + for req in &parent_execution_requests.consolidations { + if req.source_pubkey != req.target_pubkey { + exited_pubkeys.insert(req.source_pubkey); + } + } + if !exited_pubkeys.is_empty() { + voluntary_exits.retain(|exit| { + pubkey_at_index(exit.message.validator_index) + .map(|pk| !exited_pubkeys.contains(&pk)) + .unwrap_or(false) + }); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ssz_types::VariableList; + use types::{ConsolidationRequest, Epoch, MainnetEthSpec, VoluntaryExit, WithdrawalRequest}; + + type TestSpec = MainnetEthSpec; + + fn pubkey(byte: u8) -> PublicKeyBytes { + PublicKeyBytes::deserialize(&[byte; 48]).expect("valid pubkey byte length") + } + + fn exit(validator_index: u64) -> SignedVoluntaryExit { + SignedVoluntaryExit { + message: VoluntaryExit { + epoch: Epoch::new(0), + validator_index, + }, + signature: Signature::empty(), + } + } + + fn requests( + withdrawals: Vec, + consolidations: Vec, + ) -> ExecutionRequests { + ExecutionRequests { + deposits: VariableList::empty(), + withdrawals: VariableList::new(withdrawals).unwrap(), + consolidations: VariableList::new(consolidations).unwrap(), + } + } + + fn run_filter( + exits: &mut Vec, + requests: &ExecutionRequests, + validator_pubkeys: &[PublicKeyBytes], + spec: &ChainSpec, + ) { + filter_voluntary_exits_for_parent_execution_requests( + exits, + requests, + |idx| validator_pubkeys.get(idx as usize).copied(), + spec, + ); + } + + #[test] + fn full_exit_withdrawal_request_filters_matching_voluntary_exit() { + let spec = ChainSpec::mainnet(); + let validators = vec![pubkey(1), pubkey(2)]; + let mut exits = vec![exit(0), exit(1)]; + let reqs = requests( + vec![WithdrawalRequest { + source_address: Address::repeat_byte(0xaa), + validator_pubkey: validators[0], + amount: spec.full_exit_request_amount, + }], + vec![], + ); + + run_filter(&mut exits, &reqs, &validators, &spec); + + assert_eq!(exits.len(), 1); + assert_eq!(exits[0].message.validator_index, 1); + } + + #[test] + fn partial_withdrawal_request_does_not_filter_voluntary_exit() { + let spec = ChainSpec::mainnet(); + let validators = vec![pubkey(1)]; + let mut exits = vec![exit(0)]; + let reqs = requests( + vec![WithdrawalRequest { + source_address: Address::repeat_byte(0xaa), + validator_pubkey: validators[0], + amount: spec.full_exit_request_amount + 1, + }], + vec![], + ); + + run_filter(&mut exits, &reqs, &validators, &spec); + + assert_eq!(exits.len(), 1); + } + + #[test] + fn cross_pubkey_consolidation_filters_voluntary_exit_for_source_only() { + let spec = ChainSpec::mainnet(); + let validators = vec![pubkey(1), pubkey(2), pubkey(3)]; + let mut exits = vec![exit(0), exit(1), exit(2)]; + let reqs = requests( + vec![], + vec![ConsolidationRequest { + source_address: Address::repeat_byte(0xaa), + source_pubkey: validators[1], + target_pubkey: validators[2], + }], + ); + + run_filter(&mut exits, &reqs, &validators, &spec); + + // The source (validator 1) is exited; the target (validator 2) is not. + let remaining: Vec = exits.iter().map(|e| e.message.validator_index).collect(); + assert_eq!(remaining, vec![0, 2]); + } + + #[test] + fn self_consolidation_does_not_filter_voluntary_exit() { + let spec = ChainSpec::mainnet(); + let validators = vec![pubkey(1)]; + let mut exits = vec![exit(0)]; + let reqs = requests( + vec![], + vec![ConsolidationRequest { + source_address: Address::repeat_byte(0xaa), + source_pubkey: validators[0], + target_pubkey: validators[0], + }], + ); + + run_filter(&mut exits, &reqs, &validators, &spec); + + assert_eq!(exits.len(), 1); + } + + #[test] + fn empty_parent_requests_preserve_voluntary_exits() { + let spec = ChainSpec::mainnet(); + let validators = vec![pubkey(1), pubkey(2)]; + let mut exits = vec![exit(0), exit(1)]; + let reqs = requests(vec![], vec![]); + + run_filter(&mut exits, &reqs, &validators, &spec); + + assert_eq!(exits.len(), 2); + } +} From 6258eadc91c10432c93ab1487ef7ee436470b6d6 Mon Sep 17 00:00:00 2001 From: Eitan Seri-Levi Date: Tue, 28 Apr 2026 15:19:47 +0200 Subject: [PATCH 12/12] Gloas publish data columns during local block building (#9182) Make sure we are publishing columns during local block production Co-Authored-By: Eitan Seri-Levi Co-Authored-By: dapplion <35266934+dapplion@users.noreply.github.com> --- .../src/block_production/gloas.rs | 16 +- beacon_node/beacon_chain/src/kzg_utils.rs | 108 +++++++++++-- .../src/pending_payload_envelopes.rs | 93 ++++++++--- beacon_node/beacon_chain/src/test_utils.rs | 42 +++-- .../test_data_column_sidecars_gloas.ssz | Bin 0 -> 275968 bytes .../beacon_chain/tests/column_verification.rs | 72 +++++++++ .../beacon_chain/tests/prepare_payload.rs | 118 ++++++++++++++ .../src/beacon/execution_payload_envelope.rs | 151 +++++++++++++++++- beacon_node/http_api/src/publish_blocks.rs | 2 +- 9 files changed, 545 insertions(+), 57 deletions(-) create mode 100644 beacon_node/beacon_chain/src/test_utils/fixtures/test_data_column_sidecars_gloas.ssz diff --git a/beacon_node/beacon_chain/src/block_production/gloas.rs b/beacon_node/beacon_chain/src/block_production/gloas.rs index a6ebc2fefa..79ea78ce4a 100644 --- a/beacon_node/beacon_chain/src/block_production/gloas.rs +++ b/beacon_node/beacon_chain/src/block_production/gloas.rs @@ -35,6 +35,7 @@ use types::{ SignedVoluntaryExit, Slot, SyncAggregate, Withdrawal, Withdrawals, }; +use crate::pending_payload_envelopes::PendingEnvelopeData; use crate::{ BeaconChain, BeaconChainError, BeaconChainTypes, BlockProductionError, ProduceBlockVerification, block_production::BlockProductionState, @@ -74,6 +75,7 @@ pub struct ExecutionPayloadData { pub execution_requests: ExecutionRequests, pub builder_index: BuilderIndex, pub slot: Slot, + pub blobs_and_proofs: (types::BlobsList, types::KzgProofs), } impl BeaconChain { @@ -647,9 +649,14 @@ impl BeaconChain { let envelope_slot = payload_data.slot; // TODO(gloas) might be safer to cache by root instead of by slot. // We should revisit this once this code path + beacon api spec matures - self.pending_payload_envelopes - .write() - .insert(envelope_slot, signed_envelope.message); + let (blobs, _) = payload_data.blobs_and_proofs; + self.pending_payload_envelopes.write().insert( + envelope_slot, + PendingEnvelopeData { + envelope: signed_envelope.message, + blobs: Some(blobs), + }, + ); debug!( %beacon_block_root, @@ -769,7 +776,7 @@ impl BeaconChain { payload_value: _, execution_requests, blob_kzg_commitments, - blobs_and_proofs: _, + blobs_and_proofs, } = block_proposal_contents; // TODO(gloas) since we are defaulting to local building, execution payment is 0 @@ -795,6 +802,7 @@ impl BeaconChain { execution_requests, builder_index, slot: produce_at_slot, + blobs_and_proofs, }; // TODO(gloas) this is only local building diff --git a/beacon_node/beacon_chain/src/kzg_utils.rs b/beacon_node/beacon_chain/src/kzg_utils.rs index 9641aec47d..b05a896777 100644 --- a/beacon_node/beacon_chain/src/kzg_utils.rs +++ b/beacon_node/beacon_chain/src/kzg_utils.rs @@ -296,6 +296,35 @@ pub fn blobs_to_data_column_sidecars( } } +/// Build Gloas data column sidecars from blobs, computing cells and proofs locally. +pub fn blobs_to_data_column_sidecars_gloas( + blobs: &[&Blob], + beacon_block_root: Hash256, + slot: Slot, + kzg: &Kzg, + spec: &ChainSpec, +) -> Result, DataColumnSidecarError> { + if blobs.is_empty() { + return Ok(vec![]); + } + + let blob_cells_and_proofs_vec = blobs + .into_par_iter() + .map(|blob| { + let blob = blob.as_ref().try_into().map_err(|e| { + KzgError::InconsistentArrayLength(format!( + "blob should have a guaranteed size due to FixedVector: {e:?}" + )) + })?; + + kzg.compute_cells_and_proofs(blob) + }) + .collect::, KzgError>>()?; + + build_data_column_sidecars_gloas(beacon_block_root, slot, blob_cells_and_proofs_vec, spec) + .map_err(DataColumnSidecarError::BuildSidecarFailed) +} + /// Build data column sidecars from a signed beacon block and its blobs. #[instrument(skip_all, level = "debug", fields(blob_count = blobs_and_proofs.len()))] pub fn blobs_to_partial_data_columns( @@ -728,8 +757,8 @@ pub fn reconstruct_data_columns( #[cfg(test)] mod test { use crate::kzg_utils::{ - blobs_to_data_column_sidecars, reconstruct_blobs, reconstruct_data_columns, - validate_full_data_columns, + blobs_to_data_column_sidecars, blobs_to_data_column_sidecars_gloas, reconstruct_blobs, + reconstruct_data_columns, validate_full_data_columns, }; use bls::Signature; use eth2::types::BlobsBundle; @@ -737,25 +766,30 @@ mod test { use kzg::{Kzg, KzgCommitment, trusted_setup::get_trusted_setup}; use types::{ BeaconBlock, BeaconBlockFulu, BlobsList, ChainSpec, EmptyBlock, EthSpec, ForkName, - FullPayload, KzgProofs, MainnetEthSpec, SignedBeaconBlock, kzg_ext::KzgCommitments, + FullPayload, Hash256, KzgProofs, MainnetEthSpec, SignedBeaconBlock, Slot, + kzg_ext::KzgCommitments, }; type E = MainnetEthSpec; // Loading and initializing PeerDAS KZG is expensive and slow, so we group the tests together // only load it once. - // TODO(Gloas) make this generic over fulu/gloas, or write a separate function for Gloas #[test] fn test_build_data_columns_sidecars() { - let spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); let kzg = get_kzg(); - test_build_data_columns_empty(&kzg, &spec); - test_build_data_columns_fulu(&kzg, &spec); - test_reconstruct_data_columns(&kzg, &spec); - test_reconstruct_data_columns_unordered(&kzg, &spec); - test_reconstruct_blobs_from_data_columns(&kzg, &spec); - test_reconstruct_blobs_from_data_columns_unordered(&kzg, &spec); - test_validate_data_columns(&kzg, &spec); + + let fulu_spec = ForkName::Fulu.make_genesis_spec(E::default_spec()); + test_build_data_columns_empty(&kzg, &fulu_spec); + test_build_data_columns_fulu(&kzg, &fulu_spec); + test_reconstruct_data_columns(&kzg, &fulu_spec); + test_reconstruct_data_columns_unordered(&kzg, &fulu_spec); + test_reconstruct_blobs_from_data_columns(&kzg, &fulu_spec); + test_reconstruct_blobs_from_data_columns_unordered(&kzg, &fulu_spec); + test_validate_data_columns(&kzg, &fulu_spec); + + let gloas_spec = ForkName::Gloas.make_genesis_spec(E::default_spec()); + test_build_data_columns_gloas(&kzg, &gloas_spec); + test_build_data_columns_gloas_empty(&kzg, &gloas_spec); } #[track_caller] @@ -784,8 +818,49 @@ mod test { assert!(column_sidecars.is_empty()); } - // TODO(gloas) create `test_build_data_columns_gloas` and make sure its called - // in the relevant places + #[track_caller] + fn test_build_data_columns_gloas(kzg: &Kzg, spec: &ChainSpec) { + let num_of_blobs = 2; + let (blobs, _proofs) = create_test_gloas_blobs::(num_of_blobs); + let beacon_block_root = Hash256::random(); + let slot = Slot::new(0); + + let blob_refs: Vec<_> = blobs.iter().collect(); + let column_sidecars = blobs_to_data_column_sidecars_gloas::( + &blob_refs, + beacon_block_root, + slot, + kzg, + spec, + ) + .unwrap(); + + assert_eq!(column_sidecars.len(), E::number_of_columns()); + for (idx, col_sidecar) in column_sidecars.iter().enumerate() { + assert_eq!(*col_sidecar.index(), idx as u64); + assert_eq!(col_sidecar.column().len(), num_of_blobs); + assert_eq!(col_sidecar.kzg_proofs().len(), num_of_blobs); + + let gloas_col = col_sidecar.as_gloas().expect("should be Gloas sidecar"); + assert_eq!(gloas_col.beacon_block_root, beacon_block_root); + assert_eq!(gloas_col.slot, slot); + } + } + + #[track_caller] + fn test_build_data_columns_gloas_empty(kzg: &Kzg, spec: &ChainSpec) { + let blob_refs: Vec<&types::Blob> = vec![]; + let column_sidecars = blobs_to_data_column_sidecars_gloas::( + &blob_refs, + Hash256::random(), + Slot::new(0), + kzg, + spec, + ) + .unwrap(); + assert!(column_sidecars.is_empty()); + } + #[track_caller] fn test_build_data_columns_fulu(kzg: &Kzg, spec: &ChainSpec) { // Using at least 2 blobs to make sure we're arranging the data columns correctly. @@ -974,4 +1049,9 @@ mod test { (signed_block, blobs, proofs) } + + fn create_test_gloas_blobs(num_of_blobs: usize) -> (BlobsList, KzgProofs) { + let (blobs_bundle, _) = generate_blobs::(num_of_blobs, ForkName::Gloas).unwrap(); + (blobs_bundle.blobs, blobs_bundle.proofs) + } } diff --git a/beacon_node/beacon_chain/src/pending_payload_envelopes.rs b/beacon_node/beacon_chain/src/pending_payload_envelopes.rs index 351783832d..293553ef54 100644 --- a/beacon_node/beacon_chain/src/pending_payload_envelopes.rs +++ b/beacon_node/beacon_chain/src/pending_payload_envelopes.rs @@ -6,7 +6,12 @@ //! and publishes the payload. use std::collections::HashMap; -use types::{EthSpec, ExecutionPayloadEnvelope, Slot}; +use types::{BlobsList, EthSpec, ExecutionPayloadEnvelope, Slot}; + +pub struct PendingEnvelopeData { + pub envelope: ExecutionPayloadEnvelope, + pub blobs: Option>, +} /// Cache for pending execution payload envelopes awaiting publishing. /// @@ -16,7 +21,7 @@ pub struct PendingPayloadEnvelopes { /// Maximum number of slots to keep envelopes before pruning. max_slot_age: u64, /// The envelopes, keyed by slot. - envelopes: HashMap>, + envelopes: HashMap>, } impl Default for PendingPayloadEnvelopes { @@ -38,19 +43,24 @@ impl PendingPayloadEnvelopes { } /// Insert a pending envelope into the cache. - pub fn insert(&mut self, slot: Slot, envelope: ExecutionPayloadEnvelope) { + 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, envelope); + self.envelopes.insert(slot, data); } /// Get a pending envelope by slot. pub fn get(&self, slot: Slot) -> Option<&ExecutionPayloadEnvelope> { - self.envelopes.get(&slot) + self.envelopes.get(&slot).map(|d| &d.envelope) + } + + /// Remove and return the blobs and proofs for a slot, leaving the envelope in place. + pub fn take_blobs(&mut self, slot: Slot) -> Option> { + self.envelopes.get_mut(&slot).and_then(|d| d.blobs.take()) } /// Remove and return a pending envelope by slot. pub fn remove(&mut self, slot: Slot) -> Option> { - self.envelopes.remove(&slot) + self.envelopes.remove(&slot).map(|d| d.envelope) } /// Check if an envelope exists for the given slot. @@ -85,15 +95,18 @@ mod tests { type E = MainnetEthSpec; - fn make_envelope(slot: Slot) -> ExecutionPayloadEnvelope { - ExecutionPayloadEnvelope { - payload: ExecutionPayloadGloas { - slot_number: slot, - ..ExecutionPayloadGloas::default() + fn make_envelope(slot: Slot) -> PendingEnvelopeData { + PendingEnvelopeData { + envelope: ExecutionPayloadEnvelope { + payload: ExecutionPayloadGloas { + slot_number: slot, + ..ExecutionPayloadGloas::default() + }, + execution_requests: ExecutionRequests::default(), + builder_index: 0, + beacon_block_root: Hash256::ZERO, }, - execution_requests: ExecutionRequests::default(), - builder_index: 0, - beacon_block_root: Hash256::ZERO, + blobs: None, } } @@ -101,33 +114,73 @@ mod tests { fn insert_and_get() { let mut cache = PendingPayloadEnvelopes::::default(); let slot = Slot::new(1); - let envelope = make_envelope(slot); + let data = make_envelope(slot); + let expected_envelope = data.envelope.clone(); assert!(!cache.contains(slot)); assert_eq!(cache.len(), 0); - cache.insert(slot, envelope.clone()); + cache.insert(slot, data); assert!(cache.contains(slot)); assert_eq!(cache.len(), 1); - assert_eq!(cache.get(slot), Some(&envelope)); + assert_eq!(cache.get(slot), Some(&expected_envelope)); } #[test] fn remove() { let mut cache = PendingPayloadEnvelopes::::default(); let slot = Slot::new(1); - let envelope = make_envelope(slot); + let data = make_envelope(slot); + let expected_envelope = data.envelope.clone(); - cache.insert(slot, envelope.clone()); + cache.insert(slot, data); assert!(cache.contains(slot)); let removed = cache.remove(slot); - assert_eq!(removed, Some(envelope)); + assert_eq!(removed, Some(expected_envelope)); assert!(!cache.contains(slot)); assert_eq!(cache.len(), 0); } + #[test] + fn take_blobs_returns_once() { + let mut cache = PendingPayloadEnvelopes::::default(); + let slot = Slot::new(1); + + let blobs = BlobsList::::default(); + let data = PendingEnvelopeData { + envelope: make_envelope(slot).envelope, + blobs: Some(blobs), + }; + 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()); + } + + #[test] + fn take_blobs_returns_none_when_absent() { + 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()); + } + #[test] fn prune_old_envelopes() { let mut cache = PendingPayloadEnvelopes::::new(2); diff --git a/beacon_node/beacon_chain/src/test_utils.rs b/beacon_node/beacon_chain/src/test_utils.rs index 274f41d1cb..f67b5015c5 100644 --- a/beacon_node/beacon_chain/src/test_utils.rs +++ b/beacon_node/beacon_chain/src/test_utils.rs @@ -86,6 +86,8 @@ pub const FORK_NAME_ENV_VAR: &str = "FORK_NAME"; // `beacon_node/execution_layer/src/test_utils/fixtures/mainnet/test_blobs_bundle.ssz` pub const TEST_DATA_COLUMN_SIDECARS_SSZ: &[u8] = include_bytes!("test_utils/fixtures/test_data_column_sidecars.ssz"); +pub const TEST_DATA_COLUMN_SIDECARS_GLOAS_SSZ: &[u8] = + include_bytes!("test_utils/fixtures/test_data_column_sidecars_gloas.ssz"); // Default target aggregators to set during testing, this ensures an aggregator at each slot. // @@ -3789,24 +3791,24 @@ pub fn generate_data_column_sidecars_from_block( block: &SignedBeaconBlock, spec: &ChainSpec, ) -> DataColumnSidecarList { - let kzg_commitments = block.message().body().blob_kzg_commitments().unwrap(); - if kzg_commitments.is_empty() { - return vec![]; - } - - let kzg_commitments_inclusion_proof = block - .message() - .body() - .kzg_commitments_merkle_proof() - .unwrap(); - let signed_block_header = block.signed_block_header(); - // Load the precomputed column sidecar to avoid computing them for every block in the tests. // Then repeat the cells and proofs for every blob if block.fork_name_unchecked().gloas_enabled() { + let kzg_commitments = &block + .message() + .body() + .signed_execution_payload_bid() + .expect("Gloas block should have a payload bid") + .message + .blob_kzg_commitments; + if kzg_commitments.is_empty() { + return vec![]; + } + let num_blobs = kzg_commitments.len(); + let signed_block_header = block.signed_block_header(); let template_data_columns = RuntimeVariableList::>::from_ssz_bytes( - TEST_DATA_COLUMN_SIDECARS_SSZ, + TEST_DATA_COLUMN_SIDECARS_GLOAS_SSZ, E::number_of_columns(), ) .unwrap(); @@ -3826,7 +3828,7 @@ pub fn generate_data_column_sidecars_from_block( .collect::<(Vec<_>, Vec<_>)>(); let blob_cells_and_proofs_vec = - vec![(cells.try_into().unwrap(), proofs.try_into().unwrap()); kzg_commitments.len()]; + vec![(cells.try_into().unwrap(), proofs.try_into().unwrap()); num_blobs]; build_data_column_sidecars_gloas( signed_block_header.message.tree_hash_root(), @@ -3836,6 +3838,18 @@ pub fn generate_data_column_sidecars_from_block( ) .unwrap() } else { + let kzg_commitments = block.message().body().blob_kzg_commitments().unwrap(); + if kzg_commitments.is_empty() { + return vec![]; + } + + let kzg_commitments_inclusion_proof = block + .message() + .body() + .kzg_commitments_merkle_proof() + .unwrap(); + let signed_block_header = block.signed_block_header(); + // load the precomputed column sidecar to avoid computing them for every block in the tests. let template_data_columns = RuntimeVariableList::>::from_ssz_bytes( diff --git a/beacon_node/beacon_chain/src/test_utils/fixtures/test_data_column_sidecars_gloas.ssz b/beacon_node/beacon_chain/src/test_utils/fixtures/test_data_column_sidecars_gloas.ssz new file mode 100644 index 0000000000000000000000000000000000000000..554b27844b297c735bf8e16c0340f5d19d724af0 GIT binary patch literal 275968 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


j5uNBv0uPE^;9b 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 + if !spec.is_gloas_scheduled() { + return; + } + + let harness = get_harness(VALIDATOR_COUNT, spec.clone(), NodeCustodyType::Supernode); + harness.execution_block_generator().set_min_blob_count(1); + + // Build some chain depth. + let num_blocks = E::slots_per_epoch() as usize; + harness + .extend_chain( + num_blocks, + BlockStrategy::OnCanonicalHead, + AttestationStrategy::AllValidators, + ) + .await; + + harness.advance_slot(); + let slot = harness.get_current_slot(); + + // Produce a Gloas block via the harness. This caches envelope + blobs. + let state = harness.get_current_state(); + let (block_contents, opt_envelope, _post_state) = + harness.make_block_with_envelope(state, slot).await; + let signed_block = &block_contents.0; + + assert!( + opt_envelope.is_some(), + "Gloas block production should produce an envelope" + ); + + // Verify the block has blob commitments in the bid. + let bid = signed_block + .message() + .body() + .signed_execution_payload_bid() + .expect("Gloas block should have a payload bid"); + assert!( + !bid.message.blob_kzg_commitments.is_empty(), + "Block should have blob KZG commitments" + ); + + // Generate data columns from the block (using test fixtures, same as the harness does). + let data_column_sidecars = + generate_data_column_sidecars_from_block(signed_block, &harness.chain.spec); + assert_eq!( + data_column_sidecars.len(), + E::number_of_columns(), + "Should produce the correct number of data columns" + ); + + // Verify all columns are Gloas-format. + for col in &data_column_sidecars { + assert!( + col.as_gloas().is_ok(), + "Data column sidecar should be Gloas variant" + ); + let gloas_col = col.as_gloas().expect("should be Gloas sidecar"); + assert_eq!(gloas_col.beacon_block_root, signed_block.canonical_root()); + assert_eq!(gloas_col.slot, slot); + } + + // End-to-end DA flow (process_block → process_envelope → process_rpc_custody_columns) + // is not exercised here: Gloas blocks are not gated on columns at block-import time + // and the envelope/column gating belongs in a dedicated test once the DA path matures. +} + // Regression test for verify_header_signature bug: it uses head_fork() which is wrong for fork blocks #[tokio::test] async fn verify_header_signature_fork_block_bug() { diff --git a/beacon_node/beacon_chain/tests/prepare_payload.rs b/beacon_node/beacon_chain/tests/prepare_payload.rs index dc4f999eb2..1d23990b80 100644 --- a/beacon_node/beacon_chain/tests/prepare_payload.rs +++ b/beacon_node/beacon_chain/tests/prepare_payload.rs @@ -573,3 +573,121 @@ async fn prepare_payload_on_fork_boundary( advanced state" ); } + +#[tokio::test] +async fn gloas_block_production_caches_blobs_for_column_publishing() { + use beacon_chain::ProduceBlockVerification; + use beacon_chain::graffiti_calculator::GraffitiSettings; + use eth2::types::GraffitiPolicy; + + let spec = Arc::new(test_spec::()); + if !spec.fork_name_at_slot::(Slot::new(0)).gloas_enabled() { + return; + } + + let db_path = tempdir().unwrap(); + let store = get_store(&db_path, spec.clone()); + let harness = get_harness(store.clone(), LOW_VALIDATOR_COUNT); + + // Configure the mock EL to produce at least 1 blob per block. + harness.execution_block_generator().set_min_blob_count(1); + + // Extend the chain a few slots to get past genesis. + harness + .extend_chain( + (E::slots_per_epoch() as usize) + 1, + BlockStrategy::OnCanonicalHead, + AttestationStrategy::AllValidators, + ) + .await; + + harness.advance_slot(); + let slot = harness.get_current_slot(); + + // Produce a Gloas block directly via produce_block_on_state_gloas so we can + // inspect the pending cache before it's consumed. + let mut state = harness.get_current_state(); + complete_state_advance(&mut state, None, slot, &spec).unwrap(); + state.build_caches(&spec).unwrap(); + + let proposer_index = state.get_beacon_proposer_index(slot, &spec).unwrap(); + let randao_reveal = harness.sign_randao_reveal(&state, proposer_index, slot); + + let (parent_payload_status, parent_envelope) = { + let head = harness.chain.canonical_head.cached_head(); + ( + head.head_payload_status(), + head.snapshot.execution_envelope.clone(), + ) + }; + + let graffiti_settings = GraffitiSettings::new( + Some(Graffiti::default()), + Some(GraffitiPolicy::PreserveUserGraffiti), + ); + + let (_block, _post_state, _value) = harness + .chain + .produce_block_on_state_gloas( + state, + None, + parent_payload_status, + parent_envelope, + slot, + randao_reveal, + graffiti_settings, + ProduceBlockVerification::VerifyRandao, + ) + .await + .unwrap(); + + // The envelope + blobs should now be in the pending cache. + assert!( + harness + .chain + .pending_payload_envelopes + .read() + .contains(slot), + "Pending cache should contain an envelope for the produced slot" + ); + + // Take the blobs from the cache — this is what publish_execution_payload_envelope does. + let blobs = harness + .chain + .pending_payload_envelopes + .write() + .take_blobs(slot); + + assert!( + blobs.is_some(), + "Blobs should be cached alongside the envelope" + ); + + let blobs = blobs.unwrap(); + assert!( + !blobs.is_empty(), + "Blobs should be non-empty when min_blob_count >= 1" + ); + + // Verify take_blobs is consume-once. + let second_take = harness + .chain + .pending_payload_envelopes + .write() + .take_blobs(slot); + assert!( + second_take.is_none(), + "Blobs should only be consumable once" + ); + + // The envelope should still be in the cache after taking blobs. + assert!( + harness + .chain + .pending_payload_envelopes + .read() + .get(slot) + .is_some(), + "Envelope should remain in cache after taking blobs" + ); +} 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 382b967b43..06a5915c08 100644 --- a/beacon_node/http_api/src/beacon/execution_payload_envelope.rs +++ b/beacon_node/http_api/src/beacon/execution_payload_envelope.rs @@ -1,10 +1,12 @@ use crate::block_id::BlockId; +use crate::publish_blocks::publish_column_sidecars; use crate::task_spawner::{Priority, TaskSpawner}; use crate::utils::{ChainFilter, EthV1Filter, NetworkTxFilter, ResponseFilter, TaskSpawnerFilter}; use crate::version::{ ResponseIncludesVersion, add_consensus_version_header, add_ssz_content_type_header, execution_optimistic_finalized_beacon_response, }; +use beacon_chain::data_column_verification::{GossipDataColumnError, GossipVerifiedDataColumn}; use beacon_chain::{BeaconChain, BeaconChainTypes}; use bytes::Bytes; use eth2::types as api_types; @@ -12,10 +14,11 @@ use eth2::{CONTENT_TYPE_HEADER, SSZ_CONTENT_TYPE_HEADER}; use lighthouse_network::PubsubMessage; use network::NetworkMessage; use ssz::{Decode, Encode}; +use std::future::Future; use std::sync::Arc; use tokio::sync::mpsc::UnboundedSender; -use tracing::{info, warn}; -use types::SignedExecutionPayloadEnvelope; +use tracing::{debug, error, info, warn}; +use types::{EthSpec, SignedExecutionPayloadEnvelope}; use warp::{ Filter, Rejection, Reply, hyper::{Body, Response}, @@ -85,7 +88,9 @@ pub(crate) fn post_beacon_execution_payload_envelope( ) .boxed() } -/// Publishes a signed execution payload envelope to the network. +/// Publishes a signed execution payload envelope to the network. Implements +/// `POST /eth/v1/beacon/execution_payload_envelope` per the in-flight beacon-APIs PR +/// . pub async fn publish_execution_payload_envelope( envelope: SignedExecutionPayloadEnvelope, chain: Arc>, @@ -109,7 +114,24 @@ pub async fn publish_execution_payload_envelope( "Publishing signed execution payload envelope to network" ); - // Publish to the network + let blobs_and_proofs = chain.pending_payload_envelopes.write().take_blobs(slot); + + // Spawn the column-build task (CPU-bound KZG cell-and-proof computation) before + // publishing the envelope so it runs in parallel with envelope gossip, narrowing + // the window in which peers see envelope-without-columns. If envelope publication + // fails below, dropping this future drops the spawned `JoinHandle` (the running + // closure on the blocking pool finishes and is then discarded — no work cancellation). + let column_build_future = match blobs_and_proofs { + Some(blobs) if !blobs.is_empty() => Some(spawn_build_gloas_data_columns_task( + &chain, + beacon_block_root, + slot, + blobs, + )?), + _ => None, + }; + + // Publish the envelope to the network. crate::utils::publish_pubsub_message( network_tx, PubsubMessage::ExecutionPayload(Box::new(envelope)), @@ -121,9 +143,130 @@ pub async fn publish_execution_payload_envelope( ) })?; + // From here on the envelope is on the wire. `take_blobs` already consumed the cache + // entry, so a retry would not republish columns; returning Err would mislead the + // caller. Log column-build/publish failures and fall through to `Ok`. + if let Some(column_build_future) = column_build_future { + let gossip_verified_columns = match column_build_future.await { + Ok(columns) => columns, + Err(e) => { + error!( + %slot, + error = ?e, + "Failed to build data columns after envelope publication" + ); + return Ok(warp::reply().into_response()); + } + }; + + if !gossip_verified_columns.is_empty() { + if let Err(e) = publish_column_sidecars(network_tx, &gossip_verified_columns, &chain) { + error!( + %slot, + error = ?e, + "Failed to publish data column sidecars after envelope publication" + ); + return Ok(warp::reply().into_response()); + } + + let epoch = slot.epoch(T::EthSpec::slots_per_epoch()); + let sampling_column_indices = chain.sampling_columns_for_epoch(epoch); + let sampling_columns = gossip_verified_columns + .into_iter() + .filter(|col| sampling_column_indices.contains(&col.index())) + .collect::>(); + + // Local processing only — envelope already broadcast, so log and fall through. + if !sampling_columns.is_empty() + && let Err(e) = + Box::pin(chain.process_gossip_data_columns(sampling_columns, || Ok(()))).await + { + error!( + %slot, + error = ?e, + "Failed to process sampling data columns during envelope publication" + ); + } + } + } + Ok(warp::reply().into_response()) } +fn spawn_build_gloas_data_columns_task( + chain: &Arc>, + beacon_block_root: types::Hash256, + slot: types::Slot, + blobs: types::BlobsList, +) -> Result>, Rejection>>, Rejection> { + let chain_for_build = chain.clone(); + let handle = chain + .task_executor + .spawn_blocking_handle( + move || build_gloas_data_columns(&chain_for_build, beacon_block_root, slot, &blobs), + "build_gloas_data_columns", + ) + .ok_or_else(|| warp_utils::reject::custom_server_error("runtime shutdown".to_string()))?; + + Ok(async move { + handle + .await + .map_err(|_| warp_utils::reject::custom_server_error("join error".to_string()))? + }) +} + +fn build_gloas_data_columns( + chain: &BeaconChain, + beacon_block_root: types::Hash256, + slot: types::Slot, + blobs: &types::BlobsList, +) -> Result>, Rejection> { + let blob_refs: Vec<_> = blobs.iter().collect(); + let data_column_sidecars = beacon_chain::kzg_utils::blobs_to_data_column_sidecars_gloas( + &blob_refs, + beacon_block_root, + slot, + &chain.kzg, + &chain.spec, + ) + .map_err(|e| { + error!( + error = ?e, + %slot, + "Failed to build data column sidecars for envelope" + ); + warp_utils::reject::custom_server_error(format!("{e:?}")) + })?; + + let gossip_verified_columns = data_column_sidecars + .into_iter() + .filter_map(|col| { + let index = *col.index(); + match GossipVerifiedDataColumn::new_for_block_publishing(col, chain) { + Ok(verified) => Some(verified), + Err(GossipDataColumnError::PriorKnownUnpublished) => None, + Err(e) => { + warn!( + %slot, + column_index = index, + error = ?e, + "Locally-built data column failed gossip verification" + ); + None + } + } + }) + .collect::>(); + + debug!( + %slot, + column_count = gossip_verified_columns.len(), + "Built data columns for envelope publication" + ); + + Ok(gossip_verified_columns) +} + // TODO(gloas): add tests for this endpoint once we support importing payloads into the db // GET beacon/execution_payload_envelope/{block_id} pub(crate) fn get_beacon_execution_payload_envelope( diff --git a/beacon_node/http_api/src/publish_blocks.rs b/beacon_node/http_api/src/publish_blocks.rs index 6b65995a73..644ade956a 100644 --- a/beacon_node/http_api/src/publish_blocks.rs +++ b/beacon_node/http_api/src/publish_blocks.rs @@ -494,7 +494,7 @@ fn publish_blob_sidecars( .map_err(|_| BlockError::BeaconChainError(Box::new(BeaconChainError::UnableToPublish))) } -fn publish_column_sidecars( +pub(crate) fn publish_column_sidecars( sender_clone: &UnboundedSender>, data_column_sidecars: &[GossipVerifiedDataColumn], chain: &BeaconChain,