Make Bank::hash_internal_state() work with checkpoints

This commit is contained in:
Greg Fitzgerald 2019-02-18 11:23:09 -07:00
parent 760a82cb08
commit 90684483e2
2 changed files with 32 additions and 13 deletions

View File

@ -10,13 +10,13 @@ use crate::last_id_queue::{LastIdQueue, MAX_ENTRY_IDS};
use crate::poh_service::NUM_TICKS_PER_SECOND;
use crate::rpc_subscriptions::RpcSubscriptions;
use crate::status_cache::StatusCache;
use bincode::deserialize;
use bincode::{deserialize, serialize};
use log::Level;
use solana_runtime::{self, RuntimeError};
use solana_sdk::account::Account;
use solana_sdk::bpf_loader;
use solana_sdk::budget_program;
use solana_sdk::hash::Hash;
use solana_sdk::hash::{extend_and_hash, Hash};
use solana_sdk::native_loader;
use solana_sdk::native_program::ProgramError;
use solana_sdk::pubkey::Pubkey;
@ -92,6 +92,8 @@ pub struct Bank {
subscriptions: RwLock<Option<Arc<RpcSubscriptions>>>,
parent: Option<Arc<Bank>>,
parent_hash: Hash,
}
impl Default for Bank {
@ -102,14 +104,16 @@ impl Default for Bank {
status_cache: RwLock::new(BankStatusCache::default()),
subscriptions: RwLock::new(None),
parent: None,
parent_hash: Hash::default(),
}
}
}
impl Bank {
pub fn new(genesis_block: &GenesisBlock) -> Self {
let bank = Self::default();
let mut bank = Self::default();
bank.process_genesis_block(genesis_block);
bank.parent_hash = bank.hash_internal_state();
bank.add_builtin_programs();
bank
}
@ -117,6 +121,7 @@ impl Bank {
pub fn new_from_parent(parent: &Arc<Bank>) -> Self {
let mut bank = Self::default();
bank.last_id_queue = RwLock::new(parent.last_id_queue.read().unwrap().clone());
bank.parent_hash = parent.hash_internal_state();
bank.parent = Some(parent.clone());
bank
}
@ -131,7 +136,7 @@ impl Bank {
*sub = Some(subscriptions)
}
pub fn process_genesis_block(&self, genesis_block: &GenesisBlock) {
fn process_genesis_block(&self, genesis_block: &GenesisBlock) {
assert!(genesis_block.mint_id != Pubkey::default());
assert!(genesis_block.bootstrap_leader_id != Pubkey::default());
assert!(genesis_block.bootstrap_leader_vote_account_id != Pubkey::default());
@ -181,7 +186,7 @@ impl Bank {
.genesis_last_id(&genesis_block.last_id());
}
pub fn add_builtin_programs(&self) {
fn add_builtin_programs(&self) {
let system_program_account = native_loader::create_program_account("solana_system_program");
self.accounts
.store_slow(true, &system_program::id(), &system_program_account);
@ -593,7 +598,15 @@ impl Bank {
/// Hash the `accounts` HashMap. This represents a validator's interpretation
/// of the delta of the ledger since the last vote and up to now
pub fn hash_internal_state(&self) -> Hash {
self.accounts.hash_internal_state()
// If there are no accounts, return the same hash as we did before
// checkpointing.
let accounts = &self.accounts.accounts_db.read().unwrap().accounts;
if accounts.is_empty() {
return self.parent_hash;
}
let accounts_delta_hash = self.accounts.hash_internal_state();
extend_and_hash(&self.parent_hash, &serialize(&accounts_delta_hash).unwrap())
}
fn send_account_notifications(
@ -653,7 +666,6 @@ impl Bank {
#[cfg(test)]
mod tests {
use super::*;
use bincode::serialize;
use hashbrown::HashSet;
use solana_sdk::hash::hash;
use solana_sdk::native_program::ProgramError;

View File

@ -315,13 +315,9 @@ mod tests {
&keypairs,
);
let bank0 = Bank::default();
bank0.add_builtin_programs();
bank0.process_genesis_block(&genesis_block);
let bank0 = Bank::new(&genesis_block);
par_process_entries(&bank0, &entries0).unwrap();
let bank1 = Bank::default();
bank1.add_builtin_programs();
bank1.process_genesis_block(&genesis_block);
let bank1 = Bank::new(&genesis_block);
par_process_entries(&bank1, &entries1).unwrap();
let initial_state = bank0.hash_internal_state();
@ -337,6 +333,17 @@ mod tests {
.transfer(1_000, &mint_keypair, pubkey, bank1.last_id())
.unwrap();
assert_eq!(bank0.hash_internal_state(), bank1.hash_internal_state());
// Checkpointing should not change its state
let bank2 = Bank::new_from_parent(&Arc::new(bank1));
assert_eq!(bank0.hash_internal_state(), bank2.hash_internal_state());
}
#[test]
fn test_hash_internal_state_parents() {
let bank0 = Bank::new(&GenesisBlock::new(10).0);
let bank1 = Bank::new(&GenesisBlock::new(20).0);
assert_ne!(bank0.hash_internal_state(), bank1.hash_internal_state());
}
#[test]