2020-05-22 10:54:24 -07:00
|
|
|
use {
|
|
|
|
crate::{
|
|
|
|
accounts::Accounts,
|
2021-02-18 23:42:09 -08:00
|
|
|
accounts_db::{AccountStorageEntry, AccountsDb, AppendVecId, BankHashInfo},
|
2021-05-10 07:22:48 -07:00
|
|
|
accounts_index::{AccountSecondaryIndexes, Ancestors},
|
2021-05-17 16:58:36 -07:00
|
|
|
append_vec::{AppendVec, StoredMetaWriteVersion},
|
2020-09-24 12:23:09 -07:00
|
|
|
bank::{Bank, BankFieldsToDeserialize, BankRc, Builtins},
|
2020-07-13 07:00:59 -07:00
|
|
|
blockhash_queue::BlockhashQueue,
|
|
|
|
epoch_stakes::EpochStakes,
|
2021-03-10 09:49:10 -08:00
|
|
|
hardened_unpack::UnpackedAppendVecMap,
|
2020-07-13 07:00:59 -07:00
|
|
|
message_processor::MessageProcessor,
|
|
|
|
rent_collector::RentCollector,
|
2021-01-28 08:15:33 -08:00
|
|
|
serde_snapshot::future::SerializableStorage,
|
2020-07-13 07:00:59 -07:00
|
|
|
stakes::Stakes,
|
2020-05-22 10:54:24 -07:00
|
|
|
},
|
2020-07-13 07:00:59 -07:00
|
|
|
bincode,
|
2020-08-03 16:27:17 -07:00
|
|
|
bincode::{config::Options, Error},
|
2021-03-10 09:49:10 -08:00
|
|
|
log::*,
|
2020-08-03 16:27:17 -07:00
|
|
|
serde::{de::DeserializeOwned, Deserialize, Serialize},
|
2020-07-13 07:00:59 -07:00
|
|
|
solana_sdk::{
|
|
|
|
clock::{Epoch, Slot, UnixTimestamp},
|
|
|
|
epoch_schedule::EpochSchedule,
|
|
|
|
fee_calculator::{FeeCalculator, FeeRateGovernor},
|
2020-09-08 07:55:09 -07:00
|
|
|
genesis_config::ClusterType,
|
2020-07-13 07:00:59 -07:00
|
|
|
genesis_config::GenesisConfig,
|
|
|
|
hard_forks::HardForks,
|
|
|
|
hash::Hash,
|
|
|
|
inflation::Inflation,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
},
|
2020-05-22 10:54:24 -07:00
|
|
|
std::{
|
2020-09-23 18:46:42 -07:00
|
|
|
collections::{HashMap, HashSet},
|
2021-03-10 09:49:10 -08:00
|
|
|
io::{self, BufReader, BufWriter, Read, Write},
|
|
|
|
path::PathBuf,
|
2020-05-22 10:54:24 -07:00
|
|
|
result::Result,
|
2020-10-13 18:29:50 -07:00
|
|
|
sync::{atomic::Ordering, Arc, RwLock},
|
2020-05-27 10:41:05 -07:00
|
|
|
time::Instant,
|
2020-05-22 10:54:24 -07:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
2020-10-19 21:07:46 -07:00
|
|
|
use solana_frozen_abi::abi_example::IgnoreAsHelper;
|
2020-07-13 07:00:59 -07:00
|
|
|
|
|
|
|
mod common;
|
2020-05-22 10:54:24 -07:00
|
|
|
mod future;
|
|
|
|
mod tests;
|
|
|
|
mod utils;
|
|
|
|
|
|
|
|
use future::Context as TypeContextFuture;
|
|
|
|
#[allow(unused_imports)]
|
|
|
|
use utils::{serialize_iter_as_map, serialize_iter_as_seq, serialize_iter_as_tuple};
|
|
|
|
|
|
|
|
// a number of test cases in accounts_db use this
|
|
|
|
#[cfg(test)]
|
|
|
|
pub(crate) use self::tests::reconstruct_accounts_db_via_serialization;
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
pub(crate) use crate::accounts_db::{SnapshotStorage, SnapshotStorages};
|
2020-05-22 10:54:24 -07:00
|
|
|
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
2020-07-13 07:00:59 -07:00
|
|
|
pub(crate) enum SerdeStyle {
|
2021-02-18 23:42:09 -08:00
|
|
|
Newer,
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
const MAX_STREAM_SIZE: u64 = 32 * 1024 * 1024 * 1024;
|
2020-05-22 10:54:24 -07:00
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
#[derive(Clone, Debug, Default, Deserialize, Serialize, AbiExample)]
|
2021-05-17 16:58:36 -07:00
|
|
|
struct AccountsDbFields<T>(
|
|
|
|
HashMap<Slot, Vec<T>>,
|
|
|
|
StoredMetaWriteVersion,
|
|
|
|
Slot,
|
|
|
|
BankHashInfo,
|
|
|
|
);
|
2020-05-22 10:54:24 -07:00
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
trait TypeContext<'a> {
|
2020-05-22 10:54:24 -07:00
|
|
|
type SerializableAccountStorageEntry: Serialize
|
|
|
|
+ DeserializeOwned
|
|
|
|
+ From<&'a AccountStorageEntry>
|
2021-01-28 08:15:33 -08:00
|
|
|
+ SerializableStorage;
|
2020-05-22 10:54:24 -07:00
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
fn serialize_bank_and_storage<S: serde::ser::Serializer>(
|
2020-05-22 10:54:24 -07:00
|
|
|
serializer: S,
|
2020-07-13 07:00:59 -07:00
|
|
|
serializable_bank: &SerializableBankAndStorage<'a, Self>,
|
2020-05-22 10:54:24 -07:00
|
|
|
) -> std::result::Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
Self: std::marker::Sized;
|
|
|
|
|
|
|
|
fn serialize_accounts_db_fields<S: serde::ser::Serializer>(
|
|
|
|
serializer: S,
|
2021-02-18 23:42:09 -08:00
|
|
|
serializable_db: &SerializableAccountsDb<'a, Self>,
|
2020-05-22 10:54:24 -07:00
|
|
|
) -> std::result::Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
Self: std::marker::Sized;
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
fn deserialize_bank_fields<R>(
|
|
|
|
stream: &mut BufReader<R>,
|
|
|
|
) -> Result<
|
|
|
|
(
|
|
|
|
BankFieldsToDeserialize,
|
|
|
|
AccountsDbFields<Self::SerializableAccountStorageEntry>,
|
|
|
|
),
|
|
|
|
Error,
|
|
|
|
>
|
|
|
|
where
|
|
|
|
R: Read;
|
|
|
|
|
2020-05-22 10:54:24 -07:00
|
|
|
fn deserialize_accounts_db_fields<R>(
|
|
|
|
stream: &mut BufReader<R>,
|
2020-07-13 07:00:59 -07:00
|
|
|
) -> Result<AccountsDbFields<Self::SerializableAccountStorageEntry>, Error>
|
2020-05-22 10:54:24 -07:00
|
|
|
where
|
|
|
|
R: Read;
|
2020-07-13 07:00:59 -07:00
|
|
|
}
|
2020-05-22 10:54:24 -07:00
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
fn deserialize_from<R, T>(reader: R) -> bincode::Result<T>
|
|
|
|
where
|
|
|
|
R: Read,
|
|
|
|
T: DeserializeOwned,
|
|
|
|
{
|
|
|
|
bincode::options()
|
|
|
|
.with_limit(MAX_STREAM_SIZE)
|
|
|
|
.with_fixint_encoding()
|
|
|
|
.allow_trailing_bytes()
|
|
|
|
.deserialize_from::<R, T>(reader)
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
|
2021-01-11 17:00:23 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-03-10 09:49:10 -08:00
|
|
|
pub(crate) fn bank_from_stream<R>(
|
2020-05-22 10:54:24 -07:00
|
|
|
serde_style: SerdeStyle,
|
|
|
|
stream: &mut BufReader<R>,
|
2020-07-13 07:00:59 -07:00
|
|
|
account_paths: &[PathBuf],
|
2021-03-10 09:49:10 -08:00
|
|
|
unpacked_append_vec_map: UnpackedAppendVecMap,
|
2020-07-13 07:00:59 -07:00
|
|
|
genesis_config: &GenesisConfig,
|
|
|
|
frozen_account_pubkeys: &[Pubkey],
|
2020-09-23 18:46:42 -07:00
|
|
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
2020-09-24 12:23:09 -07:00
|
|
|
additional_builtins: Option<&Builtins>,
|
2021-05-10 07:22:48 -07:00
|
|
|
account_indexes: AccountSecondaryIndexes,
|
2021-01-11 17:00:23 -08:00
|
|
|
caching_enabled: bool,
|
2020-07-13 07:00:59 -07:00
|
|
|
) -> std::result::Result<Bank, Error>
|
2020-05-22 10:54:24 -07:00
|
|
|
where
|
|
|
|
R: Read,
|
|
|
|
{
|
|
|
|
macro_rules! INTO {
|
2020-07-13 07:00:59 -07:00
|
|
|
($x:ident) => {{
|
|
|
|
let (bank_fields, accounts_db_fields) = $x::deserialize_bank_fields(stream)?;
|
|
|
|
|
|
|
|
let bank = reconstruct_bank_from_fields(
|
|
|
|
bank_fields,
|
|
|
|
accounts_db_fields,
|
|
|
|
genesis_config,
|
|
|
|
frozen_account_pubkeys,
|
|
|
|
account_paths,
|
2021-03-10 09:49:10 -08:00
|
|
|
unpacked_append_vec_map,
|
2020-09-23 18:46:42 -07:00
|
|
|
debug_keys,
|
2020-09-24 12:23:09 -07:00
|
|
|
additional_builtins,
|
2020-12-31 18:06:03 -08:00
|
|
|
account_indexes,
|
2021-01-11 17:00:23 -08:00
|
|
|
caching_enabled,
|
2020-07-13 07:00:59 -07:00
|
|
|
)?;
|
|
|
|
Ok(bank)
|
|
|
|
}};
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
match serde_style {
|
2021-02-18 23:42:09 -08:00
|
|
|
SerdeStyle::Newer => INTO!(TypeContextFuture),
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
2020-06-17 01:56:29 -07:00
|
|
|
.map_err(|err| {
|
|
|
|
warn!("bankrc_from_stream error: {:?}", err);
|
|
|
|
err
|
|
|
|
})
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
pub(crate) fn bank_to_stream<W>(
|
2020-05-22 10:54:24 -07:00
|
|
|
serde_style: SerdeStyle,
|
|
|
|
stream: &mut BufWriter<W>,
|
2020-07-13 07:00:59 -07:00
|
|
|
bank: &Bank,
|
2020-05-22 10:54:24 -07:00
|
|
|
snapshot_storages: &[SnapshotStorage],
|
2020-06-17 01:56:29 -07:00
|
|
|
) -> Result<(), Error>
|
2020-05-22 10:54:24 -07:00
|
|
|
where
|
|
|
|
W: Write,
|
|
|
|
{
|
|
|
|
macro_rules! INTO {
|
|
|
|
($x:ident) => {
|
2020-07-13 07:00:59 -07:00
|
|
|
bincode::serialize_into(
|
2020-05-22 10:54:24 -07:00
|
|
|
stream,
|
2020-07-13 07:00:59 -07:00
|
|
|
&SerializableBankAndStorage::<$x> {
|
|
|
|
bank,
|
2020-05-22 10:54:24 -07:00
|
|
|
snapshot_storages,
|
|
|
|
phantom: std::marker::PhantomData::default(),
|
|
|
|
},
|
|
|
|
)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
match serde_style {
|
2021-02-18 23:42:09 -08:00
|
|
|
SerdeStyle::Newer => INTO!(TypeContextFuture),
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
2020-06-17 01:56:29 -07:00
|
|
|
.map_err(|err| {
|
|
|
|
warn!("bankrc_to_stream error: {:?}", err);
|
|
|
|
err
|
|
|
|
})
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
struct SerializableBankAndStorage<'a, C> {
|
|
|
|
bank: &'a Bank,
|
2020-05-22 10:54:24 -07:00
|
|
|
snapshot_storages: &'a [SnapshotStorage],
|
|
|
|
phantom: std::marker::PhantomData<C>,
|
|
|
|
}
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
impl<'a, C: TypeContext<'a>> Serialize for SerializableBankAndStorage<'a, C> {
|
2020-05-22 10:54:24 -07:00
|
|
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: serde::ser::Serializer,
|
|
|
|
{
|
2020-07-13 07:00:59 -07:00
|
|
|
C::serialize_bank_and_storage(serializer, self)
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-18 23:42:09 -08:00
|
|
|
struct SerializableAccountsDb<'a, C> {
|
|
|
|
accounts_db: &'a AccountsDb,
|
2020-05-22 10:54:24 -07:00
|
|
|
slot: Slot,
|
|
|
|
account_storage_entries: &'a [SnapshotStorage],
|
|
|
|
phantom: std::marker::PhantomData<C>,
|
|
|
|
}
|
|
|
|
|
2021-02-18 23:42:09 -08:00
|
|
|
impl<'a, C: TypeContext<'a>> Serialize for SerializableAccountsDb<'a, C> {
|
2020-05-22 10:54:24 -07:00
|
|
|
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: serde::ser::Serializer,
|
|
|
|
{
|
|
|
|
C::serialize_accounts_db_fields(serializer, self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-13 07:00:59 -07:00
|
|
|
#[cfg(RUSTC_WITH_SPECIALIZATION)]
|
2021-02-18 23:42:09 -08:00
|
|
|
impl<'a, C> IgnoreAsHelper for SerializableAccountsDb<'a, C> {}
|
2020-07-13 07:00:59 -07:00
|
|
|
|
2021-01-11 17:00:23 -08:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-03-10 09:49:10 -08:00
|
|
|
fn reconstruct_bank_from_fields<E>(
|
2020-07-13 07:00:59 -07:00
|
|
|
bank_fields: BankFieldsToDeserialize,
|
|
|
|
accounts_db_fields: AccountsDbFields<E>,
|
|
|
|
genesis_config: &GenesisConfig,
|
|
|
|
frozen_account_pubkeys: &[Pubkey],
|
|
|
|
account_paths: &[PathBuf],
|
2021-03-10 09:49:10 -08:00
|
|
|
unpacked_append_vec_map: UnpackedAppendVecMap,
|
2020-09-23 18:46:42 -07:00
|
|
|
debug_keys: Option<Arc<HashSet<Pubkey>>>,
|
2020-09-24 12:23:09 -07:00
|
|
|
additional_builtins: Option<&Builtins>,
|
2021-05-10 07:22:48 -07:00
|
|
|
account_indexes: AccountSecondaryIndexes,
|
2021-01-11 17:00:23 -08:00
|
|
|
caching_enabled: bool,
|
2020-07-13 07:00:59 -07:00
|
|
|
) -> Result<Bank, Error>
|
|
|
|
where
|
2021-01-28 08:15:33 -08:00
|
|
|
E: SerializableStorage,
|
2020-07-13 07:00:59 -07:00
|
|
|
{
|
2020-09-02 00:37:36 -07:00
|
|
|
let mut accounts_db = reconstruct_accountsdb_from_fields(
|
|
|
|
accounts_db_fields,
|
|
|
|
account_paths,
|
2021-03-10 09:49:10 -08:00
|
|
|
unpacked_append_vec_map,
|
2020-09-08 07:55:09 -07:00
|
|
|
&genesis_config.cluster_type,
|
2020-12-31 18:06:03 -08:00
|
|
|
account_indexes,
|
2021-01-11 17:00:23 -08:00
|
|
|
caching_enabled,
|
2020-09-02 00:37:36 -07:00
|
|
|
)?;
|
2020-07-13 07:00:59 -07:00
|
|
|
accounts_db.freeze_accounts(&bank_fields.ancestors, frozen_account_pubkeys);
|
|
|
|
|
|
|
|
let bank_rc = BankRc::new(Accounts::new_empty(accounts_db), bank_fields.slot);
|
2020-09-24 12:23:09 -07:00
|
|
|
let bank = Bank::new_from_fields(
|
|
|
|
bank_rc,
|
|
|
|
genesis_config,
|
|
|
|
bank_fields,
|
|
|
|
debug_keys,
|
|
|
|
additional_builtins,
|
|
|
|
);
|
2020-07-13 07:00:59 -07:00
|
|
|
|
|
|
|
Ok(bank)
|
|
|
|
}
|
|
|
|
|
2021-03-10 09:49:10 -08:00
|
|
|
fn reconstruct_accountsdb_from_fields<E>(
|
2020-07-13 07:00:59 -07:00
|
|
|
accounts_db_fields: AccountsDbFields<E>,
|
2020-05-22 10:54:24 -07:00
|
|
|
account_paths: &[PathBuf],
|
2021-03-10 09:49:10 -08:00
|
|
|
unpacked_append_vec_map: UnpackedAppendVecMap,
|
2020-09-08 07:55:09 -07:00
|
|
|
cluster_type: &ClusterType,
|
2021-05-10 07:22:48 -07:00
|
|
|
account_indexes: AccountSecondaryIndexes,
|
2021-01-11 17:00:23 -08:00
|
|
|
caching_enabled: bool,
|
2021-02-18 23:42:09 -08:00
|
|
|
) -> Result<AccountsDb, Error>
|
2020-05-22 10:54:24 -07:00
|
|
|
where
|
2021-01-28 08:15:33 -08:00
|
|
|
E: SerializableStorage,
|
2020-05-22 10:54:24 -07:00
|
|
|
{
|
2021-02-18 23:42:09 -08:00
|
|
|
let mut accounts_db = AccountsDb::new_with_config(
|
2021-01-11 17:00:23 -08:00
|
|
|
account_paths.to_vec(),
|
|
|
|
cluster_type,
|
|
|
|
account_indexes,
|
|
|
|
caching_enabled,
|
|
|
|
);
|
2020-07-13 07:00:59 -07:00
|
|
|
let AccountsDbFields(storage, version, slot, bank_hash_info) = accounts_db_fields;
|
2020-05-22 10:54:24 -07:00
|
|
|
|
2021-01-02 17:57:56 -08:00
|
|
|
// Ensure all account paths exist
|
|
|
|
for path in &accounts_db.paths {
|
|
|
|
std::fs::create_dir_all(path)
|
|
|
|
.unwrap_or_else(|err| panic!("Failed to create directory {}: {}", path.display(), err));
|
|
|
|
}
|
|
|
|
|
2020-05-27 10:41:05 -07:00
|
|
|
let mut last_log_update = Instant::now();
|
|
|
|
let mut remaining_slots_to_process = storage.len();
|
|
|
|
|
2020-05-22 10:54:24 -07:00
|
|
|
// Remap the deserialized AppendVec paths to point to correct local paths
|
|
|
|
let mut storage = storage
|
|
|
|
.into_iter()
|
|
|
|
.map(|(slot, mut slot_storage)| {
|
2020-05-27 10:41:05 -07:00
|
|
|
let now = Instant::now();
|
|
|
|
if now.duration_since(last_log_update).as_secs() >= 10 {
|
|
|
|
info!("{} slots remaining...", remaining_slots_to_process);
|
|
|
|
last_log_update = now;
|
|
|
|
}
|
|
|
|
remaining_slots_to_process -= 1;
|
|
|
|
|
2020-05-22 10:54:24 -07:00
|
|
|
let mut new_slot_storage = HashMap::new();
|
2021-01-28 08:15:33 -08:00
|
|
|
for storage_entry in slot_storage.drain(..) {
|
2021-03-10 09:49:10 -08:00
|
|
|
let file_name = AppendVec::file_name(slot, storage_entry.id());
|
2020-05-22 10:54:24 -07:00
|
|
|
|
2021-03-10 09:49:10 -08:00
|
|
|
let append_vec_path = unpacked_append_vec_map.get(&file_name).ok_or_else(|| {
|
|
|
|
io::Error::new(
|
|
|
|
io::ErrorKind::NotFound,
|
|
|
|
format!("{} not found in unpacked append vecs", file_name),
|
|
|
|
)
|
|
|
|
})?;
|
2021-01-28 08:15:33 -08:00
|
|
|
|
|
|
|
let (accounts, num_accounts) =
|
2021-03-10 09:49:10 -08:00
|
|
|
AppendVec::new_from_file(append_vec_path, storage_entry.current_len())?;
|
2021-01-28 08:15:33 -08:00
|
|
|
let u_storage_entry = AccountStorageEntry::new_existing(
|
|
|
|
slot,
|
|
|
|
storage_entry.id(),
|
|
|
|
accounts,
|
|
|
|
num_accounts,
|
|
|
|
);
|
|
|
|
|
|
|
|
new_slot_storage.insert(storage_entry.id(), Arc::new(u_storage_entry));
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
Ok((slot, new_slot_storage))
|
|
|
|
})
|
2020-06-17 01:56:29 -07:00
|
|
|
.collect::<Result<HashMap<Slot, _>, Error>>()?;
|
2020-05-22 10:54:24 -07:00
|
|
|
|
|
|
|
// discard any slots with no storage entries
|
|
|
|
// this can happen if a non-root slot was serialized
|
|
|
|
// but non-root stores should not be included in the snapshot
|
|
|
|
storage.retain(|_slot, stores| !stores.is_empty());
|
|
|
|
|
|
|
|
accounts_db
|
|
|
|
.bank_hashes
|
|
|
|
.write()
|
|
|
|
.unwrap()
|
|
|
|
.insert(slot, bank_hash_info);
|
|
|
|
|
|
|
|
// Process deserialized data, set necessary fields in self
|
|
|
|
let max_id: usize = *storage
|
|
|
|
.values()
|
|
|
|
.flat_map(HashMap::keys)
|
|
|
|
.max()
|
|
|
|
.expect("At least one storage entry must exist from deserializing stream");
|
|
|
|
|
|
|
|
{
|
2020-10-13 18:29:50 -07:00
|
|
|
accounts_db.storage.0.extend(
|
|
|
|
storage.into_iter().map(|(slot, slot_storage_entry)| {
|
|
|
|
(slot, Arc::new(RwLock::new(slot_storage_entry)))
|
|
|
|
}),
|
|
|
|
);
|
2020-05-22 10:54:24 -07:00
|
|
|
}
|
|
|
|
|
2021-01-11 17:00:23 -08:00
|
|
|
if max_id > AppendVecId::MAX / 2 {
|
|
|
|
panic!("Storage id {} larger than allowed max", max_id);
|
|
|
|
}
|
|
|
|
|
2020-05-22 10:54:24 -07:00
|
|
|
accounts_db.next_id.store(max_id + 1, Ordering::Relaxed);
|
|
|
|
accounts_db
|
|
|
|
.write_version
|
|
|
|
.fetch_add(version, Ordering::Relaxed);
|
|
|
|
accounts_db.generate_index();
|
|
|
|
Ok(accounts_db)
|
|
|
|
}
|