2019-10-28 10:29:38 -07:00
|
|
|
#![allow(clippy::implicit_hasher)]
|
2022-05-24 14:01:41 -07:00
|
|
|
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
2022-05-24 14:01:41 -07:00
|
|
|
crate::{
|
|
|
|
sigverify,
|
|
|
|
sigverify_stage::{SigVerifier, SigVerifyServiceError},
|
|
|
|
},
|
|
|
|
crossbeam_channel::Sender,
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_ledger::{
|
|
|
|
leader_schedule_cache::LeaderScheduleCache, shred::Shred,
|
|
|
|
sigverify_shreds::verify_shreds_gpu,
|
|
|
|
},
|
2021-12-11 06:44:15 -08:00
|
|
|
solana_perf::{self, packet::PacketBatch, recycler_cache::RecyclerCache},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_runtime::bank_forks::BankForks,
|
|
|
|
std::{
|
|
|
|
collections::{HashMap, HashSet},
|
|
|
|
sync::{Arc, RwLock},
|
|
|
|
},
|
|
|
|
};
|
2019-10-28 10:29:38 -07:00
|
|
|
|
2019-10-28 16:07:51 -07:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct ShredSigVerifier {
|
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
|
|
|
leader_schedule_cache: Arc<LeaderScheduleCache>,
|
2019-11-15 12:16:56 -08:00
|
|
|
recycler_cache: RecyclerCache,
|
2022-05-24 14:01:41 -07:00
|
|
|
packet_sender: Sender<Vec<PacketBatch>>,
|
2019-10-28 16:07:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ShredSigVerifier {
|
|
|
|
pub fn new(
|
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
|
|
|
leader_schedule_cache: Arc<LeaderScheduleCache>,
|
2022-05-24 14:01:41 -07:00
|
|
|
packet_sender: Sender<Vec<PacketBatch>>,
|
2019-10-28 16:07:51 -07:00
|
|
|
) -> Self {
|
|
|
|
sigverify::init();
|
|
|
|
Self {
|
|
|
|
bank_forks,
|
|
|
|
leader_schedule_cache,
|
2021-04-07 08:15:38 -07:00
|
|
|
recycler_cache: RecyclerCache::warmed(),
|
2022-05-24 14:01:41 -07:00
|
|
|
packet_sender,
|
2019-10-28 16:07:51 -07:00
|
|
|
}
|
|
|
|
}
|
2021-12-11 06:44:15 -08:00
|
|
|
fn read_slots(batches: &[PacketBatch]) -> HashSet<u64> {
|
2019-10-28 16:07:51 -07:00
|
|
|
batches
|
|
|
|
.iter()
|
2022-05-23 13:30:15 -07:00
|
|
|
.flat_map(|batch| batch.iter().filter_map(Shred::get_slot_from_packet))
|
2019-10-28 16:07:51 -07:00
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SigVerifier for ShredSigVerifier {
|
2022-05-24 14:01:41 -07:00
|
|
|
type SendType = Vec<PacketBatch>;
|
|
|
|
|
|
|
|
fn send_packets(
|
|
|
|
&mut self,
|
|
|
|
packet_batches: Vec<PacketBatch>,
|
|
|
|
) -> Result<(), SigVerifyServiceError<Self::SendType>> {
|
|
|
|
self.packet_sender.send(packet_batches)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-01-24 05:35:47 -08:00
|
|
|
fn verify_batches(
|
|
|
|
&self,
|
|
|
|
mut batches: Vec<PacketBatch>,
|
|
|
|
_valid_packets: usize,
|
|
|
|
) -> Vec<PacketBatch> {
|
2019-10-28 16:07:51 -07:00
|
|
|
let r_bank = self.bank_forks.read().unwrap().working_bank();
|
|
|
|
let slots: HashSet<u64> = Self::read_slots(&batches);
|
2019-11-02 06:23:14 -07:00
|
|
|
let mut leader_slots: HashMap<u64, [u8; 32]> = slots
|
2019-10-28 16:07:51 -07:00
|
|
|
.into_iter()
|
|
|
|
.filter_map(|slot| {
|
2019-11-02 06:23:14 -07:00
|
|
|
let key = self
|
|
|
|
.leader_schedule_cache
|
|
|
|
.slot_leader_at(slot, Some(&r_bank))?;
|
|
|
|
Some((slot, key.to_bytes()))
|
2019-10-28 16:07:51 -07:00
|
|
|
})
|
|
|
|
.collect();
|
2019-11-02 06:23:14 -07:00
|
|
|
leader_slots.insert(std::u64::MAX, [0u8; 32]);
|
2019-10-28 16:07:51 -07:00
|
|
|
|
2019-11-15 12:16:56 -08:00
|
|
|
let r = verify_shreds_gpu(&batches, &leader_slots, &self.recycler_cache);
|
2021-03-08 19:31:00 -08:00
|
|
|
solana_perf::sigverify::mark_disabled(&mut batches, &r);
|
2019-11-01 14:23:03 -07:00
|
|
|
batches
|
2019-10-28 16:07:51 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-28 10:29:38 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
pub mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
2022-05-24 14:01:41 -07:00
|
|
|
crossbeam_channel::unbounded,
|
2022-05-02 16:33:53 -07:00
|
|
|
solana_ledger::{
|
|
|
|
genesis_utils::create_genesis_config_with_leader,
|
|
|
|
shred::{Shred, ShredFlags},
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_perf::packet::Packet,
|
|
|
|
solana_runtime::bank::Bank,
|
|
|
|
solana_sdk::signature::{Keypair, Signer},
|
|
|
|
};
|
2019-11-02 06:23:14 -07:00
|
|
|
|
2019-10-28 16:07:51 -07:00
|
|
|
#[test]
|
|
|
|
fn test_sigverify_shreds_read_slots() {
|
|
|
|
solana_logger::setup();
|
2019-11-06 13:27:58 -08:00
|
|
|
let mut shred = Shred::new_from_data(
|
2020-05-15 09:35:43 -07:00
|
|
|
0xdead_c0de,
|
2019-11-06 13:27:58 -08:00
|
|
|
0xc0de,
|
|
|
|
0xdead,
|
2022-04-27 11:04:10 -07:00
|
|
|
&[1, 2, 3, 4],
|
2022-05-02 16:33:53 -07:00
|
|
|
ShredFlags::LAST_SHRED_IN_SLOT,
|
2019-11-06 13:27:58 -08:00
|
|
|
0,
|
2019-11-18 18:05:02 -08:00
|
|
|
0,
|
2019-12-12 16:50:29 -08:00
|
|
|
0xc0de,
|
2019-11-06 13:27:58 -08:00
|
|
|
);
|
2022-05-23 13:30:15 -07:00
|
|
|
let mut batches: Vec<_> = (0..2)
|
|
|
|
.map(|_| {
|
|
|
|
let mut batch = PacketBatch::with_capacity(1);
|
|
|
|
batch.resize(1, Packet::default());
|
|
|
|
batch
|
|
|
|
})
|
|
|
|
.collect();
|
2019-10-28 16:07:51 -07:00
|
|
|
|
|
|
|
let keypair = Keypair::new();
|
2022-04-19 13:00:05 -07:00
|
|
|
shred.sign(&keypair);
|
2022-05-25 09:52:54 -07:00
|
|
|
batches[0][0].buffer_mut()[..shred.payload().len()].copy_from_slice(shred.payload());
|
2022-05-23 13:30:15 -07:00
|
|
|
batches[0][0].meta.size = shred.payload().len();
|
2019-10-28 16:07:51 -07:00
|
|
|
|
2019-11-06 13:27:58 -08:00
|
|
|
let mut shred = Shred::new_from_data(
|
2020-05-15 09:35:43 -07:00
|
|
|
0xc0de_dead,
|
2019-11-06 13:27:58 -08:00
|
|
|
0xc0de,
|
|
|
|
0xdead,
|
2022-04-27 11:04:10 -07:00
|
|
|
&[1, 2, 3, 4],
|
2022-05-02 16:33:53 -07:00
|
|
|
ShredFlags::LAST_SHRED_IN_SLOT,
|
2019-11-06 13:27:58 -08:00
|
|
|
0,
|
2019-11-18 18:05:02 -08:00
|
|
|
0,
|
2019-12-12 16:50:29 -08:00
|
|
|
0xc0de,
|
2019-11-06 13:27:58 -08:00
|
|
|
);
|
2022-04-19 13:00:05 -07:00
|
|
|
shred.sign(&keypair);
|
2022-05-25 09:52:54 -07:00
|
|
|
batches[1][0].buffer_mut()[..shred.payload().len()].copy_from_slice(shred.payload());
|
2022-05-23 13:30:15 -07:00
|
|
|
batches[1][0].meta.size = shred.payload().len();
|
2019-10-28 16:07:51 -07:00
|
|
|
|
2020-05-15 09:35:43 -07:00
|
|
|
let expected: HashSet<u64> = [0xc0de_dead, 0xdead_c0de].iter().cloned().collect();
|
2021-12-11 06:44:15 -08:00
|
|
|
assert_eq!(ShredSigVerifier::read_slots(&batches), expected);
|
2019-10-28 16:07:51 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2021-12-11 06:44:15 -08:00
|
|
|
fn test_sigverify_shreds_verify_batches() {
|
2019-10-28 16:07:51 -07:00
|
|
|
let leader_keypair = Arc::new(Keypair::new());
|
|
|
|
let leader_pubkey = leader_keypair.pubkey();
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(
|
|
|
|
&create_genesis_config_with_leader(100, &leader_pubkey, 10).genesis_config,
|
|
|
|
);
|
2019-10-28 16:07:51 -07:00
|
|
|
let cache = Arc::new(LeaderScheduleCache::new_from_bank(&bank));
|
2020-06-12 10:04:17 -07:00
|
|
|
let bf = Arc::new(RwLock::new(BankForks::new(bank)));
|
2022-05-24 14:01:41 -07:00
|
|
|
let (sender, receiver) = unbounded();
|
|
|
|
let mut verifier = ShredSigVerifier::new(bf, cache, sender);
|
2019-10-28 16:07:51 -07:00
|
|
|
|
2022-05-23 13:30:15 -07:00
|
|
|
let batch_size = 2;
|
|
|
|
let mut batch = PacketBatch::with_capacity(batch_size);
|
|
|
|
batch.resize(batch_size, Packet::default());
|
|
|
|
let mut batches = vec![batch];
|
2019-10-28 16:07:51 -07:00
|
|
|
|
2022-05-02 16:33:53 -07:00
|
|
|
let mut shred = Shred::new_from_data(
|
|
|
|
0,
|
|
|
|
0xc0de,
|
|
|
|
0xdead,
|
|
|
|
&[1, 2, 3, 4],
|
|
|
|
ShredFlags::LAST_SHRED_IN_SLOT,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0xc0de,
|
|
|
|
);
|
2022-04-19 13:00:05 -07:00
|
|
|
shred.sign(&leader_keypair);
|
2022-05-25 09:52:54 -07:00
|
|
|
batches[0][0].buffer_mut()[..shred.payload().len()].copy_from_slice(shred.payload());
|
2022-05-23 13:30:15 -07:00
|
|
|
batches[0][0].meta.size = shred.payload().len();
|
2019-10-28 16:07:51 -07:00
|
|
|
|
2022-05-02 16:33:53 -07:00
|
|
|
let mut shred = Shred::new_from_data(
|
|
|
|
0,
|
|
|
|
0xbeef,
|
|
|
|
0xc0de,
|
|
|
|
&[1, 2, 3, 4],
|
|
|
|
ShredFlags::LAST_SHRED_IN_SLOT,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0xc0de,
|
|
|
|
);
|
2019-10-28 16:07:51 -07:00
|
|
|
let wrong_keypair = Keypair::new();
|
2022-04-19 13:00:05 -07:00
|
|
|
shred.sign(&wrong_keypair);
|
2022-05-25 09:52:54 -07:00
|
|
|
batches[0][1].buffer_mut()[..shred.payload().len()].copy_from_slice(shred.payload());
|
2022-05-23 13:30:15 -07:00
|
|
|
batches[0][1].meta.size = shred.payload().len();
|
2019-10-28 16:07:51 -07:00
|
|
|
|
2022-01-24 05:35:47 -08:00
|
|
|
let num_packets = solana_perf::sigverify::count_packets_in_batches(&batches);
|
|
|
|
let rv = verifier.verify_batches(batches, num_packets);
|
2022-05-23 13:30:15 -07:00
|
|
|
assert!(!rv[0][0].meta.discard());
|
|
|
|
assert!(rv[0][1].meta.discard());
|
2022-05-24 14:01:41 -07:00
|
|
|
|
|
|
|
verifier.send_packets(rv.clone()).unwrap();
|
|
|
|
let received_packets = receiver.recv().unwrap();
|
|
|
|
assert_eq!(received_packets.len(), rv.len());
|
|
|
|
for (received_packet_batch, original_packet_batch) in received_packets.iter().zip(rv.iter())
|
|
|
|
{
|
|
|
|
assert_eq!(
|
|
|
|
received_packet_batch.iter().collect::<Vec<_>>(),
|
|
|
|
original_packet_batch.iter().collect::<Vec<_>>()
|
|
|
|
);
|
|
|
|
}
|
2019-10-28 16:07:51 -07:00
|
|
|
}
|
2019-10-28 10:29:38 -07:00
|
|
|
}
|