diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 4a06c9597..04cb11cd0 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -59,7 +59,7 @@ use types::{ ProposerPreparationData, ProposerSlashing, RelativeEpoch, SignedAggregateAndProof, SignedBeaconBlock, SignedBlindedBeaconBlock, SignedBlsToExecutionChange, SignedContributionAndProof, SignedValidatorRegistrationData, SignedVoluntaryExit, Slot, - SyncCommitteeMessage, SyncContributionData, + SyncCommitteeMessage, SyncContributionData, SignedBlockContents, }; use version::{ add_consensus_version_header, execution_optimistic_fork_versioned_response, @@ -1120,11 +1120,11 @@ pub fn serve( .and(network_tx_filter.clone()) .and(log_filter.clone()) .and_then( - |block: Arc>, + |block_contents: SignedBlockContents, chain: Arc>, network_tx: UnboundedSender>, log: Logger| async move { - publish_blocks::publish_block(None, block, chain, &network_tx, log) + publish_blocks::publish_block(None, block_contents, chain, &network_tx, log) .await .map(|()| warp::reply().into_response()) }, diff --git a/beacon_node/http_api/src/publish_blocks.rs b/beacon_node/http_api/src/publish_blocks.rs index 1e785cd1e..49d655785 100644 --- a/beacon_node/http_api/src/publish_blocks.rs +++ b/beacon_node/http_api/src/publish_blocks.rs @@ -12,19 +12,21 @@ use tokio::sync::mpsc::UnboundedSender; use tree_hash::TreeHash; use types::{ AbstractExecPayload, BlindedPayload, EthSpec, ExecPayload, ExecutionBlockHash, FullPayload, - Hash256, SignedBeaconBlock, + Hash256, SignedBeaconBlock, SignedBlockContents, }; use warp::Rejection; /// Handles a request from the HTTP API for full blocks. pub async fn publish_block( block_root: Option, - block: Arc>, + block_contents: SignedBlockContents, chain: Arc>, network_tx: &UnboundedSender>, log: Logger, ) -> Result<(), Rejection> { let seen_timestamp = timestamp_now(); + let (block, maybe_blobs) = block_contents.deconstruct(); + let block = Arc::new(block); //FIXME(sean) have to move this to prior to publishing because it's included in the blobs sidecar message. //this may skew metrics @@ -37,25 +39,27 @@ pub async fn publish_block( // Send the block, regardless of whether or not it is valid. The API // specification is very clear that this is the desired behaviour. - let wrapped_block: BlockWrapper = - if matches!(block.as_ref(), &SignedBeaconBlock::Eip4844(_)) { - if let Some(sidecar) = chain.blob_cache.pop(&block_root) { - // TODO: Needs to be adjusted - // let block_and_blobs = SignedBeaconBlockAndBlobsSidecar { - // beacon_block: block, - // blobs_sidecar: Arc::new(sidecar), - // }; - unimplemented!("Needs to be adjusted") - } else { - //FIXME(sean): This should probably return a specific no-blob-cached error code, beacon API coordination required - return Err(warp_utils::reject::broadcast_without_import( - "no blob cached for block".into(), - )); - } - } else { + let wrapped_block: BlockWrapper = match block.as_ref() { + SignedBeaconBlock::Base(_) + | SignedBeaconBlock::Altair(_) + | SignedBeaconBlock::Merge(_) + | SignedBeaconBlock::Capella(_) => { crate::publish_pubsub_message(network_tx, PubsubMessage::BeaconBlock(block.clone()))?; block.into() - }; + } + SignedBeaconBlock::Eip4844(_) => { + crate::publish_pubsub_message(network_tx, PubsubMessage::BeaconBlock(block.clone()))?; + if let Some(blobs) = maybe_blobs { + for (blob_index, blob) in blobs.into_iter().enumerate() { + crate::publish_pubsub_message( + network_tx, + PubsubMessage::BlobSidecar(Box::new((blob_index as u64, blob))), + )?; + } + } + block.into() + } + }; // Determine the delay after the start of the slot, register it with metrics. let block = wrapped_block.as_block(); @@ -180,7 +184,7 @@ pub async fn publish_blinded_block( let full_block = reconstruct_block(chain.clone(), block_root, block, log.clone()).await?; publish_block::( Some(block_root), - Arc::new(full_block), + SignedBlockContents::Block(full_block), chain, network_tx, log, diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index 5a55f21e3..2a27d31da 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -612,7 +612,7 @@ impl BeaconNodeHttpClient { /// Returns `Ok(None)` on a 404 error. pub async fn post_beacon_blocks>( &self, - block: &SignedBeaconBlock, + block_contents: &SignedBlockContents, ) -> Result<(), Error> { let mut path = self.eth_path(V1)?; @@ -621,7 +621,7 @@ impl BeaconNodeHttpClient { .push("beacon") .push("blocks"); - self.post_with_timeout(path, block, self.timeouts.proposal) + self.post_with_timeout(path, block_contents, self.timeouts.proposal) .await?; Ok(()) diff --git a/consensus/types/src/lib.rs b/consensus/types/src/lib.rs index f931e0365..1c6f0b9ef 100644 --- a/consensus/types/src/lib.rs +++ b/consensus/types/src/lib.rs @@ -103,6 +103,7 @@ pub mod blobs_sidecar; pub mod signed_blob; pub mod signed_block_and_blobs; pub mod transaction; +pub mod signed_block_contents; use ethereum_types::{H160, H256}; @@ -183,8 +184,8 @@ pub use crate::signed_beacon_block::{ }; pub use crate::signed_beacon_block_header::SignedBeaconBlockHeader; pub use crate::signed_blob::*; -pub use crate::signed_block_and_blobs::SignedBeaconBlockAndBlobsSidecar; -pub use crate::signed_block_and_blobs::SignedBeaconBlockAndBlobsSidecarDecode; +pub use crate::signed_block_and_blobs::{SignedBeaconBlockAndBlobsSidecar, SignedBeaconBlockAndBlobsSidecarDecode, SignedBeaconBlockAndBlobSidecars}; +pub use crate::signed_block_contents::SignedBlockContents; pub use crate::signed_bls_to_execution_change::SignedBlsToExecutionChange; pub use crate::signed_contribution_and_proof::SignedContributionAndProof; pub use crate::signed_voluntary_exit::SignedVoluntaryExit; diff --git a/consensus/types/src/signed_blob.rs b/consensus/types/src/signed_blob.rs index 8e2e47676..d7d2f884d 100644 --- a/consensus/types/src/signed_blob.rs +++ b/consensus/types/src/signed_blob.rs @@ -3,6 +3,7 @@ use serde_derive::{Deserialize, Serialize}; use ssz_derive::{Decode, Encode}; use test_random_derive::TestRandom; use tree_hash_derive::TreeHash; +use derivative::Derivative; #[derive( Debug, @@ -14,10 +15,12 @@ use tree_hash_derive::TreeHash; Decode, TestRandom, TreeHash, + Derivative, arbitrary::Arbitrary, )] #[serde(bound = "T: EthSpec")] #[arbitrary(bound = "T: EthSpec")] +#[derivative(Hash(bound = "T: EthSpec"))] pub struct SignedBlobSidecar { pub message: BlobSidecar, pub signature: Signature, diff --git a/consensus/types/src/signed_block_and_blobs.rs b/consensus/types/src/signed_block_and_blobs.rs index 4ea0d6616..c6d154ef0 100644 --- a/consensus/types/src/signed_block_and_blobs.rs +++ b/consensus/types/src/signed_block_and_blobs.rs @@ -1,8 +1,12 @@ -use crate::{BlobsSidecar, EthSpec, SignedBeaconBlock, SignedBeaconBlockEip4844}; +use crate::{ + AbstractExecPayload, BlobsSidecar, EthSpec, SignedBeaconBlock, SignedBeaconBlockEip4844, + SignedBlobSidecar, +}; use derivative::Derivative; use serde_derive::{Deserialize, Serialize}; use ssz::{Decode, DecodeError}; use ssz_derive::{Decode, Encode}; +use ssz_types::VariableList; use std::sync::Arc; use tree_hash_derive::TreeHash; @@ -13,6 +17,7 @@ pub struct SignedBeaconBlockAndBlobsSidecarDecode { pub blobs_sidecar: BlobsSidecar, } +// TODO: will be removed once we decouple blobs in Gossip #[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative)] #[derivative(PartialEq, Hash(bound = "T: EthSpec"))] pub struct SignedBeaconBlockAndBlobsSidecar { @@ -32,3 +37,11 @@ impl SignedBeaconBlockAndBlobsSidecar { }) } } + +#[derive(Debug, Clone, Serialize, Deserialize, Encode, TreeHash, Derivative)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[serde(bound = "T: EthSpec")] +pub struct SignedBeaconBlockAndBlobSidecars> { + pub signed_block: SignedBeaconBlock, + pub signed_blob_sidecars: VariableList, ::MaxBlobsPerBlock>, +} diff --git a/consensus/types/src/signed_block_contents.rs b/consensus/types/src/signed_block_contents.rs new file mode 100644 index 000000000..a6743c60f --- /dev/null +++ b/consensus/types/src/signed_block_contents.rs @@ -0,0 +1,40 @@ +use crate::{AbstractExecPayload, EthSpec, FullPayload, SignedBeaconBlock, SignedBlobSidecar}; +use crate::signed_block_and_blobs::SignedBeaconBlockAndBlobSidecars; +use derivative::Derivative; +use serde_derive::{Deserialize, Serialize}; +use ssz_types::VariableList; + +/// A wrapper over a [`SignedBeaconBlock`] or a [`SignedBeaconBlockAndBlobSidecars`]. +#[derive(Clone, Debug, Derivative, Serialize, Deserialize)] +#[derivative(PartialEq, Hash(bound = "T: EthSpec"))] +#[serde(untagged)] +#[serde(bound = "T: EthSpec")] +pub enum SignedBlockContents = FullPayload> { + BlockAndBlobSidecars(SignedBeaconBlockAndBlobSidecars), + Block(SignedBeaconBlock), +} + +impl> SignedBlockContents { + pub fn signed_block(&self) -> &SignedBeaconBlock { + match self { + SignedBlockContents::BlockAndBlobSidecars(block_and_sidecars) => &block_and_sidecars.signed_block, + SignedBlockContents::Block(block) => block, + } + } + + pub fn deconstruct(self) -> (SignedBeaconBlock, Option, ::MaxBlobsPerBlock>>) { + match self { + SignedBlockContents::BlockAndBlobSidecars(block_and_sidecars) => ( + block_and_sidecars.signed_block, + Some(block_and_sidecars.signed_blob_sidecars), + ), + SignedBlockContents::Block(block) => (block, None), + } + } +} + +impl> From> for SignedBlockContents { + fn from(block: SignedBeaconBlock) -> Self { + SignedBlockContents::Block(block) + } +} \ No newline at end of file diff --git a/validator_client/src/block_service.rs b/validator_client/src/block_service.rs index 22064cb10..0cc0e40a1 100644 --- a/validator_client/src/block_service.rs +++ b/validator_client/src/block_service.rs @@ -14,10 +14,7 @@ use std::sync::Arc; use std::time::Duration; use tokio::sync::mpsc; use tokio::time::sleep; -use types::{ - AbstractExecPayload, BeaconBlock, BlindedPayload, BlockType, EthSpec, FullPayload, Graffiti, - PublicKeyBytes, Slot, -}; +use types::{AbstractExecPayload, BeaconBlock, BlindedPayload, BlockType, EthSpec, FullPayload, Graffiti, PublicKeyBytes, SignedBlockContents, Slot}; #[derive(Debug)] pub enum BlockError { @@ -410,11 +407,12 @@ impl BlockService { .await?; let signing_timer = metrics::start_timer(&metrics::BLOCK_SIGNING_TIMES); - let signed_block = self_ref + let signed_block_contents: SignedBlockContents = self_ref .validator_store .sign_block::(*validator_pubkey_ref, block, current_slot) .await - .map_err(|e| BlockError::Recoverable(format!("Unable to sign block: {:?}", e)))?; + .map_err(|e| BlockError::Recoverable(format!("Unable to sign block: {:?}", e)))? + .into(); let signing_time_ms = Duration::from_secs_f64(signing_timer.map_or(0.0, |t| t.stop_and_record())).as_millis(); @@ -438,7 +436,7 @@ impl BlockService { &[metrics::BEACON_BLOCK_HTTP_POST], ); beacon_node - .post_beacon_blocks(&signed_block) + .post_beacon_blocks(&signed_block_contents) .await .map_err(|e| { BlockError::Irrecoverable(format!( @@ -453,7 +451,8 @@ impl BlockService { &[metrics::BLINDED_BEACON_BLOCK_HTTP_POST], ); beacon_node - .post_beacon_blinded_blocks(&signed_block) + // TODO: need to be adjusted for blobs + .post_beacon_blinded_blocks(&signed_block_contents.signed_block()) .await .map_err(|e| { BlockError::Irrecoverable(format!( @@ -472,10 +471,10 @@ impl BlockService { log, "Successfully published block"; "block_type" => ?Payload::block_type(), - "deposits" => signed_block.message().body().deposits().len(), - "attestations" => signed_block.message().body().attestations().len(), + "deposits" => signed_block_contents.signed_block().message().body().deposits().len(), + "attestations" => signed_block_contents.signed_block().message().body().attestations().len(), "graffiti" => ?graffiti.map(|g| g.as_utf8_lossy()), - "slot" => signed_block.slot().as_u64(), + "slot" => signed_block_contents.signed_block().slot().as_u64(), ); Ok(())