Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

runtime: add rent debit charges to block metadata #17504

Merged
merged 2 commits into from
May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions runtime/src/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ use crate::{
accounts_index::{AccountSecondaryIndexes, IndexKey},
ancestors::Ancestors,
bank::{
NonceRollbackFull, NonceRollbackInfo, TransactionCheckResult, TransactionExecutionResult,
NonceRollbackFull, NonceRollbackInfo, RentDebits, TransactionCheckResult,
TransactionExecutionResult,
},
blockhash_queue::BlockhashQueue,
rent_collector::RentCollector,
Expand Down Expand Up @@ -99,12 +100,14 @@ pub type TransactionAccounts = Vec<AccountSharedData>;
pub type TransactionAccountDeps = Vec<(Pubkey, AccountSharedData)>;
pub type TransactionRent = u64;
pub type TransactionLoaders = Vec<Vec<(Pubkey, AccountSharedData)>>;
pub type TransactionRentDebits = RentDebits;
#[derive(PartialEq, Debug, Clone)]
pub struct LoadedTransaction {
pub accounts: TransactionAccounts,
pub account_deps: TransactionAccountDeps,
pub loaders: TransactionLoaders,
pub rent: TransactionRent,
pub rent_debits: TransactionRentDebits,
}

pub type TransactionLoadResult = (Result<LoadedTransaction>, Option<NonceRollbackFull>);
Expand Down Expand Up @@ -206,6 +209,7 @@ impl Accounts {
let demote_sysvar_write_locks =
feature_set.is_active(&feature_set::demote_sysvar_write_locks::id());
let mut key_check = MessageProgramIdsCache::new(&message);
let mut rent_debits = RentDebits::default();
for (i, key) in message.account_keys.iter().enumerate() {
let account = if key_check.is_non_loader_key(key, i) {
if payer_index.is_none() {
Expand Down Expand Up @@ -258,6 +262,8 @@ impl Accounts {
}

tx_rent += rent;
rent_debits.push(key, rent, account.lamports());

account
}
} else {
Expand Down Expand Up @@ -319,6 +325,7 @@ impl Accounts {
account_deps,
loaders,
rent: tx_rent,
rent_debits,
})
}
}
Expand Down Expand Up @@ -995,8 +1002,11 @@ impl Accounts {
}
}
if account.rent_epoch() == INITIAL_RENT_EPOCH {
loaded_transaction.rent +=
rent_collector.collect_from_created_account(&key, account);
let rent = rent_collector.collect_from_created_account(&key, account);
loaded_transaction.rent += rent;
loaded_transaction
.rent_debits
.push(key, rent, account.lamports());
}
accounts.push((key, &*account));
}
Expand Down Expand Up @@ -1968,6 +1978,7 @@ mod tests {
account_deps: vec![],
loaders: transaction_loaders0,
rent: transaction_rent0,
rent_debits: RentDebits::default(),
}),
None,
);
Expand All @@ -1981,6 +1992,7 @@ mod tests {
account_deps: vec![],
loaders: transaction_loaders1,
rent: transaction_rent1,
rent_debits: RentDebits::default(),
}),
None,
);
Expand Down Expand Up @@ -2363,6 +2375,7 @@ mod tests {
account_deps: vec![],
loaders: transaction_loaders,
rent: transaction_rent,
rent_debits: RentDebits::default(),
}),
nonce_rollback,
);
Expand Down Expand Up @@ -2481,6 +2494,7 @@ mod tests {
account_deps: vec![],
loaders: transaction_loaders,
rent: transaction_rent,
rent_debits: RentDebits::default(),
}),
nonce_rollback,
);
Expand Down
78 changes: 66 additions & 12 deletions runtime/src/bank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,27 @@ pub const SECONDS_PER_YEAR: f64 = 365.25 * 24.0 * 60.0 * 60.0;

pub const MAX_LEADER_SCHEDULE_STAKES: Epoch = 5;

#[derive(Clone, Debug, Default, PartialEq)]
pub struct RentDebits(pub Vec<(Pubkey, RewardInfo)>);

impl RentDebits {
pub fn push(&mut self, account: &Pubkey, rent: u64, post_balance: u64) {
if rent != 0 {
let rent_debit = i64::try_from(rent).ok().and_then(|r| r.checked_neg());
if let Some(rent_debit) = rent_debit {
let reward_info = RewardInfo {
reward_type: RewardType::Rent,
lamports: rent_debit,
post_balance,
};
self.0.push((*account, reward_info));
} else {
warn!("out of range rent debit from {}: {}", account, rent);
}
}
}
}

#[derive(Default, Debug)]
pub struct ExecuteTimings {
pub check_us: u64,
Expand Down Expand Up @@ -3537,18 +3558,22 @@ impl Bank {
fn collect_rent(
&self,
res: &[TransactionExecutionResult],
loaded_accounts: &[TransactionLoadResult],
loaded_accounts: &mut [TransactionLoadResult],
) {
let mut collected_rent: u64 = 0;
for (i, (raccs, _nonce_rollback)) in loaded_accounts.iter().enumerate() {
for (i, (raccs, _nonce_rollback)) in loaded_accounts.iter_mut().enumerate() {
let (res, _nonce_rollback) = &res[i];
if res.is_err() || raccs.is_err() {
continue;
}

let loaded_transaction = raccs.as_ref().unwrap();
let loaded_transaction = raccs.as_mut().unwrap();

collected_rent += loaded_transaction.rent;
self.rewards
.write()
.unwrap()
.append(&mut loaded_transaction.rent_debits.0);
}

self.collected_rent.fetch_add(collected_rent, Relaxed);
Expand Down Expand Up @@ -3620,19 +3645,23 @@ impl Bank {
let account_count = accounts.len();

// parallelize?
let mut rent = 0;
let mut total_rent = 0;
let mut rent_debits = RentDebits::default();
for (pubkey, mut account) in accounts {
rent += self
let rent = self
.rent_collector
.collect_from_existing_account(&pubkey, &mut account);
total_rent += rent;
// Store all of them unconditionally to purge old AppendVec,
// even if collected rent is 0 (= not updated).
// Also, there's another subtle side-effect from this: this
// ensures we verify the whole on-chain state (= all accounts)
// via the account delta hash slowly once per an epoch.
self.store_account(&pubkey, &account);
rent_debits.push(&pubkey, rent, account.lamports());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hehe, nice 👀

}
self.collected_rent.fetch_add(rent, Relaxed);
self.collected_rent.fetch_add(total_rent, Relaxed);
self.rewards.write().unwrap().append(&mut rent_debits.0);

datapoint_info!("collect_rent_eagerly", ("accounts", account_count, i64));
}
Expand Down Expand Up @@ -6083,13 +6112,17 @@ pub(crate) mod tests {
.unwrap()
.iter()
.map(|(address, reward)| {
assert_eq!(reward.reward_type, RewardType::Rent);
if *address == validator_2_pubkey {
assert_eq!(reward.post_balance, validator_2_portion + 42 - tweak_2);
} else if *address == validator_3_pubkey {
assert_eq!(reward.post_balance, validator_3_portion + 42);
if reward.lamports > 0 {
assert_eq!(reward.reward_type, RewardType::Rent);
if *address == validator_2_pubkey {
assert_eq!(reward.post_balance, validator_2_portion + 42 - tweak_2);
} else if *address == validator_3_pubkey {
assert_eq!(reward.post_balance, validator_3_portion + 42);
}
reward.lamports as u64
} else {
0
}
reward.lamports as u64
})
.sum::<u64>()
);
Expand Down Expand Up @@ -12825,4 +12858,25 @@ pub(crate) mod tests {
0
);
}

#[test]
fn test_rent_debits() {
let mut rent_debits = RentDebits::default();

// No entry for 0 rewards
rent_debits.push(&Pubkey::default(), 0, 0);
assert_eq!(rent_debits.0.len(), 0);

// Doesn't fit an `i64`, no entry. (we'll die elsewhere)
rent_debits.push(&Pubkey::default(), u64::MAX, 0);
assert_eq!(rent_debits.0.len(), 0);

// Since we're casting from `u64` the `i64::checked_neg()` is infallible

// Some that actually work
rent_debits.push(&Pubkey::default(), 1, 0);
assert_eq!(rent_debits.0.len(), 1);
rent_debits.push(&Pubkey::default(), i64::MAX as u64, 0);
assert_eq!(rent_debits.0.len(), 2);
}
}