Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -562,6 +563,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