Cleanup activated rent_for_sysvars feature (#22454)
This commit is contained in:
parent
ae6c511f13
commit
cddab635ff
|
@ -253,7 +253,6 @@ impl Accounts {
|
||||||
let mut accounts = Vec::with_capacity(message.account_keys_len());
|
let mut accounts = Vec::with_capacity(message.account_keys_len());
|
||||||
let mut account_deps = Vec::with_capacity(message.account_keys_len());
|
let mut account_deps = Vec::with_capacity(message.account_keys_len());
|
||||||
let mut rent_debits = RentDebits::default();
|
let mut rent_debits = RentDebits::default();
|
||||||
let rent_for_sysvars = feature_set.is_active(&feature_set::rent_for_sysvars::id());
|
|
||||||
for (i, key) in message.account_keys_iter().enumerate() {
|
for (i, key) in message.account_keys_iter().enumerate() {
|
||||||
let account = if !message.is_non_loader_key(i) {
|
let account = if !message.is_non_loader_key(i) {
|
||||||
// Fill in an empty account for the program slots.
|
// Fill in an empty account for the program slots.
|
||||||
|
@ -279,7 +278,6 @@ impl Accounts {
|
||||||
.collect_from_existing_account(
|
.collect_from_existing_account(
|
||||||
key,
|
key,
|
||||||
&mut account,
|
&mut account,
|
||||||
rent_for_sysvars,
|
|
||||||
self.accounts_db.filler_account_suffix.as_ref(),
|
self.accounts_db.filler_account_suffix.as_ref(),
|
||||||
)
|
)
|
||||||
.rent_amount;
|
.rent_amount;
|
||||||
|
@ -1105,7 +1103,6 @@ impl Accounts {
|
||||||
rent_collector: &RentCollector,
|
rent_collector: &RentCollector,
|
||||||
blockhash: &Hash,
|
blockhash: &Hash,
|
||||||
lamports_per_signature: u64,
|
lamports_per_signature: u64,
|
||||||
rent_for_sysvars: bool,
|
|
||||||
leave_nonce_on_success: bool,
|
leave_nonce_on_success: bool,
|
||||||
) {
|
) {
|
||||||
let accounts_to_store = self.collect_accounts_to_store(
|
let accounts_to_store = self.collect_accounts_to_store(
|
||||||
|
@ -1115,7 +1112,6 @@ impl Accounts {
|
||||||
rent_collector,
|
rent_collector,
|
||||||
blockhash,
|
blockhash,
|
||||||
lamports_per_signature,
|
lamports_per_signature,
|
||||||
rent_for_sysvars,
|
|
||||||
leave_nonce_on_success,
|
leave_nonce_on_success,
|
||||||
);
|
);
|
||||||
self.accounts_db.store_cached(slot, &accounts_to_store);
|
self.accounts_db.store_cached(slot, &accounts_to_store);
|
||||||
|
@ -1142,7 +1138,6 @@ impl Accounts {
|
||||||
rent_collector: &RentCollector,
|
rent_collector: &RentCollector,
|
||||||
blockhash: &Hash,
|
blockhash: &Hash,
|
||||||
lamports_per_signature: u64,
|
lamports_per_signature: u64,
|
||||||
rent_for_sysvars: bool,
|
|
||||||
leave_nonce_on_success: bool,
|
leave_nonce_on_success: bool,
|
||||||
) -> Vec<(&'a Pubkey, &'a AccountSharedData)> {
|
) -> Vec<(&'a Pubkey, &'a AccountSharedData)> {
|
||||||
let mut accounts = Vec::with_capacity(load_results.len());
|
let mut accounts = Vec::with_capacity(load_results.len());
|
||||||
|
@ -1202,7 +1197,7 @@ impl Accounts {
|
||||||
if execution_status.is_ok() || is_nonce_account || is_fee_payer {
|
if execution_status.is_ok() || is_nonce_account || is_fee_payer {
|
||||||
if account.rent_epoch() == INITIAL_RENT_EPOCH {
|
if account.rent_epoch() == INITIAL_RENT_EPOCH {
|
||||||
let rent = rent_collector
|
let rent = rent_collector
|
||||||
.collect_from_created_account(address, account, rent_for_sysvars)
|
.collect_from_created_account(address, account)
|
||||||
.rent_amount;
|
.rent_amount;
|
||||||
loaded_transaction.rent += rent;
|
loaded_transaction.rent += rent;
|
||||||
loaded_transaction.rent_debits.insert(
|
loaded_transaction.rent_debits.insert(
|
||||||
|
@ -2917,7 +2912,6 @@ mod tests {
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
&Hash::default(),
|
&Hash::default(),
|
||||||
0,
|
0,
|
||||||
true,
|
|
||||||
true, // leave_nonce_on_success
|
true, // leave_nonce_on_success
|
||||||
);
|
);
|
||||||
assert_eq!(collected_accounts.len(), 2);
|
assert_eq!(collected_accounts.len(), 2);
|
||||||
|
@ -3346,7 +3340,6 @@ mod tests {
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
&next_blockhash,
|
&next_blockhash,
|
||||||
0,
|
0,
|
||||||
true,
|
|
||||||
true, // leave_nonce_on_success
|
true, // leave_nonce_on_success
|
||||||
);
|
);
|
||||||
assert_eq!(collected_accounts.len(), 2);
|
assert_eq!(collected_accounts.len(), 2);
|
||||||
|
@ -3456,7 +3449,6 @@ mod tests {
|
||||||
&rent_collector,
|
&rent_collector,
|
||||||
&next_blockhash,
|
&next_blockhash,
|
||||||
0,
|
0,
|
||||||
true,
|
|
||||||
true, // leave_nonce_on_success
|
true, // leave_nonce_on_success
|
||||||
);
|
);
|
||||||
assert_eq!(collected_accounts.len(), 1);
|
assert_eq!(collected_accounts.len(), 1);
|
||||||
|
|
|
@ -6708,7 +6708,7 @@ impl AccountsDb {
|
||||||
accounts_data_len += stored_account.data().len() as u64;
|
accounts_data_len += stored_account.data().len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rent_collector.should_collect_rent(&pubkey, &stored_account, false)
|
if !rent_collector.should_collect_rent(&pubkey, &stored_account)
|
||||||
|| rent_collector.get_rent_due(&stored_account).is_exempt()
|
|| rent_collector.get_rent_due(&stored_account).is_exempt()
|
||||||
{
|
{
|
||||||
num_accounts_rent_exempt += 1;
|
num_accounts_rent_exempt += 1;
|
||||||
|
|
|
@ -1925,34 +1925,15 @@ impl Bank {
|
||||||
where
|
where
|
||||||
F: Fn(&Option<AccountSharedData>) -> AccountSharedData,
|
F: Fn(&Option<AccountSharedData>) -> AccountSharedData,
|
||||||
{
|
{
|
||||||
let old_account = if !self.rent_for_sysvars() {
|
let old_account = self.get_account_with_fixed_root(pubkey);
|
||||||
// This old behavior is being retired for simpler reasoning for the benefits of all.
|
|
||||||
// Specifically, get_sysvar_account_with_fixed_root() doesn't work nicely with eager
|
|
||||||
// rent collection, which becomes significant for sysvars after rent_for_sysvars
|
|
||||||
// activation. That's because get_sysvar_account_with_fixed_root() invocations by both
|
|
||||||
// update_slot_history() and update_recent_blockhashes() ignores any updates
|
|
||||||
// by eager rent collection in this slot.
|
|
||||||
// Also, it turned out that get_sysvar_account_with_fixed_root()'s special
|
|
||||||
// behavior (idempotent) isn't needed to begin with, because we're fairly certain that
|
|
||||||
// we don't call new_from_parent() with same child slot multiple times in the
|
|
||||||
// production code (except after proper handling of duplicate slot dumping)...
|
|
||||||
self.get_sysvar_account_with_fixed_root(pubkey)
|
|
||||||
} else {
|
|
||||||
self.get_account_with_fixed_root(pubkey)
|
|
||||||
};
|
|
||||||
let mut new_account = updater(&old_account);
|
let mut new_account = updater(&old_account);
|
||||||
|
|
||||||
if self.rent_for_sysvars() {
|
// When new sysvar comes into existence (with RENT_UNADJUSTED_INITIAL_BALANCE lamports),
|
||||||
// When new sysvar comes into existence (with RENT_UNADJUSTED_INITIAL_BALANCE lamports),
|
// this code ensures that the sysvar's balance is adjusted to be rent-exempt.
|
||||||
// this code ensures that the sysvar's balance is adjusted to be rent-exempt.
|
//
|
||||||
// Note that all of existing sysvar balances must be adjusted immediately (i.e. reset) upon
|
// More generally, this code always re-calculates for possible sysvar data size change,
|
||||||
// the `rent_for_sysvars` feature activation (ref: reset_all_sysvar_balances).
|
// although there is no such sysvars currently.
|
||||||
//
|
self.adjust_sysvar_balance_for_rent(&mut new_account);
|
||||||
// More generally, this code always re-calculates for possible sysvar data size change,
|
|
||||||
// although there is no such sysvars currently.
|
|
||||||
self.adjust_sysvar_balance_for_rent(&mut new_account);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.store_account_and_update_capitalization(pubkey, &new_account);
|
self.store_account_and_update_capitalization(pubkey, &new_account);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1967,16 +1948,10 @@ impl Bank {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|a| a.lamports())
|
.map(|a| a.lamports())
|
||||||
.unwrap_or(RENT_UNADJUSTED_INITIAL_BALANCE),
|
.unwrap_or(RENT_UNADJUSTED_INITIAL_BALANCE),
|
||||||
if !self.rent_for_sysvars() {
|
old_account
|
||||||
INITIAL_RENT_EPOCH
|
.as_ref()
|
||||||
} else {
|
.map(|a| a.rent_epoch())
|
||||||
// start to inherit rent_epoch updated by rent collection to be consistent with
|
.unwrap_or(INITIAL_RENT_EPOCH),
|
||||||
// other normal accounts
|
|
||||||
old_account
|
|
||||||
.as_ref()
|
|
||||||
.map(|a| a.rent_epoch())
|
|
||||||
.unwrap_or(INITIAL_RENT_EPOCH)
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4155,7 +4130,6 @@ impl Bank {
|
||||||
&self.rent_collector,
|
&self.rent_collector,
|
||||||
&blockhash,
|
&blockhash,
|
||||||
lamports_per_signature,
|
lamports_per_signature,
|
||||||
self.rent_for_sysvars(),
|
|
||||||
self.leave_nonce_on_success(),
|
self.leave_nonce_on_success(),
|
||||||
);
|
);
|
||||||
let rent_debits = self.collect_rent(&execution_results, loaded_txs);
|
let rent_debits = self.collect_rent(&execution_results, loaded_txs);
|
||||||
|
@ -4437,14 +4411,12 @@ impl Bank {
|
||||||
let account_count = accounts.len();
|
let account_count = accounts.len();
|
||||||
|
|
||||||
// parallelize?
|
// parallelize?
|
||||||
let rent_for_sysvars = self.rent_for_sysvars();
|
|
||||||
let mut rent_debits = RentDebits::default();
|
let mut rent_debits = RentDebits::default();
|
||||||
let mut total_collected = CollectedInfo::default();
|
let mut total_collected = CollectedInfo::default();
|
||||||
for (pubkey, mut account) in accounts {
|
for (pubkey, mut account) in accounts {
|
||||||
let collected = self.rent_collector.collect_from_existing_account(
|
let collected = self.rent_collector.collect_from_existing_account(
|
||||||
&pubkey,
|
&pubkey,
|
||||||
&mut account,
|
&mut account,
|
||||||
rent_for_sysvars,
|
|
||||||
self.rc.accounts.accounts_db.filler_account_suffix.as_ref(),
|
self.rc.accounts.accounts_db.filler_account_suffix.as_ref(),
|
||||||
);
|
);
|
||||||
total_collected += collected;
|
total_collected += collected;
|
||||||
|
@ -5312,24 +5284,6 @@ impl Bank {
|
||||||
self.rc.accounts.load_with_fixed_root(ancestors, pubkey)
|
self.rc.accounts.load_with_fixed_root(ancestors, pubkey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude self to really fetch the parent Bank's account hash and data.
|
|
||||||
//
|
|
||||||
// Being idempotent is needed to make the lazy initialization possible,
|
|
||||||
// especially for update_slot_hashes at the moment, which can be called
|
|
||||||
// multiple times with the same parent_slot in the case of forking.
|
|
||||||
//
|
|
||||||
// Generally, all of sysvar update granularity should be slot boundaries.
|
|
||||||
//
|
|
||||||
// This behavior is deprecated... See comment in update_sysvar_account() for details
|
|
||||||
fn get_sysvar_account_with_fixed_root(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
|
|
||||||
let mut ancestors = self.ancestors.clone();
|
|
||||||
ancestors.remove(&self.slot());
|
|
||||||
self.rc
|
|
||||||
.accounts
|
|
||||||
.load_with_fixed_root(&ancestors, pubkey)
|
|
||||||
.map(|(acc, _slot)| acc)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_program_accounts(
|
pub fn get_program_accounts(
|
||||||
&self,
|
&self,
|
||||||
program_id: &Pubkey,
|
program_id: &Pubkey,
|
||||||
|
@ -6173,14 +6127,6 @@ impl Bank {
|
||||||
if new_feature_activations.contains(&feature_set::spl_token_v3_3_0_release::id()) {
|
if new_feature_activations.contains(&feature_set::spl_token_v3_3_0_release::id()) {
|
||||||
self.apply_spl_token_v3_3_0_release();
|
self.apply_spl_token_v3_3_0_release();
|
||||||
}
|
}
|
||||||
if new_feature_activations.contains(&feature_set::rent_for_sysvars::id()) {
|
|
||||||
// when this feature is activated, immediately all of existing sysvars are susceptible
|
|
||||||
// to rent collection and account data removal due to insufficient balance due to only
|
|
||||||
// having 1 lamport.
|
|
||||||
// so before any is accessed, reset the balance to be rent-exempt here at the same
|
|
||||||
// timing when perpetual balance adjustment is started in update_sysvar_account().
|
|
||||||
self.reset_all_sysvar_balances();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !debug_do_not_add_builtins {
|
if !debug_do_not_add_builtins {
|
||||||
self.ensure_feature_builtins(init_finish_or_warp, &new_feature_activations);
|
self.ensure_feature_builtins(init_finish_or_warp, &new_feature_activations);
|
||||||
|
@ -6189,36 +6135,6 @@ impl Bank {
|
||||||
self.ensure_no_storage_rewards_pool();
|
self.ensure_no_storage_rewards_pool();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_all_sysvar_balances(&self) {
|
|
||||||
for sysvar_id in &[
|
|
||||||
sysvar::clock::id(),
|
|
||||||
sysvar::epoch_schedule::id(),
|
|
||||||
#[allow(deprecated)]
|
|
||||||
sysvar::fees::id(),
|
|
||||||
#[allow(deprecated)]
|
|
||||||
sysvar::recent_blockhashes::id(),
|
|
||||||
sysvar::rent::id(),
|
|
||||||
sysvar::rewards::id(),
|
|
||||||
sysvar::slot_hashes::id(),
|
|
||||||
sysvar::slot_history::id(),
|
|
||||||
sysvar::stake_history::id(),
|
|
||||||
] {
|
|
||||||
if let Some(mut account) = self.get_account(sysvar_id) {
|
|
||||||
let (old_data_len, old_lamports) = (account.data().len(), account.lamports());
|
|
||||||
self.adjust_sysvar_balance_for_rent(&mut account);
|
|
||||||
info!(
|
|
||||||
"reset_all_sysvar_balances (slot: {}): {} ({} bytes) is reset from {} to {}",
|
|
||||||
self.slot(),
|
|
||||||
sysvar_id,
|
|
||||||
old_data_len,
|
|
||||||
old_lamports,
|
|
||||||
account.lamports()
|
|
||||||
);
|
|
||||||
self.store_account_and_update_capitalization(sysvar_id, &account);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn adjust_sysvar_balance_for_rent(&self, account: &mut AccountSharedData) {
|
fn adjust_sysvar_balance_for_rent(&self, account: &mut AccountSharedData) {
|
||||||
account.set_lamports(
|
account.set_lamports(
|
||||||
self.get_minimum_balance_for_rent_exemption(account.data().len())
|
self.get_minimum_balance_for_rent_exemption(account.data().len())
|
||||||
|
@ -6405,11 +6321,6 @@ impl Bank {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rent_for_sysvars(&self) -> bool {
|
|
||||||
self.feature_set
|
|
||||||
.is_active(&feature_set::rent_for_sysvars::id())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get all the accounts for this bank and calculate stats
|
/// Get all the accounts for this bank and calculate stats
|
||||||
pub fn get_total_accounts_stats(&self) -> ScanResult<TotalAccountsStats> {
|
pub fn get_total_accounts_stats(&self) -> ScanResult<TotalAccountsStats> {
|
||||||
let accounts = self.get_all_accounts_with_modified_slots()?;
|
let accounts = self.get_all_accounts_with_modified_slots()?;
|
||||||
|
@ -6437,7 +6348,7 @@ impl Bank {
|
||||||
total_accounts_stats.executable_data_len += data_len;
|
total_accounts_stats.executable_data_len += data_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rent_collector.should_collect_rent(pubkey, account, false)
|
if !rent_collector.should_collect_rent(pubkey, account)
|
||||||
|| rent_collector.get_rent_due(account).is_exempt()
|
|| rent_collector.get_rent_due(account).is_exempt()
|
||||||
{
|
{
|
||||||
total_accounts_stats.num_rent_exempt_accounts += 1;
|
total_accounts_stats.num_rent_exempt_accounts += 1;
|
||||||
|
@ -6542,7 +6453,8 @@ pub(crate) mod tests {
|
||||||
genesis_utils::{
|
genesis_utils::{
|
||||||
activate_all_features, bootstrap_validator_stake_lamports,
|
activate_all_features, bootstrap_validator_stake_lamports,
|
||||||
create_genesis_config_with_leader, create_genesis_config_with_vote_accounts,
|
create_genesis_config_with_leader, create_genesis_config_with_vote_accounts,
|
||||||
GenesisConfigInfo, ValidatorVoteKeypairs,
|
genesis_sysvar_and_builtin_program_lamports, GenesisConfigInfo,
|
||||||
|
ValidatorVoteKeypairs,
|
||||||
},
|
},
|
||||||
stake_delegations::StakeDelegations,
|
stake_delegations::StakeDelegations,
|
||||||
status_cache::MAX_CACHE_ENTRIES,
|
status_cache::MAX_CACHE_ENTRIES,
|
||||||
|
@ -6873,6 +6785,21 @@ pub(crate) mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bank0_sysvar_delta() -> u64 {
|
||||||
|
const SLOT_HISTORY_SYSVAR_MIN_BALANCE: u64 = 913_326_000;
|
||||||
|
SLOT_HISTORY_SYSVAR_MIN_BALANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bank1_sysvar_delta() -> u64 {
|
||||||
|
const SLOT_HASHES_SYSVAR_MIN_BALANCE: u64 = 143_487_360;
|
||||||
|
SLOT_HASHES_SYSVAR_MIN_BALANCE
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_epoch_sysvar_delta() -> u64 {
|
||||||
|
const REWARDS_SYSVAR_MIN_BALANCE: u64 = 1_002_240;
|
||||||
|
REWARDS_SYSVAR_MIN_BALANCE
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bank_capitalization() {
|
fn test_bank_capitalization() {
|
||||||
let bank0 = Arc::new(Bank::new_for_tests(&GenesisConfig {
|
let bank0 = Arc::new(Bank::new_for_tests(&GenesisConfig {
|
||||||
|
@ -6887,16 +6814,26 @@ pub(crate) mod tests {
|
||||||
cluster_type: ClusterType::MainnetBeta,
|
cluster_type: ClusterType::MainnetBeta,
|
||||||
..GenesisConfig::default()
|
..GenesisConfig::default()
|
||||||
}));
|
}));
|
||||||
let sysvar_and_builtin_program_delta0 = 11;
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank0.capitalization(),
|
bank0.capitalization(),
|
||||||
42 * 42 + sysvar_and_builtin_program_delta0
|
42 * 42 + genesis_sysvar_and_builtin_program_lamports(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
bank0.freeze();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
bank0.capitalization(),
|
||||||
|
42 * 42 + genesis_sysvar_and_builtin_program_lamports() + bank0_sysvar_delta(),
|
||||||
|
);
|
||||||
|
|
||||||
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
let bank1 = Bank::new_from_parent(&bank0, &Pubkey::default(), 1);
|
||||||
let sysvar_and_builtin_program_delta1 = 2;
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank1.capitalization(),
|
bank1.capitalization(),
|
||||||
42 * 42 + sysvar_and_builtin_program_delta0 + sysvar_and_builtin_program_delta1,
|
42 * 42
|
||||||
|
+ genesis_sysvar_and_builtin_program_lamports()
|
||||||
|
+ bank0_sysvar_delta()
|
||||||
|
+ bank1_sysvar_delta(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7131,19 +7068,6 @@ pub(crate) mod tests {
|
||||||
assert_eq!(bank.capitalization(), bank.calculate_capitalization(true));
|
assert_eq!(bank.capitalization(), bank.calculate_capitalization(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_capitalization_diff_with_new_bank(
|
|
||||||
bank: &Bank,
|
|
||||||
updater: impl Fn() -> Bank,
|
|
||||||
asserter: impl Fn(u64, u64),
|
|
||||||
) -> Bank {
|
|
||||||
let old = bank.capitalization();
|
|
||||||
let bank = updater();
|
|
||||||
let new = bank.capitalization();
|
|
||||||
asserter(old, new);
|
|
||||||
assert_eq!(bank.capitalization(), bank.calculate_capitalization(true));
|
|
||||||
bank
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_store_account_and_update_capitalization_missing() {
|
fn test_store_account_and_update_capitalization_missing() {
|
||||||
let (genesis_config, _mint_keypair) = create_genesis_config(0);
|
let (genesis_config, _mint_keypair) = create_genesis_config(0);
|
||||||
|
@ -8430,18 +8354,13 @@ pub(crate) mod tests {
|
||||||
.map(|(slot, _)| *slot)
|
.map(|(slot, _)| *slot)
|
||||||
.collect::<Vec<Slot>>()
|
.collect::<Vec<Slot>>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn first_slot_in_next_epoch(&self) -> Slot {
|
|
||||||
self.epoch_schedule()
|
|
||||||
.get_first_slot_in_epoch(self.epoch() + 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rent_eager_collect_rent_in_partition() {
|
fn test_rent_eager_collect_rent_in_partition() {
|
||||||
solana_logger::setup();
|
solana_logger::setup();
|
||||||
|
|
||||||
let (mut genesis_config, _mint_keypair) = create_genesis_config(1);
|
let (mut genesis_config, _mint_keypair) = create_genesis_config(1_000_000);
|
||||||
activate_all_features(&mut genesis_config);
|
activate_all_features(&mut genesis_config);
|
||||||
|
|
||||||
let zero_lamport_pubkey = solana_sdk::pubkey::new_rand();
|
let zero_lamport_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
|
@ -8494,8 +8413,7 @@ pub(crate) mod tests {
|
||||||
|
|
||||||
bank.collect_rent_in_partition((0, 0, 1)); // all range
|
bank.collect_rent_in_partition((0, 0, 1)); // all range
|
||||||
|
|
||||||
// unrelated 1-lamport accounts exists
|
assert_eq!(bank.collected_rent.load(Relaxed), rent_collected);
|
||||||
assert_eq!(bank.collected_rent.load(Relaxed), rent_collected + 2);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.get_account(&rent_due_pubkey).unwrap().lamports(),
|
bank.get_account(&rent_due_pubkey).unwrap().lamports(),
|
||||||
little_lamports - rent_collected
|
little_lamports - rent_collected
|
||||||
|
@ -8616,15 +8534,14 @@ pub(crate) mod tests {
|
||||||
// not being eagerly-collected for exact rewards calculation
|
// not being eagerly-collected for exact rewards calculation
|
||||||
bank0.restore_old_behavior_for_fragile_tests();
|
bank0.restore_old_behavior_for_fragile_tests();
|
||||||
|
|
||||||
let sysvar_and_builtin_program_delta0 = 11;
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank0.capitalization(),
|
bank0.capitalization(),
|
||||||
42 * 1_000_000_000 + sysvar_and_builtin_program_delta0
|
42 * 1_000_000_000 + genesis_sysvar_and_builtin_program_lamports(),
|
||||||
);
|
);
|
||||||
assert!(bank0.rewards.read().unwrap().is_empty());
|
|
||||||
|
|
||||||
let ((vote_id, mut vote_account), (stake_id, stake_account)) =
|
let ((vote_id, mut vote_account), (stake_id, stake_account)) =
|
||||||
crate::stakes::tests::create_staked_node_accounts(1_0000);
|
crate::stakes::tests::create_staked_node_accounts(10_000);
|
||||||
|
let starting_vote_and_stake_balance = 10_000 + 1;
|
||||||
|
|
||||||
// set up accounts
|
// set up accounts
|
||||||
bank0.store_account_and_update_capitalization(&stake_id, &stake_account);
|
bank0.store_account_and_update_capitalization(&stake_id, &stake_account);
|
||||||
|
@ -8646,6 +8563,16 @@ pub(crate) mod tests {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
bank0.store_account_and_update_capitalization(&vote_id, &vote_account);
|
bank0.store_account_and_update_capitalization(&vote_id, &vote_account);
|
||||||
|
bank0.freeze();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
bank0.capitalization(),
|
||||||
|
42 * 1_000_000_000
|
||||||
|
+ genesis_sysvar_and_builtin_program_lamports()
|
||||||
|
+ starting_vote_and_stake_balance
|
||||||
|
+ bank0_sysvar_delta(),
|
||||||
|
);
|
||||||
|
assert!(bank0.rewards.read().unwrap().is_empty());
|
||||||
|
|
||||||
let thread_pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
let thread_pool = ThreadPoolBuilder::new().num_threads(1).build().unwrap();
|
||||||
let validator_points: u128 = bank0
|
let validator_points: u128 = bank0
|
||||||
|
@ -8682,9 +8609,10 @@ pub(crate) mod tests {
|
||||||
assert_ne!(bank1.capitalization(), bank0.capitalization());
|
assert_ne!(bank1.capitalization(), bank0.capitalization());
|
||||||
|
|
||||||
// verify the inflation is represented in validator_points *
|
// verify the inflation is represented in validator_points *
|
||||||
let sysvar_and_builtin_program_delta1 = 2;
|
let paid_rewards = bank1.capitalization()
|
||||||
let paid_rewards =
|
- bank0.capitalization()
|
||||||
bank1.capitalization() - bank0.capitalization() - sysvar_and_builtin_program_delta1;
|
- bank1_sysvar_delta()
|
||||||
|
- new_epoch_sysvar_delta();
|
||||||
|
|
||||||
let rewards = bank1
|
let rewards = bank1
|
||||||
.get_account(&sysvar::rewards::id())
|
.get_account(&sysvar::rewards::id())
|
||||||
|
@ -8751,12 +8679,10 @@ pub(crate) mod tests {
|
||||||
// not being eagerly-collected for exact rewards calculation
|
// not being eagerly-collected for exact rewards calculation
|
||||||
bank.restore_old_behavior_for_fragile_tests();
|
bank.restore_old_behavior_for_fragile_tests();
|
||||||
|
|
||||||
let sysvar_and_builtin_program_delta = 11;
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.capitalization(),
|
bank.capitalization(),
|
||||||
42 * 1_000_000_000 + sysvar_and_builtin_program_delta
|
42 * 1_000_000_000 + genesis_sysvar_and_builtin_program_lamports()
|
||||||
);
|
);
|
||||||
assert!(bank.rewards.read().unwrap().is_empty());
|
|
||||||
|
|
||||||
let vote_id = solana_sdk::pubkey::new_rand();
|
let vote_id = solana_sdk::pubkey::new_rand();
|
||||||
let mut vote_account =
|
let mut vote_account =
|
||||||
|
@ -9059,17 +8985,17 @@ pub(crate) mod tests {
|
||||||
let normal_pubkey = solana_sdk::pubkey::new_rand();
|
let normal_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
let sysvar_pubkey = sysvar::clock::id();
|
let sysvar_pubkey = sysvar::clock::id();
|
||||||
assert_eq!(bank.get_balance(&normal_pubkey), 0);
|
assert_eq!(bank.get_balance(&normal_pubkey), 0);
|
||||||
assert_eq!(bank.get_balance(&sysvar_pubkey), 1);
|
assert_eq!(bank.get_balance(&sysvar_pubkey), 1_169_280);
|
||||||
|
|
||||||
bank.transfer(500, &mint_keypair, &normal_pubkey).unwrap();
|
bank.transfer(500, &mint_keypair, &normal_pubkey).unwrap();
|
||||||
bank.transfer(500, &mint_keypair, &sysvar_pubkey)
|
bank.transfer(500, &mint_keypair, &sysvar_pubkey)
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(bank.get_balance(&normal_pubkey), 500);
|
assert_eq!(bank.get_balance(&normal_pubkey), 500);
|
||||||
assert_eq!(bank.get_balance(&sysvar_pubkey), 1);
|
assert_eq!(bank.get_balance(&sysvar_pubkey), 1_169_280);
|
||||||
|
|
||||||
let bank = Arc::new(new_from_parent(&bank));
|
let bank = Arc::new(new_from_parent(&bank));
|
||||||
assert_eq!(bank.get_balance(&normal_pubkey), 500);
|
assert_eq!(bank.get_balance(&normal_pubkey), 500);
|
||||||
assert_eq!(bank.get_balance(&sysvar_pubkey), 1);
|
assert_eq!(bank.get_balance(&sysvar_pubkey), 1_169_280);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -10112,8 +10038,6 @@ pub(crate) mod tests {
|
||||||
expected_next_slot,
|
expected_next_slot,
|
||||||
from_account::<Clock, _>(¤t_account).unwrap().slot
|
from_account::<Clock, _>(¤t_account).unwrap().slot
|
||||||
);
|
);
|
||||||
// inherit_specially_retained_account_fields() now starts to inherit rent_epoch too
|
|
||||||
// with rent_for_sysvars
|
|
||||||
assert_eq!(dummy_rent_epoch, current_account.rent_epoch());
|
assert_eq!(dummy_rent_epoch, current_account.rent_epoch());
|
||||||
},
|
},
|
||||||
|old, new| {
|
|old, new| {
|
||||||
|
@ -12256,25 +12180,25 @@ pub(crate) mod tests {
|
||||||
if bank.slot == 0 {
|
if bank.slot == 0 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"DqaWg7EVKzb5Fpe92zNBtXAWqLwcedgHDicYrCBnf3QK"
|
"2VLeMNvmpPEDy7sWw48gUVzjMa3WmgoegjavyhLTCnq7"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if bank.slot == 32 {
|
if bank.slot == 32 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"AYdhzhKrM74r9XuZBDGcHeFzg2DEtp1boggnEnzDjZSq"
|
"AYnKo6pV8WJy5yXiSkYk79LWnCUCG714fQG7Xq2EizLv"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if bank.slot == 64 {
|
if bank.slot == 64 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"EsbPVYzo1qz5reEUH5okKW4ExB6WbcidkVdW5mzpFn7C"
|
"37iX2uYecqAzxwyeWL8FCFeWg31B8u9hQhCRF76atrWy"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if bank.slot == 128 {
|
if bank.slot == 128 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.hash().to_string(),
|
bank.hash().to_string(),
|
||||||
"H3DWrQ6FqbLkFNDxbWQ62UKRbw2dbuxf3oVF2VpBk6Ga"
|
"4TDaCAvTJJg1YZ6aDhoM33Hk2cDzaraaxtGMJCmXG4wf"
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -13388,15 +13312,11 @@ pub(crate) mod tests {
|
||||||
.sum()
|
.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_cap_delta_after_sysvar_reset(bank: &Bank, sysvar_ids: &[Pubkey]) -> u64 {
|
|
||||||
min_rent_excempt_balance_for_sysvars(bank, sysvar_ids) - sysvar_ids.len() as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_adjust_sysvar_balance_for_rent() {
|
fn test_adjust_sysvar_balance_for_rent() {
|
||||||
let (genesis_config, _mint_keypair) = create_genesis_config(0);
|
let (genesis_config, _mint_keypair) = create_genesis_config(0);
|
||||||
let bank = Bank::new_for_tests(&genesis_config);
|
let bank = Bank::new_for_tests(&genesis_config);
|
||||||
let mut smaller_sample_sysvar = bank.get_account(&sysvar::clock::id()).unwrap();
|
let mut smaller_sample_sysvar = AccountSharedData::new(1, 0, &Pubkey::default());
|
||||||
assert_eq!(smaller_sample_sysvar.lamports(), 1);
|
assert_eq!(smaller_sample_sysvar.lamports(), 1);
|
||||||
bank.adjust_sysvar_balance_for_rent(&mut smaller_sample_sysvar);
|
bank.adjust_sysvar_balance_for_rent(&mut smaller_sample_sysvar);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -13419,245 +13339,6 @@ pub(crate) mod tests {
|
||||||
assert_eq!(smaller_sample_sysvar.lamports(), excess_lamports);
|
assert_eq!(smaller_sample_sysvar.lamports(), excess_lamports);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this test can be removed after rent_for_sysvars activation on mainnet-beta
|
|
||||||
#[test]
|
|
||||||
fn test_no_deletion_due_to_rent_upon_rent_for_sysvar_activation() {
|
|
||||||
solana_logger::setup();
|
|
||||||
|
|
||||||
let (mut genesis_config, _mint_keypair) = create_genesis_config(0);
|
|
||||||
let feature_balance =
|
|
||||||
std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1);
|
|
||||||
|
|
||||||
// activate all features but rent_for_sysvars
|
|
||||||
activate_all_features(&mut genesis_config);
|
|
||||||
genesis_config
|
|
||||||
.accounts
|
|
||||||
.remove(&feature_set::rent_for_sysvars::id());
|
|
||||||
let bank0 = Bank::new_for_tests(&genesis_config);
|
|
||||||
let bank1 = Arc::new(new_from_parent(&Arc::new(bank0)));
|
|
||||||
|
|
||||||
// schedule activation of simple capitalization
|
|
||||||
bank1.store_account_and_update_capitalization(
|
|
||||||
&feature_set::rent_for_sysvars::id(),
|
|
||||||
&feature::create_account(&Feature { activated_at: None }, feature_balance),
|
|
||||||
);
|
|
||||||
|
|
||||||
let bank2 =
|
|
||||||
Bank::new_from_parent(&bank1, &Pubkey::default(), bank1.first_slot_in_next_epoch());
|
|
||||||
assert_eq!(
|
|
||||||
bank2
|
|
||||||
.get_program_accounts(&sysvar::id(), &ScanConfig::default(),)
|
|
||||||
.unwrap()
|
|
||||||
.len(),
|
|
||||||
8
|
|
||||||
);
|
|
||||||
|
|
||||||
// force rent collection for sysvars
|
|
||||||
bank2.collect_rent_in_partition((0, 0, 1)); // all range
|
|
||||||
|
|
||||||
// no sysvar should be deleted due to rent
|
|
||||||
assert_eq!(
|
|
||||||
bank2
|
|
||||||
.get_program_accounts(&sysvar::id(), &ScanConfig::default(),)
|
|
||||||
.unwrap()
|
|
||||||
.len(),
|
|
||||||
8
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this test can be removed after rent_for_sysvars activation on mainnet-beta
|
|
||||||
#[test]
|
|
||||||
fn test_rent_for_sysvars_adjustment_minimum_genesis_set() {
|
|
||||||
solana_logger::setup();
|
|
||||||
|
|
||||||
let (mut genesis_config, _mint_keypair) = create_genesis_config(0);
|
|
||||||
let feature_balance =
|
|
||||||
std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1);
|
|
||||||
|
|
||||||
// inhibit deprecated rewards sysvar creation altogether
|
|
||||||
genesis_config.accounts.insert(
|
|
||||||
feature_set::deprecate_rewards_sysvar::id(),
|
|
||||||
Account::from(feature::create_account(
|
|
||||||
&Feature {
|
|
||||||
activated_at: Some(0),
|
|
||||||
},
|
|
||||||
feature_balance,
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let bank0 = Bank::new_for_tests(&genesis_config);
|
|
||||||
let bank1 = Arc::new(new_from_parent(&Arc::new(bank0)));
|
|
||||||
|
|
||||||
// schedule activation of rent_for_sysvars
|
|
||||||
bank1.store_account_and_update_capitalization(
|
|
||||||
&feature_set::rent_for_sysvars::id(),
|
|
||||||
&feature::create_account(&Feature { activated_at: None }, feature_balance),
|
|
||||||
);
|
|
||||||
|
|
||||||
{
|
|
||||||
let sysvars = bank1
|
|
||||||
.get_program_accounts(&sysvar::id(), &ScanConfig::default())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(sysvars.len(), 8);
|
|
||||||
assert!(sysvars
|
|
||||||
.iter()
|
|
||||||
.map(|(_pubkey, account)| account.lamports())
|
|
||||||
.all(|lamports| lamports == 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 8 sysvars should be reset by reset_all_sysvar_balances()
|
|
||||||
let bank2 = assert_capitalization_diff_with_new_bank(
|
|
||||||
&bank1,
|
|
||||||
|| Bank::new_from_parent(&bank1, &Pubkey::default(), bank1.first_slot_in_next_epoch()),
|
|
||||||
|old, new| {
|
|
||||||
assert_eq!(
|
|
||||||
old + expected_cap_delta_after_sysvar_reset(
|
|
||||||
&bank1,
|
|
||||||
&[
|
|
||||||
sysvar::clock::id(),
|
|
||||||
sysvar::epoch_schedule::id(),
|
|
||||||
#[allow(deprecated)]
|
|
||||||
sysvar::fees::id(),
|
|
||||||
#[allow(deprecated)]
|
|
||||||
sysvar::recent_blockhashes::id(),
|
|
||||||
sysvar::rent::id(),
|
|
||||||
sysvar::slot_hashes::id(),
|
|
||||||
sysvar::slot_history::id(),
|
|
||||||
sysvar::stake_history::id(),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
new
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
{
|
|
||||||
let sysvars = bank2
|
|
||||||
.get_program_accounts(&sysvar::id(), &ScanConfig::default())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(sysvars.len(), 8);
|
|
||||||
assert!(sysvars
|
|
||||||
.iter()
|
|
||||||
.map(|(_pubkey, account)| account.lamports())
|
|
||||||
.all(|lamports| lamports > 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this test can be removed after rent_for_sysvars activation on mainnet-beta
|
|
||||||
#[test]
|
|
||||||
fn test_rent_for_sysvars_adjustment_full_set() {
|
|
||||||
solana_logger::setup();
|
|
||||||
|
|
||||||
let (mut genesis_config, _mint_keypair) = create_genesis_config(0);
|
|
||||||
let feature_balance =
|
|
||||||
std::cmp::max(genesis_config.rent.minimum_balance(Feature::size_of()), 1);
|
|
||||||
|
|
||||||
// activate all features but rent_for_sysvars
|
|
||||||
activate_all_features(&mut genesis_config);
|
|
||||||
genesis_config
|
|
||||||
.accounts
|
|
||||||
.remove(&feature_set::rent_for_sysvars::id());
|
|
||||||
// intentionally create deprecated rewards sysvar creation
|
|
||||||
genesis_config
|
|
||||||
.accounts
|
|
||||||
.remove(&feature_set::deprecate_rewards_sysvar::id());
|
|
||||||
|
|
||||||
// intentionally create bogus builtin programs
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
|
||||||
fn mock_process_instruction(
|
|
||||||
_first_instruction_account: usize,
|
|
||||||
_data: &[u8],
|
|
||||||
_invoke_context: &mut InvokeContext,
|
|
||||||
) -> std::result::Result<(), solana_sdk::instruction::InstructionError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
let builtins = Builtins {
|
|
||||||
genesis_builtins: vec![
|
|
||||||
Builtin::new(
|
|
||||||
"mock bpf",
|
|
||||||
solana_sdk::bpf_loader::id(),
|
|
||||||
mock_process_instruction,
|
|
||||||
),
|
|
||||||
Builtin::new(
|
|
||||||
"mock bpf",
|
|
||||||
solana_sdk::bpf_loader_deprecated::id(),
|
|
||||||
mock_process_instruction,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
feature_builtins: (vec![]),
|
|
||||||
};
|
|
||||||
|
|
||||||
let bank0 = Arc::new(Bank::new_with_paths_for_tests(
|
|
||||||
&genesis_config,
|
|
||||||
Vec::new(),
|
|
||||||
None,
|
|
||||||
Some(&builtins),
|
|
||||||
AccountSecondaryIndexes::default(),
|
|
||||||
false,
|
|
||||||
AccountShrinkThreshold::default(),
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
// move to next epoch to create now deprecated rewards sysvar intentionally
|
|
||||||
let bank1 = Arc::new(Bank::new_from_parent(
|
|
||||||
&bank0,
|
|
||||||
&Pubkey::default(),
|
|
||||||
bank0.first_slot_in_next_epoch(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// schedule activation of simple capitalization
|
|
||||||
bank1.store_account_and_update_capitalization(
|
|
||||||
&feature_set::rent_for_sysvars::id(),
|
|
||||||
&feature::create_account(&Feature { activated_at: None }, feature_balance),
|
|
||||||
);
|
|
||||||
{
|
|
||||||
let sysvars = bank1
|
|
||||||
.get_program_accounts(&sysvar::id(), &ScanConfig::default())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(sysvars.len(), 9);
|
|
||||||
assert!(sysvars
|
|
||||||
.iter()
|
|
||||||
.map(|(_pubkey, account)| account.lamports())
|
|
||||||
.all(|lamports| lamports == 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 9 sysvars should be reset by reset_all_sysvar_balances()
|
|
||||||
let bank2 = assert_capitalization_diff_with_new_bank(
|
|
||||||
&bank1,
|
|
||||||
|| Bank::new_from_parent(&bank1, &Pubkey::default(), bank1.first_slot_in_next_epoch()),
|
|
||||||
|old, new| {
|
|
||||||
assert_eq!(
|
|
||||||
old + expected_cap_delta_after_sysvar_reset(
|
|
||||||
&bank1,
|
|
||||||
&[
|
|
||||||
sysvar::clock::id(),
|
|
||||||
sysvar::epoch_schedule::id(),
|
|
||||||
#[allow(deprecated)]
|
|
||||||
sysvar::fees::id(),
|
|
||||||
#[allow(deprecated)]
|
|
||||||
sysvar::recent_blockhashes::id(),
|
|
||||||
sysvar::rent::id(),
|
|
||||||
sysvar::rewards::id(),
|
|
||||||
sysvar::slot_hashes::id(),
|
|
||||||
sysvar::slot_history::id(),
|
|
||||||
sysvar::stake_history::id(),
|
|
||||||
]
|
|
||||||
),
|
|
||||||
new
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
{
|
|
||||||
let sysvars = bank2
|
|
||||||
.get_program_accounts(&sysvar::id(), &ScanConfig::default())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(sysvars.len(), 9);
|
|
||||||
assert!(sysvars
|
|
||||||
.iter()
|
|
||||||
.map(|(_pubkey, account)| account.lamports())
|
|
||||||
.all(|lamports| lamports > 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_update_clock_timestamp() {
|
fn test_update_clock_timestamp() {
|
||||||
let leader_pubkey = solana_sdk::pubkey::new_rand();
|
let leader_pubkey = solana_sdk::pubkey::new_rand();
|
||||||
|
|
|
@ -24,6 +24,25 @@ pub fn bootstrap_validator_stake_lamports() -> u64 {
|
||||||
StakeState::get_rent_exempt_reserve(&Rent::default())
|
StakeState::get_rent_exempt_reserve(&Rent::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Number of lamports automatically used for genesis accounts
|
||||||
|
pub const fn genesis_sysvar_and_builtin_program_lamports() -> u64 {
|
||||||
|
const NUM_BUILTIN_PROGRAMS: u64 = 5;
|
||||||
|
const FEES_SYSVAR_MIN_BALANCE: u64 = 946_560;
|
||||||
|
const STAKE_HISTORY_MIN_BALANCE: u64 = 114_979_200;
|
||||||
|
const CLOCK_SYSVAR_MIN_BALANCE: u64 = 1_169_280;
|
||||||
|
const RENT_SYSVAR_MIN_BALANCE: u64 = 1_009_200;
|
||||||
|
const EPOCH_SCHEDULE_SYSVAR_MIN_BALANCE: u64 = 1_120_560;
|
||||||
|
const RECENT_BLOCKHASHES_SYSVAR_MIN_BALANCE: u64 = 42_706_560;
|
||||||
|
|
||||||
|
FEES_SYSVAR_MIN_BALANCE
|
||||||
|
+ STAKE_HISTORY_MIN_BALANCE
|
||||||
|
+ CLOCK_SYSVAR_MIN_BALANCE
|
||||||
|
+ RENT_SYSVAR_MIN_BALANCE
|
||||||
|
+ EPOCH_SCHEDULE_SYSVAR_MIN_BALANCE
|
||||||
|
+ RECENT_BLOCKHASHES_SYSVAR_MIN_BALANCE
|
||||||
|
+ NUM_BUILTIN_PROGRAMS
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ValidatorVoteKeypairs {
|
pub struct ValidatorVoteKeypairs {
|
||||||
pub node_keypair: Keypair,
|
pub node_keypair: Keypair,
|
||||||
pub vote_keypair: Keypair,
|
pub vote_keypair: Keypair,
|
||||||
|
|
|
@ -219,6 +219,7 @@ solana_sdk::pubkeys!(
|
||||||
mod tests {
|
mod tests {
|
||||||
use {
|
use {
|
||||||
super::*,
|
super::*,
|
||||||
|
crate::genesis_utils::genesis_sysvar_and_builtin_program_lamports,
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{Account, AccountSharedData},
|
account::{Account, AccountSharedData},
|
||||||
epoch_schedule::EpochSchedule,
|
epoch_schedule::EpochSchedule,
|
||||||
|
@ -278,11 +279,10 @@ mod tests {
|
||||||
..GenesisConfig::default()
|
..GenesisConfig::default()
|
||||||
};
|
};
|
||||||
let mut bank = Arc::new(Bank::new_for_tests(&genesis_config));
|
let mut bank = Arc::new(Bank::new_for_tests(&genesis_config));
|
||||||
let sysvar_and_native_program_delta = 11;
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
bank.capitalization(),
|
bank.capitalization(),
|
||||||
(num_genesis_accounts + num_non_circulating_accounts + num_stake_accounts) * balance
|
(num_genesis_accounts + num_non_circulating_accounts + num_stake_accounts) * balance
|
||||||
+ sysvar_and_native_program_delta,
|
+ genesis_sysvar_and_builtin_program_lamports(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let non_circulating_supply = calculate_non_circulating_supply(&bank).unwrap();
|
let non_circulating_supply = calculate_non_circulating_supply(&bank).unwrap();
|
||||||
|
|
|
@ -7,7 +7,6 @@ use solana_sdk::{
|
||||||
incinerator,
|
incinerator,
|
||||||
pubkey::Pubkey,
|
pubkey::Pubkey,
|
||||||
rent::{Rent, RentDue},
|
rent::{Rent, RentDue},
|
||||||
sysvar,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, AbiExample)]
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug, AbiExample)]
|
||||||
|
@ -53,14 +52,8 @@ impl RentCollector {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// true if it is easy to determine this account should consider having rent collected from it
|
/// true if it is easy to determine this account should consider having rent collected from it
|
||||||
pub fn should_collect_rent(
|
pub fn should_collect_rent(&self, address: &Pubkey, account: &impl ReadableAccount) -> bool {
|
||||||
&self,
|
|
||||||
address: &Pubkey,
|
|
||||||
account: &impl ReadableAccount,
|
|
||||||
rent_for_sysvars: bool,
|
|
||||||
) -> bool {
|
|
||||||
!(account.executable() // executable accounts must be rent-exempt balance
|
!(account.executable() // executable accounts must be rent-exempt balance
|
||||||
|| (!rent_for_sysvars && sysvar::check_id(account.owner()))
|
|
||||||
|| *address == incinerator::id())
|
|| *address == incinerator::id())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +83,9 @@ impl RentCollector {
|
||||||
&self,
|
&self,
|
||||||
address: &Pubkey,
|
address: &Pubkey,
|
||||||
account: &mut AccountSharedData,
|
account: &mut AccountSharedData,
|
||||||
rent_for_sysvars: bool,
|
|
||||||
filler_account_suffix: Option<&Pubkey>,
|
filler_account_suffix: Option<&Pubkey>,
|
||||||
) -> CollectedInfo {
|
) -> CollectedInfo {
|
||||||
if self.can_skip_rent_collection(address, account, rent_for_sysvars, filler_account_suffix)
|
if self.can_skip_rent_collection(address, account, filler_account_suffix) {
|
||||||
{
|
|
||||||
return CollectedInfo::default();
|
return CollectedInfo::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,11 +125,10 @@ impl RentCollector {
|
||||||
&self,
|
&self,
|
||||||
address: &Pubkey,
|
address: &Pubkey,
|
||||||
account: &mut AccountSharedData,
|
account: &mut AccountSharedData,
|
||||||
rent_for_sysvars: bool,
|
|
||||||
) -> CollectedInfo {
|
) -> CollectedInfo {
|
||||||
// initialize rent_epoch as created at this epoch
|
// initialize rent_epoch as created at this epoch
|
||||||
account.set_rent_epoch(self.epoch);
|
account.set_rent_epoch(self.epoch);
|
||||||
self.collect_from_existing_account(address, account, rent_for_sysvars, None)
|
self.collect_from_existing_account(address, account, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Performs easy checks to see if rent collection can be skipped
|
/// Performs easy checks to see if rent collection can be skipped
|
||||||
|
@ -146,10 +136,9 @@ impl RentCollector {
|
||||||
&self,
|
&self,
|
||||||
address: &Pubkey,
|
address: &Pubkey,
|
||||||
account: &mut AccountSharedData,
|
account: &mut AccountSharedData,
|
||||||
rent_for_sysvars: bool,
|
|
||||||
filler_account_suffix: Option<&Pubkey>,
|
filler_account_suffix: Option<&Pubkey>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
!self.should_collect_rent(address, account, rent_for_sysvars)
|
!self.should_collect_rent(address, account)
|
||||||
|| account.rent_epoch() > self.epoch
|
|| account.rent_epoch() > self.epoch
|
||||||
|| crate::accounts_db::AccountsDb::is_filler_account_helper(
|
|| crate::accounts_db::AccountsDb::is_filler_account_helper(
|
||||||
address,
|
address,
|
||||||
|
@ -186,7 +175,10 @@ impl std::ops::AddAssign for CollectedInfo {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use {super::*, solana_sdk::account::Account};
|
use {
|
||||||
|
super::*,
|
||||||
|
solana_sdk::{account::Account, sysvar},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_collect_from_account_created_and_existing() {
|
fn test_collect_from_account_created_and_existing() {
|
||||||
|
@ -207,11 +199,8 @@ mod tests {
|
||||||
let rent_collector = RentCollector::default().clone_with_epoch(new_epoch);
|
let rent_collector = RentCollector::default().clone_with_epoch(new_epoch);
|
||||||
|
|
||||||
// collect rent on a newly-created account
|
// collect rent on a newly-created account
|
||||||
let collected = rent_collector.collect_from_created_account(
|
let collected = rent_collector
|
||||||
&solana_sdk::pubkey::new_rand(),
|
.collect_from_created_account(&solana_sdk::pubkey::new_rand(), &mut created_account);
|
||||||
&mut created_account,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
assert!(created_account.lamports() < old_lamports);
|
assert!(created_account.lamports() < old_lamports);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
created_account.lamports() + collected.rent_amount,
|
created_account.lamports() + collected.rent_amount,
|
||||||
|
@ -224,7 +213,6 @@ mod tests {
|
||||||
let collected = rent_collector.collect_from_existing_account(
|
let collected = rent_collector.collect_from_existing_account(
|
||||||
&solana_sdk::pubkey::new_rand(),
|
&solana_sdk::pubkey::new_rand(),
|
||||||
&mut existing_account,
|
&mut existing_account,
|
||||||
true,
|
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
assert!(existing_account.lamports() < old_lamports);
|
assert!(existing_account.lamports() < old_lamports);
|
||||||
|
@ -255,8 +243,7 @@ mod tests {
|
||||||
let rent_collector = RentCollector::default().clone_with_epoch(epoch);
|
let rent_collector = RentCollector::default().clone_with_epoch(epoch);
|
||||||
|
|
||||||
// first mark account as being collected while being rent-exempt
|
// first mark account as being collected while being rent-exempt
|
||||||
let collected =
|
let collected = rent_collector.collect_from_existing_account(&pubkey, &mut account, None);
|
||||||
rent_collector.collect_from_existing_account(&pubkey, &mut account, true, None);
|
|
||||||
assert_eq!(account.lamports(), huge_lamports);
|
assert_eq!(account.lamports(), huge_lamports);
|
||||||
assert_eq!(collected, CollectedInfo::default());
|
assert_eq!(collected, CollectedInfo::default());
|
||||||
|
|
||||||
|
@ -264,8 +251,7 @@ mod tests {
|
||||||
account.set_lamports(tiny_lamports);
|
account.set_lamports(tiny_lamports);
|
||||||
|
|
||||||
// ... and trigger another rent collection on the same epoch and check that rent is working
|
// ... and trigger another rent collection on the same epoch and check that rent is working
|
||||||
let collected =
|
let collected = rent_collector.collect_from_existing_account(&pubkey, &mut account, None);
|
||||||
rent_collector.collect_from_existing_account(&pubkey, &mut account, true, None);
|
|
||||||
assert_eq!(account.lamports(), tiny_lamports - collected.rent_amount);
|
assert_eq!(account.lamports(), tiny_lamports - collected.rent_amount);
|
||||||
assert_ne!(collected, CollectedInfo::default());
|
assert_ne!(collected, CollectedInfo::default());
|
||||||
}
|
}
|
||||||
|
@ -284,15 +270,7 @@ mod tests {
|
||||||
let epoch = 3;
|
let epoch = 3;
|
||||||
let rent_collector = RentCollector::default().clone_with_epoch(epoch);
|
let rent_collector = RentCollector::default().clone_with_epoch(epoch);
|
||||||
|
|
||||||
// old behavior: sysvars are special-cased
|
let collected = rent_collector.collect_from_existing_account(&pubkey, &mut account, None);
|
||||||
let collected =
|
|
||||||
rent_collector.collect_from_existing_account(&pubkey, &mut account, false, None);
|
|
||||||
assert_eq!(account.lamports(), tiny_lamports);
|
|
||||||
assert_eq!(collected, CollectedInfo::default());
|
|
||||||
|
|
||||||
// new behavior: sysvars are NOT special-cased
|
|
||||||
let collected =
|
|
||||||
rent_collector.collect_from_existing_account(&pubkey, &mut account, true, None);
|
|
||||||
assert_eq!(account.lamports(), 0);
|
assert_eq!(account.lamports(), 0);
|
||||||
assert_eq!(collected.rent_amount, 1);
|
assert_eq!(collected.rent_amount, 1);
|
||||||
}
|
}
|
||||||
|
@ -312,12 +290,8 @@ mod tests {
|
||||||
});
|
});
|
||||||
let rent_collector = RentCollector::default().clone_with_epoch(account_rent_epoch + 2);
|
let rent_collector = RentCollector::default().clone_with_epoch(account_rent_epoch + 2);
|
||||||
|
|
||||||
let collected = rent_collector.collect_from_existing_account(
|
let collected =
|
||||||
&Pubkey::new_unique(),
|
rent_collector.collect_from_existing_account(&Pubkey::new_unique(), &mut account, None);
|
||||||
&mut account,
|
|
||||||
true,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(collected.rent_amount, account_lamports);
|
assert_eq!(collected.rent_amount, account_lamports);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
|
@ -15,7 +15,7 @@ use {
|
||||||
NonceError, SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH,
|
NonceError, SystemError, SystemInstruction, MAX_PERMITTED_DATA_LENGTH,
|
||||||
},
|
},
|
||||||
system_program,
|
system_program,
|
||||||
sysvar::{self, rent::Rent},
|
sysvar::rent::Rent,
|
||||||
},
|
},
|
||||||
std::collections::HashSet,
|
std::collections::HashSet,
|
||||||
};
|
};
|
||||||
|
@ -124,19 +124,6 @@ fn assign(
|
||||||
return Err(InstructionError::MissingRequiredSignature);
|
return Err(InstructionError::MissingRequiredSignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bpf programs are allowed to do this; so this is inconsistent...
|
|
||||||
// Thus, we're starting to remove this restriction from system instruction
|
|
||||||
// processor for consistency and fewer special casing by piggybacking onto
|
|
||||||
// the related feature gate..
|
|
||||||
let rent_for_sysvars = invoke_context
|
|
||||||
.feature_set
|
|
||||||
.is_active(&feature_set::rent_for_sysvars::id());
|
|
||||||
if !rent_for_sysvars && sysvar::check_id(owner) {
|
|
||||||
// guard against sysvars being made
|
|
||||||
ic_msg!(invoke_context, "Assign: cannot assign to sysvar, {}", owner);
|
|
||||||
return Err(SystemError::InvalidProgramId.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
account.set_owner(*owner);
|
account.set_owner(*owner);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -492,7 +479,6 @@ mod tests {
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
account::{self, Account, AccountSharedData},
|
account::{self, Account, AccountSharedData},
|
||||||
client::SyncClient,
|
client::SyncClient,
|
||||||
feature_set::FeatureSet,
|
|
||||||
genesis_config::create_genesis_config,
|
genesis_config::create_genesis_config,
|
||||||
hash::{hash, Hash},
|
hash::{hash, Hash},
|
||||||
instruction::{AccountMeta, Instruction, InstructionError},
|
instruction::{AccountMeta, Instruction, InstructionError},
|
||||||
|
@ -980,41 +966,6 @@ mod tests {
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_create_sysvar_invalid_id_without_feature() {
|
|
||||||
let mut feature_set = FeatureSet::all_enabled();
|
|
||||||
feature_set
|
|
||||||
.active
|
|
||||||
.remove(&feature_set::rent_for_sysvars::id());
|
|
||||||
feature_set
|
|
||||||
.inactive
|
|
||||||
.insert(feature_set::rent_for_sysvars::id());
|
|
||||||
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
|
||||||
invoke_context.feature_set = Arc::new(feature_set);
|
|
||||||
// Attempt to create system account in account already owned by another program
|
|
||||||
let from = Pubkey::new_unique();
|
|
||||||
let from_account = RefCell::new(AccountSharedData::new(100, 0, &system_program::id()));
|
|
||||||
|
|
||||||
let to = Pubkey::new_unique();
|
|
||||||
let to_account = RefCell::new(AccountSharedData::new(0, 0, &system_program::id()));
|
|
||||||
|
|
||||||
let signers = [from, to].iter().cloned().collect::<HashSet<_>>();
|
|
||||||
let to_address = to.into();
|
|
||||||
|
|
||||||
let result = create_account(
|
|
||||||
&KeyedAccount::new(&from, true, &from_account),
|
|
||||||
&KeyedAccount::new(&to, false, &to_account),
|
|
||||||
&to_address,
|
|
||||||
50,
|
|
||||||
2,
|
|
||||||
&sysvar::id(),
|
|
||||||
&signers,
|
|
||||||
&invoke_context,
|
|
||||||
);
|
|
||||||
assert_eq!(result, Err(SystemError::InvalidProgramId.into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_create_data_populated() {
|
fn test_create_data_populated() {
|
||||||
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
|
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
|
||||||
|
@ -1151,34 +1102,6 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_assign_to_sysvar_without_feature() {
|
|
||||||
let mut feature_set = FeatureSet::all_enabled();
|
|
||||||
feature_set
|
|
||||||
.active
|
|
||||||
.remove(&feature_set::rent_for_sysvars::id());
|
|
||||||
feature_set
|
|
||||||
.inactive
|
|
||||||
.insert(feature_set::rent_for_sysvars::id());
|
|
||||||
let mut transaction_context = TransactionContext::new(Vec::new(), 1);
|
|
||||||
let mut invoke_context = InvokeContext::new_mock(&mut transaction_context, &[]);
|
|
||||||
invoke_context.feature_set = Arc::new(feature_set);
|
|
||||||
let new_owner = sysvar::id();
|
|
||||||
let from = Pubkey::new_unique();
|
|
||||||
let mut from_account = AccountSharedData::new(100, 0, &system_program::id());
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
assign(
|
|
||||||
&mut from_account,
|
|
||||||
&from.into(),
|
|
||||||
&new_owner,
|
|
||||||
&[from].iter().cloned().collect::<HashSet<_>>(),
|
|
||||||
&invoke_context,
|
|
||||||
),
|
|
||||||
Err(SystemError::InvalidProgramId.into())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_process_bogus_instruction() {
|
fn test_process_bogus_instruction() {
|
||||||
// Attempt to assign with no accounts
|
// Attempt to assign with no accounts
|
||||||
|
|
Loading…
Reference in New Issue