diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index 2216219ae..8411d7773 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -142,6 +142,7 @@ use { rent::RentDue, rent_collector::{CollectedInfo, RentCollector, RENT_EXEMPT_RENT_EPOCH}, rent_debits::RentDebits, + reserved_account_keys::ReservedAccountKeys, reward_info::RewardInfo, saturating_add_assign, signature::{Keypair, Signature}, @@ -563,6 +564,7 @@ impl PartialEq for Bank { transaction_log_collector_config: _, transaction_log_collector: _, feature_set: _, + reserved_account_keys: _, drop_callback: _, freeze_started: _, vote_only_bank: _, @@ -783,6 +785,9 @@ pub struct Bank { pub feature_set: Arc, + /// Set of reserved account keys that cannot be write locked + reserved_account_keys: Arc, + /// callback function only to be called when dropping and should only be called once pub drop_callback: RwLock, @@ -929,6 +934,7 @@ impl Bank { ), transaction_log_collector: Arc::>::default(), feature_set: Arc::::default(), + reserved_account_keys: Arc::::default(), drop_callback: RwLock::new(OptionalDropCallback(None)), freeze_started: AtomicBool::default(), vote_only_bank: false, @@ -1179,6 +1185,7 @@ impl Bank { transaction_log_collector_config, transaction_log_collector: Arc::new(RwLock::new(TransactionLogCollector::default())), feature_set: Arc::clone(&feature_set), + reserved_account_keys: parent.reserved_account_keys.clone(), drop_callback: RwLock::new(OptionalDropCallback( parent .drop_callback @@ -1639,6 +1646,7 @@ impl Bank { ), transaction_log_collector: Arc::>::default(), feature_set: Arc::::default(), + reserved_account_keys: Arc::::default(), drop_callback: RwLock::new(OptionalDropCallback(None)), freeze_started: AtomicBool::new(fields.hash != Hash::default()), vote_only_bank: false, @@ -6502,6 +6510,12 @@ impl Bank { } } + /// Get a set of all actively reserved account keys that are not allowed to + /// be write-locked during transaction processing. + pub fn get_reserved_account_keys(&self) -> &HashSet { + &self.reserved_account_keys.active + } + // This is called from snapshot restore AND for each epoch boundary // The entire code path herein must be idempotent fn apply_feature_activations( @@ -6532,6 +6546,13 @@ impl Bank { } } + // Update active set of reserved account keys which are not allowed to be write locked + self.reserved_account_keys = { + let mut reserved_keys = ReservedAccountKeys::clone(&self.reserved_account_keys); + reserved_keys.update_active_set(&self.feature_set); + Arc::new(reserved_keys) + }; + if new_feature_activations.contains(&feature_set::pico_inflation::id()) { *self.inflation.write().unwrap() = Inflation::pico(); self.fee_rate_governor.burn_percent = 50; // 50% fee burn diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index f472ac0a9..02c889d4b 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -7952,6 +7952,32 @@ fn test_compute_active_feature_set() { assert!(feature_set.is_active(&test_feature)); } +#[test] +fn test_reserved_account_keys() { + let bank0 = create_simple_test_arc_bank(100_000).0; + let mut bank = Bank::new_from_parent(bank0, &Pubkey::default(), 1); + bank.feature_set = Arc::new(FeatureSet::default()); + + assert_eq!( + bank.get_reserved_account_keys().len(), + 20, + "before activating the new feature, bank should already have active reserved keys" + ); + + // Activate `add_new_reserved_account_keys` feature + bank.store_account( + &feature_set::add_new_reserved_account_keys::id(), + &feature::create_account(&Feature::default(), 42), + ); + bank.apply_feature_activations(ApplyFeatureActivationsCaller::NewFromParent, true); + + assert_eq!( + bank.get_reserved_account_keys().len(), + 29, + "after activating the new feature, bank should have new active reserved keys" + ); +} + #[test] fn test_program_replacement() { let mut bank = create_simple_test_bank(0); diff --git a/sdk/src/reserved_account_keys.rs b/sdk/src/reserved_account_keys.rs index 2102949b2..37867ff9d 100644 --- a/sdk/src/reserved_account_keys.rs +++ b/sdk/src/reserved_account_keys.rs @@ -22,6 +22,16 @@ mod zk_token_proof_program { solana_sdk::declare_id!("ZkTokenProof1111111111111111111111111111111"); } +// ReservedAccountKeys is not serialized into or deserialized from bank +// snapshots but the bank requires this trait to be implemented anyways. +#[cfg(RUSTC_WITH_SPECIALIZATION)] +impl ::solana_frozen_abi::abi_example::AbiExample for ReservedAccountKeys { + fn example() -> Self { + // ReservedAccountKeys is not Serialize so just rely on Default. + ReservedAccountKeys::default() + } +} + /// `ReservedAccountKeys` holds the set of currently active/inactive /// account keys that are reserved by the protocol and may not be write-locked /// during transaction processing.