diff --git a/core/tests/snapshots.rs b/core/tests/snapshots.rs index 04a417650a8c46..d5bd0195d9828f 100644 --- a/core/tests/snapshots.rs +++ b/core/tests/snapshots.rs @@ -98,6 +98,10 @@ mod tests { tempfile::TempDir, }; + DEFINE_SNAPSHOT_VERSION_PARAMETERIZED_TEST_FUNCTIONS!(V1_3_0, Development, V1_3_0_Development); + DEFINE_SNAPSHOT_VERSION_PARAMETERIZED_TEST_FUNCTIONS!(V1_3_0, Devnet, V1_3_0_Devnet); + DEFINE_SNAPSHOT_VERSION_PARAMETERIZED_TEST_FUNCTIONS!(V1_3_0, Testnet, V1_3_0_Testnet); + DEFINE_SNAPSHOT_VERSION_PARAMETERIZED_TEST_FUNCTIONS!(V1_3_0, MainnetBeta, V1_3_0_MainnetBeta); DEFINE_SNAPSHOT_VERSION_PARAMETERIZED_TEST_FUNCTIONS!(V1_2_0, Development, V1_2_0_Development); DEFINE_SNAPSHOT_VERSION_PARAMETERIZED_TEST_FUNCTIONS!(V1_2_0, Devnet, V1_2_0_Devnet); DEFINE_SNAPSHOT_VERSION_PARAMETERIZED_TEST_FUNCTIONS!(V1_2_0, Testnet, V1_2_0_Testnet); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c16e39f45d90b2..66caede3735231 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -919,12 +919,13 @@ pub(crate) struct BankFieldsToDeserialize { pub(crate) stakes: Stakes, pub(crate) epoch_stakes: HashMap, pub(crate) is_delta: bool, + pub(crate) prior_roots: Vec, } -// Bank's common fields shared by all supported snapshot versions for serialization. -// This is separated from BankFieldsToDeserialize to avoid cloning by using refs. -// So, sync fields with BankFieldsToDeserialize! -// all members are made public to keep Bank private and to make versioned serializer workable on this +/// Bank's common fields shared by all supported snapshot versions for serialization. +/// This is separated from BankFieldsToDeserialize to avoid cloning by using refs. +/// So, sync fields with BankFieldsToDeserialize! +/// all members are made public to keep Bank private and to make versioned serializer workable on this #[derive(Debug)] pub(crate) struct BankFieldsToSerialize<'a> { pub(crate) blockhash_queue: &'a RwLock, @@ -957,6 +958,7 @@ pub(crate) struct BankFieldsToSerialize<'a> { pub(crate) stakes: &'a StakesCache, pub(crate) epoch_stakes: &'a HashMap, pub(crate) is_delta: bool, + pub(crate) prior_roots: Vec, } // Can't derive PartialEq because RwLock doesn't implement PartialEq @@ -995,6 +997,7 @@ impl PartialEq for Bank { && *self.stakes_cache.stakes() == *other.stakes_cache.stakes() && self.epoch_stakes == other.epoch_stakes && self.is_delta.load(Relaxed) == other.is_delta.load(Relaxed) + && self.prior_roots == other.prior_roots } } @@ -1179,6 +1182,14 @@ pub struct Bank { /// stream for the slot == self.slot is_delta: AtomicBool, + /// The list of roots which are no longer roots in the current bank instance. + /// As we eliminate rewrites/ancient append vec, we need to the ability to + /// remember slots within that last epoch that WERE roots even if they no + /// longer contain any accounts. Without remembering those prior roots, + /// accounts that we skip rewrites might have their rent collection time + /// point to the incorrect roots as their correct roots were removed. + pub prior_roots: Vec, + /// The builtin programs builtin_programs: BuiltinPrograms, @@ -1352,6 +1363,7 @@ impl Bank { stakes_cache: StakesCache::default(), epoch_stakes: HashMap::::default(), is_delta: AtomicBool::default(), + prior_roots: Vec::::default(), builtin_programs: BuiltinPrograms::default(), compute_budget: Option::::default(), builtin_feature_transitions: Arc::>::default(), @@ -1668,6 +1680,7 @@ impl Bank { ancestors: Ancestors::default(), hash: RwLock::new(Hash::default()), is_delta: AtomicBool::new(false), + prior_roots: parent.prior_roots.clone(), tick_height: AtomicU64::new(parent.tick_height.load(Relaxed)), signature_count: AtomicU64::new(0), builtin_programs, @@ -1964,6 +1977,7 @@ impl Bank { stakes_cache: StakesCache::new(fields.stakes), epoch_stakes: fields.epoch_stakes, is_delta: AtomicBool::new(fields.is_delta), + prior_roots: fields.prior_roots, builtin_programs: new(), compute_budget: None, builtin_feature_transitions: new(), @@ -2066,6 +2080,7 @@ impl Bank { stakes: &self.stakes_cache, epoch_stakes: &self.epoch_stakes, is_delta: self.is_delta.load(Relaxed), + prior_roots: self.prior_roots.clone(), } } diff --git a/runtime/src/serde_snapshot.rs b/runtime/src/serde_snapshot.rs index 82cf9500b6bfeb..81abd1fb07e35f 100644 --- a/runtime/src/serde_snapshot.rs +++ b/runtime/src/serde_snapshot.rs @@ -46,6 +46,7 @@ use { }; mod newer; +mod older; mod storage; mod tests; mod utils; @@ -57,6 +58,7 @@ pub(crate) use tests::reconstruct_accounts_db_via_serialization; #[derive(Copy, Clone, Eq, PartialEq)] pub(crate) enum SerdeStyle { Newer, + Older, } const MAX_STREAM_SIZE: u64 = 32 * 1024 * 1024 * 1024; @@ -237,6 +239,7 @@ where } match serde_style { SerdeStyle::Newer => INTO!(newer), + SerdeStyle::Older => INTO!(older), } .map_err(|err| { warn!("bankrc_from_stream error: {:?}", err); @@ -267,6 +270,7 @@ where } match serde_style { SerdeStyle::Newer => INTO!(newer), + SerdeStyle::Older => INTO!(older), } .map_err(|err| { warn!("bankrc_to_stream error: {:?}", err); diff --git a/runtime/src/serde_snapshot/newer.rs b/runtime/src/serde_snapshot/newer.rs index 4c12d9742892e4..3e36c019a42e14 100644 --- a/runtime/src/serde_snapshot/newer.rs +++ b/runtime/src/serde_snapshot/newer.rs @@ -6,18 +6,12 @@ use { }, crate::{ancestors::AncestorsForSerialization, stakes::StakesCache}, solana_measure::measure::Measure, - std::{cell::RefCell, collections::HashSet, sync::RwLock}, + solana_sdk::deserialize_utils::default_on_eof, + std::{cell::RefCell, sync::RwLock}, }; type AccountsDbFields = super::AccountsDbFields; -#[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize, AbiExample)] -struct UnusedAccounts { - unused1: HashSet, - unused2: HashSet, - unused3: HashMap, -} - // Deserializable version of Bank which need not be serializable, // because it's handled by SerializableVersionedBank. // So, sync fields with it! @@ -39,8 +33,6 @@ struct DeserializableVersionedBank { ns_per_slot: u128, genesis_creation_time: UnixTimestamp, slots_per_year: f64, - #[allow(dead_code)] - unused: u64, slot: Slot, epoch: Epoch, block_height: u64, @@ -53,10 +45,10 @@ struct DeserializableVersionedBank { epoch_schedule: EpochSchedule, inflation: Inflation, stakes: Stakes, - #[allow(dead_code)] - unused_accounts: UnusedAccounts, epoch_stakes: HashMap, is_delta: bool, + #[serde(deserialize_with = "default_on_eof")] + prior_roots: Vec, } impl From for BankFieldsToDeserialize { @@ -92,6 +84,7 @@ impl From for BankFieldsToDeserialize { stakes: dvb.stakes, epoch_stakes: dvb.epoch_stakes, is_delta: dvb.is_delta, + prior_roots: dvb.prior_roots, } } } @@ -116,7 +109,6 @@ struct SerializableVersionedBank<'a> { ns_per_slot: u128, genesis_creation_time: UnixTimestamp, slots_per_year: f64, - unused: u64, slot: Slot, epoch: Epoch, block_height: u64, @@ -129,9 +121,9 @@ struct SerializableVersionedBank<'a> { epoch_schedule: EpochSchedule, inflation: Inflation, stakes: &'a StakesCache, - unused_accounts: UnusedAccounts, epoch_stakes: &'a HashMap, is_delta: bool, + prior_roots: Vec, } impl<'a> From> for SerializableVersionedBank<'a> { @@ -153,7 +145,6 @@ impl<'a> From> for SerializableVersionedB ns_per_slot: rhs.ns_per_slot, genesis_creation_time: rhs.genesis_creation_time, slots_per_year: rhs.slots_per_year, - unused: u64::default(), slot: rhs.slot, epoch: rhs.epoch, block_height: rhs.block_height, @@ -166,9 +157,9 @@ impl<'a> From> for SerializableVersionedB epoch_schedule: rhs.epoch_schedule, inflation: rhs.inflation, stakes: rhs.stakes, - unused_accounts: UnusedAccounts::default(), epoch_stakes: rhs.epoch_stakes, is_delta: rhs.is_delta, + prior_roots: rhs.prior_roots, } } } diff --git a/runtime/src/serde_snapshot/older.rs b/runtime/src/serde_snapshot/older.rs new file mode 100644 index 00000000000000..fc3c67a9ca0915 --- /dev/null +++ b/runtime/src/serde_snapshot/older.rs @@ -0,0 +1,272 @@ +use { + super::{ + storage::SerializableAccountStorageEntry, + utils::{serialize_iter_as_map, serialize_iter_as_seq}, + *, + }, + crate::{ancestors::AncestorsForSerialization, stakes::StakesCache}, + solana_measure::measure::Measure, + std::{cell::RefCell, collections::HashSet, sync::RwLock}, +}; + +type AccountsDbFields = super::AccountsDbFields; + +#[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize, AbiExample)] +struct UnusedAccounts { + unused1: HashSet, + unused2: HashSet, + unused3: HashMap, +} + +// Deserializable version of Bank which need not be serializable, +// because it's handled by SerializableVersionedBank. +// So, sync fields with it! +#[derive(Clone, Deserialize)] +struct DeserializableVersionedBank { + blockhash_queue: BlockhashQueue, + ancestors: AncestorsForSerialization, + hash: Hash, + parent_hash: Hash, + parent_slot: Slot, + hard_forks: HardForks, + transaction_count: u64, + tick_height: u64, + signature_count: u64, + capitalization: u64, + max_tick_height: u64, + hashes_per_tick: Option, + ticks_per_slot: u64, + ns_per_slot: u128, + genesis_creation_time: UnixTimestamp, + slots_per_year: f64, + #[allow(dead_code)] + unused: u64, + slot: Slot, + epoch: Epoch, + block_height: u64, + collector_id: Pubkey, + collector_fees: u64, + fee_calculator: FeeCalculator, + fee_rate_governor: FeeRateGovernor, + collected_rent: u64, + rent_collector: RentCollector, + epoch_schedule: EpochSchedule, + inflation: Inflation, + stakes: Stakes, + #[allow(dead_code)] + unused_accounts: UnusedAccounts, + epoch_stakes: HashMap, + is_delta: bool, +} + +impl From for BankFieldsToDeserialize { + fn from(dvb: DeserializableVersionedBank) -> Self { + BankFieldsToDeserialize { + blockhash_queue: dvb.blockhash_queue, + ancestors: dvb.ancestors, + hash: dvb.hash, + parent_hash: dvb.parent_hash, + parent_slot: dvb.parent_slot, + hard_forks: dvb.hard_forks, + transaction_count: dvb.transaction_count, + tick_height: dvb.tick_height, + signature_count: dvb.signature_count, + capitalization: dvb.capitalization, + max_tick_height: dvb.max_tick_height, + hashes_per_tick: dvb.hashes_per_tick, + ticks_per_slot: dvb.ticks_per_slot, + ns_per_slot: dvb.ns_per_slot, + genesis_creation_time: dvb.genesis_creation_time, + slots_per_year: dvb.slots_per_year, + slot: dvb.slot, + epoch: dvb.epoch, + block_height: dvb.block_height, + collector_id: dvb.collector_id, + collector_fees: dvb.collector_fees, + fee_calculator: dvb.fee_calculator, + fee_rate_governor: dvb.fee_rate_governor, + collected_rent: dvb.collected_rent, + rent_collector: dvb.rent_collector, + epoch_schedule: dvb.epoch_schedule, + inflation: dvb.inflation, + stakes: dvb.stakes, + epoch_stakes: dvb.epoch_stakes, + is_delta: dvb.is_delta, + prior_roots: Vec::::default(), + } + } +} + +// Serializable version of Bank, not Deserializable to avoid cloning by using refs. +// Sync fields with DeserializableVersionedBank! +#[derive(Serialize)] +struct SerializableVersionedBank<'a> { + blockhash_queue: &'a RwLock, + ancestors: &'a AncestorsForSerialization, + hash: Hash, + parent_hash: Hash, + parent_slot: Slot, + hard_forks: &'a RwLock, + transaction_count: u64, + tick_height: u64, + signature_count: u64, + capitalization: u64, + max_tick_height: u64, + hashes_per_tick: Option, + ticks_per_slot: u64, + ns_per_slot: u128, + genesis_creation_time: UnixTimestamp, + slots_per_year: f64, + unused: u64, + slot: Slot, + epoch: Epoch, + block_height: u64, + collector_id: Pubkey, + collector_fees: u64, + fee_calculator: FeeCalculator, + fee_rate_governor: FeeRateGovernor, + collected_rent: u64, + rent_collector: RentCollector, + epoch_schedule: EpochSchedule, + inflation: Inflation, + stakes: &'a StakesCache, + unused_accounts: UnusedAccounts, + epoch_stakes: &'a HashMap, + is_delta: bool, +} + +impl<'a> From> for SerializableVersionedBank<'a> { + fn from(rhs: crate::bank::BankFieldsToSerialize<'a>) -> Self { + Self { + blockhash_queue: rhs.blockhash_queue, + ancestors: rhs.ancestors, + hash: rhs.hash, + parent_hash: rhs.parent_hash, + parent_slot: rhs.parent_slot, + hard_forks: rhs.hard_forks, + transaction_count: rhs.transaction_count, + tick_height: rhs.tick_height, + signature_count: rhs.signature_count, + capitalization: rhs.capitalization, + max_tick_height: rhs.max_tick_height, + hashes_per_tick: rhs.hashes_per_tick, + ticks_per_slot: rhs.ticks_per_slot, + ns_per_slot: rhs.ns_per_slot, + genesis_creation_time: rhs.genesis_creation_time, + slots_per_year: rhs.slots_per_year, + unused: u64::default(), + slot: rhs.slot, + epoch: rhs.epoch, + block_height: rhs.block_height, + collector_id: rhs.collector_id, + collector_fees: rhs.collector_fees, + fee_calculator: rhs.fee_calculator, + fee_rate_governor: rhs.fee_rate_governor, + collected_rent: rhs.collected_rent, + rent_collector: rhs.rent_collector, + epoch_schedule: rhs.epoch_schedule, + inflation: rhs.inflation, + stakes: rhs.stakes, + unused_accounts: UnusedAccounts::default(), + epoch_stakes: rhs.epoch_stakes, + is_delta: rhs.is_delta, + } + } +} + +#[cfg(RUSTC_WITH_SPECIALIZATION)] +impl<'a> solana_frozen_abi::abi_example::IgnoreAsHelper for SerializableVersionedBank<'a> {} + +pub(super) struct Context {} + +impl<'a> TypeContext<'a> for Context { + type SerializableAccountStorageEntry = SerializableAccountStorageEntry; + + fn serialize_bank_and_storage( + serializer: S, + serializable_bank: &SerializableBankAndStorage<'a, Self>, + ) -> std::result::Result + where + Self: std::marker::Sized, + { + let ancestors = HashMap::from(&serializable_bank.bank.ancestors); + let fields = serializable_bank.bank.get_fields_to_serialize(&ancestors); + ( + SerializableVersionedBank::from(fields), + SerializableAccountsDb::<'a, Self> { + accounts_db: &*serializable_bank.bank.rc.accounts.accounts_db, + slot: serializable_bank.bank.rc.slot, + account_storage_entries: serializable_bank.snapshot_storages, + phantom: std::marker::PhantomData::default(), + }, + ) + .serialize(serializer) + } + + fn serialize_accounts_db_fields( + serializer: S, + serializable_db: &SerializableAccountsDb<'a, Self>, + ) -> std::result::Result + where + Self: std::marker::Sized, + { + // sample write version before serializing storage entries + let version = serializable_db + .accounts_db + .write_version + .load(Ordering::Acquire); + + // (1st of 3 elements) write the list of account storage entry lists out as a map + let entry_count = RefCell::::new(0); + let entries = + serialize_iter_as_map(serializable_db.account_storage_entries.iter().map(|x| { + *entry_count.borrow_mut() += x.len(); + ( + x.first().unwrap().slot(), + serialize_iter_as_seq( + x.iter() + .map(|x| Self::SerializableAccountStorageEntry::from(x.as_ref())), + ), + ) + })); + let slot = serializable_db.slot; + let hash = serializable_db + .accounts_db + .bank_hashes + .read() + .unwrap() + .get(&serializable_db.slot) + .unwrap_or_else(|| panic!("No bank_hashes entry for slot {}", serializable_db.slot)) + .clone(); + + let mut serialize_account_storage_timer = Measure::start("serialize_account_storage_ms"); + let result = (entries, version, slot, hash).serialize(serializer); + serialize_account_storage_timer.stop(); + datapoint_info!( + "serialize_account_storage_ms", + ("duration", serialize_account_storage_timer.as_ms(), i64), + ("num_entries", *entry_count.borrow(), i64), + ); + result + } + + fn deserialize_bank_fields( + mut stream: &mut BufReader, + ) -> Result<(BankFieldsToDeserialize, AccountsDbFields), Error> + where + R: Read, + { + let bank_fields = deserialize_from::<_, DeserializableVersionedBank>(&mut stream)?.into(); + let accounts_db_fields = Self::deserialize_accounts_db_fields(stream)?; + Ok((bank_fields, accounts_db_fields)) + } + + fn deserialize_accounts_db_fields( + stream: &mut BufReader, + ) -> Result + where + R: Read, + { + deserialize_from(stream) + } +} diff --git a/runtime/src/serde_snapshot/tests.rs b/runtime/src/serde_snapshot/tests.rs index faf55adf192a34..97d18720df18b8 100644 --- a/runtime/src/serde_snapshot/tests.rs +++ b/runtime/src/serde_snapshot/tests.rs @@ -104,6 +104,11 @@ where account_paths, unpacked_append_vec_map, ), + SerdeStyle::Older => context_accountsdb_from_stream::( + stream, + account_paths, + unpacked_append_vec_map, + ), } } @@ -127,6 +132,15 @@ where phantom: std::marker::PhantomData::default(), }, ), + SerdeStyle::Older => serialize_into( + stream, + &SerializableAccountsDb:: { + accounts_db, + slot, + account_storage_entries, + phantom: std::marker::PhantomData::default(), + }, + ), } } @@ -189,7 +203,7 @@ fn test_bank_serialize_style(serde_style: SerdeStyle) { let key1 = Keypair::new(); bank1.deposit(&key1.pubkey(), 5).unwrap(); - let bank2 = Bank::new_from_parent(&bank0, &Pubkey::default(), 2); + let mut bank2 = Bank::new_from_parent(&bank0, &Pubkey::default(), 2); // Test new account let key2 = Keypair::new(); @@ -202,6 +216,9 @@ fn test_bank_serialize_style(serde_style: SerdeStyle) { bank2.freeze(); bank2.squash(); bank2.force_flush_accounts_cache(); + // Append a dummy `prior_roots` to test its cross-version compatibility. + let mut test_prior_roots = vec![0, 1, 2]; + bank2.prior_roots.append(&mut test_prior_roots); let snapshot_storages = bank2.get_snapshot_storages(None); let mut buf = vec![]; @@ -250,6 +267,12 @@ fn test_bank_serialize_style(serde_style: SerdeStyle) { assert_eq!(dbank.get_balance(&key1.pubkey()), 0); assert_eq!(dbank.get_balance(&key2.pubkey()), 10); assert_eq!(dbank.get_balance(&key3.pubkey()), 0); + // In case we are using older version, we expect it does not understand + // `prior_roots` field. Thus, we revert the dummy value we assign to + // `prior_roots` back to the `Vec::default` and expect the bank2 == dbank. + if serde_style == SerdeStyle::Older { + bank2.prior_roots = Vec::::default(); + } assert!(bank2 == dbank); } @@ -260,7 +283,7 @@ pub(crate) fn reconstruct_accounts_db_via_serialization( let mut writer = Cursor::new(vec![]); let snapshot_storages = accounts.get_snapshot_storages(slot, None, None).0; accountsdb_to_stream( - SerdeStyle::Newer, + SerdeStyle::Older, // TODO(yhchiang): switch to Newer once we bump to V1_3_0 &mut writer, accounts, slot, @@ -274,9 +297,13 @@ pub(crate) fn reconstruct_accounts_db_via_serialization( // Simulate obtaining a copy of the AppendVecs from a tarball let unpacked_append_vec_map = copy_append_vecs(accounts, copied_accounts.path()).unwrap(); - let mut accounts_db = - accountsdb_from_stream(SerdeStyle::Newer, &mut reader, &[], unpacked_append_vec_map) - .unwrap(); + let mut accounts_db = accountsdb_from_stream( + SerdeStyle::Older, // TODO(yhchiang): switch to Newer once we bump to V1_3_0 + &mut reader, + &[], + unpacked_append_vec_map, + ) + .unwrap(); // The append vecs will be used from `copied_accounts` directly by the new AccountsDb so keep // its TempDir alive @@ -299,13 +326,24 @@ fn test_bank_serialize_newer() { test_bank_serialize_style(SerdeStyle::Newer) } +#[test] +fn test_accounts_serialize_older() { + test_accounts_serialize_style(SerdeStyle::Older) +} + +#[test] +fn test_bank_serialize_older() { + test_bank_serialize_style(SerdeStyle::Older) +} + #[cfg(RUSTC_WITH_SPECIALIZATION)] mod test_bank_serialize { use super::*; // This some what long test harness is required to freeze the ABI of - // Bank's serialization due to versioned nature - #[frozen_abi(digest = "HVyzePMkma8T54PymRW32FAgDXpSdom59K6RnPsCNJjj")] + // Bank's serialization due to versioned nature. + // The following hash is for snapshot V1_3_0 + #[frozen_abi(digest = "3mV3i1yLMGyMfPxRXyXcZAKEtmMFrSXAW2pqLQ3uwgZP")] #[derive(Serialize, AbiExample)] pub struct BankAbiTestWrapperNewer { #[serde(serialize_with = "wrapper_newer")] @@ -332,4 +370,35 @@ mod test_bank_serialize { }) .serialize(s) } + + // This some what long test harness is required to freeze the ABI of + // Bank's serialization due to versioned nature. + // The following hash is for snapshot V1_2_0 + #[frozen_abi(digest = "5zTpYmVsKjkvpJB8o95LJWyXe2rV7bnxRPmmfKk75brf")] + #[derive(Serialize, AbiExample)] + pub struct BankAbiTestWrapperOlder { + #[serde(serialize_with = "wrapper_older")] + bank: Bank, + } + + pub fn wrapper_older(bank: &Bank, s: S) -> std::result::Result + where + S: serde::Serializer, + { + let snapshot_storages = bank + .rc + .accounts + .accounts_db + .get_snapshot_storages(0, None, None) + .0; + // ensure there is a single snapshot storage example for ABI digesting + assert_eq!(snapshot_storages.len(), 1); + + (SerializableBankAndStorage:: { + bank, + snapshot_storages: &snapshot_storages, + phantom: std::marker::PhantomData::default(), + }) + .serialize(s) + } } diff --git a/runtime/src/snapshot_utils.rs b/runtime/src/snapshot_utils.rs index 56d1889aa125bf..57115317571407 100644 --- a/runtime/src/snapshot_utils.rs +++ b/runtime/src/snapshot_utils.rs @@ -51,6 +51,7 @@ pub const DEFAULT_FULL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS: Slot = 25_000; pub const DEFAULT_INCREMENTAL_SNAPSHOT_ARCHIVE_INTERVAL_SLOTS: Slot = 100; const MAX_SNAPSHOT_DATA_FILE_SIZE: u64 = 32 * 1024 * 1024 * 1024; // 32 GiB const MAX_SNAPSHOT_VERSION_FILE_SIZE: u64 = 8; // byte +const VERSION_STRING_V1_3_0: &str = "1.3.0"; const VERSION_STRING_V1_2_0: &str = "1.2.0"; pub(crate) const TMP_BANK_SNAPSHOT_PREFIX: &str = "tmp-bank-snapshot-"; pub const TMP_SNAPSHOT_ARCHIVE_PREFIX: &str = "tmp-snapshot-archive-"; @@ -62,6 +63,7 @@ pub const INCREMENTAL_SNAPSHOT_ARCHIVE_FILENAME_REGEX: &str = r"^incremental-sna #[derive(Copy, Clone, Eq, PartialEq, Debug)] pub enum SnapshotVersion { + V1_3_0, V1_2_0, } @@ -80,6 +82,7 @@ impl fmt::Display for SnapshotVersion { impl From for &'static str { fn from(snapshot_version: SnapshotVersion) -> &'static str { match snapshot_version { + SnapshotVersion::V1_3_0 => VERSION_STRING_V1_3_0, SnapshotVersion::V1_2_0 => VERSION_STRING_V1_2_0, } } @@ -99,6 +102,7 @@ impl FromStr for SnapshotVersion { version_string }; match version_string { + VERSION_STRING_V1_3_0 => Ok(SnapshotVersion::V1_3_0), VERSION_STRING_V1_2_0 => Ok(SnapshotVersion::V1_2_0), _ => Err("unsupported snapshot version"), } @@ -622,7 +626,8 @@ pub fn add_bank_snapshot>( let mut bank_serialize = Measure::start("bank-serialize-ms"); let bank_snapshot_serializer = move |stream: &mut BufWriter| -> Result<()> { let serde_style = match snapshot_version { - SnapshotVersion::V1_2_0 => SerdeStyle::Newer, + SnapshotVersion::V1_3_0 => SerdeStyle::Newer, + SnapshotVersion::V1_2_0 => SerdeStyle::Older, }; bank_to_stream(serde_style, stream.by_ref(), bank, snapshot_storages)?; Ok(()) @@ -1470,7 +1475,7 @@ fn rebuild_bank_from_snapshots( let bank = deserialize_snapshot_data_files(&snapshot_root_paths, |snapshot_streams| { Ok( match incremental_snapshot_version.unwrap_or(full_snapshot_version) { - SnapshotVersion::V1_2_0 => bank_from_streams( + SnapshotVersion::V1_3_0 => bank_from_streams( SerdeStyle::Newer, snapshot_streams, account_paths, @@ -1486,6 +1491,22 @@ fn rebuild_bank_from_snapshots( accounts_db_config, accounts_update_notifier, ), + SnapshotVersion::V1_2_0 => bank_from_streams( + SerdeStyle::Older, + snapshot_streams, + account_paths, + unpacked_append_vec_map, + genesis_config, + debug_keys, + additional_builtins, + account_secondary_indexes, + accounts_db_caching_enabled, + limit_load_slot_count_from_snapshot, + shrink_ratio, + verify_index, + accounts_db_config, + accounts_update_notifier, + ), }?, ) })?;