Skip to content

Commit

Permalink
Refactor: pull out fee payer balance check (#25519)
Browse files Browse the repository at this point in the history
(cherry picked from commit 7b98ff1)
  • Loading branch information
buffalu authored and mergify[bot] committed May 25, 2022
1 parent ca73a36 commit 16dfe47
Showing 1 changed file with 63 additions and 44 deletions.
107 changes: 63 additions & 44 deletions runtime/src/accounts.rs
Expand Up @@ -348,51 +348,15 @@ impl Accounts {
if payer_index != 0 {
warn!("Payer index should be 0! {:?}", tx);
}
let (ref payer_address, ref mut payer_account) = accounts[payer_index];
if payer_account.lamports() == 0 {
error_counters.account_not_found += 1;
return Err(TransactionError::AccountNotFound);
}
let min_balance = match get_system_account_kind(payer_account).ok_or_else(|| {
error_counters.invalid_account_for_fee += 1;
TransactionError::InvalidAccountForFee
})? {
SystemAccountKind::System => 0,
SystemAccountKind::Nonce => {
// Should we ever allow a fees charge to zero a nonce account's
// balance. The state MUST be set to uninitialized in that case
rent_collector.rent.minimum_balance(NonceState::size())
}
};

if payer_account.lamports() < fee + min_balance {
error_counters.insufficient_funds += 1;
return Err(TransactionError::InsufficientFundsForFee);
}
let payer_pre_rent_state =
RentState::from_account(payer_account, &rent_collector.rent);
payer_account
.checked_sub_lamports(fee)
.map_err(|_| TransactionError::InsufficientFundsForFee)?;

let payer_post_rent_state =
RentState::from_account(payer_account, &rent_collector.rent);
let rent_state_result = check_rent_state_with_account(
&payer_pre_rent_state,
&payer_post_rent_state,
payer_address,
payer_account,
feature_set.is_active(&feature_set::do_support_realloc::id()),
feature_set
.is_active(&feature_set::include_account_index_in_rent_error::ID)
.then(|| payer_index),
);
// Feature gate only wraps the actual error return so that the metrics and debug
// logging generated by `check_rent_state_with_account()` can be examined before
// feature activation
if feature_set.is_active(&feature_set::require_rent_exempt_accounts::id()) {
rent_state_result?;
}
Self::check_fee_payer_balance(
&mut accounts,
payer_index,
error_counters,
rent_collector,
feature_set,
fee,
)?;

let program_indices = message
.instructions()
Expand All @@ -406,6 +370,7 @@ impl Accounts {
)
})
.collect::<Result<Vec<Vec<usize>>>>()?;

Ok(LoadedTransaction {
accounts,
program_indices,
Expand All @@ -419,6 +384,60 @@ impl Accounts {
}
}

fn check_fee_payer_balance(
accounts: &mut [(Pubkey, AccountSharedData)],
payer_index: usize,
error_counters: &mut TransactionErrorMetrics,
rent_collector: &RentCollector,
feature_set: &FeatureSet,
fee: u64,
) -> Result<()> {
let (ref payer_address, ref mut payer_account) = accounts[payer_index];
if payer_account.lamports() == 0 {
error_counters.account_not_found += 1;
return Err(TransactionError::AccountNotFound);
}
let min_balance = match get_system_account_kind(payer_account).ok_or_else(|| {
error_counters.invalid_account_for_fee += 1;
TransactionError::InvalidAccountForFee
})? {
SystemAccountKind::System => 0,
SystemAccountKind::Nonce => {
// Should we ever allow a fees charge to zero a nonce account's
// balance. The state MUST be set to uninitialized in that case
rent_collector.rent.minimum_balance(NonceState::size())
}
};

if payer_account.lamports() < fee + min_balance {
error_counters.insufficient_funds += 1;
return Err(TransactionError::InsufficientFundsForFee);
}
let payer_pre_rent_state = RentState::from_account(payer_account, &rent_collector.rent);
payer_account
.checked_sub_lamports(fee)
.map_err(|_| TransactionError::InsufficientFundsForFee)?;

let payer_post_rent_state = RentState::from_account(payer_account, &rent_collector.rent);
let rent_state_result = check_rent_state_with_account(
&payer_pre_rent_state,
&payer_post_rent_state,
payer_address,
payer_account,
feature_set.is_active(&feature_set::do_support_realloc::id()),
feature_set
.is_active(&feature_set::include_account_index_in_rent_error::ID)
.then(|| payer_index),
);
// Feature gate only wraps the actual error return so that the metrics and debug
// logging generated by `check_rent_state_with_account()` can be examined before
// feature activation
if feature_set.is_active(&feature_set::require_rent_exempt_accounts::id()) {
rent_state_result?;
}
Ok(())
}

fn load_executable_accounts(
&self,
ancestors: &Ancestors,
Expand Down

0 comments on commit 16dfe47

Please sign in to comment.