use {
crate::{
account_rent_state::{check_rent_state, RentState},
bank::Bank,
},
solana_program_runtime::invoke_context::TransactionAccountRefCell,
solana_sdk::{
account::ReadableAccount, feature_set, message::SanitizedMessage, native_loader,
transaction::Result,
},
};
pub(crate) struct TransactionAccountStateInfo {
rent_state: Option<RentState>, }
impl Bank {
pub(crate) fn get_transaction_account_state_info(
&self,
transaction_account_refcells: &[TransactionAccountRefCell],
message: &SanitizedMessage,
) -> Vec<TransactionAccountStateInfo> {
transaction_account_refcells
.iter()
.take(message.account_keys_len())
.enumerate()
.map(|(i, (_pubkey, account_refcell))| {
let account = account_refcell.borrow();
let rent_state = if message.is_writable(i) {
debug_assert!(!native_loader::check_id(account.owner()));
Some(RentState::from_account(
&account,
&self.rent_collector().rent,
))
} else {
None
};
TransactionAccountStateInfo { rent_state }
})
.collect()
}
pub(crate) fn verify_transaction_account_state_changes(
&self,
pre_state_infos: &[TransactionAccountStateInfo],
post_state_infos: &[TransactionAccountStateInfo],
transaction_account_refcells: &[TransactionAccountRefCell],
) -> Result<()> {
let require_rent_exempt_accounts = self
.feature_set
.is_active(&feature_set::require_rent_exempt_accounts::id());
for ((pre_state_info, post_state_info), (pubkey, account_refcell)) in pre_state_infos
.iter()
.zip(post_state_infos)
.zip(transaction_account_refcells)
{
if let Err(err) = check_rent_state(
pre_state_info.rent_state.as_ref(),
post_state_info.rent_state.as_ref(),
pubkey,
&account_refcell.borrow(),
) {
if require_rent_exempt_accounts {
return Err(err);
}
}
}
Ok(())
}
}