diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 28428dabe099f4..b31a9cb2a46f44 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -128,7 +128,8 @@ use { BankId, Epoch, Slot, SlotCount, SlotIndex, UnixTimestamp, DEFAULT_HASHES_PER_TICK, DEFAULT_TICKS_PER_SECOND, INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_TRANSACTION_FORWARDING_DELAY, MAX_TRANSACTION_FORWARDING_DELAY_GPU, - SECONDS_PER_DAY, + SECONDS_PER_DAY, UPDATED_HASHES_PER_TICK2, UPDATED_HASHES_PER_TICK3, + UPDATED_HASHES_PER_TICK4, UPDATED_HASHES_PER_TICK5, UPDATED_HASHES_PER_TICK6, }, epoch_info::EpochInfo, epoch_schedule::EpochSchedule, @@ -8053,6 +8054,26 @@ impl Bank { self.apply_updated_hashes_per_tick(DEFAULT_HASHES_PER_TICK); } + if new_feature_activations.contains(&feature_set::update_hashes_per_tick2::id()) { + self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK2); + } + + if new_feature_activations.contains(&feature_set::update_hashes_per_tick3::id()) { + self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK3); + } + + if new_feature_activations.contains(&feature_set::update_hashes_per_tick4::id()) { + self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK4); + } + + if new_feature_activations.contains(&feature_set::update_hashes_per_tick5::id()) { + self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK5); + } + + if new_feature_activations.contains(&feature_set::update_hashes_per_tick6::id()) { + self.apply_updated_hashes_per_tick(UPDATED_HASHES_PER_TICK6); + } + if new_feature_activations.contains(&feature_set::programify_feature_gate_program::id()) { let datapoint_name = "bank-progamify_feature_gate_program"; if let Err(e) = replace_account::replace_empty_account_with_upgradeable_program( diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index 97c08289fbc0e7..9dd27bfd3254bf 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -62,6 +62,8 @@ use { clock::{ BankId, Epoch, Slot, UnixTimestamp, DEFAULT_HASHES_PER_TICK, DEFAULT_SLOTS_PER_EPOCH, DEFAULT_TICKS_PER_SLOT, INITIAL_RENT_EPOCH, MAX_PROCESSING_AGE, MAX_RECENT_BLOCKHASHES, + UPDATED_HASHES_PER_TICK2, UPDATED_HASHES_PER_TICK3, UPDATED_HASHES_PER_TICK4, + UPDATED_HASHES_PER_TICK5, UPDATED_HASHES_PER_TICK6, }, compute_budget::ComputeBudgetInstruction, entrypoint::MAX_PERMITTED_DATA_INCREASE, @@ -12230,6 +12232,80 @@ fn test_feature_activation_idempotent() { assert_eq!(bank.hashes_per_tick, Some(DEFAULT_HASHES_PER_TICK)); } +#[test] +fn test_feature_hashes_per_tick() { + let mut genesis_config = GenesisConfig::default(); + const HASHES_PER_TICK_START: u64 = 3; + genesis_config.poh_config.hashes_per_tick = Some(HASHES_PER_TICK_START); + + let mut bank = Bank::new_for_tests(&genesis_config); + assert_eq!(bank.hashes_per_tick, Some(HASHES_PER_TICK_START)); + + // Don't activate feature + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false); + assert_eq!(bank.hashes_per_tick, Some(HASHES_PER_TICK_START)); + + // Activate feature + let feature_account_balance = + std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1); + bank.store_account( + &feature_set::update_hashes_per_tick::id(), + &feature::create_account(&Feature { activated_at: None }, feature_account_balance), + ); + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false); + assert_eq!(bank.hashes_per_tick, Some(DEFAULT_HASHES_PER_TICK)); + + // Activate feature + let feature_account_balance = + std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1); + bank.store_account( + &feature_set::update_hashes_per_tick2::id(), + &feature::create_account(&Feature { activated_at: None }, feature_account_balance), + ); + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false); + assert_eq!(bank.hashes_per_tick, Some(UPDATED_HASHES_PER_TICK2)); + + // Activate feature + let feature_account_balance = + std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1); + bank.store_account( + &feature_set::update_hashes_per_tick3::id(), + &feature::create_account(&Feature { activated_at: None }, feature_account_balance), + ); + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false); + assert_eq!(bank.hashes_per_tick, Some(UPDATED_HASHES_PER_TICK3)); + + // Activate feature + let feature_account_balance = + std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1); + bank.store_account( + &feature_set::update_hashes_per_tick4::id(), + &feature::create_account(&Feature { activated_at: None }, feature_account_balance), + ); + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false); + assert_eq!(bank.hashes_per_tick, Some(UPDATED_HASHES_PER_TICK4)); + + // Activate feature + let feature_account_balance = + std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1); + bank.store_account( + &feature_set::update_hashes_per_tick5::id(), + &feature::create_account(&Feature { activated_at: None }, feature_account_balance), + ); + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false); + assert_eq!(bank.hashes_per_tick, Some(UPDATED_HASHES_PER_TICK5)); + + // Activate feature + let feature_account_balance = + std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1); + bank.store_account( + &feature_set::update_hashes_per_tick6::id(), + &feature::create_account(&Feature { activated_at: None }, feature_account_balance), + ); + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, false); + assert_eq!(bank.hashes_per_tick, Some(UPDATED_HASHES_PER_TICK6)); +} + #[test_case(true)] #[test_case(false)] fn test_stake_account_consistency_with_rent_epoch_max_feature( diff --git a/sdk/program/src/clock.rs b/sdk/program/src/clock.rs index 45f49f218b15c7..e988bafb21d354 100644 --- a/sdk/program/src/clock.rs +++ b/sdk/program/src/clock.rs @@ -44,10 +44,43 @@ pub const DEFAULT_TICKS_PER_SLOT: u64 = 64; // GCP n1-standard hardware and also a xeon e5-2520 v4 are about this rate of hashes/s pub const DEFAULT_HASHES_PER_SECOND: u64 = 2_000_000; +// Empirical sampling of mainnet validator hash rate showed the following stake +// percentages can exceed the designated hash rates as of July 2023: +// 97.6% +pub const UPDATED_HASHES_PER_SECOND_2: u64 = 2_800_000; +// 96.2% +pub const UPDATED_HASHES_PER_SECOND_3: u64 = 4_400_000; +// 96.2% +pub const UPDATED_HASHES_PER_SECOND_4: u64 = 7_600_000; +// 96.2% +pub const UPDATED_HASHES_PER_SECOND_5: u64 = 9_200_000; +// 96.2% +pub const UPDATED_HASHES_PER_SECOND_6: u64 = 10_000_000; + #[cfg(test)] static_assertions::const_assert_eq!(DEFAULT_HASHES_PER_TICK, 12_500); pub const DEFAULT_HASHES_PER_TICK: u64 = DEFAULT_HASHES_PER_SECOND / DEFAULT_TICKS_PER_SECOND; +#[cfg(test)] +static_assertions::const_assert_eq!(UPDATED_HASHES_PER_TICK2, 17_500); +pub const UPDATED_HASHES_PER_TICK2: u64 = UPDATED_HASHES_PER_SECOND_2 / DEFAULT_TICKS_PER_SECOND; + +#[cfg(test)] +static_assertions::const_assert_eq!(UPDATED_HASHES_PER_TICK3, 27_500); +pub const UPDATED_HASHES_PER_TICK3: u64 = UPDATED_HASHES_PER_SECOND_3 / DEFAULT_TICKS_PER_SECOND; + +#[cfg(test)] +static_assertions::const_assert_eq!(UPDATED_HASHES_PER_TICK4, 47_500); +pub const UPDATED_HASHES_PER_TICK4: u64 = UPDATED_HASHES_PER_SECOND_4 / DEFAULT_TICKS_PER_SECOND; + +#[cfg(test)] +static_assertions::const_assert_eq!(UPDATED_HASHES_PER_TICK5, 57_500); +pub const UPDATED_HASHES_PER_TICK5: u64 = UPDATED_HASHES_PER_SECOND_5 / DEFAULT_TICKS_PER_SECOND; + +#[cfg(test)] +static_assertions::const_assert_eq!(UPDATED_HASHES_PER_TICK6, 62_500); +pub const UPDATED_HASHES_PER_TICK6: u64 = UPDATED_HASHES_PER_SECOND_6 / DEFAULT_TICKS_PER_SECOND; + // 1 Dev Epoch = 400 ms * 8192 ~= 55 minutes pub const DEFAULT_DEV_SLOTS_PER_EPOCH: u64 = 8192; diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 9ec56b03e0e3bf..bc81d781a7c176 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -704,6 +704,26 @@ pub mod programify_feature_gate_program { solana_sdk::declare_id!("8GdovDzVwWU5edz2G697bbB7GZjrUc6aQZLWyNNAtHdg"); } +pub mod update_hashes_per_tick2 { + solana_sdk::declare_id!("EWme9uFqfy1ikK1jhJs8fM5hxWnK336QJpbscNtizkTU"); +} + +pub mod update_hashes_per_tick3 { + solana_sdk::declare_id!("8C8MCtsab5SsfammbzvYz65HHauuUYdbY2DZ4sznH6h5"); +} + +pub mod update_hashes_per_tick4 { + solana_sdk::declare_id!("8We4E7DPwF2WfAN8tRTtWQNhi98B99Qpuj7JoZ3Aikgg"); +} + +pub mod update_hashes_per_tick5 { + solana_sdk::declare_id!("BsKLKAn1WM4HVhPRDsjosmqSg2J8Tq5xP2s2daDS6Ni4"); +} + +pub mod update_hashes_per_tick6 { + solana_sdk::declare_id!("FKu1qYwLQSiehz644H6Si65U5ZQ2cp9GxsyFUfYcuADv"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -875,6 +895,11 @@ lazy_static! { (better_error_codes_for_tx_lamport_check::id(), "better error codes for tx lamport check #33353"), (enable_alt_bn128_compression_syscall::id(), "add alt_bn128 compression syscalls"), (programify_feature_gate_program::id(), "move feature gate activation logic to an on-chain program #32783"), + (update_hashes_per_tick2::id(), "Update desired hashes per tick to 2.8M"), + (update_hashes_per_tick3::id(), "Update desired hashes per tick to 4.4M"), + (update_hashes_per_tick4::id(), "Update desired hashes per tick to 7.6M"), + (update_hashes_per_tick5::id(), "Update desired hashes per tick to 9.2M"), + (update_hashes_per_tick6::id(), "Update desired hashes per tick to 10M"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()