Skip to content

Commit

Permalink
stop requiring data allocation to check for rent (solana-labs#543)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffwashington authored Apr 2, 2024
1 parent 9ea627c commit ccb0986
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 28 deletions.
41 changes: 28 additions & 13 deletions accounts-db/src/accounts_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8608,20 +8608,25 @@ impl AccountsDb {
}

/// return Some(lamports_to_top_off) if 'account' would collect rent
fn stats_for_rent_payers<T: ReadableAccount>(
fn stats_for_rent_payers(
pubkey: &Pubkey,
account: &T,
lamports: u64,
account_data_len: usize,
account_rent_epoch: Epoch,
executable: bool,
rent_collector: &RentCollector,
) -> Option<u64> {
if account.lamports() == 0 {
if lamports == 0 {
return None;
}
(rent_collector.should_collect_rent(pubkey, account)
&& !rent_collector.get_rent_due(account).is_exempt())
(rent_collector.should_collect_rent(pubkey, executable)
&& !rent_collector
.get_rent_due(lamports, account_data_len, account_rent_epoch)
.is_exempt())
.then(|| {
let min_balance = rent_collector.rent.minimum_balance(account.data().len());
let min_balance = rent_collector.rent.minimum_balance(account_data_len);
// return lamports required to top off this account to make it rent exempt
min_balance.saturating_sub(account.lamports())
min_balance.saturating_sub(lamports)
})
}

Expand Down Expand Up @@ -8661,9 +8666,14 @@ impl AccountsDb {
accounts_data_len += stored_account.data().len() as u64;
}

if let Some(amount_to_top_off_rent_this_account) =
Self::stats_for_rent_payers(pubkey, &stored_account, rent_collector)
{
if let Some(amount_to_top_off_rent_this_account) = Self::stats_for_rent_payers(
pubkey,
stored_account.lamports(),
stored_account.data().len(),
stored_account.rent_epoch(),
stored_account.executable(),
rent_collector,
) {
amount_to_top_off_rent += amount_to_top_off_rent_this_account;
num_accounts_rent_paying += 1;
// remember this rent-paying account pubkey
Expand Down Expand Up @@ -9090,9 +9100,14 @@ impl AccountsDb {
);
let loaded_account = accessor.check_and_get_loaded_account();
accounts_data_len_from_duplicates += loaded_account.data().len();
if let Some(lamports_to_top_off) =
Self::stats_for_rent_payers(pubkey, &loaded_account, rent_collector)
{
if let Some(lamports_to_top_off) = Self::stats_for_rent_payers(
pubkey,
loaded_account.lamports(),
loaded_account.data().len(),
loaded_account.rent_epoch(),
loaded_account.executable(),
rent_collector,
) {
removed_rent_paying += 1;
removed_top_off += lamports_to_top_off;
}
Expand Down
16 changes: 13 additions & 3 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5165,7 +5165,11 @@ impl Bank {
// account itself is rent-exempted but its `rent_epoch` is not u64::MAX, we will set its
// `rent_epoch` to u64::MAX. In such case, the behavior stays the same as before.
if account.rent_epoch() != RENT_EXEMPT_RENT_EPOCH
&& self.rent_collector.get_rent_due(account) == RentDue::Exempt
&& self.rent_collector.get_rent_due(
account.lamports(),
account.data().len(),
account.rent_epoch(),
) == RentDue::Exempt
{
account.set_rent_epoch(RENT_EXEMPT_RENT_EPOCH);
}
Expand Down Expand Up @@ -7803,8 +7807,14 @@ impl TotalAccountsStats {
self.executable_data_len += data_len;
}

if !rent_collector.should_collect_rent(address, account)
|| rent_collector.get_rent_due(account).is_exempt()
if !rent_collector.should_collect_rent(address, account.executable())
|| rent_collector
.get_rent_due(
account.lamports(),
account.data().len(),
account.rent_epoch(),
)
.is_exempt()
{
self.num_rent_exempt_accounts += 1;
} else {
Expand Down
27 changes: 16 additions & 11 deletions sdk/src/rent_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,22 @@ impl RentCollector {
}

/// true if it is easy to determine this account should consider having rent collected from it
pub fn should_collect_rent(&self, address: &Pubkey, account: &impl ReadableAccount) -> bool {
!(account.executable() // executable accounts must be rent-exempt balance
pub fn should_collect_rent(&self, address: &Pubkey, executable: bool) -> bool {
!(executable // executable accounts must be rent-exempt balance
|| *address == incinerator::id())
}

/// given an account that 'should_collect_rent'
/// returns (amount rent due, is_exempt_from_rent)
pub fn get_rent_due(&self, account: &impl ReadableAccount) -> RentDue {
if self
.rent
.is_exempt(account.lamports(), account.data().len())
{
pub fn get_rent_due(
&self,
lamports: u64,
data_len: usize,
account_rent_epoch: Epoch,
) -> RentDue {
if self.rent.is_exempt(lamports, data_len) {
RentDue::Exempt
} else {
let account_rent_epoch = account.rent_epoch();
let slots_elapsed: u64 = (account_rent_epoch..=self.epoch)
.map(|epoch| {
self.epoch_schedule
Expand All @@ -103,7 +104,7 @@ impl RentCollector {
};

// we know this account is not exempt
let due = self.rent.due_amount(account.data().len(), years_elapsed);
let due = self.rent.due_amount(data_len, years_elapsed);
RentDue::Paying(due)
}
}
Expand Down Expand Up @@ -158,11 +159,15 @@ impl RentCollector {
// Maybe collect rent later, leave account alone for now.
return RentResult::NoRentCollectionNow;
}
if !self.should_collect_rent(address, account) {
if !self.should_collect_rent(address, account.executable()) {
// easy to determine this account should not consider having rent collected from it
return RentResult::Exempt;
}
match self.get_rent_due(account) {
match self.get_rent_due(
account.lamports(),
account.data().len(),
account.rent_epoch(),
) {
// account will not have rent collected ever
RentDue::Exempt => RentResult::Exempt,
// potentially rent paying account
Expand Down
6 changes: 5 additions & 1 deletion svm/src/account_loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
// account itself is rent-exempted but its `rent_epoch` is not u64::MAX, we will set its
// `rent_epoch` to u64::MAX. In such case, the behavior stays the same as before.
if account.rent_epoch() != RENT_EXEMPT_RENT_EPOCH
&& rent_collector.get_rent_due(&account) == RentDue::Exempt
&& rent_collector.get_rent_due(
account.lamports(),
account.data().len(),
account.rent_epoch(),
) == RentDue::Exempt
{
account.set_rent_epoch(RENT_EXEMPT_RENT_EPOCH);
}
Expand Down

0 comments on commit ccb0986

Please sign in to comment.