* 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
(cherry picked from commit c75d97e3f2
)
Co-authored-by: Tyera Eulberg <teulberg@gmail.com>
This commit is contained in:
@ -1335,6 +1335,32 @@ impl Bank {
|
|||||||
(examined_count, rewritten_count)
|
(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
|
// update rewards based on the previous epoch
|
||||||
fn update_rewards(
|
fn update_rewards(
|
||||||
&mut self,
|
&mut self,
|
||||||
@ -1346,9 +1372,9 @@ impl Bank {
|
|||||||
}
|
}
|
||||||
// if I'm the first Bank in an epoch, count, claim, disburse rewards from Inflation
|
// if I'm the first Bank in an epoch, count, claim, disburse rewards from Inflation
|
||||||
|
|
||||||
// calculated as: prev_slot / (slots / year)
|
// calculated as: num_slots / (slots / year)
|
||||||
let slot_in_year =
|
let num_slots = self.get_inflation_num_slots();
|
||||||
(self.epoch_schedule.get_last_slot_in_epoch(prev_epoch)) as f64 / self.slots_per_year;
|
let slot_in_year = num_slots as f64 / self.slots_per_year;
|
||||||
|
|
||||||
let epoch_duration_in_years = self.epoch_duration_in_years(prev_epoch);
|
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
|
self.rent_collector.rent.burn_percent = 50; // 50% rent burn
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_feature_activations.contains(&feature_set::inflation_kill_switch::id()) {
|
if new_feature_activations.contains(&feature_set::full_inflation::id()) {
|
||||||
*self.inflation.write().unwrap() = Inflation::new_disabled();
|
*self.inflation.write().unwrap() = Inflation::full();
|
||||||
self.fee_rate_governor.burn_percent = 100; // 100% fee burn
|
self.fee_rate_governor.burn_percent = 50; // 50% fee burn
|
||||||
self.rent_collector.rent.burn_percent = 100; // 100% rent burn
|
self.rent_collector.rent.burn_percent = 50; // 50% rent burn
|
||||||
}
|
}
|
||||||
|
|
||||||
if new_feature_activations.contains(&feature_set::spl_token_v2_multisig_fix::id()) {
|
if new_feature_activations.contains(&feature_set::spl_token_v2_multisig_fix::id()) {
|
||||||
@ -10700,4 +10726,140 @@ pub(crate) mod tests {
|
|||||||
|
|
||||||
assert_eq!(bank.rewrite_stakes(), (1, 1));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,11 @@ pub mod consistent_recent_blockhashes_sysvar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub mod pico_inflation {
|
pub mod pico_inflation {
|
||||||
solana_sdk::declare_id!("GaBtBJvmS4Arjj5W1NmFcyvPjsHN38UGYDq2MDwbs9Qu");
|
solana_sdk::declare_id!("4RWNif6C2WCNiKVW7otP4G7dkmkHGyKQWRpuZ1pxKU5m");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod inflation_kill_switch {
|
pub mod full_inflation {
|
||||||
solana_sdk::declare_id!("SECCKV5UVUsr8sTVSVAzULjdm87r7mLPaqH2FGZjevR");
|
solana_sdk::declare_id!("DT4n6ABDqs6w4bnfwrXT9rsprcPf6cdDga1egctaPkLC");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod spl_token_v2_multisig_fix {
|
pub mod spl_token_v2_multisig_fix {
|
||||||
@ -97,7 +97,7 @@ lazy_static! {
|
|||||||
(secp256k1_program_enabled::id(), "secp256k1 program"),
|
(secp256k1_program_enabled::id(), "secp256k1 program"),
|
||||||
(consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"),
|
(consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"),
|
||||||
(pico_inflation::id(), "pico-inflation"),
|
(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"),
|
(spl_token_v2_multisig_fix::id(), "spl-token multisig fix"),
|
||||||
(bpf_loader2_program::id(), "bpf_loader2 program"),
|
(bpf_loader2_program::id(), "bpf_loader2 program"),
|
||||||
(bpf_compute_budget_balancing::id(), "compute budget balancing"),
|
(bpf_compute_budget_balancing::id(), "compute budget balancing"),
|
||||||
|
@ -69,6 +69,17 @@ impl Inflation {
|
|||||||
Self::new_fixed(0.0001) // 0.01% 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
|
/// inflation rate at year
|
||||||
pub fn total(&self, year: f64) -> f64 {
|
pub fn total(&self, year: f64) -> f64 {
|
||||||
assert!(year >= 0.0);
|
assert!(year >= 0.0);
|
||||||
|
Reference in New Issue
Block a user