Skip to main content

commonware_consensus/marshal/standard/
variant.rs

1//! Standard variant implementation for Marshal.
2//!
3//! The standard variant broadcasts complete blocks to all peers. Each validator
4//! receives the full block directly from the proposer or via gossip.
5
6use crate::{
7    marshal::core::{Buffer, Variant},
8    types::Round,
9    Block,
10};
11use commonware_broadcast::{buffered, Broadcaster};
12use commonware_cryptography::{Digestible, PublicKey};
13use commonware_p2p::Recipients;
14use commonware_utils::channel::oneshot;
15
16/// The standard variant of Marshal, which broadcasts complete blocks.
17///
18/// This variant sends the entire block to all peers.
19#[derive(Default, Clone, Copy)]
20pub struct Standard<B: Block>(std::marker::PhantomData<B>);
21
22impl<B> Variant for Standard<B>
23where
24    B: Block,
25{
26    type ApplicationBlock = B;
27    type Block = B;
28    type StoredBlock = B;
29    type Commitment = <B as Digestible>::Digest;
30
31    fn commitment(block: &Self::Block) -> Self::Commitment {
32        // Standard variant commitment is exactly the block digest.
33        block.digest()
34    }
35
36    fn commitment_to_inner(commitment: Self::Commitment) -> <Self::Block as Digestible>::Digest {
37        // Trivial left-inverse: digest == commitment in this variant.
38        commitment
39    }
40
41    fn parent_commitment(block: &Self::Block) -> Self::Commitment {
42        // In standard mode, commitments are digests, so parent commitment is parent digest.
43        block.parent()
44    }
45
46    fn into_inner(block: Self::Block) -> Self::ApplicationBlock {
47        block
48    }
49}
50
51impl<B, K> Buffer<Standard<B>> for buffered::Mailbox<K, B>
52where
53    B: Block,
54    K: PublicKey,
55{
56    type PublicKey = K;
57    type CachedBlock = B;
58
59    async fn find_by_digest(&self, digest: B::Digest) -> Option<Self::CachedBlock> {
60        self.get(digest).await
61    }
62
63    async fn find_by_commitment(&self, commitment: B::Digest) -> Option<Self::CachedBlock> {
64        self.find_by_digest(commitment).await
65    }
66
67    async fn subscribe_by_digest(&self, digest: B::Digest) -> oneshot::Receiver<Self::CachedBlock> {
68        let (tx, rx) = oneshot::channel();
69        self.subscribe_prepared(digest, tx).await;
70        rx
71    }
72
73    async fn subscribe_by_commitment(
74        &self,
75        commitment: B::Digest,
76    ) -> oneshot::Receiver<Self::CachedBlock> {
77        self.subscribe_by_digest(commitment).await
78    }
79
80    async fn finalized(&self, _commitment: B::Digest) {
81        // No cleanup needed in standard mode - the buffer handles its own pruning
82    }
83
84    async fn send(&self, _round: Round, block: B, recipients: Recipients<K>) {
85        let _peers = Broadcaster::broadcast(self, recipients, block).await;
86    }
87}