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:
		@@ -1,113 +1,59 @@
 | 
				
			|||||||
use crate::consensus::StakeLockout;
 | 
					use crate::result::{Error, Result};
 | 
				
			||||||
use crate::service::Service;
 | 
					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::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::sync::{Arc, RwLock};
 | 
				
			||||||
use std::thread::{self, Builder, JoinHandle};
 | 
					use std::thread::{self, Builder, JoinHandle};
 | 
				
			||||||
 | 
					use std::time::Duration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Default, PartialEq)]
 | 
					#[derive(Debug, Default, Eq, PartialEq)]
 | 
				
			||||||
pub struct Confidence {
 | 
					pub struct BankConfidence {
 | 
				
			||||||
    fork_stakes: u64,
 | 
					    confidence: [u64; MAX_LOCKOUT_HISTORY],
 | 
				
			||||||
    total_stake: u64,
 | 
					 | 
				
			||||||
    lockouts: u64,
 | 
					 | 
				
			||||||
    stake_weighted_lockouts: u128,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Confidence {
 | 
					impl BankConfidence {
 | 
				
			||||||
    pub fn new(fork_stakes: u64, total_stake: u64, lockouts: u64) -> Self {
 | 
					    pub fn increase_confirmation_stake(&mut self, confirmation_count: usize, stake: u64) {
 | 
				
			||||||
        Self {
 | 
					        assert!(confirmation_count > 0 && confirmation_count <= MAX_LOCKOUT_HISTORY);
 | 
				
			||||||
            fork_stakes,
 | 
					        self.confidence[confirmation_count - 1] += stake;
 | 
				
			||||||
            total_stake,
 | 
					 | 
				
			||||||
            lockouts,
 | 
					 | 
				
			||||||
            stake_weighted_lockouts: 0,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn new_with_stake_weighted(
 | 
					
 | 
				
			||||||
        fork_stakes: u64,
 | 
					    pub fn get_confirmation_stake(&mut self, confirmation_count: usize) -> u64 {
 | 
				
			||||||
        total_stake: u64,
 | 
					        assert!(confirmation_count > 0 && confirmation_count <= MAX_LOCKOUT_HISTORY);
 | 
				
			||||||
        lockouts: u64,
 | 
					        self.confidence[confirmation_count - 1]
 | 
				
			||||||
        stake_weighted_lockouts: u128,
 | 
					 | 
				
			||||||
    ) -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            fork_stakes,
 | 
					 | 
				
			||||||
            total_stake,
 | 
					 | 
				
			||||||
            lockouts,
 | 
					 | 
				
			||||||
            stake_weighted_lockouts,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Default, PartialEq)]
 | 
					#[derive(Default)]
 | 
				
			||||||
pub struct ForkConfidenceCache {
 | 
					pub struct ForkConfidenceCache {
 | 
				
			||||||
    confidence: HashMap<u64, Confidence>,
 | 
					    bank_confidence: HashMap<u64, BankConfidence>,
 | 
				
			||||||
 | 
					    _total_stake: u64,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ForkConfidenceCache {
 | 
					impl ForkConfidenceCache {
 | 
				
			||||||
    pub fn cache_fork_confidence(
 | 
					    pub fn new(bank_confidence: HashMap<u64, BankConfidence>, total_stake: u64) -> Self {
 | 
				
			||||||
        &mut self,
 | 
					        Self {
 | 
				
			||||||
        fork: u64,
 | 
					            bank_confidence,
 | 
				
			||||||
        fork_stakes: u64,
 | 
					            _total_stake: total_stake,
 | 
				
			||||||
        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 cache_stake_weighted_lockouts(&mut self, fork: u64, stake_weighted_lockouts: u128) {
 | 
					    pub fn get_fork_confidence(&self, fork: u64) -> Option<&BankConfidence> {
 | 
				
			||||||
        self.confidence
 | 
					        self.bank_confidence.get(&fork)
 | 
				
			||||||
            .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 struct ConfidenceAggregationData {
 | 
					pub struct ConfidenceAggregationData {
 | 
				
			||||||
    lockouts: HashMap<u64, StakeLockout>,
 | 
					    bank: Arc<Bank>,
 | 
				
			||||||
    root: Option<u64>,
 | 
					 | 
				
			||||||
    ancestors: Arc<HashMap<u64, HashSet<u64>>>,
 | 
					 | 
				
			||||||
    total_staked: u64,
 | 
					    total_staked: u64,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ConfidenceAggregationData {
 | 
					impl ConfidenceAggregationData {
 | 
				
			||||||
    pub fn new(
 | 
					    pub fn new(bank: Arc<Bank>, total_staked: u64) -> Self {
 | 
				
			||||||
        lockouts: HashMap<u64, StakeLockout>,
 | 
					        Self { bank, total_staked }
 | 
				
			||||||
        root: Option<u64>,
 | 
					 | 
				
			||||||
        ancestors: Arc<HashMap<u64, HashSet<u64>>>,
 | 
					 | 
				
			||||||
        total_staked: u64,
 | 
					 | 
				
			||||||
    ) -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            lockouts,
 | 
					 | 
				
			||||||
            root,
 | 
					 | 
				
			||||||
            ancestors,
 | 
					 | 
				
			||||||
            total_staked,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -116,38 +62,17 @@ pub struct AggregateConfidenceService {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl 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(
 | 
					    pub fn new(
 | 
				
			||||||
        exit: &Arc<AtomicBool>,
 | 
					        exit: &Arc<AtomicBool>,
 | 
				
			||||||
        fork_confidence_cache: Arc<RwLock<ForkConfidenceCache>>,
 | 
					        fork_confidence_cache: Arc<RwLock<ForkConfidenceCache>>,
 | 
				
			||||||
    ) -> (Sender<ConfidenceAggregationData>, Self) {
 | 
					    ) -> (Sender<ConfidenceAggregationData>, Self) {
 | 
				
			||||||
        let (lockouts_sender, lockouts_receiver): (
 | 
					        let (sender, receiver): (
 | 
				
			||||||
            Sender<ConfidenceAggregationData>,
 | 
					            Sender<ConfidenceAggregationData>,
 | 
				
			||||||
            Receiver<ConfidenceAggregationData>,
 | 
					            Receiver<ConfidenceAggregationData>,
 | 
				
			||||||
        ) = channel();
 | 
					        ) = channel();
 | 
				
			||||||
        let exit_ = exit.clone();
 | 
					        let exit_ = exit.clone();
 | 
				
			||||||
        (
 | 
					        (
 | 
				
			||||||
            lockouts_sender,
 | 
					            sender,
 | 
				
			||||||
            Self {
 | 
					            Self {
 | 
				
			||||||
                t_confidence: Builder::new()
 | 
					                t_confidence: Builder::new()
 | 
				
			||||||
                    .name("solana-aggregate-stake-lockouts".to_string())
 | 
					                    .name("solana-aggregate-stake-lockouts".to_string())
 | 
				
			||||||
@@ -155,54 +80,121 @@ impl AggregateConfidenceService {
 | 
				
			|||||||
                        if exit_.load(Ordering::Relaxed) {
 | 
					                        if exit_.load(Ordering::Relaxed) {
 | 
				
			||||||
                            break;
 | 
					                            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 =
 | 
					                        if let Err(e) = Self::run(&receiver, &fork_confidence_cache, &exit_) {
 | 
				
			||||||
                                fork_confidence_cache.write().unwrap();
 | 
					                            match e {
 | 
				
			||||||
 | 
					                                Error::RecvTimeoutError(RecvTimeoutError::Disconnected) => break,
 | 
				
			||||||
                            // Cache the confidence values
 | 
					                                Error::RecvTimeoutError(RecvTimeoutError::Timeout) => (),
 | 
				
			||||||
                            for (fork, stake_lockout) in aggregation_data.lockouts.iter() {
 | 
					                                _ => info!(
 | 
				
			||||||
                                if aggregation_data.root.is_none()
 | 
					                                    "Unexpected error from AggregateConfidenceService: {:?}",
 | 
				
			||||||
                                    || *fork >= aggregation_data.root.unwrap()
 | 
					                                    e
 | 
				
			||||||
                                {
 | 
					                                ),
 | 
				
			||||||
                                    w_fork_confidence_cache.cache_fork_confidence(
 | 
					 | 
				
			||||||
                                        *fork,
 | 
					 | 
				
			||||||
                                        stake_lockout.stake(),
 | 
					 | 
				
			||||||
                                        aggregation_data.total_staked,
 | 
					 | 
				
			||||||
                                        stake_lockout.lockout(),
 | 
					 | 
				
			||||||
                                    );
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
 | 
					 | 
				
			||||||
                            // 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(),
 | 
					                    .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 {
 | 
					impl Service for AggregateConfidenceService {
 | 
				
			||||||
@@ -216,64 +208,169 @@ impl Service for AggregateConfidenceService {
 | 
				
			|||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod tests {
 | 
					mod tests {
 | 
				
			||||||
    use super::*;
 | 
					    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]
 | 
					    #[test]
 | 
				
			||||||
    fn test_fork_confidence_cache() {
 | 
					    fn test_bank_confidence() {
 | 
				
			||||||
        let mut cache = ForkConfidenceCache::default();
 | 
					        let mut cache = BankConfidence::default();
 | 
				
			||||||
        let fork = 0;
 | 
					        assert_eq!(cache.get_confirmation_stake(1), 0);
 | 
				
			||||||
        assert!(cache.confidence.get(&fork).is_none());
 | 
					        cache.increase_confirmation_stake(1, 10);
 | 
				
			||||||
        cache.cache_fork_confidence(fork, 11, 12, 13);
 | 
					        assert_eq!(cache.get_confirmation_stake(1), 10);
 | 
				
			||||||
        assert_eq!(
 | 
					        cache.increase_confirmation_stake(1, 20);
 | 
				
			||||||
            cache.confidence.get(&fork).unwrap(),
 | 
					        assert_eq!(cache.get_confirmation_stake(1), 30);
 | 
				
			||||||
            &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,
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[test]
 | 
					    #[test]
 | 
				
			||||||
    fn test_aggregate_confidence() {
 | 
					    fn test_aggregate_confidence_for_vote_account_1() {
 | 
				
			||||||
        let stakes = vec![
 | 
					        let ancestors = vec![3, 4, 5, 7, 9, 11];
 | 
				
			||||||
            (0, StakeLockout::new(1, 32)),
 | 
					        let mut confidence = HashMap::new();
 | 
				
			||||||
            (1, StakeLockout::new(1, 24)),
 | 
					        let lamports = 5;
 | 
				
			||||||
            (2, StakeLockout::new(1, 16)),
 | 
					        let mut vote_state = VoteState::new(&Pubkey::default(), &Pubkey::default(), 0);
 | 
				
			||||||
            (3, StakeLockout::new(1, 8)),
 | 
					
 | 
				
			||||||
        ]
 | 
					        let root = ancestors.last().unwrap();
 | 
				
			||||||
        .into_iter()
 | 
					        vote_state.root_slot = Some(*root);
 | 
				
			||||||
        .collect();
 | 
					        AggregateConfidenceService::aggregate_confidence_for_vote_account(
 | 
				
			||||||
        let ancestors = vec![
 | 
					            &mut confidence,
 | 
				
			||||||
            (0, HashSet::new()),
 | 
					            &vote_state,
 | 
				
			||||||
            (1, vec![0].into_iter().collect()),
 | 
					            &ancestors,
 | 
				
			||||||
            (2, vec![0, 1].into_iter().collect()),
 | 
					            lamports,
 | 
				
			||||||
            (3, vec![0, 1, 2].into_iter().collect()),
 | 
					        );
 | 
				
			||||||
        ]
 | 
					
 | 
				
			||||||
        .into_iter()
 | 
					        for a in ancestors {
 | 
				
			||||||
        .collect();
 | 
					            let mut expected = BankConfidence::default();
 | 
				
			||||||
        let stake_weighted_lockouts =
 | 
					            expected.increase_confirmation_stake(MAX_LOCKOUT_HISTORY, lamports);
 | 
				
			||||||
            AggregateConfidenceService::aggregate_confidence(Some(1), &ancestors, &stakes);
 | 
					            assert_eq!(*confidence.get(&a).unwrap(), expected);
 | 
				
			||||||
        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);
 | 
					    #[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());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -156,7 +156,7 @@ impl ReplayStage {
 | 
				
			|||||||
                        &mut progress,
 | 
					                        &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);
 | 
					                        subscriptions.notify_subscribers(bank.slot(), &bank_forks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if let Some(votable_leader) =
 | 
					                        if let Some(votable_leader) =
 | 
				
			||||||
@@ -184,7 +184,6 @@ impl ReplayStage {
 | 
				
			|||||||
                        Self::handle_votable_bank(
 | 
					                        Self::handle_votable_bank(
 | 
				
			||||||
                            &bank,
 | 
					                            &bank,
 | 
				
			||||||
                            &bank_forks,
 | 
					                            &bank_forks,
 | 
				
			||||||
                            &ancestors,
 | 
					 | 
				
			||||||
                            &mut tower,
 | 
					                            &mut tower,
 | 
				
			||||||
                            &mut progress,
 | 
					                            &mut progress,
 | 
				
			||||||
                            &vote_account,
 | 
					                            &vote_account,
 | 
				
			||||||
@@ -193,7 +192,6 @@ impl ReplayStage {
 | 
				
			|||||||
                            &blocktree,
 | 
					                            &blocktree,
 | 
				
			||||||
                            &leader_schedule_cache,
 | 
					                            &leader_schedule_cache,
 | 
				
			||||||
                            &root_bank_sender,
 | 
					                            &root_bank_sender,
 | 
				
			||||||
                            lockouts,
 | 
					 | 
				
			||||||
                            total_staked,
 | 
					                            total_staked,
 | 
				
			||||||
                            &lockouts_sender,
 | 
					                            &lockouts_sender,
 | 
				
			||||||
                            &snapshot_package_sender,
 | 
					                            &snapshot_package_sender,
 | 
				
			||||||
@@ -406,7 +404,6 @@ impl ReplayStage {
 | 
				
			|||||||
    fn handle_votable_bank<T>(
 | 
					    fn handle_votable_bank<T>(
 | 
				
			||||||
        bank: &Arc<Bank>,
 | 
					        bank: &Arc<Bank>,
 | 
				
			||||||
        bank_forks: &Arc<RwLock<BankForks>>,
 | 
					        bank_forks: &Arc<RwLock<BankForks>>,
 | 
				
			||||||
        ancestors: &Arc<HashMap<u64, HashSet<u64>>>,
 | 
					 | 
				
			||||||
        tower: &mut Tower,
 | 
					        tower: &mut Tower,
 | 
				
			||||||
        progress: &mut HashMap<u64, ForkProgress>,
 | 
					        progress: &mut HashMap<u64, ForkProgress>,
 | 
				
			||||||
        vote_account: &Pubkey,
 | 
					        vote_account: &Pubkey,
 | 
				
			||||||
@@ -415,7 +412,6 @@ impl ReplayStage {
 | 
				
			|||||||
        blocktree: &Arc<Blocktree>,
 | 
					        blocktree: &Arc<Blocktree>,
 | 
				
			||||||
        leader_schedule_cache: &Arc<LeaderScheduleCache>,
 | 
					        leader_schedule_cache: &Arc<LeaderScheduleCache>,
 | 
				
			||||||
        root_bank_sender: &Sender<Vec<Arc<Bank>>>,
 | 
					        root_bank_sender: &Sender<Vec<Arc<Bank>>>,
 | 
				
			||||||
        lockouts: HashMap<u64, StakeLockout>,
 | 
					 | 
				
			||||||
        total_staked: u64,
 | 
					        total_staked: u64,
 | 
				
			||||||
        lockouts_sender: &Sender<ConfidenceAggregationData>,
 | 
					        lockouts_sender: &Sender<ConfidenceAggregationData>,
 | 
				
			||||||
        snapshot_package_sender: &Option<SnapshotPackageSender>,
 | 
					        snapshot_package_sender: &Option<SnapshotPackageSender>,
 | 
				
			||||||
@@ -455,7 +451,7 @@ impl ReplayStage {
 | 
				
			|||||||
                Err(e)?;
 | 
					                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 {
 | 
					        if let Some(ref voting_keypair) = voting_keypair {
 | 
				
			||||||
            let node_keypair = cluster_info.read().unwrap().keypair.clone();
 | 
					            let node_keypair = cluster_info.read().unwrap().keypair.clone();
 | 
				
			||||||
@@ -476,18 +472,11 @@ impl ReplayStage {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn update_confidence_cache(
 | 
					    fn update_confidence_cache(
 | 
				
			||||||
        ancestors: &Arc<HashMap<u64, HashSet<u64>>>,
 | 
					        bank: Arc<Bank>,
 | 
				
			||||||
        tower: &Tower,
 | 
					 | 
				
			||||||
        lockouts: HashMap<u64, StakeLockout>,
 | 
					 | 
				
			||||||
        total_staked: u64,
 | 
					        total_staked: u64,
 | 
				
			||||||
        lockouts_sender: &Sender<ConfidenceAggregationData>,
 | 
					        lockouts_sender: &Sender<ConfidenceAggregationData>,
 | 
				
			||||||
    ) {
 | 
					    ) {
 | 
				
			||||||
        if let Err(e) = lockouts_sender.send(ConfidenceAggregationData::new(
 | 
					        if let Err(e) = lockouts_sender.send(ConfidenceAggregationData::new(bank, total_staked)) {
 | 
				
			||||||
            lockouts,
 | 
					 | 
				
			||||||
            tower.root(),
 | 
					 | 
				
			||||||
            ancestors.clone(),
 | 
					 | 
				
			||||||
            total_staked,
 | 
					 | 
				
			||||||
        )) {
 | 
					 | 
				
			||||||
            trace!("lockouts_sender failed: {:?}", e);
 | 
					            trace!("lockouts_sender failed: {:?}", e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -809,7 +798,7 @@ mod test {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::blocktree::tests::make_slot_entries;
 | 
					    use crate::blocktree::tests::make_slot_entries;
 | 
				
			||||||
    use crate::blocktree::{entries_to_test_shreds, get_tmp_ledger_path};
 | 
					    use crate::blocktree::{entries_to_test_shreds, get_tmp_ledger_path};
 | 
				
			||||||
    use crate::confidence::Confidence;
 | 
					    use crate::confidence::BankConfidence;
 | 
				
			||||||
    use crate::entry;
 | 
					    use crate::entry;
 | 
				
			||||||
    use crate::genesis_utils::{create_genesis_block, create_genesis_block_with_leader};
 | 
					    use crate::genesis_utils::{create_genesis_block, create_genesis_block_with_leader};
 | 
				
			||||||
    use crate::replay_stage::ReplayStage;
 | 
					    use crate::replay_stage::ReplayStage;
 | 
				
			||||||
@@ -1028,43 +1017,18 @@ mod test {
 | 
				
			|||||||
            &[arc_bank0.clone()],
 | 
					            &[arc_bank0.clone()],
 | 
				
			||||||
            vec![0],
 | 
					            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);
 | 
					        assert!(fork_confidence_cache
 | 
				
			||||||
        let ancestors = Arc::new(bank_forks.read().unwrap().ancestors());
 | 
					            .read()
 | 
				
			||||||
 | 
					            .unwrap()
 | 
				
			||||||
        let votable =
 | 
					            .get_fork_confidence(0)
 | 
				
			||||||
            ReplayStage::generate_votable_banks(&ancestors, &bank_forks, &tower, &mut progress);
 | 
					            .is_none());
 | 
				
			||||||
        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
 | 
					        assert!(fork_confidence_cache
 | 
				
			||||||
            .read()
 | 
					            .read()
 | 
				
			||||||
            .unwrap()
 | 
					            .unwrap()
 | 
				
			||||||
            .get_fork_confidence(1)
 | 
					            .get_fork_confidence(1)
 | 
				
			||||||
            .is_none());
 | 
					            .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 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());
 | 
					        let _res = bank1.transfer(10, &genesis_block_info.mint_keypair, &Pubkey::new_rand());
 | 
				
			||||||
        for _ in 0..genesis_block.ticks_per_slot {
 | 
					        for _ in 0..genesis_block.ticks_per_slot {
 | 
				
			||||||
@@ -1074,20 +1038,7 @@ mod test {
 | 
				
			|||||||
        bank_forks.write().unwrap().insert(bank1);
 | 
					        bank_forks.write().unwrap().insert(bank1);
 | 
				
			||||||
        let arc_bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
 | 
					        let arc_bank1 = bank_forks.read().unwrap().get(1).unwrap().clone();
 | 
				
			||||||
        leader_vote(&arc_bank1, &leader_voting_pubkey);
 | 
					        leader_vote(&arc_bank1, &leader_voting_pubkey);
 | 
				
			||||||
        let ancestors = Arc::new(bank_forks.read().unwrap().ancestors());
 | 
					        ReplayStage::update_confidence_cache(arc_bank1.clone(), leader_lamports, &lockouts_sender);
 | 
				
			||||||
        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());
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let bank2 = Bank::new_from_parent(&arc_bank1, &Pubkey::default(), arc_bank1.slot() + 1);
 | 
					        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());
 | 
					        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);
 | 
					        bank_forks.write().unwrap().insert(bank2);
 | 
				
			||||||
        let arc_bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
 | 
					        let arc_bank2 = bank_forks.read().unwrap().get(2).unwrap().clone();
 | 
				
			||||||
        leader_vote(&arc_bank2, &leader_voting_pubkey);
 | 
					        leader_vote(&arc_bank2, &leader_voting_pubkey);
 | 
				
			||||||
        let ancestors = Arc::new(bank_forks.read().unwrap().ancestors());
 | 
					        ReplayStage::update_confidence_cache(arc_bank2.clone(), leader_lamports, &lockouts_sender);
 | 
				
			||||||
        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));
 | 
					        thread::sleep(Duration::from_millis(200));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let mut expected0 = BankConfidence::default();
 | 
				
			||||||
 | 
					        expected0.increase_confirmation_stake(2, leader_lamports);
 | 
				
			||||||
        assert_eq!(
 | 
					        assert_eq!(
 | 
				
			||||||
            fork_confidence_cache
 | 
					            fork_confidence_cache
 | 
				
			||||||
                .read()
 | 
					                .read()
 | 
				
			||||||
                .unwrap()
 | 
					                .unwrap()
 | 
				
			||||||
                .get_fork_confidence(0)
 | 
					                .get_fork_confidence(0)
 | 
				
			||||||
                .unwrap(),
 | 
					                .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!(
 | 
					        assert_eq!(
 | 
				
			||||||
            fork_confidence_cache
 | 
					            fork_confidence_cache
 | 
				
			||||||
                .read()
 | 
					                .read()
 | 
				
			||||||
                .unwrap()
 | 
					                .unwrap()
 | 
				
			||||||
                .get_fork_confidence(1)
 | 
					                .get_fork_confidence(1)
 | 
				
			||||||
                .unwrap(),
 | 
					                .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!(
 | 
					        assert_eq!(
 | 
				
			||||||
            fork_confidence_cache
 | 
					            fork_confidence_cache
 | 
				
			||||||
                .read()
 | 
					                .read()
 | 
				
			||||||
                .unwrap()
 | 
					                .unwrap()
 | 
				
			||||||
                .get_fork_confidence(2)
 | 
					                .get_fork_confidence(2)
 | 
				
			||||||
                .unwrap(),
 | 
					                .unwrap(),
 | 
				
			||||||
            &Confidence::new_with_stake_weighted(0, 3, 2, 0)
 | 
					            &expected2
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -402,6 +402,20 @@ impl Bank {
 | 
				
			|||||||
        *self.hash.read().unwrap() != Hash::default()
 | 
					        *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) {
 | 
					    fn update_clock(&self) {
 | 
				
			||||||
        self.store_account(
 | 
					        self.store_account(
 | 
				
			||||||
            &clock::id(),
 | 
					            &clock::id(),
 | 
				
			||||||
@@ -1539,6 +1553,7 @@ mod tests {
 | 
				
			|||||||
    use crate::genesis_utils::{
 | 
					    use crate::genesis_utils::{
 | 
				
			||||||
        create_genesis_block_with_leader, GenesisBlockInfo, BOOTSTRAP_LEADER_LAMPORTS,
 | 
					        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 bincode::{deserialize_from, serialize_into, serialized_size};
 | 
				
			||||||
    use solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;
 | 
					    use solana_sdk::clock::DEFAULT_TICKS_PER_SLOT;
 | 
				
			||||||
    use solana_sdk::genesis_block::create_genesis_block;
 | 
					    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!(bank1.get_program_accounts(&program_id).len(), 2);
 | 
				
			||||||
        assert_eq!(bank3.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<_>>()
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user