Skip to content

Commit

Permalink
Adds inspect_account() to TransactionProcessingCallback (#2678)
Browse files Browse the repository at this point in the history
  • Loading branch information
brooksprumo authored Aug 21, 2024
1 parent d852dfc commit 0880cb6
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 5 deletions.
34 changes: 29 additions & 5 deletions svm/src/account_loader.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use {
crate::{
account_overrides::AccountOverrides, account_rent_state::RentState, nonce_info::NonceInfo,
rollback_accounts::RollbackAccounts, transaction_error_metrics::TransactionErrorMetrics,
transaction_processing_callback::TransactionProcessingCallback,
account_overrides::AccountOverrides,
account_rent_state::RentState,
nonce_info::NonceInfo,
rollback_accounts::RollbackAccounts,
transaction_error_metrics::TransactionErrorMetrics,
transaction_processing_callback::{AccountState, TransactionProcessingCallback},
},
itertools::Itertools,
solana_compute_budget::compute_budget_limits::ComputeBudgetLimits,
Expand Down Expand Up @@ -410,9 +413,11 @@ fn load_transaction_account<CB: TransactionProcessingCallback>(
loaded_programs: &ProgramCacheForTxBatch,
) -> Result<(LoadedTransactionAccount, bool)> {
let mut account_found = true;
let mut was_inspected = false;
let is_instruction_account = u8::try_from(account_index)
.map(|i| instruction_accounts.contains(&&i))
.unwrap_or(false);
let is_writable = message.is_writable(account_index);
let loaded_account = if solana_sdk::sysvar::instructions::check_id(account_key) {
// Since the instructions sysvar is constructed by the SVM and modified
// for each transaction instruction, it cannot be overridden.
Expand All @@ -429,7 +434,7 @@ fn load_transaction_account<CB: TransactionProcessingCallback>(
account: account_override.clone(),
rent_collected: 0,
}
} else if let Some(program) = (!is_instruction_account && !message.is_writable(account_index))
} else if let Some(program) = (!is_instruction_account && !is_writable)
.then_some(())
.and_then(|_| loaded_programs.find(account_key))
{
Expand All @@ -447,7 +452,17 @@ fn load_transaction_account<CB: TransactionProcessingCallback>(
callbacks
.get_account_shared_data(account_key)
.map(|mut account| {
let rent_collected = if message.is_writable(account_index) {
let rent_collected = if is_writable {
// Inspect the account prior to collecting rent, since
// rent collection can modify the account.
debug_assert!(!was_inspected);
callbacks.inspect_account(
account_key,
AccountState::Alive(&account),
is_writable,
);
was_inspected = true;

collect_rent_from_account(
feature_set,
rent_collector,
Expand Down Expand Up @@ -480,6 +495,15 @@ fn load_transaction_account<CB: TransactionProcessingCallback>(
})
};

if !was_inspected {
let account_state = if account_found {
AccountState::Alive(&loaded_account.account)
} else {
AccountState::Dead
};
callbacks.inspect_account(account_key, account_state, is_writable);
}

Ok((loaded_account, account_found))
}

Expand Down
12 changes: 12 additions & 0 deletions svm/src/transaction_processing_callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,16 @@ pub trait TransactionProcessingCallback {
fn get_account_shared_data(&self, pubkey: &Pubkey) -> Option<AccountSharedData>;

fn add_builtin_account(&self, _name: &str, _program_id: &Pubkey) {}

fn inspect_account(&self, _address: &Pubkey, _account_state: AccountState, _is_writable: bool) {
}
}

/// The state the account is in initially, before transaction processing
#[derive(Debug)]
pub enum AccountState<'a> {
/// This account is dead, and will be created by this transaction
Dead,
/// This account is alive, and already existed prior to this transaction
Alive(&'a AccountSharedData),
}

0 comments on commit 0880cb6

Please sign in to comment.