Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
Determine vote_state ahead of time (#8303) (#8521)
Browse files Browse the repository at this point in the history
automerge
  • Loading branch information
mergify[bot] authored Feb 28, 2020
1 parent 7b23e79 commit 2c3632a
Show file tree
Hide file tree
Showing 8 changed files with 594 additions and 55 deletions.
2 changes: 1 addition & 1 deletion cli/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ pub fn process_show_vote_account(
build_balance_message(vote_account.lamports, use_lamports_unit, true)
);
println!("Validator Identity: {}", vote_state.node_pubkey);
println!("Authorized Voter: {}", vote_state.authorized_voter);
println!("Authorized Voter: {:?}", vote_state.authorized_voters());
println!(
"Authorized Withdrawer: {}",
vote_state.authorized_withdrawer
Expand Down
9 changes: 9 additions & 0 deletions core/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ use solana_metrics::datapoint_info;
use solana_runtime::bank::Bank;
use solana_sdk::{
clock::{Slot, DEFAULT_SLOTS_PER_TURN},
epoch_schedule::MAX_LEADER_SCHEDULE_EPOCH_OFFSET,
genesis_config::GenesisConfig,
hash::Hash,
pubkey::Pubkey,
Expand Down Expand Up @@ -569,6 +570,14 @@ fn new_banks_from_blockstore(
error!("Failed to load genesis from {:?}: {}", blockstore_path, err);
process::exit(1);
});

// This needs to be limited otherwise the state in the VoteAccount data
// grows too large
let leader_schedule_slot_offset = genesis_config.epoch_schedule.leader_schedule_slot_offset;
let slots_per_epoch = genesis_config.epoch_schedule.slots_per_epoch;
let leader_epoch_offset = (leader_schedule_slot_offset + slots_per_epoch - 1) / slots_per_epoch;
assert!(leader_epoch_offset <= MAX_LEADER_SCHEDULE_EPOCH_OFFSET);

let genesis_hash = genesis_config.hash();
info!("genesis hash: {}", genesis_hash);

Expand Down
102 changes: 102 additions & 0 deletions programs/vote/src/authorized_voters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use log::*;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::pubkey::Pubkey;
use std::collections::BTreeMap;

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct AuthorizedVoters {
authorized_voters: BTreeMap<u64, Pubkey>,
}

impl AuthorizedVoters {
pub fn new(epoch: u64, pubkey: Pubkey) -> Self {
let mut authorized_voters = BTreeMap::new();
authorized_voters.insert(epoch, pubkey);
Self { authorized_voters }
}

pub fn get_authorized_voter(&self, epoch: u64) -> Option<Pubkey> {
self.get_or_calculate_authorized_voter_for_epoch(epoch)
.map(|(pubkey, _)| pubkey)
}

pub fn get_and_cache_authorized_voter_for_epoch(&mut self, epoch: u64) -> Option<Pubkey> {
let res = self.get_or_calculate_authorized_voter_for_epoch(epoch);

res.map(|(pubkey, existed)| {
if !existed {
self.authorized_voters.insert(epoch, pubkey);
}
pubkey
})
}

pub fn insert(&mut self, epoch: u64, authorized_voter: Pubkey) {
self.authorized_voters.insert(epoch, authorized_voter);
}

pub fn purge_authorized_voters(&mut self, current_epoch: u64) -> bool {
// Iterate through the keys in order, filtering out the ones
// less than the current epoch
let expired_keys: Vec<_> = self
.authorized_voters
.range(0..current_epoch)
.map(|(authorized_epoch, _)| *authorized_epoch)
.collect();

for key in expired_keys {
self.authorized_voters.remove(&key);
}

// Have to uphold this invariant b/c this is
// 1) The check for whether the vote state is initialized
// 2) How future authorized voters for uninitialized epochs are set
// by this function
assert!(!self.authorized_voters.is_empty());
true
}

pub fn is_empty(&self) -> bool {
self.authorized_voters.is_empty()
}

pub fn first(&self) -> Option<(&u64, &Pubkey)> {
self.authorized_voters.iter().next()
}

pub fn last(&self) -> Option<(&u64, &Pubkey)> {
self.authorized_voters.iter().next_back()
}

pub fn len(&self) -> usize {
self.authorized_voters.len()
}

pub fn contains(&self, epoch: u64) -> bool {
self.authorized_voters.get(&epoch).is_some()
}

// Returns the authorized voter at the given epoch if the epoch is >= the
// current epoch, and a bool indicating whether the entry for this epoch
// exists in the self.authorized_voter map
fn get_or_calculate_authorized_voter_for_epoch(&self, epoch: u64) -> Option<(Pubkey, bool)> {
let res = self.authorized_voters.get(&epoch);
if res.is_none() {
// If no authorized voter has been set yet for this epoch,
// this must mean the authorized voter remains unchanged
// from the latest epoch before this one
let res = self.authorized_voters.range(0..epoch).next_back();

if res.is_none() {
warn!(
"Tried to query for the authorized voter of an epoch earlier
than the current epoch. Earlier epochs have been purged"
);
}

res.map(|(_, pubkey)| (*pubkey, false))
} else {
res.map(|pubkey| (*pubkey, true))
}
}
}
1 change: 1 addition & 0 deletions programs/vote/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod authorized_voters;
pub mod vote_instruction;
pub mod vote_state;

Expand Down
16 changes: 11 additions & 5 deletions programs/vote/src/vote_instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,11 @@ pub fn update_node(
authorized_voter_pubkey: &Pubkey,
node_pubkey: &Pubkey,
) -> Instruction {
let account_metas =
vec![AccountMeta::new(*vote_pubkey, false)].with_signer(authorized_voter_pubkey);
let account_metas = vec![
AccountMeta::new(*vote_pubkey, false),
AccountMeta::new_readonly(sysvar::clock::id(), false),
]
.with_signer(authorized_voter_pubkey);

Instruction::new(
id(),
Expand Down Expand Up @@ -205,9 +208,12 @@ pub fn process_instruction(
&signers,
&Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
),
VoteInstruction::UpdateNode(node_pubkey) => {
vote_state::update_node(me, &node_pubkey, &signers)
}
VoteInstruction::UpdateNode(node_pubkey) => vote_state::update_node(
me,
&node_pubkey,
&signers,
&Clock::from_keyed_account(next_keyed_account(keyed_accounts)?)?,
),
VoteInstruction::Vote(vote) => {
inc_new_counter_info!("vote-native", 1);
vote_state::process_vote(
Expand Down
Loading

0 comments on commit 2c3632a

Please sign in to comment.