diff --git a/beacon_node/beacon_processor/src/lib.rs b/beacon_node/beacon_processor/src/lib.rs index d9ae0e2345..d3e9133542 100644 --- a/beacon_node/beacon_processor/src/lib.rs +++ b/beacon_node/beacon_processor/src/lib.rs @@ -409,6 +409,10 @@ pub enum Work { DataColumnsByRootsRequest(BlockingFn), DataColumnsByRangeRequest(BlockingFn), GossipBlsToExecutionChange(BlockingFn), + GossipExecutionPayload(AsyncFn), + GossipExecutionPayloadBid(BlockingFn), + GossipPayloadAttestation(BlockingFn), + GossipProposerPreferences(BlockingFn), LightClientBootstrapRequest(BlockingFn), LightClientOptimisticUpdateRequest(BlockingFn), LightClientFinalityUpdateRequest(BlockingFn), @@ -461,6 +465,10 @@ pub enum WorkType { DataColumnsByRootsRequest, DataColumnsByRangeRequest, GossipBlsToExecutionChange, + GossipExecutionPayload, + GossipExecutionPayloadBid, + GossipPayloadAttestation, + GossipProposerPreferences, LightClientBootstrapRequest, LightClientOptimisticUpdateRequest, LightClientFinalityUpdateRequest, @@ -496,6 +504,10 @@ impl Work { WorkType::GossipLightClientOptimisticUpdate } Work::GossipBlsToExecutionChange(_) => WorkType::GossipBlsToExecutionChange, + Work::GossipExecutionPayload(_) => WorkType::GossipExecutionPayload, + Work::GossipExecutionPayloadBid(_) => WorkType::GossipExecutionPayloadBid, + Work::GossipPayloadAttestation(_) => WorkType::GossipPayloadAttestation, + Work::GossipProposerPreferences(_) => WorkType::GossipProposerPreferences, Work::RpcBlock { .. } => WorkType::RpcBlock, Work::RpcBlobs { .. } => WorkType::RpcBlobs, Work::RpcCustodyColumn { .. } => WorkType::RpcCustodyColumn, @@ -777,10 +789,13 @@ impl BeaconProcessor { // on the delayed ones. } else if let Some(item) = work_queues.delayed_block_queue.pop() { Some(item) - // Check gossip blocks before gossip attestations, since a block might be + // Check gossip blocks and payloads before gossip attestations, since a block might be // required to verify some attestations. } else if let Some(item) = work_queues.gossip_block_queue.pop() { Some(item) + } else if let Some(item) = work_queues.gossip_execution_payload_queue.pop() + { + Some(item) } else if let Some(item) = work_queues.gossip_blob_queue.pop() { Some(item) } else if let Some(item) = work_queues.gossip_data_column_queue.pop() { @@ -903,6 +918,12 @@ impl BeaconProcessor { // Convert any gossip attestations that need to be converted. } else if let Some(item) = work_queues.attestation_to_convert_queue.pop() { Some(item) + // Check payload attestation messages after attestations. They dont give rewards + // but they influence fork choice. + } else if let Some(item) = + work_queues.gossip_payload_attestation_queue.pop() + { + Some(item) // Check sync committee messages after attestations as their rewards are lesser // and they don't influence fork choice. } else if let Some(item) = work_queues.sync_contribution_queue.pop() { @@ -914,6 +935,17 @@ impl BeaconProcessor { } else if let Some(item) = work_queues.unknown_block_aggregate_queue.pop() { Some(item) } else if let Some(item) = work_queues.unknown_block_attestation_queue.pop() + { + Some(item) + // Check execution payload bids. Most proposers will request bids directly from builders + // instead of receiving them over gossip. + } else if let Some(item) = + work_queues.gossip_execution_payload_bid_queue.pop() + { + Some(item) + // Check proposer preferences. + } else if let Some(item) = + work_queues.gossip_proposer_preferences_queue.pop() { Some(item) // Check RPC methods next. Status messages are needed for sync so @@ -1143,6 +1175,18 @@ impl BeaconProcessor { Work::GossipBlsToExecutionChange { .. } => work_queues .gossip_bls_to_execution_change_queue .push(work, work_id), + Work::GossipExecutionPayload { .. } => work_queues + .gossip_execution_payload_queue + .push(work, work_id), + Work::GossipExecutionPayloadBid { .. } => work_queues + .gossip_execution_payload_bid_queue + .push(work, work_id), + Work::GossipPayloadAttestation { .. } => work_queues + .gossip_payload_attestation_queue + .push(work, work_id), + Work::GossipProposerPreferences { .. } => work_queues + .gossip_proposer_preferences_queue + .push(work, work_id), Work::BlobsByRootsRequest { .. } => { work_queues.blob_broots_queue.push(work, work_id) } @@ -1229,6 +1273,18 @@ impl BeaconProcessor { WorkType::GossipBlsToExecutionChange => { work_queues.gossip_bls_to_execution_change_queue.len() } + WorkType::GossipExecutionPayload => { + work_queues.gossip_execution_payload_queue.len() + } + WorkType::GossipExecutionPayloadBid => { + work_queues.gossip_execution_payload_bid_queue.len() + } + WorkType::GossipPayloadAttestation => { + work_queues.gossip_payload_attestation_queue.len() + } + WorkType::GossipProposerPreferences => { + work_queues.gossip_proposer_preferences_queue.len() + } WorkType::LightClientBootstrapRequest => { work_queues.lc_bootstrap_queue.len() } @@ -1383,7 +1439,8 @@ impl BeaconProcessor { Work::IgnoredRpcBlock { process_fn } => task_spawner.spawn_blocking(process_fn), Work::GossipBlock(work) | Work::GossipBlobSidecar(work) - | Work::GossipDataColumnSidecar(work) => task_spawner.spawn_async(async move { + | Work::GossipDataColumnSidecar(work) + | Work::GossipExecutionPayload(work) => task_spawner.spawn_async(async move { work.await; }), Work::BlobsByRangeRequest(process_fn) @@ -1416,6 +1473,9 @@ impl BeaconProcessor { | Work::GossipLightClientOptimisticUpdate(process_fn) | Work::Status(process_fn) | Work::GossipBlsToExecutionChange(process_fn) + | Work::GossipExecutionPayloadBid(process_fn) + | Work::GossipPayloadAttestation(process_fn) + | Work::GossipProposerPreferences(process_fn) | Work::LightClientBootstrapRequest(process_fn) | Work::LightClientOptimisticUpdateRequest(process_fn) | Work::LightClientFinalityUpdateRequest(process_fn) diff --git a/beacon_node/beacon_processor/src/scheduler/work_queue.rs b/beacon_node/beacon_processor/src/scheduler/work_queue.rs index c6f74961d1..934659b304 100644 --- a/beacon_node/beacon_processor/src/scheduler/work_queue.rs +++ b/beacon_node/beacon_processor/src/scheduler/work_queue.rs @@ -135,6 +135,10 @@ pub struct BeaconProcessorQueueLengths { dcbroots_queue: usize, dcbrange_queue: usize, gossip_bls_to_execution_change_queue: usize, + gossip_execution_payload_queue: usize, + gossip_execution_payload_bid_queue: usize, + gossip_payload_attestation_queue: usize, + gossip_proposer_preferences_queue: usize, lc_bootstrap_queue: usize, lc_rpc_optimistic_update_queue: usize, lc_rpc_finality_update_queue: usize, @@ -201,6 +205,15 @@ impl BeaconProcessorQueueLengths { dcbroots_queue: 1024, dcbrange_queue: 1024, gossip_bls_to_execution_change_queue: 16384, + // TODO(EIP-7732): verify 1024 is preferable. I used same value as `gossip_block_queue` and `gossip_blob_queue` + gossip_execution_payload_queue: 1024, + // TODO(EIP-7732) how big should this queue be? + gossip_execution_payload_bid_queue: 1024, + // PTC size ~512 per slot, buffer 2-3 slots for reorgs and processing delays (512 * 3 = 1536) + // TODO(EIP-7732): verify if this is preferable queue length or otherwise + gossip_payload_attestation_queue: 1536, + // TODO(EIP-7732): verify if this is preferable queue length + gossip_proposer_preferences_queue: 1024, lc_gossip_finality_update_queue: 1024, lc_gossip_optimistic_update_queue: 1024, lc_bootstrap_queue: 1024, @@ -245,6 +258,10 @@ pub struct WorkQueues { pub dcbroots_queue: FifoQueue>, pub dcbrange_queue: FifoQueue>, pub gossip_bls_to_execution_change_queue: FifoQueue>, + pub gossip_execution_payload_queue: FifoQueue>, + pub gossip_execution_payload_bid_queue: FifoQueue>, + pub gossip_payload_attestation_queue: FifoQueue>, + pub gossip_proposer_preferences_queue: FifoQueue>, pub lc_gossip_finality_update_queue: FifoQueue>, pub lc_gossip_optimistic_update_queue: FifoQueue>, pub lc_bootstrap_queue: FifoQueue>, @@ -310,6 +327,15 @@ impl WorkQueues { let gossip_bls_to_execution_change_queue = FifoQueue::new(queue_lengths.gossip_bls_to_execution_change_queue); + let gossip_execution_payload_queue = + FifoQueue::new(queue_lengths.gossip_execution_payload_queue); + let gossip_execution_payload_bid_queue = + FifoQueue::new(queue_lengths.gossip_execution_payload_bid_queue); + let gossip_payload_attestation_queue = + FifoQueue::new(queue_lengths.gossip_payload_attestation_queue); + let gossip_proposer_preferences_queue = + FifoQueue::new(queue_lengths.gossip_proposer_preferences_queue); + let lc_gossip_optimistic_update_queue = FifoQueue::new(queue_lengths.lc_gossip_optimistic_update_queue); let lc_gossip_finality_update_queue = @@ -357,6 +383,10 @@ impl WorkQueues { dcbroots_queue, dcbrange_queue, gossip_bls_to_execution_change_queue, + gossip_execution_payload_queue, + gossip_execution_payload_bid_queue, + gossip_payload_attestation_queue, + gossip_proposer_preferences_queue, lc_gossip_optimistic_update_queue, lc_gossip_finality_update_queue, lc_bootstrap_queue, diff --git a/beacon_node/lighthouse_network/src/service/gossip_cache.rs b/beacon_node/lighthouse_network/src/service/gossip_cache.rs index 120b9e6c24..e9862e3f74 100644 --- a/beacon_node/lighthouse_network/src/service/gossip_cache.rs +++ b/beacon_node/lighthouse_network/src/service/gossip_cache.rs @@ -40,6 +40,14 @@ pub struct GossipCache { sync_committee_message: Option, /// Timeout for signed BLS to execution changes. bls_to_execution_change: Option, + /// Timeout for signed execution payload envelope. + execution_payload: Option, + /// Timeout for execution payload bid. + execution_payload_bid: Option, + /// Timeout for payload attestation message. + payload_attestation: Option, + /// Timeout for proposer preferences. + proposer_preferences: Option, /// Timeout for light client finality updates. light_client_finality_update: Option, /// Timeout for light client optimistic updates. @@ -71,6 +79,14 @@ pub struct GossipCacheBuilder { sync_committee_message: Option, /// Timeout for signed BLS to execution changes. bls_to_execution_change: Option, + /// Timeout for signed execution payload envelope. + execution_payload: Option, + /// Timeout for execution payload bid. + execution_payload_bid: Option, + /// Timeout for payload attestation message. + payload_attestation: Option, + /// Timeout for proposer preferences. + proposer_preferences: Option, /// Timeout for light client finality updates. light_client_finality_update: Option, /// Timeout for light client optimistic updates. @@ -139,6 +155,30 @@ impl GossipCacheBuilder { self } + /// Timeout for signed execution payload envelope. + pub fn execution_payload_timeout(mut self, timeout: Duration) -> Self { + self.execution_payload = Some(timeout); + self + } + + /// Timeout for execution payload bid. + pub fn execution_payload_bid_timeout(mut self, timeout: Duration) -> Self { + self.execution_payload_bid = Some(timeout); + self + } + + /// Timeout for payload attestation message. + pub fn payload_attestation_timeout(mut self, timeout: Duration) -> Self { + self.payload_attestation = Some(timeout); + self + } + + /// Timeout for proposer preferences. + pub fn proposer_preferences_timeout(mut self, timeout: Duration) -> Self { + self.proposer_preferences = Some(timeout); + self + } + /// Timeout for light client finality update messages. pub fn light_client_finality_update_timeout(mut self, timeout: Duration) -> Self { self.light_client_finality_update = Some(timeout); @@ -165,6 +205,10 @@ impl GossipCacheBuilder { signed_contribution_and_proof, sync_committee_message, bls_to_execution_change, + execution_payload, + execution_payload_bid, + payload_attestation, + proposer_preferences, light_client_finality_update, light_client_optimistic_update, } = self; @@ -182,6 +226,10 @@ impl GossipCacheBuilder { signed_contribution_and_proof: signed_contribution_and_proof.or(default_timeout), sync_committee_message: sync_committee_message.or(default_timeout), bls_to_execution_change: bls_to_execution_change.or(default_timeout), + execution_payload: execution_payload.or(default_timeout), + execution_payload_bid: execution_payload_bid.or(default_timeout), + payload_attestation: payload_attestation.or(default_timeout), + proposer_preferences: proposer_preferences.or(default_timeout), light_client_finality_update: light_client_finality_update.or(default_timeout), light_client_optimistic_update: light_client_optimistic_update.or(default_timeout), } @@ -209,6 +257,10 @@ impl GossipCache { GossipKind::SignedContributionAndProof => self.signed_contribution_and_proof, GossipKind::SyncCommitteeMessage(_) => self.sync_committee_message, GossipKind::BlsToExecutionChange => self.bls_to_execution_change, + GossipKind::ExecutionPayload => self.execution_payload, + GossipKind::ExecutionPayloadBid => self.execution_payload_bid, + GossipKind::PayloadAttestation => self.payload_attestation, + GossipKind::ProposerPreferences => self.proposer_preferences, GossipKind::LightClientFinalityUpdate => self.light_client_finality_update, GossipKind::LightClientOptimisticUpdate => self.light_client_optimistic_update, }; diff --git a/beacon_node/lighthouse_network/src/service/utils.rs b/beacon_node/lighthouse_network/src/service/utils.rs index c9b4906f34..d235e4b28f 100644 --- a/beacon_node/lighthouse_network/src/service/utils.rs +++ b/beacon_node/lighthouse_network/src/service/utils.rs @@ -272,6 +272,10 @@ pub(crate) fn create_whitelist_filter( add(AttesterSlashing); add(SignedContributionAndProof); add(BlsToExecutionChange); + add(ExecutionPayload); + add(ExecutionPayloadBid); + add(PayloadAttestation); + add(ProposerPreferences); add(LightClientFinalityUpdate); add(LightClientOptimisticUpdate); for id in 0..spec.attestation_subnet_count { diff --git a/beacon_node/lighthouse_network/src/types/pubsub.rs b/beacon_node/lighthouse_network/src/types/pubsub.rs index ffdbbc43be..d1df7face7 100644 --- a/beacon_node/lighthouse_network/src/types/pubsub.rs +++ b/beacon_node/lighthouse_network/src/types/pubsub.rs @@ -10,13 +10,14 @@ use std::sync::Arc; use types::{ AttesterSlashing, AttesterSlashingBase, AttesterSlashingElectra, BlobSidecar, DataColumnSidecar, DataColumnSubnetId, EthSpec, ForkContext, ForkName, - LightClientFinalityUpdate, LightClientOptimisticUpdate, ProposerSlashing, - SignedAggregateAndProof, SignedAggregateAndProofBase, SignedAggregateAndProofElectra, - SignedBeaconBlock, SignedBeaconBlockAltair, SignedBeaconBlockBase, SignedBeaconBlockBellatrix, - SignedBeaconBlockCapella, SignedBeaconBlockDeneb, SignedBeaconBlockElectra, - SignedBeaconBlockFulu, SignedBeaconBlockGloas, SignedBlsToExecutionChange, - SignedContributionAndProof, SignedVoluntaryExit, SingleAttestation, SubnetId, - SyncCommitteeMessage, SyncSubnetId, + LightClientFinalityUpdate, LightClientOptimisticUpdate, PayloadAttestationMessage, + ProposerSlashing, SignedAggregateAndProof, SignedAggregateAndProofBase, + SignedAggregateAndProofElectra, SignedBeaconBlock, SignedBeaconBlockAltair, + SignedBeaconBlockBase, SignedBeaconBlockBellatrix, SignedBeaconBlockCapella, + SignedBeaconBlockDeneb, SignedBeaconBlockElectra, SignedBeaconBlockFulu, + SignedBeaconBlockGloas, SignedBlsToExecutionChange, SignedContributionAndProof, + SignedExecutionPayloadBid, SignedExecutionPayloadEnvelope, SignedProposerPreferences, + SignedVoluntaryExit, SingleAttestation, SubnetId, SyncCommitteeMessage, SyncSubnetId, }; #[derive(Debug, Clone, PartialEq)] @@ -43,6 +44,14 @@ pub enum PubsubMessage { SyncCommitteeMessage(Box<(SyncSubnetId, SyncCommitteeMessage)>), /// Gossipsub message for BLS to execution change messages. BlsToExecutionChange(Box), + /// Gossipsub message providing notification of a signed execution payload envelope. + ExecutionPayload(Box>), + /// Gossipsub message providing notification of a payload attestation message. + PayloadAttestation(Box), + /// Gossipsub message providing notification of a signed execution payload bid. + ExecutionPayloadBid(Box), + /// Gossipsub message providing notification of signed proposer preferences. + ProposerPreferences(Box), /// Gossipsub message providing notification of a light client finality update. LightClientFinalityUpdate(Box>), /// Gossipsub message providing notification of a light client optimistic update. @@ -146,6 +155,10 @@ impl PubsubMessage { PubsubMessage::SignedContributionAndProof(_) => GossipKind::SignedContributionAndProof, PubsubMessage::SyncCommitteeMessage(data) => GossipKind::SyncCommitteeMessage(data.0), PubsubMessage::BlsToExecutionChange(_) => GossipKind::BlsToExecutionChange, + PubsubMessage::ExecutionPayload(_) => GossipKind::ExecutionPayload, + PubsubMessage::PayloadAttestation(_) => GossipKind::PayloadAttestation, + PubsubMessage::ExecutionPayloadBid(_) => GossipKind::ExecutionPayloadBid, + PubsubMessage::ProposerPreferences(_) => GossipKind::ProposerPreferences, PubsubMessage::LightClientFinalityUpdate(_) => GossipKind::LightClientFinalityUpdate, PubsubMessage::LightClientOptimisticUpdate(_) => { GossipKind::LightClientOptimisticUpdate @@ -350,6 +363,35 @@ impl PubsubMessage { bls_to_execution_change, ))) } + GossipKind::ExecutionPayload => { + let execution_payload_envelope = + SignedExecutionPayloadEnvelope::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + Ok(PubsubMessage::ExecutionPayload(Box::new( + execution_payload_envelope, + ))) + } + GossipKind::ExecutionPayloadBid => { + let execution_payload_bid = SignedExecutionPayloadBid::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + Ok(PubsubMessage::ExecutionPayloadBid(Box::new( + execution_payload_bid, + ))) + } + GossipKind::PayloadAttestation => { + let payload_attestation = PayloadAttestationMessage::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + Ok(PubsubMessage::PayloadAttestation(Box::new( + payload_attestation, + ))) + } + GossipKind::ProposerPreferences => { + let proposer_preferences = SignedProposerPreferences::from_ssz_bytes(data) + .map_err(|e| format!("{:?}", e))?; + Ok(PubsubMessage::ProposerPreferences(Box::new( + proposer_preferences, + ))) + } GossipKind::LightClientFinalityUpdate => { let light_client_finality_update = match fork_context .get_fork_from_context_bytes(gossip_topic.fork_digest) @@ -412,6 +454,10 @@ impl PubsubMessage { PubsubMessage::SignedContributionAndProof(data) => data.as_ssz_bytes(), PubsubMessage::SyncCommitteeMessage(data) => data.1.as_ssz_bytes(), PubsubMessage::BlsToExecutionChange(data) => data.as_ssz_bytes(), + PubsubMessage::ExecutionPayload(data) => data.as_ssz_bytes(), + PubsubMessage::PayloadAttestation(data) => data.as_ssz_bytes(), + PubsubMessage::ExecutionPayloadBid(data) => data.as_ssz_bytes(), + PubsubMessage::ProposerPreferences(data) => data.as_ssz_bytes(), PubsubMessage::LightClientFinalityUpdate(data) => data.as_ssz_bytes(), PubsubMessage::LightClientOptimisticUpdate(data) => data.as_ssz_bytes(), } @@ -467,6 +513,38 @@ impl std::fmt::Display for PubsubMessage { data.message.validator_index, data.message.to_execution_address ) } + PubsubMessage::ExecutionPayload(data) => { + write!( + f, + "Signed Execution Payload Envelope: slot: {:?}, beacon block root: {:?}", + data.slot(), + data.beacon_block_root() + ) + } + PubsubMessage::PayloadAttestation(data) => { + write!( + f, + "Payload Attestation Message: slot: {:?}, beacon block root: {:?}, payload present: {:?}, blob data available: {:?}", + data.data.slot, + data.data.beacon_block_root, + data.data.payload_present, + data.data.blob_data_available + ) + } + PubsubMessage::ExecutionPayloadBid(data) => { + write!( + f, + "Execution payload bid: slot: {:?} value: {:?}", + data.message.slot, data.message.value + ) + } + PubsubMessage::ProposerPreferences(data) => { + write!( + f, + "Proposer preferences: slot: {:?}, validator_index: {:?}", + data.message.proposal_slot, data.message.validator_index + ) + } PubsubMessage::LightClientFinalityUpdate(_data) => { write!(f, "Light CLient Finality Update") } diff --git a/beacon_node/lighthouse_network/src/types/topics.rs b/beacon_node/lighthouse_network/src/types/topics.rs index bdd62aa7cb..a3ea4babce 100644 --- a/beacon_node/lighthouse_network/src/types/topics.rs +++ b/beacon_node/lighthouse_network/src/types/topics.rs @@ -29,6 +29,10 @@ pub const ATTESTER_SLASHING_TOPIC: &str = "attester_slashing"; pub const SIGNED_CONTRIBUTION_AND_PROOF_TOPIC: &str = "sync_committee_contribution_and_proof"; pub const SYNC_COMMITTEE_PREFIX_TOPIC: &str = "sync_committee_"; pub const BLS_TO_EXECUTION_CHANGE_TOPIC: &str = "bls_to_execution_change"; +pub const EXECUTION_PAYLOAD: &str = "execution_payload"; +pub const EXECUTION_PAYLOAD_BID: &str = "execution_payload_bid"; +pub const PAYLOAD_ATTESTATION: &str = "payload_attestation_message"; +pub const PROPOSER_PREFERENCES: &str = "proposer_preferences"; pub const LIGHT_CLIENT_FINALITY_UPDATE: &str = "light_client_finality_update"; pub const LIGHT_CLIENT_OPTIMISTIC_UPDATE: &str = "light_client_optimistic_update"; @@ -91,6 +95,13 @@ pub fn core_topics_to_subscribe( } } + if fork_name.gloas_enabled() { + topics.push(GossipKind::ExecutionPayload); + topics.push(GossipKind::ExecutionPayloadBid); + topics.push(GossipKind::PayloadAttestation); + topics.push(GossipKind::ProposerPreferences); + } + topics } @@ -114,6 +125,10 @@ pub fn is_fork_non_core_topic(topic: &GossipTopic, _fork_name: ForkName) -> bool | GossipKind::AttesterSlashing | GossipKind::SignedContributionAndProof | GossipKind::BlsToExecutionChange + | GossipKind::ExecutionPayload + | GossipKind::ExecutionPayloadBid + | GossipKind::PayloadAttestation + | GossipKind::ProposerPreferences | GossipKind::LightClientFinalityUpdate | GossipKind::LightClientOptimisticUpdate => false, } @@ -171,6 +186,14 @@ pub enum GossipKind { SyncCommitteeMessage(SyncSubnetId), /// Topic for validator messages which change their withdrawal address. BlsToExecutionChange, + /// Topic for signed execution payload envelopes. + ExecutionPayload, + /// Topic for payload attestation messages. + PayloadAttestation, + /// Topic for signed execution payload bids. + ExecutionPayloadBid, + /// Topic for signed proposer preferences. + ProposerPreferences, /// Topic for publishing finality updates for light clients. LightClientFinalityUpdate, /// Topic for publishing optimistic updates for light clients. @@ -255,6 +278,10 @@ impl GossipTopic { PROPOSER_SLASHING_TOPIC => GossipKind::ProposerSlashing, ATTESTER_SLASHING_TOPIC => GossipKind::AttesterSlashing, BLS_TO_EXECUTION_CHANGE_TOPIC => GossipKind::BlsToExecutionChange, + EXECUTION_PAYLOAD => GossipKind::ExecutionPayload, + EXECUTION_PAYLOAD_BID => GossipKind::ExecutionPayloadBid, + PAYLOAD_ATTESTATION => GossipKind::PayloadAttestation, + PROPOSER_PREFERENCES => GossipKind::ProposerPreferences, LIGHT_CLIENT_FINALITY_UPDATE => GossipKind::LightClientFinalityUpdate, LIGHT_CLIENT_OPTIMISTIC_UPDATE => GossipKind::LightClientOptimisticUpdate, topic => match subnet_topic_index(topic) { @@ -320,6 +347,10 @@ impl std::fmt::Display for GossipTopic { format!("{}{}", DATA_COLUMN_SIDECAR_PREFIX, *column_subnet_id) } GossipKind::BlsToExecutionChange => BLS_TO_EXECUTION_CHANGE_TOPIC.into(), + GossipKind::ExecutionPayload => EXECUTION_PAYLOAD.into(), + GossipKind::PayloadAttestation => PAYLOAD_ATTESTATION.into(), + GossipKind::ExecutionPayloadBid => EXECUTION_PAYLOAD_BID.into(), + GossipKind::ProposerPreferences => PROPOSER_PREFERENCES.into(), GossipKind::LightClientFinalityUpdate => LIGHT_CLIENT_FINALITY_UPDATE.into(), GossipKind::LightClientOptimisticUpdate => LIGHT_CLIENT_OPTIMISTIC_UPDATE.into(), }; 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 51083d1e09..fec557ec04 100644 --- a/beacon_node/network/src/network_beacon_processor/gossip_methods.rs +++ b/beacon_node/network/src/network_beacon_processor/gossip_methods.rs @@ -35,9 +35,11 @@ use tracing::{Instrument, Span, debug, error, info, instrument, trace, warn}; use types::{ Attestation, AttestationData, AttestationRef, AttesterSlashing, BlobSidecar, DataColumnSidecar, DataColumnSubnetId, EthSpec, Hash256, IndexedAttestation, LightClientFinalityUpdate, - LightClientOptimisticUpdate, ProposerSlashing, SignedAggregateAndProof, SignedBeaconBlock, - SignedBlsToExecutionChange, SignedContributionAndProof, SignedVoluntaryExit, SingleAttestation, - Slot, SubnetId, SyncCommitteeMessage, SyncSubnetId, block::BlockImportSource, + LightClientOptimisticUpdate, PayloadAttestationMessage, ProposerSlashing, + SignedAggregateAndProof, SignedBeaconBlock, SignedBlsToExecutionChange, + SignedContributionAndProof, SignedExecutionPayloadBid, SignedExecutionPayloadEnvelope, + SignedProposerPreferences, SignedVoluntaryExit, SingleAttestation, Slot, SubnetId, + SyncCommitteeMessage, SyncSubnetId, block::BlockImportSource, }; use beacon_processor::work_reprocessing_queue::QueuedColumnReconstruction; @@ -3221,4 +3223,85 @@ impl NetworkBeaconProcessor { write_file(error_path, error.to_string().as_bytes()); } } + + pub async fn process_gossip_execution_payload( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + execution_payload: SignedExecutionPayloadEnvelope, + ) { + // TODO(EIP-7732): Implement proper execution payload envelope gossip processing. + // This should integrate with the envelope_verification.rs module once it's implemented. + + trace!( + %peer_id, + builder_index = execution_payload.message.builder_index, + slot = %execution_payload.message.slot, + beacon_block_root = %execution_payload.message.beacon_block_root, + "Processing execution payload envelope" + ); + + // For now, ignore all envelopes since verification is not implemented + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + } + + pub fn process_gossip_execution_payload_bid( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + payload_bid: SignedExecutionPayloadBid, + ) { + // TODO(EIP-7732): Implement proper payload bid gossip processing. + // This should integrate with a payload execution bid verification module once it's implemented. + + trace!( + %peer_id, + slot = %payload_bid.message.slot, + value = %payload_bid.message.value, + "Processing execution payload bid" + ); + + // For now, ignore all payload bids since verification is not implemented + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + } + + pub fn process_gossip_payload_attestation( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + payload_attestation_message: PayloadAttestationMessage, + ) { + // TODO(EIP-7732): Implement proper payload attestation message gossip processing. + // This should integrate with a payload_attestation_verification.rs module once it's implemented. + + 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" + ); + + // For now, ignore all payload attestation messages since verification is not implemented + self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore); + } + + pub fn process_gossip_proposer_preferences( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + proposer_preferences: SignedProposerPreferences, + ) { + // TODO(EIP-7732): Implement proper proposer preferences gossip processing. + + trace!( + %peer_id, + validator_index = proposer_preferences.message.validator_index, + slot = %proposer_preferences.message.proposal_slot, + "Processing proposer preferences" + ); + + // For now, ignore all proposer preferences since verification is not implemented + 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 5f1ba18391..c326dfd597 100644 --- a/beacon_node/network/src/network_beacon_processor/mod.rs +++ b/beacon_node/network/src/network_beacon_processor/mod.rs @@ -423,6 +423,92 @@ impl NetworkBeaconProcessor { }) } + /// Create a new `Work` event for some execution payload envelope. + pub fn send_gossip_execution_payload( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + execution_payload: Box>, + ) -> Result<(), Error> { + let processor = self.clone(); + let process_fn = async move { + processor + .process_gossip_execution_payload(message_id, peer_id, *execution_payload) + .await + }; + + self.try_send(BeaconWorkEvent { + drop_during_sync: false, + work: Work::GossipExecutionPayload(Box::pin(process_fn)), + }) + } + + /// Create a new `Work` event for some execution payload bid + pub fn send_gossip_execution_payload_bid( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + execution_payload_bid: Box, + ) -> Result<(), Error> { + let processor = self.clone(); + let process_fn = move || { + processor.process_gossip_execution_payload_bid( + message_id, + peer_id, + *execution_payload_bid, + ) + }; + + self.try_send(BeaconWorkEvent { + drop_during_sync: true, + work: Work::GossipExecutionPayloadBid(Box::new(process_fn)), + }) + } + + /// Create a new `Work` event for some payload attestation + pub fn send_gossip_payload_attestation( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + payload_attestation_message: Box, + ) -> Result<(), Error> { + let processor = self.clone(); + let process_fn = move || { + processor.process_gossip_payload_attestation( + message_id, + peer_id, + *payload_attestation_message, + ) + }; + + self.try_send(BeaconWorkEvent { + drop_during_sync: true, + work: Work::GossipPayloadAttestation(Box::new(process_fn)), + }) + } + + /// Create a new `Work` event for some proposer preferences + pub fn send_gossip_proposer_preferences( + self: &Arc, + message_id: MessageId, + peer_id: PeerId, + proposer_preferences: Box, + ) -> Result<(), Error> { + let processor = self.clone(); + let process_fn = move || { + processor.process_gossip_proposer_preferences( + message_id, + peer_id, + *proposer_preferences, + ) + }; + + self.try_send(BeaconWorkEvent { + drop_during_sync: false, + work: Work::GossipProposerPreferences(Box::new(process_fn)), + }) + } + /// Create a new `Work` event for some block, where the result from computation (if any) is /// sent to the other side of `result_tx`. pub fn send_rpc_beacon_block( diff --git a/beacon_node/network/src/router.rs b/beacon_node/network/src/router.rs index 60fe094bb7..8373dec322 100644 --- a/beacon_node/network/src/router.rs +++ b/beacon_node/network/src/router.rs @@ -486,6 +486,49 @@ impl Router { bls_to_execution_change, ), ), + PubsubMessage::ExecutionPayload(signed_execution_payload_envelope) => { + trace!(%peer_id, "Received a signed execution payload envelope"); + self.handle_beacon_processor_send_result( + self.network_beacon_processor.send_gossip_execution_payload( + message_id, + peer_id, + signed_execution_payload_envelope, + ), + ) + } + PubsubMessage::PayloadAttestation(payload_attestation_message) => { + trace!(%peer_id, "Received a payload attestation message"); + self.handle_beacon_processor_send_result( + self.network_beacon_processor + .send_gossip_payload_attestation( + message_id, + peer_id, + payload_attestation_message, + ), + ) + } + PubsubMessage::ExecutionPayloadBid(execution_payload_bid) => { + trace!(%peer_id, "Received a signed execution payload bid"); + self.handle_beacon_processor_send_result( + self.network_beacon_processor + .send_gossip_execution_payload_bid( + message_id, + peer_id, + execution_payload_bid, + ), + ) + } + PubsubMessage::ProposerPreferences(proposer_preferences) => { + trace!(%peer_id, "Received signed proposer preferences"); + self.handle_beacon_processor_send_result( + self.network_beacon_processor + .send_gossip_proposer_preferences( + message_id, + peer_id, + proposer_preferences, + ), + ) + } } } diff --git a/consensus/types/src/builder/mod.rs b/consensus/types/src/builder/mod.rs index f4e0e346f2..bc6140f9d9 100644 --- a/consensus/types/src/builder/mod.rs +++ b/consensus/types/src/builder/mod.rs @@ -2,6 +2,7 @@ mod builder; mod builder_bid; mod builder_pending_payment; mod builder_pending_withdrawal; +mod proposer_preferences; pub use builder::{Builder, BuilderIndex}; pub use builder_bid::{ @@ -10,3 +11,4 @@ pub use builder_bid::{ }; pub use builder_pending_payment::BuilderPendingPayment; pub use builder_pending_withdrawal::BuilderPendingWithdrawal; +pub use proposer_preferences::{ProposerPreferences, SignedProposerPreferences}; diff --git a/consensus/types/src/builder/proposer_preferences.rs b/consensus/types/src/builder/proposer_preferences.rs new file mode 100644 index 0000000000..46dffdf3b7 --- /dev/null +++ b/consensus/types/src/builder/proposer_preferences.rs @@ -0,0 +1,51 @@ +use crate::test_utils::TestRandom; +use crate::{Address, ForkName, SignedRoot, Slot}; +use bls::Signature; +use context_deserialize::context_deserialize; +use educe::Educe; +use serde::{Deserialize, Serialize}; +use ssz_derive::{Decode, Encode}; +use test_random_derive::TestRandom; +use tree_hash_derive::TreeHash; + +#[derive( + Default, Debug, Clone, Serialize, Encode, Decode, Deserialize, TreeHash, Educe, TestRandom, +)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[educe(PartialEq, Hash)] +#[context_deserialize(ForkName)] +// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/p2p-interface.md#new-proposerpreferences +pub struct ProposerPreferences { + pub proposal_slot: Slot, + pub validator_index: u64, + pub fee_recipient: Address, + pub gas_limit: u64, +} + +impl SignedRoot for ProposerPreferences {} + +#[derive(TestRandom, TreeHash, Debug, Clone, Encode, Decode, Serialize, Deserialize, Educe)] +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] +#[educe(PartialEq, Hash)] +#[context_deserialize(ForkName)] +// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/p2p-interface.md#new-signedproposerpreferences +pub struct SignedProposerPreferences { + pub message: ProposerPreferences, + pub signature: Signature, +} + +impl SignedProposerPreferences { + pub fn empty() -> Self { + Self { + message: ProposerPreferences::default(), + signature: Signature::empty(), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + ssz_and_tree_hash_tests!(ProposerPreferences); +}