2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
crate::{
|
2022-05-24 14:01:41 -07:00
|
|
|
banking_stage::BankingPacketSender,
|
2021-12-03 09:00:31 -08:00
|
|
|
optimistic_confirmation_verifier::OptimisticConfirmationVerifier,
|
|
|
|
replay_stage::DUPLICATE_THRESHOLD,
|
|
|
|
result::{Error, Result},
|
|
|
|
sigverify,
|
|
|
|
verified_vote_packets::{
|
|
|
|
ValidatorGossipVotesIterator, VerifiedVoteMetadata, VerifiedVotePackets,
|
|
|
|
},
|
|
|
|
vote_stake_tracker::VoteStakeTracker,
|
2021-11-18 15:20:41 -08:00
|
|
|
},
|
2022-01-11 02:44:46 -08:00
|
|
|
crossbeam_channel::{unbounded, Receiver, RecvTimeoutError, Select, Sender},
|
2021-12-03 09:00:31 -08:00
|
|
|
log::*,
|
|
|
|
solana_gossip::{
|
|
|
|
cluster_info::{ClusterInfo, GOSSIP_SLEEP_MILLIS},
|
|
|
|
crds::Cursor,
|
|
|
|
},
|
|
|
|
solana_ledger::blockstore::Blockstore,
|
|
|
|
solana_measure::measure::Measure,
|
|
|
|
solana_metrics::inc_new_counter_debug,
|
2022-05-24 14:01:41 -07:00
|
|
|
solana_perf::packet,
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_poh::poh_recorder::PohRecorder,
|
|
|
|
solana_rpc::{
|
|
|
|
optimistically_confirmed_bank_tracker::{BankNotification, BankNotificationSender},
|
|
|
|
rpc_subscriptions::RpcSubscriptions,
|
|
|
|
},
|
|
|
|
solana_runtime::{
|
2022-01-19 18:39:21 -08:00
|
|
|
bank::Bank,
|
|
|
|
bank_forks::BankForks,
|
|
|
|
commitment::VOTE_THRESHOLD_SIZE,
|
|
|
|
epoch_stakes::EpochStakes,
|
|
|
|
vote_parser::{self, ParsedVote},
|
|
|
|
vote_sender_types::ReplayVoteReceiver,
|
|
|
|
vote_transaction::VoteTransaction,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
solana_sdk::{
|
2022-01-03 13:07:47 -08:00
|
|
|
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_TICKS_PER_SLOT},
|
2021-12-03 09:00:31 -08:00
|
|
|
hash::Hash,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::Signature,
|
|
|
|
slot_hashes,
|
2022-06-27 06:53:34 -07:00
|
|
|
timing::AtomicInterval,
|
2021-12-03 09:00:31 -08:00
|
|
|
transaction::Transaction,
|
|
|
|
},
|
|
|
|
std::{
|
|
|
|
collections::{HashMap, HashSet},
|
2022-01-03 13:07:47 -08:00
|
|
|
iter::repeat,
|
2021-12-03 09:00:31 -08:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
2022-07-05 07:29:44 -07:00
|
|
|
Arc, RwLock,
|
2021-12-03 09:00:31 -08:00
|
|
|
},
|
|
|
|
thread::{self, sleep, Builder, JoinHandle},
|
|
|
|
time::{Duration, Instant},
|
2020-03-15 20:31:05 -07:00
|
|
|
},
|
|
|
|
};
|
2019-01-31 15:51:29 -08:00
|
|
|
|
2020-03-09 22:03:09 -07:00
|
|
|
// Map from a vote account to the authorized voter for an epoch
|
2021-03-24 23:41:52 -07:00
|
|
|
pub type ThresholdConfirmedSlots = Vec<(Slot, Hash)>;
|
2022-01-11 02:44:46 -08:00
|
|
|
pub type VerifiedLabelVotePacketsSender = Sender<Vec<VerifiedVoteMetadata>>;
|
|
|
|
pub type VerifiedLabelVotePacketsReceiver = Receiver<Vec<VerifiedVoteMetadata>>;
|
|
|
|
pub type VerifiedVoteTransactionsSender = Sender<Vec<Transaction>>;
|
|
|
|
pub type VerifiedVoteTransactionsReceiver = Receiver<Vec<Transaction>>;
|
|
|
|
pub type VerifiedVoteSender = Sender<(Pubkey, Vec<Slot>)>;
|
|
|
|
pub type VerifiedVoteReceiver = Receiver<(Pubkey, Vec<Slot>)>;
|
|
|
|
pub type GossipVerifiedVoteHashSender = Sender<(Pubkey, Slot, Hash)>;
|
|
|
|
pub type GossipVerifiedVoteHashReceiver = Receiver<(Pubkey, Slot, Hash)>;
|
|
|
|
pub type GossipDuplicateConfirmedSlotsSender = Sender<ThresholdConfirmedSlots>;
|
|
|
|
pub type GossipDuplicateConfirmedSlotsReceiver = Receiver<ThresholdConfirmedSlots>;
|
2021-03-24 23:41:52 -07:00
|
|
|
|
|
|
|
const THRESHOLDS_TO_CHECK: [f64; 2] = [DUPLICATE_THRESHOLD, VOTE_THRESHOLD_SIZE];
|
2021-11-18 15:20:41 -08:00
|
|
|
const BANK_SEND_VOTES_LOOP_SLEEP_MS: u128 = 10;
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-03-26 17:55:17 -07:00
|
|
|
#[derive(Default)]
|
2020-03-09 22:03:09 -07:00
|
|
|
pub struct SlotVoteTracker {
|
2020-07-20 17:29:07 -07:00
|
|
|
// Maps pubkeys that have voted for this slot
|
|
|
|
// to whether or not we've seen the vote on gossip.
|
|
|
|
// True if seen on gossip, false if only seen in replay.
|
2021-02-07 18:07:00 -08:00
|
|
|
voted: HashMap<Pubkey, bool>,
|
2020-07-28 02:33:27 -07:00
|
|
|
optimistic_votes_tracker: HashMap<Hash, VoteStakeTracker>,
|
2021-04-10 17:34:45 -07:00
|
|
|
voted_slot_updates: Option<Vec<Pubkey>>,
|
2020-07-20 17:29:07 -07:00
|
|
|
gossip_only_stake: u64,
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SlotVoteTracker {
|
2022-01-03 13:07:47 -08:00
|
|
|
pub(crate) fn get_voted_slot_updates(&mut self) -> Option<Vec<Pubkey>> {
|
2021-04-10 17:34:45 -07:00
|
|
|
self.voted_slot_updates.take()
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
2020-07-28 02:33:27 -07:00
|
|
|
|
2022-01-03 13:07:47 -08:00
|
|
|
fn get_or_insert_optimistic_votes_tracker(&mut self, hash: Hash) -> &mut VoteStakeTracker {
|
2020-07-28 02:33:27 -07:00
|
|
|
self.optimistic_votes_tracker.entry(hash).or_default()
|
|
|
|
}
|
2022-01-03 13:07:47 -08:00
|
|
|
pub(crate) fn optimistic_votes_tracker(&self, hash: &Hash) -> Option<&VoteStakeTracker> {
|
2020-07-28 02:33:27 -07:00
|
|
|
self.optimistic_votes_tracker.get(hash)
|
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
|
2020-03-26 17:55:17 -07:00
|
|
|
#[derive(Default)]
|
2020-03-09 22:03:09 -07:00
|
|
|
pub struct VoteTracker {
|
|
|
|
// Map from a slot to a set of validators who have voted for that slot
|
2020-07-09 22:52:54 -07:00
|
|
|
slot_vote_trackers: RwLock<HashMap<Slot, Arc<RwLock<SlotVoteTracker>>>>,
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl VoteTracker {
|
2022-01-03 13:07:47 -08:00
|
|
|
fn get_or_insert_slot_tracker(&self, slot: Slot) -> Arc<RwLock<SlotVoteTracker>> {
|
|
|
|
if let Some(slot_vote_tracker) = self.slot_vote_trackers.read().unwrap().get(&slot) {
|
|
|
|
return slot_vote_tracker.clone();
|
2020-07-28 02:33:27 -07:00
|
|
|
}
|
2022-01-03 13:07:47 -08:00
|
|
|
let mut slot_vote_trackers = self.slot_vote_trackers.write().unwrap();
|
|
|
|
slot_vote_trackers.entry(slot).or_default().clone()
|
2020-07-28 02:33:27 -07:00
|
|
|
}
|
|
|
|
|
2022-01-03 13:07:47 -08:00
|
|
|
pub(crate) fn get_slot_vote_tracker(&self, slot: Slot) -> Option<Arc<RwLock<SlotVoteTracker>>> {
|
2020-03-09 22:03:09 -07:00
|
|
|
self.slot_vote_trackers.read().unwrap().get(&slot).cloned()
|
|
|
|
}
|
|
|
|
|
2020-03-26 17:55:17 -07:00
|
|
|
#[cfg(test)]
|
2022-01-03 13:07:47 -08:00
|
|
|
pub(crate) fn insert_vote(&self, slot: Slot, pubkey: Pubkey) {
|
2020-03-26 17:55:17 -07:00
|
|
|
let mut w_slot_vote_trackers = self.slot_vote_trackers.write().unwrap();
|
|
|
|
|
|
|
|
let slot_vote_tracker = w_slot_vote_trackers.entry(slot).or_default();
|
|
|
|
|
|
|
|
let mut w_slot_vote_tracker = slot_vote_tracker.write().unwrap();
|
|
|
|
|
2021-02-07 18:07:00 -08:00
|
|
|
w_slot_vote_tracker.voted.insert(pubkey, true);
|
2021-04-10 17:34:45 -07:00
|
|
|
if let Some(ref mut voted_slot_updates) = w_slot_vote_tracker.voted_slot_updates {
|
|
|
|
voted_slot_updates.push(pubkey)
|
2020-03-09 22:03:09 -07:00
|
|
|
} else {
|
2021-04-10 17:34:45 -07:00
|
|
|
w_slot_vote_tracker.voted_slot_updates = Some(vec![pubkey]);
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-23 18:19:12 -07:00
|
|
|
fn purge_stale_state(&self, root_bank: &Bank) {
|
2020-03-26 17:55:17 -07:00
|
|
|
// Purge any outdated slot data
|
|
|
|
let new_root = root_bank.slot();
|
|
|
|
self.slot_vote_trackers
|
2020-03-09 22:03:09 -07:00
|
|
|
.write()
|
|
|
|
.unwrap()
|
2020-03-26 17:55:17 -07:00
|
|
|
.retain(|slot, _| *slot >= new_root);
|
|
|
|
}
|
|
|
|
|
2020-10-23 18:19:12 -07:00
|
|
|
fn progress_with_new_root_bank(&self, root_bank: &Bank) {
|
|
|
|
self.purge_stale_state(root_bank);
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-18 15:20:41 -08:00
|
|
|
struct BankVoteSenderState {
|
|
|
|
bank: Arc<Bank>,
|
|
|
|
previously_sent_to_bank_votes: HashSet<Signature>,
|
|
|
|
bank_send_votes_stats: BankSendVotesStats,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BankVoteSenderState {
|
|
|
|
fn new(bank: Arc<Bank>) -> Self {
|
|
|
|
Self {
|
|
|
|
bank,
|
|
|
|
previously_sent_to_bank_votes: HashSet::new(),
|
|
|
|
bank_send_votes_stats: BankSendVotesStats::default(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn report_metrics(&self) {
|
|
|
|
self.bank_send_votes_stats.report_metrics(self.bank.slot());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct BankSendVotesStats {
|
|
|
|
num_votes_sent: usize,
|
|
|
|
num_batches_sent: usize,
|
|
|
|
total_elapsed: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BankSendVotesStats {
|
|
|
|
fn report_metrics(&self, slot: Slot) {
|
|
|
|
datapoint_info!(
|
|
|
|
"cluster_info_vote_listener-bank-send-vote-stats",
|
|
|
|
("slot", slot, i64),
|
|
|
|
("num_votes_sent", self.num_votes_sent, i64),
|
|
|
|
("total_elapsed", self.total_elapsed, i64),
|
|
|
|
("num_batches_sent", self.num_batches_sent, i64),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-27 06:53:34 -07:00
|
|
|
#[derive(Default)]
|
|
|
|
struct VoteProcessingTiming {
|
|
|
|
gossip_txn_processing_time_us: u64,
|
|
|
|
gossip_slot_confirming_time_us: u64,
|
|
|
|
last_report: AtomicInterval,
|
|
|
|
}
|
|
|
|
|
|
|
|
const VOTE_PROCESSING_REPORT_INTERVAL_MS: u64 = 1_000;
|
|
|
|
|
|
|
|
impl VoteProcessingTiming {
|
|
|
|
fn reset(&mut self) {
|
|
|
|
self.gossip_slot_confirming_time_us = 0;
|
|
|
|
self.gossip_slot_confirming_time_us = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn update(&mut self, vote_txn_processing_time_us: u64, vote_slot_confirming_time_us: u64) {
|
|
|
|
self.gossip_txn_processing_time_us += vote_txn_processing_time_us;
|
|
|
|
self.gossip_slot_confirming_time_us += vote_slot_confirming_time_us;
|
|
|
|
|
|
|
|
if self
|
|
|
|
.last_report
|
|
|
|
.should_update(VOTE_PROCESSING_REPORT_INTERVAL_MS)
|
|
|
|
{
|
|
|
|
datapoint_info!(
|
|
|
|
"vote-processing-timing",
|
|
|
|
(
|
|
|
|
"vote_txn_processing_us",
|
|
|
|
self.gossip_txn_processing_time_us as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"slot_confirming_time_us",
|
|
|
|
self.gossip_slot_confirming_time_us as i64,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
);
|
|
|
|
self.reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-31 15:51:29 -08:00
|
|
|
pub struct ClusterInfoVoteListener {
|
|
|
|
thread_hdls: Vec<JoinHandle<()>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ClusterInfoVoteListener {
|
2020-07-28 02:33:27 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2019-01-31 15:51:29 -08:00
|
|
|
pub fn new(
|
2021-12-30 07:03:14 -08:00
|
|
|
exit: Arc<AtomicBool>,
|
2020-04-21 12:54:45 -07:00
|
|
|
cluster_info: Arc<ClusterInfo>,
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_packets_sender: BankingPacketSender,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: Arc<RwLock<PohRecorder>>,
|
2020-03-09 22:03:09 -07:00
|
|
|
vote_tracker: Arc<VoteTracker>,
|
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2020-05-17 14:01:08 -07:00
|
|
|
subscriptions: Arc<RpcSubscriptions>,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_sender: VerifiedVoteSender,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender: GossipVerifiedVoteHashSender,
|
2020-08-07 11:21:35 -07:00
|
|
|
replay_votes_receiver: ReplayVoteReceiver,
|
2020-07-28 02:33:27 -07:00
|
|
|
blockstore: Arc<Blockstore>,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender: Option<BankNotificationSender>,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender: GossipDuplicateConfirmedSlotsSender,
|
2019-01-31 15:51:29 -08:00
|
|
|
) -> Self {
|
2020-07-09 22:52:54 -07:00
|
|
|
let (verified_vote_label_packets_sender, verified_vote_label_packets_receiver) =
|
|
|
|
unbounded();
|
2020-03-15 20:31:05 -07:00
|
|
|
let (verified_vote_transactions_sender, verified_vote_transactions_receiver) = unbounded();
|
2021-12-30 07:03:14 -08:00
|
|
|
let listen_thread = {
|
|
|
|
let exit = exit.clone();
|
|
|
|
let bank_forks = bank_forks.clone();
|
|
|
|
Builder::new()
|
|
|
|
.name("solana-cluster_info_vote_listener".to_string())
|
|
|
|
.spawn(move || {
|
|
|
|
let _ = Self::recv_loop(
|
|
|
|
exit,
|
|
|
|
&cluster_info,
|
|
|
|
&bank_forks,
|
|
|
|
verified_vote_label_packets_sender,
|
|
|
|
verified_vote_transactions_sender,
|
|
|
|
);
|
|
|
|
})
|
|
|
|
.unwrap()
|
|
|
|
};
|
2020-03-15 20:31:05 -07:00
|
|
|
let exit_ = exit.clone();
|
|
|
|
let bank_send_thread = Builder::new()
|
|
|
|
.name("solana-cluster_info_bank_send".to_string())
|
|
|
|
.spawn(move || {
|
|
|
|
let _ = Self::bank_send_loop(
|
|
|
|
exit_,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_label_packets_receiver,
|
2019-04-09 22:06:32 -07:00
|
|
|
poh_recorder,
|
2020-07-09 22:52:54 -07:00
|
|
|
&verified_packets_sender,
|
2019-04-09 22:06:32 -07:00
|
|
|
);
|
2019-01-31 15:51:29 -08:00
|
|
|
})
|
|
|
|
.unwrap();
|
2020-03-09 22:03:09 -07:00
|
|
|
|
|
|
|
let send_thread = Builder::new()
|
|
|
|
.name("solana-cluster_info_process_votes".to_string())
|
|
|
|
.spawn(move || {
|
2020-03-15 20:31:05 -07:00
|
|
|
let _ = Self::process_votes_loop(
|
2021-12-30 07:03:14 -08:00
|
|
|
exit,
|
2020-03-15 20:31:05 -07:00
|
|
|
verified_vote_transactions_receiver,
|
|
|
|
vote_tracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
bank_forks,
|
2020-05-17 14:01:08 -07:00
|
|
|
subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_sender,
|
2020-07-20 17:29:07 -07:00
|
|
|
replay_votes_receiver,
|
2020-07-28 02:33:27 -07:00
|
|
|
blockstore,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender,
|
2020-03-15 20:31:05 -07:00
|
|
|
);
|
2020-03-09 22:03:09 -07:00
|
|
|
})
|
|
|
|
.unwrap();
|
|
|
|
|
2019-01-31 15:51:29 -08:00
|
|
|
Self {
|
2020-03-15 20:31:05 -07:00
|
|
|
thread_hdls: vec![listen_thread, send_thread, bank_send_thread],
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-30 07:03:14 -08:00
|
|
|
pub(crate) fn join(self) -> thread::Result<()> {
|
|
|
|
self.thread_hdls.into_iter().try_for_each(JoinHandle::join)
|
2019-01-31 15:51:29 -08:00
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2019-01-31 15:51:29 -08:00
|
|
|
fn recv_loop(
|
2019-03-04 19:53:50 -08:00
|
|
|
exit: Arc<AtomicBool>,
|
2020-04-21 12:54:45 -07:00
|
|
|
cluster_info: &ClusterInfo,
|
2021-12-30 07:03:14 -08:00
|
|
|
bank_forks: &RwLock<BankForks>,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_label_packets_sender: VerifiedLabelVotePacketsSender,
|
2020-03-15 20:31:05 -07:00
|
|
|
verified_vote_transactions_sender: VerifiedVoteTransactionsSender,
|
2019-01-31 15:51:29 -08:00
|
|
|
) -> Result<()> {
|
2021-05-06 07:04:17 -07:00
|
|
|
let mut cursor = Cursor::default();
|
|
|
|
while !exit.load(Ordering::Relaxed) {
|
2021-11-18 15:20:41 -08:00
|
|
|
let votes = cluster_info.get_votes(&mut cursor);
|
2020-03-15 20:31:05 -07:00
|
|
|
inc_new_counter_debug!("cluster_info_vote_listener-recv_count", votes.len());
|
2020-04-23 17:04:09 -07:00
|
|
|
if !votes.is_empty() {
|
2021-12-30 07:03:14 -08:00
|
|
|
let (vote_txs, packets) = Self::verify_votes(votes, bank_forks);
|
2020-03-15 20:31:05 -07:00
|
|
|
verified_vote_transactions_sender.send(vote_txs)?;
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_label_packets_sender.send(packets)?;
|
2020-03-15 20:31:05 -07:00
|
|
|
}
|
|
|
|
sleep(Duration::from_millis(GOSSIP_SLEEP_MILLIS));
|
|
|
|
}
|
2021-05-06 07:04:17 -07:00
|
|
|
Ok(())
|
2020-03-15 20:31:05 -07:00
|
|
|
}
|
|
|
|
|
2021-03-03 11:07:16 -08:00
|
|
|
#[allow(clippy::type_complexity)]
|
2021-12-30 07:03:14 -08:00
|
|
|
fn verify_votes(
|
|
|
|
votes: Vec<Transaction>,
|
|
|
|
bank_forks: &RwLock<BankForks>,
|
|
|
|
) -> (Vec<Transaction>, Vec<VerifiedVoteMetadata>) {
|
2021-12-11 06:44:15 -08:00
|
|
|
let mut packet_batches = packet::to_packet_batches(&votes, 1);
|
2021-10-07 02:38:23 -07:00
|
|
|
|
|
|
|
// Votes should already be filtered by this point.
|
2022-01-24 05:35:47 -08:00
|
|
|
sigverify::ed25519_verify_cpu(
|
|
|
|
&mut packet_batches,
|
|
|
|
/*reject_non_vote=*/ false,
|
|
|
|
votes.len(),
|
|
|
|
);
|
2021-12-30 07:03:14 -08:00
|
|
|
let root_bank = bank_forks.read().unwrap().root_bank();
|
|
|
|
let epoch_schedule = root_bank.epoch_schedule();
|
|
|
|
votes
|
|
|
|
.into_iter()
|
|
|
|
.zip(packet_batches)
|
|
|
|
.filter(|(_, packet_batch)| {
|
2021-12-11 06:44:15 -08:00
|
|
|
// to_packet_batches() above splits into 1 packet long batches
|
2022-05-23 13:30:15 -07:00
|
|
|
assert_eq!(packet_batch.len(), 1);
|
|
|
|
!packet_batch[0].meta.discard()
|
2021-12-30 07:03:14 -08:00
|
|
|
})
|
|
|
|
.filter_map(|(tx, packet_batch)| {
|
2022-05-19 18:28:46 -07:00
|
|
|
let (vote_account_key, vote, ..) = vote_parser::parse_vote_transaction(&tx)?;
|
2021-12-30 07:03:14 -08:00
|
|
|
let slot = vote.last_voted_slot()?;
|
|
|
|
let epoch = epoch_schedule.get_epoch(slot);
|
|
|
|
let authorized_voter = root_bank
|
|
|
|
.epoch_stakes(epoch)?
|
|
|
|
.epoch_authorized_voters()
|
|
|
|
.get(&vote_account_key)?;
|
|
|
|
let mut keys = tx.message.account_keys.iter().enumerate();
|
|
|
|
if !keys.any(|(i, key)| tx.message.is_signer(i) && key == authorized_voter) {
|
|
|
|
return None;
|
2021-03-08 19:31:00 -08:00
|
|
|
}
|
2021-12-30 07:03:14 -08:00
|
|
|
let verified_vote_metadata = VerifiedVoteMetadata {
|
|
|
|
vote_account_key,
|
|
|
|
vote,
|
|
|
|
packet_batch,
|
|
|
|
signature: *tx.signatures.first()?,
|
|
|
|
};
|
|
|
|
Some((tx, verified_vote_metadata))
|
2021-03-08 19:31:00 -08:00
|
|
|
})
|
2021-12-30 07:03:14 -08:00
|
|
|
.unzip()
|
2020-04-23 17:04:09 -07:00
|
|
|
}
|
|
|
|
|
2020-03-15 20:31:05 -07:00
|
|
|
fn bank_send_loop(
|
|
|
|
exit: Arc<AtomicBool>,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_label_packets_receiver: VerifiedLabelVotePacketsReceiver,
|
2022-07-05 07:29:44 -07:00
|
|
|
poh_recorder: Arc<RwLock<PohRecorder>>,
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_packets_sender: &BankingPacketSender,
|
2020-03-15 20:31:05 -07:00
|
|
|
) -> Result<()> {
|
|
|
|
let mut verified_vote_packets = VerifiedVotePackets::default();
|
|
|
|
let mut time_since_lock = Instant::now();
|
2021-11-18 15:20:41 -08:00
|
|
|
let mut bank_vote_sender_state_option: Option<BankVoteSenderState> = None;
|
|
|
|
|
2020-03-15 20:31:05 -07:00
|
|
|
loop {
|
|
|
|
if exit.load(Ordering::Relaxed) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2021-06-11 09:29:05 -07:00
|
|
|
let would_be_leader = poh_recorder
|
2022-07-05 07:29:44 -07:00
|
|
|
.read()
|
2021-06-11 09:29:05 -07:00
|
|
|
.unwrap()
|
2021-11-18 15:20:41 -08:00
|
|
|
.would_be_leader(3 * slot_hashes::MAX_ENTRIES as u64 * DEFAULT_TICKS_PER_SLOT);
|
|
|
|
|
2021-01-25 01:01:47 -08:00
|
|
|
if let Err(e) = verified_vote_packets.receive_and_process_vote_packets(
|
2020-07-09 22:52:54 -07:00
|
|
|
&verified_vote_label_packets_receiver,
|
2021-06-11 09:29:05 -07:00
|
|
|
would_be_leader,
|
2020-07-09 22:52:54 -07:00
|
|
|
) {
|
2020-03-15 20:31:05 -07:00
|
|
|
match e {
|
2022-01-11 02:44:46 -08:00
|
|
|
Error::RecvTimeout(RecvTimeoutError::Disconnected)
|
|
|
|
| Error::RecvTimeout(RecvTimeoutError::Timeout) => (),
|
2020-03-15 20:31:05 -07:00
|
|
|
_ => {
|
|
|
|
error!("thread {:?} error {:?}", thread::current().name(), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-18 15:20:41 -08:00
|
|
|
if time_since_lock.elapsed().as_millis() > BANK_SEND_VOTES_LOOP_SLEEP_MS as u128 {
|
|
|
|
// Always set this to avoid taking the poh lock too often
|
|
|
|
time_since_lock = Instant::now();
|
|
|
|
// We will take this lock at most once every `BANK_SEND_VOTES_LOOP_SLEEP_MS`
|
2022-07-05 07:29:44 -07:00
|
|
|
let current_working_bank = poh_recorder.read().unwrap().bank();
|
2022-04-29 01:32:46 -07:00
|
|
|
if let Some(current_working_bank) = current_working_bank {
|
2021-11-18 15:20:41 -08:00
|
|
|
Self::check_for_leader_bank_and_send_votes(
|
|
|
|
&mut bank_vote_sender_state_option,
|
|
|
|
current_working_bank,
|
|
|
|
verified_packets_sender,
|
|
|
|
&verified_vote_packets,
|
|
|
|
)?;
|
2019-04-26 17:27:31 -07:00
|
|
|
}
|
2019-04-09 22:06:32 -07:00
|
|
|
}
|
2019-01-31 15:51:29 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-18 15:20:41 -08:00
|
|
|
fn check_for_leader_bank_and_send_votes(
|
|
|
|
bank_vote_sender_state_option: &mut Option<BankVoteSenderState>,
|
|
|
|
current_working_bank: Arc<Bank>,
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_packets_sender: &BankingPacketSender,
|
2021-11-18 15:20:41 -08:00
|
|
|
verified_vote_packets: &VerifiedVotePackets,
|
|
|
|
) -> Result<()> {
|
|
|
|
// We will take this lock at most once every `BANK_SEND_VOTES_LOOP_SLEEP_MS`
|
|
|
|
if let Some(bank_vote_sender_state) = bank_vote_sender_state_option {
|
|
|
|
if bank_vote_sender_state.bank.slot() != current_working_bank.slot() {
|
|
|
|
bank_vote_sender_state.report_metrics();
|
|
|
|
*bank_vote_sender_state_option =
|
|
|
|
Some(BankVoteSenderState::new(current_working_bank));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*bank_vote_sender_state_option = Some(BankVoteSenderState::new(current_working_bank));
|
|
|
|
}
|
|
|
|
|
|
|
|
let bank_vote_sender_state = bank_vote_sender_state_option.as_mut().unwrap();
|
|
|
|
let BankVoteSenderState {
|
|
|
|
ref bank,
|
|
|
|
ref mut bank_send_votes_stats,
|
|
|
|
ref mut previously_sent_to_bank_votes,
|
|
|
|
} = bank_vote_sender_state;
|
|
|
|
|
|
|
|
// This logic may run multiple times for the same leader bank,
|
|
|
|
// we just have to ensure that the same votes are not sent
|
|
|
|
// to the bank multiple times, which is guaranteed by
|
|
|
|
// `previously_sent_to_bank_votes`
|
|
|
|
let gossip_votes_iterator = ValidatorGossipVotesIterator::new(
|
|
|
|
bank.clone(),
|
|
|
|
verified_vote_packets,
|
|
|
|
previously_sent_to_bank_votes,
|
|
|
|
);
|
|
|
|
|
|
|
|
let mut filter_gossip_votes_timing = Measure::start("filter_gossip_votes");
|
|
|
|
|
|
|
|
// Send entire batch at a time so that there is no partial processing of
|
|
|
|
// a single validator's votes by two different banks. This might happen
|
2022-05-09 10:42:58 -07:00
|
|
|
// if we sent each vote individually, for instance if we created two different
|
2021-11-18 15:20:41 -08:00
|
|
|
// leader banks from the same common parent, one leader bank may process
|
|
|
|
// only the later votes and ignore the earlier votes.
|
|
|
|
for single_validator_votes in gossip_votes_iterator {
|
|
|
|
bank_send_votes_stats.num_votes_sent += single_validator_votes.len();
|
|
|
|
bank_send_votes_stats.num_batches_sent += 1;
|
2022-05-24 14:01:41 -07:00
|
|
|
verified_packets_sender.send((single_validator_votes, None))?;
|
2021-11-18 15:20:41 -08:00
|
|
|
}
|
|
|
|
filter_gossip_votes_timing.stop();
|
|
|
|
bank_send_votes_stats.total_elapsed += filter_gossip_votes_timing.as_us();
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-03-24 23:41:52 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-03-09 22:03:09 -07:00
|
|
|
fn process_votes_loop(
|
|
|
|
exit: Arc<AtomicBool>,
|
2020-07-29 23:17:40 -07:00
|
|
|
gossip_vote_txs_receiver: VerifiedVoteTransactionsReceiver,
|
2020-03-09 22:03:09 -07:00
|
|
|
vote_tracker: Arc<VoteTracker>,
|
2020-07-28 02:33:27 -07:00
|
|
|
bank_forks: Arc<RwLock<BankForks>>,
|
2020-05-17 14:01:08 -07:00
|
|
|
subscriptions: Arc<RpcSubscriptions>,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender: GossipVerifiedVoteHashSender,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_sender: VerifiedVoteSender,
|
2020-08-07 11:21:35 -07:00
|
|
|
replay_votes_receiver: ReplayVoteReceiver,
|
2020-07-28 02:33:27 -07:00
|
|
|
blockstore: Arc<Blockstore>,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender: Option<BankNotificationSender>,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender: GossipDuplicateConfirmedSlotsSender,
|
2020-03-09 22:03:09 -07:00
|
|
|
) -> Result<()> {
|
2020-10-23 18:19:12 -07:00
|
|
|
let mut confirmation_verifier =
|
2020-07-28 02:33:27 -07:00
|
|
|
OptimisticConfirmationVerifier::new(bank_forks.read().unwrap().root());
|
|
|
|
let mut last_process_root = Instant::now();
|
2021-03-24 23:41:52 -07:00
|
|
|
let cluster_confirmed_slot_sender = Some(cluster_confirmed_slot_sender);
|
2022-06-27 06:53:34 -07:00
|
|
|
let mut vote_processing_time = Some(VoteProcessingTiming::default());
|
2020-03-09 22:03:09 -07:00
|
|
|
loop {
|
|
|
|
if exit.load(Ordering::Relaxed) {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2021-12-30 07:03:14 -08:00
|
|
|
let root_bank = bank_forks.read().unwrap().root_bank();
|
2020-10-23 18:19:12 -07:00
|
|
|
if last_process_root.elapsed().as_millis() > DEFAULT_MS_PER_SLOT as u128 {
|
|
|
|
let unrooted_optimistic_slots = confirmation_verifier
|
|
|
|
.verify_for_unrooted_optimistic_slots(&root_bank, &blockstore);
|
2020-07-28 02:33:27 -07:00
|
|
|
// SlotVoteTracker's for all `slots` in `unrooted_optimistic_slots`
|
|
|
|
// should still be available because we haven't purged in
|
2020-10-23 18:19:12 -07:00
|
|
|
// `progress_with_new_root_bank()` yet, which is called below
|
2020-07-28 02:33:27 -07:00
|
|
|
OptimisticConfirmationVerifier::log_unrooted_optimistic_slots(
|
|
|
|
&root_bank,
|
|
|
|
&vote_tracker,
|
|
|
|
&unrooted_optimistic_slots,
|
|
|
|
);
|
2020-10-23 18:19:12 -07:00
|
|
|
vote_tracker.progress_with_new_root_bank(&root_bank);
|
2020-07-28 02:33:27 -07:00
|
|
|
last_process_root = Instant::now();
|
|
|
|
}
|
2020-10-23 18:19:12 -07:00
|
|
|
let confirmed_slots = Self::listen_and_confirm_votes(
|
2020-07-29 23:17:40 -07:00
|
|
|
&gossip_vote_txs_receiver,
|
2020-05-17 14:01:08 -07:00
|
|
|
&vote_tracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
&root_bank,
|
2020-06-08 17:38:14 -07:00
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-09 22:52:54 -07:00
|
|
|
&verified_vote_sender,
|
2020-07-20 17:29:07 -07:00
|
|
|
&replay_votes_receiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
&bank_notification_sender,
|
2021-03-24 23:41:52 -07:00
|
|
|
&cluster_confirmed_slot_sender,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut vote_processing_time,
|
2020-07-28 02:33:27 -07:00
|
|
|
);
|
2020-10-23 18:19:12 -07:00
|
|
|
match confirmed_slots {
|
|
|
|
Ok(confirmed_slots) => {
|
2021-03-24 23:41:52 -07:00
|
|
|
confirmation_verifier
|
2022-05-24 12:03:28 -07:00
|
|
|
.add_new_optimistic_confirmed_slots(confirmed_slots.clone(), &blockstore);
|
2020-10-23 18:19:12 -07:00
|
|
|
}
|
|
|
|
Err(e) => match e {
|
2022-01-11 02:44:46 -08:00
|
|
|
Error::RecvTimeout(RecvTimeoutError::Disconnected) => {
|
2021-11-18 15:20:41 -08:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Error::ReadyTimeout => (),
|
2020-03-09 22:03:09 -07:00
|
|
|
_ => {
|
|
|
|
error!("thread {:?} error {:?}", thread::current().name(), e);
|
|
|
|
}
|
2020-10-23 18:19:12 -07:00
|
|
|
},
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-17 14:01:08 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
pub fn get_and_process_votes_for_tests(
|
2020-07-29 23:17:40 -07:00
|
|
|
gossip_vote_txs_receiver: &VerifiedVoteTransactionsReceiver,
|
2020-06-08 17:38:14 -07:00
|
|
|
vote_tracker: &VoteTracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
root_bank: &Bank,
|
2020-06-08 17:38:14 -07:00
|
|
|
subscriptions: &RpcSubscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender: &GossipVerifiedVoteHashSender,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_sender: &VerifiedVoteSender,
|
2020-08-07 11:21:35 -07:00
|
|
|
replay_votes_receiver: &ReplayVoteReceiver,
|
2021-03-24 23:41:52 -07:00
|
|
|
) -> Result<ThresholdConfirmedSlots> {
|
2020-10-23 18:19:12 -07:00
|
|
|
Self::listen_and_confirm_votes(
|
2020-07-29 23:17:40 -07:00
|
|
|
gossip_vote_txs_receiver,
|
2020-05-22 14:53:47 -07:00
|
|
|
vote_tracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
root_bank,
|
2020-05-22 14:53:47 -07:00
|
|
|
subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_sender,
|
2020-07-20 17:29:07 -07:00
|
|
|
replay_votes_receiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-05-22 14:53:47 -07:00
|
|
|
)
|
2020-05-17 14:01:08 -07:00
|
|
|
}
|
|
|
|
|
2022-06-27 06:53:34 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-10-23 18:19:12 -07:00
|
|
|
fn listen_and_confirm_votes(
|
2020-07-29 23:17:40 -07:00
|
|
|
gossip_vote_txs_receiver: &VerifiedVoteTransactionsReceiver,
|
2020-06-08 17:38:14 -07:00
|
|
|
vote_tracker: &VoteTracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
root_bank: &Bank,
|
2020-06-08 17:38:14 -07:00
|
|
|
subscriptions: &RpcSubscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender: &GossipVerifiedVoteHashSender,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_sender: &VerifiedVoteSender,
|
2020-08-07 11:21:35 -07:00
|
|
|
replay_votes_receiver: &ReplayVoteReceiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender: &Option<BankNotificationSender>,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender: &Option<GossipDuplicateConfirmedSlotsSender>,
|
2022-06-27 06:53:34 -07:00
|
|
|
vote_processing_time: &mut Option<VoteProcessingTiming>,
|
2021-03-24 23:41:52 -07:00
|
|
|
) -> Result<ThresholdConfirmedSlots> {
|
2020-07-20 17:29:07 -07:00
|
|
|
let mut sel = Select::new();
|
2020-07-29 23:17:40 -07:00
|
|
|
sel.recv(gossip_vote_txs_receiver);
|
2020-07-20 17:29:07 -07:00
|
|
|
sel.recv(replay_votes_receiver);
|
2022-02-04 11:01:59 -08:00
|
|
|
let mut remaining_wait_time = Duration::from_millis(200);
|
|
|
|
while remaining_wait_time > Duration::ZERO {
|
2020-07-20 17:29:07 -07:00
|
|
|
let start = Instant::now();
|
|
|
|
// Wait for one of the receivers to be ready. `ready_timeout`
|
|
|
|
// will return if channels either have something, or are
|
|
|
|
// disconnected. `ready_timeout` can wake up spuriously,
|
|
|
|
// hence the loop
|
2022-02-04 11:01:59 -08:00
|
|
|
let _ = sel.ready_timeout(remaining_wait_time)?;
|
2020-07-28 02:33:27 -07:00
|
|
|
|
|
|
|
// Should not early return from this point onwards until `process_votes()`
|
|
|
|
// returns below to avoid missing any potential `optimistic_confirmed_slots`
|
2020-07-29 23:17:40 -07:00
|
|
|
let gossip_vote_txs: Vec<_> = gossip_vote_txs_receiver.try_iter().flatten().collect();
|
2020-07-20 17:29:07 -07:00
|
|
|
let replay_votes: Vec<_> = replay_votes_receiver.try_iter().collect();
|
2020-07-29 23:17:40 -07:00
|
|
|
if !gossip_vote_txs.is_empty() || !replay_votes.is_empty() {
|
2020-10-23 18:19:12 -07:00
|
|
|
return Ok(Self::filter_and_confirm_with_new_votes(
|
2020-07-20 17:29:07 -07:00
|
|
|
vote_tracker,
|
2020-07-29 23:17:40 -07:00
|
|
|
gossip_vote_txs,
|
|
|
|
replay_votes,
|
2020-07-28 02:33:27 -07:00
|
|
|
root_bank,
|
2020-07-20 17:29:07 -07:00
|
|
|
subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender,
|
2020-07-20 17:29:07 -07:00
|
|
|
verified_vote_sender,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender,
|
2022-06-27 06:53:34 -07:00
|
|
|
vote_processing_time,
|
2020-07-28 02:33:27 -07:00
|
|
|
));
|
2020-07-20 17:29:07 -07:00
|
|
|
}
|
2022-02-04 11:01:59 -08:00
|
|
|
remaining_wait_time = remaining_wait_time.saturating_sub(start.elapsed());
|
2019-01-31 15:51:29 -08:00
|
|
|
}
|
2020-07-28 02:33:27 -07:00
|
|
|
Ok(vec![])
|
|
|
|
}
|
|
|
|
|
2020-07-29 23:17:40 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-10-23 18:19:12 -07:00
|
|
|
fn track_new_votes_and_notify_confirmations(
|
2021-12-22 06:25:46 -08:00
|
|
|
vote: VoteTransaction,
|
2020-07-29 23:17:40 -07:00
|
|
|
vote_pubkey: &Pubkey,
|
2022-05-19 18:28:46 -07:00
|
|
|
vote_transaction_signature: Signature,
|
2020-05-17 14:01:08 -07:00
|
|
|
vote_tracker: &VoteTracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
root_bank: &Bank,
|
2020-06-08 17:38:14 -07:00
|
|
|
subscriptions: &RpcSubscriptions,
|
2020-07-09 22:52:54 -07:00
|
|
|
verified_vote_sender: &VerifiedVoteSender,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender: &GossipVerifiedVoteHashSender,
|
2021-02-07 18:07:00 -08:00
|
|
|
diff: &mut HashMap<Slot, HashMap<Pubkey, bool>>,
|
2021-03-24 23:41:52 -07:00
|
|
|
new_optimistic_confirmed_slots: &mut ThresholdConfirmedSlots,
|
2020-07-29 23:17:40 -07:00
|
|
|
is_gossip_vote: bool,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender: &Option<BankNotificationSender>,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender: &Option<GossipDuplicateConfirmedSlotsSender>,
|
2020-07-29 23:17:40 -07:00
|
|
|
) {
|
2021-12-07 16:47:26 -08:00
|
|
|
if vote.is_empty() {
|
2020-07-29 23:17:40 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-12-07 16:47:26 -08:00
|
|
|
let (last_vote_slot, last_vote_hash) = vote.last_voted_slot_hash().unwrap();
|
2020-07-29 23:17:40 -07:00
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
let root = root_bank.slot();
|
2020-07-29 23:17:40 -07:00
|
|
|
let mut is_new_vote = false;
|
2021-12-07 16:47:26 -08:00
|
|
|
let vote_slots = vote.slots();
|
2020-10-23 18:19:12 -07:00
|
|
|
// If slot is before the root, ignore it
|
2021-12-07 16:47:26 -08:00
|
|
|
for slot in vote_slots.iter().filter(|slot| **slot > root).rev() {
|
2020-10-23 18:19:12 -07:00
|
|
|
let slot = *slot;
|
|
|
|
|
|
|
|
// if we don't have stake information, ignore it
|
|
|
|
let epoch = root_bank.epoch_schedule().get_epoch(slot);
|
2020-07-29 23:17:40 -07:00
|
|
|
let epoch_stakes = root_bank.epoch_stakes(epoch);
|
2020-10-23 18:19:12 -07:00
|
|
|
if epoch_stakes.is_none() {
|
2020-07-29 23:17:40 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let epoch_stakes = epoch_stakes.unwrap();
|
|
|
|
|
|
|
|
// The last vote slot, which is the greatest slot in the stack
|
|
|
|
// of votes in a vote transaction, qualifies for optimistic confirmation.
|
2022-01-13 16:51:00 -08:00
|
|
|
// We cannot count any other slots in this vote toward optimistic confirmation because:
|
|
|
|
// 1) There may have been a switch between the earlier vote and the last vote
|
|
|
|
// 2) We do not know the hash of the earlier slot
|
2020-10-23 18:19:12 -07:00
|
|
|
if slot == last_vote_slot {
|
2021-08-30 08:54:01 -07:00
|
|
|
let vote_accounts = epoch_stakes.stakes().vote_accounts();
|
2022-06-25 09:41:35 -07:00
|
|
|
let stake = vote_accounts.get_delegated_stake(vote_pubkey);
|
2020-10-23 18:19:12 -07:00
|
|
|
let total_stake = epoch_stakes.total_stake();
|
2020-07-29 23:17:40 -07:00
|
|
|
|
|
|
|
// Fast track processing of the last slot in a vote transactions
|
|
|
|
// so that notifications for optimistic confirmation can be sent
|
|
|
|
// as soon as possible.
|
2021-03-24 23:41:52 -07:00
|
|
|
let (reached_threshold_results, is_new) = Self::track_optimistic_confirmation_vote(
|
2020-07-29 23:17:40 -07:00
|
|
|
vote_tracker,
|
2020-10-23 18:19:12 -07:00
|
|
|
last_vote_slot,
|
|
|
|
last_vote_hash,
|
2021-02-07 18:07:00 -08:00
|
|
|
*vote_pubkey,
|
2020-07-29 23:17:40 -07:00
|
|
|
stake,
|
2020-10-23 18:19:12 -07:00
|
|
|
total_stake,
|
2020-07-29 23:17:40 -07:00
|
|
|
);
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2021-04-10 17:34:45 -07:00
|
|
|
if is_gossip_vote && is_new && stake > 0 {
|
|
|
|
let _ = gossip_verified_vote_hash_sender.send((
|
|
|
|
*vote_pubkey,
|
|
|
|
last_vote_slot,
|
|
|
|
last_vote_hash,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2021-03-24 23:41:52 -07:00
|
|
|
if reached_threshold_results[0] {
|
|
|
|
if let Some(sender) = cluster_confirmed_slot_sender {
|
|
|
|
let _ = sender.send(vec![(last_vote_slot, last_vote_hash)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if reached_threshold_results[1] {
|
2020-10-23 18:19:12 -07:00
|
|
|
new_optimistic_confirmed_slots.push((last_vote_slot, last_vote_hash));
|
2020-07-30 02:52:27 -07:00
|
|
|
// Notify subscribers about new optimistic confirmation
|
2020-09-28 19:43:05 -07:00
|
|
|
if let Some(sender) = bank_notification_sender {
|
|
|
|
sender
|
2020-10-23 18:19:12 -07:00
|
|
|
.send(BankNotification::OptimisticallyConfirmed(last_vote_slot))
|
2020-09-28 19:43:05 -07:00
|
|
|
.unwrap_or_else(|err| {
|
|
|
|
warn!("bank_notification_sender failed: {:?}", err)
|
|
|
|
});
|
|
|
|
}
|
2020-07-29 23:17:40 -07:00
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-07-29 23:17:40 -07:00
|
|
|
if !is_new && !is_gossip_vote {
|
|
|
|
// By now:
|
|
|
|
// 1) The vote must have come from ReplayStage,
|
|
|
|
// 2) We've seen this vote from replay for this hash before
|
2020-10-23 18:19:12 -07:00
|
|
|
// (`track_optimistic_confirmation_vote()` will not set `is_new == true`
|
2020-07-29 23:17:40 -07:00
|
|
|
// for same slot different hash), so short circuit because this vote
|
|
|
|
// has no new information
|
|
|
|
|
|
|
|
// Note gossip votes will always be processed because those should be unique
|
|
|
|
// and we need to update the gossip-only stake in the `VoteTracker`.
|
|
|
|
return;
|
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-07-29 23:17:40 -07:00
|
|
|
is_new_vote = is_new;
|
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-10-23 18:19:12 -07:00
|
|
|
diff.entry(slot)
|
2020-07-29 23:17:40 -07:00
|
|
|
.or_default()
|
2021-02-07 18:07:00 -08:00
|
|
|
.entry(*vote_pubkey)
|
2020-07-29 23:17:40 -07:00
|
|
|
.and_modify(|seen_in_gossip_previously| {
|
|
|
|
*seen_in_gossip_previously = *seen_in_gossip_previously || is_gossip_vote
|
|
|
|
})
|
|
|
|
.or_insert(is_gossip_vote);
|
|
|
|
}
|
|
|
|
|
|
|
|
if is_new_vote {
|
2022-05-19 18:28:46 -07:00
|
|
|
subscriptions.notify_vote(*vote_pubkey, vote, vote_transaction_signature);
|
2021-12-07 16:47:26 -08:00
|
|
|
let _ = verified_vote_sender.send((*vote_pubkey, vote_slots));
|
2020-07-29 23:17:40 -07:00
|
|
|
}
|
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2022-06-27 06:53:34 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-10-23 18:19:12 -07:00
|
|
|
fn filter_and_confirm_with_new_votes(
|
2020-07-29 23:17:40 -07:00
|
|
|
vote_tracker: &VoteTracker,
|
|
|
|
gossip_vote_txs: Vec<Transaction>,
|
2021-12-07 16:47:26 -08:00
|
|
|
replayed_votes: Vec<ParsedVote>,
|
2020-07-29 23:17:40 -07:00
|
|
|
root_bank: &Bank,
|
|
|
|
subscriptions: &RpcSubscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender: &GossipVerifiedVoteHashSender,
|
2020-07-29 23:17:40 -07:00
|
|
|
verified_vote_sender: &VerifiedVoteSender,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender: &Option<BankNotificationSender>,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender: &Option<GossipDuplicateConfirmedSlotsSender>,
|
2022-06-27 06:53:34 -07:00
|
|
|
vote_processing_time: &mut Option<VoteProcessingTiming>,
|
2021-03-24 23:41:52 -07:00
|
|
|
) -> ThresholdConfirmedSlots {
|
2021-02-07 18:07:00 -08:00
|
|
|
let mut diff: HashMap<Slot, HashMap<Pubkey, bool>> = HashMap::new();
|
2020-07-29 23:17:40 -07:00
|
|
|
let mut new_optimistic_confirmed_slots = vec![];
|
|
|
|
|
|
|
|
// Process votes from gossip and ReplayStage
|
2022-06-27 06:53:34 -07:00
|
|
|
let mut gossip_vote_txn_processing_time = Measure::start("gossip_vote_processing_time");
|
2022-01-03 13:07:47 -08:00
|
|
|
let votes = gossip_vote_txs
|
2020-07-29 23:17:40 -07:00
|
|
|
.iter()
|
2022-01-19 18:39:21 -08:00
|
|
|
.filter_map(vote_parser::parse_vote_transaction)
|
2022-01-03 13:07:47 -08:00
|
|
|
.zip(repeat(/*is_gossip:*/ true))
|
|
|
|
.chain(replayed_votes.into_iter().zip(repeat(/*is_gossip:*/ false)));
|
2022-05-19 18:28:46 -07:00
|
|
|
for ((vote_pubkey, vote, _switch_proof, signature), is_gossip) in votes {
|
2020-10-23 18:19:12 -07:00
|
|
|
Self::track_new_votes_and_notify_confirmations(
|
2020-07-29 23:17:40 -07:00
|
|
|
vote,
|
|
|
|
&vote_pubkey,
|
2022-05-19 18:28:46 -07:00
|
|
|
signature,
|
2021-06-18 06:34:46 -07:00
|
|
|
vote_tracker,
|
2020-07-29 23:17:40 -07:00
|
|
|
root_bank,
|
|
|
|
subscriptions,
|
|
|
|
verified_vote_sender,
|
2021-04-10 17:34:45 -07:00
|
|
|
gossip_verified_vote_hash_sender,
|
2020-07-29 23:17:40 -07:00
|
|
|
&mut diff,
|
|
|
|
&mut new_optimistic_confirmed_slots,
|
2020-09-05 21:27:50 -07:00
|
|
|
is_gossip,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_notification_sender,
|
2021-03-24 23:41:52 -07:00
|
|
|
cluster_confirmed_slot_sender,
|
2020-07-29 23:17:40 -07:00
|
|
|
);
|
2020-07-20 17:29:07 -07:00
|
|
|
}
|
2022-06-27 06:53:34 -07:00
|
|
|
gossip_vote_txn_processing_time.stop();
|
|
|
|
let gossip_vote_txn_processing_time_us = gossip_vote_txn_processing_time.as_us();
|
2020-07-20 17:29:07 -07:00
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
// Process all the slots accumulated from replay and gossip.
|
2022-06-27 06:53:34 -07:00
|
|
|
let mut gossip_vote_slot_confirming_time = Measure::start("gossip_vote_slot_confirm_time");
|
2020-07-20 17:29:07 -07:00
|
|
|
for (slot, mut slot_diff) in diff {
|
2020-07-28 02:33:27 -07:00
|
|
|
let slot_tracker = vote_tracker.get_or_insert_slot_tracker(slot);
|
|
|
|
{
|
|
|
|
let r_slot_tracker = slot_tracker.read().unwrap();
|
|
|
|
// Only keep the pubkeys we haven't seen voting for this slot
|
|
|
|
slot_diff.retain(|pubkey, seen_in_gossip_above| {
|
|
|
|
let seen_in_gossip_previously = r_slot_tracker.voted.get(pubkey);
|
|
|
|
let is_new = seen_in_gossip_previously.is_none();
|
|
|
|
// `is_new_from_gossip` means we observed a vote for this slot
|
|
|
|
// for the first time in gossip
|
|
|
|
let is_new_from_gossip = !seen_in_gossip_previously.cloned().unwrap_or(false)
|
|
|
|
&& *seen_in_gossip_above;
|
|
|
|
is_new || is_new_from_gossip
|
|
|
|
});
|
|
|
|
}
|
|
|
|
let mut w_slot_tracker = slot_tracker.write().unwrap();
|
2021-04-10 17:34:45 -07:00
|
|
|
if w_slot_tracker.voted_slot_updates.is_none() {
|
|
|
|
w_slot_tracker.voted_slot_updates = Some(vec![]);
|
2020-07-28 02:33:27 -07:00
|
|
|
}
|
|
|
|
let mut gossip_only_stake = 0;
|
|
|
|
let epoch = root_bank.epoch_schedule().get_epoch(slot);
|
|
|
|
let epoch_stakes = root_bank.epoch_stakes(epoch);
|
|
|
|
|
|
|
|
for (pubkey, seen_in_gossip_above) in slot_diff {
|
2020-07-30 02:52:27 -07:00
|
|
|
if seen_in_gossip_above {
|
2020-07-28 02:33:27 -07:00
|
|
|
// By this point we know if the vote was seen in gossip above,
|
2020-07-30 02:52:27 -07:00
|
|
|
// it was not seen in gossip at any point in the past (if it was seen
|
|
|
|
// in gossip in the past, `is_new` would be false and it would have
|
|
|
|
// been filtered out above), so it's safe to increment the gossip-only
|
|
|
|
// stake
|
|
|
|
Self::sum_stake(&mut gossip_only_stake, epoch_stakes, &pubkey);
|
|
|
|
}
|
2020-07-28 02:33:27 -07:00
|
|
|
|
|
|
|
// From the `slot_diff.retain` earlier, we know because there are
|
|
|
|
// no other writers to `slot_vote_tracker` that
|
|
|
|
// `is_new || is_new_from_gossip`. In both cases we want to record
|
|
|
|
// `is_new_from_gossip` for the `pubkey` entry.
|
2021-02-07 18:07:00 -08:00
|
|
|
w_slot_tracker.voted.insert(pubkey, seen_in_gossip_above);
|
2021-04-10 17:34:45 -07:00
|
|
|
w_slot_tracker
|
|
|
|
.voted_slot_updates
|
|
|
|
.as_mut()
|
|
|
|
.unwrap()
|
|
|
|
.push(pubkey);
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
2020-07-30 02:52:27 -07:00
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
w_slot_tracker.gossip_only_stake += gossip_only_stake
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
2022-06-27 06:53:34 -07:00
|
|
|
gossip_vote_slot_confirming_time.stop();
|
|
|
|
let gossip_vote_slot_confirming_time_us = gossip_vote_slot_confirming_time.as_us();
|
|
|
|
|
|
|
|
match vote_processing_time {
|
|
|
|
Some(ref mut vote_processing_time) => vote_processing_time.update(
|
|
|
|
gossip_vote_txn_processing_time_us,
|
|
|
|
gossip_vote_slot_confirming_time_us,
|
|
|
|
),
|
|
|
|
None => {}
|
|
|
|
}
|
2020-07-28 02:33:27 -07:00
|
|
|
new_optimistic_confirmed_slots
|
|
|
|
}
|
|
|
|
|
2020-07-29 23:17:40 -07:00
|
|
|
// Returns if the slot was optimistically confirmed, and whether
|
|
|
|
// the slot was new
|
2020-10-23 18:19:12 -07:00
|
|
|
fn track_optimistic_confirmation_vote(
|
2020-07-28 02:33:27 -07:00
|
|
|
vote_tracker: &VoteTracker,
|
|
|
|
slot: Slot,
|
|
|
|
hash: Hash,
|
2021-02-07 18:07:00 -08:00
|
|
|
pubkey: Pubkey,
|
2020-07-28 02:33:27 -07:00
|
|
|
stake: u64,
|
|
|
|
total_epoch_stake: u64,
|
2021-03-24 23:41:52 -07:00
|
|
|
) -> (Vec<bool>, bool) {
|
2020-07-28 02:33:27 -07:00
|
|
|
let slot_tracker = vote_tracker.get_or_insert_slot_tracker(slot);
|
|
|
|
// Insert vote and check for optimistic confirmation
|
|
|
|
let mut w_slot_tracker = slot_tracker.write().unwrap();
|
|
|
|
|
|
|
|
w_slot_tracker
|
|
|
|
.get_or_insert_optimistic_votes_tracker(hash)
|
2021-03-24 23:41:52 -07:00
|
|
|
.add_vote_pubkey(pubkey, stake, total_epoch_stake, &THRESHOLDS_TO_CHECK)
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
2020-05-22 14:53:47 -07:00
|
|
|
|
2020-07-30 02:52:27 -07:00
|
|
|
fn sum_stake(sum: &mut u64, epoch_stakes: Option<&EpochStakes>, pubkey: &Pubkey) {
|
2020-05-22 14:53:47 -07:00
|
|
|
if let Some(stakes) = epoch_stakes {
|
2022-06-25 09:41:35 -07:00
|
|
|
*sum += stakes.stakes().vote_accounts().get_delegated_stake(pubkey)
|
2020-05-22 14:53:47 -07:00
|
|
|
}
|
|
|
|
}
|
2019-01-31 15:51:29 -08:00
|
|
|
}
|
2019-05-21 21:45:38 -07:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
solana_perf::packet,
|
|
|
|
solana_rpc::optimistically_confirmed_bank_tracker::OptimisticallyConfirmedBank,
|
|
|
|
solana_runtime::{
|
|
|
|
bank::Bank,
|
|
|
|
commitment::BlockCommitmentCache,
|
|
|
|
genesis_utils::{
|
|
|
|
self, create_genesis_config, GenesisConfigInfo, ValidatorVoteKeypairs,
|
|
|
|
},
|
|
|
|
vote_sender_types::ReplayVoteSender,
|
|
|
|
},
|
|
|
|
solana_sdk::{
|
|
|
|
hash::Hash,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::{Keypair, Signature, Signer},
|
|
|
|
},
|
2022-01-19 18:39:21 -08:00
|
|
|
solana_vote_program::{vote_state::Vote, vote_transaction},
|
2021-12-17 15:03:09 -08:00
|
|
|
std::{
|
|
|
|
collections::BTreeSet,
|
2021-12-30 07:03:14 -08:00
|
|
|
iter::repeat_with,
|
2021-12-17 15:03:09 -08:00
|
|
|
sync::{atomic::AtomicU64, Arc},
|
|
|
|
},
|
2020-07-29 23:17:40 -07:00
|
|
|
};
|
2019-05-21 21:45:38 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_max_vote_tx_fits() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let node_keypair = Keypair::new();
|
|
|
|
let vote_keypair = Keypair::new();
|
2020-05-15 09:35:43 -07:00
|
|
|
let slots: Vec<_> = (0..31).collect();
|
2019-05-31 11:45:17 -07:00
|
|
|
|
2020-03-09 22:03:09 -07:00
|
|
|
let vote_tx = vote_transaction::new_vote_transaction(
|
|
|
|
slots,
|
|
|
|
Hash::default(),
|
|
|
|
Hash::default(),
|
|
|
|
&node_keypair,
|
|
|
|
&vote_keypair,
|
|
|
|
&vote_keypair,
|
2020-07-28 02:33:27 -07:00
|
|
|
Some(Hash::default()),
|
2020-03-09 22:03:09 -07:00
|
|
|
);
|
2019-05-21 21:45:38 -07:00
|
|
|
|
|
|
|
use bincode::serialized_size;
|
|
|
|
info!("max vote size {}", serialized_size(&vote_tx).unwrap());
|
|
|
|
|
2021-12-11 06:44:15 -08:00
|
|
|
let packet_batches = packet::to_packet_batches(&[vote_tx], 1); // panics if won't fit
|
2019-05-21 21:45:38 -07:00
|
|
|
|
2021-12-11 06:44:15 -08:00
|
|
|
assert_eq!(packet_batches.len(), 1);
|
2019-05-21 21:45:38 -07:00
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-03-26 17:55:17 -07:00
|
|
|
#[test]
|
|
|
|
fn test_update_new_root() {
|
2020-05-17 14:01:08 -07:00
|
|
|
let (vote_tracker, bank, _, _) = setup();
|
2020-03-26 17:55:17 -07:00
|
|
|
|
|
|
|
// Check outdated slots are purged with new root
|
2021-02-07 18:07:00 -08:00
|
|
|
let new_voter = solana_sdk::pubkey::new_rand();
|
2020-03-26 17:55:17 -07:00
|
|
|
// Make separate copy so the original doesn't count toward
|
|
|
|
// the ref count, which would prevent cleanup
|
2021-02-07 18:07:00 -08:00
|
|
|
let new_voter_ = new_voter;
|
2020-03-26 17:55:17 -07:00
|
|
|
vote_tracker.insert_vote(bank.slot(), new_voter_);
|
|
|
|
assert!(vote_tracker
|
|
|
|
.slot_vote_trackers
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.contains_key(&bank.slot()));
|
|
|
|
let bank1 = Bank::new_from_parent(&bank, &Pubkey::default(), bank.slot() + 1);
|
2020-10-23 18:19:12 -07:00
|
|
|
vote_tracker.progress_with_new_root_bank(&bank1);
|
2020-03-26 17:55:17 -07:00
|
|
|
assert!(!vote_tracker
|
|
|
|
.slot_vote_trackers
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.contains_key(&bank.slot()));
|
|
|
|
|
|
|
|
// Check `keys` and `epoch_authorized_voters` are purged when new
|
|
|
|
// root bank moves to the next epoch
|
|
|
|
let current_epoch = bank.epoch();
|
|
|
|
let new_epoch_bank = Bank::new_from_parent(
|
|
|
|
&bank,
|
|
|
|
&Pubkey::default(),
|
|
|
|
bank.epoch_schedule()
|
|
|
|
.get_first_slot_in_epoch(current_epoch + 1),
|
|
|
|
);
|
2020-10-23 18:19:12 -07:00
|
|
|
vote_tracker.progress_with_new_root_bank(&new_epoch_bank);
|
2020-03-26 17:55:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_update_new_leader_schedule_epoch() {
|
2022-01-03 13:07:47 -08:00
|
|
|
let (_, bank, _, _) = setup();
|
2020-03-26 17:55:17 -07:00
|
|
|
|
|
|
|
// Check outdated slots are purged with new root
|
|
|
|
let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
|
|
|
let next_leader_schedule_epoch = leader_schedule_epoch + 1;
|
|
|
|
let mut next_leader_schedule_computed = bank.slot();
|
|
|
|
loop {
|
|
|
|
next_leader_schedule_computed += 1;
|
|
|
|
if bank.get_leader_schedule_epoch(next_leader_schedule_computed)
|
|
|
|
== next_leader_schedule_epoch
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert_eq!(
|
|
|
|
bank.get_leader_schedule_epoch(next_leader_schedule_computed),
|
|
|
|
next_leader_schedule_epoch
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-03-09 22:03:09 -07:00
|
|
|
#[test]
|
2020-07-28 02:33:27 -07:00
|
|
|
fn test_votes_in_range() {
|
2020-03-09 22:03:09 -07:00
|
|
|
// Create some voters at genesis
|
2020-07-28 02:33:27 -07:00
|
|
|
let stake_per_validator = 100;
|
2020-05-17 14:01:08 -07:00
|
|
|
let (vote_tracker, _, validator_voting_keypairs, subscriptions) = setup();
|
2020-03-09 22:03:09 -07:00
|
|
|
let (votes_sender, votes_receiver) = unbounded();
|
2020-07-28 02:33:27 -07:00
|
|
|
let (verified_vote_sender, _verified_vote_receiver) = unbounded();
|
2021-04-10 17:34:45 -07:00
|
|
|
let (gossip_verified_vote_hash_sender, _gossip_verified_vote_hash_receiver) = unbounded();
|
2020-07-20 17:29:07 -07:00
|
|
|
let (replay_votes_sender, replay_votes_receiver) = unbounded();
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } =
|
|
|
|
genesis_utils::create_genesis_config_with_vote_accounts(
|
|
|
|
10_000,
|
|
|
|
&validator_voting_keypairs,
|
|
|
|
vec![stake_per_validator; validator_voting_keypairs.len()],
|
|
|
|
);
|
|
|
|
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank0 = Bank::new_for_tests(&genesis_config);
|
2020-07-28 02:33:27 -07:00
|
|
|
// Votes for slots less than the provided root bank's slot should not be processed
|
|
|
|
let bank3 = Arc::new(Bank::new_from_parent(
|
|
|
|
&Arc::new(bank0),
|
|
|
|
&Pubkey::default(),
|
|
|
|
3,
|
|
|
|
));
|
2020-03-09 22:03:09 -07:00
|
|
|
let vote_slots = vec![1, 2];
|
2020-07-28 02:33:27 -07:00
|
|
|
send_vote_txs(
|
|
|
|
vote_slots,
|
|
|
|
vec![],
|
|
|
|
&validator_voting_keypairs,
|
|
|
|
None,
|
|
|
|
&votes_sender,
|
|
|
|
&replay_votes_sender,
|
|
|
|
);
|
2020-10-23 18:19:12 -07:00
|
|
|
ClusterInfoVoteListener::listen_and_confirm_votes(
|
2020-07-28 02:33:27 -07:00
|
|
|
&votes_receiver,
|
|
|
|
&vote_tracker,
|
|
|
|
&bank3,
|
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-28 02:33:27 -07:00
|
|
|
&verified_vote_sender,
|
|
|
|
&replay_votes_receiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-07-28 02:33:27 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Vote slots for slots greater than root bank's set of currently calculated epochs
|
|
|
|
// are ignored
|
|
|
|
let max_epoch = bank3.get_leader_schedule_epoch(bank3.slot());
|
|
|
|
assert!(bank3.epoch_stakes(max_epoch).is_some());
|
|
|
|
let unknown_epoch = max_epoch + 1;
|
|
|
|
assert!(bank3.epoch_stakes(unknown_epoch).is_none());
|
|
|
|
let first_slot_in_unknown_epoch = bank3
|
|
|
|
.epoch_schedule()
|
|
|
|
.get_first_slot_in_epoch(unknown_epoch);
|
|
|
|
let vote_slots = vec![first_slot_in_unknown_epoch, first_slot_in_unknown_epoch + 1];
|
|
|
|
send_vote_txs(
|
|
|
|
vote_slots,
|
|
|
|
vec![],
|
|
|
|
&validator_voting_keypairs,
|
|
|
|
None,
|
|
|
|
&votes_sender,
|
|
|
|
&replay_votes_sender,
|
|
|
|
);
|
2020-10-23 18:19:12 -07:00
|
|
|
ClusterInfoVoteListener::listen_and_confirm_votes(
|
2020-07-28 02:33:27 -07:00
|
|
|
&votes_receiver,
|
|
|
|
&vote_tracker,
|
|
|
|
&bank3,
|
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-28 02:33:27 -07:00
|
|
|
&verified_vote_sender,
|
|
|
|
&replay_votes_receiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-07-28 02:33:27 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Should be no updates since everything was ignored
|
|
|
|
assert!(vote_tracker.slot_vote_trackers.read().unwrap().is_empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
fn send_vote_txs(
|
|
|
|
gossip_vote_slots: Vec<Slot>,
|
|
|
|
replay_vote_slots: Vec<Slot>,
|
|
|
|
validator_voting_keypairs: &[ValidatorVoteKeypairs],
|
2020-07-29 23:17:40 -07:00
|
|
|
switch_proof_hash: Option<Hash>,
|
2020-07-28 02:33:27 -07:00
|
|
|
votes_sender: &VerifiedVoteTransactionsSender,
|
2020-08-07 11:21:35 -07:00
|
|
|
replay_votes_sender: &ReplayVoteSender,
|
2020-07-28 02:33:27 -07:00
|
|
|
) {
|
2020-03-09 22:03:09 -07:00
|
|
|
validator_voting_keypairs.iter().for_each(|keypairs| {
|
|
|
|
let node_keypair = &keypairs.node_keypair;
|
|
|
|
let vote_keypair = &keypairs.vote_keypair;
|
|
|
|
let vote_tx = vote_transaction::new_vote_transaction(
|
2020-07-28 02:33:27 -07:00
|
|
|
gossip_vote_slots.clone(),
|
2020-03-09 22:03:09 -07:00
|
|
|
Hash::default(),
|
|
|
|
Hash::default(),
|
|
|
|
node_keypair,
|
|
|
|
vote_keypair,
|
|
|
|
vote_keypair,
|
2020-07-29 23:17:40 -07:00
|
|
|
switch_proof_hash,
|
2020-03-09 22:03:09 -07:00
|
|
|
);
|
|
|
|
votes_sender.send(vec![vote_tx]).unwrap();
|
2020-07-29 23:17:40 -07:00
|
|
|
let replay_vote = Vote::new(replay_vote_slots.clone(), Hash::default());
|
|
|
|
// Send same vote twice, but should only notify once
|
|
|
|
for _ in 0..2 {
|
2020-07-20 17:29:07 -07:00
|
|
|
replay_votes_sender
|
2020-07-29 23:17:40 -07:00
|
|
|
.send((
|
|
|
|
vote_keypair.pubkey(),
|
2021-12-22 06:25:46 -08:00
|
|
|
VoteTransaction::from(replay_vote.clone()),
|
2020-07-29 23:17:40 -07:00
|
|
|
switch_proof_hash,
|
2022-05-19 18:28:46 -07:00
|
|
|
Signature::default(),
|
2020-07-29 23:17:40 -07:00
|
|
|
))
|
2020-07-20 17:29:07 -07:00
|
|
|
.unwrap();
|
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
});
|
2020-07-28 02:33:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_test_process_votes(hash: Option<Hash>) {
|
|
|
|
// Create some voters at genesis
|
|
|
|
let stake_per_validator = 100;
|
|
|
|
let (vote_tracker, _, validator_voting_keypairs, subscriptions) = setup();
|
|
|
|
let (votes_txs_sender, votes_txs_receiver) = unbounded();
|
|
|
|
let (replay_votes_sender, replay_votes_receiver) = unbounded();
|
2021-04-10 17:34:45 -07:00
|
|
|
let (gossip_verified_vote_hash_sender, gossip_verified_vote_hash_receiver) = unbounded();
|
2020-07-28 02:33:27 -07:00
|
|
|
let (verified_vote_sender, verified_vote_receiver) = unbounded();
|
|
|
|
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } =
|
|
|
|
genesis_utils::create_genesis_config_with_vote_accounts(
|
|
|
|
10_000,
|
|
|
|
&validator_voting_keypairs,
|
|
|
|
vec![stake_per_validator; validator_voting_keypairs.len()],
|
|
|
|
);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank0 = Bank::new_for_tests(&genesis_config);
|
2020-07-28 02:33:27 -07:00
|
|
|
|
|
|
|
let gossip_vote_slots = vec![1, 2];
|
|
|
|
let replay_vote_slots = vec![3, 4];
|
|
|
|
send_vote_txs(
|
|
|
|
gossip_vote_slots.clone(),
|
|
|
|
replay_vote_slots.clone(),
|
|
|
|
&validator_voting_keypairs,
|
|
|
|
hash,
|
|
|
|
&votes_txs_sender,
|
|
|
|
&replay_votes_sender,
|
|
|
|
);
|
2020-03-09 22:03:09 -07:00
|
|
|
|
|
|
|
// Check that all the votes were registered for each validator correctly
|
2020-10-23 18:19:12 -07:00
|
|
|
ClusterInfoVoteListener::listen_and_confirm_votes(
|
2020-07-28 02:33:27 -07:00
|
|
|
&votes_txs_receiver,
|
2020-05-17 14:01:08 -07:00
|
|
|
&vote_tracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
&bank0,
|
2020-06-08 17:38:14 -07:00
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-09 22:52:54 -07:00
|
|
|
&verified_vote_sender,
|
2020-07-20 17:29:07 -07:00
|
|
|
&replay_votes_receiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-05-17 14:01:08 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2020-07-09 22:52:54 -07:00
|
|
|
|
2021-04-10 17:34:45 -07:00
|
|
|
let mut gossip_verified_votes: HashMap<Slot, HashMap<Hash, Vec<Pubkey>>> = HashMap::new();
|
|
|
|
for (pubkey, slot, hash) in gossip_verified_vote_hash_receiver.try_iter() {
|
|
|
|
// send_vote_txs() will send each vote twice, but we should only get a notification
|
|
|
|
// once for each via this channel
|
|
|
|
let exists = gossip_verified_votes
|
|
|
|
.get(&slot)
|
|
|
|
.and_then(|slot_hashes| slot_hashes.get(&hash))
|
|
|
|
.map(|slot_hash_voters| slot_hash_voters.contains(&pubkey))
|
|
|
|
.unwrap_or(false);
|
|
|
|
assert!(!exists);
|
|
|
|
gossip_verified_votes
|
|
|
|
.entry(slot)
|
|
|
|
.or_default()
|
|
|
|
.entry(hash)
|
|
|
|
.or_default()
|
|
|
|
.push(pubkey);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only the last vote in the `gossip_vote` set should count towards
|
|
|
|
// the `voted_hash_updates` set. Important to note here that replay votes
|
|
|
|
// should not count
|
|
|
|
let last_gossip_vote_slot = *gossip_vote_slots.last().unwrap();
|
|
|
|
assert_eq!(gossip_verified_votes.len(), 1);
|
|
|
|
let slot_hashes = gossip_verified_votes.get(&last_gossip_vote_slot).unwrap();
|
|
|
|
assert_eq!(slot_hashes.len(), 1);
|
|
|
|
let slot_hash_votes = slot_hashes.get(&Hash::default()).unwrap();
|
|
|
|
assert_eq!(slot_hash_votes.len(), validator_voting_keypairs.len());
|
|
|
|
for voting_keypairs in &validator_voting_keypairs {
|
|
|
|
let pubkey = voting_keypairs.vote_keypair.pubkey();
|
|
|
|
assert!(slot_hash_votes.contains(&pubkey));
|
|
|
|
}
|
|
|
|
|
2020-07-09 22:52:54 -07:00
|
|
|
// Check that the received votes were pushed to other commponents
|
2020-07-20 17:29:07 -07:00
|
|
|
// subscribing via `verified_vote_receiver`
|
2020-07-28 02:33:27 -07:00
|
|
|
let all_expected_slots: BTreeSet<_> = gossip_vote_slots
|
2021-04-10 17:34:45 -07:00
|
|
|
.clone()
|
2020-07-20 17:29:07 -07:00
|
|
|
.into_iter()
|
2021-04-10 17:34:45 -07:00
|
|
|
.chain(replay_vote_slots.clone().into_iter())
|
2020-07-20 17:29:07 -07:00
|
|
|
.collect();
|
|
|
|
let mut pubkey_to_votes: HashMap<Pubkey, BTreeSet<Slot>> = HashMap::new();
|
|
|
|
for (received_pubkey, new_votes) in verified_vote_receiver.try_iter() {
|
|
|
|
let already_received_votes = pubkey_to_votes.entry(received_pubkey).or_default();
|
|
|
|
for new_vote in new_votes {
|
|
|
|
// `new_vote` should only be received once
|
|
|
|
assert!(already_received_votes.insert(new_vote));
|
|
|
|
}
|
2020-07-09 22:52:54 -07:00
|
|
|
}
|
2020-07-20 17:29:07 -07:00
|
|
|
assert_eq!(pubkey_to_votes.len(), validator_voting_keypairs.len());
|
|
|
|
for keypairs in &validator_voting_keypairs {
|
|
|
|
assert_eq!(
|
|
|
|
*pubkey_to_votes
|
|
|
|
.get(&keypairs.vote_keypair.pubkey())
|
|
|
|
.unwrap(),
|
|
|
|
all_expected_slots
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the vote trackers were updated correctly
|
|
|
|
for vote_slot in all_expected_slots {
|
2020-03-09 22:03:09 -07:00
|
|
|
let slot_vote_tracker = vote_tracker.get_slot_vote_tracker(vote_slot).unwrap();
|
|
|
|
let r_slot_vote_tracker = slot_vote_tracker.read().unwrap();
|
|
|
|
for voting_keypairs in &validator_voting_keypairs {
|
|
|
|
let pubkey = voting_keypairs.vote_keypair.pubkey();
|
2020-07-20 17:29:07 -07:00
|
|
|
assert!(r_slot_vote_tracker.voted.contains_key(&pubkey));
|
2020-03-09 22:03:09 -07:00
|
|
|
assert!(r_slot_vote_tracker
|
2021-04-10 17:34:45 -07:00
|
|
|
.voted_slot_updates
|
2020-03-09 22:03:09 -07:00
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.contains(&Arc::new(pubkey)));
|
2021-04-10 17:34:45 -07:00
|
|
|
// Only the last vote in the stack of `gossip_vote` and `replay_vote_slots`
|
|
|
|
// should count towards the `optimistic` vote set,
|
2020-07-28 02:33:27 -07:00
|
|
|
let optimistic_votes_tracker =
|
|
|
|
r_slot_vote_tracker.optimistic_votes_tracker(&Hash::default());
|
2021-04-10 17:34:45 -07:00
|
|
|
if vote_slot == *gossip_vote_slots.last().unwrap()
|
|
|
|
|| vote_slot == *replay_vote_slots.last().unwrap()
|
|
|
|
{
|
2020-07-28 02:33:27 -07:00
|
|
|
let optimistic_votes_tracker = optimistic_votes_tracker.unwrap();
|
|
|
|
assert!(optimistic_votes_tracker.voted().contains(&pubkey));
|
|
|
|
assert_eq!(
|
|
|
|
optimistic_votes_tracker.stake(),
|
|
|
|
stake_per_validator * validator_voting_keypairs.len() as u64
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
assert!(optimistic_votes_tracker.is_none())
|
|
|
|
}
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
#[test]
|
|
|
|
fn test_process_votes1() {
|
|
|
|
run_test_process_votes(None);
|
|
|
|
run_test_process_votes(Some(Hash::default()));
|
|
|
|
}
|
|
|
|
|
2020-03-09 22:03:09 -07:00
|
|
|
#[test]
|
|
|
|
fn test_process_votes2() {
|
|
|
|
// Create some voters at genesis
|
2020-05-17 14:01:08 -07:00
|
|
|
let (vote_tracker, _, validator_voting_keypairs, subscriptions) = setup();
|
2020-07-28 02:33:27 -07:00
|
|
|
|
|
|
|
// Create bank with the voters
|
|
|
|
let stake_per_validator = 100;
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } =
|
|
|
|
genesis_utils::create_genesis_config_with_vote_accounts(
|
|
|
|
10_000,
|
|
|
|
&validator_voting_keypairs,
|
|
|
|
vec![stake_per_validator; validator_voting_keypairs.len()],
|
|
|
|
);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank0 = Bank::new_for_tests(&genesis_config);
|
2020-07-28 02:33:27 -07:00
|
|
|
|
2020-03-09 22:03:09 -07:00
|
|
|
// Send some votes to process
|
2020-07-09 22:52:54 -07:00
|
|
|
let (votes_txs_sender, votes_txs_receiver) = unbounded();
|
2021-04-10 17:34:45 -07:00
|
|
|
let (gossip_verified_vote_hash_sender, _gossip_verified_vote_hash_receiver) = unbounded();
|
2020-07-09 22:52:54 -07:00
|
|
|
let (verified_vote_sender, verified_vote_receiver) = unbounded();
|
2020-07-20 17:29:07 -07:00
|
|
|
let (_replay_votes_sender, replay_votes_receiver) = unbounded();
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-07-09 22:52:54 -07:00
|
|
|
let mut expected_votes = vec![];
|
2020-07-28 02:33:27 -07:00
|
|
|
let num_voters_per_slot = 2;
|
|
|
|
let bank_hash = Hash::default();
|
|
|
|
for (i, keyset) in validator_voting_keypairs
|
|
|
|
.chunks(num_voters_per_slot)
|
|
|
|
.enumerate()
|
|
|
|
{
|
2020-03-09 22:03:09 -07:00
|
|
|
let validator_votes: Vec<_> = keyset
|
|
|
|
.iter()
|
|
|
|
.map(|keypairs| {
|
|
|
|
let node_keypair = &keypairs.node_keypair;
|
|
|
|
let vote_keypair = &keypairs.vote_keypair;
|
2020-07-09 22:52:54 -07:00
|
|
|
expected_votes.push((vote_keypair.pubkey(), vec![i as Slot + 1]));
|
2020-05-15 09:35:43 -07:00
|
|
|
vote_transaction::new_vote_transaction(
|
2020-03-09 22:03:09 -07:00
|
|
|
vec![i as u64 + 1],
|
2020-07-28 02:33:27 -07:00
|
|
|
bank_hash,
|
2020-03-09 22:03:09 -07:00
|
|
|
Hash::default(),
|
|
|
|
node_keypair,
|
|
|
|
vote_keypair,
|
|
|
|
vote_keypair,
|
2020-07-28 02:33:27 -07:00
|
|
|
None,
|
2020-05-15 09:35:43 -07:00
|
|
|
)
|
2020-03-09 22:03:09 -07:00
|
|
|
})
|
|
|
|
.collect();
|
2020-07-09 22:52:54 -07:00
|
|
|
votes_txs_sender.send(validator_votes).unwrap();
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
|
2020-07-09 22:52:54 -07:00
|
|
|
// Read and process votes from channel `votes_receiver`
|
2020-10-23 18:19:12 -07:00
|
|
|
ClusterInfoVoteListener::listen_and_confirm_votes(
|
2020-07-09 22:52:54 -07:00
|
|
|
&votes_txs_receiver,
|
2020-05-17 14:01:08 -07:00
|
|
|
&vote_tracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
&bank0,
|
2020-06-08 17:38:14 -07:00
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-09 22:52:54 -07:00
|
|
|
&verified_vote_sender,
|
2020-07-20 17:29:07 -07:00
|
|
|
&replay_votes_receiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-05-17 14:01:08 -07:00
|
|
|
)
|
|
|
|
.unwrap();
|
2020-07-09 22:52:54 -07:00
|
|
|
|
|
|
|
// Check that the received votes were pushed to other commponents
|
|
|
|
// subscribing via a channel
|
2020-07-20 17:29:07 -07:00
|
|
|
let received_votes: Vec<_> = verified_vote_receiver.try_iter().collect();
|
2020-07-09 22:52:54 -07:00
|
|
|
assert_eq!(received_votes.len(), validator_voting_keypairs.len());
|
|
|
|
for (expected_pubkey_vote, received_pubkey_vote) in
|
|
|
|
expected_votes.iter().zip(received_votes.iter())
|
|
|
|
{
|
|
|
|
assert_eq!(expected_pubkey_vote, received_pubkey_vote);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that all the votes were registered for each validator correctly
|
2020-03-09 22:03:09 -07:00
|
|
|
for (i, keyset) in validator_voting_keypairs.chunks(2).enumerate() {
|
|
|
|
let slot_vote_tracker = vote_tracker.get_slot_vote_tracker(i as u64 + 1).unwrap();
|
|
|
|
let r_slot_vote_tracker = &slot_vote_tracker.read().unwrap();
|
|
|
|
for voting_keypairs in keyset {
|
|
|
|
let pubkey = voting_keypairs.vote_keypair.pubkey();
|
2020-07-20 17:29:07 -07:00
|
|
|
assert!(r_slot_vote_tracker.voted.contains_key(&pubkey));
|
2020-03-09 22:03:09 -07:00
|
|
|
assert!(r_slot_vote_tracker
|
2021-04-10 17:34:45 -07:00
|
|
|
.voted_slot_updates
|
2020-03-09 22:03:09 -07:00
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.contains(&Arc::new(pubkey)));
|
2020-07-28 02:33:27 -07:00
|
|
|
// All the votes were single votes, so they should all count towards
|
|
|
|
// the optimistic confirmation vote set
|
|
|
|
let optimistic_votes_tracker = r_slot_vote_tracker
|
|
|
|
.optimistic_votes_tracker(&bank_hash)
|
|
|
|
.unwrap();
|
|
|
|
assert!(optimistic_votes_tracker.voted().contains(&pubkey));
|
|
|
|
assert_eq!(
|
|
|
|
optimistic_votes_tracker.stake(),
|
|
|
|
num_voters_per_slot as u64 * stake_per_validator
|
|
|
|
);
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-29 23:17:40 -07:00
|
|
|
fn run_test_process_votes3(switch_proof_hash: Option<Hash>) {
|
2020-07-20 17:29:07 -07:00
|
|
|
let (votes_sender, votes_receiver) = unbounded();
|
|
|
|
let (verified_vote_sender, _verified_vote_receiver) = unbounded();
|
2021-04-10 17:34:45 -07:00
|
|
|
let (gossip_verified_vote_hash_sender, _gossip_verified_vote_hash_receiver) = unbounded();
|
2021-12-07 16:47:26 -08:00
|
|
|
let (replay_votes_sender, replay_votes_receiver): (ReplayVoteSender, ReplayVoteReceiver) =
|
|
|
|
unbounded();
|
2020-07-20 17:29:07 -07:00
|
|
|
|
|
|
|
let vote_slot = 1;
|
2020-07-30 02:52:27 -07:00
|
|
|
let vote_bank_hash = Hash::default();
|
2020-07-20 17:29:07 -07:00
|
|
|
// Events:
|
|
|
|
// 0: Send gossip vote
|
|
|
|
// 1: Send replay vote
|
|
|
|
// 2: Send both
|
|
|
|
let ordered_events = vec![
|
|
|
|
vec![0],
|
|
|
|
vec![1],
|
|
|
|
vec![0, 1],
|
|
|
|
vec![1, 0],
|
|
|
|
vec![2],
|
|
|
|
vec![0, 1, 2],
|
|
|
|
vec![1, 0, 2],
|
2020-07-29 23:17:40 -07:00
|
|
|
vec![0, 1, 2, 0, 1, 2],
|
2020-07-20 17:29:07 -07:00
|
|
|
];
|
|
|
|
for events in ordered_events {
|
|
|
|
let (vote_tracker, bank, validator_voting_keypairs, subscriptions) = setup();
|
|
|
|
let node_keypair = &validator_voting_keypairs[0].node_keypair;
|
|
|
|
let vote_keypair = &validator_voting_keypairs[0].vote_keypair;
|
|
|
|
for &e in &events {
|
|
|
|
if e == 0 || e == 2 {
|
|
|
|
// Create vote transaction
|
|
|
|
let vote_tx = vote_transaction::new_vote_transaction(
|
|
|
|
vec![vote_slot],
|
2020-07-30 02:52:27 -07:00
|
|
|
vote_bank_hash,
|
2020-07-20 17:29:07 -07:00
|
|
|
Hash::default(),
|
|
|
|
node_keypair,
|
|
|
|
vote_keypair,
|
|
|
|
vote_keypair,
|
2020-07-29 23:17:40 -07:00
|
|
|
switch_proof_hash,
|
2020-07-20 17:29:07 -07:00
|
|
|
);
|
|
|
|
votes_sender.send(vec![vote_tx.clone()]).unwrap();
|
|
|
|
}
|
|
|
|
if e == 1 || e == 2 {
|
|
|
|
replay_votes_sender
|
2020-07-29 23:17:40 -07:00
|
|
|
.send((
|
|
|
|
vote_keypair.pubkey(),
|
2021-12-22 06:25:46 -08:00
|
|
|
VoteTransaction::from(Vote::new(vec![vote_slot], Hash::default())),
|
2020-07-29 23:17:40 -07:00
|
|
|
switch_proof_hash,
|
2022-05-19 18:28:46 -07:00
|
|
|
Signature::default(),
|
2020-07-29 23:17:40 -07:00
|
|
|
))
|
2020-07-20 17:29:07 -07:00
|
|
|
.unwrap();
|
|
|
|
}
|
2020-10-23 18:19:12 -07:00
|
|
|
let _ = ClusterInfoVoteListener::listen_and_confirm_votes(
|
2020-07-20 17:29:07 -07:00
|
|
|
&votes_receiver,
|
|
|
|
&vote_tracker,
|
2020-07-28 02:33:27 -07:00
|
|
|
&bank,
|
2020-07-20 17:29:07 -07:00
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-20 17:29:07 -07:00
|
|
|
&verified_vote_sender,
|
|
|
|
&replay_votes_receiver,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-07-20 17:29:07 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
let slot_vote_tracker = vote_tracker.get_slot_vote_tracker(vote_slot).unwrap();
|
|
|
|
let r_slot_vote_tracker = &slot_vote_tracker.read().unwrap();
|
|
|
|
|
2021-04-18 10:27:36 -07:00
|
|
|
assert_eq!(
|
|
|
|
r_slot_vote_tracker
|
|
|
|
.optimistic_votes_tracker(&vote_bank_hash)
|
|
|
|
.unwrap()
|
|
|
|
.stake(),
|
|
|
|
100
|
|
|
|
);
|
2020-07-20 17:29:07 -07:00
|
|
|
if events == vec![1] {
|
|
|
|
// Check `gossip_only_stake` is not incremented
|
|
|
|
assert_eq!(r_slot_vote_tracker.gossip_only_stake, 0);
|
|
|
|
} else {
|
2020-07-28 02:33:27 -07:00
|
|
|
// Check that both the `gossip_only_stake` and `total_voted_stake` both
|
2020-07-20 17:29:07 -07:00
|
|
|
// increased
|
|
|
|
assert_eq!(r_slot_vote_tracker.gossip_only_stake, 100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
#[test]
|
|
|
|
fn test_run_test_process_votes3() {
|
|
|
|
run_test_process_votes3(None);
|
|
|
|
run_test_process_votes3(Some(Hash::default()));
|
|
|
|
}
|
|
|
|
|
2020-03-09 22:03:09 -07:00
|
|
|
#[test]
|
|
|
|
fn test_vote_tracker_references() {
|
|
|
|
// Create some voters at genesis
|
2020-07-23 18:50:42 -07:00
|
|
|
let validator_keypairs: Vec<_> =
|
|
|
|
(0..2).map(|_| ValidatorVoteKeypairs::new_rand()).collect();
|
2020-03-09 22:03:09 -07:00
|
|
|
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } =
|
|
|
|
genesis_utils::create_genesis_config_with_vote_accounts(
|
|
|
|
10_000,
|
2020-07-20 17:29:07 -07:00
|
|
|
&validator_keypairs,
|
2020-07-23 18:50:42 -07:00
|
|
|
vec![100; validator_keypairs.len()],
|
2020-03-09 22:03:09 -07:00
|
|
|
);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-05-17 14:01:08 -07:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2020-09-28 19:43:05 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank = bank_forks.read().unwrap().get(0).unwrap();
|
2022-02-04 11:01:59 -08:00
|
|
|
let vote_tracker = VoteTracker::default();
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-05-17 14:01:08 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_forks,
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::default())),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank,
|
2020-05-17 14:01:08 -07:00
|
|
|
));
|
2020-03-09 22:03:09 -07:00
|
|
|
|
|
|
|
// Send a vote to process, should add a reference to the pubkey for that voter
|
|
|
|
// in the tracker
|
2020-07-20 17:29:07 -07:00
|
|
|
let validator0_keypairs = &validator_keypairs[0];
|
|
|
|
let voted_slot = bank.slot() + 1;
|
2020-03-09 22:03:09 -07:00
|
|
|
let vote_tx = vec![vote_transaction::new_vote_transaction(
|
|
|
|
// Must vote > root to be processed
|
2020-07-20 17:29:07 -07:00
|
|
|
vec![voted_slot],
|
2020-03-09 22:03:09 -07:00
|
|
|
Hash::default(),
|
|
|
|
Hash::default(),
|
|
|
|
&validator0_keypairs.node_keypair,
|
|
|
|
&validator0_keypairs.vote_keypair,
|
|
|
|
&validator0_keypairs.vote_keypair,
|
2020-07-28 02:33:27 -07:00
|
|
|
None,
|
2020-03-09 22:03:09 -07:00
|
|
|
)];
|
|
|
|
|
2020-07-09 22:52:54 -07:00
|
|
|
let (verified_vote_sender, _verified_vote_receiver) = unbounded();
|
2021-04-10 17:34:45 -07:00
|
|
|
let (gossip_verified_vote_hash_sender, _gossip_verified_vote_hash_receiver) = unbounded();
|
2020-10-23 18:19:12 -07:00
|
|
|
ClusterInfoVoteListener::filter_and_confirm_with_new_votes(
|
2020-07-09 22:52:54 -07:00
|
|
|
&vote_tracker,
|
|
|
|
vote_tx,
|
2020-07-29 23:17:40 -07:00
|
|
|
// Add gossip vote for same slot, should not affect outcome
|
|
|
|
vec![(
|
|
|
|
validator0_keypairs.vote_keypair.pubkey(),
|
2021-12-22 06:25:46 -08:00
|
|
|
VoteTransaction::from(Vote::new(vec![voted_slot], Hash::default())),
|
2020-07-29 23:17:40 -07:00
|
|
|
None,
|
2022-05-19 18:28:46 -07:00
|
|
|
Signature::default(),
|
2020-07-29 23:17:40 -07:00
|
|
|
)],
|
2020-07-28 02:33:27 -07:00
|
|
|
&bank,
|
2020-07-09 22:52:54 -07:00
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-09 22:52:54 -07:00
|
|
|
&verified_vote_sender,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-07-09 22:52:54 -07:00
|
|
|
);
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-03-26 17:55:17 -07:00
|
|
|
// Setup next epoch
|
|
|
|
let old_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
|
|
|
let new_epoch = old_epoch + 1;
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-03-26 17:55:17 -07:00
|
|
|
// Test with votes across two epochs
|
|
|
|
let first_slot_in_new_epoch = bank.epoch_schedule().get_first_slot_in_epoch(new_epoch);
|
2020-03-09 22:03:09 -07:00
|
|
|
|
2020-07-20 17:29:07 -07:00
|
|
|
// Make 2 new votes in two different epochs for the same pubkey,
|
|
|
|
// the ref count should go up by 3 * ref_count_per_vote
|
2020-07-28 02:33:27 -07:00
|
|
|
// Add 1 vote through the replay channel for a different pubkey,
|
|
|
|
// ref count should equal `current_ref_count` for that pubkey.
|
|
|
|
let vote_txs: Vec<_> = [first_slot_in_new_epoch - 1, first_slot_in_new_epoch]
|
2020-03-09 22:03:09 -07:00
|
|
|
.iter()
|
|
|
|
.map(|slot| {
|
|
|
|
vote_transaction::new_vote_transaction(
|
|
|
|
// Must vote > root to be processed
|
|
|
|
vec![*slot],
|
|
|
|
Hash::default(),
|
|
|
|
Hash::default(),
|
|
|
|
&validator0_keypairs.node_keypair,
|
|
|
|
&validator0_keypairs.vote_keypair,
|
|
|
|
&validator0_keypairs.vote_keypair,
|
2020-07-28 02:33:27 -07:00
|
|
|
None,
|
2020-03-09 22:03:09 -07:00
|
|
|
)
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
let new_root_bank =
|
|
|
|
Bank::new_from_parent(&bank, &Pubkey::default(), first_slot_in_new_epoch - 2);
|
2020-10-23 18:19:12 -07:00
|
|
|
ClusterInfoVoteListener::filter_and_confirm_with_new_votes(
|
2020-07-09 22:52:54 -07:00
|
|
|
&vote_tracker,
|
|
|
|
vote_txs,
|
2020-07-29 23:17:40 -07:00
|
|
|
vec![(
|
|
|
|
validator_keypairs[1].vote_keypair.pubkey(),
|
2021-12-22 06:25:46 -08:00
|
|
|
VoteTransaction::from(Vote::new(vec![first_slot_in_new_epoch], Hash::default())),
|
2020-07-29 23:17:40 -07:00
|
|
|
None,
|
2022-05-19 18:28:46 -07:00
|
|
|
Signature::default(),
|
2020-07-29 23:17:40 -07:00
|
|
|
)],
|
2020-07-28 02:33:27 -07:00
|
|
|
&new_root_bank,
|
2020-07-09 22:52:54 -07:00
|
|
|
&subscriptions,
|
2021-04-10 17:34:45 -07:00
|
|
|
&gossip_verified_vote_hash_sender,
|
2020-07-09 22:52:54 -07:00
|
|
|
&verified_vote_sender,
|
2020-09-28 19:43:05 -07:00
|
|
|
&None,
|
2021-03-24 23:41:52 -07:00
|
|
|
&None,
|
2022-06-27 06:53:34 -07:00
|
|
|
&mut None,
|
2020-07-20 17:29:07 -07:00
|
|
|
);
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
2020-03-26 17:55:17 -07:00
|
|
|
|
2020-05-17 14:01:08 -07:00
|
|
|
fn setup() -> (
|
|
|
|
Arc<VoteTracker>,
|
|
|
|
Arc<Bank>,
|
|
|
|
Vec<ValidatorVoteKeypairs>,
|
|
|
|
Arc<RpcSubscriptions>,
|
|
|
|
) {
|
2020-07-23 18:50:42 -07:00
|
|
|
let validator_voting_keypairs: Vec<_> =
|
|
|
|
(0..10).map(|_| ValidatorVoteKeypairs::new_rand()).collect();
|
2020-03-26 17:55:17 -07:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } =
|
|
|
|
genesis_utils::create_genesis_config_with_vote_accounts(
|
|
|
|
10_000,
|
|
|
|
&validator_voting_keypairs,
|
2020-07-23 18:50:42 -07:00
|
|
|
vec![100; validator_voting_keypairs.len()],
|
2020-03-26 17:55:17 -07:00
|
|
|
);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2022-02-04 11:01:59 -08:00
|
|
|
let vote_tracker = VoteTracker::default();
|
2020-05-17 14:01:08 -07:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2020-09-28 19:43:05 -07:00
|
|
|
let bank_forks = Arc::new(RwLock::new(BankForks::new(bank)));
|
2022-04-28 11:51:00 -07:00
|
|
|
let bank = bank_forks.read().unwrap().get(0).unwrap();
|
2020-09-28 19:43:05 -07:00
|
|
|
let optimistically_confirmed_bank =
|
|
|
|
OptimisticallyConfirmedBank::locked_from_bank_forks_root(&bank_forks);
|
2021-12-17 15:03:09 -08:00
|
|
|
let max_complete_transaction_status_slot = Arc::new(AtomicU64::default());
|
2021-09-17 12:40:14 -07:00
|
|
|
let subscriptions = Arc::new(RpcSubscriptions::new_for_tests(
|
2020-05-17 14:01:08 -07:00
|
|
|
&exit,
|
2021-12-17 15:03:09 -08:00
|
|
|
max_complete_transaction_status_slot,
|
2020-09-28 19:43:05 -07:00
|
|
|
bank_forks,
|
2020-06-25 21:06:58 -07:00
|
|
|
Arc::new(RwLock::new(BlockCommitmentCache::default())),
|
2020-09-28 19:43:05 -07:00
|
|
|
optimistically_confirmed_bank,
|
2020-05-17 14:01:08 -07:00
|
|
|
));
|
2020-03-26 17:55:17 -07:00
|
|
|
|
|
|
|
(
|
|
|
|
Arc::new(vote_tracker),
|
2020-05-17 14:01:08 -07:00
|
|
|
bank,
|
2020-03-26 17:55:17 -07:00
|
|
|
validator_voting_keypairs,
|
2020-05-17 14:01:08 -07:00
|
|
|
subscriptions,
|
2020-03-26 17:55:17 -07:00
|
|
|
)
|
|
|
|
}
|
2020-04-23 17:04:09 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_verify_votes_empty() {
|
|
|
|
solana_logger::setup();
|
2021-12-30 07:03:14 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
let bank_forks = RwLock::new(BankForks::new(bank));
|
2020-04-23 17:04:09 -07:00
|
|
|
let votes = vec![];
|
2021-12-30 07:03:14 -08:00
|
|
|
let (vote_txs, packets) = ClusterInfoVoteListener::verify_votes(votes, &bank_forks);
|
2020-04-23 17:04:09 -07:00
|
|
|
assert!(vote_txs.is_empty());
|
|
|
|
assert!(packets.is_empty());
|
|
|
|
}
|
|
|
|
|
2021-11-18 15:20:41 -08:00
|
|
|
fn verify_packets_len(packets: &[VerifiedVoteMetadata], ref_value: usize) {
|
|
|
|
let num_packets: usize = packets
|
|
|
|
.iter()
|
2022-05-23 13:30:15 -07:00
|
|
|
.map(|vote_metadata| vote_metadata.packet_batch.len())
|
2021-11-18 15:20:41 -08:00
|
|
|
.sum();
|
2020-04-23 17:04:09 -07:00
|
|
|
assert_eq!(num_packets, ref_value);
|
|
|
|
}
|
|
|
|
|
2021-12-30 07:03:14 -08:00
|
|
|
fn test_vote_tx(
|
|
|
|
validator_vote_keypairs: Option<&ValidatorVoteKeypairs>,
|
|
|
|
hash: Option<Hash>,
|
|
|
|
) -> Transaction {
|
|
|
|
let other = ValidatorVoteKeypairs::new_rand();
|
|
|
|
let validator_vote_keypair = validator_vote_keypairs.unwrap_or(&other);
|
|
|
|
// TODO authorized_voter_keypair should be different from vote-keypair
|
|
|
|
// but that is what create_genesis_... currently generates.
|
2020-05-15 09:35:43 -07:00
|
|
|
vote_transaction::new_vote_transaction(
|
2020-04-23 17:04:09 -07:00
|
|
|
vec![0],
|
|
|
|
Hash::default(),
|
|
|
|
Hash::default(),
|
2021-12-30 07:03:14 -08:00
|
|
|
&validator_vote_keypair.node_keypair,
|
|
|
|
&validator_vote_keypair.vote_keypair,
|
|
|
|
&validator_vote_keypair.vote_keypair, // authorized_voter_keypair
|
2020-07-28 02:33:27 -07:00
|
|
|
hash,
|
2020-05-15 09:35:43 -07:00
|
|
|
)
|
2020-04-23 17:04:09 -07:00
|
|
|
}
|
|
|
|
|
2020-07-28 02:33:27 -07:00
|
|
|
fn run_test_verify_votes_1_pass(hash: Option<Hash>) {
|
2021-12-30 07:03:14 -08:00
|
|
|
let voting_keypairs: Vec<_> = repeat_with(ValidatorVoteKeypairs::new_rand)
|
|
|
|
.take(10)
|
|
|
|
.collect();
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } =
|
|
|
|
genesis_utils::create_genesis_config_with_vote_accounts(
|
|
|
|
10_000, // mint_lamports
|
|
|
|
&voting_keypairs,
|
|
|
|
vec![100; voting_keypairs.len()], // stakes
|
|
|
|
);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
let bank_forks = RwLock::new(BankForks::new(bank));
|
|
|
|
let vote_tx = test_vote_tx(voting_keypairs.first(), hash);
|
2020-05-15 09:35:43 -07:00
|
|
|
let votes = vec![vote_tx];
|
2021-12-30 07:03:14 -08:00
|
|
|
let (vote_txs, packets) = ClusterInfoVoteListener::verify_votes(votes, &bank_forks);
|
2020-04-23 17:04:09 -07:00
|
|
|
assert_eq!(vote_txs.len(), 1);
|
|
|
|
verify_packets_len(&packets, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2020-07-28 02:33:27 -07:00
|
|
|
fn test_verify_votes_1_pass() {
|
|
|
|
run_test_verify_votes_1_pass(None);
|
|
|
|
run_test_verify_votes_1_pass(Some(Hash::default()));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_test_bad_vote(hash: Option<Hash>) {
|
2021-12-30 07:03:14 -08:00
|
|
|
let voting_keypairs: Vec<_> = repeat_with(ValidatorVoteKeypairs::new_rand)
|
|
|
|
.take(10)
|
|
|
|
.collect();
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } =
|
|
|
|
genesis_utils::create_genesis_config_with_vote_accounts(
|
|
|
|
10_000, // mint_lamports
|
|
|
|
&voting_keypairs,
|
|
|
|
vec![100; voting_keypairs.len()], // stakes
|
|
|
|
);
|
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
|
|
|
let bank_forks = RwLock::new(BankForks::new(bank));
|
|
|
|
let vote_tx = test_vote_tx(voting_keypairs.first(), hash);
|
2020-04-23 17:04:09 -07:00
|
|
|
let mut bad_vote = vote_tx.clone();
|
|
|
|
bad_vote.signatures[0] = Signature::default();
|
|
|
|
let votes = vec![vote_tx.clone(), bad_vote, vote_tx];
|
2021-12-30 07:03:14 -08:00
|
|
|
let (vote_txs, packets) = ClusterInfoVoteListener::verify_votes(votes, &bank_forks);
|
2020-04-23 17:04:09 -07:00
|
|
|
assert_eq!(vote_txs.len(), 2);
|
|
|
|
verify_packets_len(&packets, 2);
|
|
|
|
}
|
2020-07-20 17:29:07 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_sum_stake() {
|
|
|
|
let (_, bank, validator_voting_keypairs, _) = setup();
|
|
|
|
let vote_keypair = &validator_voting_keypairs[0].vote_keypair;
|
|
|
|
let epoch_stakes = bank.epoch_stakes(bank.epoch()).unwrap();
|
|
|
|
let mut gossip_only_stake = 0;
|
|
|
|
|
|
|
|
ClusterInfoVoteListener::sum_stake(
|
|
|
|
&mut gossip_only_stake,
|
|
|
|
Some(epoch_stakes),
|
|
|
|
&vote_keypair.pubkey(),
|
|
|
|
);
|
|
|
|
assert_eq!(gossip_only_stake, 100);
|
|
|
|
}
|
2020-07-28 02:33:27 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bad_vote() {
|
|
|
|
run_test_bad_vote(None);
|
|
|
|
run_test_bad_vote(Some(Hash::default()));
|
|
|
|
}
|
2021-11-18 15:20:41 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_check_for_leader_bank_and_send_votes() {
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(1000);
|
|
|
|
let current_leader_bank = Arc::new(Bank::new_for_tests(&genesis_config));
|
|
|
|
let mut bank_vote_sender_state_option: Option<BankVoteSenderState> = None;
|
|
|
|
let verified_vote_packets = VerifiedVotePackets::default();
|
|
|
|
let (verified_packets_sender, _verified_packets_receiver) = unbounded();
|
|
|
|
|
|
|
|
// 1) If we hand over a `current_leader_bank`, vote sender state should be updated
|
|
|
|
ClusterInfoVoteListener::check_for_leader_bank_and_send_votes(
|
|
|
|
&mut bank_vote_sender_state_option,
|
|
|
|
current_leader_bank.clone(),
|
|
|
|
&verified_packets_sender,
|
|
|
|
&verified_vote_packets,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
bank_vote_sender_state_option.as_ref().unwrap().bank.slot(),
|
|
|
|
current_leader_bank.slot()
|
|
|
|
);
|
|
|
|
bank_vote_sender_state_option
|
|
|
|
.as_mut()
|
|
|
|
.unwrap()
|
|
|
|
.previously_sent_to_bank_votes
|
|
|
|
.insert(Signature::new_unique());
|
|
|
|
|
|
|
|
// 2) Handing over the same leader bank again should not update the state
|
|
|
|
ClusterInfoVoteListener::check_for_leader_bank_and_send_votes(
|
|
|
|
&mut bank_vote_sender_state_option,
|
|
|
|
current_leader_bank.clone(),
|
|
|
|
&verified_packets_sender,
|
|
|
|
&verified_vote_packets,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
// If we hand over a `current_leader_bank`, vote sender state should be updated
|
|
|
|
assert_eq!(
|
|
|
|
bank_vote_sender_state_option.as_ref().unwrap().bank.slot(),
|
|
|
|
current_leader_bank.slot()
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
bank_vote_sender_state_option
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.previously_sent_to_bank_votes
|
|
|
|
.len(),
|
|
|
|
1
|
|
|
|
);
|
|
|
|
|
|
|
|
let current_leader_bank = Arc::new(Bank::new_from_parent(
|
|
|
|
¤t_leader_bank,
|
|
|
|
&Pubkey::default(),
|
|
|
|
current_leader_bank.slot() + 1,
|
|
|
|
));
|
|
|
|
ClusterInfoVoteListener::check_for_leader_bank_and_send_votes(
|
|
|
|
&mut bank_vote_sender_state_option,
|
|
|
|
current_leader_bank.clone(),
|
|
|
|
&verified_packets_sender,
|
|
|
|
&verified_vote_packets,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// 3) If we hand over a new `current_leader_bank`, vote sender state should be updated
|
|
|
|
// to the new bank
|
|
|
|
assert_eq!(
|
|
|
|
bank_vote_sender_state_option.as_ref().unwrap().bank.slot(),
|
|
|
|
current_leader_bank.slot()
|
|
|
|
);
|
|
|
|
assert!(bank_vote_sender_state_option
|
|
|
|
.as_ref()
|
|
|
|
.unwrap()
|
|
|
|
.previously_sent_to_bank_votes
|
|
|
|
.is_empty());
|
|
|
|
}
|
2019-05-21 21:45:38 -07:00
|
|
|
}
|