use solana_address::Address;
use solana_rent::Rent;
use solana_transaction_context::IndexOfAccount;
use solana_transaction_error::{TransactionError, TransactionResult};
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum RentState {
Uninitialized,
RentPaying {
lamports: u64, data_size: usize, },
RentExempt,
}
pub(crate) fn check_rent_state_with_account(
pre_rent_state: &RentState,
post_rent_state: &RentState,
address: &Address,
account_index: IndexOfAccount,
) -> TransactionResult<()> {
if !solana_sdk_ids::incinerator::check_id(address) &&
!transition_allowed(pre_rent_state, post_rent_state)
{
let account_index = account_index as u8;
Err(TransactionError::InsufficientFundsForRent { account_index })
} else {
Ok(())
}
}
pub(crate) fn get_account_rent_state(
rent: &Rent,
account_lamports: u64,
account_size: usize,
) -> RentState {
if account_lamports == 0 {
RentState::Uninitialized
} else if rent.is_exempt(account_lamports, account_size) {
RentState::RentExempt
} else {
RentState::RentPaying { data_size: account_size, lamports: account_lamports }
}
}
pub(crate) fn transition_allowed(pre_rent_state: &RentState, post_rent_state: &RentState) -> bool {
match post_rent_state {
RentState::Uninitialized | RentState::RentExempt => true,
RentState::RentPaying { data_size: post_data_size, lamports: post_lamports } => {
match pre_rent_state {
RentState::Uninitialized | RentState::RentExempt => false,
RentState::RentPaying { data_size: pre_data_size, lamports: pre_lamports } => {
post_data_size == pre_data_size && post_lamports <= pre_lamports
}
}
}
}
}