2020-06-17 20:54:52 -07:00
|
|
|
//! The `bank_forks` module implements BankForks a DAG of checkpointed Banks
|
2019-02-16 19:58:07 -08:00
|
|
|
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
crate::{
|
2022-09-07 13:41:40 -07:00
|
|
|
accounts_background_service::{AbsRequestSender, SnapshotRequest, SnapshotRequestType},
|
2021-12-03 09:00:31 -08:00
|
|
|
bank::Bank,
|
2022-09-30 11:59:41 -07:00
|
|
|
epoch_accounts_hash,
|
2021-12-03 09:00:31 -08:00
|
|
|
snapshot_config::SnapshotConfig,
|
|
|
|
},
|
|
|
|
log::*,
|
|
|
|
solana_measure::measure::Measure,
|
2022-09-30 11:59:41 -07:00
|
|
|
solana_sdk::{clock::Slot, feature_set, hash::Hash, timing},
|
2021-12-03 09:00:31 -08:00
|
|
|
std::{
|
|
|
|
collections::{hash_map::Entry, HashMap, HashSet},
|
|
|
|
ops::Index,
|
2022-09-23 13:01:03 -07:00
|
|
|
sync::{
|
|
|
|
atomic::{AtomicBool, AtomicU64, Ordering},
|
|
|
|
Arc,
|
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
time::Instant,
|
|
|
|
},
|
2019-11-02 00:38:30 -07:00
|
|
|
};
|
2019-02-16 19:58:07 -08:00
|
|
|
|
2022-05-14 08:53:37 -07:00
|
|
|
pub const MAX_ROOT_DISTANCE_FOR_VOTE_ONLY: Slot = 400;
|
2022-09-23 13:01:03 -07:00
|
|
|
pub type AtomicSlot = AtomicU64;
|
|
|
|
pub struct ReadOnlyAtomicSlot {
|
|
|
|
slot: Arc<AtomicSlot>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ReadOnlyAtomicSlot {
|
|
|
|
pub fn get(&self) -> Slot {
|
|
|
|
self.slot.load(Ordering::Relaxed)
|
|
|
|
}
|
|
|
|
}
|
2022-05-14 08:53:37 -07:00
|
|
|
|
2022-01-14 18:00:07 -08:00
|
|
|
#[derive(Debug, Default, Copy, Clone)]
|
|
|
|
struct SetRootMetrics {
|
|
|
|
timings: SetRootTimings,
|
2021-11-15 15:28:18 -08:00
|
|
|
total_parent_banks: i64,
|
2022-01-14 18:00:07 -08:00
|
|
|
tx_count: i64,
|
|
|
|
dropped_banks_len: i64,
|
|
|
|
accounts_data_len: i64,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Default, Copy, Clone)]
|
|
|
|
struct SetRootTimings {
|
2021-11-05 18:05:36 -07:00
|
|
|
total_squash_cache_ms: i64,
|
|
|
|
total_squash_accounts_ms: i64,
|
2021-11-22 09:29:45 -08:00
|
|
|
total_squash_accounts_index_ms: i64,
|
|
|
|
total_squash_accounts_cache_ms: i64,
|
|
|
|
total_squash_accounts_store_ms: i64,
|
2021-11-05 18:05:36 -07:00
|
|
|
total_snapshot_ms: i64,
|
|
|
|
prune_non_rooted_ms: i64,
|
|
|
|
drop_parent_banks_ms: i64,
|
2021-11-15 15:28:18 -08:00
|
|
|
prune_slots_ms: i64,
|
|
|
|
prune_remove_ms: i64,
|
2021-11-05 18:05:36 -07:00
|
|
|
}
|
|
|
|
|
2019-02-16 19:58:07 -08:00
|
|
|
pub struct BankForks {
|
2021-02-05 10:00:45 -08:00
|
|
|
banks: HashMap<Slot, Arc<Bank>>,
|
|
|
|
descendants: HashMap<Slot, HashSet<Slot>>,
|
2022-09-23 13:01:03 -07:00
|
|
|
root: Arc<AtomicSlot>,
|
|
|
|
|
2019-10-19 12:09:45 -07:00
|
|
|
pub snapshot_config: Option<SnapshotConfig>,
|
2020-04-16 15:12:20 -07:00
|
|
|
|
|
|
|
pub accounts_hash_interval_slots: Slot,
|
|
|
|
last_accounts_hash_slot: Slot,
|
2022-05-14 08:53:37 -07:00
|
|
|
in_vote_only_mode: Arc<AtomicBool>,
|
2019-02-28 10:57:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Index<u64> for BankForks {
|
|
|
|
type Output = Arc<Bank>;
|
2020-06-17 19:16:57 -07:00
|
|
|
fn index(&self, bank_slot: Slot) -> &Self::Output {
|
2019-03-04 16:40:28 -08:00
|
|
|
&self.banks[&bank_slot]
|
2019-02-28 10:57:58 -08:00
|
|
|
}
|
2019-02-16 19:58:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BankForks {
|
2020-06-12 10:04:17 -07:00
|
|
|
pub fn new(bank: Bank) -> Self {
|
|
|
|
let root = bank.slot();
|
|
|
|
Self::new_from_banks(&[Arc::new(bank)], root)
|
2019-02-16 19:58:07 -08:00
|
|
|
}
|
2019-03-18 12:12:33 -07:00
|
|
|
|
2022-04-28 11:51:00 -07:00
|
|
|
pub fn banks(&self) -> HashMap<Slot, Arc<Bank>> {
|
|
|
|
self.banks.clone()
|
2021-02-05 10:00:45 -08:00
|
|
|
}
|
|
|
|
|
2022-05-14 08:53:37 -07:00
|
|
|
pub fn get_vote_only_mode_signal(&self) -> Arc<AtomicBool> {
|
|
|
|
self.in_vote_only_mode.clone()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.banks.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_empty(&self) -> bool {
|
|
|
|
self.banks.is_empty()
|
|
|
|
}
|
|
|
|
|
2019-03-18 12:12:33 -07:00
|
|
|
/// Create a map of bank slot id to the set of ancestors for the bank slot.
|
2019-11-02 00:38:30 -07:00
|
|
|
pub fn ancestors(&self) -> HashMap<Slot, HashSet<Slot>> {
|
2022-09-23 13:01:03 -07:00
|
|
|
let root = self.root();
|
2021-02-05 10:00:45 -08:00
|
|
|
self.banks
|
|
|
|
.iter()
|
|
|
|
.map(|(slot, bank)| {
|
|
|
|
let ancestors = bank.proper_ancestors().filter(|k| *k >= root);
|
|
|
|
(*slot, ancestors.collect())
|
|
|
|
})
|
|
|
|
.collect()
|
2019-03-18 12:12:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a map of bank slot id to the set of all of its descendants
|
2022-04-28 11:51:00 -07:00
|
|
|
pub fn descendants(&self) -> HashMap<Slot, HashSet<Slot>> {
|
|
|
|
self.descendants.clone()
|
2019-03-18 12:12:33 -07:00
|
|
|
}
|
|
|
|
|
2019-11-02 00:38:30 -07:00
|
|
|
pub fn frozen_banks(&self) -> HashMap<Slot, Arc<Bank>> {
|
2019-03-18 16:04:36 -07:00
|
|
|
self.banks
|
|
|
|
.iter()
|
|
|
|
.filter(|(_, b)| b.is_frozen())
|
|
|
|
.map(|(k, b)| (*k, b.clone()))
|
|
|
|
.collect()
|
2019-02-26 21:57:45 -08:00
|
|
|
}
|
2019-03-18 16:04:36 -07:00
|
|
|
|
2022-07-28 11:33:19 -07:00
|
|
|
pub fn active_bank_slots(&self) -> Vec<Slot> {
|
2019-03-03 16:44:06 -08:00
|
|
|
self.banks
|
|
|
|
.iter()
|
|
|
|
.filter(|(_, v)| !v.is_frozen())
|
|
|
|
.map(|(k, _v)| *k)
|
|
|
|
.collect()
|
2019-02-26 21:57:45 -08:00
|
|
|
}
|
2019-03-19 17:30:36 -07:00
|
|
|
|
2022-04-28 11:51:00 -07:00
|
|
|
pub fn get(&self, bank_slot: Slot) -> Option<Arc<Bank>> {
|
|
|
|
self.banks.get(&bank_slot).cloned()
|
2019-02-26 21:57:45 -08:00
|
|
|
}
|
2019-02-16 19:58:07 -08:00
|
|
|
|
2021-04-12 01:00:59 -07:00
|
|
|
pub fn get_with_checked_hash(
|
|
|
|
&self,
|
|
|
|
(bank_slot, expected_hash): (Slot, Hash),
|
2022-04-28 11:51:00 -07:00
|
|
|
) -> Option<Arc<Bank>> {
|
|
|
|
let maybe_bank = self.get(bank_slot);
|
|
|
|
if let Some(bank) = &maybe_bank {
|
2021-04-12 01:00:59 -07:00
|
|
|
assert_eq!(bank.hash(), expected_hash);
|
|
|
|
}
|
|
|
|
maybe_bank
|
|
|
|
}
|
|
|
|
|
2021-07-08 19:07:32 -07:00
|
|
|
pub fn bank_hash(&self, slot: Slot) -> Option<Hash> {
|
|
|
|
self.get(slot).map(|bank| bank.hash())
|
|
|
|
}
|
|
|
|
|
2020-12-27 05:28:05 -08:00
|
|
|
pub fn root_bank(&self) -> Arc<Bank> {
|
|
|
|
self[self.root()].clone()
|
2020-03-09 22:03:09 -07:00
|
|
|
}
|
|
|
|
|
2020-05-05 19:45:41 -07:00
|
|
|
pub fn new_from_banks(initial_forks: &[Arc<Bank>], root: Slot) -> Self {
|
2019-02-28 12:09:19 -08:00
|
|
|
let mut banks = HashMap::new();
|
2020-05-06 08:24:59 -07:00
|
|
|
|
2019-08-13 17:20:14 -07:00
|
|
|
// Iterate through the heads of all the different forks
|
|
|
|
for bank in initial_forks {
|
2019-02-28 12:09:19 -08:00
|
|
|
banks.insert(bank.slot(), bank.clone());
|
2019-08-13 17:20:14 -07:00
|
|
|
let parents = bank.parents();
|
|
|
|
for parent in parents {
|
2022-04-25 17:17:21 -07:00
|
|
|
if banks.insert(parent.slot(), parent.clone()).is_some() {
|
2019-08-13 17:20:14 -07:00
|
|
|
// All ancestors have already been inserted by another fork
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-02-28 12:09:19 -08:00
|
|
|
}
|
2021-02-05 10:00:45 -08:00
|
|
|
let mut descendants = HashMap::<_, HashSet<_>>::new();
|
|
|
|
for (slot, bank) in &banks {
|
|
|
|
descendants.entry(*slot).or_default();
|
|
|
|
for parent in bank.proper_ancestors() {
|
|
|
|
descendants.entry(parent).or_default().insert(*slot);
|
|
|
|
}
|
|
|
|
}
|
2019-02-28 12:09:19 -08:00
|
|
|
Self {
|
2022-09-23 13:01:03 -07:00
|
|
|
root: Arc::new(AtomicSlot::new(root)),
|
2019-02-28 12:09:19 -08:00
|
|
|
banks,
|
2021-02-05 10:00:45 -08:00
|
|
|
descendants,
|
2019-07-31 17:58:10 -07:00
|
|
|
snapshot_config: None,
|
2020-04-16 15:12:20 -07:00
|
|
|
accounts_hash_interval_slots: std::u64::MAX,
|
|
|
|
last_accounts_hash_slot: root,
|
2022-05-14 08:53:37 -07:00
|
|
|
in_vote_only_mode: Arc::new(AtomicBool::new(false)),
|
2019-02-28 12:09:19 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-09 22:06:47 -07:00
|
|
|
pub fn insert(&mut self, bank: Bank) -> Arc<Bank> {
|
2019-03-18 16:04:36 -07:00
|
|
|
let bank = Arc::new(bank);
|
2019-03-18 20:23:34 -07:00
|
|
|
let prev = self.banks.insert(bank.slot(), bank.clone());
|
2019-03-03 16:44:06 -08:00
|
|
|
assert!(prev.is_none());
|
2021-02-05 10:00:45 -08:00
|
|
|
let slot = bank.slot();
|
|
|
|
self.descendants.entry(slot).or_default();
|
|
|
|
for parent in bank.proper_ancestors() {
|
|
|
|
self.descendants.entry(parent).or_default().insert(slot);
|
|
|
|
}
|
2019-07-09 22:06:47 -07:00
|
|
|
bank
|
2019-02-16 19:58:07 -08:00
|
|
|
}
|
|
|
|
|
2020-05-05 14:07:21 -07:00
|
|
|
pub fn remove(&mut self, slot: Slot) -> Option<Arc<Bank>> {
|
2021-02-05 10:00:45 -08:00
|
|
|
let bank = self.banks.remove(&slot)?;
|
|
|
|
for parent in bank.proper_ancestors() {
|
|
|
|
let mut entry = match self.descendants.entry(parent) {
|
|
|
|
Entry::Vacant(_) => panic!("this should not happen!"),
|
|
|
|
Entry::Occupied(entry) => entry,
|
|
|
|
};
|
|
|
|
entry.get_mut().remove(&slot);
|
|
|
|
if entry.get().is_empty() && !self.banks.contains_key(&parent) {
|
|
|
|
entry.remove_entry();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let entry = match self.descendants.entry(slot) {
|
|
|
|
Entry::Vacant(_) => panic!("this should not happen!"),
|
|
|
|
Entry::Occupied(entry) => entry,
|
|
|
|
};
|
|
|
|
if entry.get().is_empty() {
|
|
|
|
entry.remove_entry();
|
|
|
|
}
|
|
|
|
Some(bank)
|
2020-05-05 14:07:21 -07:00
|
|
|
}
|
|
|
|
|
2020-06-17 19:16:57 -07:00
|
|
|
pub fn highest_slot(&self) -> Slot {
|
|
|
|
self.banks.values().map(|bank| bank.slot()).max().unwrap()
|
|
|
|
}
|
|
|
|
|
2019-02-28 10:57:58 -08:00
|
|
|
pub fn working_bank(&self) -> Arc<Bank> {
|
2020-06-17 19:16:57 -07:00
|
|
|
self[self.highest_slot()].clone()
|
2019-02-16 19:58:07 -08:00
|
|
|
}
|
2019-03-18 16:04:36 -07:00
|
|
|
|
2021-11-05 18:05:36 -07:00
|
|
|
fn do_set_root_return_metrics(
|
2019-11-02 00:38:30 -07:00
|
|
|
&mut self,
|
|
|
|
root: Slot,
|
2021-02-18 23:42:09 -08:00
|
|
|
accounts_background_request_sender: &AbsRequestSender,
|
2020-07-07 16:59:46 -07:00
|
|
|
highest_confirmed_root: Option<Slot>,
|
2022-01-14 18:00:07 -08:00
|
|
|
) -> (Vec<Arc<Bank>>, SetRootMetrics) {
|
2020-04-08 14:35:24 -07:00
|
|
|
let old_epoch = self.root_bank().epoch();
|
2022-09-23 13:01:03 -07:00
|
|
|
self.root.store(root, Ordering::Relaxed);
|
|
|
|
|
2019-03-18 16:04:36 -07:00
|
|
|
let root_bank = self
|
|
|
|
.banks
|
|
|
|
.get(&root)
|
|
|
|
.expect("root bank didn't exist in bank_forks");
|
2020-04-08 14:35:24 -07:00
|
|
|
let new_epoch = root_bank.epoch();
|
|
|
|
if old_epoch != new_epoch {
|
|
|
|
info!(
|
|
|
|
"Root entering
|
2021-11-05 18:05:36 -07:00
|
|
|
epoch: {},
|
|
|
|
next_epoch_start_slot: {},
|
|
|
|
epoch_stakes: {:#?}",
|
2020-04-08 14:35:24 -07:00
|
|
|
new_epoch,
|
|
|
|
root_bank
|
|
|
|
.epoch_schedule()
|
|
|
|
.get_first_slot_in_epoch(new_epoch + 1),
|
|
|
|
root_bank
|
|
|
|
.epoch_stakes(new_epoch)
|
|
|
|
.unwrap()
|
|
|
|
.node_id_to_vote_accounts()
|
|
|
|
);
|
|
|
|
}
|
2019-05-13 13:23:52 -07:00
|
|
|
let root_tx_count = root_bank
|
|
|
|
.parents()
|
|
|
|
.last()
|
|
|
|
.map(|bank| bank.transaction_count())
|
|
|
|
.unwrap_or(0);
|
2020-04-16 15:12:20 -07:00
|
|
|
// Calculate the accounts hash at a fixed interval
|
2020-03-04 19:23:40 -08:00
|
|
|
let mut is_root_bank_squashed = false;
|
2020-04-16 15:12:20 -07:00
|
|
|
let mut banks = vec![root_bank];
|
|
|
|
let parents = root_bank.parents();
|
|
|
|
banks.extend(parents.iter());
|
2021-11-15 15:28:18 -08:00
|
|
|
let total_parent_banks = banks.len();
|
2021-11-02 10:23:35 -07:00
|
|
|
let mut total_squash_accounts_ms = 0;
|
2021-11-22 09:29:45 -08:00
|
|
|
let mut total_squash_accounts_index_ms = 0;
|
|
|
|
let mut total_squash_accounts_cache_ms = 0;
|
|
|
|
let mut total_squash_accounts_store_ms = 0;
|
2021-11-02 10:23:35 -07:00
|
|
|
let mut total_squash_cache_ms = 0;
|
|
|
|
let mut total_snapshot_ms = 0;
|
2022-09-30 11:59:41 -07:00
|
|
|
|
|
|
|
// handle epoch accounts hash
|
|
|
|
// go through all the banks, oldest first
|
|
|
|
// find the newest bank where we should do EAH
|
|
|
|
// NOTE: Instead of filter-collect-assert, `.find()` could be used instead. Once
|
|
|
|
// sufficient testing guarantees only one bank will ever request an EAH, change to
|
|
|
|
// `.find()`.
|
|
|
|
let eah_banks: Vec<_> = banks
|
|
|
|
.iter()
|
|
|
|
.filter(|&&bank| self.should_request_epoch_accounts_hash(bank))
|
|
|
|
.collect();
|
|
|
|
assert!(
|
|
|
|
eah_banks.len() <= 1,
|
|
|
|
"At most one bank should request an epoch accounts hash calculation! num banks: {}, bank slots: {:?}",
|
|
|
|
eah_banks.len(),
|
|
|
|
eah_banks.iter().map(|bank| bank.slot()).collect::<Vec<_>>(),
|
|
|
|
);
|
|
|
|
if let Some(eah_bank) = eah_banks.first() {
|
|
|
|
debug!(
|
|
|
|
"sending epoch accounts hash request, slot: {}",
|
|
|
|
eah_bank.slot()
|
|
|
|
);
|
2022-10-05 14:44:35 -07:00
|
|
|
|
2022-09-30 11:59:41 -07:00
|
|
|
self.last_accounts_hash_slot = eah_bank.slot();
|
|
|
|
let squash_timing = eah_bank.squash();
|
|
|
|
total_squash_accounts_ms += squash_timing.squash_accounts_ms as i64;
|
|
|
|
total_squash_accounts_index_ms += squash_timing.squash_accounts_index_ms as i64;
|
|
|
|
total_squash_accounts_cache_ms += squash_timing.squash_accounts_cache_ms as i64;
|
|
|
|
total_squash_accounts_store_ms += squash_timing.squash_accounts_store_ms as i64;
|
|
|
|
total_squash_cache_ms += squash_timing.squash_cache_ms as i64;
|
|
|
|
is_root_bank_squashed = eah_bank.slot() == root;
|
|
|
|
|
2022-10-19 07:37:14 -07:00
|
|
|
eah_bank
|
|
|
|
.rc
|
|
|
|
.accounts
|
|
|
|
.accounts_db
|
|
|
|
.epoch_accounts_hash_manager
|
|
|
|
.set_in_flight(eah_bank.slot());
|
2022-09-30 11:59:41 -07:00
|
|
|
accounts_background_request_sender
|
|
|
|
.send_snapshot_request(SnapshotRequest {
|
|
|
|
snapshot_root_bank: Arc::clone(eah_bank),
|
|
|
|
status_cache_slot_deltas: Vec::default(),
|
|
|
|
request_type: SnapshotRequestType::EpochAccountsHash,
|
2022-10-25 09:10:53 -07:00
|
|
|
enqueued: Instant::now(),
|
2022-09-30 11:59:41 -07:00
|
|
|
})
|
|
|
|
.expect("send epoch accounts hash request");
|
2022-10-14 08:00:04 -07:00
|
|
|
}
|
|
|
|
drop(eah_banks);
|
|
|
|
|
|
|
|
// After checking for EAH requests, also check for regular snapshot requests.
|
|
|
|
//
|
|
|
|
// This is needed when a snapshot request occurs in a slot after an EAH request, and is
|
|
|
|
// part of the same set of `banks` in a single `set_root()` invocation. While (very)
|
|
|
|
// unlikely for a validator with defaut snapshot intervals (and accounts hash verifier
|
|
|
|
// intervals), it *is* possible, and there are tests to exercise this possibility.
|
|
|
|
if let Some(bank) = banks.iter().find(|bank| {
|
2022-09-10 16:11:37 -07:00
|
|
|
bank.slot() > self.last_accounts_hash_slot
|
|
|
|
&& bank.block_height() % self.accounts_hash_interval_slots == 0
|
|
|
|
}) {
|
2020-04-16 15:12:20 -07:00
|
|
|
let bank_slot = bank.slot();
|
2022-09-10 16:11:37 -07:00
|
|
|
self.last_accounts_hash_slot = bank_slot;
|
|
|
|
let squash_timing = bank.squash();
|
|
|
|
total_squash_accounts_ms += squash_timing.squash_accounts_ms as i64;
|
|
|
|
total_squash_accounts_index_ms += squash_timing.squash_accounts_index_ms as i64;
|
|
|
|
total_squash_accounts_cache_ms += squash_timing.squash_accounts_cache_ms as i64;
|
|
|
|
total_squash_accounts_store_ms += squash_timing.squash_accounts_store_ms as i64;
|
|
|
|
total_squash_cache_ms += squash_timing.squash_cache_ms as i64;
|
|
|
|
is_root_bank_squashed = bank_slot == root;
|
2020-04-16 15:12:20 -07:00
|
|
|
|
2022-09-10 16:11:37 -07:00
|
|
|
let mut snapshot_time = Measure::start("squash::snapshot_time");
|
|
|
|
if self.snapshot_config.is_some()
|
|
|
|
&& accounts_background_request_sender.is_snapshot_creation_enabled()
|
|
|
|
{
|
2022-09-22 10:52:04 -07:00
|
|
|
if bank.is_startup_verification_complete() {
|
2022-09-10 16:11:37 -07:00
|
|
|
// Save off the status cache because these may get pruned if another
|
|
|
|
// `set_root()` is called before the snapshots package can be generated
|
|
|
|
let status_cache_slot_deltas =
|
|
|
|
bank.status_cache.read().unwrap().root_slot_deltas();
|
|
|
|
if let Err(e) =
|
|
|
|
accounts_background_request_sender.send_snapshot_request(SnapshotRequest {
|
|
|
|
snapshot_root_bank: Arc::clone(bank),
|
|
|
|
status_cache_slot_deltas,
|
|
|
|
request_type: SnapshotRequestType::Snapshot,
|
2022-10-25 09:10:53 -07:00
|
|
|
enqueued: Instant::now(),
|
2022-09-10 16:11:37 -07:00
|
|
|
})
|
|
|
|
{
|
|
|
|
warn!(
|
|
|
|
"Error sending snapshot request for bank: {}, err: {:?}",
|
|
|
|
bank_slot, e
|
|
|
|
);
|
2020-03-04 19:23:40 -08:00
|
|
|
}
|
2022-09-10 16:11:37 -07:00
|
|
|
} else {
|
|
|
|
info!("Not sending snapshot request for bank: {}, startup verification is incomplete", bank_slot);
|
2019-07-31 17:58:10 -07:00
|
|
|
}
|
|
|
|
}
|
2022-09-10 16:11:37 -07:00
|
|
|
snapshot_time.stop();
|
|
|
|
total_snapshot_ms += snapshot_time.as_ms() as i64;
|
2019-07-31 17:58:10 -07:00
|
|
|
}
|
2022-09-30 11:59:41 -07:00
|
|
|
|
2020-03-04 19:23:40 -08:00
|
|
|
if !is_root_bank_squashed {
|
2021-11-02 10:23:35 -07:00
|
|
|
let squash_timing = root_bank.squash();
|
2021-11-05 18:05:36 -07:00
|
|
|
total_squash_accounts_ms += squash_timing.squash_accounts_ms as i64;
|
2021-11-22 09:29:45 -08:00
|
|
|
total_squash_accounts_index_ms += squash_timing.squash_accounts_index_ms as i64;
|
|
|
|
total_squash_accounts_cache_ms += squash_timing.squash_accounts_cache_ms as i64;
|
|
|
|
total_squash_accounts_store_ms += squash_timing.squash_accounts_store_ms as i64;
|
2021-11-05 18:05:36 -07:00
|
|
|
total_squash_cache_ms += squash_timing.squash_cache_ms as i64;
|
2020-03-04 19:23:40 -08:00
|
|
|
}
|
|
|
|
let new_tx_count = root_bank.transaction_count();
|
2022-05-24 17:26:32 -07:00
|
|
|
let accounts_data_len = root_bank.load_accounts_data_size() as i64;
|
2021-11-02 10:23:35 -07:00
|
|
|
let mut prune_time = Measure::start("set_root::prune");
|
2021-11-15 15:28:18 -08:00
|
|
|
let (removed_banks, prune_slots_ms, prune_remove_ms) =
|
|
|
|
self.prune_non_rooted(root, highest_confirmed_root);
|
2021-11-02 10:23:35 -07:00
|
|
|
prune_time.stop();
|
2021-11-15 15:28:18 -08:00
|
|
|
let dropped_banks_len = removed_banks.len();
|
2019-08-06 18:47:30 -07:00
|
|
|
|
2021-11-05 18:05:36 -07:00
|
|
|
let mut drop_parent_banks_time = Measure::start("set_root::drop_banks");
|
|
|
|
drop(parents);
|
|
|
|
drop_parent_banks_time.stop();
|
|
|
|
|
2021-11-15 15:28:18 -08:00
|
|
|
(
|
|
|
|
removed_banks,
|
2022-01-14 18:00:07 -08:00
|
|
|
SetRootMetrics {
|
|
|
|
timings: SetRootTimings {
|
|
|
|
total_squash_cache_ms,
|
|
|
|
total_squash_accounts_ms,
|
|
|
|
total_squash_accounts_index_ms,
|
|
|
|
total_squash_accounts_cache_ms,
|
|
|
|
total_squash_accounts_store_ms,
|
|
|
|
total_snapshot_ms,
|
|
|
|
prune_non_rooted_ms: prune_time.as_ms() as i64,
|
|
|
|
drop_parent_banks_ms: drop_parent_banks_time.as_ms() as i64,
|
|
|
|
prune_slots_ms: prune_slots_ms as i64,
|
|
|
|
prune_remove_ms: prune_remove_ms as i64,
|
|
|
|
},
|
2021-11-15 15:28:18 -08:00
|
|
|
total_parent_banks: total_parent_banks as i64,
|
|
|
|
tx_count: (new_tx_count - root_tx_count) as i64,
|
|
|
|
dropped_banks_len: dropped_banks_len as i64,
|
2022-01-14 18:00:07 -08:00
|
|
|
accounts_data_len,
|
2021-11-15 15:28:18 -08:00
|
|
|
},
|
|
|
|
)
|
2021-11-05 18:05:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_root(
|
|
|
|
&mut self,
|
|
|
|
root: Slot,
|
|
|
|
accounts_background_request_sender: &AbsRequestSender,
|
|
|
|
highest_confirmed_root: Option<Slot>,
|
2021-11-15 15:28:18 -08:00
|
|
|
) -> Vec<Arc<Bank>> {
|
2021-11-05 18:05:36 -07:00
|
|
|
let set_root_start = Instant::now();
|
2021-11-15 15:28:18 -08:00
|
|
|
let (removed_banks, set_root_metrics) = self.do_set_root_return_metrics(
|
2021-11-05 18:05:36 -07:00
|
|
|
root,
|
|
|
|
accounts_background_request_sender,
|
|
|
|
highest_confirmed_root,
|
|
|
|
);
|
2021-11-02 10:23:35 -07:00
|
|
|
datapoint_info!(
|
|
|
|
"bank-forks_set_root",
|
|
|
|
(
|
|
|
|
"elapsed_ms",
|
|
|
|
timing::duration_as_ms(&set_root_start.elapsed()) as usize,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
("slot", root, i64),
|
2021-11-15 15:28:18 -08:00
|
|
|
(
|
|
|
|
"total_parent_banks",
|
|
|
|
set_root_metrics.total_parent_banks,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
("total_banks", self.banks.len(), i64),
|
2021-11-05 18:05:36 -07:00
|
|
|
(
|
|
|
|
"total_squash_cache_ms",
|
2022-01-14 18:00:07 -08:00
|
|
|
set_root_metrics.timings.total_squash_cache_ms,
|
2021-11-05 18:05:36 -07:00
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"total_squash_accounts_ms",
|
2022-01-14 18:00:07 -08:00
|
|
|
set_root_metrics.timings.total_squash_accounts_ms,
|
2021-11-05 18:05:36 -07:00
|
|
|
i64
|
|
|
|
),
|
2021-11-22 09:29:45 -08:00
|
|
|
(
|
|
|
|
"total_squash_accounts_index_ms",
|
2022-01-14 18:00:07 -08:00
|
|
|
set_root_metrics.timings.total_squash_accounts_index_ms,
|
2021-11-22 09:29:45 -08:00
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"total_squash_accounts_cache_ms",
|
2022-01-14 18:00:07 -08:00
|
|
|
set_root_metrics.timings.total_squash_accounts_cache_ms,
|
2021-11-22 09:29:45 -08:00
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"total_squash_accounts_store_ms",
|
2022-01-14 18:00:07 -08:00
|
|
|
set_root_metrics.timings.total_squash_accounts_store_ms,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"total_snapshot_ms",
|
|
|
|
set_root_metrics.timings.total_snapshot_ms,
|
2021-11-22 09:29:45 -08:00
|
|
|
i64
|
|
|
|
),
|
2021-11-05 18:05:36 -07:00
|
|
|
("tx_count", set_root_metrics.tx_count, i64),
|
|
|
|
(
|
|
|
|
"prune_non_rooted_ms",
|
2022-01-14 18:00:07 -08:00
|
|
|
set_root_metrics.timings.prune_non_rooted_ms,
|
2021-11-05 18:05:36 -07:00
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"drop_parent_banks_ms",
|
2022-01-14 18:00:07 -08:00
|
|
|
set_root_metrics.timings.drop_parent_banks_ms,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"prune_slots_ms",
|
|
|
|
set_root_metrics.timings.prune_slots_ms,
|
|
|
|
i64
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"prune_remove_ms",
|
|
|
|
set_root_metrics.timings.prune_remove_ms,
|
2021-11-05 18:05:36 -07:00
|
|
|
i64
|
|
|
|
),
|
2021-11-15 15:28:18 -08:00
|
|
|
("dropped_banks_len", set_root_metrics.dropped_banks_len, i64),
|
2022-01-14 18:00:07 -08:00
|
|
|
("accounts_data_len", set_root_metrics.accounts_data_len, i64),
|
2019-05-13 13:23:52 -07:00
|
|
|
);
|
2021-11-15 15:28:18 -08:00
|
|
|
removed_banks
|
2019-03-18 16:04:36 -07:00
|
|
|
}
|
|
|
|
|
2019-11-02 00:38:30 -07:00
|
|
|
pub fn root(&self) -> Slot {
|
2022-09-23 13:01:03 -07:00
|
|
|
self.root.load(Ordering::Relaxed)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets a read-only wrapper to an atomic slot holding the root slot.
|
|
|
|
pub fn get_atomic_root(&self) -> ReadOnlyAtomicSlot {
|
|
|
|
ReadOnlyAtomicSlot {
|
|
|
|
slot: self.root.clone(),
|
|
|
|
}
|
2019-05-07 23:34:10 -07:00
|
|
|
}
|
|
|
|
|
2021-05-14 05:47:48 -07:00
|
|
|
/// After setting a new root, prune the banks that are no longer on rooted paths
|
|
|
|
///
|
|
|
|
/// Given the following banks and slots...
|
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// slot 6 * (G)
|
|
|
|
/// /
|
|
|
|
/// slot 5 (F) * /
|
|
|
|
/// | /
|
|
|
|
/// slot 4 (E) * | /
|
|
|
|
/// | |/
|
|
|
|
/// slot 3 | * (D) <-- root, from set_root()
|
|
|
|
/// | |
|
|
|
|
/// slot 2 (C) * |
|
|
|
|
/// \ |
|
|
|
|
/// slot 1 \ * (B)
|
|
|
|
/// \ |
|
|
|
|
/// slot 0 * (A) <-- highest confirmed root [1]
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// ...where (D) is set as root, clean up (C) and (E), since they are not rooted.
|
|
|
|
///
|
|
|
|
/// (A) is kept because it is greater-than-or-equal-to the highest confirmed root, and (D) is
|
|
|
|
/// one of its descendants
|
|
|
|
/// (B) is kept for the same reason as (A)
|
|
|
|
/// (C) is pruned since it is a lower slot than (D), but (D) is _not_ one of its descendants
|
|
|
|
/// (D) is kept since it is the root
|
|
|
|
/// (E) is pruned since it is not a descendant of (D)
|
|
|
|
/// (F) is kept since it is a descendant of (D)
|
|
|
|
/// (G) is kept for the same reason as (F)
|
|
|
|
///
|
|
|
|
/// and in table form...
|
|
|
|
///
|
|
|
|
/// ```text
|
|
|
|
/// | | is root a | is a descendant ||
|
|
|
|
/// slot | is root? | descendant? | of root? || keep?
|
|
|
|
/// ------+----------+-------------+-----------------++-------
|
|
|
|
/// (A) | N | Y | N || Y
|
|
|
|
/// (B) | N | Y | N || Y
|
|
|
|
/// (C) | N | N | N || N
|
|
|
|
/// (D) | Y | N | N || Y
|
|
|
|
/// (E) | N | N | N || N
|
|
|
|
/// (F) | N | N | Y || Y
|
|
|
|
/// (G) | N | N | Y || Y
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// [1] RPC has the concept of commitment level, which is based on the highest confirmed root,
|
|
|
|
/// i.e. the cluster-confirmed root. This commitment is stronger than the local node's root.
|
|
|
|
/// So (A) and (B) are kept to facilitate RPC at different commitment levels. Everything below
|
|
|
|
/// the highest confirmed root can be pruned.
|
2021-11-15 15:28:18 -08:00
|
|
|
fn prune_non_rooted(
|
|
|
|
&mut self,
|
|
|
|
root: Slot,
|
|
|
|
highest_confirmed_root: Option<Slot>,
|
|
|
|
) -> (Vec<Arc<Bank>>, u64, u64) {
|
|
|
|
// Clippy doesn't like separating the two collects below,
|
|
|
|
// but we want to collect timing separately, and the 2nd requires
|
|
|
|
// a unique borrow to self which is already borrowed by self.banks
|
|
|
|
#![allow(clippy::needless_collect)]
|
|
|
|
let mut prune_slots_time = Measure::start("prune_slots");
|
2021-02-05 10:00:45 -08:00
|
|
|
let highest_confirmed_root = highest_confirmed_root.unwrap_or(root);
|
|
|
|
let prune_slots: Vec<_> = self
|
|
|
|
.banks
|
|
|
|
.keys()
|
|
|
|
.copied()
|
|
|
|
.filter(|slot| {
|
|
|
|
let keep = *slot == root
|
|
|
|
|| self.descendants[&root].contains(slot)
|
|
|
|
|| (*slot < root
|
|
|
|
&& *slot >= highest_confirmed_root
|
|
|
|
&& self.descendants[slot].contains(&root));
|
|
|
|
!keep
|
|
|
|
})
|
|
|
|
.collect();
|
2021-11-15 15:28:18 -08:00
|
|
|
prune_slots_time.stop();
|
|
|
|
|
|
|
|
let mut prune_remove_time = Measure::start("prune_slots");
|
|
|
|
let removed_banks = prune_slots
|
|
|
|
.into_iter()
|
|
|
|
.filter_map(|slot| self.remove(slot))
|
|
|
|
.collect();
|
|
|
|
prune_remove_time.stop();
|
|
|
|
|
|
|
|
(
|
|
|
|
removed_banks,
|
|
|
|
prune_slots_time.as_ms(),
|
|
|
|
prune_remove_time.as_ms(),
|
|
|
|
)
|
2019-07-26 10:27:57 -07:00
|
|
|
}
|
|
|
|
|
2019-11-04 18:10:06 -08:00
|
|
|
pub fn set_snapshot_config(&mut self, snapshot_config: Option<SnapshotConfig>) {
|
|
|
|
self.snapshot_config = snapshot_config;
|
2019-05-30 21:31:35 -07:00
|
|
|
}
|
|
|
|
|
2020-04-16 15:12:20 -07:00
|
|
|
pub fn set_accounts_hash_interval_slots(&mut self, accounts_interval_slots: u64) {
|
|
|
|
self.accounts_hash_interval_slots = accounts_interval_slots;
|
|
|
|
}
|
2022-09-30 11:59:41 -07:00
|
|
|
|
|
|
|
/// Determine if this bank should request an epoch accounts hash
|
|
|
|
#[must_use]
|
|
|
|
fn should_request_epoch_accounts_hash(&self, bank: &Bank) -> bool {
|
|
|
|
if !bank
|
|
|
|
.feature_set
|
|
|
|
.is_active(&feature_set::epoch_accounts_hash::id())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-11-15 10:26:19 -08:00
|
|
|
if !epoch_accounts_hash::is_enabled_this_epoch(bank) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-30 11:59:41 -07:00
|
|
|
let start_slot = epoch_accounts_hash::calculation_start(bank);
|
|
|
|
bank.slot() > self.last_accounts_hash_slot
|
|
|
|
&& bank.parent_slot() < start_slot
|
|
|
|
&& bank.slot() >= start_slot
|
|
|
|
}
|
2019-02-16 19:58:07 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2021-12-03 09:00:31 -08:00
|
|
|
use {
|
|
|
|
super::*,
|
|
|
|
crate::{
|
|
|
|
bank::tests::update_vote_account_timestamp,
|
2022-11-17 08:01:01 -08:00
|
|
|
epoch_accounts_hash::EpochAccountsHash,
|
2021-12-03 09:00:31 -08:00
|
|
|
genesis_utils::{
|
|
|
|
create_genesis_config, create_genesis_config_with_leader, GenesisConfigInfo,
|
|
|
|
},
|
2020-11-09 18:10:09 -08:00
|
|
|
},
|
2021-12-03 09:00:31 -08:00
|
|
|
solana_sdk::{
|
|
|
|
clock::UnixTimestamp,
|
2022-09-30 11:59:41 -07:00
|
|
|
epoch_schedule::EpochSchedule,
|
2021-12-03 09:00:31 -08:00
|
|
|
hash::Hash,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::{Keypair, Signer},
|
|
|
|
},
|
|
|
|
solana_vote_program::vote_state::BlockTimestamp,
|
2022-10-05 14:44:35 -07:00
|
|
|
std::{sync::atomic::Ordering::Relaxed, time::Duration},
|
2020-11-09 18:10:09 -08:00
|
|
|
};
|
2019-02-16 19:58:07 -08:00
|
|
|
|
|
|
|
#[test]
|
2020-05-06 08:24:59 -07:00
|
|
|
fn test_bank_forks_new() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let mut bank_forks = BankForks::new(bank);
|
2019-03-09 19:28:43 -08:00
|
|
|
let child_bank = Bank::new_from_parent(&bank_forks[0u64], &Pubkey::default(), 1);
|
2019-02-16 19:58:07 -08:00
|
|
|
child_bank.register_tick(&Hash::default());
|
2019-03-18 20:23:34 -07:00
|
|
|
bank_forks.insert(child_bank);
|
2019-02-28 10:57:58 -08:00
|
|
|
assert_eq!(bank_forks[1u64].tick_height(), 1);
|
2019-02-26 09:18:24 -08:00
|
|
|
assert_eq!(bank_forks.working_bank().tick_height(), 1);
|
2019-02-16 19:58:07 -08:00
|
|
|
}
|
2019-02-26 21:57:45 -08:00
|
|
|
|
2020-05-06 08:24:59 -07:00
|
|
|
#[test]
|
|
|
|
fn test_bank_forks_new_from_banks() {
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Arc::new(Bank::new_for_tests(&genesis_config));
|
2020-05-06 08:24:59 -07:00
|
|
|
let child_bank = Arc::new(Bank::new_from_parent(&bank, &Pubkey::default(), 1));
|
|
|
|
|
|
|
|
let bank_forks = BankForks::new_from_banks(&[bank.clone(), child_bank.clone()], 0);
|
|
|
|
assert_eq!(bank_forks.root(), 0);
|
|
|
|
assert_eq!(bank_forks.working_bank().slot(), 1);
|
|
|
|
|
2020-05-15 09:35:43 -07:00
|
|
|
let bank_forks = BankForks::new_from_banks(&[child_bank, bank], 0);
|
2020-05-06 08:24:59 -07:00
|
|
|
assert_eq!(bank_forks.root(), 0);
|
|
|
|
assert_eq!(bank_forks.working_bank().slot(), 1);
|
|
|
|
}
|
|
|
|
|
2019-03-18 12:12:33 -07:00
|
|
|
#[test]
|
2019-03-18 15:20:04 -07:00
|
|
|
fn test_bank_forks_descendants() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let mut bank_forks = BankForks::new(bank);
|
2019-03-18 12:12:33 -07:00
|
|
|
let bank0 = bank_forks[0].clone();
|
|
|
|
let bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
2019-03-18 20:23:34 -07:00
|
|
|
bank_forks.insert(bank);
|
2019-03-18 12:12:33 -07:00
|
|
|
let bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 2);
|
2019-03-18 20:23:34 -07:00
|
|
|
bank_forks.insert(bank);
|
2019-03-18 15:20:04 -07:00
|
|
|
let descendants = bank_forks.descendants();
|
2022-01-21 16:01:22 -08:00
|
|
|
let children: HashSet<u64> = [1u64, 2u64].iter().copied().collect();
|
2019-05-30 21:31:35 -07:00
|
|
|
assert_eq!(children, *descendants.get(&0).unwrap());
|
2019-03-18 15:20:04 -07:00
|
|
|
assert!(descendants[&1].is_empty());
|
|
|
|
assert!(descendants[&2].is_empty());
|
2019-03-18 12:12:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bank_forks_ancestors() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let mut bank_forks = BankForks::new(bank);
|
2019-03-18 12:12:33 -07:00
|
|
|
let bank0 = bank_forks[0].clone();
|
|
|
|
let bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
2019-03-18 20:23:34 -07:00
|
|
|
bank_forks.insert(bank);
|
2019-03-18 12:12:33 -07:00
|
|
|
let bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 2);
|
2019-03-18 20:23:34 -07:00
|
|
|
bank_forks.insert(bank);
|
2019-03-18 12:12:33 -07:00
|
|
|
let ancestors = bank_forks.ancestors();
|
|
|
|
assert!(ancestors[&0].is_empty());
|
|
|
|
let parents: Vec<u64> = ancestors[&1].iter().cloned().collect();
|
|
|
|
assert_eq!(parents, vec![0]);
|
|
|
|
let parents: Vec<u64> = ancestors[&2].iter().cloned().collect();
|
|
|
|
assert_eq!(parents, vec![0]);
|
|
|
|
}
|
|
|
|
|
2019-02-26 21:57:45 -08:00
|
|
|
#[test]
|
|
|
|
fn test_bank_forks_frozen_banks() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let mut bank_forks = BankForks::new(bank);
|
2019-03-09 19:28:43 -08:00
|
|
|
let child_bank = Bank::new_from_parent(&bank_forks[0u64], &Pubkey::default(), 1);
|
2019-03-18 20:23:34 -07:00
|
|
|
bank_forks.insert(child_bank);
|
2019-02-26 21:57:45 -08:00
|
|
|
assert!(bank_forks.frozen_banks().get(&0).is_some());
|
|
|
|
assert!(bank_forks.frozen_banks().get(&1).is_none());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bank_forks_active_banks() {
|
2019-11-08 20:56:57 -08:00
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank = Bank::new_for_tests(&genesis_config);
|
2020-06-12 10:04:17 -07:00
|
|
|
let mut bank_forks = BankForks::new(bank);
|
2019-03-09 19:28:43 -08:00
|
|
|
let child_bank = Bank::new_from_parent(&bank_forks[0u64], &Pubkey::default(), 1);
|
2019-03-18 20:23:34 -07:00
|
|
|
bank_forks.insert(child_bank);
|
2022-07-28 11:33:19 -07:00
|
|
|
assert_eq!(bank_forks.active_bank_slots(), vec![1]);
|
2019-02-26 21:57:45 -08:00
|
|
|
}
|
2020-11-09 18:10:09 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bank_forks_different_set_root() {
|
|
|
|
solana_logger::setup();
|
|
|
|
let leader_keypair = Keypair::new();
|
|
|
|
let GenesisConfigInfo {
|
|
|
|
mut genesis_config,
|
|
|
|
voting_keypair,
|
2021-12-29 10:34:31 -08:00
|
|
|
..
|
2020-11-09 18:10:09 -08:00
|
|
|
} = create_genesis_config_with_leader(10_000, &leader_keypair.pubkey(), 1_000);
|
|
|
|
let slots_in_epoch = 32;
|
|
|
|
genesis_config.epoch_schedule = EpochSchedule::new(slots_in_epoch);
|
|
|
|
|
2022-10-05 14:44:35 -07:00
|
|
|
// Spin up a thread to be a fake Accounts Background Service. Need to intercept and handle
|
2022-11-17 08:01:01 -08:00
|
|
|
// all EpochAccountsHash requests so future rooted banks do not hang in Bank::freeze()
|
|
|
|
// waiting for an in-flight EAH calculation to complete.
|
2022-10-05 14:44:35 -07:00
|
|
|
let (snapshot_request_sender, snapshot_request_receiver) = crossbeam_channel::unbounded();
|
|
|
|
let abs_request_sender = AbsRequestSender::new(snapshot_request_sender);
|
|
|
|
let bg_exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let bg_thread = {
|
|
|
|
let exit = Arc::clone(&bg_exit);
|
|
|
|
std::thread::spawn(move || {
|
|
|
|
while !exit.load(Relaxed) {
|
|
|
|
snapshot_request_receiver
|
|
|
|
.try_iter()
|
|
|
|
.filter(|snapshot_request| {
|
|
|
|
snapshot_request.request_type == SnapshotRequestType::EpochAccountsHash
|
|
|
|
})
|
|
|
|
.for_each(|snapshot_request| {
|
|
|
|
snapshot_request
|
|
|
|
.snapshot_root_bank
|
|
|
|
.rc
|
|
|
|
.accounts
|
|
|
|
.accounts_db
|
|
|
|
.epoch_accounts_hash_manager
|
2022-11-17 08:01:01 -08:00
|
|
|
.set_valid(
|
|
|
|
EpochAccountsHash::new(Hash::new_unique()),
|
|
|
|
snapshot_request.snapshot_root_bank.slot(),
|
|
|
|
)
|
2022-10-05 14:44:35 -07:00
|
|
|
});
|
|
|
|
std::thread::sleep(Duration::from_millis(100));
|
|
|
|
}
|
|
|
|
})
|
|
|
|
};
|
|
|
|
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank0 = Bank::new_for_tests(&genesis_config);
|
2020-11-09 18:10:09 -08:00
|
|
|
let mut bank_forks0 = BankForks::new(bank0);
|
2022-10-05 14:44:35 -07:00
|
|
|
bank_forks0.set_root(0, &abs_request_sender, None);
|
2020-11-09 18:10:09 -08:00
|
|
|
|
2021-08-05 06:42:38 -07:00
|
|
|
let bank1 = Bank::new_for_tests(&genesis_config);
|
2020-11-09 18:10:09 -08:00
|
|
|
let mut bank_forks1 = BankForks::new(bank1);
|
|
|
|
|
|
|
|
let additional_timestamp_secs = 2;
|
|
|
|
|
2021-02-09 14:49:00 -08:00
|
|
|
let num_slots = slots_in_epoch + 1; // Advance past first epoch boundary
|
2020-11-09 18:10:09 -08:00
|
|
|
for slot in 1..num_slots {
|
|
|
|
// Just after the epoch boundary, timestamp a vote that will shift
|
|
|
|
// Clock::unix_timestamp from Bank::unix_timestamp_from_genesis()
|
|
|
|
let update_timestamp_case = slot == slots_in_epoch;
|
|
|
|
|
|
|
|
let child1 = Bank::new_from_parent(&bank_forks0[slot - 1], &Pubkey::default(), slot);
|
|
|
|
let child2 = Bank::new_from_parent(&bank_forks1[slot - 1], &Pubkey::default(), slot);
|
|
|
|
|
|
|
|
if update_timestamp_case {
|
|
|
|
for child in &[&child1, &child2] {
|
|
|
|
let recent_timestamp: UnixTimestamp = child.unix_timestamp_from_genesis();
|
|
|
|
update_vote_account_timestamp(
|
|
|
|
BlockTimestamp {
|
|
|
|
slot: child.slot(),
|
|
|
|
timestamp: recent_timestamp + additional_timestamp_secs,
|
|
|
|
},
|
2021-06-18 06:34:46 -07:00
|
|
|
child,
|
2020-11-09 18:10:09 -08:00
|
|
|
&voting_keypair.pubkey(),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set root in bank_forks0 to truncate the ancestor history
|
|
|
|
bank_forks0.insert(child1);
|
2022-10-05 14:44:35 -07:00
|
|
|
bank_forks0.set_root(slot, &abs_request_sender, None);
|
2020-11-09 18:10:09 -08:00
|
|
|
|
|
|
|
// Don't set root in bank_forks1 to keep the ancestor history
|
|
|
|
bank_forks1.insert(child2);
|
|
|
|
}
|
|
|
|
let child1 = &bank_forks0.working_bank();
|
|
|
|
let child2 = &bank_forks1.working_bank();
|
|
|
|
|
|
|
|
child1.freeze();
|
|
|
|
child2.freeze();
|
|
|
|
|
|
|
|
info!("child0.ancestors: {:?}", child1.ancestors);
|
|
|
|
info!("child1.ancestors: {:?}", child2.ancestors);
|
|
|
|
assert_eq!(child1.hash(), child2.hash());
|
2022-10-05 14:44:35 -07:00
|
|
|
|
|
|
|
bg_exit.store(true, Relaxed);
|
|
|
|
bg_thread.join().unwrap();
|
2020-11-09 18:10:09 -08:00
|
|
|
}
|
2021-02-05 10:00:45 -08:00
|
|
|
|
|
|
|
fn make_hash_map(data: Vec<(Slot, Vec<Slot>)>) -> HashMap<Slot, HashSet<Slot>> {
|
|
|
|
data.into_iter()
|
|
|
|
.map(|(k, v)| (k, v.into_iter().collect()))
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bank_forks_with_set_root() {
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let mut banks = vec![Arc::new(Bank::new_for_tests(&genesis_config))];
|
2021-02-05 10:00:45 -08:00
|
|
|
assert_eq!(banks[0].slot(), 0);
|
|
|
|
let mut bank_forks = BankForks::new_from_banks(&banks, 0);
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[0], &Pubkey::default(), 1)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[1], &Pubkey::default(), 2)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[0], &Pubkey::default(), 3)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[3], &Pubkey::default(), 4)));
|
|
|
|
assert_eq!(
|
|
|
|
bank_forks.ancestors(),
|
|
|
|
make_hash_map(vec![
|
|
|
|
(0, vec![]),
|
|
|
|
(1, vec![0]),
|
|
|
|
(2, vec![0, 1]),
|
|
|
|
(3, vec![0]),
|
|
|
|
(4, vec![0, 3]),
|
|
|
|
])
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2022-04-28 11:51:00 -07:00
|
|
|
bank_forks.descendants(),
|
2021-02-05 10:00:45 -08:00
|
|
|
make_hash_map(vec![
|
|
|
|
(0, vec![1, 2, 3, 4]),
|
|
|
|
(1, vec![2]),
|
|
|
|
(2, vec![]),
|
|
|
|
(3, vec![4]),
|
|
|
|
(4, vec![]),
|
|
|
|
])
|
|
|
|
);
|
|
|
|
bank_forks.set_root(
|
|
|
|
2,
|
2021-02-18 23:42:09 -08:00
|
|
|
&AbsRequestSender::default(),
|
2021-02-05 10:00:45 -08:00
|
|
|
None, // highest confirmed root
|
|
|
|
);
|
|
|
|
banks[2].squash();
|
|
|
|
assert_eq!(bank_forks.ancestors(), make_hash_map(vec![(2, vec![]),]));
|
|
|
|
assert_eq!(
|
2022-04-28 11:51:00 -07:00
|
|
|
bank_forks.descendants(),
|
2021-02-05 10:00:45 -08:00
|
|
|
make_hash_map(vec![(0, vec![2]), (1, vec![2]), (2, vec![]),])
|
|
|
|
);
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[2], &Pubkey::default(), 5)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[5], &Pubkey::default(), 6)));
|
|
|
|
assert_eq!(
|
|
|
|
bank_forks.ancestors(),
|
|
|
|
make_hash_map(vec![(2, vec![]), (5, vec![2]), (6, vec![2, 5])])
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2022-04-28 11:51:00 -07:00
|
|
|
bank_forks.descendants(),
|
2021-02-05 10:00:45 -08:00
|
|
|
make_hash_map(vec![
|
|
|
|
(0, vec![2]),
|
|
|
|
(1, vec![2]),
|
|
|
|
(2, vec![5, 6]),
|
|
|
|
(5, vec![6]),
|
|
|
|
(6, vec![])
|
|
|
|
])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_bank_forks_with_highest_confirmed_root() {
|
|
|
|
let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
|
2021-08-05 06:42:38 -07:00
|
|
|
let mut banks = vec![Arc::new(Bank::new_for_tests(&genesis_config))];
|
2021-02-05 10:00:45 -08:00
|
|
|
assert_eq!(banks[0].slot(), 0);
|
|
|
|
let mut bank_forks = BankForks::new_from_banks(&banks, 0);
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[0], &Pubkey::default(), 1)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[1], &Pubkey::default(), 2)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[0], &Pubkey::default(), 3)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[3], &Pubkey::default(), 4)));
|
|
|
|
assert_eq!(
|
|
|
|
bank_forks.ancestors(),
|
|
|
|
make_hash_map(vec![
|
|
|
|
(0, vec![]),
|
|
|
|
(1, vec![0]),
|
|
|
|
(2, vec![0, 1]),
|
|
|
|
(3, vec![0]),
|
|
|
|
(4, vec![0, 3]),
|
|
|
|
])
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2022-04-28 11:51:00 -07:00
|
|
|
bank_forks.descendants(),
|
2021-02-05 10:00:45 -08:00
|
|
|
make_hash_map(vec![
|
|
|
|
(0, vec![1, 2, 3, 4]),
|
|
|
|
(1, vec![2]),
|
|
|
|
(2, vec![]),
|
|
|
|
(3, vec![4]),
|
|
|
|
(4, vec![]),
|
|
|
|
])
|
|
|
|
);
|
|
|
|
bank_forks.set_root(
|
|
|
|
2,
|
2021-02-18 23:42:09 -08:00
|
|
|
&AbsRequestSender::default(),
|
2021-02-05 10:00:45 -08:00
|
|
|
Some(1), // highest confirmed root
|
|
|
|
);
|
|
|
|
banks[2].squash();
|
|
|
|
assert_eq!(
|
|
|
|
bank_forks.ancestors(),
|
|
|
|
make_hash_map(vec![(1, vec![]), (2, vec![]),])
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2022-04-28 11:51:00 -07:00
|
|
|
bank_forks.descendants(),
|
2021-02-05 10:00:45 -08:00
|
|
|
make_hash_map(vec![(0, vec![1, 2]), (1, vec![2]), (2, vec![]),])
|
|
|
|
);
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[2], &Pubkey::default(), 5)));
|
|
|
|
banks.push(bank_forks.insert(Bank::new_from_parent(&banks[5], &Pubkey::default(), 6)));
|
|
|
|
assert_eq!(
|
|
|
|
bank_forks.ancestors(),
|
|
|
|
make_hash_map(vec![
|
|
|
|
(1, vec![]),
|
|
|
|
(2, vec![]),
|
|
|
|
(5, vec![2]),
|
|
|
|
(6, vec![2, 5])
|
|
|
|
])
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2022-04-28 11:51:00 -07:00
|
|
|
bank_forks.descendants(),
|
2021-02-05 10:00:45 -08:00
|
|
|
make_hash_map(vec![
|
|
|
|
(0, vec![1, 2]),
|
|
|
|
(1, vec![2]),
|
|
|
|
(2, vec![5, 6]),
|
|
|
|
(5, vec![6]),
|
|
|
|
(6, vec![])
|
|
|
|
])
|
|
|
|
);
|
|
|
|
}
|
2019-02-16 19:58:07 -08:00
|
|
|
}
|