99
1010use crate :: Block ;
1111use commonware_broadcast:: { buffered, Broadcaster } ;
12- use commonware_codec:: { EncodeSize , Error as CodecError , FixedSize , Read , ReadExt , Write } ;
12+ use commonware_codec:: { Decode , EncodeSize , Error as CodecError , FixedSize , Read , ReadExt , Write } ;
1313use commonware_coding:: reed_solomon:: { self , decode, Chunk , Error as ReedSolomonError } ;
1414use commonware_cryptography:: { Committable , Digestible , Hasher , PublicKey } ;
1515use commonware_p2p:: Recipients ;
@@ -47,14 +47,14 @@ where
4747 B : Block < Digest = H :: Digest , Commitment = H :: Digest > ,
4848 H : Hasher ,
4949{
50- /// Inner [`buffered::Mailbox`] for broadcasting and receiving erasure coded chunks .
51- mailbox : buffered:: Mailbox < P , Shard < B , H > > ,
50+ /// Inner [`buffered::Mailbox`] for broadcasting and receiving erasure coded shards .
51+ mailbox : buffered:: Mailbox < P , Shard < CodedBlock < B , H > , H > > ,
5252
5353 /// [`Read`] configuration for the block type.
5454 block_codec_cfg : B :: Cfg ,
5555
5656 /// Open subscriptions for blocks by commitment.
57- block_subscriptions : BTreeMap < B :: Commitment , BlockSubscription < B > > ,
57+ block_subscriptions : BTreeMap < B :: Commitment , BlockSubscription < CodedBlock < B , H > > > ,
5858}
5959
6060impl < P , B , H > ShardLayer < P , B , H >
6464 H : Hasher ,
6565{
6666 /// Create a new [ShardLayer] with the given buffered mailbox.
67- pub fn new ( mailbox : buffered:: Mailbox < P , Shard < B , H > > , block_codec_cfg : B :: Cfg ) -> Self {
67+ pub fn new (
68+ mailbox : buffered:: Mailbox < P , Shard < CodedBlock < B , H > , H > > ,
69+ block_codec_cfg : B :: Cfg ,
70+ ) -> Self {
6871 Self {
6972 mailbox,
7073 block_codec_cfg,
7376 }
7477
7578 /// Broadcasts [Shard]s of a [Block] to a pre-determined set of peers.
76- pub async fn broadcast_chunks (
77- & mut self ,
78- coding_commitment : B :: Commitment ,
79- config : ( u16 , u16 ) ,
80- chunks : Vec < ( P , Chunk < H > ) > ,
81- ) {
82- for ( peer, chunk) in chunks {
83- let message = Shard :: new ( coding_commitment, config, chunk) ;
79+ pub async fn broadcast_shards ( & mut self , block : CodedBlock < B , H > , participants : Vec < P > ) {
80+ for ( i, peer) in participants. into_iter ( ) . enumerate ( ) {
81+ let message = block. shard ( i as u16 ) . expect ( "invalid shard index" ) ;
8482 let _peers = self . mailbox . broadcast ( Recipients :: One ( peer) , message) . await ;
8583 }
8684 }
@@ -113,14 +111,14 @@ where
113111 pub async fn try_reconstruct (
114112 & mut self ,
115113 commitment : B :: Commitment ,
116- ) -> Result < Option < B > , ReconstructionError > {
117- let available_chunks = self . mailbox . get ( None , commitment, None ) . await ;
114+ ) -> Result < Option < CodedBlock < B , H > > , ReconstructionError > {
115+ let available_shards = self . mailbox . get ( None , commitment, None ) . await ;
118116
119- let Some ( ( total, min) ) = available_chunks . first ( ) . map ( |c| c. config ) else {
120- // No chunks available.
117+ let Some ( ( total, min) ) = available_shards . first ( ) . map ( |c| c. config ) else {
118+ // No shards available.
121119 return Ok ( None ) ;
122120 } ;
123- let coded_chunks = available_chunks
121+ let coded_shards = available_shards
124122 . iter ( )
125123 . cloned ( )
126124 . map ( |c| c. chunk )
@@ -129,23 +127,24 @@ where
129127 // TODO: Make sure min is all valid chunks
130128 // TODO: If we do encounter a block that's invalid, block the peer.
131129
132- if coded_chunks . len ( ) < min as usize {
133- // Not enough chunks to recover the block yet.
130+ if coded_shards . len ( ) < min as usize {
131+ // Not enough shards to recover the block yet.
134132 debug ! (
135133 %commitment,
136- have = coded_chunks . len( ) ,
134+ have = coded_shards . len( ) ,
137135 need = min,
138- "not enough chunks to reconstruct block" ,
136+ "not enough shards to reconstruct block" ,
139137 ) ;
140138 return Ok ( None ) ;
141139 }
142140
143- // Attempt to recover the block from the available chunks . This process will also
144- // check the chunks ' inclusion within the commitment.
145- let recovered = decode ( total, min, & commitment, coded_chunks ) ?;
141+ // Attempt to recover the block from the available shards . This process will also
142+ // check the shards ' inclusion within the commitment.
143+ let recovered = decode ( total, min, & commitment, coded_shards ) ?;
146144
147145 // Attempt to decode the block from the recovered data.
148- let block = B :: decode_cfg ( & mut recovered. as_slice ( ) , & self . block_codec_cfg ) ?;
146+ let block =
147+ CodedBlock :: < B , H > :: decode_cfg ( & mut recovered. as_slice ( ) , & self . block_codec_cfg ) ?;
149148
150149 // Notify any subscribers that have been waiting for this block.
151150 if let Some ( mut sub) = self . block_subscriptions . remove ( & commitment) {
@@ -156,8 +155,8 @@ where
156155
157156 info ! (
158157 %commitment,
159- digest = %block. digest( ) ,
160- height = block. height( ) ,
158+ digest = %block. inner ( ) . digest( ) ,
159+ height = block. inner ( ) . height( ) ,
161160 "successfully reconstructed block"
162161 ) ;
163162
@@ -172,7 +171,7 @@ where
172171 pub async fn subscribe_block (
173172 & mut self ,
174173 commitment : B :: Commitment ,
175- responder : oneshot:: Sender < B > ,
174+ responder : oneshot:: Sender < CodedBlock < B , H > > ,
176175 ) -> Result < ( ) , ReconstructionError > {
177176 match self . block_subscriptions . entry ( commitment) {
178177 Entry :: Vacant ( entry) => {
@@ -185,36 +184,37 @@ where
185184 }
186185 }
187186
188- // Try to reconstruct the block immediately in case we already have enough chunks .
187+ // Try to reconstruct the block immediately in case we already have enough shards .
189188 self . try_reconstruct ( commitment) . await ?;
190189
191190 Ok ( ( ) )
192191 }
193192
194- pub async fn get_chunk (
193+ /// Performs a best-effort retrieval of a shard by commitment and index. If the mailbox does
194+ /// not have the shard cached, `None` is returned.
195+ pub async fn get_shard (
195196 & mut self ,
196197 commitment : B :: Commitment ,
197198 index : u16 ,
198- ) -> Option < Shard < B , H > > {
199+ ) -> Option < Shard < CodedBlock < B , H > , H > > {
199200 let index_hash = shard_uuid :: < B , H > ( commitment, index) ;
200201 self . mailbox
201202 . get ( None , commitment, Some ( index_hash) )
202203 . await
203- . iter ( )
204+ . first ( )
204205 . cloned ( )
205- . next ( )
206206 }
207207
208- /// Subscribes to a chunk by commitment and index with an externally prepared responder.
208+ /// Subscribes to a shard by commitment and index with an externally prepared responder.
209209 ///
210- /// The responder will be sent the chunk when it is available; either instantly (if cached)
210+ /// The responder will be sent the shard when it is available; either instantly (if cached)
211211 /// or when it is received from the network. The request can be canceled by dropping the
212212 /// responder.
213- pub async fn subscribe_chunk (
213+ pub async fn subscribe_shard (
214214 & mut self ,
215215 commitment : B :: Commitment ,
216216 index : u16 ,
217- responder : oneshot:: Sender < Shard < B , H > > ,
217+ responder : oneshot:: Sender < Shard < CodedBlock < B , H > , H > > ,
218218 ) {
219219 let index_hash = shard_uuid :: < B , H > ( commitment, index) ;
220220 self . mailbox
@@ -225,10 +225,10 @@ where
225225
226226/// A broadcastable, erasure coded [Chunk] of a [Block].
227227///
228- /// Each chunk is associated with a commitment to the full block's
229- /// erasure coded data. This allows recipients to verify the integrity of the chunk
230- /// (to varying degrees; For reed-solomon which is currently hard-coded, no guarantee
231- /// of the chunk's correctness is possible without additional chunks .)
228+ /// Each shard is associated with a commitment to the full block's erasure coded data.
229+ /// This allows recipients to verify the integrity of the shard (to varying degrees; For
230+ /// reed-solomon which is currently hard-coded, no guarantee of the shard's correctness
231+ /// is possible without additional shard .)
232232#[ derive( Debug , Clone ) ]
233233pub struct Shard < B , H >
234234where
@@ -245,7 +245,7 @@ where
245245 B : Block < Digest = H :: Digest , Commitment = H :: Digest > ,
246246 H : Hasher ,
247247{
248- /// Create a new [Shard] from a block's hash, coding commitment, and a chunk
248+ /// Create a new [Shard] from a block's hash, coding commitment, and a [Chunk]
249249 /// of the coded block.
250250 ///
251251 /// ## Panics
@@ -443,6 +443,15 @@ where
443443 pub fn chunks ( & self ) -> & [ Chunk < H > ] {
444444 self . chunks . as_slice ( )
445445 }
446+
447+ /// Returns a [Shard] at the given index, if the index is valid.
448+ pub fn shard ( & self , index : u16 ) -> Option < Shard < CodedBlock < B , H > , H > > {
449+ Some ( Shard :: new (
450+ self . commitment ,
451+ self . config ,
452+ self . chunks . get ( index as usize ) ?. clone ( ) ,
453+ ) )
454+ }
446455}
447456
448457impl < B , H > Write for CodedBlock < B , H >
0 commit comments