@@ -55,7 +55,6 @@ pub use crate::{
55
55
} ;
56
56
use {
57
57
crate :: blockstore:: MAX_DATA_SHREDS_PER_SLOT ,
58
- bincode:: config:: Options ,
59
58
bitflags:: bitflags,
60
59
num_enum:: { IntoPrimitive , TryFromPrimitive } ,
61
60
serde:: { Deserialize , Serialize } ,
68
67
pubkey:: Pubkey ,
69
68
signature:: { Keypair , Signature , Signer } ,
70
69
} ,
71
- std:: { fmt:: Debug , mem:: size_of, ops:: RangeInclusive } ,
70
+ std:: { fmt:: Debug , io :: Cursor , mem:: size_of, ops:: RangeInclusive } ,
72
71
thiserror:: Error ,
73
72
} ;
74
73
@@ -229,34 +228,6 @@ impl ErasureSetId {
229
228
}
230
229
231
230
impl Shred {
232
- fn deserialize_obj < ' de , T > ( index : & mut usize , size : usize , buf : & ' de [ u8 ] ) -> bincode:: Result < T >
233
- where
234
- T : Deserialize < ' de > ,
235
- {
236
- let end = std:: cmp:: min ( * index + size, buf. len ( ) ) ;
237
- let ret = bincode:: options ( )
238
- . with_limit ( PACKET_DATA_SIZE as u64 )
239
- . with_fixint_encoding ( )
240
- . allow_trailing_bytes ( )
241
- . deserialize ( & buf[ * index..end] ) ?;
242
- * index += size;
243
- Ok ( ret)
244
- }
245
-
246
- fn serialize_obj_into < ' de , T > (
247
- index : & mut usize ,
248
- size : usize ,
249
- buf : & ' de mut [ u8 ] ,
250
- obj : & T ,
251
- ) -> bincode:: Result < ( ) >
252
- where
253
- T : Serialize ,
254
- {
255
- bincode:: serialize_into ( & mut buf[ * index..* index + size] , obj) ?;
256
- * index += size;
257
- Ok ( ( ) )
258
- }
259
-
260
231
pub fn copy_to_packet ( & self , packet : & mut Packet ) {
261
232
let len = self . payload . len ( ) ;
262
233
packet. data [ ..len] . copy_from_slice ( & self . payload [ ..] ) ;
@@ -306,24 +277,13 @@ impl Shred {
306
277
data_header. flags |= ShredFlags :: LAST_SHRED_IN_SLOT
307
278
}
308
279
309
- let mut start = 0 ;
310
- Self :: serialize_obj_into (
311
- & mut start,
312
- SIZE_OF_COMMON_SHRED_HEADER ,
313
- & mut payload,
314
- & common_header,
315
- )
316
- . expect ( "Failed to write common header into shred buffer" ) ;
317
-
318
- Self :: serialize_obj_into (
319
- & mut start,
320
- SIZE_OF_DATA_SHRED_HEADER ,
321
- & mut payload,
322
- & data_header,
323
- )
324
- . expect ( "Failed to write data header into shred buffer" ) ;
280
+ let mut cursor = Cursor :: new ( & mut payload[ ..] ) ;
281
+ bincode:: serialize_into ( & mut cursor, & common_header) . unwrap ( ) ;
282
+ bincode:: serialize_into ( & mut cursor, & data_header) . unwrap ( ) ;
325
283
// TODO: Need to check if data is too large!
326
- payload[ start..start + data. len ( ) ] . copy_from_slice ( data) ;
284
+ let offset = cursor. position ( ) as usize ;
285
+ debug_assert_eq ! ( offset, SHRED_DATA_OFFSET ) ;
286
+ payload[ offset..offset + data. len ( ) ] . copy_from_slice ( data) ;
327
287
Self {
328
288
common_header,
329
289
data_header,
@@ -333,23 +293,19 @@ impl Shred {
333
293
}
334
294
335
295
pub fn new_from_serialized_shred ( mut payload : Vec < u8 > ) -> Result < Self , Error > {
336
- let mut start = 0 ;
337
- let common_header: ShredCommonHeader =
338
- Self :: deserialize_obj ( & mut start, SIZE_OF_COMMON_SHRED_HEADER , & payload) ?;
339
-
340
- // Shreds should be padded out to SHRED_PAYLOAD_SIZE
341
- // so that erasure generation/recovery works correctly
342
- // But only the data_header.size is stored in blockstore.
343
- payload. resize ( SHRED_PAYLOAD_SIZE , 0 ) ;
296
+ let mut cursor = Cursor :: new ( & payload[ ..] ) ;
297
+ let common_header: ShredCommonHeader = bincode:: deserialize_from ( & mut cursor) ?;
344
298
let ( data_header, coding_header) = match common_header. shred_type {
345
299
ShredType :: Code => {
346
- let coding_header: CodingShredHeader =
347
- Self :: deserialize_obj ( & mut start, SIZE_OF_CODING_SHRED_HEADER , & payload) ?;
300
+ let coding_header = bincode:: deserialize_from ( & mut cursor) ?;
301
+ // see: https://github.com/solana-labs/solana/pull/10109
302
+ payload. truncate ( SHRED_PAYLOAD_SIZE ) ;
348
303
( DataShredHeader :: default ( ) , coding_header)
349
304
}
350
305
ShredType :: Data => {
351
- let data_header: DataShredHeader =
352
- Self :: deserialize_obj ( & mut start, SIZE_OF_DATA_SHRED_HEADER , & payload) ?;
306
+ let data_header = bincode:: deserialize_from ( & mut cursor) ?;
307
+ // see: https://github.com/solana-labs/solana/pull/16602
308
+ payload. resize ( SHRED_PAYLOAD_SIZE , 0u8 ) ;
353
309
( data_header, CodingShredHeader :: default ( ) )
354
310
}
355
311
} ;
@@ -386,24 +342,14 @@ impl Shred {
386
342
position,
387
343
} ;
388
344
let mut payload = vec ! [ 0 ; SHRED_PAYLOAD_SIZE ] ;
389
- let mut start = 0 ;
390
- Self :: serialize_obj_into (
391
- & mut start,
392
- SIZE_OF_COMMON_SHRED_HEADER ,
393
- & mut payload,
394
- & common_header,
395
- )
396
- . expect ( "Failed to write header into shred buffer" ) ;
397
- Self :: serialize_obj_into (
398
- & mut start,
399
- SIZE_OF_CODING_SHRED_HEADER ,
400
- & mut payload,
401
- & coding_header,
402
- )
403
- . expect ( "Failed to write coding header into shred buffer" ) ;
345
+ let mut cursor = Cursor :: new ( & mut payload[ ..] ) ;
346
+ bincode:: serialize_into ( & mut cursor, & common_header) . unwrap ( ) ;
347
+ bincode:: serialize_into ( & mut cursor, & coding_header) . unwrap ( ) ;
404
348
// Tests may have an empty parity_shard.
405
349
if !parity_shard. is_empty ( ) {
406
- payload[ SIZE_OF_CODING_SHRED_HEADERS ..] . copy_from_slice ( parity_shard) ;
350
+ let offset = cursor. position ( ) as usize ;
351
+ debug_assert_eq ! ( offset, SIZE_OF_CODING_SHRED_HEADERS ) ;
352
+ payload[ offset..] . copy_from_slice ( parity_shard) ;
407
353
}
408
354
Shred {
409
355
common_header,
@@ -491,9 +437,14 @@ impl Shred {
491
437
} ,
492
438
} ;
493
439
match shred_type {
494
- ShredType :: Code => Ok ( shred) ,
440
+ ShredType :: Code => {
441
+ if shred. len ( ) != SHRED_PAYLOAD_SIZE {
442
+ return Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ;
443
+ }
444
+ Ok ( shred)
445
+ }
495
446
ShredType :: Data => {
496
- if shred. len ( ) > SHRED_PAYLOAD_SIZE {
447
+ if ! ( SHRED_DATA_OFFSET .. SHRED_PAYLOAD_SIZE ) . contains ( & shred. len ( ) ) {
497
448
return Err ( Error :: InvalidPayloadSize ( shred. len ( ) ) ) ;
498
449
}
499
450
shred. resize ( SHRED_PAYLOAD_SIZE , 0u8 ) ;
@@ -627,24 +578,12 @@ impl Shred {
627
578
628
579
pub fn set_index ( & mut self , index : u32 ) {
629
580
self . common_header . index = index;
630
- Self :: serialize_obj_into (
631
- & mut 0 ,
632
- SIZE_OF_COMMON_SHRED_HEADER ,
633
- & mut self . payload ,
634
- & self . common_header ,
635
- )
636
- . unwrap ( ) ;
581
+ bincode:: serialize_into ( & mut self . payload [ ..] , & self . common_header ) . unwrap ( ) ;
637
582
}
638
583
639
584
pub fn set_slot ( & mut self , slot : Slot ) {
640
585
self . common_header . slot = slot;
641
- Self :: serialize_obj_into (
642
- & mut 0 ,
643
- SIZE_OF_COMMON_SHRED_HEADER ,
644
- & mut self . payload ,
645
- & self . common_header ,
646
- )
647
- . unwrap ( ) ;
586
+ bincode:: serialize_into ( & mut self . payload [ ..] , & self . common_header ) . unwrap ( ) ;
648
587
}
649
588
650
589
pub fn signature ( & self ) -> Signature {
@@ -695,6 +634,8 @@ impl Shred {
695
634
if self . is_data ( ) {
696
635
self . data_header . flags |= ShredFlags :: LAST_SHRED_IN_SLOT
697
636
}
637
+ let buffer = & mut self . payload [ SIZE_OF_COMMON_SHRED_HEADER ..] ;
638
+ bincode:: serialize_into ( buffer, & self . data_header ) . unwrap ( ) ;
698
639
}
699
640
700
641
#[ cfg( test) ]
@@ -704,17 +645,9 @@ impl Shred {
704
645
. flags
705
646
. remove ( ShredFlags :: DATA_COMPLETE_SHRED ) ;
706
647
}
707
-
708
648
// Data header starts after the shred common header
709
- let mut start = SIZE_OF_COMMON_SHRED_HEADER ;
710
- let size_of_data_shred_header = SIZE_OF_DATA_SHRED_HEADER ;
711
- Self :: serialize_obj_into (
712
- & mut start,
713
- size_of_data_shred_header,
714
- & mut self . payload ,
715
- & self . data_header ,
716
- )
717
- . expect ( "Failed to write data header into shred buffer" ) ;
649
+ let buffer = & mut self . payload [ SIZE_OF_COMMON_SHRED_HEADER ..] ;
650
+ bincode:: serialize_into ( buffer, & self . data_header ) . unwrap ( ) ;
718
651
}
719
652
720
653
pub fn data_complete ( & self ) -> bool {
@@ -1276,6 +1209,48 @@ mod tests {
1276
1209
) ;
1277
1210
}
1278
1211
1212
+ #[ test]
1213
+ fn test_serde_compat_shred_data_empty ( ) {
1214
+ const SEED : & str = "E3M5hm8yAEB7iPhQxFypAkLqxNeZCTuGBDMa8Jdrghoo" ;
1215
+ const PAYLOAD : & str = "nRNFVBEsV9FEM5KfmsCXJsgELRSkCV55drTavdy5aZPnsp\
1216
+ B8WvsgY99ZuNHDnwkrqe6Lx7ARVmercwugR5HwDcLA9ivKMypk9PNucDPLs67TXWy6k9R\
1217
+ ozKmy";
1218
+ let mut rng = {
1219
+ let seed = <[ u8 ; 32 ] >:: try_from ( bs58_decode ( SEED ) ) . unwrap ( ) ;
1220
+ ChaChaRng :: from_seed ( seed)
1221
+ } ;
1222
+ let keypair = Keypair :: generate ( & mut rng) ;
1223
+ let mut shred = Shred :: new_from_data (
1224
+ 142076266 , // slot
1225
+ 21443 , // index
1226
+ 51279 , // parent_offset
1227
+ & [ ] , // data
1228
+ true , // is_last_data
1229
+ false , // is_last_in_slot
1230
+ 49 , // reference_tick
1231
+ 59445 , // version
1232
+ 21414 , // fec_set_index
1233
+ ) ;
1234
+ shred. sign ( & keypair) ;
1235
+ assert ! ( shred. verify( & keypair. pubkey( ) ) ) ;
1236
+ assert_matches ! ( shred. sanitize( ) , Ok ( ( ) ) ) ;
1237
+ let payload = bs58_decode ( PAYLOAD ) ;
1238
+ let mut packet = Packet :: default ( ) ;
1239
+ packet. data [ ..payload. len ( ) ] . copy_from_slice ( & payload) ;
1240
+ packet. meta . size = payload. len ( ) ;
1241
+ assert_eq ! ( shred. bytes_to_store( ) , payload) ;
1242
+ assert_eq ! ( shred, Shred :: new_from_serialized_shred( payload) . unwrap( ) ) ;
1243
+ assert_eq ! (
1244
+ shred. reference_tick( ) ,
1245
+ Shred :: reference_tick_from_data( & packet. data)
1246
+ ) ;
1247
+ assert_eq ! ( Shred :: get_slot_from_packet( & packet) , Some ( shred. slot( ) ) ) ;
1248
+ assert_eq ! (
1249
+ get_shred_slot_index_type( & packet, & mut ShredFetchStats :: default ( ) ) ,
1250
+ Some ( ( shred. slot( ) , shred. index( ) , shred. shred_type( ) ) )
1251
+ ) ;
1252
+ }
1253
+
1279
1254
#[ test]
1280
1255
fn test_serde_compat_shred_code ( ) {
1281
1256
const SEED : & str = "4jfjh3UZVyaEgvyG9oQmNyFY9yHDmbeH9eUhnBKkrcrN" ;
0 commit comments