Skip to main content

commonware_consensus/marshal/coding/
variant.rs

1use crate::{
2    marshal::{
3        coding::{
4            shards,
5            types::{CodedBlock, StoredCodedBlock},
6        },
7        core::{Buffer, Variant},
8    },
9    simplex::types::Context,
10    types::{coding::Commitment, Round},
11    CertifiableBlock,
12};
13use commonware_coding::Scheme as CodingScheme;
14use commonware_cryptography::{Committable, Digestible, Hasher, PublicKey};
15use commonware_p2p::Recipients;
16use commonware_utils::channel::oneshot;
17use std::sync::Arc;
18
19/// The coding variant of Marshal, which uses erasure coding for block dissemination.
20///
21/// This variant distributes blocks as erasure-coded shards, allowing reconstruction
22/// from a subset of shards. This reduces bandwidth requirements for block propagation.
23#[derive(Default, Clone, Copy)]
24pub struct Coding<B, C, H, P>(std::marker::PhantomData<(B, C, H, P)>)
25where
26    B: CertifiableBlock<Context = Context<Commitment, P>>,
27    C: CodingScheme,
28    H: Hasher,
29    P: PublicKey;
30
31impl<B, C, H, P> Variant for Coding<B, C, H, P>
32where
33    B: CertifiableBlock<Context = Context<Commitment, P>>,
34    C: CodingScheme,
35    H: Hasher,
36    P: PublicKey,
37{
38    type ApplicationBlock = B;
39    type Block = CodedBlock<B, C, H>;
40    type StoredBlock = StoredCodedBlock<B, C, H>;
41    type Commitment = Commitment;
42
43    fn commitment(block: &Self::Block) -> Self::Commitment {
44        // Commitment is deterministic from the coded block contents.
45        block.commitment()
46    }
47
48    fn commitment_to_inner(commitment: Self::Commitment) -> <Self::Block as Digestible>::Digest {
49        // The inner digest is embedded in the coding commitment.
50        commitment.block()
51    }
52
53    fn parent_commitment(block: &Self::Block) -> Self::Commitment {
54        // Parent commitment is embedded in the consensus context.
55        block.context().parent.1
56    }
57
58    fn into_inner(block: Self::Block) -> Self::ApplicationBlock {
59        block.into_inner()
60    }
61}
62
63impl<B, C, H, P> Buffer<Coding<B, C, H, P>> for shards::Mailbox<B, C, H, P>
64where
65    B: CertifiableBlock<Context = Context<Commitment, P>>,
66    C: CodingScheme,
67    H: Hasher,
68    P: PublicKey,
69{
70    type PublicKey = P;
71    type CachedBlock = Arc<CodedBlock<B, C, H>>;
72
73    async fn find_by_digest(
74        &self,
75        digest: <CodedBlock<B, C, H> as Digestible>::Digest,
76    ) -> Option<Self::CachedBlock> {
77        self.get_by_digest(digest).await
78    }
79
80    async fn find_by_commitment(&self, commitment: Commitment) -> Option<Self::CachedBlock> {
81        self.get(commitment).await
82    }
83
84    async fn subscribe_by_digest(
85        &self,
86        digest: <CodedBlock<B, C, H> as Digestible>::Digest,
87    ) -> oneshot::Receiver<Self::CachedBlock> {
88        self.subscribe_by_digest(digest).await
89    }
90
91    async fn subscribe_by_commitment(
92        &self,
93        commitment: Commitment,
94    ) -> oneshot::Receiver<Self::CachedBlock> {
95        self.subscribe(commitment).await
96    }
97
98    async fn finalized(&self, commitment: Commitment) {
99        self.prune(commitment).await;
100    }
101
102    async fn send(&self, round: Round, block: CodedBlock<B, C, H>, _recipients: Recipients<P>) {
103        self.proposed(round, block).await;
104    }
105}