2020-03-15 20:31:05 -07:00
|
|
|
use crate::{
|
2020-07-09 22:52:54 -07:00
|
|
|
cluster_info_vote_listener::VerifiedLabelVotePacketsReceiver, crds_value::CrdsValueLabel,
|
2020-03-17 23:30:23 -07:00
|
|
|
result::Result,
|
2020-03-15 20:31:05 -07:00
|
|
|
};
|
2020-03-17 23:30:23 -07:00
|
|
|
use solana_perf::packet::Packets;
|
2021-03-03 11:07:16 -08:00
|
|
|
use solana_sdk::clock::Slot;
|
|
|
|
use std::{
|
|
|
|
collections::{hash_map::Entry, HashMap},
|
|
|
|
time::Duration,
|
|
|
|
};
|
2020-03-15 20:31:05 -07:00
|
|
|
|
|
|
|
#[derive(Default)]
|
2021-03-03 11:07:16 -08:00
|
|
|
pub struct VerifiedVotePackets(HashMap<CrdsValueLabel, (u64, Slot, Packets)>);
|
2020-03-15 20:31:05 -07:00
|
|
|
|
|
|
|
impl VerifiedVotePackets {
|
2021-01-25 01:01:47 -08:00
|
|
|
pub fn receive_and_process_vote_packets(
|
2020-03-15 20:31:05 -07:00
|
|
|
&mut self,
|
2020-07-09 22:52:54 -07:00
|
|
|
vote_packets_receiver: &VerifiedLabelVotePacketsReceiver,
|
2020-03-15 20:31:05 -07:00
|
|
|
last_update_version: &mut u64,
|
|
|
|
) -> Result<()> {
|
|
|
|
let timer = Duration::from_millis(200);
|
|
|
|
let vote_packets = vote_packets_receiver.recv_timeout(timer)?;
|
|
|
|
*last_update_version += 1;
|
2021-03-03 11:07:16 -08:00
|
|
|
for (label, slot, packet) in vote_packets {
|
|
|
|
self.0.insert(label, (*last_update_version, slot, packet));
|
2020-03-15 20:31:05 -07:00
|
|
|
}
|
|
|
|
while let Ok(vote_packets) = vote_packets_receiver.try_recv() {
|
2021-03-03 11:07:16 -08:00
|
|
|
for (label, slot, packet) in vote_packets {
|
|
|
|
self.0.insert(label, (*last_update_version, slot, packet));
|
2020-03-15 20:31:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-01-25 01:01:47 -08:00
|
|
|
#[cfg(test)]
|
2021-03-03 11:07:16 -08:00
|
|
|
fn get_vote_packets(&self, key: &CrdsValueLabel) -> Option<&(u64, Slot, Packets)> {
|
2021-01-25 01:01:47 -08:00
|
|
|
self.0.get(key)
|
|
|
|
}
|
|
|
|
|
2021-02-26 15:23:08 -08:00
|
|
|
pub fn get_latest_votes(&self, last_update_version: u64) -> (u64, Packets) {
|
2020-03-15 20:31:05 -07:00
|
|
|
let mut new_update_version = last_update_version;
|
2021-03-03 11:07:16 -08:00
|
|
|
let mut votes = HashMap::new();
|
|
|
|
for (label, (version, slot, packets)) in &self.0 {
|
|
|
|
new_update_version = std::cmp::max(*version, new_update_version);
|
|
|
|
if *version <= last_update_version {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
match votes.entry(label.pubkey()) {
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
entry.insert((slot, packets));
|
|
|
|
}
|
|
|
|
Entry::Occupied(mut entry) => {
|
|
|
|
let (entry_slot, _) = entry.get();
|
|
|
|
if *entry_slot < slot {
|
|
|
|
*entry.get_mut() = (slot, packets);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let packets = votes
|
|
|
|
.into_iter()
|
2021-04-09 09:55:24 -07:00
|
|
|
.flat_map(|(_, (_, packets))| &packets.packets)
|
|
|
|
.cloned()
|
2020-03-15 20:31:05 -07:00
|
|
|
.collect();
|
2021-02-26 15:23:08 -08:00
|
|
|
(new_update_version, Packets::new(packets))
|
2020-03-15 20:31:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2020-03-17 23:30:23 -07:00
|
|
|
use crate::result::Error;
|
2020-03-15 20:31:05 -07:00
|
|
|
use crossbeam_channel::{unbounded, RecvTimeoutError};
|
2020-03-17 23:30:23 -07:00
|
|
|
use solana_perf::packet::{Meta, Packet};
|
2020-03-15 20:31:05 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_latest_votes() {
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
2020-12-13 17:26:34 -08:00
|
|
|
let label1 = CrdsValueLabel::Vote(0, pubkey);
|
|
|
|
let label2 = CrdsValueLabel::Vote(1, pubkey);
|
2020-03-15 20:31:05 -07:00
|
|
|
let mut verified_vote_packets = VerifiedVotePackets(HashMap::new());
|
|
|
|
|
|
|
|
let data = Packet {
|
|
|
|
meta: Meta {
|
|
|
|
repair: true,
|
|
|
|
..Meta::default()
|
|
|
|
},
|
|
|
|
..Packet::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let none_empty_packets = Packets::new(vec![data, Packet::default()]);
|
|
|
|
|
|
|
|
verified_vote_packets
|
|
|
|
.0
|
2021-03-03 11:07:16 -08:00
|
|
|
.insert(label1, (2, 42, none_empty_packets));
|
2020-03-15 20:31:05 -07:00
|
|
|
verified_vote_packets
|
|
|
|
.0
|
2021-03-03 11:07:16 -08:00
|
|
|
.insert(label2, (1, 23, Packets::default()));
|
2020-03-15 20:31:05 -07:00
|
|
|
|
|
|
|
// Both updates have timestamps greater than 0, so both should be returned
|
|
|
|
let (new_update_version, updates) = verified_vote_packets.get_latest_votes(0);
|
|
|
|
assert_eq!(new_update_version, 2);
|
2021-02-26 15:23:08 -08:00
|
|
|
assert_eq!(updates.packets.len(), 2);
|
2020-03-15 20:31:05 -07:00
|
|
|
|
|
|
|
// Only the nonempty packet had a timestamp greater than 1
|
|
|
|
let (new_update_version, updates) = verified_vote_packets.get_latest_votes(1);
|
|
|
|
assert_eq!(new_update_version, 2);
|
2021-05-19 07:31:47 -07:00
|
|
|
assert!(!updates.packets.is_empty());
|
2020-03-15 20:31:05 -07:00
|
|
|
|
|
|
|
// If the given timestamp is greater than all timestamps in any update,
|
|
|
|
// returned timestamp should be the same as the given timestamp, and
|
|
|
|
// no updates should be returned
|
|
|
|
let (new_update_version, updates) = verified_vote_packets.get_latest_votes(3);
|
|
|
|
assert_eq!(new_update_version, 3);
|
|
|
|
assert!(updates.is_empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_get_and_process_vote_packets() {
|
|
|
|
let (s, r) = unbounded();
|
2020-10-19 12:12:08 -07:00
|
|
|
let pubkey = solana_sdk::pubkey::new_rand();
|
2020-12-13 17:26:34 -08:00
|
|
|
let label1 = CrdsValueLabel::Vote(0, pubkey);
|
|
|
|
let label2 = CrdsValueLabel::Vote(1, pubkey);
|
2020-03-15 20:31:05 -07:00
|
|
|
let mut update_version = 0;
|
2021-03-03 11:07:16 -08:00
|
|
|
s.send(vec![(label1.clone(), 17, Packets::default())])
|
|
|
|
.unwrap();
|
|
|
|
s.send(vec![(label2.clone(), 23, Packets::default())])
|
|
|
|
.unwrap();
|
2020-03-15 20:31:05 -07:00
|
|
|
|
|
|
|
let data = Packet {
|
|
|
|
meta: Meta {
|
|
|
|
repair: true,
|
|
|
|
..Meta::default()
|
|
|
|
},
|
|
|
|
..Packet::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
let later_packets = Packets::new(vec![data, Packet::default()]);
|
2021-03-03 11:07:16 -08:00
|
|
|
s.send(vec![(label1.clone(), 42, later_packets)]).unwrap();
|
2020-03-15 20:31:05 -07:00
|
|
|
let mut verified_vote_packets = VerifiedVotePackets(HashMap::new());
|
|
|
|
verified_vote_packets
|
2021-01-25 01:01:47 -08:00
|
|
|
.receive_and_process_vote_packets(&r, &mut update_version)
|
2020-03-15 20:31:05 -07:00
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Test timestamps for same batch are the same
|
2021-01-25 01:01:47 -08:00
|
|
|
let update_version1 = verified_vote_packets.get_vote_packets(&label1).unwrap().0;
|
2020-03-15 20:31:05 -07:00
|
|
|
assert_eq!(
|
|
|
|
update_version1,
|
2021-01-25 01:01:47 -08:00
|
|
|
verified_vote_packets.get_vote_packets(&label2).unwrap().0
|
2020-03-15 20:31:05 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
// Test the later value overwrote the earlier one for this label
|
2021-01-25 01:01:47 -08:00
|
|
|
assert!(
|
|
|
|
verified_vote_packets
|
|
|
|
.get_vote_packets(&label1)
|
|
|
|
.unwrap()
|
2021-03-03 11:07:16 -08:00
|
|
|
.2
|
2021-01-25 01:01:47 -08:00
|
|
|
.packets
|
|
|
|
.len()
|
|
|
|
> 1
|
|
|
|
);
|
2020-03-15 20:31:05 -07:00
|
|
|
assert_eq!(
|
2021-01-25 01:01:47 -08:00
|
|
|
verified_vote_packets
|
|
|
|
.get_vote_packets(&label2)
|
|
|
|
.unwrap()
|
2021-03-03 11:07:16 -08:00
|
|
|
.2
|
2021-01-25 01:01:47 -08:00
|
|
|
.packets
|
|
|
|
.len(),
|
2020-03-15 20:31:05 -07:00
|
|
|
0
|
|
|
|
);
|
|
|
|
|
|
|
|
// Test timestamp for next batch overwrites the original
|
2021-03-03 11:07:16 -08:00
|
|
|
s.send(vec![(label2.clone(), 51, Packets::default())])
|
|
|
|
.unwrap();
|
2020-03-15 20:31:05 -07:00
|
|
|
verified_vote_packets
|
2021-01-25 01:01:47 -08:00
|
|
|
.receive_and_process_vote_packets(&r, &mut update_version)
|
2020-03-15 20:31:05 -07:00
|
|
|
.unwrap();
|
2021-01-25 01:01:47 -08:00
|
|
|
let update_version2 = verified_vote_packets.get_vote_packets(&label2).unwrap().0;
|
2020-03-15 20:31:05 -07:00
|
|
|
assert!(update_version2 > update_version1);
|
|
|
|
|
|
|
|
// Test empty doesn't bump the version
|
|
|
|
let before = update_version;
|
|
|
|
assert_matches!(
|
2021-01-25 01:01:47 -08:00
|
|
|
verified_vote_packets.receive_and_process_vote_packets(&r, &mut update_version),
|
2020-03-15 20:31:05 -07:00
|
|
|
Err(Error::CrossbeamRecvTimeoutError(RecvTimeoutError::Timeout))
|
|
|
|
);
|
|
|
|
assert_eq!(before, update_version);
|
|
|
|
}
|
|
|
|
}
|