defines shred flags using bitflags crate (#24874)
Shred flags uses raw bit-masking ops which lacks type-safety: https://github.com/solana-labs/solana/blob/a829ddc92/ledger/src/shred.rs#L112-L114 This commit instead uses bitflags crate to define shred flags.
This commit is contained in:
parent
a829ddc922
commit
e812430e28
|
@ -10,8 +10,7 @@ use {
|
||||||
},
|
},
|
||||||
solana_entry::entry::Entry,
|
solana_entry::entry::Entry,
|
||||||
solana_ledger::shred::{
|
solana_ledger::shred::{
|
||||||
ProcessShredsStats, Shred, Shredder, MAX_DATA_SHREDS_PER_FEC_BLOCK,
|
ProcessShredsStats, Shred, ShredFlags, Shredder, MAX_DATA_SHREDS_PER_FEC_BLOCK,
|
||||||
SHRED_TICK_REFERENCE_MASK,
|
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
signature::Keypair,
|
signature::Keypair,
|
||||||
|
@ -63,6 +62,7 @@ impl StandardBroadcastRun {
|
||||||
max_ticks_in_slot: u8,
|
max_ticks_in_slot: u8,
|
||||||
stats: &mut ProcessShredsStats,
|
stats: &mut ProcessShredsStats,
|
||||||
) -> Vec<Shred> {
|
) -> Vec<Shred> {
|
||||||
|
const SHRED_TICK_REFERENCE_MASK: u8 = ShredFlags::SHRED_TICK_REFERENCE_MASK.bits();
|
||||||
let (current_slot, _) = self.current_slot_and_parent.unwrap();
|
let (current_slot, _) = self.current_slot_and_parent.unwrap();
|
||||||
match self.unfinished_slot {
|
match self.unfinished_slot {
|
||||||
None => Vec::default(),
|
None => Vec::default(),
|
||||||
|
|
|
@ -56,6 +56,7 @@ pub use crate::{
|
||||||
use {
|
use {
|
||||||
crate::blockstore::MAX_DATA_SHREDS_PER_SLOT,
|
crate::blockstore::MAX_DATA_SHREDS_PER_SLOT,
|
||||||
bincode::config::Options,
|
bincode::config::Options,
|
||||||
|
bitflags::bitflags,
|
||||||
num_enum::{IntoPrimitive, TryFromPrimitive},
|
num_enum::{IntoPrimitive, TryFromPrimitive},
|
||||||
serde::{Deserialize, Serialize},
|
serde::{Deserialize, Serialize},
|
||||||
solana_entry::entry::{create_ticks, Entry},
|
solana_entry::entry::{create_ticks, Entry},
|
||||||
|
@ -109,9 +110,14 @@ const ENCODED_PAYLOAD_SIZE: usize = SHRED_PAYLOAD_SIZE - SIZE_OF_CODING_SHRED_HE
|
||||||
|
|
||||||
pub const MAX_DATA_SHREDS_PER_FEC_BLOCK: u32 = 32;
|
pub const MAX_DATA_SHREDS_PER_FEC_BLOCK: u32 = 32;
|
||||||
|
|
||||||
pub const SHRED_TICK_REFERENCE_MASK: u8 = 0b0011_1111;
|
bitflags! {
|
||||||
const LAST_SHRED_IN_SLOT: u8 = 0b1000_0000;
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
const DATA_COMPLETE_SHRED: u8 = 0b0100_0000;
|
pub struct ShredFlags:u8 {
|
||||||
|
const SHRED_TICK_REFERENCE_MASK = 0b0011_1111;
|
||||||
|
const DATA_COMPLETE_SHRED = 0b0100_0000;
|
||||||
|
const LAST_SHRED_IN_SLOT = 0b1000_0000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -173,7 +179,7 @@ struct ShredCommonHeader {
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Deserialize, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Deserialize, Serialize)]
|
||||||
struct DataShredHeader {
|
struct DataShredHeader {
|
||||||
parent_offset: u16,
|
parent_offset: u16,
|
||||||
flags: u8,
|
flags: ShredFlags,
|
||||||
size: u16, // common shred header + data shred header + data
|
size: u16, // common shred header + data shred header + data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,16 +288,22 @@ impl Shred {
|
||||||
let size = (data.len() + SIZE_OF_DATA_SHRED_HEADER + SIZE_OF_COMMON_SHRED_HEADER) as u16;
|
let size = (data.len() + SIZE_OF_DATA_SHRED_HEADER + SIZE_OF_COMMON_SHRED_HEADER) as u16;
|
||||||
let mut data_header = DataShredHeader {
|
let mut data_header = DataShredHeader {
|
||||||
parent_offset,
|
parent_offset,
|
||||||
flags: reference_tick.min(SHRED_TICK_REFERENCE_MASK),
|
flags: unsafe {
|
||||||
|
ShredFlags::from_bits_unchecked(
|
||||||
|
ShredFlags::SHRED_TICK_REFERENCE_MASK
|
||||||
|
.bits()
|
||||||
|
.min(reference_tick),
|
||||||
|
)
|
||||||
|
},
|
||||||
size,
|
size,
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_last_data {
|
if is_last_data {
|
||||||
data_header.flags |= DATA_COMPLETE_SHRED
|
data_header.flags |= ShredFlags::DATA_COMPLETE_SHRED
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_last_in_slot {
|
if is_last_in_slot {
|
||||||
data_header.flags |= LAST_SHRED_IN_SLOT
|
data_header.flags |= ShredFlags::LAST_SHRED_IN_SLOT
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
|
@ -669,7 +681,9 @@ impl Shred {
|
||||||
|
|
||||||
pub fn last_in_slot(&self) -> bool {
|
pub fn last_in_slot(&self) -> bool {
|
||||||
if self.is_data() {
|
if self.is_data() {
|
||||||
self.data_header.flags & LAST_SHRED_IN_SLOT == LAST_SHRED_IN_SLOT
|
self.data_header
|
||||||
|
.flags
|
||||||
|
.contains(ShredFlags::LAST_SHRED_IN_SLOT)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -679,14 +693,16 @@ impl Shred {
|
||||||
/// Use this only for test code which doesn't care about actual shred
|
/// Use this only for test code which doesn't care about actual shred
|
||||||
pub fn set_last_in_slot(&mut self) {
|
pub fn set_last_in_slot(&mut self) {
|
||||||
if self.is_data() {
|
if self.is_data() {
|
||||||
self.data_header.flags |= LAST_SHRED_IN_SLOT
|
self.data_header.flags |= ShredFlags::LAST_SHRED_IN_SLOT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) fn unset_data_complete(&mut self) {
|
pub(crate) fn unset_data_complete(&mut self) {
|
||||||
if self.is_data() {
|
if self.is_data() {
|
||||||
self.data_header.flags &= !DATA_COMPLETE_SHRED;
|
self.data_header
|
||||||
|
.flags
|
||||||
|
.remove(ShredFlags::DATA_COMPLETE_SHRED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data header starts after the shred common header
|
// Data header starts after the shred common header
|
||||||
|
@ -703,7 +719,9 @@ impl Shred {
|
||||||
|
|
||||||
pub fn data_complete(&self) -> bool {
|
pub fn data_complete(&self) -> bool {
|
||||||
if self.is_data() {
|
if self.is_data() {
|
||||||
self.data_header.flags & DATA_COMPLETE_SHRED == DATA_COMPLETE_SHRED
|
self.data_header
|
||||||
|
.flags
|
||||||
|
.contains(ShredFlags::DATA_COMPLETE_SHRED)
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
@ -711,10 +729,11 @@ impl Shred {
|
||||||
|
|
||||||
pub(crate) fn reference_tick(&self) -> u8 {
|
pub(crate) fn reference_tick(&self) -> u8 {
|
||||||
if self.is_data() {
|
if self.is_data() {
|
||||||
self.data_header.flags & SHRED_TICK_REFERENCE_MASK
|
self.data_header.flags & ShredFlags::SHRED_TICK_REFERENCE_MASK
|
||||||
} else {
|
} else {
|
||||||
SHRED_TICK_REFERENCE_MASK
|
ShredFlags::SHRED_TICK_REFERENCE_MASK
|
||||||
}
|
}
|
||||||
|
.bits()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get slot from a shred packet with partial deserialize
|
// Get slot from a shred packet with partial deserialize
|
||||||
|
@ -733,7 +752,7 @@ impl Shred {
|
||||||
let flags = data[SIZE_OF_COMMON_SHRED_HEADER + SIZE_OF_DATA_SHRED_HEADER
|
let flags = data[SIZE_OF_COMMON_SHRED_HEADER + SIZE_OF_DATA_SHRED_HEADER
|
||||||
- size_of::<u8>()
|
- size_of::<u8>()
|
||||||
- size_of::<u16>()];
|
- size_of::<u16>()];
|
||||||
flags & SHRED_TICK_REFERENCE_MASK
|
flags & ShredFlags::SHRED_TICK_REFERENCE_MASK.bits()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(&self, pubkey: &Pubkey) -> bool {
|
pub fn verify(&self, pubkey: &Pubkey) -> bool {
|
||||||
|
@ -1300,4 +1319,47 @@ mod tests {
|
||||||
Some((shred.slot(), shred.index(), shred.shred_type()))
|
Some((shred.slot(), shred.index(), shred.shred_type()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_shred_flags() {
|
||||||
|
fn make_shred(is_last_data: bool, is_last_in_slot: bool, reference_tick: u8) -> Shred {
|
||||||
|
Shred::new_from_data(
|
||||||
|
0, // slot
|
||||||
|
0, // index
|
||||||
|
0, // parent_offset
|
||||||
|
&[], // data
|
||||||
|
is_last_data,
|
||||||
|
is_last_in_slot,
|
||||||
|
reference_tick,
|
||||||
|
0, // version
|
||||||
|
0, // fec_set_index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fn check_shred_flags(
|
||||||
|
shred: &Shred,
|
||||||
|
is_last_data: bool,
|
||||||
|
is_last_in_slot: bool,
|
||||||
|
reference_tick: u8,
|
||||||
|
) {
|
||||||
|
assert_eq!(shred.data_complete(), is_last_data);
|
||||||
|
assert_eq!(shred.last_in_slot(), is_last_in_slot);
|
||||||
|
assert_eq!(shred.reference_tick(), reference_tick.min(63u8));
|
||||||
|
assert_eq!(
|
||||||
|
Shred::reference_tick_from_data(&shred.payload),
|
||||||
|
reference_tick.min(63u8),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for is_last_data in [false, true] {
|
||||||
|
for is_last_in_slot in [false, true] {
|
||||||
|
for reference_tick in [0, 37, 63, 64, 80, 128, 255] {
|
||||||
|
let mut shred = make_shred(is_last_data, is_last_in_slot, reference_tick);
|
||||||
|
check_shred_flags(&shred, is_last_data, is_last_in_slot, reference_tick);
|
||||||
|
shred.set_last_in_slot();
|
||||||
|
check_shred_flags(&shred, is_last_data, true, reference_tick);
|
||||||
|
shred.unset_data_complete();
|
||||||
|
check_shred_flags(&shred, false, true, reference_tick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,8 +351,8 @@ mod tests {
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
crate::shred::{
|
crate::shred::{
|
||||||
max_entries_per_n_shred, max_ticks_per_n_shreds, verify_test_data_shred, ShredType,
|
max_entries_per_n_shred, max_ticks_per_n_shreds, verify_test_data_shred, ShredFlags,
|
||||||
SHRED_TICK_REFERENCE_MASK,
|
ShredType,
|
||||||
},
|
},
|
||||||
bincode::serialized_size,
|
bincode::serialized_size,
|
||||||
matches::assert_matches,
|
matches::assert_matches,
|
||||||
|
@ -549,10 +549,13 @@ mod tests {
|
||||||
0, // next_code_index
|
0, // next_code_index
|
||||||
);
|
);
|
||||||
data_shreds.iter().for_each(|s| {
|
data_shreds.iter().for_each(|s| {
|
||||||
assert_eq!(s.reference_tick(), SHRED_TICK_REFERENCE_MASK);
|
assert_eq!(
|
||||||
|
s.reference_tick(),
|
||||||
|
ShredFlags::SHRED_TICK_REFERENCE_MASK.bits()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Shred::reference_tick_from_data(s.payload()),
|
Shred::reference_tick_from_data(s.payload()),
|
||||||
SHRED_TICK_REFERENCE_MASK
|
ShredFlags::SHRED_TICK_REFERENCE_MASK.bits()
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -561,7 +564,7 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
deserialized_shred.reference_tick(),
|
deserialized_shred.reference_tick(),
|
||||||
SHRED_TICK_REFERENCE_MASK
|
ShredFlags::SHRED_TICK_REFERENCE_MASK.bits(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue