//! Standard variant implementation for Marshal. //! //! The standard variant broadcasts complete blocks to all peers. Each validator //! receives the full block directly from the proposer or via gossip. use crate::{ marshal::{ ancestry::BlockProvider, core::{Buffer, CommitmentFallback, Mailbox, Variant}, }, types::Round, Block, }; use commonware_broadcast::{buffered, Broadcaster}; use commonware_codec::Read; use commonware_cryptography::{certificate::Scheme, Digestible, PublicKey}; use commonware_p2p::Recipients; use commonware_utils::channel::oneshot; use std::future::Future; /// The standard variant of Marshal, which broadcasts complete blocks. /// /// This variant sends the entire block to all peers. #[derive(Default, Clone, Copy)] pub struct Standard(std::marker::PhantomData); impl Variant for Standard where B: Block, { type ApplicationBlock = B; type Block = B; type StoredBlock = B; type Commitment = ::Digest; fn commitment(block: &Self::Block) -> Self::Commitment { // Standard variant commitment is exactly the block digest. block.digest() } fn commitment_to_inner(commitment: Self::Commitment) -> ::Digest { // Trivial left-inverse: digest == commitment in this variant. commitment } fn parent_commitment(block: &Self::Block) -> Self::Commitment { // In standard mode, commitments are digests, so parent commitment is parent digest. block.parent() } fn block_cfg( block_cfg: &::Cfg, _expected: Self::Commitment, ) -> ::Cfg { block_cfg.clone() } fn into_inner(block: Self::Block) -> Self::ApplicationBlock { block } } impl Buffer> for buffered::Mailbox where B: Block, K: PublicKey, { type PublicKey = K; async fn find_by_digest(&self, digest: B::Digest) -> Option { self.get(digest).await } async fn find_by_commitment(&self, commitment: B::Digest) -> Option { self.find_by_digest(commitment).await } fn subscribe_by_digest(&self, digest: B::Digest) -> Option> { let (tx, rx) = oneshot::channel(); self.subscribe_prepared(digest, tx); Some(rx) } fn subscribe_by_commitment(&self, commitment: B::Digest) -> Option> { self.subscribe_by_digest(commitment) } fn finalized(&self, _commitment: B::Digest) { // No cleanup needed in standard mode - the buffer handles its own pruning } fn send(&self, _round: Round, block: B, recipients: Recipients) { Broadcaster::broadcast(self, recipients, block); } } impl BlockProvider for Mailbox> where S: Scheme, B: Block, { type Block = B; fn subscribe_parent( &self, block: &Self::Block, ) -> impl Future> + Send + 'static { let receiver = block.height().previous().map(|parent_height| { self.subscribe_by_commitment( block.parent(), CommitmentFallback::FetchByCommitment { height: parent_height, }, ) }); async move { let receiver = receiver?; receiver.await.ok() } } }