From e15f95a36f036c55b9609e3859ea47071aba3a0d Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Sun, 20 Dec 2020 14:36:56 -0700 Subject: [PATCH] Fix timestamp handling on ledger warp (#14210) * Reset timestamp for slot and epoch-start on warp * Fix genesis timestamp metric source * Remove check that timestamp > unix_timestamp_from_genesis Default to previous timestamp, not genesis timestamp * Move timestamp metrics to report even on warp * Initialize slot 0 timestamps correctly * Add feature gate to warp testnet timestamp * Review suggestion: simplify warp-timestamp slot check --- runtime/src/bank.rs | 78 ++++++++++++++++++++++++++++-------------- sdk/src/feature_set.rs | 5 +++ 2 files changed, 58 insertions(+), 25 deletions(-) diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 773d57a30a..09c24ad4f0 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -1075,10 +1075,22 @@ impl Bank { /// * Adjusts the new bank's tick height to avoid having to run PoH for millions of slots /// * Freezes the new bank, assuming that the user will `Bank::new_from_parent` from this bank pub fn warp_from_parent(parent: &Arc, collector_id: &Pubkey, slot: Slot) -> Self { + let parent_timestamp = parent.clock().unix_timestamp; let mut new = Bank::new_from_parent(parent, collector_id, slot); new.apply_feature_activations(true); new.update_epoch_stakes(new.epoch_schedule().get_epoch(slot)); new.tick_height.store(new.max_tick_height(), Relaxed); + + let mut clock = new.clock(); + clock.epoch_start_timestamp = parent_timestamp; + clock.unix_timestamp = parent_timestamp; + new.update_sysvar_account(&sysvar::clock::id(), |account| { + create_account( + &clock, + new.inherit_specially_retained_account_balance(account), + ) + }); + new.freeze(); new } @@ -1310,6 +1322,7 @@ impl Bank { .feature_set .is_active(&feature_set::timestamp_correction::id()) { + unix_timestamp = self.clock().unix_timestamp; let (estimate_type, epoch_start_timestamp) = if let Some(timestamp_bounding_activation_slot) = self .feature_set @@ -1319,14 +1332,23 @@ impl Bank { // needed for timestamp bounding, but isn't yet corrected for the activation slot let epoch_start_timestamp = if self.slot() > timestamp_bounding_activation_slot { - let epoch = if let Some(epoch) = parent_epoch { - epoch + let warp_testnet_timestamp = self + .feature_set + .activated_slot(&feature_set::warp_testnet_timestamp::id()); + if warp_testnet_timestamp == Some(self.slot()) + && self.cluster_type() == ClusterType::Testnet + { + None } else { - self.epoch() - }; - let first_slot_in_epoch = - self.epoch_schedule.get_first_slot_in_epoch(epoch); - Some((first_slot_in_epoch, self.clock().epoch_start_timestamp)) + let epoch = if let Some(epoch) = parent_epoch { + epoch + } else { + self.epoch() + }; + let first_slot_in_epoch = + self.epoch_schedule.get_first_slot_in_epoch(epoch); + Some((first_slot_in_epoch, self.clock().epoch_start_timestamp)) + } } else { None }; @@ -1334,30 +1356,29 @@ impl Bank { } else { (EstimateType::Unbounded, None) }; + + let ancestor_timestamp = self.clock().unix_timestamp; if let Some(timestamp_estimate) = self.get_timestamp_estimate(estimate_type, epoch_start_timestamp) { - if timestamp_estimate > unix_timestamp { - unix_timestamp = timestamp_estimate; - let ancestor_timestamp = self.clock().unix_timestamp; - if self - .feature_set - .is_active(&feature_set::timestamp_bounding::id()) - && timestamp_estimate < ancestor_timestamp - { - unix_timestamp = ancestor_timestamp; - } - datapoint_info!( - "bank-timestamp-correction", - ("slot", self.slot(), i64), - ("from_genesis", unix_timestamp, i64), - ("corrected", timestamp_estimate, i64), - ("ancestor_timestamp", ancestor_timestamp, i64), - ); + unix_timestamp = timestamp_estimate; + if self + .feature_set + .is_active(&feature_set::timestamp_bounding::id()) + && timestamp_estimate < ancestor_timestamp + { + unix_timestamp = ancestor_timestamp; } } + datapoint_info!( + "bank-timestamp-correction", + ("slot", self.slot(), i64), + ("from_genesis", self.unix_timestamp_from_genesis(), i64), + ("corrected", unix_timestamp, i64), + ("ancestor_timestamp", ancestor_timestamp, i64), + ); } - let epoch_start_timestamp = if self + let mut epoch_start_timestamp = if self .feature_set .is_active(&feature_set::timestamp_bounding::id()) { @@ -1370,6 +1391,10 @@ impl Bank { } else { Self::get_unused_from_slot(self.slot, self.unused) as i64 }; + if self.slot == 0 { + unix_timestamp = self.unix_timestamp_from_genesis(); + epoch_start_timestamp = self.unix_timestamp_from_genesis(); + } let clock = sysvar::clock::Clock { slot: self.slot, epoch_start_timestamp, @@ -11146,6 +11171,9 @@ pub(crate) mod tests { .. } = create_genesis_config_with_leader(5, &leader_pubkey, 3); let mut bank = Bank::new(&genesis_config); + // Advance past slot 0, which has special handling. + bank = new_from_parent(&Arc::new(bank)); + bank = new_from_parent(&Arc::new(bank)); assert_eq!( bank.clock().unix_timestamp, bank.unix_timestamp_from_genesis() diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 2bd4af1db8..a10ad7d545 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -110,6 +110,10 @@ pub mod try_find_program_address_syscall_enabled { solana_sdk::declare_id!("EMsMNadQNhCYDyGpYH5Tx6dGHxiUqKHk782PU5XaWfmi"); } +pub mod warp_testnet_timestamp { + solana_sdk::declare_id!("Bfqm7fGk5MBptqa2WHXWFLH7uJvq8hkJcAQPipy2bAMk"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -139,6 +143,7 @@ lazy_static! { (simple_capitalization::id(), "simple capitalization"), (bpf_loader_upgradeable_program::id(), "upgradeable bpf loader"), (try_find_program_address_syscall_enabled::id(), "add try_find_program_address syscall"), + (warp_testnet_timestamp::id(), "warp testnet timestamp to current #TODO"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()