@@ -9,7 +9,7 @@ use commonware_coding::{Config as CodingConfig, Scheme};
99use commonware_cryptography:: { Committable , Digestible , Hasher } ;
1010use commonware_parallel:: { Sequential , Strategy } ;
1111use commonware_utils:: { Faults , N3f1 , NZU16 } ;
12- use std:: marker:: PhantomData ;
12+ use std:: { marker:: PhantomData , sync :: Arc } ;
1313
1414/// A broadcastable shard of erasure coded data, including the coding commitment and
1515/// the configuration used to code the data.
@@ -142,7 +142,7 @@ where
142142#[ derive( Debug ) ]
143143pub struct CodedBlock < B : Block , C : Scheme , H : Hasher > {
144144 /// The inner block type.
145- inner : B ,
145+ inner : Arc < B > ,
146146 /// The erasure coding configuration.
147147 config : CodingConfig ,
148148 /// The erasure coding commitment.
@@ -152,7 +152,7 @@ pub struct CodedBlock<B: Block, C: Scheme, H: Hasher> {
152152 /// These shards are optional to enable lazy construction. If the block is
153153 /// constructed with [`Self::new_trusted`], the shards are computed lazily
154154 /// via [`Self::shards`].
155- shards : Option < Vec < C :: Shard > > ,
155+ shards : Option < Arc < [ C :: Shard ] > > ,
156156 /// Phantom data for the hasher.
157157 _hasher : PhantomData < H > ,
158158}
@@ -175,18 +175,18 @@ impl<B: Block, C: Scheme, H: Hasher> CodedBlock<B, C, H> {
175175 pub fn new ( inner : B , config : CodingConfig , strategy : & impl Strategy ) -> Self {
176176 let ( commitment, shards) = Self :: encode ( & inner, config, strategy) ;
177177 Self {
178- inner,
178+ inner : Arc :: new ( inner ) ,
179179 config,
180180 commitment,
181- shards : Some ( shards) ,
181+ shards : Some ( shards. into ( ) ) ,
182182 _hasher : PhantomData ,
183183 }
184184 }
185185
186186 /// Create a new [`CodedBlock`] from a [`Block`] and trusted [`Commitment`].
187187 pub fn new_trusted ( inner : B , commitment : Commitment ) -> Self {
188188 Self {
189- inner,
189+ inner : Arc :: new ( inner ) ,
190190 config : commitment. config ( ) ,
191191 commitment : commitment. root ( ) ,
192192 shards : None ,
@@ -213,7 +213,7 @@ impl<B: Block, C: Scheme, H: Hasher> CodedBlock<B, C, H> {
213213 "coded block constructed with trusted commitment does not match commitment"
214214 ) ;
215215
216- self . shards = Some ( shards) ;
216+ self . shards = Some ( shards. into ( ) ) ;
217217 self . shards . as_ref ( ) . unwrap ( )
218218 }
219219 }
@@ -232,28 +232,28 @@ impl<B: Block, C: Scheme, H: Hasher> CodedBlock<B, C, H> {
232232 }
233233
234234 /// Returns a reference to the inner [`Block`].
235- pub const fn inner ( & self ) -> & B {
235+ pub fn inner ( & self ) -> & B {
236236 & self . inner
237237 }
238238
239239 /// Takes the inner [`Block`].
240240 pub fn into_inner ( self ) -> B {
241- self . inner
241+ Arc :: unwrap_or_clone ( self . inner )
242242 }
243243}
244244
245- impl < B : CertifiableBlock , C : Scheme , H : Hasher > From < CodedBlock < B , C , H > >
245+ impl < B : CertifiableBlock + Clone , C : Scheme , H : Hasher > From < CodedBlock < B , C , H > >
246246 for StoredCodedBlock < B , C , H >
247247{
248248 fn from ( block : CodedBlock < B , C , H > ) -> Self {
249249 Self :: new ( block)
250250 }
251251}
252252
253- impl < B : Block + Clone , C : Scheme , H : Hasher > Clone for CodedBlock < B , C , H > {
253+ impl < B : Block , C : Scheme , H : Hasher > Clone for CodedBlock < B , C , H > {
254254 fn clone ( & self ) -> Self {
255255 Self {
256- inner : self . inner . clone ( ) ,
256+ inner : Arc :: clone ( & self . inner ) ,
257257 config : self . config ,
258258 commitment : self . commitment ,
259259 shards : self . shards . clone ( ) ,
@@ -315,10 +315,10 @@ impl<B: Block, C: Scheme, H: Hasher> Read for CodedBlock<B, C, H> {
315315 } ) ?;
316316
317317 Ok ( Self {
318- inner,
318+ inner : Arc :: new ( inner ) ,
319319 config,
320320 commitment,
321- shards : Some ( shards) ,
321+ shards : Some ( shards. into ( ) ) ,
322322 _hasher : PhantomData ,
323323 } )
324324 }
@@ -380,15 +380,15 @@ pub struct StoredCodedBlock<B: Block, C: Scheme, H: Hasher> {
380380 _scheme : PhantomData < ( C , H ) > ,
381381}
382382
383- impl < B : CertifiableBlock , C : Scheme , H : Hasher > StoredCodedBlock < B , C , H > {
383+ impl < B : CertifiableBlock + Clone , C : Scheme , H : Hasher > StoredCodedBlock < B , C , H > {
384384 /// Create a [`StoredCodedBlock`] from a verified [`CodedBlock`].
385385 ///
386386 /// The caller must ensure the [`CodedBlock`] has been properly verified
387387 /// (i.e., its commitment was computed or validated against a trusted source).
388388 pub fn new ( block : CodedBlock < B , C , H > ) -> Self {
389389 Self {
390390 commitment : block. commitment ( ) ,
391- inner : block. inner ,
391+ inner : block. into_inner ( ) ,
392392 _scheme : PhantomData ,
393393 }
394394 }
@@ -621,6 +621,24 @@ mod test {
621621 assert ! ( coded_block == decoded) ;
622622 }
623623
624+ #[ test]
625+ fn test_coded_block_clone_shares_storage ( ) {
626+ const CONFIG : CodingConfig = CodingConfig {
627+ minimum_shards : NZU16 ! ( 1 ) ,
628+ extra_shards : NZU16 ! ( 2 ) ,
629+ } ;
630+
631+ let block = Block :: new :: < Sha256 > ( ( ) , Sha256 :: hash ( b"parent" ) , Height :: new ( 42 ) , 1_234_567 ) ;
632+ let coded_block = CodedBlock :: < Block , RS , H > :: new ( block, CONFIG , & Sequential ) ;
633+ let cloned = coded_block. clone ( ) ;
634+
635+ assert ! ( Arc :: ptr_eq( & coded_block. inner, & cloned. inner) ) ;
636+ assert ! ( Arc :: ptr_eq(
637+ coded_block. shards. as_ref( ) . unwrap( ) ,
638+ cloned. shards. as_ref( ) . unwrap( )
639+ ) ) ;
640+ }
641+
624642 #[ test]
625643 fn test_stored_coded_block_codec_roundtrip ( ) {
626644 const CONFIG : CodingConfig = CodingConfig {
0 commit comments