//! 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}, }, simplex::scheme::Scheme as SimplexScheme, types::Round, Block, }; use commonware_broadcast::buffered; use commonware_codec::Read; use commonware_cryptography::{certificate::Scheme, Digestible, PublicKey}; use commonware_p2p::Recipients; use commonware_utils::channel::oneshot; use std::{future::Future, sync::Arc}; /// 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 stored_commitment(block: &Self::StoredBlock) -> Self::Commitment { 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 check_payload(_scheme: &S, _payload: Self::Commitment) -> bool where S: SimplexScheme, { true } fn block_cfg( block_cfg: &::Cfg, _expected: Self::Commitment, ) -> ::Cfg { block_cfg.clone() } fn into_inner(block: Self::Block) -> Self::ApplicationBlock { block } fn into_inner_shared(block: Arc) -> Arc { block } fn owned_into_inner_shared(block: Self::Block) -> Arc { Arc::new(block) } fn from_application_block( block: Self::ApplicationBlock, _payload: Self::Commitment, ) -> Self::Block { 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>> { Some(self.subscribe(digest)) } 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: Arc, recipients: Recipients) { self.broadcast_shared(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 { receiver?.await.ok() } } }