From c75d97e3f200dc5558e6f97fa4e774abc0bb523f Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 20 Nov 2020 09:54:41 -0700 Subject: [PATCH] Add new inflation feature-ids (#13671) * Add new inflation feature-ids, and full_inflation default values * Compute inflation start from full_inflation activation * Include pico_inflation in inflation start computation * Add full-inflation constructor * Align inflation taper with rewards accrual start and catch overflow edge case --- runtime/src/bank.rs | 176 +++++++++++++++++++++++++++++++++++++++-- sdk/src/feature_set.rs | 8 +- sdk/src/inflation.rs | 11 +++ 3 files changed, 184 insertions(+), 11 deletions(-) diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 76d01683f..8f30230bf 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -1335,6 +1335,32 @@ impl Bank { (examined_count, rewritten_count) } + // Calculates the starting-slot for inflation from the activation slot. + // This method assumes that `pico_inflation` will be enabled before `full_inflation`, giving + // precedence to the latter. However, since `pico_inflation` is fixed-rate Inflation, should + // `pico_inflation` be enabled 2nd, the incorrect start slot provided here should have no + // effect on the inflation calculation. + fn get_inflation_start_slot(&self) -> Slot { + self.feature_set + .activated_slot(&feature_set::full_inflation::id()) + .unwrap_or_else(|| { + self.feature_set + .activated_slot(&feature_set::pico_inflation::id()) + .unwrap_or(0) + }) + } + + fn get_inflation_num_slots(&self) -> u64 { + let inflation_activation_slot = self.get_inflation_start_slot(); + // Normalize inflation_start to align with the start of rewards accrual. + let inflation_start_slot = self.epoch_schedule.get_first_slot_in_epoch( + self.epoch_schedule + .get_epoch(inflation_activation_slot) + .saturating_sub(1), + ); + self.epoch_schedule.get_first_slot_in_epoch(self.epoch()) - inflation_start_slot + } + // update rewards based on the previous epoch fn update_rewards( &mut self, @@ -1346,9 +1372,9 @@ impl Bank { } // if I'm the first Bank in an epoch, count, claim, disburse rewards from Inflation - // calculated as: prev_slot / (slots / year) - let slot_in_year = - (self.epoch_schedule.get_last_slot_in_epoch(prev_epoch)) as f64 / self.slots_per_year; + // calculated as: num_slots / (slots / year) + let num_slots = self.get_inflation_num_slots(); + let slot_in_year = num_slots as f64 / self.slots_per_year; let epoch_duration_in_years = self.epoch_duration_in_years(prev_epoch); @@ -4142,10 +4168,10 @@ impl Bank { self.rent_collector.rent.burn_percent = 50; // 50% rent burn } - if new_feature_activations.contains(&feature_set::inflation_kill_switch::id()) { - *self.inflation.write().unwrap() = Inflation::new_disabled(); - self.fee_rate_governor.burn_percent = 100; // 100% fee burn - self.rent_collector.rent.burn_percent = 100; // 100% rent burn + if new_feature_activations.contains(&feature_set::full_inflation::id()) { + *self.inflation.write().unwrap() = Inflation::full(); + self.fee_rate_governor.burn_percent = 50; // 50% fee burn + self.rent_collector.rent.burn_percent = 50; // 50% rent burn } if new_feature_activations.contains(&feature_set::spl_token_v2_multisig_fix::id()) { @@ -10702,4 +10728,140 @@ pub(crate) mod tests { assert_eq!(bank.rewrite_stakes(), (1, 1)); } + + #[test] + fn test_get_inflation_start_slot() { + let GenesisConfigInfo { + mut genesis_config, .. + } = create_genesis_config_with_leader(42, &solana_sdk::pubkey::new_rand(), 42); + genesis_config + .accounts + .remove(&feature_set::pico_inflation::id()) + .unwrap(); + genesis_config + .accounts + .remove(&feature_set::full_inflation::id()) + .unwrap(); + let bank = Bank::new(&genesis_config); + + // Advance to slot 1 + let mut bank = new_from_parent(&Arc::new(bank)); + bank = new_from_parent(&Arc::new(bank)); + assert_eq!(bank.get_inflation_start_slot(), 0); + + // Request `full_inflation` activation + let pico_inflation_activation_slot = 1; + bank.store_account( + &feature_set::pico_inflation::id(), + &feature::create_account( + &Feature { + activated_at: Some(pico_inflation_activation_slot), + }, + 42, + ), + ); + bank.compute_active_feature_set(true); + assert_eq!( + bank.get_inflation_start_slot(), + pico_inflation_activation_slot + ); + + // Advance to slot 2 + bank = new_from_parent(&Arc::new(bank)); + + // Request `full_inflation` activation, which takes priority over pico_inflation + let full_inflation_activation_slot = 2; + bank.store_account( + &feature_set::full_inflation::id(), + &feature::create_account( + &Feature { + activated_at: Some(full_inflation_activation_slot), + }, + 42, + ), + ); + bank.compute_active_feature_set(true); + assert_eq!( + bank.get_inflation_start_slot(), + full_inflation_activation_slot + ); + } + + #[test] + fn test_get_inflation_num_slots_with_activations() { + let GenesisConfigInfo { + mut genesis_config, .. + } = create_genesis_config_with_leader(42, &solana_sdk::pubkey::new_rand(), 42); + let slots_per_epoch = 32; + genesis_config.epoch_schedule = EpochSchedule::new(slots_per_epoch); + genesis_config + .accounts + .remove(&feature_set::pico_inflation::id()) + .unwrap(); + genesis_config + .accounts + .remove(&feature_set::full_inflation::id()) + .unwrap(); + let mut bank = Bank::new(&genesis_config); + assert_eq!(bank.get_inflation_num_slots(), 0); + for _ in 0..2 * slots_per_epoch { + bank = new_from_parent(&Arc::new(bank)); + } + assert_eq!(bank.get_inflation_num_slots(), 2 * slots_per_epoch); + + // Activate pico_inflation + let pico_inflation_activation_slot = bank.slot(); + bank.store_account( + &feature_set::pico_inflation::id(), + &feature::create_account( + &Feature { + activated_at: Some(pico_inflation_activation_slot), + }, + 42, + ), + ); + bank.compute_active_feature_set(true); + assert_eq!(bank.get_inflation_num_slots(), slots_per_epoch); + for _ in 0..slots_per_epoch { + bank = new_from_parent(&Arc::new(bank)); + } + assert_eq!(bank.get_inflation_num_slots(), 2 * slots_per_epoch); + + // Activate full_inflation + let full_inflation_activation_slot = bank.slot(); + bank.store_account( + &feature_set::full_inflation::id(), + &feature::create_account( + &Feature { + activated_at: Some(full_inflation_activation_slot), + }, + 42, + ), + ); + bank.compute_active_feature_set(true); + assert_eq!(bank.get_inflation_num_slots(), slots_per_epoch); + for _ in 0..slots_per_epoch { + bank = new_from_parent(&Arc::new(bank)); + } + assert_eq!(bank.get_inflation_num_slots(), 2 * slots_per_epoch); + } + + #[test] + fn test_get_inflation_num_slots_already_activated() { + let GenesisConfigInfo { + mut genesis_config, .. + } = create_genesis_config_with_leader(42, &solana_sdk::pubkey::new_rand(), 42); + let slots_per_epoch = 32; + genesis_config.epoch_schedule = EpochSchedule::new(slots_per_epoch); + let mut bank = Bank::new(&genesis_config); + assert_eq!(bank.get_inflation_num_slots(), 0); + for _ in 0..slots_per_epoch { + bank = new_from_parent(&Arc::new(bank)); + } + assert_eq!(bank.get_inflation_num_slots(), slots_per_epoch); + for _ in 0..slots_per_epoch { + bank = new_from_parent(&Arc::new(bank)); + } + assert_eq!(bank.get_inflation_num_slots(), 2 * slots_per_epoch); + } } diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index ccb38c8af..0b8ed82d9 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -19,11 +19,11 @@ pub mod consistent_recent_blockhashes_sysvar { } pub mod pico_inflation { - solana_sdk::declare_id!("GaBtBJvmS4Arjj5W1NmFcyvPjsHN38UGYDq2MDwbs9Qu"); + solana_sdk::declare_id!("4RWNif6C2WCNiKVW7otP4G7dkmkHGyKQWRpuZ1pxKU5m"); } -pub mod inflation_kill_switch { - solana_sdk::declare_id!("SECCKV5UVUsr8sTVSVAzULjdm87r7mLPaqH2FGZjevR"); +pub mod full_inflation { + solana_sdk::declare_id!("DT4n6ABDqs6w4bnfwrXT9rsprcPf6cdDga1egctaPkLC"); } pub mod spl_token_v2_multisig_fix { @@ -97,7 +97,7 @@ lazy_static! { (secp256k1_program_enabled::id(), "secp256k1 program"), (consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"), (pico_inflation::id(), "pico-inflation"), - (inflation_kill_switch::id(), "inflation kill switch"), + (full_inflation::id(), "full-inflation"), (spl_token_v2_multisig_fix::id(), "spl-token multisig fix"), (bpf_loader2_program::id(), "bpf_loader2 program"), (bpf_compute_budget_balancing::id(), "compute budget balancing"), diff --git a/sdk/src/inflation.rs b/sdk/src/inflation.rs index f809ee206..6392417ef 100644 --- a/sdk/src/inflation.rs +++ b/sdk/src/inflation.rs @@ -69,6 +69,17 @@ impl Inflation { Self::new_fixed(0.0001) // 0.01% inflation } + pub fn full() -> Self { + Self { + initial: DEFAULT_INITIAL, + terminal: DEFAULT_TERMINAL, + taper: DEFAULT_TAPER, + foundation: 0.0, + foundation_term: 0.0, + __unused: 0.0, + } + } + /// inflation rate at year pub fn total(&self, year: f64) -> f64 { assert!(year >= 0.0);