Create bank snapshots (#4244)
* Revert "Revert "Create bank snapshots (#3671)" (#4243)"
This reverts commit 81fa69d347
.
* keep saved and unsaved copies of status cache
* fix format check
* bench for status cache serialize
* misc cleanup
* remove appendvec storage on purge
* fix accounts restore
* cleanup
* Pass snapshot path as args
* Fix clippy
This commit is contained in:
@ -1,10 +1,15 @@
|
||||
//! The `bank_forks` module implments BankForks a DAG of checkpointed Banks
|
||||
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use bincode::{deserialize_from, serialize_into};
|
||||
use solana_metrics::inc_new_counter_info;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_runtime::bank::{Bank, BankRc, StatusCacheRc};
|
||||
use solana_sdk::timing;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufWriter, Error, ErrorKind};
|
||||
use std::ops::Index;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
@ -12,6 +17,8 @@ pub struct BankForks {
|
||||
banks: HashMap<u64, Arc<Bank>>,
|
||||
working_bank: Arc<Bank>,
|
||||
root: u64,
|
||||
slots: HashSet<u64>,
|
||||
snapshot_path: Option<String>,
|
||||
}
|
||||
|
||||
impl Index<u64> for BankForks {
|
||||
@ -30,6 +37,8 @@ impl BankForks {
|
||||
banks,
|
||||
working_bank,
|
||||
root: 0,
|
||||
slots: HashSet::new(),
|
||||
snapshot_path: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +54,7 @@ impl BankForks {
|
||||
}
|
||||
|
||||
/// Create a map of bank slot id to the set of all of its descendants
|
||||
#[allow(clippy::or_fun_call)]
|
||||
pub fn descendants(&self) -> HashMap<u64, HashSet<u64>> {
|
||||
let mut descendants = HashMap::new();
|
||||
for bank in self.banks.values() {
|
||||
@ -91,6 +101,8 @@ impl BankForks {
|
||||
root,
|
||||
banks,
|
||||
working_bank,
|
||||
slots: HashSet::new(),
|
||||
snapshot_path: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,9 +150,199 @@ impl BankForks {
|
||||
}
|
||||
|
||||
fn prune_non_root(&mut self, root: u64) {
|
||||
let slots: HashSet<u64> = self
|
||||
.banks
|
||||
.iter()
|
||||
.filter(|(_, b)| b.is_frozen())
|
||||
.map(|(k, _)| *k)
|
||||
.collect();
|
||||
let descendants = self.descendants();
|
||||
self.banks
|
||||
.retain(|slot, _| descendants[&root].contains(slot))
|
||||
.retain(|slot, _| descendants[&root].contains(slot));
|
||||
if self.snapshot_path.is_some() {
|
||||
let diff: HashSet<_> = slots.symmetric_difference(&self.slots).collect();
|
||||
trace!("prune non root {} - {:?}", root, diff);
|
||||
for slot in diff.iter() {
|
||||
if **slot > root {
|
||||
let _ = self.add_snapshot(**slot, root);
|
||||
} else if **slot > 0 {
|
||||
BankForks::remove_snapshot(**slot, &self.snapshot_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.slots = slots.clone();
|
||||
}
|
||||
|
||||
fn get_io_error(error: &str) -> Error {
|
||||
warn!("BankForks error: {:?}", error);
|
||||
Error::new(ErrorKind::Other, error)
|
||||
}
|
||||
|
||||
fn get_snapshot_path(path: &Option<String>) -> PathBuf {
|
||||
Path::new(&path.clone().unwrap()).to_path_buf()
|
||||
}
|
||||
|
||||
pub fn add_snapshot(&self, slot: u64, root: u64) -> Result<(), Error> {
|
||||
let path = BankForks::get_snapshot_path(&self.snapshot_path);
|
||||
fs::create_dir_all(path.clone())?;
|
||||
let bank_file = format!("{}", slot);
|
||||
let bank_file_path = path.join(bank_file);
|
||||
trace!("path: {:?}", bank_file_path);
|
||||
let file = File::create(bank_file_path)?;
|
||||
let mut stream = BufWriter::new(file);
|
||||
let bank_slot = self.get(slot);
|
||||
if bank_slot.is_none() {
|
||||
return Err(BankForks::get_io_error("bank_forks get error"));
|
||||
}
|
||||
let bank = bank_slot.unwrap().clone();
|
||||
serialize_into(&mut stream, &*bank)
|
||||
.map_err(|_| BankForks::get_io_error("serialize bank error"))?;
|
||||
let mut parent_slot: u64 = 0;
|
||||
if let Some(parent_bank) = bank.parent() {
|
||||
parent_slot = parent_bank.slot();
|
||||
}
|
||||
serialize_into(&mut stream, &parent_slot)
|
||||
.map_err(|_| BankForks::get_io_error("serialize bank parent error"))?;
|
||||
serialize_into(&mut stream, &root)
|
||||
.map_err(|_| BankForks::get_io_error("serialize root error"))?;
|
||||
serialize_into(&mut stream, &bank.src)
|
||||
.map_err(|_| BankForks::get_io_error("serialize bank status cache error"))?;
|
||||
serialize_into(&mut stream, &bank.rc)
|
||||
.map_err(|_| BankForks::get_io_error("serialize bank accounts error"))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_snapshot(slot: u64, path: &Option<String>) {
|
||||
let path = BankForks::get_snapshot_path(path);
|
||||
let bank_file = format!("{}", slot);
|
||||
let bank_file_path = path.join(bank_file);
|
||||
let _ = fs::remove_file(bank_file_path);
|
||||
}
|
||||
|
||||
pub fn set_snapshot_config(&mut self, path: Option<String>) {
|
||||
self.snapshot_path = path;
|
||||
}
|
||||
|
||||
fn load_snapshots(
|
||||
names: &[u64],
|
||||
bank_maps: &mut Vec<(u64, u64, Bank)>,
|
||||
status_cache_rc: &StatusCacheRc,
|
||||
snapshot_path: &Option<String>,
|
||||
) -> Option<(BankRc, u64)> {
|
||||
let path = BankForks::get_snapshot_path(snapshot_path);
|
||||
let mut bank_rc: Option<(BankRc, u64)> = None;
|
||||
|
||||
for bank_slot in names.iter().rev() {
|
||||
let bank_path = format!("{}", bank_slot);
|
||||
let bank_file_path = path.join(bank_path.clone());
|
||||
info!("Load from {:?}", bank_file_path);
|
||||
let file = File::open(bank_file_path);
|
||||
if file.is_err() {
|
||||
warn!("Snapshot file open failed for {}", bank_slot);
|
||||
continue;
|
||||
}
|
||||
let file = file.unwrap();
|
||||
let mut stream = BufReader::new(file);
|
||||
let bank: Result<Bank, std::io::Error> = deserialize_from(&mut stream)
|
||||
.map_err(|_| BankForks::get_io_error("deserialize bank error"));
|
||||
let slot: Result<u64, std::io::Error> = deserialize_from(&mut stream)
|
||||
.map_err(|_| BankForks::get_io_error("deserialize bank parent error"));
|
||||
let parent_slot = if slot.is_ok() { slot.unwrap() } else { 0 };
|
||||
let root: Result<u64, std::io::Error> = deserialize_from(&mut stream)
|
||||
.map_err(|_| BankForks::get_io_error("deserialize root error"));
|
||||
let status_cache: Result<StatusCacheRc, std::io::Error> = deserialize_from(&mut stream)
|
||||
.map_err(|_| BankForks::get_io_error("deserialize bank status cache error"));
|
||||
if bank_rc.is_none() {
|
||||
let rc: Result<BankRc, std::io::Error> = deserialize_from(&mut stream)
|
||||
.map_err(|_| BankForks::get_io_error("deserialize bank accounts error"));
|
||||
if rc.is_ok() {
|
||||
bank_rc = Some((rc.unwrap(), root.unwrap()));
|
||||
}
|
||||
}
|
||||
if bank_rc.is_some() {
|
||||
match bank {
|
||||
Ok(v) => {
|
||||
if status_cache.is_ok() {
|
||||
status_cache_rc.append(&status_cache.unwrap());
|
||||
}
|
||||
bank_maps.push((*bank_slot, parent_slot, v));
|
||||
}
|
||||
Err(_) => warn!("Load snapshot failed for {}", bank_slot),
|
||||
}
|
||||
} else {
|
||||
BankForks::remove_snapshot(*bank_slot, snapshot_path);
|
||||
warn!("Load snapshot rc failed for {}", bank_slot);
|
||||
}
|
||||
}
|
||||
bank_rc
|
||||
}
|
||||
|
||||
fn setup_banks(
|
||||
bank_maps: &mut Vec<(u64, u64, Bank)>,
|
||||
bank_rc: &BankRc,
|
||||
status_cache_rc: &StatusCacheRc,
|
||||
) -> (HashMap<u64, Arc<Bank>>, HashSet<u64>, u64) {
|
||||
let mut banks = HashMap::new();
|
||||
let mut slots = HashSet::new();
|
||||
let (last_slot, last_parent_slot, mut last_bank) = bank_maps.remove(0);
|
||||
last_bank.set_bank_rc(&bank_rc, &status_cache_rc);
|
||||
|
||||
while let Some((slot, parent_slot, mut bank)) = bank_maps.pop() {
|
||||
bank.set_bank_rc(&bank_rc, &status_cache_rc);
|
||||
if parent_slot != 0 {
|
||||
if let Some(parent) = banks.get(&parent_slot) {
|
||||
bank.set_parent(parent);
|
||||
}
|
||||
}
|
||||
if slot > 0 {
|
||||
banks.insert(slot, Arc::new(bank));
|
||||
slots.insert(slot);
|
||||
}
|
||||
}
|
||||
if last_parent_slot != 0 {
|
||||
if let Some(parent) = banks.get(&last_parent_slot) {
|
||||
last_bank.set_parent(parent);
|
||||
}
|
||||
}
|
||||
banks.insert(last_slot, Arc::new(last_bank));
|
||||
slots.insert(last_slot);
|
||||
|
||||
(banks, slots, last_slot)
|
||||
}
|
||||
|
||||
pub fn load_from_snapshot(snapshot_path: &Option<String>) -> Result<Self, Error> {
|
||||
let path = BankForks::get_snapshot_path(snapshot_path);
|
||||
let paths = fs::read_dir(path)?;
|
||||
let mut names = paths
|
||||
.filter_map(|entry| {
|
||||
entry.ok().and_then(|e| {
|
||||
e.path()
|
||||
.file_name()
|
||||
.and_then(|n| n.to_str().map(|s| s.parse::<u64>().unwrap()))
|
||||
})
|
||||
})
|
||||
.collect::<Vec<u64>>();
|
||||
|
||||
names.sort();
|
||||
let mut bank_maps = vec![];
|
||||
let status_cache_rc = StatusCacheRc::default();
|
||||
let rc = BankForks::load_snapshots(&names, &mut bank_maps, &status_cache_rc, snapshot_path);
|
||||
if bank_maps.is_empty() || rc.is_none() {
|
||||
BankForks::remove_snapshot(0, snapshot_path);
|
||||
return Err(Error::new(ErrorKind::Other, "no snapshots loaded"));
|
||||
}
|
||||
|
||||
let (bank_rc, root) = rc.unwrap();
|
||||
let (banks, slots, last_slot) =
|
||||
BankForks::setup_banks(&mut bank_maps, &bank_rc, &status_cache_rc);
|
||||
let working_bank = banks[&last_slot].clone();
|
||||
Ok(BankForks {
|
||||
banks,
|
||||
working_bank,
|
||||
root,
|
||||
slots,
|
||||
snapshot_path: snapshot_path.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,6 +352,10 @@ mod tests {
|
||||
use crate::genesis_utils::{create_genesis_block, GenesisBlockInfo};
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_sdk::system_transaction;
|
||||
use std::env;
|
||||
use std::fs::remove_dir_all;
|
||||
|
||||
#[test]
|
||||
fn test_bank_forks() {
|
||||
@ -174,8 +380,8 @@ mod tests {
|
||||
let bank = Bank::new_from_parent(&bank0, &Pubkey::default(), 2);
|
||||
bank_forks.insert(bank);
|
||||
let descendants = bank_forks.descendants();
|
||||
let children: Vec<u64> = descendants[&0].iter().cloned().collect();
|
||||
assert_eq!(children, vec![1, 2]);
|
||||
let children: HashSet<u64> = [1u64, 2u64].to_vec().into_iter().collect();
|
||||
assert_eq!(children, *descendants.get(&0).unwrap());
|
||||
assert!(descendants[&1].is_empty());
|
||||
assert!(descendants[&2].is_empty());
|
||||
}
|
||||
@ -219,4 +425,103 @@ mod tests {
|
||||
assert_eq!(bank_forks.active_banks(), vec![1]);
|
||||
}
|
||||
|
||||
struct TempPaths {
|
||||
pub paths: String,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! tmp_bank_accounts_name {
|
||||
() => {
|
||||
&format!("{}-{}", file!(), line!())
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! get_tmp_bank_accounts_path {
|
||||
() => {
|
||||
get_tmp_bank_accounts_path(tmp_bank_accounts_name!())
|
||||
};
|
||||
}
|
||||
|
||||
impl Drop for TempPaths {
|
||||
fn drop(&mut self) {
|
||||
let paths: Vec<String> = self.paths.split(',').map(|s| s.to_string()).collect();
|
||||
paths.iter().for_each(|p| {
|
||||
let _ignored = remove_dir_all(p);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn get_paths_vec(paths: &str) -> Vec<String> {
|
||||
paths.split(',').map(|s| s.to_string()).collect()
|
||||
}
|
||||
|
||||
fn get_tmp_snapshots_path() -> TempPaths {
|
||||
let out_dir = env::var("OUT_DIR").unwrap_or_else(|_| "target".to_string());
|
||||
let path = format!("{}/snapshots", out_dir);
|
||||
TempPaths {
|
||||
paths: path.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_tmp_bank_accounts_path(paths: &str) -> TempPaths {
|
||||
let vpaths = get_paths_vec(paths);
|
||||
let out_dir = env::var("OUT_DIR").unwrap_or_else(|_| "target".to_string());
|
||||
let vpaths: Vec<_> = vpaths
|
||||
.iter()
|
||||
.map(|path| format!("{}/{}", out_dir, path))
|
||||
.collect();
|
||||
TempPaths {
|
||||
paths: vpaths.join(","),
|
||||
}
|
||||
}
|
||||
|
||||
fn restore_from_snapshot(bank_forks: BankForks, last_slot: u64) {
|
||||
let new = BankForks::load_from_snapshot(&bank_forks.snapshot_path).unwrap();
|
||||
for (slot, _) in new.banks.iter() {
|
||||
let bank = bank_forks.banks.get(slot).unwrap().clone();
|
||||
let new_bank = new.banks.get(slot).unwrap();
|
||||
bank.compare_bank(&new_bank);
|
||||
}
|
||||
assert_eq!(new.working_bank().slot(), last_slot);
|
||||
for (slot, _) in new.banks.iter() {
|
||||
BankForks::remove_snapshot(*slot, &bank_forks.snapshot_path);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bank_forks_snapshot_n() {
|
||||
solana_logger::setup();
|
||||
let path = get_tmp_bank_accounts_path!();
|
||||
let spath = get_tmp_snapshots_path();
|
||||
let GenesisBlockInfo {
|
||||
genesis_block,
|
||||
mint_keypair,
|
||||
..
|
||||
} = create_genesis_block(10_000);
|
||||
for index in 0..10 {
|
||||
let bank0 = Bank::new_with_paths(&genesis_block, Some(path.paths.clone()));
|
||||
bank0.freeze();
|
||||
let slot = bank0.slot();
|
||||
let mut bank_forks = BankForks::new(0, bank0);
|
||||
bank_forks.set_snapshot_config(Some(spath.paths.clone()));
|
||||
bank_forks.add_snapshot(slot, 0).unwrap();
|
||||
for forks in 0..index {
|
||||
let bank = Bank::new_from_parent(&bank_forks[forks], &Pubkey::default(), forks + 1);
|
||||
let key1 = Keypair::new().pubkey();
|
||||
let tx = system_transaction::create_user_account(
|
||||
&mint_keypair,
|
||||
&key1,
|
||||
1,
|
||||
genesis_block.hash(),
|
||||
);
|
||||
assert_eq!(bank.process_transaction(&tx), Ok(()));
|
||||
bank.freeze();
|
||||
let slot = bank.slot();
|
||||
bank_forks.insert(bank);
|
||||
bank_forks.add_snapshot(slot, 0).unwrap();
|
||||
}
|
||||
restore_from_snapshot(bank_forks, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use solana_kvstore as kvstore;
|
||||
|
||||
use bincode::deserialize;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[cfg(not(feature = "kvstore"))]
|
||||
use rocksdb;
|
||||
|
@ -26,7 +26,6 @@ use crate::staking_utils;
|
||||
use crate::streamer::{BlobReceiver, BlobSender};
|
||||
use bincode::{deserialize, serialize};
|
||||
use core::cmp;
|
||||
use hashbrown::HashMap;
|
||||
use rand::{thread_rng, Rng};
|
||||
use rayon::prelude::*;
|
||||
use solana_metrics::{datapoint_debug, inc_new_counter_debug, inc_new_counter_error};
|
||||
@ -40,7 +39,7 @@ use solana_sdk::signature::{Keypair, KeypairUtil, Signable, Signature};
|
||||
use solana_sdk::timing::{duration_as_ms, timestamp};
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use std::cmp::min;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::{BTreeSet, HashMap};
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
|
@ -8,10 +8,10 @@ use crate::crds_gossip_error::CrdsGossipError;
|
||||
use crate::crds_gossip_pull::CrdsGossipPull;
|
||||
use crate::crds_gossip_push::{CrdsGossipPush, CRDS_GOSSIP_NUM_ACTIVE};
|
||||
use crate::crds_value::CrdsValue;
|
||||
use hashbrown::HashMap;
|
||||
use solana_runtime::bloom::Bloom;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::collections::HashMap;
|
||||
|
||||
///The min size for bloom filters
|
||||
pub const CRDS_GOSSIP_BLOOM_SIZE: usize = 1000;
|
||||
|
@ -16,13 +16,13 @@ use crate::crds_gossip_error::CrdsGossipError;
|
||||
use crate::crds_value::{CrdsValue, CrdsValueLabel};
|
||||
use crate::packet::BLOB_DATA_SIZE;
|
||||
use bincode::serialized_size;
|
||||
use hashbrown::HashMap;
|
||||
use rand;
|
||||
use rand::distributions::{Distribution, WeightedIndex};
|
||||
use solana_runtime::bloom::Bloom;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub const CRDS_GOSSIP_PULL_CRDS_TIMEOUT_MS: u64 = 15000;
|
||||
|
@ -15,7 +15,6 @@ use crate::crds_gossip_error::CrdsGossipError;
|
||||
use crate::crds_value::{CrdsValue, CrdsValueLabel};
|
||||
use crate::packet::BLOB_DATA_SIZE;
|
||||
use bincode::serialized_size;
|
||||
use hashbrown::HashMap;
|
||||
use indexmap::map::IndexMap;
|
||||
use rand;
|
||||
use rand::distributions::{Distribution, WeightedIndex};
|
||||
@ -25,6 +24,7 @@ use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::timing::timestamp;
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub const CRDS_GOSSIP_NUM_ACTIVE: usize = 30;
|
||||
pub const CRDS_GOSSIP_PUSH_FANOUT: usize = 6;
|
||||
|
@ -1,13 +1,12 @@
|
||||
use crate::bank_forks::BankForks;
|
||||
use crate::staking_utils;
|
||||
use hashbrown::{HashMap, HashSet};
|
||||
use solana_metrics::datapoint_info;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::account::Account;
|
||||
use solana_sdk::hash::Hash;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_vote_api::vote_state::{Lockout, Vote, VoteState, MAX_LOCKOUT_HISTORY};
|
||||
use std::collections::VecDeque;
|
||||
use std::collections::{HashMap, HashSet, VecDeque};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub const VOTE_THRESHOLD_DEPTH: usize = 8;
|
||||
|
@ -13,7 +13,6 @@ use crate::poh_recorder::PohRecorder;
|
||||
use crate::result::{Error, Result};
|
||||
use crate::rpc_subscriptions::RpcSubscriptions;
|
||||
use crate::service::Service;
|
||||
use hashbrown::HashMap;
|
||||
use solana_metrics::{datapoint_warn, inc_new_counter_error, inc_new_counter_info};
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::hash::Hash;
|
||||
@ -22,6 +21,7 @@ use solana_sdk::signature::KeypairUtil;
|
||||
use solana_sdk::timing::{self, duration_as_ms};
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use solana_vote_api::vote_instruction;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::mpsc::{channel, Receiver, RecvTimeoutError, Sender};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
@ -510,7 +510,7 @@ impl ReplayStage {
|
||||
let bank_slot = bank.slot();
|
||||
let bank_progress = &mut progress
|
||||
.entry(bank_slot)
|
||||
.or_insert(ForkProgress::new(bank.last_blockhash()));
|
||||
.or_insert_with(|| ForkProgress::new(bank.last_blockhash()));
|
||||
blocktree.get_slot_entries_with_blob_count(bank_slot, bank_progress.num_blobs as u64, None)
|
||||
}
|
||||
|
||||
@ -522,7 +522,7 @@ impl ReplayStage {
|
||||
) -> Result<()> {
|
||||
let bank_progress = &mut progress
|
||||
.entry(bank.slot())
|
||||
.or_insert(ForkProgress::new(bank.last_blockhash()));
|
||||
.or_insert_with(|| ForkProgress::new(bank.last_blockhash()));
|
||||
let result = Self::verify_and_process_entries(&bank, &entries, &bank_progress.last_entry);
|
||||
bank_progress.num_blobs += num;
|
||||
if let Some(last_entry) = entries.last() {
|
||||
|
@ -1,9 +1,9 @@
|
||||
use hashbrown::HashMap;
|
||||
use solana_runtime::bank::Bank;
|
||||
use solana_sdk::account::Account;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_vote_api::vote_state::VoteState;
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Looks through vote accounts, and finds the latest slot that has achieved
|
||||
/// supermajority lockout
|
||||
@ -47,7 +47,7 @@ pub fn vote_account_stakes_at_epoch(
|
||||
/// that have non-zero balance in any of their managed staking accounts
|
||||
pub fn staked_nodes_at_epoch(bank: &Bank, epoch_height: u64) -> Option<HashMap<Pubkey, u64>> {
|
||||
bank.epoch_vote_accounts(epoch_height)
|
||||
.map(|vote_accounts| to_staked_nodes(to_vote_states(vote_accounts.into_iter())))
|
||||
.map(|vote_accounts| to_staked_nodes(to_vote_states(vote_accounts.iter())))
|
||||
}
|
||||
|
||||
// input (vote_pubkey, (stake, vote_account)) => (stake, vote_state)
|
||||
@ -78,7 +78,7 @@ fn epoch_stakes_and_lockouts(bank: &Bank, epoch_height: u64) -> Vec<(u64, Option
|
||||
let node_staked_accounts = bank
|
||||
.epoch_vote_accounts(epoch_height)
|
||||
.expect("Bank state for epoch is missing")
|
||||
.into_iter();
|
||||
.iter();
|
||||
|
||||
to_vote_states(node_staked_accounts)
|
||||
.map(|(stake, states)| (stake, states.root_slot))
|
||||
@ -116,13 +116,13 @@ pub(crate) mod tests {
|
||||
create_genesis_block, create_genesis_block_with_leader, GenesisBlockInfo,
|
||||
BOOTSTRAP_LEADER_LAMPORTS,
|
||||
};
|
||||
use hashbrown::HashSet;
|
||||
use solana_sdk::instruction::Instruction;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use solana_sdk::signature::{Keypair, KeypairUtil};
|
||||
use solana_sdk::transaction::Transaction;
|
||||
use solana_stake_api::stake_instruction;
|
||||
use solana_vote_api::vote_instruction;
|
||||
use std::collections::HashSet;
|
||||
use std::iter::FromIterator;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -38,6 +38,7 @@ pub struct ValidatorConfig {
|
||||
pub storage_rotate_count: u64,
|
||||
pub account_paths: Option<String>,
|
||||
pub rpc_config: JsonRpcConfig,
|
||||
pub snapshot_path: Option<String>,
|
||||
}
|
||||
impl Default for ValidatorConfig {
|
||||
fn default() -> Self {
|
||||
@ -52,6 +53,7 @@ impl Default for ValidatorConfig {
|
||||
storage_rotate_count: NUM_HASHES_FOR_STORAGE_ROTATE,
|
||||
account_paths: None,
|
||||
rpc_config: JsonRpcConfig::default(),
|
||||
snapshot_path: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,7 +95,11 @@ impl Validator {
|
||||
completed_slots_receiver,
|
||||
leader_schedule_cache,
|
||||
poh_config,
|
||||
) = new_banks_from_blocktree(ledger_path, config.account_paths.clone());
|
||||
) = new_banks_from_blocktree(
|
||||
ledger_path,
|
||||
config.account_paths.clone(),
|
||||
config.snapshot_path.clone(),
|
||||
);
|
||||
|
||||
let leader_schedule_cache = Arc::new(leader_schedule_cache);
|
||||
let exit = Arc::new(AtomicBool::new(false));
|
||||
@ -108,7 +114,7 @@ impl Validator {
|
||||
let blocktree = Arc::new(blocktree);
|
||||
|
||||
let poh_config = Arc::new(poh_config);
|
||||
let (poh_recorder, entry_receiver) = PohRecorder::new_with_clear_signal(
|
||||
let (mut poh_recorder, entry_receiver) = PohRecorder::new_with_clear_signal(
|
||||
bank.tick_height(),
|
||||
bank.last_blockhash(),
|
||||
bank.slot(),
|
||||
@ -120,6 +126,10 @@ impl Validator {
|
||||
&leader_schedule_cache,
|
||||
&poh_config,
|
||||
);
|
||||
if config.snapshot_path.is_some() {
|
||||
poh_recorder.set_bank(&bank);
|
||||
}
|
||||
|
||||
let poh_recorder = Arc::new(Mutex::new(poh_recorder));
|
||||
let poh_service = PohService::new(poh_recorder.clone(), &poh_config, &exit);
|
||||
assert_eq!(
|
||||
@ -280,9 +290,40 @@ impl Validator {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_bank_forks(
|
||||
genesis_block: &GenesisBlock,
|
||||
blocktree: &Blocktree,
|
||||
account_paths: Option<String>,
|
||||
snapshot_path: Option<String>,
|
||||
) -> (BankForks, Vec<BankForksInfo>, LeaderScheduleCache) {
|
||||
if snapshot_path.is_some() {
|
||||
let bank_forks = BankForks::load_from_snapshot(&snapshot_path);
|
||||
match bank_forks {
|
||||
Ok(v) => {
|
||||
let bank = &v.working_bank();
|
||||
let fork_info = BankForksInfo {
|
||||
bank_slot: bank.slot(),
|
||||
entry_height: bank.tick_height(),
|
||||
};
|
||||
return (v, vec![fork_info], LeaderScheduleCache::new_from_bank(bank));
|
||||
}
|
||||
Err(_) => warn!("Failed to load from snapshot, fallback to load from ledger"),
|
||||
}
|
||||
}
|
||||
let (mut bank_forks, bank_forks_info, leader_schedule_cache) =
|
||||
blocktree_processor::process_blocktree(&genesis_block, &blocktree, account_paths)
|
||||
.expect("process_blocktree failed");
|
||||
if snapshot_path.is_some() {
|
||||
bank_forks.set_snapshot_config(snapshot_path);
|
||||
let _ = bank_forks.add_snapshot(0, 0);
|
||||
}
|
||||
(bank_forks, bank_forks_info, leader_schedule_cache)
|
||||
}
|
||||
|
||||
pub fn new_banks_from_blocktree(
|
||||
blocktree_path: &str,
|
||||
account_paths: Option<String>,
|
||||
snapshot_path: Option<String>,
|
||||
) -> (
|
||||
BankForks,
|
||||
Vec<BankForksInfo>,
|
||||
@ -300,8 +341,7 @@ pub fn new_banks_from_blocktree(
|
||||
.expect("Expected to successfully open database ledger");
|
||||
|
||||
let (bank_forks, bank_forks_info, leader_schedule_cache) =
|
||||
blocktree_processor::process_blocktree(&genesis_block, &blocktree, account_paths)
|
||||
.expect("process_blocktree failed");
|
||||
get_bank_forks(&genesis_block, &blocktree, account_paths, snapshot_path);
|
||||
|
||||
(
|
||||
bank_forks,
|
||||
|
Reference in New Issue
Block a user