parent
a1ab81a896
commit
dad5c62df5
|
@ -13,6 +13,7 @@ use solana_client::{rpc_client::RpcClient, rpc_request::RpcVoteAccountInfo};
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
clock::{self, Slot},
|
clock::{self, Slot},
|
||||||
commitment_config::CommitmentConfig,
|
commitment_config::CommitmentConfig,
|
||||||
|
epoch_schedule::{Epoch, EpochSchedule},
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
signature::{Keypair, KeypairUtil},
|
signature::{Keypair, KeypairUtil},
|
||||||
|
@ -261,6 +262,20 @@ fn new_spinner_progress_bar() -> ProgressBar {
|
||||||
progress_bar
|
progress_bar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Aggregate epoch credit stats and return (total credits, total slots, total epochs)
|
||||||
|
pub fn aggregate_epoch_credits(
|
||||||
|
epoch_credits: &[(Epoch, u64, u64)],
|
||||||
|
epoch_schedule: &EpochSchedule,
|
||||||
|
) -> (u64, u64, u64) {
|
||||||
|
epoch_credits
|
||||||
|
.iter()
|
||||||
|
.fold((0, 0, 0), |acc, (epoch, credits, prev_credits)| {
|
||||||
|
let credits_earned = credits - prev_credits;
|
||||||
|
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
|
||||||
|
(acc.0 + credits_earned, acc.1 + slots_in_epoch, acc.2 + 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_catchup(rpc_client: &RpcClient, node_pubkey: &Pubkey) -> ProcessResult {
|
pub fn process_catchup(rpc_client: &RpcClient, node_pubkey: &Pubkey) -> ProcessResult {
|
||||||
let cluster_nodes = rpc_client.get_cluster_nodes()?;
|
let cluster_nodes = rpc_client.get_cluster_nodes()?;
|
||||||
|
|
||||||
|
@ -551,6 +566,7 @@ pub fn process_show_gossip(rpc_client: &RpcClient) -> ProcessResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) -> ProcessResult {
|
pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) -> ProcessResult {
|
||||||
|
let epoch_schedule = rpc_client.get_epoch_schedule()?;
|
||||||
let vote_accounts = rpc_client.get_vote_accounts()?;
|
let vote_accounts = rpc_client.get_vote_accounts()?;
|
||||||
let total_active_stake = vote_accounts
|
let total_active_stake = vote_accounts
|
||||||
.current
|
.current
|
||||||
|
@ -593,19 +609,21 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
style(format!(
|
style(format!(
|
||||||
" {:<44} {:<44} {} {} {} {}",
|
" {:<44} {:<44} {} {} {} {:>7} {}",
|
||||||
"Identity Pubkey",
|
"Identity Pubkey",
|
||||||
"Vote Account Pubkey",
|
"Vote Account Pubkey",
|
||||||
"Commission",
|
"Commission",
|
||||||
"Last Vote",
|
"Last Vote",
|
||||||
"Root Block",
|
"Root Block",
|
||||||
|
"Uptime",
|
||||||
"Active Stake",
|
"Active Stake",
|
||||||
))
|
))
|
||||||
.bold()
|
.bold()
|
||||||
);
|
);
|
||||||
|
|
||||||
fn print_vote_account(
|
fn print_vote_account(
|
||||||
vote_account: &RpcVoteAccountInfo,
|
vote_account: RpcVoteAccountInfo,
|
||||||
|
epoch_schedule: &EpochSchedule,
|
||||||
total_active_stake: f64,
|
total_active_stake: f64,
|
||||||
use_lamports_unit: bool,
|
use_lamports_unit: bool,
|
||||||
delinquent: bool,
|
delinquent: bool,
|
||||||
|
@ -617,8 +635,20 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||||
format!("{}", v)
|
format!("{}", v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn uptime(epoch_credits: Vec<(Epoch, u64, u64)>, epoch_schedule: &EpochSchedule) -> String {
|
||||||
|
let (total_credits, total_slots, _) =
|
||||||
|
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
|
||||||
|
if total_slots > 0 {
|
||||||
|
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
|
||||||
|
format!("{:.2}%", total_uptime)
|
||||||
|
} else {
|
||||||
|
"-".into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>12}",
|
"{} {:<44} {:<44} {:>9}% {:>8} {:>10} {:>7} {}",
|
||||||
if delinquent {
|
if delinquent {
|
||||||
WARNING.to_string()
|
WARNING.to_string()
|
||||||
} else {
|
} else {
|
||||||
|
@ -629,6 +659,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||||
vote_account.commission,
|
vote_account.commission,
|
||||||
non_zero_or_dash(vote_account.last_vote),
|
non_zero_or_dash(vote_account.last_vote),
|
||||||
non_zero_or_dash(vote_account.root_slot),
|
non_zero_or_dash(vote_account.root_slot),
|
||||||
|
uptime(vote_account.epoch_credits, epoch_schedule),
|
||||||
if vote_account.activated_stake > 0 {
|
if vote_account.activated_stake > 0 {
|
||||||
format!(
|
format!(
|
||||||
"{} ({:.2}%)",
|
"{} ({:.2}%)",
|
||||||
|
@ -641,11 +672,23 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for vote_account in vote_accounts.current.iter() {
|
for vote_account in vote_accounts.current.into_iter() {
|
||||||
print_vote_account(vote_account, total_active_stake, use_lamports_unit, false);
|
print_vote_account(
|
||||||
|
vote_account,
|
||||||
|
&epoch_schedule,
|
||||||
|
total_active_stake,
|
||||||
|
use_lamports_unit,
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for vote_account in vote_accounts.delinquent.iter() {
|
for vote_account in vote_accounts.delinquent.into_iter() {
|
||||||
print_vote_account(vote_account, total_active_stake, use_lamports_unit, true);
|
print_vote_account(
|
||||||
|
vote_account,
|
||||||
|
&epoch_schedule,
|
||||||
|
total_active_stake,
|
||||||
|
use_lamports_unit,
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok("".to_string())
|
Ok("".to_string())
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
use crate::cli::{
|
use crate::{
|
||||||
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
cli::{
|
||||||
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError, ProcessResult,
|
build_balance_message, check_account_for_fee, check_unique_pubkeys,
|
||||||
|
log_instruction_custom_error, CliCommand, CliCommandInfo, CliConfig, CliError,
|
||||||
|
ProcessResult,
|
||||||
|
},
|
||||||
|
cluster_query::aggregate_epoch_credits,
|
||||||
};
|
};
|
||||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||||
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
use solana_clap_utils::{input_parsers::*, input_validators::*};
|
||||||
|
@ -400,33 +404,37 @@ pub fn process_uptime(
|
||||||
if !vote_state.votes.is_empty() {
|
if !vote_state.votes.is_empty() {
|
||||||
println!("Uptime:");
|
println!("Uptime:");
|
||||||
|
|
||||||
let epoch_credits_vec: Vec<(u64, u64, u64)> = vote_state.epoch_credits().copied().collect();
|
let epoch_credits: Vec<(u64, u64, u64)> = if let Some(x) = span {
|
||||||
|
vote_state
|
||||||
let epoch_credits = if let Some(x) = span {
|
.epoch_credits()
|
||||||
epoch_credits_vec.iter().rev().take(x as usize)
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.take(x as usize)
|
||||||
|
.cloned()
|
||||||
|
.collect()
|
||||||
} else {
|
} else {
|
||||||
epoch_credits_vec.iter().rev().take(epoch_credits_vec.len())
|
vote_state.epoch_credits().iter().rev().cloned().collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
if aggregate {
|
if aggregate {
|
||||||
let (credits_earned, slots_in_epoch, epochs): (u64, u64, u64) =
|
let (total_credits, total_slots, epochs) =
|
||||||
epoch_credits.fold((0, 0, 0), |acc, (epoch, credits, prev_credits)| {
|
aggregate_epoch_credits(&epoch_credits, &epoch_schedule);
|
||||||
let credits_earned = credits - prev_credits;
|
if total_slots > 0 {
|
||||||
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
|
let total_uptime = 100_f64 * total_credits as f64 / total_slots as f64;
|
||||||
(acc.0 + credits_earned, acc.1 + slots_in_epoch, acc.2 + 1)
|
println!("{:.2}% over {} epochs", total_uptime, epochs);
|
||||||
});
|
} else {
|
||||||
let total_uptime = credits_earned as f64 / slots_in_epoch as f64;
|
println!("Insufficient voting history available");
|
||||||
println!("{:.2}% over {} epochs", total_uptime * 100_f64, epochs,);
|
}
|
||||||
} else {
|
} else {
|
||||||
for (epoch, credits, prev_credits) in epoch_credits {
|
for (epoch, credits, prev_credits) in epoch_credits {
|
||||||
let credits_earned = credits - prev_credits;
|
let credits_earned = credits - prev_credits;
|
||||||
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(*epoch);
|
let slots_in_epoch = epoch_schedule.get_slots_in_epoch(epoch);
|
||||||
let uptime = credits_earned as f64 / slots_in_epoch as f64;
|
let uptime = credits_earned as f64 / slots_in_epoch as f64;
|
||||||
println!("- epoch: {} {:.2}% uptime", epoch, uptime * 100_f64,);
|
println!("- epoch: {} {:.2}% uptime", epoch, uptime * 100_f64,);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(x) = span {
|
if let Some(x) = span {
|
||||||
if x > epoch_credits_vec.len() as u64 {
|
if x > vote_state.epoch_credits().len() as u64 {
|
||||||
println!("(span longer than available epochs)");
|
println!("(span longer than available epochs)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,10 @@ pub struct RpcVoteAccountInfo {
|
||||||
/// Whether this account is staked for the current epoch
|
/// Whether this account is staked for the current epoch
|
||||||
pub epoch_vote_account: bool,
|
pub epoch_vote_account: bool,
|
||||||
|
|
||||||
|
/// History of how many credits earned by the end of each epoch
|
||||||
|
/// each tuple is (Epoch, credits, prev_credits)
|
||||||
|
pub epoch_credits: Vec<(Epoch, u64, u64)>,
|
||||||
|
|
||||||
/// Most recent slot voted on by this vote account (0 if no votes exist)
|
/// Most recent slot voted on by this vote account (0 if no votes exist)
|
||||||
pub last_vote: u64,
|
pub last_vote: u64,
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,7 @@ impl JsonRpcRequestProcessor {
|
||||||
activated_stake: *activated_stake,
|
activated_stake: *activated_stake,
|
||||||
commission: vote_state.commission,
|
commission: vote_state.commission,
|
||||||
root_slot: vote_state.root_slot.unwrap_or(0),
|
root_slot: vote_state.root_slot.unwrap_or(0),
|
||||||
|
epoch_credits: vote_state.epoch_credits().clone(),
|
||||||
epoch_vote_account,
|
epoch_vote_account,
|
||||||
last_vote,
|
last_vote,
|
||||||
}
|
}
|
||||||
|
@ -1014,7 +1015,10 @@ pub mod tests {
|
||||||
system_transaction,
|
system_transaction,
|
||||||
transaction::TransactionError,
|
transaction::TransactionError,
|
||||||
};
|
};
|
||||||
use solana_vote_program::{vote_instruction, vote_state::VoteInit};
|
use solana_vote_program::{
|
||||||
|
vote_instruction,
|
||||||
|
vote_state::{Vote, VoteInit, MAX_LOCKOUT_HISTORY},
|
||||||
|
};
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
|
@ -1022,20 +1026,23 @@ pub mod tests {
|
||||||
};
|
};
|
||||||
|
|
||||||
const TEST_MINT_LAMPORTS: u64 = 1_000_000;
|
const TEST_MINT_LAMPORTS: u64 = 1_000_000;
|
||||||
|
const TEST_SLOTS_PER_EPOCH: u64 = 50;
|
||||||
|
|
||||||
struct RpcHandler {
|
struct RpcHandler {
|
||||||
io: MetaIoHandler<Meta>,
|
io: MetaIoHandler<Meta>,
|
||||||
meta: Meta,
|
meta: Meta,
|
||||||
bank: Arc<Bank>,
|
bank: Arc<Bank>,
|
||||||
|
bank_forks: Arc<RwLock<BankForks>>,
|
||||||
blockhash: Hash,
|
blockhash: Hash,
|
||||||
alice: Keypair,
|
alice: Keypair,
|
||||||
leader_pubkey: Pubkey,
|
leader_pubkey: Pubkey,
|
||||||
|
leader_vote_keypair: Keypair,
|
||||||
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
block_commitment_cache: Arc<RwLock<BlockCommitmentCache>>,
|
||||||
confirmed_block_signatures: Vec<Signature>,
|
confirmed_block_signatures: Vec<Signature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> RpcHandler {
|
fn start_rpc_handler_with_tx(pubkey: &Pubkey) -> RpcHandler {
|
||||||
let (bank_forks, alice) = new_bank_forks();
|
let (bank_forks, alice, leader_vote_keypair) = new_bank_forks();
|
||||||
let bank = bank_forks.read().unwrap().working_bank();
|
let bank = bank_forks.read().unwrap().working_bank();
|
||||||
|
|
||||||
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
|
let commitment_slot0 = BlockCommitment::new([8; MAX_LOCKOUT_HISTORY]);
|
||||||
|
@ -1077,7 +1084,7 @@ pub mod tests {
|
||||||
|
|
||||||
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
let request_processor = Arc::new(RwLock::new(JsonRpcRequestProcessor::new(
|
||||||
JsonRpcConfig::default(),
|
JsonRpcConfig::default(),
|
||||||
bank_forks,
|
bank_forks.clone(),
|
||||||
block_commitment_cache.clone(),
|
block_commitment_cache.clone(),
|
||||||
blocktree,
|
blocktree,
|
||||||
StorageState::default(),
|
StorageState::default(),
|
||||||
|
@ -1107,9 +1114,11 @@ pub mod tests {
|
||||||
io,
|
io,
|
||||||
meta,
|
meta,
|
||||||
bank,
|
bank,
|
||||||
|
bank_forks,
|
||||||
blockhash,
|
blockhash,
|
||||||
alice,
|
alice,
|
||||||
leader_pubkey,
|
leader_pubkey,
|
||||||
|
leader_vote_keypair,
|
||||||
block_commitment_cache,
|
block_commitment_cache,
|
||||||
confirmed_block_signatures,
|
confirmed_block_signatures,
|
||||||
}
|
}
|
||||||
|
@ -1120,7 +1129,7 @@ pub mod tests {
|
||||||
let bob_pubkey = Pubkey::new_rand();
|
let bob_pubkey = Pubkey::new_rand();
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let validator_exit = create_validator_exit(&exit);
|
let validator_exit = create_validator_exit(&exit);
|
||||||
let (bank_forks, alice) = new_bank_forks();
|
let (bank_forks, alice, _) = new_bank_forks();
|
||||||
let bank = bank_forks.read().unwrap().working_bank();
|
let bank = bank_forks.read().unwrap().working_bank();
|
||||||
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
let block_commitment_cache = Arc::new(RwLock::new(BlockCommitmentCache::default()));
|
||||||
let ledger_path = get_tmp_ledger_path!();
|
let ledger_path = get_tmp_ledger_path!();
|
||||||
|
@ -1630,20 +1639,23 @@ pub mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair) {
|
fn new_bank_forks() -> (Arc<RwLock<BankForks>>, Keypair, Keypair) {
|
||||||
let GenesisConfigInfo {
|
let GenesisConfigInfo {
|
||||||
mut genesis_config,
|
mut genesis_config,
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
..
|
voting_keypair,
|
||||||
} = create_genesis_config(TEST_MINT_LAMPORTS);
|
} = create_genesis_config(TEST_MINT_LAMPORTS);
|
||||||
|
|
||||||
genesis_config.rent.lamports_per_byte_year = 50;
|
genesis_config.rent.lamports_per_byte_year = 50;
|
||||||
genesis_config.rent.exemption_threshold = 2.0;
|
genesis_config.rent.exemption_threshold = 2.0;
|
||||||
|
genesis_config.epoch_schedule =
|
||||||
|
EpochSchedule::custom(TEST_SLOTS_PER_EPOCH, TEST_SLOTS_PER_EPOCH, false);
|
||||||
|
|
||||||
let bank = Bank::new(&genesis_config);
|
let bank = Bank::new(&genesis_config);
|
||||||
(
|
(
|
||||||
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),
|
Arc::new(RwLock::new(BankForks::new(bank.slot(), bank))),
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
|
voting_keypair,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1905,8 +1917,10 @@ pub mod tests {
|
||||||
let RpcHandler {
|
let RpcHandler {
|
||||||
io,
|
io,
|
||||||
meta,
|
meta,
|
||||||
bank,
|
mut bank,
|
||||||
|
bank_forks,
|
||||||
alice,
|
alice,
|
||||||
|
leader_vote_keypair,
|
||||||
..
|
..
|
||||||
} = start_rpc_handler_with_tx(&Pubkey::new_rand());
|
} = start_rpc_handler_with_tx(&Pubkey::new_rand());
|
||||||
|
|
||||||
|
@ -1936,7 +1950,42 @@ pub mod tests {
|
||||||
.expect("process transaction");
|
.expect("process transaction");
|
||||||
assert_eq!(bank.vote_accounts().len(), 2);
|
assert_eq!(bank.vote_accounts().len(), 2);
|
||||||
|
|
||||||
let req = format!(r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts"}}"#);
|
// Advance bank to the next epoch
|
||||||
|
for _ in 0..TEST_SLOTS_PER_EPOCH {
|
||||||
|
bank.freeze();
|
||||||
|
|
||||||
|
let instruction = vote_instruction::vote(
|
||||||
|
&leader_vote_keypair.pubkey(),
|
||||||
|
&leader_vote_keypair.pubkey(),
|
||||||
|
Vote {
|
||||||
|
slots: vec![bank.slot()],
|
||||||
|
hash: bank.hash(),
|
||||||
|
timestamp: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
bank = bank_forks.write().unwrap().insert(Bank::new_from_parent(
|
||||||
|
&bank,
|
||||||
|
&Pubkey::default(),
|
||||||
|
bank.slot() + 1,
|
||||||
|
));
|
||||||
|
|
||||||
|
let transaction = Transaction::new_signed_with_payer(
|
||||||
|
vec![instruction],
|
||||||
|
Some(&alice.pubkey()),
|
||||||
|
&[&alice, &leader_vote_keypair],
|
||||||
|
bank.last_blockhash(),
|
||||||
|
);
|
||||||
|
|
||||||
|
bank.process_transaction(&transaction)
|
||||||
|
.expect("process transaction");
|
||||||
|
}
|
||||||
|
|
||||||
|
let req = format!(
|
||||||
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
|
||||||
|
json!([CommitmentConfig::recent()])
|
||||||
|
);
|
||||||
|
|
||||||
let res = io.handle_request_sync(&req, meta.clone());
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
|
@ -1944,12 +1993,19 @@ pub mod tests {
|
||||||
let vote_account_status: RpcVoteAccountStatus =
|
let vote_account_status: RpcVoteAccountStatus =
|
||||||
serde_json::from_value(result["result"].clone()).unwrap();
|
serde_json::from_value(result["result"].clone()).unwrap();
|
||||||
|
|
||||||
// The bootstrap leader vote account will be delinquent as it has stake but has never
|
// The vote account with no stake should not be present.
|
||||||
// voted. The vote account with no stake should not be present.
|
assert!(vote_account_status.delinquent.is_empty());
|
||||||
assert!(vote_account_status.current.is_empty());
|
|
||||||
assert_eq!(vote_account_status.delinquent.len(), 1);
|
// The leader vote account should be active and have voting history.
|
||||||
for vote_account_info in vote_account_status.delinquent {
|
assert_eq!(vote_account_status.current.len(), 1);
|
||||||
assert_ne!(vote_account_info.activated_stake, 0);
|
let leader_info = &vote_account_status.current[0];
|
||||||
}
|
assert_eq!(
|
||||||
|
leader_info.vote_pubkey,
|
||||||
|
leader_vote_keypair.pubkey().to_string()
|
||||||
|
);
|
||||||
|
assert_ne!(leader_info.activated_stake, 0);
|
||||||
|
// Subtract one because the last vote always carries over to the next epoch
|
||||||
|
let expected_credits = TEST_SLOTS_PER_EPOCH - MAX_LOCKOUT_HISTORY as u64 - 1;
|
||||||
|
assert_eq!(leader_info.epoch_credits, vec![(0, expected_credits, 0)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,8 +334,8 @@ impl VoteState {
|
||||||
/// Each tuple of (Epoch, u64, u64) is read as (epoch, credits, prev_credits), where
|
/// Each tuple of (Epoch, u64, u64) is read as (epoch, credits, prev_credits), where
|
||||||
/// credits for each epoch is credits - prev_credits; while redundant this makes
|
/// credits for each epoch is credits - prev_credits; while redundant this makes
|
||||||
/// calculating rewards over partial epochs nice and simple
|
/// calculating rewards over partial epochs nice and simple
|
||||||
pub fn epoch_credits(&self) -> impl Iterator<Item = &(Epoch, u64, u64)> {
|
pub fn epoch_credits(&self) -> &Vec<(Epoch, u64, u64)> {
|
||||||
self.epoch_credits.iter()
|
&self.epoch_credits
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_expired_votes(&mut self, slot: Slot) {
|
fn pop_expired_votes(&mut self, slot: Slot) {
|
||||||
|
@ -1236,13 +1236,7 @@ mod tests {
|
||||||
let mut vote_state = VoteState::default();
|
let mut vote_state = VoteState::default();
|
||||||
|
|
||||||
assert_eq!(vote_state.credits(), 0);
|
assert_eq!(vote_state.credits(), 0);
|
||||||
assert_eq!(
|
assert_eq!(vote_state.epoch_credits().clone(), vec![]);
|
||||||
vote_state
|
|
||||||
.epoch_credits()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<(Epoch, u64, u64)>>(),
|
|
||||||
vec![]
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut expected = vec![];
|
let mut expected = vec![];
|
||||||
let mut credits = 0;
|
let mut credits = 0;
|
||||||
|
@ -1260,46 +1254,19 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(vote_state.credits(), credits);
|
assert_eq!(vote_state.credits(), credits);
|
||||||
assert_eq!(
|
assert_eq!(vote_state.epoch_credits().clone(), expected);
|
||||||
vote_state
|
|
||||||
.epoch_credits()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<(Epoch, u64, u64)>>(),
|
|
||||||
expected
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vote_state_epoch0_no_credits() {
|
fn test_vote_state_epoch0_no_credits() {
|
||||||
let mut vote_state = VoteState::default();
|
let mut vote_state = VoteState::default();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(vote_state.epoch_credits().len(), 0);
|
||||||
vote_state
|
|
||||||
.epoch_credits()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<(Epoch, u64, u64)>>()
|
|
||||||
.len(),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
vote_state.increment_credits(1);
|
vote_state.increment_credits(1);
|
||||||
assert_eq!(
|
assert_eq!(vote_state.epoch_credits().len(), 0);
|
||||||
vote_state
|
|
||||||
.epoch_credits()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<(Epoch, u64, u64)>>()
|
|
||||||
.len(),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
vote_state.increment_credits(2);
|
vote_state.increment_credits(2);
|
||||||
assert_eq!(
|
assert_eq!(vote_state.epoch_credits().len(), 1);
|
||||||
vote_state
|
|
||||||
.epoch_credits()
|
|
||||||
.cloned()
|
|
||||||
.collect::<Vec<(Epoch, u64, u64)>>()
|
|
||||||
.len(),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in New Issue