Skip to content

Commit 64c57ed

Browse files
committed
removes shred wire layout specs from sigverify
sigverify_shres relies on wire layout specs of shreds: https://github.com/solana-labs/solana/blob/0376ab41a/ledger/src/sigverify_shreds.rs#L39-L46 https://github.com/solana-labs/solana/blob/0376ab41a/ledger/src/sigverify_shreds.rs#L298-L305 In preparation of solana-labs#25237 which adds a new shred variant with different layout and signed message, this commit removes shred layout specification from sigverify and instead encapsulate that in shred module.
1 parent 0376ab4 commit 64c57ed

File tree

6 files changed

+207
-216
lines changed

6 files changed

+207
-216
lines changed

core/src/repair_response.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,17 @@ mod test {
9191
.iter()
9292
.cloned()
9393
.collect();
94-
let rv = verify_shred_cpu(&packet, &leader_slots);
95-
assert_eq!(rv, Some(1));
94+
assert!(verify_shred_cpu(&packet, &leader_slots));
9695

9796
let wrong_keypair = Keypair::new();
9897
let leader_slots = [(slot, wrong_keypair.pubkey().to_bytes())]
9998
.iter()
10099
.cloned()
101100
.collect();
102-
let rv = verify_shred_cpu(&packet, &leader_slots);
103-
assert_eq!(rv, Some(0));
101+
assert!(!verify_shred_cpu(&packet, &leader_slots));
104102

105103
let leader_slots = HashMap::new();
106-
let rv = verify_shred_cpu(&packet, &leader_slots);
107-
assert_eq!(rv, None);
104+
assert!(!verify_shred_cpu(&packet, &leader_slots));
108105
}
109106

110107
#[test]

core/src/sigverify_shreds.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
use {
33
crate::{sigverify, sigverify_stage::SigVerifier},
44
solana_ledger::{
5-
leader_schedule_cache::LeaderScheduleCache, shred::Shred,
6-
sigverify_shreds::verify_shreds_gpu,
5+
leader_schedule_cache::LeaderScheduleCache, shred, sigverify_shreds::verify_shreds_gpu,
76
},
87
solana_perf::{self, packet::PacketBatch, recycler_cache::RecyclerCache},
98
solana_runtime::bank_forks::BankForks,
@@ -32,10 +31,12 @@ impl ShredSigVerifier {
3231
recycler_cache: RecyclerCache::warmed(),
3332
}
3433
}
35-
fn read_slots(batches: &[PacketBatch]) -> HashSet<u64> {
34+
fn read_slots(batches: &[PacketBatch]) -> HashSet<Slot> {
3635
batches
3736
.iter()
38-
.flat_map(|batch| batch.iter().filter_map(Shred::get_slot_from_packet))
37+
.flat_map(PacketBatch::iter)
38+
.map(shred::layout::get_shred)
39+
.filter_map(shred::layout::get_slot)
3940
.collect()
4041
}
4142
}

ledger/src/blockstore.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1856,7 +1856,7 @@ impl Blockstore {
18561856
let upper_index = cmp::min(current_index, end_index);
18571857
// the tick that will be used to figure out the timeout for this hole
18581858
let data = db_iterator.value().expect("couldn't read value");
1859-
let reference_tick = u64::from(Shred::reference_tick_from_data(data).unwrap());
1859+
let reference_tick = u64::from(shred::layout::get_reference_tick(data).unwrap());
18601860
if ticks_since_first_insert < reference_tick + MAX_TURBINE_DELAY_IN_TICKS {
18611861
// The higher index holes have not timed out yet
18621862
break 'outer;

ledger/src/shred.rs

Lines changed: 94 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use {
5656
num_enum::{IntoPrimitive, TryFromPrimitive},
5757
serde::{Deserialize, Serialize},
5858
solana_entry::entry::{create_ticks, Entry},
59-
solana_perf::packet::Packet,
59+
solana_perf::packet::{deserialize_from_with_limit, Packet},
6060
solana_sdk::{
6161
clock::Slot,
6262
hash::{hashv, Hash},
@@ -315,7 +315,7 @@ impl Shred {
315315
}
316316

317317
pub fn new_from_serialized_shred(shred: Vec<u8>) -> Result<Self, Error> {
318-
Ok(match Self::shred_type_from_payload(&shred)? {
318+
Ok(match layout::get_shred_type(&shred)? {
319319
ShredType::Code => Self::from(ShredCode::from_payload(shred)?),
320320
ShredType::Data => Self::from(ShredData::from_payload(shred)?),
321321
})
@@ -381,7 +381,7 @@ impl Shred {
381381

382382
// Possibly zero pads bytes stored in blockstore.
383383
pub(crate) fn resize_stored_shred(shred: Vec<u8>) -> Result<Vec<u8>, Error> {
384-
match Self::shred_type_from_payload(&shred)? {
384+
match layout::get_shred_type(&shred)? {
385385
ShredType::Code => ShredCode::resize_stored_shred(shred),
386386
ShredType::Data => ShredData::resize_stored_shred(shred),
387387
}
@@ -430,16 +430,6 @@ impl Shred {
430430
self.common_header().shred_type
431431
}
432432

433-
fn shred_type_from_payload(shred: &[u8]) -> Result<ShredType, Error> {
434-
match shred.get(OFFSET_OF_SHRED_TYPE) {
435-
None => Err(Error::InvalidPayloadSize(shred.len())),
436-
Some(shred_type) => match ShredType::try_from(*shred_type) {
437-
Err(_) => Err(Error::InvalidShredType),
438-
Ok(shred_type) => Ok(shred_type),
439-
},
440-
}
441-
}
442-
443433
pub fn is_data(&self) -> bool {
444434
self.shred_type() == ShredType::Data
445435
}
@@ -477,25 +467,6 @@ impl Shred {
477467
}
478468
}
479469

480-
// Get slot from a shred packet with partial deserialize
481-
pub fn get_slot_from_packet(p: &Packet) -> Option<Slot> {
482-
let slot_start = OFFSET_OF_SHRED_SLOT;
483-
let slot_end = slot_start + SIZE_OF_SHRED_SLOT;
484-
p.deserialize_slice(slot_start..slot_end).ok()
485-
}
486-
487-
pub(crate) fn reference_tick_from_data(data: &[u8]) -> Result<u8, Error> {
488-
const SHRED_FLAGS_OFFSET: usize = SIZE_OF_COMMON_SHRED_HEADER + std::mem::size_of::<u16>();
489-
if Self::shred_type_from_payload(data)? != ShredType::Data {
490-
return Err(Error::InvalidShredType);
491-
}
492-
let flags = match data.get(SHRED_FLAGS_OFFSET) {
493-
None => return Err(Error::InvalidPayloadSize(data.len())),
494-
Some(flags) => flags,
495-
};
496-
Ok(flags & ShredFlags::SHRED_TICK_REFERENCE_MASK.bits())
497-
}
498-
499470
pub fn verify(&self, pubkey: &Pubkey) -> bool {
500471
let message = self.signed_payload();
501472
self.signature().verify(pubkey.as_ref(), message)
@@ -524,6 +495,73 @@ impl Shred {
524495
}
525496
}
526497

498+
// Helper methods to extract pieces of the shred from the payload
499+
// without deserializing the entire payload.
500+
pub mod layout {
501+
use {super::*, std::ops::Range};
502+
503+
fn get_shred_size(packet: &Packet) -> usize {
504+
if packet.meta.repair() {
505+
packet.meta.size.saturating_sub(SIZE_OF_NONCE)
506+
} else {
507+
packet.meta.size
508+
}
509+
}
510+
511+
pub fn get_shred(packet: &Packet) -> &[u8] {
512+
&packet.data[..get_shred_size(packet)]
513+
}
514+
515+
pub(crate) fn get_signature(shred: &[u8]) -> Option<Signature> {
516+
Some(Signature::new(shred.get(..SIZE_OF_SIGNATURE)?))
517+
}
518+
519+
pub(crate) const fn get_signature_range() -> Range<usize> {
520+
0..SIZE_OF_SIGNATURE
521+
}
522+
523+
pub(super) fn get_shred_type(shred: &[u8]) -> Result<ShredType, Error> {
524+
match shred.get(OFFSET_OF_SHRED_TYPE) {
525+
None => Err(Error::InvalidPayloadSize(shred.len())),
526+
Some(shred_type) => match ShredType::try_from(*shred_type) {
527+
Err(_) => Err(Error::InvalidShredType),
528+
Ok(shred_type) => Ok(shred_type),
529+
},
530+
}
531+
}
532+
533+
pub fn get_slot(shred: &[u8]) -> Option<Slot> {
534+
deserialize_from_with_limit(shred.get(OFFSET_OF_SHRED_SLOT..)?).ok()
535+
}
536+
537+
pub(super) fn get_index(shred: &[u8]) -> Option<u32> {
538+
deserialize_from_with_limit(shred.get(OFFSET_OF_SHRED_INDEX..)?).ok()
539+
}
540+
541+
// Returns chunk of the payload which is signed.
542+
pub(crate) fn get_signed_message(shred: &[u8]) -> Option<&[u8]> {
543+
shred.get(SIZE_OF_SIGNATURE..)
544+
}
545+
546+
// Returns slice range of the packet payload which is signed.
547+
pub(crate) fn get_signed_message_range(packet: &Packet) -> Range<usize> {
548+
SIZE_OF_SIGNATURE..get_shred_size(packet)
549+
}
550+
551+
pub(crate) fn get_reference_tick(shred: &[u8]) -> Result<u8, Error> {
552+
const SIZE_OF_PARENT_OFFSET: usize = std::mem::size_of::<u16>();
553+
const OFFSET_OF_SHRED_FLAGS: usize = SIZE_OF_COMMON_SHRED_HEADER + SIZE_OF_PARENT_OFFSET;
554+
if get_shred_type(shred)? != ShredType::Data {
555+
return Err(Error::InvalidShredType);
556+
}
557+
let flags = match shred.get(OFFSET_OF_SHRED_FLAGS) {
558+
None => return Err(Error::InvalidPayloadSize(shred.len())),
559+
Some(flags) => flags,
560+
};
561+
Ok(flags & ShredFlags::SHRED_TICK_REFERENCE_MASK.bits())
562+
}
563+
}
564+
527565
impl From<ShredCode> for Shred {
528566
fn from(shred: ShredCode) -> Self {
529567
Self::ShredCode(shred)
@@ -538,50 +576,39 @@ impl From<ShredData> for Shred {
538576

539577
// Get slot, index, and type from a packet with partial deserialize
540578
pub fn get_shred_slot_index_type(
541-
p: &Packet,
579+
packet: &Packet,
542580
stats: &mut ShredFetchStats,
543581
) -> Option<(Slot, u32, ShredType)> {
544-
let index_start = OFFSET_OF_SHRED_INDEX;
545-
let index_end = index_start + SIZE_OF_SHRED_INDEX;
546-
let slot_start = OFFSET_OF_SHRED_SLOT;
547-
let slot_end = slot_start + SIZE_OF_SHRED_SLOT;
548-
549-
debug_assert!(index_end > slot_end);
550-
debug_assert!(index_end > OFFSET_OF_SHRED_TYPE);
551-
552-
if index_end > p.meta.size {
582+
let shred = layout::get_shred(packet);
583+
if OFFSET_OF_SHRED_INDEX + SIZE_OF_SHRED_INDEX > shred.len() {
553584
stats.index_overrun += 1;
554585
return None;
555586
}
556-
557-
let index = match p.deserialize_slice(index_start..index_end) {
558-
Ok(x) => x,
559-
Err(_e) => {
560-
stats.index_bad_deserialize += 1;
587+
let shred_type = match layout::get_shred_type(shred) {
588+
Ok(shred_type) => shred_type,
589+
Err(_) => {
590+
stats.bad_shred_type += 1;
561591
return None;
562592
}
563593
};
564-
565-
if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
566-
stats.index_out_of_bounds += 1;
567-
return None;
568-
}
569-
570-
let slot = match p.deserialize_slice(slot_start..slot_end) {
571-
Ok(x) => x,
572-
Err(_e) => {
594+
let slot = match layout::get_slot(shred) {
595+
Some(slot) => slot,
596+
None => {
573597
stats.slot_bad_deserialize += 1;
574598
return None;
575599
}
576600
};
577-
578-
let shred_type = match ShredType::try_from(p.data[OFFSET_OF_SHRED_TYPE]) {
579-
Err(_) => {
580-
stats.bad_shred_type += 1;
601+
let index = match layout::get_index(shred) {
602+
Some(index) => index,
603+
None => {
604+
stats.index_bad_deserialize += 1;
581605
return None;
582606
}
583-
Ok(shred_type) => shred_type,
584607
};
608+
if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
609+
stats.index_out_of_bounds += 1;
610+
return None;
611+
}
585612
Some((slot, index, shred_type))
586613
}
587614

@@ -898,9 +925,9 @@ mod tests {
898925
assert_eq!(shred, Shred::new_from_serialized_shred(payload).unwrap());
899926
assert_eq!(
900927
shred.reference_tick(),
901-
Shred::reference_tick_from_data(&packet.data).unwrap()
928+
layout::get_reference_tick(&packet.data).unwrap()
902929
);
903-
assert_eq!(Shred::get_slot_from_packet(&packet), Some(shred.slot()));
930+
assert_eq!(layout::get_slot(&packet.data), Some(shred.slot()));
904931
assert_eq!(
905932
get_shred_slot_index_type(&packet, &mut ShredFetchStats::default()),
906933
Some((shred.slot(), shred.index(), shred.shred_type()))
@@ -939,9 +966,9 @@ mod tests {
939966
assert_eq!(shred, Shred::new_from_serialized_shred(payload).unwrap());
940967
assert_eq!(
941968
shred.reference_tick(),
942-
Shred::reference_tick_from_data(&packet.data).unwrap()
969+
layout::get_reference_tick(&packet.data).unwrap()
943970
);
944-
assert_eq!(Shred::get_slot_from_packet(&packet), Some(shred.slot()));
971+
assert_eq!(layout::get_slot(&packet.data), Some(shred.slot()));
945972
assert_eq!(
946973
get_shred_slot_index_type(&packet, &mut ShredFetchStats::default()),
947974
Some((shred.slot(), shred.index(), shred.shred_type()))
@@ -985,7 +1012,7 @@ mod tests {
9851012
packet.meta.size = payload.len();
9861013
assert_eq!(shred.bytes_to_store(), payload);
9871014
assert_eq!(shred, Shred::new_from_serialized_shred(payload).unwrap());
988-
assert_eq!(Shred::get_slot_from_packet(&packet), Some(shred.slot()));
1015+
assert_eq!(layout::get_slot(&packet.data), Some(shred.slot()));
9891016
assert_eq!(
9901017
get_shred_slot_index_type(&packet, &mut ShredFetchStats::default()),
9911018
Some((shred.slot(), shred.index(), shred.shred_type()))
@@ -1024,7 +1051,7 @@ mod tests {
10241051
assert_eq!(shred.last_in_slot(), is_last_in_slot);
10251052
assert_eq!(shred.reference_tick(), reference_tick.min(63u8));
10261053
assert_eq!(
1027-
Shred::reference_tick_from_data(shred.payload()).unwrap(),
1054+
layout::get_reference_tick(shred.payload()).unwrap(),
10281055
reference_tick.min(63u8),
10291056
);
10301057
}

ledger/src/shredder.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ mod tests {
353353
use {
354354
super::*,
355355
crate::shred::{
356-
max_entries_per_n_shred, max_ticks_per_n_shreds, verify_test_data_shred, ShredType,
356+
self, max_entries_per_n_shred, max_ticks_per_n_shreds, verify_test_data_shred,
357+
ShredType,
357358
},
358359
bincode::serialized_size,
359360
matches::assert_matches,
@@ -519,7 +520,7 @@ mod tests {
519520
);
520521
data_shreds.iter().for_each(|s| {
521522
assert_eq!(s.reference_tick(), 5);
522-
assert_eq!(Shred::reference_tick_from_data(s.payload()).unwrap(), 5);
523+
assert_eq!(shred::layout::get_reference_tick(s.payload()).unwrap(), 5);
523524
});
524525

525526
let deserialized_shred =
@@ -555,7 +556,7 @@ mod tests {
555556
ShredFlags::SHRED_TICK_REFERENCE_MASK.bits()
556557
);
557558
assert_eq!(
558-
Shred::reference_tick_from_data(s.payload()).unwrap(),
559+
shred::layout::get_reference_tick(s.payload()).unwrap(),
559560
ShredFlags::SHRED_TICK_REFERENCE_MASK.bits()
560561
);
561562
});

0 commit comments

Comments
 (0)