simplifies packet/shred sanity checks (#26356)
This commit is contained in:
parent
53b9420562
commit
d3a14f5b30
|
@ -11,7 +11,6 @@ use {
|
||||||
solana_streamer::streamer::{self, PacketBatchReceiver, StreamerReceiveStats},
|
solana_streamer::streamer::{self, PacketBatchReceiver, StreamerReceiveStats},
|
||||||
std::{
|
std::{
|
||||||
net::UdpSocket,
|
net::UdpSocket,
|
||||||
ops::RangeBounds,
|
|
||||||
sync::{atomic::AtomicBool, Arc, RwLock},
|
sync::{atomic::AtomicBool, Arc, RwLock},
|
||||||
thread::{self, Builder, JoinHandle},
|
thread::{self, Builder, JoinHandle},
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
|
@ -63,12 +62,12 @@ impl ShredFetchStage {
|
||||||
}
|
}
|
||||||
stats.shred_count += packet_batch.len();
|
stats.shred_count += packet_batch.len();
|
||||||
// Limit shreds to 2 epochs away.
|
// Limit shreds to 2 epochs away.
|
||||||
let slot_bounds = (last_root + 1)..(last_slot + 2 * slots_per_epoch);
|
let max_slot = last_slot + 2 * slots_per_epoch;
|
||||||
for packet in packet_batch.iter_mut() {
|
for packet in packet_batch.iter_mut() {
|
||||||
if should_discard_packet(
|
if should_discard_packet(
|
||||||
packet,
|
packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds.clone(),
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&packet_hasher,
|
&packet_hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -197,14 +196,13 @@ impl ShredFetchStage {
|
||||||
fn should_discard_packet(
|
fn should_discard_packet(
|
||||||
packet: &Packet,
|
packet: &Packet,
|
||||||
root: Slot,
|
root: Slot,
|
||||||
// Range of slots to ingest shreds for.
|
max_slot: Slot, // Max slot to ingest shreds for.
|
||||||
slot_bounds: impl RangeBounds<Slot>,
|
|
||||||
shred_version: u16,
|
shred_version: u16,
|
||||||
packet_hasher: &PacketHasher,
|
packet_hasher: &PacketHasher,
|
||||||
shreds_received: &mut ShredsReceived,
|
shreds_received: &mut ShredsReceived,
|
||||||
stats: &mut ShredFetchStats,
|
stats: &mut ShredFetchStats,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if should_discard_shred(packet, root, shred_version, slot_bounds, stats) {
|
if should_discard_shred(packet, root, max_slot, shred_version, stats) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
let hash = packet_hasher.hash_packet(packet);
|
let hash = packet_hasher.hash_packet(packet);
|
||||||
|
@ -253,11 +251,11 @@ mod tests {
|
||||||
let last_root = 0;
|
let last_root = 0;
|
||||||
let last_slot = 100;
|
let last_slot = 100;
|
||||||
let slots_per_epoch = 10;
|
let slots_per_epoch = 10;
|
||||||
let slot_bounds = (last_root + 1)..(last_slot + 2 * slots_per_epoch);
|
let max_slot = last_slot + 2 * slots_per_epoch;
|
||||||
assert!(!should_discard_packet(
|
assert!(!should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds.clone(),
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -272,7 +270,7 @@ mod tests {
|
||||||
assert!(!should_discard_packet(
|
assert!(!should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds,
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -290,7 +288,7 @@ mod tests {
|
||||||
let last_slot = 100;
|
let last_slot = 100;
|
||||||
let slots_per_epoch = 10;
|
let slots_per_epoch = 10;
|
||||||
let shred_version = 59445;
|
let shred_version = 59445;
|
||||||
let slot_bounds = (last_root + 1)..(last_slot + 2 * slots_per_epoch);
|
let max_slot = last_slot + 2 * slots_per_epoch;
|
||||||
|
|
||||||
let hasher = PacketHasher::default();
|
let hasher = PacketHasher::default();
|
||||||
|
|
||||||
|
@ -298,7 +296,7 @@ mod tests {
|
||||||
assert!(should_discard_packet(
|
assert!(should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds.clone(),
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -321,7 +319,7 @@ mod tests {
|
||||||
assert!(should_discard_packet(
|
assert!(should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
3,
|
3,
|
||||||
3..slot_bounds.end,
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -332,7 +330,7 @@ mod tests {
|
||||||
assert!(should_discard_packet(
|
assert!(should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds.clone(),
|
max_slot,
|
||||||
345, // shred_version
|
345, // shred_version
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -344,7 +342,7 @@ mod tests {
|
||||||
assert!(!should_discard_packet(
|
assert!(!should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds.clone(),
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -355,7 +353,7 @@ mod tests {
|
||||||
assert!(should_discard_packet(
|
assert!(should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds.clone(),
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -379,7 +377,7 @@ mod tests {
|
||||||
assert!(should_discard_packet(
|
assert!(should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds.clone(),
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
@ -392,7 +390,7 @@ mod tests {
|
||||||
assert!(should_discard_packet(
|
assert!(should_discard_packet(
|
||||||
&packet,
|
&packet,
|
||||||
last_root,
|
last_root,
|
||||||
slot_bounds,
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
&hasher,
|
&hasher,
|
||||||
&mut shreds_received,
|
&mut shreds_received,
|
||||||
|
|
|
@ -69,7 +69,7 @@ use {
|
||||||
signature::{Keypair, Signature, Signer},
|
signature::{Keypair, Signature, Signer},
|
||||||
},
|
},
|
||||||
static_assertions::const_assert_eq,
|
static_assertions::const_assert_eq,
|
||||||
std::{fmt::Debug, ops::RangeBounds},
|
std::fmt::Debug,
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -532,9 +532,7 @@ pub mod layout {
|
||||||
|
|
||||||
pub fn get_shred(packet: &Packet) -> Option<&[u8]> {
|
pub fn get_shred(packet: &Packet) -> Option<&[u8]> {
|
||||||
let size = get_shred_size(packet)?;
|
let size = get_shred_size(packet)?;
|
||||||
let shred = packet.data(..size)?;
|
packet.data(..size)
|
||||||
// Should at least have a signature.
|
|
||||||
(size >= SIZE_OF_SIGNATURE).then(|| shred)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_signature(shred: &[u8]) -> Option<Signature> {
|
pub(crate) fn get_signature(shred: &[u8]) -> Option<Signature> {
|
||||||
|
@ -678,15 +676,16 @@ impl TryFrom<u8> for ShredVariant {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Accepts shreds in the slot range [root + 1, max_slot].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn should_discard_shred(
|
pub fn should_discard_shred(
|
||||||
packet: &Packet,
|
packet: &Packet,
|
||||||
root: Slot,
|
root: Slot,
|
||||||
|
max_slot: Slot,
|
||||||
shred_version: u16,
|
shred_version: u16,
|
||||||
// Range of slots to ingest shreds for.
|
|
||||||
slot_bounds: impl RangeBounds<Slot>,
|
|
||||||
stats: &mut ShredFetchStats,
|
stats: &mut ShredFetchStats,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
debug_assert!(root < max_slot);
|
||||||
let shred = match layout::get_shred(packet) {
|
let shred = match layout::get_shred(packet) {
|
||||||
None => {
|
None => {
|
||||||
stats.index_overrun += 1;
|
stats.index_overrun += 1;
|
||||||
|
@ -694,10 +693,18 @@ pub fn should_discard_shred(
|
||||||
}
|
}
|
||||||
Some(shred) => shred,
|
Some(shred) => shred,
|
||||||
};
|
};
|
||||||
if OFFSET_OF_SHRED_INDEX + SIZE_OF_SHRED_INDEX > shred.len() {
|
match layout::get_version(shred) {
|
||||||
|
None => {
|
||||||
stats.index_overrun += 1;
|
stats.index_overrun += 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
Some(version) => {
|
||||||
|
if version != shred_version {
|
||||||
|
stats.shred_version_mismatch += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let shred_type = match layout::get_shred_type(shred) {
|
let shred_type = match layout::get_shred_type(shred) {
|
||||||
Ok(shred_type) => shred_type,
|
Ok(shred_type) => shred_type,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
@ -707,7 +714,7 @@ pub fn should_discard_shred(
|
||||||
};
|
};
|
||||||
let slot = match layout::get_slot(shred) {
|
let slot = match layout::get_slot(shred) {
|
||||||
Some(slot) => {
|
Some(slot) => {
|
||||||
if !slot_bounds.contains(&slot) {
|
if slot > max_slot {
|
||||||
stats.slot_out_of_range += 1;
|
stats.slot_out_of_range += 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -725,10 +732,6 @@ pub fn should_discard_shred(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if layout::get_version(shred) != Some(shred_version) {
|
|
||||||
stats.shred_version_mismatch += 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
match shred_type {
|
match shred_type {
|
||||||
ShredType::Code => {
|
ShredType::Code => {
|
||||||
if index >= shred_code::MAX_CODE_SHREDS_PER_SLOT as u32 {
|
if index >= shred_code::MAX_CODE_SHREDS_PER_SLOT as u32 {
|
||||||
|
@ -739,7 +742,6 @@ pub fn should_discard_shred(
|
||||||
stats.slot_out_of_range += 1;
|
stats.slot_out_of_range += 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
ShredType::Data => {
|
ShredType::Data => {
|
||||||
if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
|
if index >= MAX_DATA_SHREDS_PER_SLOT as u32 {
|
||||||
|
@ -764,9 +766,9 @@ pub fn should_discard_shred(
|
||||||
stats.slot_out_of_range += 1;
|
stats.slot_out_of_range += 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
false
|
false
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn max_ticks_per_n_shreds(num_shreds: u64, shred_data_size: Option<usize>) -> u64 {
|
pub fn max_ticks_per_n_shreds(num_shreds: u64, shred_data_size: Option<usize>) -> u64 {
|
||||||
|
@ -940,7 +942,7 @@ mod tests {
|
||||||
let mut packet = Packet::default();
|
let mut packet = Packet::default();
|
||||||
let root = 1;
|
let root = 1;
|
||||||
let shred_version = 798;
|
let shred_version = 798;
|
||||||
let slot_bounds = ..16;
|
let max_slot = 16;
|
||||||
let shred = Shred::new_from_data(
|
let shred = Shred::new_from_data(
|
||||||
2, // slot
|
2, // slot
|
||||||
3, // index
|
3, // index
|
||||||
|
@ -956,8 +958,8 @@ mod tests {
|
||||||
assert!(!should_discard_shred(
|
assert!(!should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(stats, ShredFetchStats::default());
|
assert_eq!(stats, ShredFetchStats::default());
|
||||||
|
@ -966,8 +968,8 @@ mod tests {
|
||||||
assert!(should_discard_shred(
|
assert!(should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(stats.index_overrun, 1);
|
assert_eq!(stats.index_overrun, 1);
|
||||||
|
@ -976,8 +978,8 @@ mod tests {
|
||||||
assert!(should_discard_shred(
|
assert!(should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(stats.index_overrun, 2);
|
assert_eq!(stats.index_overrun, 2);
|
||||||
|
@ -986,8 +988,8 @@ mod tests {
|
||||||
assert!(should_discard_shred(
|
assert!(should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(stats.index_overrun, 3);
|
assert_eq!(stats.index_overrun, 3);
|
||||||
|
@ -996,8 +998,8 @@ mod tests {
|
||||||
assert!(should_discard_shred(
|
assert!(should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(stats.index_overrun, 4);
|
assert_eq!(stats.index_overrun, 4);
|
||||||
|
@ -1006,8 +1008,8 @@ mod tests {
|
||||||
assert!(should_discard_shred(
|
assert!(should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(stats.bad_parent_offset, 1);
|
assert_eq!(stats.bad_parent_offset, 1);
|
||||||
|
@ -1026,8 +1028,8 @@ mod tests {
|
||||||
assert!(!should_discard_shred(
|
assert!(!should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1045,8 +1047,8 @@ mod tests {
|
||||||
assert!(should_discard_shred(
|
assert!(should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(1, stats.index_out_of_bounds);
|
assert_eq!(1, stats.index_out_of_bounds);
|
||||||
|
@ -1059,19 +1061,38 @@ mod tests {
|
||||||
30, // num_data_shreds
|
30, // num_data_shreds
|
||||||
4, // num_coding_shreds
|
4, // num_coding_shreds
|
||||||
3, // position
|
3, // position
|
||||||
200, // version
|
shred_version,
|
||||||
);
|
);
|
||||||
shred.copy_to_packet(&mut packet);
|
shred.copy_to_packet(&mut packet);
|
||||||
|
assert!(!should_discard_shred(
|
||||||
|
&packet,
|
||||||
|
root,
|
||||||
|
max_slot,
|
||||||
|
shred_version,
|
||||||
|
&mut stats
|
||||||
|
));
|
||||||
packet.buffer_mut()[OFFSET_OF_SHRED_VARIANT] = u8::MAX;
|
packet.buffer_mut()[OFFSET_OF_SHRED_VARIANT] = u8::MAX;
|
||||||
|
|
||||||
assert!(should_discard_shred(
|
assert!(should_discard_shred(
|
||||||
&packet,
|
&packet,
|
||||||
root,
|
root,
|
||||||
|
max_slot,
|
||||||
shred_version,
|
shred_version,
|
||||||
slot_bounds,
|
|
||||||
&mut stats
|
&mut stats
|
||||||
));
|
));
|
||||||
assert_eq!(1, stats.bad_shred_type);
|
assert_eq!(1, stats.bad_shred_type);
|
||||||
|
assert_eq!(stats.shred_version_mismatch, 0);
|
||||||
|
|
||||||
|
packet.buffer_mut()[OFFSET_OF_SHRED_INDEX + SIZE_OF_SHRED_INDEX + 1] = u8::MAX;
|
||||||
|
assert!(should_discard_shred(
|
||||||
|
&packet,
|
||||||
|
root,
|
||||||
|
max_slot,
|
||||||
|
shred_version,
|
||||||
|
&mut stats
|
||||||
|
));
|
||||||
|
assert_eq!(1, stats.bad_shred_type);
|
||||||
|
assert_eq!(stats.shred_version_mismatch, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asserts that ShredType is backward compatible with u8.
|
// Asserts that ShredType is backward compatible with u8.
|
||||||
|
|
Loading…
Reference in New Issue