From deb5108257f7cd256854269316500476c4a89c1b Mon Sep 17 00:00:00 2001 From: Sathish Ambley Date: Thu, 2 May 2019 20:56:23 -0700 Subject: [PATCH] Remove rc feature dependency --- core/src/bank_forks.rs | 57 +++++++++--- runtime/Cargo.toml | 2 +- runtime/src/accounts.rs | 11 ++- runtime/src/accounts_db.rs | 135 +++++++++++++++++++++-------- runtime/src/append_vec.rs | 7 +- runtime/src/bank.rs | 173 +++++++++++++++++++++++++++++-------- 6 files changed, 292 insertions(+), 93 deletions(-) diff --git a/core/src/bank_forks.rs b/core/src/bank_forks.rs index ade0601f3e981f..9d754963c2888f 100644 --- a/core/src/bank_forks.rs +++ b/core/src/bank_forks.rs @@ -169,7 +169,7 @@ impl BankForks { let bank_file_path = path.join(bank_file); let file = File::create(bank_file_path)?; let mut stream = BufWriter::new(file); - serialize_into(&mut stream, self.get(slot).unwrap()) + serialize_into(&mut stream, &*self.get(slot).unwrap().clone()) .map_err(|_| BankForks::get_io_error("serialize bank error"))?; Ok(()) } @@ -185,6 +185,37 @@ impl BankForks { self.use_snapshot = use_snapshot; } + fn setup_banks( + bank_maps: &mut Vec<(u64, Bank)>, + ) -> (HashMap>, HashSet, u64) { + let mut banks = HashMap::new(); + let mut slots = HashSet::new(); + let (last_slot, mut last_bank) = bank_maps.remove(0); + let accounts = last_bank.accounts(); + let status_cache = last_bank.status_cache(); + + while let Some((slot, mut bank)) = bank_maps.pop() { + bank.set_accounts(&accounts); + bank.set_status_cache(&status_cache); + if bank.parent_slot() != 0 { + if let Some(parent) = banks.get(&bank.parent_slot()) { + bank.set_parent(parent); + } + } + banks.insert(slot, Arc::new(bank)); + slots.insert(slot); + } + if last_bank.parent_slot() != 0 { + if let Some(parent) = banks.get(&last_bank.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() -> Result { let path = BankForks::get_snapshot_path(); let paths = fs::read_dir(path.clone())?; @@ -199,9 +230,7 @@ impl BankForks { .collect::>(); names.sort(); - let mut banks: HashMap> = HashMap::new(); - let mut slots = HashSet::new(); - let mut last_slot: u64 = 0; + let mut bank_maps = vec![]; for bank_slot in names.clone() { let bank_path = format!("{}", bank_slot); let bank_file_path = path.join(bank_path.clone()); @@ -211,15 +240,15 @@ impl BankForks { let bank: Result = deserialize_from(&mut stream) .map_err(|_| BankForks::get_io_error("deserialize bank error")); match bank { - Ok(v) => { - banks.insert(bank_slot, Arc::new(v)); - slots.insert(bank_slot); - last_slot = bank_slot; - } + Ok(v) => bank_maps.insert(0, (bank_slot, v)), Err(_) => warn!("Load snapshot failed for {}", bank_slot), } } - info!("last slot: {}", last_slot); + if bank_maps.is_empty() { + return Err(Error::new(ErrorKind::Other, "no snapshots loaded")); + } + + let (banks, slots, last_slot) = BankForks::setup_banks(&mut bank_maps); let working_bank = banks[&last_slot].clone(); Ok(BankForks { banks, @@ -354,11 +383,11 @@ mod tests { } fn save_and_load_snapshot(bank_forks: &BankForks) { - let bank = bank_forks.banks.get(&0).unwrap(); + let bank = bank_forks.banks.get(&0).unwrap().clone(); let tick_height = bank.tick_height(); - let bank_ser = serialize(&bank).unwrap(); - let child_bank = bank_forks.banks.get(&1).unwrap(); - let child_bank_ser = serialize(&child_bank).unwrap(); + let bank_ser = serialize(&*bank).unwrap(); + let child_bank = bank_forks.banks.get(&1).unwrap().clone(); + let child_bank_ser = serialize(&*child_bank).unwrap(); for (slot, _) in bank_forks.banks.iter() { bank_forks.add_snapshot(*slot).unwrap(); } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 682b17cddeeacf..0db386d923dd2a 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4.2" memmap = "0.6.2" rand = "0.6.5" rayon = "1.0.0" -serde = { version = "1.0.88", features = ["rc"] } +serde = "1.0.88" serde_derive = "1.0.88" serde_json = "1.0.38" solana-logger = { path = "../logger", version = "0.15.0" } diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index b4c694f03372e5..a627094da54ff8 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -41,6 +41,7 @@ type AccountLocks = ( #[derive(Default, Debug, Serialize, Deserialize)] pub struct Accounts { /// Single global AccountsDB + #[serde(skip)] pub accounts_db: Arc, /// set of accounts which are currently in the pipeline @@ -60,7 +61,6 @@ impl Drop for Accounts { if self.own_paths && (Arc::strong_count(&self.accounts_db) == 1) { let paths = get_paths_vec(&self.paths); paths.iter().for_each(|p| { - info!("drop remove {:?}", p); let _ignored = remove_dir_all(p); // it is safe to delete the parent @@ -1054,12 +1054,17 @@ mod tests { check_accounts(&accounts, &pubkeys, 100); accounts.add_root(0); - let mut buf = vec![0u8; serialized_size(&accounts).unwrap() as usize]; + let sz = + serialized_size(&accounts).unwrap() + serialized_size(&*accounts.accounts_db).unwrap(); + let mut buf = vec![0u8; sz as usize]; let mut writer = Cursor::new(&mut buf[..]); serialize_into(&mut writer, &accounts).unwrap(); + serialize_into(&mut writer, &*accounts.accounts_db).unwrap(); let mut reader = Cursor::new(&mut buf[..]); - let daccounts: Accounts = deserialize_from(&mut reader).unwrap(); + let mut daccounts: Accounts = deserialize_from(&mut reader).unwrap(); + let accounts_db: AccountsDB = deserialize_from(&mut reader).unwrap(); + daccounts.accounts_db = Arc::new(accounts_db); check_accounts(&daccounts, &pubkeys, 100); assert_eq!( accounts.hash_internal_state(0), diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index acdd6a21957d08..29ff76a670ee16 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -24,6 +24,8 @@ use bincode::{deserialize_from, serialize_into, serialized_size}; use log::*; use rand::{thread_rng, Rng}; use rayon::prelude::*; +use serde::de::{MapAccess, Visitor}; +use serde::ser::{SerializeMap, Serializer}; use serde::{Deserialize, Serialize}; use solana_sdk::account::Account; use solana_sdk::pubkey::Pubkey; @@ -67,10 +69,58 @@ pub struct AccountInfo { } /// An offset into the AccountsDB::storage vector pub type AppendVecId = usize; -pub type AccountStorage = HashMap>; pub type InstructionAccounts = Vec; pub type InstructionLoaders = Vec>; +#[derive(Default, Debug)] +pub struct AccountStorage(HashMap>); + +struct AccountStorageVisitor; + +impl<'de> Visitor<'de> for AccountStorageVisitor { + type Value = AccountStorage; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Expecting AccountStorage") + } + + #[allow(clippy::mutex_atomic)] + fn visit_map(self, mut access: M) -> Result + where + M: MapAccess<'de>, + { + let mut map = HashMap::new(); + + while let Some((key, value)) = access.next_entry()? { + map.insert(key, Arc::new(value)); + } + + Ok(AccountStorage(map)) + } +} + +impl Serialize for AccountStorage { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(self.0.len()))?; + for (k, v) in &self.0 { + map.serialize_entry(k, &**v)?; + } + map.end() + } +} + +impl<'de> Deserialize<'de> for AccountStorage { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_map(AccountStorageVisitor) + } +} + #[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)] pub enum AccountStorageStatus { StorageAvailable = 0, @@ -200,7 +250,7 @@ impl AccountsDB { let paths = get_paths_vec(&paths); AccountsDB { accounts_index: RwLock::new(AccountsIndex::default()), - storage: RwLock::new(HashMap::new()), + storage: RwLock::new(AccountStorage(HashMap::new())), next_id: AtomicUsize::new(0), write_version: AtomicUsize::new(0), paths, @@ -222,7 +272,7 @@ impl AccountsDB { } pub fn has_accounts(&self, fork: Fork) -> bool { - for x in self.storage.read().unwrap().values() { + for x in self.storage.read().unwrap().0.values() { if x.fork_id == fork && x.count() > 0 { return true; } @@ -242,6 +292,7 @@ impl AccountsDB { .storage .read() .unwrap() + .0 .values() .filter(|store| store.fork_id == fork_id) .cloned() @@ -268,6 +319,7 @@ impl AccountsDB { let info = accounts_index.get(pubkey, ancestors)?; //TODO: thread this as a ref storage + .0 .get(&info.id) .and_then(|store| Some(store.accounts.get_account(info.offset)?.0.clone_account())) } @@ -282,6 +334,7 @@ impl AccountsDB { let mut candidates: Vec> = { let stores = self.storage.read().unwrap(); stores + .0 .values() .filter_map(|x| { if x.status() == AccountStorageStatus::StorageAvailable && x.fork_id == fork_id @@ -297,7 +350,7 @@ impl AccountsDB { let mut stores = self.storage.write().unwrap(); let path_idx = thread_rng().gen_range(0, self.paths.len()); let storage = Arc::new(self.new_storage_entry(fork_id, &self.paths[path_idx])); - stores.insert(storage.id, storage.clone()); + stores.0.insert(storage.id, storage.clone()); candidates.push(storage); } let rv = thread_rng().gen_range(0, candidates.len()); @@ -309,7 +362,7 @@ impl AccountsDB { let is_root = self.accounts_index.read().unwrap().is_root(fork); trace!("PURGING {} {}", fork, is_root); if !is_root { - self.storage.write().unwrap().retain(|_, v| { + self.storage.write().unwrap().0.retain(|_, v| { trace!("PURGING {} {}", v.fork_id, fork); v.fork_id != fork }); @@ -371,7 +424,7 @@ impl AccountsDB { fn remove_dead_accounts(&self, reclaims: Vec<(Fork, AccountInfo)>) -> HashSet { let storage = self.storage.read().unwrap(); for (fork_id, account_info) in reclaims { - if let Some(store) = storage.get(&account_info.id) { + if let Some(store) = storage.0.get(&account_info.id) { assert_eq!( fork_id, store.fork_id, "AccountDB::accounts_index corrupted. Storage should only point to one fork" @@ -381,6 +434,7 @@ impl AccountsDB { } //TODO: performance here could be improved if AccountsDB::storage was organized by fork let dead_forks: HashSet = storage + .0 .values() .filter_map(|x| { if x.count() == 0 { @@ -391,6 +445,7 @@ impl AccountsDB { }) .collect(); let live_forks: HashSet = storage + .0 .values() .filter_map(|x| if x.count() > 0 { Some(x.fork_id) } else { None }) .collect(); @@ -442,6 +497,7 @@ impl AccountsDB { .storage .read() .unwrap() + .0 .values() .map(|x| x.fork_id) .collect(); @@ -469,11 +525,9 @@ impl AccountsDB { while let Some(maps) = accumulator.pop() { AccountsDB::merge(&mut account_maps, &maps); } - let storage = self.fork_storage(*fork_id); let mut accounts_index = self.accounts_index.write().unwrap(); for (pubkey, (_, account_info)) in account_maps.iter() { accounts_index.insert(*fork_id, pubkey, account_info.clone()); - storage.add_account(); } } } @@ -528,7 +582,7 @@ impl<'a> serde::de::Visitor<'a> for AccountsDBVisitor { let write_version: u64 = deserialize_from(&mut rd).map_err(Error::custom)?; let file_size: u64 = deserialize_from(&mut rd).map_err(Error::custom)?; - let mut ids: Vec = storage.read().unwrap().keys().cloned().collect(); + let mut ids: Vec = storage.read().unwrap().0.keys().cloned().collect(); ids.sort(); let mut accounts_db = AccountsDB { @@ -756,16 +810,16 @@ mod tests { db.store(1, &[(&pubkeys[0], &account)]); { let stores = db.storage.read().unwrap(); - assert_eq!(stores.len(), 2); - assert_eq!(stores[&0].count(), 2); - assert_eq!(stores[&1].count(), 2); + assert_eq!(stores.0.len(), 2); + assert_eq!(stores.0[&0].count(), 2); + assert_eq!(stores.0[&1].count(), 2); } db.add_root(1); { let stores = db.storage.read().unwrap(); - assert_eq!(stores.len(), 2); - assert_eq!(stores[&0].count(), 2); - assert_eq!(stores[&1].count(), 2); + assert_eq!(stores.0.len(), 2); + assert_eq!(stores.0[&0].count(), 2); + assert_eq!(stores.0[&1].count(), 2); } } @@ -838,9 +892,12 @@ mod tests { fn check_storage(accounts: &AccountsDB, count: usize) -> bool { let stores = accounts.storage.read().unwrap(); - assert_eq!(stores.len(), 1); - assert_eq!(stores[&0].status(), AccountStorageStatus::StorageAvailable); - stores[&0].count() == count + assert_eq!(stores.0.len(), 1); + assert_eq!( + stores.0[&0].status(), + AccountStorageStatus::StorageAvailable + ); + stores.0[&0].count() == count } fn check_accounts( @@ -925,7 +982,7 @@ mod tests { } let mut append_vec_histogram = HashMap::new(); - for storage in accounts.storage.read().unwrap().values() { + for storage in accounts.storage.read().unwrap().0.values() { *append_vec_histogram.entry(storage.fork_id).or_insert(0) += 1; } for count in append_vec_histogram.values() { @@ -947,9 +1004,12 @@ mod tests { accounts.store(0, &[(&pubkey1, &account1)]); { let stores = accounts.storage.read().unwrap(); - assert_eq!(stores.len(), 1); - assert_eq!(stores[&0].count(), 1); - assert_eq!(stores[&0].status(), AccountStorageStatus::StorageAvailable); + assert_eq!(stores.0.len(), 1); + assert_eq!(stores.0[&0].count(), 1); + assert_eq!( + stores.0[&0].status(), + AccountStorageStatus::StorageAvailable + ); } let pubkey2 = Pubkey::new_rand(); @@ -957,11 +1017,14 @@ mod tests { accounts.store(0, &[(&pubkey2, &account2)]); { let stores = accounts.storage.read().unwrap(); - assert_eq!(stores.len(), 2); - assert_eq!(stores[&0].count(), 1); - assert_eq!(stores[&0].status(), AccountStorageStatus::StorageFull); - assert_eq!(stores[&1].count(), 1); - assert_eq!(stores[&1].status(), AccountStorageStatus::StorageAvailable); + assert_eq!(stores.0.len(), 2); + assert_eq!(stores.0[&0].count(), 1); + assert_eq!(stores.0[&0].status(), AccountStorageStatus::StorageFull); + assert_eq!(stores.0[&1].count(), 1); + assert_eq!( + stores.0[&1].status(), + AccountStorageStatus::StorageAvailable + ); } let ancestors = vec![(0, 0)].into_iter().collect(); assert_eq!(accounts.load_slow(&ancestors, &pubkey1).unwrap(), account1); @@ -973,13 +1036,13 @@ mod tests { accounts.store(0, &[(&pubkey1, &account1)]); { let stores = accounts.storage.read().unwrap(); - assert_eq!(stores.len(), 3); - assert_eq!(stores[&0].count(), count[index]); - assert_eq!(stores[&0].status(), status[0]); - assert_eq!(stores[&1].count(), 1); - assert_eq!(stores[&1].status(), status[1]); - assert_eq!(stores[&2].count(), count[index ^ 1]); - assert_eq!(stores[&2].status(), status[0]); + assert_eq!(stores.0.len(), 3); + assert_eq!(stores.0[&0].count(), count[index]); + assert_eq!(stores.0[&0].status(), status[0]); + assert_eq!(stores.0[&1].count(), 1); + assert_eq!(stores.0[&1].status(), status[1]); + assert_eq!(stores.0[&2].count(), count[index ^ 1]); + assert_eq!(stores.0[&2].status(), status[0]); } let ancestors = vec![(0, 0)].into_iter().collect(); assert_eq!(accounts.load_slow(&ancestors, &pubkey1).unwrap(), account1); @@ -1035,13 +1098,13 @@ mod tests { assert!(accounts.accounts_index.read().unwrap().is_purged(0)); //fork is still there, since gc is lazy - assert!(accounts.storage.read().unwrap().get(&info.id).is_some()); + assert!(accounts.storage.read().unwrap().0.get(&info.id).is_some()); //store causes cleanup accounts.store(1, &[(&pubkey, &account)]); //fork is gone - assert!(accounts.storage.read().unwrap().get(&info.id).is_none()); + assert!(accounts.storage.read().unwrap().0.get(&info.id).is_none()); //new value is there let ancestors = vec![(1, 1)].into_iter().collect(); diff --git a/runtime/src/append_vec.rs b/runtime/src/append_vec.rs index 53f6f230ee9bb3..dd760d9043edfa 100644 --- a/runtime/src/append_vec.rs +++ b/runtime/src/append_vec.rs @@ -302,8 +302,9 @@ impl Serialize for AppendVec { S: serde::ser::Serializer, { use serde::ser::Error; - let len = - serialized_size(&self.path).unwrap() + 2 * serialized_size(&self.file_size).unwrap(); + let len = serialized_size(&self.path).unwrap() + + std::mem::size_of::() as u64 + + serialized_size(&self.file_size).unwrap(); let mut buf = vec![0u8; len as usize]; let mut wr = Cursor::new(&mut buf[..]); serialize_into(&mut wr, &self.path).map_err(Error::custom)?; @@ -340,7 +341,7 @@ impl<'a> serde::de::Visitor<'a> for AppendVecVisitor { .write(true) .create(false) .open(path.as_path()) - .unwrap(); + .map_err(Error::custom)?; let map = unsafe { MmapMut::map_mut(&data).expect("failed to map the data file") }; Ok(AppendVec { diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index e1d5fe1843111f..58fa872c87a2ec 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -4,7 +4,7 @@ //! already been signed and verified. use crate::accounts::Accounts; -use crate::accounts_db::{ErrorCounters, InstructionAccounts, InstructionLoaders}; +use crate::accounts_db::{AccountsDB, ErrorCounters, InstructionAccounts, InstructionLoaders}; use crate::blockhash_queue::BlockhashQueue; use crate::locked_accounts_results::LockedAccountsResults; use crate::message_processor::{MessageProcessor, ProcessInstruction}; @@ -12,7 +12,7 @@ use crate::serde_utils::{ deserialize_atomicbool, deserialize_atomicusize, serialize_atomicbool, serialize_atomicusize, }; use crate::status_cache::StatusCache; -use bincode::serialize; +use bincode::{deserialize_from, serialize, serialize_into, serialized_size}; use log::*; use serde::{Deserialize, Serialize}; use solana_metrics::counter::Counter; @@ -30,6 +30,8 @@ use solana_sdk::transaction::{Result, Transaction, TransactionError}; use solana_vote_api::vote_state::{self, Vote, MAX_LOCKOUT_HISTORY}; use std::cmp; use std::collections::HashMap; +use std::fmt; +use std::io::Cursor; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::{Arc, RwLock}; use std::time::Instant; @@ -123,20 +125,95 @@ impl EpochSchedule { type BankStatusCache = StatusCache>; -/// Manager for the state of all accounts and programs after processing its entries. -#[derive(Deserialize, Serialize, Default)] -pub struct Bank { +#[derive(Default)] +struct BankRc { /// where all the Accounts are stored accounts: Arc, /// A cache of signature statuses status_cache: Arc>, - /// FIFO queue of `recent_blockhash` items - blockhash_queue: RwLock, + /// parent slot + parent_slot: u64, /// Previous checkpoint of this bank parent: RwLock>>, +} + +impl Serialize for BankRc { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::ser::Serializer, + { + use serde::ser::Error; + let len = serialized_size(&*self.accounts.accounts_db).unwrap() + + serialized_size(&*self.accounts).unwrap() + + serialized_size(&*self.status_cache).unwrap() + + serialized_size(&self.parent_slot).unwrap(); + let mut parent_slot = 0; + let bank = self.parent.read().unwrap().clone(); + if bank.is_some() { + parent_slot = bank.unwrap().slot(); + } + let mut buf = vec![0u8; len as usize]; + let mut wr = Cursor::new(&mut buf[..]); + serialize_into(&mut wr, &*self.accounts.accounts_db).map_err(Error::custom)?; + serialize_into(&mut wr, &*self.accounts).map_err(Error::custom)?; + serialize_into(&mut wr, &*self.status_cache).map_err(Error::custom)?; + serialize_into(&mut wr, &parent_slot).map_err(Error::custom)?; + let len = wr.position() as usize; + serializer.serialize_bytes(&wr.into_inner()[..len]) + } +} + +struct BankRcVisitor; + +impl<'a> serde::de::Visitor<'a> for BankRcVisitor { + type Value = BankRc; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("Expecting BankRc") + } + + #[allow(clippy::mutex_atomic)] + fn visit_bytes(self, data: &[u8]) -> std::result::Result + where + E: serde::de::Error, + { + use serde::de::Error; + let mut rd = Cursor::new(&data[..]); + let accounts_db: AccountsDB = deserialize_from(&mut rd).map_err(Error::custom)?; + let mut accounts: Accounts = deserialize_from(&mut rd).map_err(Error::custom)?; + let status_cache: BankStatusCache = deserialize_from(&mut rd).map_err(Error::custom)?; + let parent_slot: u64 = deserialize_from(&mut rd).map_err(Error::custom)?; + + accounts.accounts_db = Arc::new(accounts_db); + Ok(BankRc { + accounts: Arc::new(accounts), + status_cache: Arc::new(RwLock::new(status_cache)), + parent_slot, + parent: RwLock::new(None), + }) + } +} + +impl<'de> Deserialize<'de> for BankRc { + fn deserialize(deserializer: D) -> std::result::Result + where + D: ::serde::Deserializer<'de>, + { + deserializer.deserialize_bytes(BankRcVisitor) + } +} + +/// Manager for the state of all accounts and programs after processing its entries. +#[derive(Default, Deserialize, Serialize)] +pub struct Bank { + /// References to accounts, parent and signature status + rc: BankRc, + + /// FIFO queue of `recent_blockhash` items + blockhash_queue: RwLock, /// The set of parents including this bank pub ancestors: HashMap, @@ -209,7 +286,7 @@ impl Bank { pub fn new_with_paths(genesis_block: &GenesisBlock, paths: Option) -> Self { let mut bank = Self::default(); bank.ancestors.insert(bank.slot(), 0); - bank.accounts = Arc::new(Accounts::new(paths)); + bank.rc.accounts = Arc::new(Accounts::new(paths)); bank.process_genesis_block(genesis_block); // genesis needs stakes for all epochs up to the epoch implied by // slot = 0 and genesis configuration @@ -227,7 +304,7 @@ impl Bank { let mut bank = Self::default(); bank.blockhash_queue = RwLock::new(parent.blockhash_queue.read().unwrap().clone()); - bank.status_cache = parent.status_cache.clone(); + bank.rc.status_cache = parent.rc.status_cache.clone(); bank.bank_height = parent.bank_height + 1; bank.transaction_count @@ -251,11 +328,12 @@ impl Bank { .to_owned(), ); - bank.parent = RwLock::new(Some(parent.clone())); + bank.rc.parent_slot = parent.slot(); + bank.rc.parent = RwLock::new(Some(parent.clone())); bank.parent_hash = parent.hash(); bank.collector_id = *collector_id; - bank.accounts = Arc::new(Accounts::new_from_parent(&parent.accounts)); + bank.rc.accounts = Arc::new(Accounts::new_from_parent(&parent.rc.accounts)); bank.epoch_vote_accounts = { let mut epoch_vote_accounts = parent.epoch_vote_accounts.clone(); @@ -311,19 +389,19 @@ impl Bank { self.freeze(); let parents = self.parents(); - *self.parent.write().unwrap() = None; + *self.rc.parent.write().unwrap() = None; let squash_accounts_start = Instant::now(); for p in parents.iter().rev() { // root forks cannot be purged - self.accounts.add_root(p.slot()); + self.rc.accounts.add_root(p.slot()); } let squash_accounts_ms = duration_as_ms(&squash_accounts_start.elapsed()); let squash_cache_start = Instant::now(); parents .iter() - .for_each(|p| self.status_cache.write().unwrap().add_root(p.slot())); + .for_each(|p| self.rc.status_cache.write().unwrap().add_root(p.slot())); let squash_cache_ms = duration_as_ms(&squash_cache_start.elapsed()); solana_metrics::submit( @@ -342,7 +420,7 @@ impl Bank { /// Return the more recent checkpoint of this bank instance. pub fn parent(&self) -> Option> { - self.parent.read().unwrap().clone() + self.rc.parent.read().unwrap().clone() } fn process_genesis_block(&mut self, genesis_block: &GenesisBlock) { @@ -447,7 +525,7 @@ impl Bank { /// Forget all signatures. Useful for benchmarking. pub fn clear_signatures(&self) { - self.status_cache.write().unwrap().clear_signatures(); + self.rc.status_cache.write().unwrap().clear_signatures(); } pub fn can_commit(result: &Result<()>) -> bool { @@ -459,7 +537,7 @@ impl Bank { } fn update_transaction_statuses(&self, txs: &[Transaction], res: &[Result<()>]) { - let mut status_cache = self.status_cache.write().unwrap(); + let mut status_cache = self.rc.status_cache.write().unwrap(); for (i, tx) in txs.iter().enumerate() { if Self::can_commit(&res[i]) && !tx.signatures.is_empty() { status_cache.insert( @@ -544,14 +622,14 @@ impl Bank { } // TODO: put this assert back in // assert!(!self.is_frozen()); - let results = self.accounts.lock_accounts(txs); + let results = self.rc.accounts.lock_accounts(txs); LockedAccountsResults::new(results, &self, txs) } pub fn unlock_accounts(&self, locked_accounts_results: &mut LockedAccountsResults) { if locked_accounts_results.needs_unlock { locked_accounts_results.needs_unlock = false; - self.accounts.unlock_accounts( + self.rc.accounts.unlock_accounts( locked_accounts_results.transactions(), locked_accounts_results.locked_accounts_results(), ) @@ -564,7 +642,7 @@ impl Bank { results: Vec>, error_counters: &mut ErrorCounters, ) -> Vec> { - self.accounts.load_accounts( + self.rc.accounts.load_accounts( &self.ancestors, txs, results, @@ -618,7 +696,7 @@ impl Bank { lock_results: Vec>, error_counters: &mut ErrorCounters, ) -> Vec> { - let rcache = self.status_cache.read().unwrap(); + let rcache = self.rc.status_cache.read().unwrap(); txs.iter() .zip(lock_results.into_iter()) .map(|(tx, lock_res)| { @@ -796,7 +874,8 @@ impl Bank { // TODO: put this assert back in // assert!(!self.is_frozen()); let now = Instant::now(); - self.accounts + self.rc + .accounts .store_accounts(self.slot(), txs, executed, loaded_accounts); self.store_vote_accounts(txs, executed, loaded_accounts); @@ -864,7 +943,7 @@ impl Bank { } fn store(&self, pubkey: &Pubkey, account: &Account) { - self.accounts.store_slow(self.slot(), pubkey, account); + self.rc.accounts.store_slow(self.slot(), pubkey, account); if solana_vote_api::check_id(&account.owner) { let mut vote_accounts = self.vote_accounts.write().unwrap(); if account.lamports != 0 { @@ -898,27 +977,43 @@ impl Bank { } pub fn accounts(&self) -> Arc { - self.accounts.clone() + self.rc.accounts.clone() } pub fn set_accounts(&mut self, accounts: &Arc) { - self.accounts = accounts.clone(); + self.rc.accounts = accounts.clone(); + } + + pub fn status_cache(&self) -> Arc> { + self.rc.status_cache.clone() + } + + pub fn set_status_cache(&mut self, status_cache: &Arc>) { + self.rc.status_cache = status_cache.clone(); + } + + pub fn parent_slot(&self) -> u64 { + self.rc.parent_slot + } + + pub fn set_parent(&mut self, parent: &Arc) { + self.rc.parent = RwLock::new(Some(parent.clone())); } pub fn get_account(&self, pubkey: &Pubkey) -> Option { - self.accounts.load_slow(&self.ancestors, pubkey) + self.rc.accounts.load_slow(&self.ancestors, pubkey) } pub fn get_program_accounts_modified_since_parent( &self, program_id: &Pubkey, ) -> Vec<(Pubkey, Account)> { - self.accounts.load_by_program(self.slot(), program_id) + self.rc.accounts.load_by_program(self.slot(), program_id) } pub fn get_account_modified_since_parent(&self, pubkey: &Pubkey) -> Option { let just_self: HashMap = vec![(self.slot(), 0)].into_iter().collect(); - self.accounts.load_slow(&just_self, pubkey) + self.rc.accounts.load_slow(&just_self, pubkey) } pub fn transaction_count(&self) -> u64 { @@ -933,7 +1028,7 @@ impl Bank { &self, signature: &Signature, ) -> Option<(usize, Result<()>)> { - let rcache = self.status_cache.read().unwrap(); + let rcache = self.rc.status_cache.read().unwrap(); rcache.get_signature_status_slow(signature, &self.ancestors) } @@ -951,11 +1046,11 @@ impl Bank { fn hash_internal_state(&self) -> Hash { // If there are no accounts, return the same hash as we did before // checkpointing. - if !self.accounts.has_accounts(self.slot()) { + if !self.rc.accounts.has_accounts(self.slot()) { return self.parent_hash; } - let accounts_delta_hash = self.accounts.hash_internal_state(self.slot()); + let accounts_delta_hash = self.rc.accounts.hash_internal_state(self.slot()); extend_and_hash(&self.parent_hash, &serialize(&accounts_delta_hash).unwrap()) } @@ -1080,12 +1175,12 @@ impl Bank { let dbhq = dbank.blockhash_queue.read().unwrap(); assert_eq!(*bhq, *dbhq); - let sc = self.status_cache.read().unwrap(); - let dsc = dbank.status_cache.read().unwrap(); + let sc = self.rc.status_cache.read().unwrap(); + let dsc = dbank.rc.status_cache.read().unwrap(); assert_eq!(*sc, *dsc); assert_eq!( - self.accounts.hash_internal_state(self.slot), - dbank.accounts.hash_internal_state(dbank.slot) + self.rc.accounts.hash_internal_state(self.slot), + dbank.rc.accounts.hash_internal_state(dbank.slot) ); } } @@ -1093,7 +1188,7 @@ impl Bank { impl Drop for Bank { fn drop(&mut self) { // For root forks this is a noop - self.accounts.purge_fork(self.slot()); + self.rc.accounts.purge_fork(self.slot()); } } @@ -2022,12 +2117,18 @@ mod tests { let bank0 = Arc::new(Bank::new(&genesis_block)); let bank = new_from_parent(&bank0); + // Test new account + let key = Keypair::new(); + bank.deposit(&key.pubkey(), 10); + assert_eq!(bank.get_balance(&key.pubkey()), 10); + let mut buf = vec![0u8; serialized_size(&bank).unwrap() as usize]; let mut writer = Cursor::new(&mut buf[..]); serialize_into(&mut writer, &bank).unwrap(); let mut reader = Cursor::new(&mut buf[..]); let dbank: Bank = deserialize_from(&mut reader).unwrap(); + assert_eq!(dbank.get_balance(&key.pubkey()), 10); bank.compare_bank(&dbank); } }