* removes epoch_authorized_voters from VoteTracker (#22192)
https://github.com/solana-labs/solana/pull/22169
verifies authorized-voter early on in vote-listener pipeline; and so
VoteTracker no longer needs to maintain and check for epoch authorized
voters.
(cherry picked from commit 69d71f8f86
)
# Conflicts:
# core/src/cluster_info_vote_listener.rs
* removes backport merge conflicts
Co-authored-by: behzad nouri <behzadnouri@gmail.com>
This commit is contained in:
@ -31,12 +31,11 @@ use {
|
|||||||
bank::Bank,
|
bank::Bank,
|
||||||
bank_forks::BankForks,
|
bank_forks::BankForks,
|
||||||
commitment::VOTE_THRESHOLD_SIZE,
|
commitment::VOTE_THRESHOLD_SIZE,
|
||||||
epoch_stakes::{EpochAuthorizedVoters, EpochStakes},
|
epoch_stakes::EpochStakes,
|
||||||
vote_sender_types::{ReplayVoteReceiver, ReplayedVote},
|
vote_sender_types::{ReplayVoteReceiver, ReplayedVote},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
clock::{Epoch, Slot, DEFAULT_MS_PER_SLOT, DEFAULT_TICKS_PER_SLOT},
|
clock::{Slot, DEFAULT_MS_PER_SLOT, DEFAULT_TICKS_PER_SLOT},
|
||||||
epoch_schedule::EpochSchedule,
|
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::Signature,
|
signature::Signature,
|
||||||
@ -46,6 +45,7 @@ use {
|
|||||||
solana_vote_program::{self, vote_state::Vote, vote_transaction},
|
solana_vote_program::{self, vote_state::Vote, vote_transaction},
|
||||||
std::{
|
std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
|
iter::repeat,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
Arc, Mutex, RwLock,
|
Arc, Mutex, RwLock,
|
||||||
@ -57,7 +57,6 @@ use {
|
|||||||
|
|
||||||
// Map from a vote account to the authorized voter for an epoch
|
// Map from a vote account to the authorized voter for an epoch
|
||||||
pub type ThresholdConfirmedSlots = Vec<(Slot, Hash)>;
|
pub type ThresholdConfirmedSlots = Vec<(Slot, Hash)>;
|
||||||
pub type VotedHashUpdates = HashMap<Hash, Vec<Pubkey>>;
|
|
||||||
pub type VerifiedLabelVotePacketsSender = CrossbeamSender<Vec<VerifiedVoteMetadata>>;
|
pub type VerifiedLabelVotePacketsSender = CrossbeamSender<Vec<VerifiedVoteMetadata>>;
|
||||||
pub type VerifiedLabelVotePacketsReceiver = CrossbeamReceiver<Vec<VerifiedVoteMetadata>>;
|
pub type VerifiedLabelVotePacketsReceiver = CrossbeamReceiver<Vec<VerifiedVoteMetadata>>;
|
||||||
pub type VerifiedVoteTransactionsSender = CrossbeamSender<Vec<Transaction>>;
|
pub type VerifiedVoteTransactionsSender = CrossbeamSender<Vec<Transaction>>;
|
||||||
@ -84,14 +83,14 @@ pub struct SlotVoteTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SlotVoteTracker {
|
impl SlotVoteTracker {
|
||||||
pub fn get_voted_slot_updates(&mut self) -> Option<Vec<Pubkey>> {
|
pub(crate) fn get_voted_slot_updates(&mut self) -> Option<Vec<Pubkey>> {
|
||||||
self.voted_slot_updates.take()
|
self.voted_slot_updates.take()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_insert_optimistic_votes_tracker(&mut self, hash: Hash) -> &mut VoteStakeTracker {
|
fn get_or_insert_optimistic_votes_tracker(&mut self, hash: Hash) -> &mut VoteStakeTracker {
|
||||||
self.optimistic_votes_tracker.entry(hash).or_default()
|
self.optimistic_votes_tracker.entry(hash).or_default()
|
||||||
}
|
}
|
||||||
pub fn optimistic_votes_tracker(&self, hash: &Hash) -> Option<&VoteStakeTracker> {
|
pub(crate) fn optimistic_votes_tracker(&self, hash: &Hash) -> Option<&VoteStakeTracker> {
|
||||||
self.optimistic_votes_tracker.get(hash)
|
self.optimistic_votes_tracker.get(hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,82 +99,29 @@ impl SlotVoteTracker {
|
|||||||
pub struct VoteTracker {
|
pub struct VoteTracker {
|
||||||
// Map from a slot to a set of validators who have voted for that slot
|
// Map from a slot to a set of validators who have voted for that slot
|
||||||
slot_vote_trackers: RwLock<HashMap<Slot, Arc<RwLock<SlotVoteTracker>>>>,
|
slot_vote_trackers: RwLock<HashMap<Slot, Arc<RwLock<SlotVoteTracker>>>>,
|
||||||
// Don't track votes from people who are not staked, acts as a spam filter
|
|
||||||
epoch_authorized_voters: RwLock<HashMap<Epoch, Arc<EpochAuthorizedVoters>>>,
|
|
||||||
leader_schedule_epoch: RwLock<Epoch>,
|
|
||||||
current_epoch: RwLock<Epoch>,
|
|
||||||
epoch_schedule: EpochSchedule,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VoteTracker {
|
impl VoteTracker {
|
||||||
pub fn new(root_bank: &Bank) -> Self {
|
pub(crate) fn new(root_bank: &Bank) -> Self {
|
||||||
let current_epoch = root_bank.epoch();
|
let vote_tracker = VoteTracker::default();
|
||||||
let vote_tracker = Self {
|
|
||||||
leader_schedule_epoch: RwLock::new(current_epoch),
|
|
||||||
current_epoch: RwLock::new(current_epoch),
|
|
||||||
epoch_schedule: *root_bank.epoch_schedule(),
|
|
||||||
..VoteTracker::default()
|
|
||||||
};
|
|
||||||
vote_tracker.progress_with_new_root_bank(root_bank);
|
vote_tracker.progress_with_new_root_bank(root_bank);
|
||||||
assert_eq!(
|
|
||||||
*vote_tracker.leader_schedule_epoch.read().unwrap(),
|
|
||||||
root_bank.get_leader_schedule_epoch(root_bank.slot())
|
|
||||||
);
|
|
||||||
assert_eq!(*vote_tracker.current_epoch.read().unwrap(), current_epoch,);
|
|
||||||
vote_tracker
|
vote_tracker
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_or_insert_slot_tracker(&self, slot: Slot) -> Arc<RwLock<SlotVoteTracker>> {
|
fn get_or_insert_slot_tracker(&self, slot: Slot) -> Arc<RwLock<SlotVoteTracker>> {
|
||||||
let mut slot_tracker = self.slot_vote_trackers.read().unwrap().get(&slot).cloned();
|
if let Some(slot_vote_tracker) = self.slot_vote_trackers.read().unwrap().get(&slot) {
|
||||||
|
return slot_vote_tracker.clone();
|
||||||
if slot_tracker.is_none() {
|
}
|
||||||
let new_slot_tracker = Arc::new(RwLock::new(SlotVoteTracker {
|
let mut slot_vote_trackers = self.slot_vote_trackers.write().unwrap();
|
||||||
voted: HashMap::new(),
|
slot_vote_trackers.entry(slot).or_default().clone()
|
||||||
optimistic_votes_tracker: HashMap::default(),
|
|
||||||
voted_slot_updates: None,
|
|
||||||
gossip_only_stake: 0,
|
|
||||||
}));
|
|
||||||
self.slot_vote_trackers
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(slot, new_slot_tracker.clone());
|
|
||||||
slot_tracker = Some(new_slot_tracker);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slot_tracker.unwrap()
|
pub(crate) fn get_slot_vote_tracker(&self, slot: Slot) -> Option<Arc<RwLock<SlotVoteTracker>>> {
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_slot_vote_tracker(&self, slot: Slot) -> Option<Arc<RwLock<SlotVoteTracker>>> {
|
|
||||||
self.slot_vote_trackers.read().unwrap().get(&slot).cloned()
|
self.slot_vote_trackers.read().unwrap().get(&slot).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_authorized_voter(&self, pubkey: &Pubkey, slot: Slot) -> Option<Pubkey> {
|
|
||||||
let epoch = self.epoch_schedule.get_epoch(slot);
|
|
||||||
self.epoch_authorized_voters
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.get(&epoch)
|
|
||||||
.map(|epoch_authorized_voters| epoch_authorized_voters.get(pubkey))
|
|
||||||
.unwrap_or(None)
|
|
||||||
.cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn vote_contains_authorized_voter(
|
|
||||||
vote_tx: &Transaction,
|
|
||||||
authorized_voter: &Pubkey,
|
|
||||||
) -> bool {
|
|
||||||
let message = &vote_tx.message;
|
|
||||||
for (i, key) in message.account_keys.iter().enumerate() {
|
|
||||||
if message.is_signer(i) && key == authorized_voter {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn insert_vote(&self, slot: Slot, pubkey: Pubkey) {
|
pub(crate) fn insert_vote(&self, slot: Slot, pubkey: Pubkey) {
|
||||||
let mut w_slot_vote_trackers = self.slot_vote_trackers.write().unwrap();
|
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 slot_vote_tracker = w_slot_vote_trackers.entry(slot).or_default();
|
||||||
@ -190,59 +136,16 @@ impl VoteTracker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn progress_leader_schedule_epoch(&self, root_bank: &Bank) {
|
|
||||||
// Update with any newly calculated epoch state about future epochs
|
|
||||||
let start_leader_schedule_epoch = *self.leader_schedule_epoch.read().unwrap();
|
|
||||||
let mut greatest_leader_schedule_epoch = start_leader_schedule_epoch;
|
|
||||||
for leader_schedule_epoch in
|
|
||||||
start_leader_schedule_epoch..=root_bank.get_leader_schedule_epoch(root_bank.slot())
|
|
||||||
{
|
|
||||||
let exists = self
|
|
||||||
.epoch_authorized_voters
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.contains_key(&leader_schedule_epoch);
|
|
||||||
if !exists {
|
|
||||||
let epoch_authorized_voters = root_bank
|
|
||||||
.epoch_stakes(leader_schedule_epoch)
|
|
||||||
.unwrap()
|
|
||||||
.epoch_authorized_voters()
|
|
||||||
.clone();
|
|
||||||
self.epoch_authorized_voters
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(leader_schedule_epoch, epoch_authorized_voters);
|
|
||||||
greatest_leader_schedule_epoch = leader_schedule_epoch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if greatest_leader_schedule_epoch != start_leader_schedule_epoch {
|
|
||||||
*self.leader_schedule_epoch.write().unwrap() = greatest_leader_schedule_epoch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn purge_stale_state(&self, root_bank: &Bank) {
|
fn purge_stale_state(&self, root_bank: &Bank) {
|
||||||
// Purge any outdated slot data
|
// Purge any outdated slot data
|
||||||
let new_root = root_bank.slot();
|
let new_root = root_bank.slot();
|
||||||
let root_epoch = root_bank.epoch();
|
|
||||||
self.slot_vote_trackers
|
self.slot_vote_trackers
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.retain(|slot, _| *slot >= new_root);
|
.retain(|slot, _| *slot >= new_root);
|
||||||
|
|
||||||
let current_epoch = *self.current_epoch.read().unwrap();
|
|
||||||
if root_epoch != current_epoch {
|
|
||||||
// If root moved to a new epoch, purge outdated state
|
|
||||||
self.epoch_authorized_voters
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.retain(|epoch, _| *epoch >= root_epoch);
|
|
||||||
*self.current_epoch.write().unwrap() = root_epoch;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn progress_with_new_root_bank(&self, root_bank: &Bank) {
|
fn progress_with_new_root_bank(&self, root_bank: &Bank) {
|
||||||
self.progress_leader_schedule_epoch(root_bank);
|
|
||||||
self.purge_stale_state(root_bank);
|
self.purge_stale_state(root_bank);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -785,39 +688,6 @@ impl ClusterInfoVoteListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_gossip_votes(
|
|
||||||
vote_tracker: &VoteTracker,
|
|
||||||
vote_pubkey: &Pubkey,
|
|
||||||
vote: &Vote,
|
|
||||||
gossip_tx: &Transaction,
|
|
||||||
) -> bool {
|
|
||||||
if vote.slots.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let last_vote_slot = vote.slots.last().unwrap();
|
|
||||||
// Votes from gossip need to be verified as they have not been
|
|
||||||
// verified by the replay pipeline. Determine the authorized voter
|
|
||||||
// based on the last vote slot. This will drop votes from authorized
|
|
||||||
// voters trying to make votes for slots earlier than the epoch for
|
|
||||||
// which they are authorized
|
|
||||||
let actual_authorized_voter =
|
|
||||||
vote_tracker.get_authorized_voter(vote_pubkey, *last_vote_slot);
|
|
||||||
|
|
||||||
if actual_authorized_voter.is_none() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Voting without the correct authorized pubkey, dump the vote
|
|
||||||
if !VoteTracker::vote_contains_authorized_voter(
|
|
||||||
gossip_tx,
|
|
||||||
&actual_authorized_voter.unwrap(),
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
fn filter_and_confirm_with_new_votes(
|
fn filter_and_confirm_with_new_votes(
|
||||||
vote_tracker: &VoteTracker,
|
vote_tracker: &VoteTracker,
|
||||||
gossip_vote_txs: Vec<Transaction>,
|
gossip_vote_txs: Vec<Transaction>,
|
||||||
@ -833,17 +703,12 @@ impl ClusterInfoVoteListener {
|
|||||||
let mut new_optimistic_confirmed_slots = vec![];
|
let mut new_optimistic_confirmed_slots = vec![];
|
||||||
|
|
||||||
// Process votes from gossip and ReplayStage
|
// Process votes from gossip and ReplayStage
|
||||||
for (is_gossip, (vote_pubkey, vote, _)) in gossip_vote_txs
|
let votes = gossip_vote_txs
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|gossip_tx| {
|
.filter_map(vote_transaction::parse_vote_transaction)
|
||||||
vote_transaction::parse_vote_transaction(gossip_tx)
|
.zip(repeat(/*is_gossip:*/ true))
|
||||||
.filter(|(vote_pubkey, vote, _)| {
|
.chain(replayed_votes.into_iter().zip(repeat(/*is_gossip:*/ false)));
|
||||||
Self::filter_gossip_votes(vote_tracker, vote_pubkey, vote, gossip_tx)
|
for ((vote_pubkey, vote, _), is_gossip) in votes {
|
||||||
})
|
|
||||||
.map(|v| (true, v))
|
|
||||||
})
|
|
||||||
.chain(replayed_votes.into_iter().map(|v| (false, v)))
|
|
||||||
{
|
|
||||||
Self::track_new_votes_and_notify_confirmations(
|
Self::track_new_votes_and_notify_confirmations(
|
||||||
vote,
|
vote,
|
||||||
&vote_pubkey,
|
&vote_pubkey,
|
||||||
@ -991,73 +856,6 @@ mod tests {
|
|||||||
assert_eq!(packet_batches.len(), 1);
|
assert_eq!(packet_batches.len(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_vote_contains_authorized_voter(hash: Option<Hash>) {
|
|
||||||
let node_keypair = Keypair::new();
|
|
||||||
let vote_keypair = Keypair::new();
|
|
||||||
let authorized_voter = Keypair::new();
|
|
||||||
|
|
||||||
let vote_tx = vote_transaction::new_vote_transaction(
|
|
||||||
vec![0],
|
|
||||||
Hash::default(),
|
|
||||||
Hash::default(),
|
|
||||||
&node_keypair,
|
|
||||||
&vote_keypair,
|
|
||||||
&authorized_voter,
|
|
||||||
hash,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check that the two signing keys pass the check
|
|
||||||
assert!(VoteTracker::vote_contains_authorized_voter(
|
|
||||||
&vote_tx,
|
|
||||||
&node_keypair.pubkey()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(VoteTracker::vote_contains_authorized_voter(
|
|
||||||
&vote_tx,
|
|
||||||
&authorized_voter.pubkey()
|
|
||||||
));
|
|
||||||
|
|
||||||
// Non signing key shouldn't pass the check
|
|
||||||
assert!(!VoteTracker::vote_contains_authorized_voter(
|
|
||||||
&vote_tx,
|
|
||||||
&vote_keypair.pubkey()
|
|
||||||
));
|
|
||||||
|
|
||||||
// Set the authorized voter == vote keypair
|
|
||||||
let vote_tx = vote_transaction::new_vote_transaction(
|
|
||||||
vec![0],
|
|
||||||
Hash::default(),
|
|
||||||
Hash::default(),
|
|
||||||
&node_keypair,
|
|
||||||
&vote_keypair,
|
|
||||||
&vote_keypair,
|
|
||||||
hash,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check that the node_keypair and vote keypair pass the authorized voter check
|
|
||||||
assert!(VoteTracker::vote_contains_authorized_voter(
|
|
||||||
&vote_tx,
|
|
||||||
&node_keypair.pubkey()
|
|
||||||
));
|
|
||||||
|
|
||||||
assert!(VoteTracker::vote_contains_authorized_voter(
|
|
||||||
&vote_tx,
|
|
||||||
&vote_keypair.pubkey()
|
|
||||||
));
|
|
||||||
|
|
||||||
// The other keypair should not pass the check
|
|
||||||
assert!(!VoteTracker::vote_contains_authorized_voter(
|
|
||||||
&vote_tx,
|
|
||||||
&authorized_voter.pubkey()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_vote_contains_authorized_voter() {
|
|
||||||
run_vote_contains_authorized_voter(None);
|
|
||||||
run_vote_contains_authorized_voter(Some(Hash::default()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_new_root() {
|
fn test_update_new_root() {
|
||||||
let (vote_tracker, bank, _, _) = setup();
|
let (vote_tracker, bank, _, _) = setup();
|
||||||
@ -1091,15 +889,11 @@ mod tests {
|
|||||||
.get_first_slot_in_epoch(current_epoch + 1),
|
.get_first_slot_in_epoch(current_epoch + 1),
|
||||||
);
|
);
|
||||||
vote_tracker.progress_with_new_root_bank(&new_epoch_bank);
|
vote_tracker.progress_with_new_root_bank(&new_epoch_bank);
|
||||||
assert_eq!(
|
|
||||||
*vote_tracker.current_epoch.read().unwrap(),
|
|
||||||
current_epoch + 1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_new_leader_schedule_epoch() {
|
fn test_update_new_leader_schedule_epoch() {
|
||||||
let (vote_tracker, bank, _, _) = setup();
|
let (_, bank, _, _) = setup();
|
||||||
|
|
||||||
// Check outdated slots are purged with new root
|
// Check outdated slots are purged with new root
|
||||||
let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
||||||
@ -1117,25 +911,6 @@ mod tests {
|
|||||||
bank.get_leader_schedule_epoch(next_leader_schedule_computed),
|
bank.get_leader_schedule_epoch(next_leader_schedule_computed),
|
||||||
next_leader_schedule_epoch
|
next_leader_schedule_epoch
|
||||||
);
|
);
|
||||||
let next_leader_schedule_bank =
|
|
||||||
Bank::new_from_parent(&bank, &Pubkey::default(), next_leader_schedule_computed);
|
|
||||||
vote_tracker.progress_leader_schedule_epoch(&next_leader_schedule_bank);
|
|
||||||
assert_eq!(
|
|
||||||
*vote_tracker.leader_schedule_epoch.read().unwrap(),
|
|
||||||
next_leader_schedule_epoch
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
vote_tracker
|
|
||||||
.epoch_authorized_voters
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.get(&next_leader_schedule_epoch)
|
|
||||||
.unwrap(),
|
|
||||||
next_leader_schedule_bank
|
|
||||||
.epoch_stakes(next_leader_schedule_epoch)
|
|
||||||
.unwrap()
|
|
||||||
.epoch_authorized_voters()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1577,59 +1352,6 @@ mod tests {
|
|||||||
run_test_process_votes3(Some(Hash::default()));
|
run_test_process_votes3(Some(Hash::default()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_voters_by_epoch() {
|
|
||||||
// Create some voters at genesis
|
|
||||||
let (vote_tracker, bank, validator_voting_keypairs, _) = setup();
|
|
||||||
let last_known_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
|
||||||
let last_known_slot = bank
|
|
||||||
.epoch_schedule()
|
|
||||||
.get_last_slot_in_epoch(last_known_epoch);
|
|
||||||
|
|
||||||
// Check we can get the authorized voters
|
|
||||||
for keypairs in &validator_voting_keypairs {
|
|
||||||
assert!(vote_tracker
|
|
||||||
.get_authorized_voter(&keypairs.vote_keypair.pubkey(), last_known_slot)
|
|
||||||
.is_some());
|
|
||||||
assert!(vote_tracker
|
|
||||||
.get_authorized_voter(&keypairs.vote_keypair.pubkey(), last_known_slot + 1)
|
|
||||||
.is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the set of relevant voters for the next epoch
|
|
||||||
let new_epoch = last_known_epoch + 1;
|
|
||||||
let first_slot_in_new_epoch = bank.epoch_schedule().get_first_slot_in_epoch(new_epoch);
|
|
||||||
let new_keypairs: Vec<_> = (0..10).map(|_| ValidatorVoteKeypairs::new_rand()).collect();
|
|
||||||
let new_epoch_authorized_voters: HashMap<_, _> = new_keypairs
|
|
||||||
.iter()
|
|
||||||
.chain(validator_voting_keypairs[0..5].iter())
|
|
||||||
.map(|keypair| (keypair.vote_keypair.pubkey(), keypair.vote_keypair.pubkey()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
vote_tracker
|
|
||||||
.epoch_authorized_voters
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(new_epoch, Arc::new(new_epoch_authorized_voters));
|
|
||||||
|
|
||||||
// These keypairs made it into the new epoch
|
|
||||||
for keypairs in new_keypairs
|
|
||||||
.iter()
|
|
||||||
.chain(validator_voting_keypairs[0..5].iter())
|
|
||||||
{
|
|
||||||
assert!(vote_tracker
|
|
||||||
.get_authorized_voter(&keypairs.vote_keypair.pubkey(), first_slot_in_new_epoch)
|
|
||||||
.is_some());
|
|
||||||
}
|
|
||||||
|
|
||||||
// These keypairs were not refreshed in new epoch
|
|
||||||
for keypairs in validator_voting_keypairs[5..10].iter() {
|
|
||||||
assert!(vote_tracker
|
|
||||||
.get_authorized_voter(&keypairs.vote_keypair.pubkey(), first_slot_in_new_epoch)
|
|
||||||
.is_none());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vote_tracker_references() {
|
fn test_vote_tracker_references() {
|
||||||
// Create some voters at genesis
|
// Create some voters at genesis
|
||||||
@ -1695,17 +1417,6 @@ mod tests {
|
|||||||
// Setup next epoch
|
// Setup next epoch
|
||||||
let old_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
let old_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
||||||
let new_epoch = old_epoch + 1;
|
let new_epoch = old_epoch + 1;
|
||||||
let new_epoch_vote_accounts: HashMap<_, _> = vec![(
|
|
||||||
validator0_keypairs.vote_keypair.pubkey(),
|
|
||||||
validator0_keypairs.vote_keypair.pubkey(),
|
|
||||||
)]
|
|
||||||
.into_iter()
|
|
||||||
.collect();
|
|
||||||
vote_tracker
|
|
||||||
.epoch_authorized_voters
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.insert(new_epoch, Arc::new(new_epoch_vote_accounts));
|
|
||||||
|
|
||||||
// Test with votes across two epochs
|
// Test with votes across two epochs
|
||||||
let first_slot_in_new_epoch = bank.epoch_schedule().get_first_slot_in_epoch(new_epoch);
|
let first_slot_in_new_epoch = bank.epoch_schedule().get_first_slot_in_epoch(new_epoch);
|
||||||
@ -1779,29 +1490,6 @@ mod tests {
|
|||||||
optimistically_confirmed_bank,
|
optimistically_confirmed_bank,
|
||||||
));
|
));
|
||||||
|
|
||||||
// Integrity Checks
|
|
||||||
let current_epoch = bank.epoch();
|
|
||||||
let leader_schedule_epoch = bank.get_leader_schedule_epoch(bank.slot());
|
|
||||||
|
|
||||||
// Check the vote tracker has all the known epoch state on construction
|
|
||||||
for epoch in current_epoch..=leader_schedule_epoch {
|
|
||||||
assert_eq!(
|
|
||||||
vote_tracker
|
|
||||||
.epoch_authorized_voters
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.get(&epoch)
|
|
||||||
.unwrap(),
|
|
||||||
bank.epoch_stakes(epoch).unwrap().epoch_authorized_voters()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the epoch state is correct
|
|
||||||
assert_eq!(
|
|
||||||
*vote_tracker.leader_schedule_epoch.read().unwrap(),
|
|
||||||
leader_schedule_epoch,
|
|
||||||
);
|
|
||||||
assert_eq!(*vote_tracker.current_epoch.read().unwrap(), current_epoch);
|
|
||||||
(
|
(
|
||||||
Arc::new(vote_tracker),
|
Arc::new(vote_tracker),
|
||||||
bank,
|
bank,
|
||||||
|
Reference in New Issue
Block a user