Add generalized voting process to enable full inflation
This commit is contained in:
parent
1de6d28eaf
commit
072e5e54d8
|
@ -1600,13 +1600,18 @@ impl Bank {
|
|||
// `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)
|
||||
})
|
||||
let mut slots = self
|
||||
.feature_set
|
||||
.full_inflation_features_enabled()
|
||||
.iter()
|
||||
.filter_map(|id| self.feature_set.activated_slot(&id))
|
||||
.collect::<Vec<_>>();
|
||||
slots.sort_unstable();
|
||||
slots.get(0).cloned().unwrap_or_else(|| {
|
||||
self.feature_set
|
||||
.activated_slot(&feature_set::pico_inflation::id())
|
||||
.unwrap_or(0)
|
||||
})
|
||||
}
|
||||
|
||||
fn get_inflation_num_slots(&self) -> u64 {
|
||||
|
@ -4669,7 +4674,8 @@ impl Bank {
|
|||
self.rent_collector.rent.burn_percent = 50; // 50% rent burn
|
||||
}
|
||||
|
||||
if new_feature_activations.contains(&feature_set::full_inflation::id()) {
|
||||
if !new_feature_activations.is_disjoint(&self.feature_set.full_inflation_features_enabled())
|
||||
{
|
||||
*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
|
||||
|
@ -11863,7 +11869,7 @@ pub(crate) mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_inflation_start_slot() {
|
||||
fn test_get_inflation_start_slot_devnet_testnet() {
|
||||
let GenesisConfigInfo {
|
||||
mut genesis_config, ..
|
||||
} = create_genesis_config_with_leader(42, &solana_sdk::pubkey::new_rand(), 42);
|
||||
|
@ -11873,51 +11879,156 @@ pub(crate) mod tests {
|
|||
.unwrap();
|
||||
genesis_config
|
||||
.accounts
|
||||
.remove(&feature_set::full_inflation::id())
|
||||
.remove(&feature_set::full_inflation::devnet_and_testnet::id())
|
||||
.unwrap();
|
||||
for pair in feature_set::FULL_INFLATION_FEATURE_PAIRS.iter() {
|
||||
genesis_config.accounts.remove(&pair.vote_id).unwrap();
|
||||
genesis_config.accounts.remove(&pair.enable_id).unwrap();
|
||||
}
|
||||
|
||||
let bank = Bank::new(&genesis_config);
|
||||
|
||||
// Advance to slot 1
|
||||
// Advance slot
|
||||
let mut bank = new_from_parent(&Arc::new(bank));
|
||||
bank = new_from_parent(&Arc::new(bank));
|
||||
assert_eq!(bank.get_inflation_start_slot(), 0);
|
||||
assert_eq!(bank.slot(), 2);
|
||||
|
||||
// Request `full_inflation` activation
|
||||
let pico_inflation_activation_slot = 1;
|
||||
// Request `pico_inflation` activation
|
||||
bank.store_account(
|
||||
&feature_set::pico_inflation::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(pico_inflation_activation_slot),
|
||||
activated_at: Some(1),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.compute_active_feature_set(true);
|
||||
assert_eq!(
|
||||
bank.get_inflation_start_slot(),
|
||||
pico_inflation_activation_slot
|
||||
);
|
||||
assert_eq!(bank.get_inflation_start_slot(), 1);
|
||||
|
||||
// Advance to slot 2
|
||||
// Advance slot
|
||||
bank = new_from_parent(&Arc::new(bank));
|
||||
assert_eq!(bank.slot(), 3);
|
||||
|
||||
// Request `full_inflation` activation, which takes priority over pico_inflation
|
||||
let full_inflation_activation_slot = 2;
|
||||
// Request `full_inflation::devnet_and_testnet` activation, which takes priority over pico_inflation
|
||||
bank.store_account(
|
||||
&feature_set::full_inflation::id(),
|
||||
&feature_set::full_inflation::devnet_and_testnet::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(full_inflation_activation_slot),
|
||||
activated_at: Some(2),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.compute_active_feature_set(true);
|
||||
assert_eq!(
|
||||
bank.get_inflation_start_slot(),
|
||||
full_inflation_activation_slot
|
||||
assert_eq!(bank.get_inflation_start_slot(), 2);
|
||||
|
||||
// Request `full_inflation::candidate_example` activation, which should have no effect on `get_inflation_start_slot`
|
||||
bank.store_account(
|
||||
&feature_set::full_inflation::candidate_example::vote::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(3),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.store_account(
|
||||
&feature_set::full_inflation::candidate_example::enable::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(3),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.compute_active_feature_set(true);
|
||||
assert_eq!(bank.get_inflation_start_slot(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_inflation_start_slot_mainnet() {
|
||||
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::devnet_and_testnet::id())
|
||||
.unwrap();
|
||||
for pair in feature_set::FULL_INFLATION_FEATURE_PAIRS.iter() {
|
||||
genesis_config.accounts.remove(&pair.vote_id).unwrap();
|
||||
genesis_config.accounts.remove(&pair.enable_id).unwrap();
|
||||
}
|
||||
|
||||
let bank = Bank::new(&genesis_config);
|
||||
|
||||
// Advance slot
|
||||
let mut bank = new_from_parent(&Arc::new(bank));
|
||||
bank = new_from_parent(&Arc::new(bank));
|
||||
assert_eq!(bank.get_inflation_start_slot(), 0);
|
||||
assert_eq!(bank.slot(), 2);
|
||||
|
||||
// Request `pico_inflation` activation
|
||||
bank.store_account(
|
||||
&feature_set::pico_inflation::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(1),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.compute_active_feature_set(true);
|
||||
assert_eq!(bank.get_inflation_start_slot(), 1);
|
||||
|
||||
// Advance slot
|
||||
bank = new_from_parent(&Arc::new(bank));
|
||||
assert_eq!(bank.slot(), 3);
|
||||
|
||||
// Request `full_inflation::candidate_example` activation, which takes priority over pico_inflation
|
||||
bank.store_account(
|
||||
&feature_set::full_inflation::candidate_example::vote::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(2),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.store_account(
|
||||
&feature_set::full_inflation::candidate_example::enable::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(2),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.compute_active_feature_set(true);
|
||||
assert_eq!(bank.get_inflation_start_slot(), 2);
|
||||
|
||||
// Advance slot
|
||||
bank = new_from_parent(&Arc::new(bank));
|
||||
assert_eq!(bank.slot(), 4);
|
||||
|
||||
// Request `full_inflation::devnet_and_testnet` activation, which should have no effect on
|
||||
// `get_inflation_start_slot`
|
||||
bank.store_account(
|
||||
&feature_set::full_inflation::devnet_and_testnet::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(bank.slot()),
|
||||
},
|
||||
42,
|
||||
),
|
||||
);
|
||||
bank.compute_active_feature_set(true);
|
||||
assert_eq!(bank.get_inflation_start_slot(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -11933,8 +12044,13 @@ pub(crate) mod tests {
|
|||
.unwrap();
|
||||
genesis_config
|
||||
.accounts
|
||||
.remove(&feature_set::full_inflation::id())
|
||||
.remove(&feature_set::full_inflation::devnet_and_testnet::id())
|
||||
.unwrap();
|
||||
for pair in feature_set::FULL_INFLATION_FEATURE_PAIRS.iter() {
|
||||
genesis_config.accounts.remove(&pair.vote_id).unwrap();
|
||||
genesis_config.accounts.remove(&pair.enable_id).unwrap();
|
||||
}
|
||||
|
||||
let mut bank = Bank::new(&genesis_config);
|
||||
assert_eq!(bank.get_inflation_num_slots(), 0);
|
||||
for _ in 0..2 * slots_per_epoch {
|
||||
|
@ -11960,10 +12076,10 @@ pub(crate) mod tests {
|
|||
}
|
||||
assert_eq!(bank.get_inflation_num_slots(), 2 * slots_per_epoch);
|
||||
|
||||
// Activate full_inflation
|
||||
// Activate full_inflation::devnet_and_testnet
|
||||
let full_inflation_activation_slot = bank.slot();
|
||||
bank.store_account(
|
||||
&feature_set::full_inflation::id(),
|
||||
&feature_set::full_inflation::devnet_and_testnet::id(),
|
||||
&feature::create_account(
|
||||
&Feature {
|
||||
activated_at: Some(full_inflation_activation_slot),
|
||||
|
|
|
@ -27,7 +27,27 @@ pub mod pico_inflation {
|
|||
}
|
||||
|
||||
pub mod full_inflation {
|
||||
solana_sdk::declare_id!("DT4n6ABDqs6w4bnfwrXT9rsprcPf6cdDga1egctaPkLC");
|
||||
pub mod devnet_and_testnet {
|
||||
solana_sdk::declare_id!("DT4n6ABDqs6w4bnfwrXT9rsprcPf6cdDga1egctaPkLC");
|
||||
}
|
||||
|
||||
// `candidate_example` is an example to follow by a candidate that wishes to enable full
|
||||
// inflation. There are multiple references to `candidate_example` in this file that need to
|
||||
// be touched in addition to the following block.
|
||||
//
|
||||
// The candidate provides the `enable::id` address and contacts the Solana Foundation to
|
||||
// receive a `vote::id` address.
|
||||
//
|
||||
pub mod candidate_example {
|
||||
pub mod vote {
|
||||
// The private key for this address is held by the Solana Foundation
|
||||
solana_sdk::declare_id!("DummyVoteAddress111111111111111111111111111");
|
||||
}
|
||||
pub mod enable {
|
||||
// The private key for this address is held by candidate_example
|
||||
solana_sdk::declare_id!("DummyEnab1eAddress1111111111111111111111111");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod spl_token_v2_multisig_fix {
|
||||
|
@ -153,8 +173,8 @@ lazy_static! {
|
|||
(secp256k1_program_enabled::id(), "secp256k1 program"),
|
||||
(consistent_recent_blockhashes_sysvar::id(), "consistent recentblockhashes sysvar"),
|
||||
(deprecate_rewards_sysvar::id(), "deprecate unused rewards sysvar"),
|
||||
(pico_inflation::id(), "pico-inflation"),
|
||||
(full_inflation::id(), "full-inflation"),
|
||||
(pico_inflation::id(), "pico inflation"),
|
||||
(full_inflation::devnet_and_testnet::id(), "full inflation on devnet and testnet"),
|
||||
(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"),
|
||||
|
@ -184,6 +204,8 @@ lazy_static! {
|
|||
(use_loaded_executables::id(), "Use loaded executable accounts"),
|
||||
(turbine_retransmit_peers_patch::id(), "turbine retransmit peers patch #14631"),
|
||||
(prevent_upgrade_and_invoke::id(), "Prevent upgrade and invoke in same tx batch"),
|
||||
(full_inflation::candidate_example::vote::id(), "Community vote allowing candidate_example to enable full inflation"),
|
||||
(full_inflation::candidate_example::enable::id(), "Full inflation enabled by candidate_example"),
|
||||
/*************** ADD NEW FEATURES HERE ***************/
|
||||
]
|
||||
.iter()
|
||||
|
@ -202,6 +224,25 @@ lazy_static! {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FullInflationFeaturePair {
|
||||
pub vote_id: Pubkey, // Feature that grants the candidate the ability to enable full inflation
|
||||
pub enable_id: Pubkey, // Feature to enable full inflation by the candidate
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
/// Set of feature pairs that once enabled will trigger full inflation
|
||||
pub static ref FULL_INFLATION_FEATURE_PAIRS: HashSet<FullInflationFeaturePair> = [
|
||||
FullInflationFeaturePair {
|
||||
vote_id: full_inflation::candidate_example::vote::id(),
|
||||
enable_id: full_inflation::candidate_example::enable::id(),
|
||||
},
|
||||
]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// `FeatureSet` holds the set of currently active/inactive runtime features
|
||||
#[derive(AbiExample, Debug, Clone)]
|
||||
pub struct FeatureSet {
|
||||
|
@ -230,6 +271,25 @@ impl FeatureSet {
|
|||
self.is_active(&cumulative_rent_related_fixes::id())
|
||||
}
|
||||
|
||||
/// List of enabled features that trigger full inflation
|
||||
pub fn full_inflation_features_enabled(&self) -> HashSet<Pubkey> {
|
||||
let mut hash_set = FULL_INFLATION_FEATURE_PAIRS
|
||||
.iter()
|
||||
.filter_map(|pair| {
|
||||
if self.is_active(&pair.vote_id) && self.is_active(&pair.enable_id) {
|
||||
Some(pair.enable_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
if self.is_active(&full_inflation::devnet_and_testnet::id()) {
|
||||
hash_set.insert(full_inflation::devnet_and_testnet::id());
|
||||
}
|
||||
hash_set
|
||||
}
|
||||
|
||||
/// All features enabled, useful for testing
|
||||
pub fn all_enabled() -> Self {
|
||||
Self {
|
||||
|
@ -238,3 +298,63 @@ impl FeatureSet {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_full_inflation_features_enabled_devnet_and_testnet() {
|
||||
let mut feature_set = FeatureSet::default();
|
||||
assert!(feature_set.full_inflation_features_enabled().is_empty());
|
||||
feature_set
|
||||
.active
|
||||
.insert(full_inflation::devnet_and_testnet::id(), 42);
|
||||
assert_eq!(
|
||||
feature_set.full_inflation_features_enabled(),
|
||||
[full_inflation::devnet_and_testnet::id()]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_full_inflation_features_enabled() {
|
||||
// Normal sequence: vote_id then enable_id
|
||||
let mut feature_set = FeatureSet::default();
|
||||
assert!(feature_set.full_inflation_features_enabled().is_empty());
|
||||
feature_set
|
||||
.active
|
||||
.insert(full_inflation::candidate_example::vote::id(), 42);
|
||||
assert!(feature_set.full_inflation_features_enabled().is_empty());
|
||||
feature_set
|
||||
.active
|
||||
.insert(full_inflation::candidate_example::enable::id(), 42);
|
||||
assert_eq!(
|
||||
feature_set.full_inflation_features_enabled(),
|
||||
[full_inflation::candidate_example::enable::id()]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect()
|
||||
);
|
||||
|
||||
// Backwards sequence: enable_id and then vote_id
|
||||
let mut feature_set = FeatureSet::default();
|
||||
assert!(feature_set.full_inflation_features_enabled().is_empty());
|
||||
feature_set
|
||||
.active
|
||||
.insert(full_inflation::candidate_example::enable::id(), 42);
|
||||
assert!(feature_set.full_inflation_features_enabled().is_empty());
|
||||
feature_set
|
||||
.active
|
||||
.insert(full_inflation::candidate_example::vote::id(), 42);
|
||||
assert_eq!(
|
||||
feature_set.full_inflation_features_enabled(),
|
||||
[full_inflation::candidate_example::enable::id()]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue