changes Shred::parent return type to Option<Slot> (#21370)

Shred::parent can return garbage if the struct fields are invalid:
https://github.com/solana-labs/solana/blob/8a50b6302/ledger/src/shred.rs#L446-L453

The commit adds more sanity checks and changes the return type to Option<Slot>.
This commit is contained in:
behzad nouri 2021-11-23 14:45:26 +00:00 committed by GitHub
parent 22a2537aac
commit dd338b6c9f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 24 additions and 12 deletions

View File

@ -596,7 +596,7 @@ mod test {
.expect("Expected a shred that signals an interrupt");
// Validate the shred
assert_eq!(shred.parent(), parent);
assert_eq!(shred.parent(), Some(parent));
assert_eq!(shred.slot(), slot);
assert_eq!(shred.index(), next_shred_index);
assert!(shred.is_data());

View File

@ -164,7 +164,10 @@ impl ReceiveWindowStats {
fn verify_shred_slot(shred: &Shred, root: u64) -> bool {
match shred.shred_type() {
// Only data shreds have parent information
ShredType::Data => blockstore::verify_shred_slots(shred.slot(), shred.parent(), root),
ShredType::Data => match shred.parent() {
Some(parent) => blockstore::verify_shred_slots(shred.slot(), parent, root),
None => false,
},
// Filter out outdated coding shreds
ShredType::Code => shred.slot() >= root,
}

View File

@ -1209,8 +1209,12 @@ impl Blockstore {
get_index_meta_entry(&self.db, slot, index_working_set, index_meta_time);
let index_meta = &mut index_meta_working_set_entry.index;
let slot_meta_entry =
get_slot_meta_entry(&self.db, slot_meta_working_set, slot, shred.parent());
let slot_meta_entry = get_slot_meta_entry(
&self.db,
slot_meta_working_set,
slot,
shred.parent().ok_or(InsertDataShredError::InvalidShred)?,
);
let slot_meta = &mut slot_meta_entry.new_slot_meta.borrow_mut();

View File

@ -69,7 +69,11 @@ use {
pubkey::Pubkey,
signature::{Keypair, Signature, Signer},
},
std::{cell::RefCell, convert::TryInto, mem::size_of},
std::{
cell::RefCell,
convert::{TryFrom, TryInto},
mem::size_of,
},
thiserror::Error,
};
@ -443,12 +447,13 @@ impl Shred {
self.common_header.slot
}
// TODO: This should return Option<Slot>
pub fn parent(&self) -> Slot {
if self.is_data() {
self.common_header.slot - u64::from(self.data_header.parent_offset)
} else {
std::u64::MAX
pub fn parent(&self) -> Option<Slot> {
match self.shred_type() {
ShredType::Data => {
let parent_offset = Slot::try_from(self.data_header.parent_offset);
self.slot().checked_sub(parent_offset.ok()?)
}
ShredType::Code => None,
}
}
@ -1098,7 +1103,7 @@ pub fn verify_test_data_shred(
assert!(shred.is_data());
assert_eq!(shred.index(), index);
assert_eq!(shred.slot(), slot);
assert_eq!(shred.parent(), parent);
assert_eq!(shred.parent(), Some(parent));
assert_eq!(verify, shred.verify(pk));
if is_last_in_slot {
assert!(shred.last_in_slot());