Confidence implementation (#5993)

* Change confidence parameters

* Add status_cache_ancestors to get all relevant ancestors of a bank including roots from status cache

* Fix and add tests

* Clippy
This commit is contained in:
carllin 2019-09-20 19:38:56 -07:00 committed by GitHub
parent fd6e7020eb
commit 8240d1fe0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 353 additions and 277 deletions

View File

@ -1,113 +1,59 @@
use crate::consensus::StakeLockout;
use crate::result::{Error, Result};
use crate::service::Service;
use std::collections::{HashMap, HashSet};
use solana_runtime::bank::Bank;
use solana_vote_api::vote_state::VoteState;
use solana_vote_api::vote_state::MAX_LOCKOUT_HISTORY;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::mpsc::{channel, Receiver, RecvTimeoutError, Sender};
use std::sync::{Arc, RwLock};
use std::thread::{self, Builder, JoinHandle};
use std::time::Duration;
#[derive(Debug, Default, PartialEq)]
pub struct Confidence {
fork_stakes: u64,
total_stake: u64,
lockouts: u64,
stake_weighted_lockouts: u128,
#[derive(Debug, Default, Eq, PartialEq)]
pub struct BankConfidence {
confidence: [u64; MAX_LOCKOUT_HISTORY],
}
impl Confidence {
pub fn new(fork_stakes: u64, total_stake: u64, lockouts: u64) -> Self {
Self {
fork_stakes,
total_stake,
lockouts,
stake_weighted_lockouts: 0,
}
impl BankConfidence {
pub fn increase_confirmation_stake(&mut self, confirmation_count: usize, stake: u64) {
assert!(confirmation_count > 0 && confirmation_count <= MAX_LOCKOUT_HISTORY);
self.confidence[confirmation_count - 1] += stake;
}
pub fn new_with_stake_weighted(
fork_stakes: u64,
total_stake: u64,
lockouts: u64,
stake_weighted_lockouts: u128,
) -> Self {
Self {
fork_stakes,
total_stake,
lockouts,
stake_weighted_lockouts,
}
pub fn get_confirmation_stake(&mut self, confirmation_count: usize) -> u64 {
assert!(confirmation_count > 0 && confirmation_count <= MAX_LOCKOUT_HISTORY);
self.confidence[confirmation_count - 1]
}
}
#[derive(Default, PartialEq)]
#[derive(Default)]
pub struct ForkConfidenceCache {
confidence: HashMap<u64, Confidence>,
bank_confidence: HashMap<u64, BankConfidence>,
_total_stake: u64,
}
impl ForkConfidenceCache {
pub fn cache_fork_confidence(
&mut self,
fork: u64,
fork_stakes: u64,
total_stake: u64,
lockouts: u64,
) {
self.confidence
.entry(fork)
.and_modify(|entry| {
entry.fork_stakes = fork_stakes;
entry.total_stake = total_stake;
entry.lockouts = lockouts;
})
.or_insert_with(|| Confidence::new(fork_stakes, total_stake, lockouts));
pub fn new(bank_confidence: HashMap<u64, BankConfidence>, total_stake: u64) -> Self {
Self {
bank_confidence,
_total_stake: total_stake,
}
}
pub fn cache_stake_weighted_lockouts(&mut self, fork: u64, stake_weighted_lockouts: u128) {
self.confidence
.entry(fork)
.and_modify(|entry| {
entry.stake_weighted_lockouts = stake_weighted_lockouts;
})
.or_insert(Confidence {
fork_stakes: 0,
total_stake: 0,
lockouts: 0,
stake_weighted_lockouts,
});
}
pub fn get_fork_confidence(&self, fork: u64) -> Option<&Confidence> {
self.confidence.get(&fork)
}
pub fn prune_confidence_cache(&mut self, ancestors: &HashMap<u64, HashSet<u64>>, root: u64) {
// For Every slot `s` in this cache must exist some bank `b` in BankForks with
// `b.slot() == s`, and because `ancestors` has an entry for every bank in BankForks,
// then there must be an entry in `ancestors` for every slot in `self.confidence`
self.confidence
.retain(|slot, _| slot == &root || ancestors[&slot].contains(&root));
pub fn get_fork_confidence(&self, fork: u64) -> Option<&BankConfidence> {
self.bank_confidence.get(&fork)
}
}
pub struct ConfidenceAggregationData {
lockouts: HashMap<u64, StakeLockout>,
root: Option<u64>,
ancestors: Arc<HashMap<u64, HashSet<u64>>>,
bank: Arc<Bank>,
total_staked: u64,
}
impl ConfidenceAggregationData {
pub fn new(
lockouts: HashMap<u64, StakeLockout>,
root: Option<u64>,
ancestors: Arc<HashMap<u64, HashSet<u64>>>,
total_staked: u64,
) -> Self {
Self {
lockouts,
root,
ancestors,
total_staked,
}
pub fn new(bank: Arc<Bank>, total_staked: u64) -> Self {
Self { bank, total_staked }
}
}
@ -116,38 +62,17 @@ pub struct AggregateConfidenceService {
}
impl AggregateConfidenceService {
pub fn aggregate_confidence(
root: Option<u64>,
ancestors: &HashMap<u64, HashSet<u64>>,
stake_lockouts: &HashMap<u64, StakeLockout>,
) -> HashMap<u64, u128> {
let mut stake_weighted_lockouts: HashMap<u64, u128> = HashMap::new();
for (fork, lockout) in stake_lockouts.iter() {
if root.is_none() || *fork >= root.unwrap() {
let mut slot_with_ancestors = vec![*fork];
slot_with_ancestors.extend(ancestors.get(&fork).unwrap_or(&HashSet::new()));
for slot in slot_with_ancestors {
if root.is_none() || slot >= root.unwrap() {
let entry = stake_weighted_lockouts.entry(slot).or_default();
*entry += u128::from(lockout.lockout()) * u128::from(lockout.stake());
}
}
}
}
stake_weighted_lockouts
}
pub fn new(
exit: &Arc<AtomicBool>,
fork_confidence_cache: Arc<RwLock<ForkConfidenceCache>>,
) -> (Sender<ConfidenceAggregationData>, Self) {
let (lockouts_sender, lockouts_receiver): (
let (sender, receiver): (
Sender<ConfidenceAggregationData>,
Receiver<ConfidenceAggregationData>,
) = channel();
let exit_ = exit.clone();
(
lockouts_sender,
sender,
Self {
t_confidence: Builder::new()
.name("solana-aggregate-stake-lockouts".to_string())
@ -155,54 +80,121 @@ impl AggregateConfidenceService {
if exit_.load(Ordering::Relaxed) {
break;
}
if let Ok(aggregation_data) = lockouts_receiver.try_recv() {
let stake_weighted_lockouts = Self::aggregate_confidence(
aggregation_data.root,
&aggregation_data.ancestors,
&aggregation_data.lockouts,
);
let mut w_fork_confidence_cache =
fork_confidence_cache.write().unwrap();
// Cache the confidence values
for (fork, stake_lockout) in aggregation_data.lockouts.iter() {
if aggregation_data.root.is_none()
|| *fork >= aggregation_data.root.unwrap()
{
w_fork_confidence_cache.cache_fork_confidence(
*fork,
stake_lockout.stake(),
aggregation_data.total_staked,
stake_lockout.lockout(),
);
}
if let Err(e) = Self::run(&receiver, &fork_confidence_cache, &exit_) {
match e {
Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break,
Error::RecvTimeoutError(RecvTimeoutError::Timeout) => (),
_ => info!(
"Unexpected error from AggregateConfidenceService: {:?}",
e
),
}
// Cache the stake weighted lockouts
for (fork, stake_weighted_lockout) in stake_weighted_lockouts.iter() {
if aggregation_data.root.is_none()
|| *fork >= aggregation_data.root.unwrap()
{
w_fork_confidence_cache.cache_stake_weighted_lockouts(
*fork,
*stake_weighted_lockout,
)
}
}
if let Some(root) = aggregation_data.root {
w_fork_confidence_cache
.prune_confidence_cache(&aggregation_data.ancestors, root);
}
drop(w_fork_confidence_cache);
}
})
.unwrap(),
},
)
}
fn run(
receiver: &Receiver<ConfidenceAggregationData>,
fork_confidence_cache: &RwLock<ForkConfidenceCache>,
exit: &Arc<AtomicBool>,
) -> Result<()> {
loop {
if exit.load(Ordering::Relaxed) {
return Ok(());
}
let mut aggregation_data = receiver.recv_timeout(Duration::from_secs(1))?;
while let Ok(new_data) = receiver.try_recv() {
aggregation_data = new_data;
}
let ancestors = aggregation_data.bank.status_cache_ancestors();
if ancestors.is_empty() {
continue;
}
let bank_confidence = Self::aggregate_confidence(&ancestors, &aggregation_data.bank);
let mut new_fork_confidence =
ForkConfidenceCache::new(bank_confidence, aggregation_data.total_staked);
let mut w_fork_confidence_cache = fork_confidence_cache.write().unwrap();
std::mem::swap(&mut *w_fork_confidence_cache, &mut new_fork_confidence);
}
}
pub fn aggregate_confidence(ancestors: &[u64], bank: &Bank) -> HashMap<u64, BankConfidence> {
assert!(!ancestors.is_empty());
// Check ancestors is sorted
for a in ancestors.windows(2) {
assert!(a[0] < a[1]);
}
let mut confidence = HashMap::new();
for (_, (lamports, account)) in bank.vote_accounts().into_iter() {
if lamports == 0 {
continue;
}
let vote_state = VoteState::from(&account);
if vote_state.is_none() {
continue;
}
let vote_state = vote_state.unwrap();
Self::aggregate_confidence_for_vote_account(
&mut confidence,
&vote_state,
ancestors,
lamports,
);
}
confidence
}
fn aggregate_confidence_for_vote_account(
confidence: &mut HashMap<u64, BankConfidence>,
vote_state: &VoteState,
ancestors: &[u64],
lamports: u64,
) {
assert!(!ancestors.is_empty());
let mut ancestors_index = 0;
if let Some(root) = vote_state.root_slot {
for (i, a) in ancestors.iter().enumerate() {
if *a <= root {
confidence
.entry(*a)
.or_insert_with(BankConfidence::default)
.increase_confirmation_stake(MAX_LOCKOUT_HISTORY, lamports);
} else {
ancestors_index = i;
break;
}
}
}
for vote in &vote_state.votes {
while ancestors[ancestors_index] <= vote.slot {
confidence
.entry(ancestors[ancestors_index])
.or_insert_with(BankConfidence::default)
.increase_confirmation_stake(vote.confirmation_count as usize, lamports);
ancestors_index += 1;
if ancestors_index == ancestors.len() {
return;
}
}
}
}
}
impl Service for AggregateConfidenceService {
@ -216,64 +208,169 @@ impl Service for AggregateConfidenceService {
#[cfg(test)]
mod tests {
use super::*;
use crate::genesis_utils::{create_genesis_block, GenesisBlockInfo};
use solana_sdk::pubkey::Pubkey;
use solana_stake_api::stake_state;
use solana_vote_api::vote_state;
#[test]
fn test_fork_confidence_cache() {
let mut cache = ForkConfidenceCache::default();
let fork = 0;
assert!(cache.confidence.get(&fork).is_none());
cache.cache_fork_confidence(fork, 11, 12, 13);
assert_eq!(
cache.confidence.get(&fork).unwrap(),
&Confidence {
fork_stakes: 11,
total_stake: 12,
lockouts: 13,
stake_weighted_lockouts: 0,
}
);
// Ensure that {fork_stakes, total_stake, lockouts} and stake_weighted_lockouts
// can be updated separately
cache.cache_stake_weighted_lockouts(fork, 20);
assert_eq!(
cache.confidence.get(&fork).unwrap(),
&Confidence {
fork_stakes: 11,
total_stake: 12,
lockouts: 13,
stake_weighted_lockouts: 20,
}
);
cache.cache_fork_confidence(fork, 21, 22, 23);
assert_eq!(
cache.confidence.get(&fork).unwrap().stake_weighted_lockouts,
20,
);
fn test_bank_confidence() {
let mut cache = BankConfidence::default();
assert_eq!(cache.get_confirmation_stake(1), 0);
cache.increase_confirmation_stake(1, 10);
assert_eq!(cache.get_confirmation_stake(1), 10);
cache.increase_confirmation_stake(1, 20);
assert_eq!(cache.get_confirmation_stake(1), 30);
}
#[test]
fn test_aggregate_confidence() {
let stakes = vec![
(0, StakeLockout::new(1, 32)),
(1, StakeLockout::new(1, 24)),
(2, StakeLockout::new(1, 16)),
(3, StakeLockout::new(1, 8)),
]
.into_iter()
.collect();
let ancestors = vec![
(0, HashSet::new()),
(1, vec![0].into_iter().collect()),
(2, vec![0, 1].into_iter().collect()),
(3, vec![0, 1, 2].into_iter().collect()),
]
.into_iter()
.collect();
let stake_weighted_lockouts =
AggregateConfidenceService::aggregate_confidence(Some(1), &ancestors, &stakes);
assert!(stake_weighted_lockouts.get(&0).is_none());
assert_eq!(*stake_weighted_lockouts.get(&1).unwrap(), 8 + 16 + 24);
assert_eq!(*stake_weighted_lockouts.get(&2).unwrap(), 8 + 16);
assert_eq!(*stake_weighted_lockouts.get(&3).unwrap(), 8);
fn test_aggregate_confidence_for_vote_account_1() {
let ancestors = vec![3, 4, 5, 7, 9, 11];
let mut confidence = HashMap::new();
let lamports = 5;
let mut vote_state = VoteState::new(&Pubkey::default(), &Pubkey::default(), 0);
let root = ancestors.last().unwrap();
vote_state.root_slot = Some(*root);
AggregateConfidenceService::aggregate_confidence_for_vote_account(
&mut confidence,
&vote_state,
&ancestors,
lamports,
);
for a in ancestors {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(MAX_LOCKOUT_HISTORY, lamports);
assert_eq!(*confidence.get(&a).unwrap(), expected);
}
}
#[test]
fn test_aggregate_confidence_for_vote_account_2() {
let ancestors = vec![3, 4, 5, 7, 9, 11];
let mut confidence = HashMap::new();
let lamports = 5;
let mut vote_state = VoteState::new(&Pubkey::default(), &Pubkey::default(), 0);
let root = ancestors[2];
vote_state.root_slot = Some(root);
vote_state.process_slot_vote_unchecked(*ancestors.last().unwrap());
AggregateConfidenceService::aggregate_confidence_for_vote_account(
&mut confidence,
&vote_state,
&ancestors,
lamports,
);
for a in ancestors {
if a <= root {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(MAX_LOCKOUT_HISTORY, lamports);
assert_eq!(*confidence.get(&a).unwrap(), expected);
} else {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(1, lamports);
assert_eq!(*confidence.get(&a).unwrap(), expected);
}
}
}
#[test]
fn test_aggregate_confidence_for_vote_account_3() {
let ancestors = vec![3, 4, 5, 7, 9, 10, 11];
let mut confidence = HashMap::new();
let lamports = 5;
let mut vote_state = VoteState::new(&Pubkey::default(), &Pubkey::default(), 0);
let root = ancestors[2];
vote_state.root_slot = Some(root);
assert!(ancestors[4] + 2 >= ancestors[6]);
vote_state.process_slot_vote_unchecked(ancestors[4]);
vote_state.process_slot_vote_unchecked(ancestors[6]);
AggregateConfidenceService::aggregate_confidence_for_vote_account(
&mut confidence,
&vote_state,
&ancestors,
lamports,
);
for (i, a) in ancestors.iter().enumerate() {
if *a <= root {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(MAX_LOCKOUT_HISTORY, lamports);
assert_eq!(*confidence.get(&a).unwrap(), expected);
} else if i <= 4 {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(2, lamports);
assert_eq!(*confidence.get(&a).unwrap(), expected);
} else if i <= 6 {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(1, lamports);
assert_eq!(*confidence.get(&a).unwrap(), expected);
}
}
}
#[test]
fn test_aggregate_confidence_validity() {
let ancestors = vec![3, 4, 5, 7, 9, 10, 11];
let GenesisBlockInfo {
mut genesis_block, ..
} = create_genesis_block(10_000);
let pk1 = Pubkey::new_rand();
let mut vote_account1 = vote_state::create_account(&pk1, &Pubkey::new_rand(), 0, 100);
let stake_account1 = stake_state::create_account(&pk1, &vote_account1, 100);
let pk2 = Pubkey::new_rand();
let mut vote_account2 = vote_state::create_account(&pk2, &Pubkey::new_rand(), 0, 50);
let stake_account2 = stake_state::create_account(&pk2, &vote_account2, 50);
genesis_block.accounts.extend(vec![
(pk1, vote_account1.clone()),
(Pubkey::new_rand(), stake_account1),
(pk2, vote_account2.clone()),
(Pubkey::new_rand(), stake_account2),
]);
// Create bank
let bank = Arc::new(Bank::new(&genesis_block));
let mut vote_state1 = VoteState::from(&vote_account1).unwrap();
vote_state1.process_slot_vote_unchecked(3);
vote_state1.process_slot_vote_unchecked(5);
vote_state1.to(&mut vote_account1).unwrap();
bank.store_account(&pk1, &vote_account1);
let mut vote_state2 = VoteState::from(&vote_account2).unwrap();
vote_state2.process_slot_vote_unchecked(9);
vote_state2.process_slot_vote_unchecked(10);
vote_state2.to(&mut vote_account2).unwrap();
bank.store_account(&pk2, &vote_account2);
let confidence = AggregateConfidenceService::aggregate_confidence(&ancestors, &bank);
for a in ancestors {
if a <= 3 {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(2, 150);
assert_eq!(*confidence.get(&a).unwrap(), expected);
} else if a <= 5 {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(1, 100);
expected.increase_confirmation_stake(2, 50);
assert_eq!(*confidence.get(&a).unwrap(), expected);
} else if a <= 9 {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(2, 50);
assert_eq!(*confidence.get(&a).unwrap(), expected);
} else if a <= 10 {
let mut expected = BankConfidence::default();
expected.increase_confirmation_stake(1, 50);
assert_eq!(*confidence.get(&a).unwrap(), expected);
} else {
assert!(confidence.get(&a).is_none());
}
}
}
}

View File

@ -156,7 +156,7 @@ impl ReplayStage {
&mut progress,
);
if let Some((_, bank, lockouts, total_staked)) = votable.into_iter().last() {
if let Some((_, bank, _, total_staked)) = votable.into_iter().last() {
subscriptions.notify_subscribers(bank.slot(), &bank_forks);
if let Some(votable_leader) =
@ -184,7 +184,6 @@ impl ReplayStage {
Self::handle_votable_bank(
&bank,
&bank_forks,
&ancestors,
&mut tower,
&mut progress,
&vote_account,
@ -193,7 +192,6 @@ impl ReplayStage {
&blocktree,
&leader_schedule_cache,
&root_bank_sender,
lockouts,
total_staked,
&lockouts_sender,
&snapshot_package_sender,
@ -406,7 +404,6 @@ impl ReplayStage {
fn handle_votable_bank<T>(
bank: &Arc<Bank>,
bank_forks: &Arc<RwLock<BankForks>>,
ancestors: &Arc<HashMap<u64, HashSet<u64>>>,
tower: &mut Tower,
progress: &mut HashMap<u64, ForkProgress>,
vote_account: &Pubkey,
@ -415,7 +412,6 @@ impl ReplayStage {
blocktree: &Arc<Blocktree>,
leader_schedule_cache: &Arc<LeaderScheduleCache>,
root_bank_sender: &Sender<Vec<Arc<Bank>>>,
lockouts: HashMap<u64, StakeLockout>,
total_staked: u64,
lockouts_sender: &Sender<ConfidenceAggregationData>,
snapshot_package_sender: &Option<SnapshotPackageSender>,
@ -455,7 +451,7 @@ impl ReplayStage {
Err(e)?;
}
}
Self::update_confidence_cache(ancestors, tower, lockouts, total_staked, lockouts_sender);
Self::update_confidence_cache(bank.clone(), total_staked, lockouts_sender);
if let Some(ref voting_keypair) = voting_keypair {
let node_keypair = cluster_info.read().unwrap().keypair.clone();
@ -476,18 +472,11 @@ impl ReplayStage {
}
fn update_confidence_cache(
ancestors: &Arc<HashMap<u64, HashSet<u64>>>,
tower: &Tower,
lockouts: HashMap<u64, StakeLockout>,
bank: Arc<Bank>,
total_staked: u64,
lockouts_sender: &Sender<ConfidenceAggregationData>,
) {
if let Err(e) = lockouts_sender.send(ConfidenceAggregationData::new(
lockouts,
tower.root(),
ancestors.clone(),
total_staked,
)) {
if let Err(e) = lockouts_sender.send(ConfidenceAggregationData::new(bank, total_staked)) {
trace!("lockouts_sender failed: {:?}", e);
}
}
@ -809,7 +798,7 @@ mod test {
use super::*;
use crate::blocktree::tests::make_slot_entries;
use crate::blocktree::{entries_to_test_shreds, get_tmp_ledger_path};
use crate::confidence::Confidence;
use crate::confidence::BankConfidence;
use crate::entry;
use crate::genesis_utils::{create_genesis_block, create_genesis_block_with_leader};
use crate::replay_stage::ReplayStage;
@ -1028,43 +1017,18 @@ mod test {
&[arc_bank0.clone()],
vec![0],
)));
let pubkey = Pubkey::new_rand();
let mut tower = Tower::new(&pubkey, &Pubkey::new_rand(), &bank_forks.read().unwrap());
let mut progress = HashMap::new();
leader_vote(&arc_bank0, &leader_voting_pubkey);
let ancestors = Arc::new(bank_forks.read().unwrap().ancestors());
let votable =
ReplayStage::generate_votable_banks(&ancestors, &bank_forks, &tower, &mut progress);
if let Some((_, _, lockouts, total_staked)) = votable.into_iter().last() {
ReplayStage::update_confidence_cache(
&ancestors,
&tower,
lockouts,
total_staked,
&lockouts_sender,
);
}
thread::sleep(Duration::from_millis(200));
assert_eq!(
fork_confidence_cache
.read()
.unwrap()
.get_fork_confidence(0)
.unwrap(),
&Confidence::new(0, 3, 2)
);
assert!(fork_confidence_cache
.read()
.unwrap()
.get_fork_confidence(0)
.is_none());
assert!(fork_confidence_cache
.read()
.unwrap()
.get_fork_confidence(1)
.is_none());
tower.record_vote(arc_bank0.slot(), arc_bank0.hash());
let bank1 = Bank::new_from_parent(&arc_bank0, &Pubkey::default(), arc_bank0.slot() + 1);
let _res = bank1.transfer(10, &genesis_block_info.mint_keypair, &Pubkey::new_rand());
for _ in 0..genesis_block.ticks_per_slot {
@ -1074,20 +1038,7 @@ mod test {
bank_forks.write().unwrap().insert(bank1);
let arc_bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
leader_vote(&arc_bank1, &leader_voting_pubkey);
let ancestors = Arc::new(bank_forks.read().unwrap().ancestors());
let votable =
ReplayStage::generate_votable_banks(&ancestors, &bank_forks, &tower, &mut progress);
if let Some((_, _, lockouts, total_staked)) = votable.into_iter().last() {
ReplayStage::update_confidence_cache(
&ancestors,
&tower,
lockouts,
total_staked,
&lockouts_sender,
);
}
tower.record_vote(arc_bank1.slot(), arc_bank1.hash());
ReplayStage::update_confidence_cache(arc_bank1.clone(), leader_lamports, &lockouts_sender);
let bank2 = Bank::new_from_parent(&arc_bank1, &Pubkey::default(), arc_bank1.slot() + 1);
let _res = bank2.transfer(10, &genesis_block_info.mint_keypair, &Pubkey::new_rand());
@ -1098,43 +1049,38 @@ mod test {
bank_forks.write().unwrap().insert(bank2);
let arc_bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
leader_vote(&arc_bank2, &leader_voting_pubkey);
let ancestors = Arc::new(bank_forks.read().unwrap().ancestors());
let votable =
ReplayStage::generate_votable_banks(&ancestors, &bank_forks, &tower, &mut progress);
if let Some((_, _, lockouts, total_staked)) = votable.into_iter().last() {
ReplayStage::update_confidence_cache(
&ancestors,
&tower,
lockouts,
total_staked,
&lockouts_sender,
);
}
ReplayStage::update_confidence_cache(arc_bank2.clone(), leader_lamports, &lockouts_sender);
thread::sleep(Duration::from_millis(200));
let mut expected0 = BankConfidence::default();
expected0.increase_confirmation_stake(2, leader_lamports);
assert_eq!(
fork_confidence_cache
.read()
.unwrap()
.get_fork_confidence(0)
.unwrap(),
&Confidence::new_with_stake_weighted(3, 3, 14, 60)
&expected0,
);
let mut expected1 = BankConfidence::default();
expected1.increase_confirmation_stake(2, leader_lamports);
assert_eq!(
fork_confidence_cache
.read()
.unwrap()
.get_fork_confidence(1)
.unwrap(),
&Confidence::new_with_stake_weighted(3, 3, 6, 18)
&expected1
);
let mut expected2 = BankConfidence::default();
expected2.increase_confirmation_stake(1, leader_lamports);
assert_eq!(
fork_confidence_cache
.read()
.unwrap()
.get_fork_confidence(2)
.unwrap(),
&Confidence::new_with_stake_weighted(0, 3, 2, 0)
&expected2
);
}
}

View File

@ -402,6 +402,20 @@ impl Bank {
*self.hash.read().unwrap() != Hash::default()
}
pub fn status_cache_ancestors(&self) -> Vec<u64> {
let mut roots = self.src.status_cache.read().unwrap().roots().clone();
let min = roots.iter().min().cloned().unwrap_or(0);
for ancestor in self.ancestors.keys() {
if *ancestor >= min {
roots.insert(*ancestor);
}
}
let mut ancestors: Vec<_> = roots.into_iter().collect();
ancestors.sort();
ancestors
}
fn update_clock(&self) {
self.store_account(
&clock::id(),
@ -1539,6 +1553,7 @@ mod tests {
use crate::genesis_utils::{
create_genesis_block_with_leader, GenesisBlockInfo, BOOTSTRAP_LEADER_LAMPORTS,
};
use crate::status_cache::MAX_CACHE_ENTRIES;
use bincode::{deserialize_from, serialize_into, serialized_size};
use solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;
use solana_sdk::genesis_block::create_genesis_block;
@ -3021,4 +3036,22 @@ mod tests {
assert_eq!(bank1.get_program_accounts(&program_id).len(), 2);
assert_eq!(bank3.get_program_accounts(&program_id).len(), 2);
}
#[test]
fn test_status_cache_ancestors() {
let (genesis_block, _mint_keypair) = create_genesis_block(500);
let parent = Arc::new(Bank::new(&genesis_block));
let bank1 = Arc::new(new_from_parent(&parent));
let mut bank = bank1;
for _ in 0..MAX_CACHE_ENTRIES * 2 {
bank = Arc::new(new_from_parent(&bank));
bank.squash();
}
let bank = new_from_parent(&bank);
assert_eq!(
bank.status_cache_ancestors(),
(bank.slot() - MAX_CACHE_ENTRIES as u64..=bank.slot()).collect::<Vec<_>>()
);
}
}