Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check bank capitalization (bp #11927) #12184

Merged
merged 3 commits into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions accounts-bench/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ solana-logger = { path = "../logger", version = "1.3.10" }
solana-runtime = { path = "../runtime", version = "1.3.10" }
solana-measure = { path = "../measure", version = "1.3.10" }
solana-sdk = { path = "../sdk", version = "1.3.10" }
solana-version = { path = "../version", version = "1.3.10" }
rand = "0.7.0"
clap = "2.33.1"
crossbeam-channel = "0.4"
Expand Down
14 changes: 8 additions & 6 deletions accounts-bench/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
use clap::{value_t, App, Arg};
use clap::{crate_description, crate_name, value_t, App, Arg};
use rayon::prelude::*;
use solana_measure::measure::Measure;
use solana_runtime::{
accounts::{create_test_accounts, update_accounts, Accounts},
accounts_index::Ancestors,
};
use solana_sdk::{genesis_config::ClusterType, pubkey::Pubkey};
use std::env;
use std::fs;
use std::path::PathBuf;

fn main() {
solana_logger::setup();

let matches = App::new("crate")
.about("about")
.version("version")
let matches = App::new(crate_name!())
.about(crate_description!())
.version(solana_version::version!())
.arg(
Arg::with_name("num_slots")
.long("num_slots")
Expand Down Expand Up @@ -50,7 +51,8 @@ fn main() {
let clean = matches.is_present("clean");
println!("clean: {:?}", clean);

let path = PathBuf::from("farf/accounts-bench");
let path = PathBuf::from(env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_owned()))
.join("accounts-bench");
if fs::remove_dir_all(path.clone()).is_err() {
println!("Warning: Couldn't remove {:?}", path);
}
Expand Down Expand Up @@ -96,7 +98,7 @@ fn main() {
} else {
let mut pubkeys: Vec<Pubkey> = vec![];
let mut time = Measure::start("hash");
let hash = accounts.accounts_db.update_accounts_hash(0, &ancestors);
let hash = accounts.accounts_db.update_accounts_hash(0, &ancestors).0;
time.stop();
println!("hash: {} {}", hash, time);
create_test_accounts(&accounts, &mut pubkeys, 1, 0);
Expand Down
2 changes: 1 addition & 1 deletion core/src/non_circulating_supply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub fn calculate_non_circulating_supply(bank: &Arc<Bank>) -> NonCirculatingSuppl
let withdraw_authority_list = withdraw_authority();

let clock = bank.clock();
let stake_accounts = bank.get_program_accounts(Some(&solana_stake_program::id()));
let stake_accounts = bank.get_program_accounts(&solana_stake_program::id());
for (pubkey, account) in stake_accounts.iter() {
let stake_account = StakeState::from(&account).unwrap_or_default();
match stake_account {
Expand Down
2 changes: 1 addition & 1 deletion core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1308,7 +1308,7 @@ fn get_filtered_program_accounts(
program_id: &Pubkey,
filters: Vec<RpcFilterType>,
) -> impl Iterator<Item = (Pubkey, Account)> {
bank.get_program_accounts(Some(&program_id))
bank.get_program_accounts(&program_id)
.into_iter()
.filter(move |(_, account)| {
filters.iter().all(|filter_type| match filter_type {
Expand Down
17 changes: 4 additions & 13 deletions ledger-tool/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use solana_vote_program::{
};
use std::{
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
convert::{TryFrom, TryInto},
convert::TryInto,
ffi::OsStr,
fs::{self, File},
io::{self, stdout, BufRead, BufReader, Write},
Expand Down Expand Up @@ -708,16 +708,7 @@ fn open_genesis_config_by(ledger_path: &Path, matches: &ArgMatches<'_>) -> Genes
}

fn assert_capitalization(bank: &Bank) {
let calculated_capitalization = bank.calculate_capitalization();
assert_eq!(
bank.capitalization(),
calculated_capitalization,
"Capitalization mismatch!?: +/-{}",
Sol(u64::try_from(
(i128::from(calculated_capitalization) - i128::from(bank.capitalization())).abs()
)
.unwrap()),
);
assert!(bank.calculate_and_verify_capitalization());
}

#[allow(clippy::cognitive_complexity)]
Expand Down Expand Up @@ -1695,7 +1686,7 @@ fn main() {

if remove_stake_accounts {
for (address, mut account) in bank
.get_program_accounts(Some(&solana_stake_program::id()))
.get_program_accounts(&solana_stake_program::id())
.into_iter()
{
account.lamports = 0;
Expand Down Expand Up @@ -1723,7 +1714,7 @@ fn main() {

// Delete existing vote accounts
for (address, mut account) in bank
.get_program_accounts(Some(&solana_vote_program::id()))
.get_program_accounts(&solana_vote_program::id())
.into_iter()
{
account.lamports = 0;
Expand Down
10 changes: 10 additions & 0 deletions ledger/src/blockstore_processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ pub enum BlockstoreProcessorError {

#[error("invalid hard fork")]
InvalidHardFork(Slot),

#[error("root bank with mismatched capitalization at {0}")]
RootBankWithMismatchedCapitalization(Slot),
}

/// Callback for accessing bank state while processing the blockstore
Expand Down Expand Up @@ -481,6 +484,13 @@ fn do_process_blockstore_from_root(
);
assert!(bank_forks.active_banks().is_empty());

// We might be promptly restarted after bad capitalization was detected while creating newer snapshot.
// In that case, we're most likely restored from the last good snapshot and replayed up to this root.
// So again check here for the bad capitalization to avoid to continue until the next snapshot creation.
if !bank_forks.root_bank().calculate_and_verify_capitalization() {
return Err(BlockstoreProcessorError::RootBankWithMismatchedCapitalization(root));
}

Ok((bank_forks, leader_schedule_cache))
}

Expand Down
8 changes: 5 additions & 3 deletions runtime/benches/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,12 @@ fn test_accounts_hash_bank_hash(bencher: &mut Bencher) {
&ClusterType::Development,
);
let mut pubkeys: Vec<Pubkey> = vec![];
create_test_accounts(&accounts, &mut pubkeys, 60000, 0);
let num_accounts = 60_000;
let slot = 0;
create_test_accounts(&accounts, &mut pubkeys, num_accounts, slot);
let ancestors = vec![(0, 0)].into_iter().collect();
accounts.accounts_db.update_accounts_hash(0, &ancestors);
bencher.iter(|| assert!(accounts.verify_bank_hash(0, &ancestors)));
let (_, total_lamports) = accounts.accounts_db.update_accounts_hash(0, &ancestors);
bencher.iter(|| assert!(accounts.verify_bank_hash_and_lamports(0, &ancestors, total_lamports)));
}

#[bench]
Expand Down
31 changes: 27 additions & 4 deletions runtime/src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,32 @@ impl Accounts {
accounts_balances
}

pub fn calculate_capitalization(&self, ancestors: &Ancestors) -> u64 {
let balances = self
.load_all(ancestors)
.into_iter()
.map(|(_pubkey, account, _slot)| {
AccountsDB::account_balance_for_capitalization(
account.lamports,
&account.owner,
account.executable,
)
});

AccountsDB::checked_sum_for_capitalization(balances)
}

#[must_use]
pub fn verify_bank_hash(&self, slot: Slot, ancestors: &Ancestors) -> bool {
if let Err(err) = self.accounts_db.verify_bank_hash(slot, ancestors) {
pub fn verify_bank_hash_and_lamports(
&self,
slot: Slot,
ancestors: &Ancestors,
total_lamports: u64,
) -> bool {
if let Err(err) =
self.accounts_db
.verify_bank_hash_and_lamports(slot, ancestors, total_lamports)
{
warn!("verify_bank_hash failed: {:?}", err);
false
} else {
Expand Down Expand Up @@ -460,13 +483,13 @@ impl Accounts {
pub fn load_by_program(
&self,
ancestors: &Ancestors,
program_id: Option<&Pubkey>,
program_id: &Pubkey,
) -> Vec<(Pubkey, Account)> {
self.accounts_db.scan_accounts(
ancestors,
|collector: &mut Vec<(Pubkey, Account)>, some_account_tuple| {
Self::load_while_filtering(collector, some_account_tuple, |account| {
program_id.is_none() || Some(&account.owner) == program_id
account.owner == *program_id
})
},
)
Expand Down
Loading