solana_svm/
account_loader.rs

1#[cfg(feature = "dev-context-only-utils")]
2use qualifier_attr::field_qualifiers;
3use {
4    crate::{
5        account_overrides::AccountOverrides,
6        nonce_info::NonceInfo,
7        rollback_accounts::RollbackAccounts,
8        transaction_error_metrics::TransactionErrorMetrics,
9        transaction_execution_result::ExecutedTransaction,
10        transaction_processing_callback::{AccountState, TransactionProcessingCallback},
11    },
12    ahash::{AHashMap, AHashSet},
13    solana_account::{
14        Account, AccountSharedData, ReadableAccount, WritableAccount, PROGRAM_OWNERS,
15    },
16    solana_compute_budget::compute_budget_limits::ComputeBudgetLimits,
17    solana_feature_set::{self as feature_set, FeatureSet},
18    solana_fee_structure::FeeDetails,
19    solana_instruction::{BorrowedAccountMeta, BorrowedInstruction},
20    solana_instructions_sysvar::construct_instructions_data,
21    solana_nonce::state::State as NonceState,
22    solana_nonce_account::{get_system_account_kind, SystemAccountKind},
23    solana_pubkey::Pubkey,
24    solana_rent::RentDue,
25    solana_rent_debits::RentDebits,
26    solana_sdk::rent_collector::{CollectedInfo, RENT_EXEMPT_RENT_EPOCH},
27    solana_sdk_ids::{
28        native_loader,
29        sysvar::{self, slot_history},
30    },
31    solana_svm_rent_collector::svm_rent_collector::SVMRentCollector,
32    solana_svm_transaction::svm_message::SVMMessage,
33    solana_transaction_context::{IndexOfAccount, TransactionAccount},
34    solana_transaction_error::{TransactionError, TransactionResult as Result},
35    std::{
36        num::{NonZeroU32, Saturating},
37        sync::Arc,
38    },
39};
40
41// for the load instructions
42pub(crate) type TransactionRent = u64;
43pub(crate) type TransactionProgramIndices = Vec<Vec<IndexOfAccount>>;
44pub type TransactionCheckResult = Result<CheckedTransactionDetails>;
45type TransactionValidationResult = Result<ValidatedTransactionDetails>;
46
47#[derive(PartialEq, Eq, Debug)]
48pub(crate) enum TransactionLoadResult {
49    /// All transaction accounts were loaded successfully
50    Loaded(LoadedTransaction),
51    /// Some transaction accounts needed for execution were unable to be loaded
52    /// but the fee payer and any nonce account needed for fee collection were
53    /// loaded successfully
54    FeesOnly(FeesOnlyTransaction),
55    /// Some transaction accounts needed for fee collection were unable to be
56    /// loaded
57    NotLoaded(TransactionError),
58}
59
60#[derive(PartialEq, Eq, Debug, Clone)]
61#[cfg_attr(feature = "dev-context-only-utils", derive(Default))]
62pub struct CheckedTransactionDetails {
63    pub(crate) nonce: Option<NonceInfo>,
64    pub(crate) lamports_per_signature: u64,
65}
66
67impl CheckedTransactionDetails {
68    pub fn new(nonce: Option<NonceInfo>, lamports_per_signature: u64) -> Self {
69        Self {
70            nonce,
71            lamports_per_signature,
72        }
73    }
74}
75
76#[derive(PartialEq, Eq, Debug, Clone)]
77#[cfg_attr(feature = "dev-context-only-utils", derive(Default))]
78pub(crate) struct ValidatedTransactionDetails {
79    pub(crate) rollback_accounts: RollbackAccounts,
80    pub(crate) compute_budget_limits: ComputeBudgetLimits,
81    pub(crate) fee_details: FeeDetails,
82    pub(crate) loaded_fee_payer_account: LoadedTransactionAccount,
83}
84
85#[derive(PartialEq, Eq, Debug, Clone)]
86#[cfg_attr(feature = "dev-context-only-utils", derive(Default))]
87pub(crate) struct LoadedTransactionAccount {
88    pub(crate) account: AccountSharedData,
89    pub(crate) loaded_size: usize,
90    pub(crate) rent_collected: u64,
91}
92
93#[derive(PartialEq, Eq, Debug, Clone)]
94#[cfg_attr(feature = "dev-context-only-utils", derive(Default))]
95#[cfg_attr(
96    feature = "dev-context-only-utils",
97    field_qualifiers(
98        program_indices(pub),
99        compute_budget_limits(pub),
100        loaded_accounts_data_size(pub)
101    )
102)]
103pub struct LoadedTransaction {
104    pub accounts: Vec<TransactionAccount>,
105    pub(crate) program_indices: TransactionProgramIndices,
106    pub fee_details: FeeDetails,
107    pub rollback_accounts: RollbackAccounts,
108    pub(crate) compute_budget_limits: ComputeBudgetLimits,
109    pub rent: TransactionRent,
110    pub rent_debits: RentDebits,
111    pub(crate) loaded_accounts_data_size: u32,
112}
113
114#[derive(PartialEq, Eq, Debug, Clone)]
115pub struct FeesOnlyTransaction {
116    pub load_error: TransactionError,
117    pub rollback_accounts: RollbackAccounts,
118    pub fee_details: FeeDetails,
119}
120
121#[cfg_attr(feature = "dev-context-only-utils", derive(Clone))]
122pub(crate) struct AccountLoader<'a, CB: TransactionProcessingCallback> {
123    account_cache: AHashMap<Pubkey, AccountSharedData>,
124    callbacks: &'a CB,
125    pub(crate) feature_set: Arc<FeatureSet>,
126}
127impl<'a, CB: TransactionProcessingCallback> AccountLoader<'a, CB> {
128    pub(crate) fn new_with_account_cache_capacity(
129        account_overrides: Option<&'a AccountOverrides>,
130        callbacks: &'a CB,
131        feature_set: Arc<FeatureSet>,
132        capacity: usize,
133    ) -> AccountLoader<'a, CB> {
134        let mut account_cache = AHashMap::with_capacity(capacity);
135
136        // SlotHistory may be overridden for simulation.
137        // No other uses of AccountOverrides are expected.
138        if let Some(slot_history) =
139            account_overrides.and_then(|overrides| overrides.get(&slot_history::id()))
140        {
141            account_cache.insert(slot_history::id(), slot_history.clone());
142        }
143
144        Self {
145            account_cache,
146            callbacks,
147            feature_set,
148        }
149    }
150
151    pub(crate) fn load_account(
152        &mut self,
153        account_key: &Pubkey,
154        is_writable: bool,
155    ) -> Option<LoadedTransactionAccount> {
156        let account = if let Some(account) = self.account_cache.get(account_key) {
157            // If lamports is 0, a previous transaction deallocated this account.
158            // We return None instead of the account we found so it can be created fresh.
159            // We never evict from the cache, or else we would fetch stale state from accounts-db.
160            if account.lamports() == 0 {
161                None
162            } else {
163                Some(account.clone())
164            }
165        } else if let Some(account) = self.callbacks.get_account_shared_data(account_key) {
166            self.account_cache.insert(*account_key, account.clone());
167            Some(account)
168        } else {
169            None
170        };
171
172        // Inspect prior to collecting rent, since rent collection can modify the account.
173        self.callbacks.inspect_account(
174            account_key,
175            if let Some(ref account) = account {
176                AccountState::Alive(account)
177            } else {
178                AccountState::Dead
179            },
180            is_writable,
181        );
182
183        account.map(|account| LoadedTransactionAccount {
184            loaded_size: account.data().len(),
185            account,
186            rent_collected: 0,
187        })
188    }
189
190    pub(crate) fn update_accounts_for_executed_tx(
191        &mut self,
192        message: &impl SVMMessage,
193        executed_transaction: &ExecutedTransaction,
194    ) {
195        if executed_transaction.was_successful() {
196            self.update_accounts_for_successful_tx(
197                message,
198                &executed_transaction.loaded_transaction.accounts,
199            );
200        } else {
201            self.update_accounts_for_failed_tx(
202                message,
203                &executed_transaction.loaded_transaction.rollback_accounts,
204            );
205        }
206    }
207
208    pub(crate) fn update_accounts_for_failed_tx(
209        &mut self,
210        message: &impl SVMMessage,
211        rollback_accounts: &RollbackAccounts,
212    ) {
213        let fee_payer_address = message.fee_payer();
214        match rollback_accounts {
215            RollbackAccounts::FeePayerOnly { fee_payer_account } => {
216                self.account_cache
217                    .insert(*fee_payer_address, fee_payer_account.clone());
218            }
219            RollbackAccounts::SameNonceAndFeePayer { nonce } => {
220                self.account_cache
221                    .insert(*nonce.address(), nonce.account().clone());
222            }
223            RollbackAccounts::SeparateNonceAndFeePayer {
224                nonce,
225                fee_payer_account,
226            } => {
227                self.account_cache
228                    .insert(*nonce.address(), nonce.account().clone());
229                self.account_cache
230                    .insert(*fee_payer_address, fee_payer_account.clone());
231            }
232        }
233    }
234
235    fn update_accounts_for_successful_tx(
236        &mut self,
237        message: &impl SVMMessage,
238        transaction_accounts: &[TransactionAccount],
239    ) {
240        for (i, (address, account)) in (0..message.account_keys().len()).zip(transaction_accounts) {
241            if !message.is_writable(i) {
242                continue;
243            }
244
245            // Accounts that are invoked and also not passed as an instruction
246            // account to a program don't need to be stored because it's assumed
247            // to be impossible for a committable transaction to modify an
248            // invoked account if said account isn't passed to some program.
249            if message.is_invoked(i) && !message.is_instruction_account(i) {
250                continue;
251            }
252
253            self.account_cache.insert(*address, account.clone());
254        }
255    }
256}
257
258/// Collect rent from an account if rent is still enabled and regardless of
259/// whether rent is enabled, set the rent epoch to u64::MAX if the account is
260/// rent exempt.
261pub fn collect_rent_from_account(
262    feature_set: &FeatureSet,
263    rent_collector: &dyn SVMRentCollector,
264    address: &Pubkey,
265    account: &mut AccountSharedData,
266) -> CollectedInfo {
267    if !feature_set.is_active(&feature_set::disable_rent_fees_collection::id()) {
268        rent_collector.collect_rent(address, account)
269    } else {
270        // When rent fee collection is disabled, we won't collect rent for any account. If there
271        // are any rent paying accounts, their `rent_epoch` won't change either. However, if the
272        // account itself is rent-exempted but its `rent_epoch` is not u64::MAX, we will set its
273        // `rent_epoch` to u64::MAX. In such case, the behavior stays the same as before.
274        if account.rent_epoch() != RENT_EXEMPT_RENT_EPOCH
275            && rent_collector.get_rent_due(
276                account.lamports(),
277                account.data().len(),
278                account.rent_epoch(),
279            ) == RentDue::Exempt
280        {
281            account.set_rent_epoch(RENT_EXEMPT_RENT_EPOCH);
282        }
283
284        CollectedInfo::default()
285    }
286}
287
288/// Check whether the payer_account is capable of paying the fee. The
289/// side effect is to subtract the fee amount from the payer_account
290/// balance of lamports. If the payer_acount is not able to pay the
291/// fee, the error_metrics is incremented, and a specific error is
292/// returned.
293pub fn validate_fee_payer(
294    payer_address: &Pubkey,
295    payer_account: &mut AccountSharedData,
296    payer_index: IndexOfAccount,
297    error_metrics: &mut TransactionErrorMetrics,
298    rent_collector: &dyn SVMRentCollector,
299    fee: u64,
300) -> Result<()> {
301    if payer_account.lamports() == 0 {
302        error_metrics.account_not_found += 1;
303        return Err(TransactionError::AccountNotFound);
304    }
305    let system_account_kind = get_system_account_kind(payer_account).ok_or_else(|| {
306        error_metrics.invalid_account_for_fee += 1;
307        TransactionError::InvalidAccountForFee
308    })?;
309    let min_balance = match system_account_kind {
310        SystemAccountKind::System => 0,
311        SystemAccountKind::Nonce => {
312            // Should we ever allow a fees charge to zero a nonce account's
313            // balance. The state MUST be set to uninitialized in that case
314            rent_collector
315                .get_rent()
316                .minimum_balance(NonceState::size())
317        }
318    };
319
320    payer_account
321        .lamports()
322        .checked_sub(min_balance)
323        .and_then(|v| v.checked_sub(fee))
324        .ok_or_else(|| {
325            error_metrics.insufficient_funds += 1;
326            TransactionError::InsufficientFundsForFee
327        })?;
328
329    let payer_pre_rent_state = rent_collector.get_account_rent_state(payer_account);
330    payer_account
331        .checked_sub_lamports(fee)
332        .map_err(|_| TransactionError::InsufficientFundsForFee)?;
333
334    let payer_post_rent_state = rent_collector.get_account_rent_state(payer_account);
335    rent_collector.check_rent_state_with_account(
336        &payer_pre_rent_state,
337        &payer_post_rent_state,
338        payer_address,
339        payer_account,
340        payer_index,
341    )
342}
343
344pub(crate) fn load_transaction<CB: TransactionProcessingCallback>(
345    account_loader: &mut AccountLoader<CB>,
346    message: &impl SVMMessage,
347    validation_result: TransactionValidationResult,
348    error_metrics: &mut TransactionErrorMetrics,
349    rent_collector: &dyn SVMRentCollector,
350) -> TransactionLoadResult {
351    match validation_result {
352        Err(e) => TransactionLoadResult::NotLoaded(e),
353        Ok(tx_details) => {
354            let load_result = load_transaction_accounts(
355                account_loader,
356                message,
357                tx_details.loaded_fee_payer_account,
358                &tx_details.compute_budget_limits,
359                error_metrics,
360                rent_collector,
361            );
362
363            match load_result {
364                Ok(loaded_tx_accounts) => TransactionLoadResult::Loaded(LoadedTransaction {
365                    accounts: loaded_tx_accounts.accounts,
366                    program_indices: loaded_tx_accounts.program_indices,
367                    fee_details: tx_details.fee_details,
368                    rent: loaded_tx_accounts.rent,
369                    rent_debits: loaded_tx_accounts.rent_debits,
370                    rollback_accounts: tx_details.rollback_accounts,
371                    compute_budget_limits: tx_details.compute_budget_limits,
372                    loaded_accounts_data_size: loaded_tx_accounts.loaded_accounts_data_size,
373                }),
374                Err(err) => TransactionLoadResult::FeesOnly(FeesOnlyTransaction {
375                    load_error: err,
376                    fee_details: tx_details.fee_details,
377                    rollback_accounts: tx_details.rollback_accounts,
378                }),
379            }
380        }
381    }
382}
383
384#[derive(PartialEq, Eq, Debug, Clone)]
385struct LoadedTransactionAccounts {
386    pub(crate) accounts: Vec<TransactionAccount>,
387    pub(crate) program_indices: TransactionProgramIndices,
388    pub(crate) rent: TransactionRent,
389    pub(crate) rent_debits: RentDebits,
390    pub(crate) loaded_accounts_data_size: u32,
391}
392
393fn load_transaction_accounts<CB: TransactionProcessingCallback>(
394    account_loader: &mut AccountLoader<CB>,
395    message: &impl SVMMessage,
396    loaded_fee_payer_account: LoadedTransactionAccount,
397    compute_budget_limits: &ComputeBudgetLimits,
398    error_metrics: &mut TransactionErrorMetrics,
399    rent_collector: &dyn SVMRentCollector,
400) -> Result<LoadedTransactionAccounts> {
401    let mut tx_rent: TransactionRent = 0;
402    let account_keys = message.account_keys();
403    let mut accounts = Vec::with_capacity(account_keys.len());
404    let mut validated_loaders = AHashSet::with_capacity(PROGRAM_OWNERS.len());
405    let mut rent_debits = RentDebits::default();
406    let mut accumulated_accounts_data_size: Saturating<u32> = Saturating(0);
407
408    let mut collect_loaded_account = |key, loaded_account| -> Result<()> {
409        let LoadedTransactionAccount {
410            account,
411            loaded_size,
412            rent_collected,
413        } = loaded_account;
414
415        accumulate_and_check_loaded_account_data_size(
416            &mut accumulated_accounts_data_size,
417            loaded_size,
418            compute_budget_limits.loaded_accounts_bytes,
419            error_metrics,
420        )?;
421
422        tx_rent += rent_collected;
423        rent_debits.insert(key, rent_collected, account.lamports());
424
425        accounts.push((*key, account));
426        Ok(())
427    };
428
429    // Since the fee payer is always the first account, collect it first.
430    // We can use it directly because it was already loaded during validation.
431    collect_loaded_account(message.fee_payer(), loaded_fee_payer_account)?;
432
433    // Attempt to load and collect remaining non-fee payer accounts
434    for (account_index, account_key) in account_keys.iter().enumerate().skip(1) {
435        let loaded_account = load_transaction_account(
436            account_loader,
437            message,
438            account_key,
439            account_index,
440            rent_collector,
441        );
442        collect_loaded_account(account_key, loaded_account)?;
443    }
444
445    let program_indices = message
446        .program_instructions_iter()
447        .map(|(program_id, instruction)| {
448            let mut account_indices = Vec::with_capacity(2);
449            if native_loader::check_id(program_id) {
450                return Ok(account_indices);
451            }
452
453            let program_index = instruction.program_id_index as usize;
454
455            let Some(LoadedTransactionAccount {
456                account: program_account,
457                ..
458            }) = account_loader.load_account(program_id, false)
459            else {
460                error_metrics.account_not_found += 1;
461                return Err(TransactionError::ProgramAccountNotFound);
462            };
463
464            if !account_loader
465                .feature_set
466                .is_active(&feature_set::remove_accounts_executable_flag_checks::id())
467                && !program_account.executable()
468            {
469                error_metrics.invalid_program_for_execution += 1;
470                return Err(TransactionError::InvalidProgramForExecution);
471            }
472            account_indices.insert(0, program_index as IndexOfAccount);
473
474            let owner_id = program_account.owner();
475            if native_loader::check_id(owner_id) {
476                return Ok(account_indices);
477            }
478
479            if !validated_loaders.contains(owner_id) {
480                // NOTE there are several feature gate activations that affect this code:
481                // * `remove_accounts_executable_flag_checks`: this implicitly makes system, vote, stake, et al valid loaders
482                //   it is impossible to mark an account executable and also have it be owned by one of them
483                //   so, with the feature disabled, we always fail the executable check if they are a program id owner
484                //   however, with the feature enabled, any account owned by an account owned by native loader is a "program"
485                //   this is benign (any such transaction will fail at execution) but it affects which transactions pay fees
486                // * `enable_transaction_loading_failure_fees`: loading failures behave the same as execution failures
487                //   at this point we can restrict valid loaders to those contained in `PROGRAM_OWNERS`
488                //   since any other pseudo-loader owner is destined to fail at execution
489                // * SIMD-186: explicitly defines a sensible transaction data size algorithm
490                //   at this point we stop counting loaders toward transaction data size entirely
491                //
492                // when _all three_ of `remove_accounts_executable_flag_checks`, `enable_transaction_loading_failure_fees`,
493                // and SIMD-186 are active, we do not need to load loaders at all to comply with consensus rules
494                // we may verify program ids are owned by `PROGRAM_OWNERS` purely as an optimization
495                // this could even be done before loading the rest of the accounts for a transaction
496                if let Some(LoadedTransactionAccount {
497                    account: owner_account,
498                    loaded_size: owner_size,
499                    ..
500                }) = account_loader.load_account(owner_id, false)
501                {
502                    if !native_loader::check_id(owner_account.owner())
503                        || (!account_loader
504                            .feature_set
505                            .is_active(&feature_set::remove_accounts_executable_flag_checks::id())
506                            && !owner_account.executable())
507                    {
508                        error_metrics.invalid_program_for_execution += 1;
509                        return Err(TransactionError::InvalidProgramForExecution);
510                    }
511                    accumulate_and_check_loaded_account_data_size(
512                        &mut accumulated_accounts_data_size,
513                        owner_size,
514                        compute_budget_limits.loaded_accounts_bytes,
515                        error_metrics,
516                    )?;
517                    validated_loaders.insert(*owner_id);
518                } else {
519                    error_metrics.account_not_found += 1;
520                    return Err(TransactionError::ProgramAccountNotFound);
521                }
522            }
523            Ok(account_indices)
524        })
525        .collect::<Result<Vec<Vec<IndexOfAccount>>>>()?;
526
527    Ok(LoadedTransactionAccounts {
528        accounts,
529        program_indices,
530        rent: tx_rent,
531        rent_debits,
532        loaded_accounts_data_size: accumulated_accounts_data_size.0,
533    })
534}
535
536fn load_transaction_account<CB: TransactionProcessingCallback>(
537    account_loader: &mut AccountLoader<CB>,
538    message: &impl SVMMessage,
539    account_key: &Pubkey,
540    account_index: usize,
541    rent_collector: &dyn SVMRentCollector,
542) -> LoadedTransactionAccount {
543    let is_writable = message.is_writable(account_index);
544    let loaded_account = if solana_sdk_ids::sysvar::instructions::check_id(account_key) {
545        // Since the instructions sysvar is constructed by the SVM and modified
546        // for each transaction instruction, it cannot be loaded.
547        LoadedTransactionAccount {
548            loaded_size: 0,
549            account: construct_instructions_account(message),
550            rent_collected: 0,
551        }
552    } else if let Some(mut loaded_account) = account_loader.load_account(account_key, is_writable) {
553        loaded_account.rent_collected = if is_writable {
554            collect_rent_from_account(
555                &account_loader.feature_set,
556                rent_collector,
557                account_key,
558                &mut loaded_account.account,
559            )
560            .rent_amount
561        } else {
562            0
563        };
564
565        loaded_account
566    } else {
567        let mut default_account = AccountSharedData::default();
568        // All new accounts must be rent-exempt (enforced in Bank::execute_loaded_transaction).
569        // Currently, rent collection sets rent_epoch to u64::MAX, but initializing the account
570        // with this field already set would allow us to skip rent collection for these accounts.
571        default_account.set_rent_epoch(RENT_EXEMPT_RENT_EPOCH);
572        LoadedTransactionAccount {
573            loaded_size: default_account.data().len(),
574            account: default_account,
575            rent_collected: 0,
576        }
577    };
578
579    loaded_account
580}
581
582/// Accumulate loaded account data size into `accumulated_accounts_data_size`.
583/// Returns TransactionErr::MaxLoadedAccountsDataSizeExceeded if
584/// `accumulated_accounts_data_size` exceeds
585/// `requested_loaded_accounts_data_size_limit`.
586fn accumulate_and_check_loaded_account_data_size(
587    accumulated_loaded_accounts_data_size: &mut Saturating<u32>,
588    account_data_size: usize,
589    requested_loaded_accounts_data_size_limit: NonZeroU32,
590    error_metrics: &mut TransactionErrorMetrics,
591) -> Result<()> {
592    let Ok(account_data_size) = u32::try_from(account_data_size) else {
593        error_metrics.max_loaded_accounts_data_size_exceeded += 1;
594        return Err(TransactionError::MaxLoadedAccountsDataSizeExceeded);
595    };
596    *accumulated_loaded_accounts_data_size += account_data_size;
597    if accumulated_loaded_accounts_data_size.0 > requested_loaded_accounts_data_size_limit.get() {
598        error_metrics.max_loaded_accounts_data_size_exceeded += 1;
599        Err(TransactionError::MaxLoadedAccountsDataSizeExceeded)
600    } else {
601        Ok(())
602    }
603}
604
605fn construct_instructions_account(message: &impl SVMMessage) -> AccountSharedData {
606    let account_keys = message.account_keys();
607    let mut decompiled_instructions = Vec::with_capacity(message.num_instructions());
608    for (program_id, instruction) in message.program_instructions_iter() {
609        let accounts = instruction
610            .accounts
611            .iter()
612            .map(|account_index| {
613                let account_index = usize::from(*account_index);
614                BorrowedAccountMeta {
615                    is_signer: message.is_signer(account_index),
616                    is_writable: message.is_writable(account_index),
617                    pubkey: account_keys.get(account_index).unwrap(),
618                }
619            })
620            .collect();
621
622        decompiled_instructions.push(BorrowedInstruction {
623            accounts,
624            data: instruction.data,
625            program_id,
626        });
627    }
628
629    AccountSharedData::from(Account {
630        data: construct_instructions_data(&decompiled_instructions),
631        owner: sysvar::id(),
632        ..Account::default()
633    })
634}
635
636#[cfg(test)]
637mod tests {
638    use {
639        super::*,
640        crate::{
641            transaction_account_state_info::TransactionAccountStateInfo,
642            transaction_processing_callback::TransactionProcessingCallback,
643        },
644        solana_account::{Account, AccountSharedData, ReadableAccount, WritableAccount},
645        solana_compute_budget::{compute_budget::ComputeBudget, compute_budget_limits},
646        solana_epoch_schedule::EpochSchedule,
647        solana_feature_set::FeatureSet,
648        solana_hash::Hash,
649        solana_instruction::{AccountMeta, Instruction},
650        solana_keypair::Keypair,
651        solana_message::{
652            compiled_instruction::CompiledInstruction,
653            v0::{LoadedAddresses, LoadedMessage},
654            LegacyMessage, Message, MessageHeader, SanitizedMessage,
655        },
656        solana_native_token::{sol_to_lamports, LAMPORTS_PER_SOL},
657        solana_nonce::{self as nonce, versions::Versions as NonceVersions},
658        solana_program::bpf_loader_upgradeable::UpgradeableLoaderState,
659        solana_pubkey::Pubkey,
660        solana_rent::Rent,
661        solana_rent_debits::RentDebits,
662        solana_reserved_account_keys::ReservedAccountKeys,
663        solana_sdk::rent_collector::{RentCollector, RENT_EXEMPT_RENT_EPOCH},
664        solana_sdk_ids::{
665            bpf_loader, bpf_loader_upgradeable, native_loader, system_program, sysvar,
666        },
667        solana_signature::Signature,
668        solana_signer::Signer,
669        solana_system_transaction::transfer,
670        solana_transaction::{sanitized::SanitizedTransaction, Transaction},
671        solana_transaction_context::{TransactionAccount, TransactionContext},
672        solana_transaction_error::{TransactionError, TransactionResult as Result},
673        std::{borrow::Cow, cell::RefCell, collections::HashMap, fs::File, io::Read, sync::Arc},
674    };
675
676    #[derive(Clone, Default)]
677    struct TestCallbacks {
678        accounts_map: HashMap<Pubkey, AccountSharedData>,
679        #[allow(clippy::type_complexity)]
680        inspected_accounts:
681            RefCell<HashMap<Pubkey, Vec<(Option<AccountSharedData>, /* is_writable */ bool)>>>,
682    }
683
684    impl TransactionProcessingCallback for TestCallbacks {
685        fn account_matches_owners(&self, _account: &Pubkey, _owners: &[Pubkey]) -> Option<usize> {
686            None
687        }
688
689        fn get_account_shared_data(&self, pubkey: &Pubkey) -> Option<AccountSharedData> {
690            self.accounts_map.get(pubkey).cloned()
691        }
692
693        fn inspect_account(
694            &self,
695            address: &Pubkey,
696            account_state: AccountState,
697            is_writable: bool,
698        ) {
699            let account = match account_state {
700                AccountState::Dead => None,
701                AccountState::Alive(account) => Some(account.clone()),
702            };
703            self.inspected_accounts
704                .borrow_mut()
705                .entry(*address)
706                .or_default()
707                .push((account, is_writable));
708        }
709    }
710
711    impl<'a> From<&'a TestCallbacks> for AccountLoader<'a, TestCallbacks> {
712        fn from(callbacks: &'a TestCallbacks) -> AccountLoader<'a, TestCallbacks> {
713            AccountLoader::new_with_account_cache_capacity(
714                None,
715                callbacks,
716                Arc::<FeatureSet>::default(),
717                0,
718            )
719        }
720    }
721
722    fn load_accounts_with_features_and_rent(
723        tx: Transaction,
724        accounts: &[TransactionAccount],
725        rent_collector: &RentCollector,
726        error_metrics: &mut TransactionErrorMetrics,
727        feature_set: &mut FeatureSet,
728    ) -> TransactionLoadResult {
729        feature_set.deactivate(&feature_set::disable_rent_fees_collection::id());
730        let sanitized_tx = SanitizedTransaction::from_transaction_for_tests(tx);
731        let fee_payer_account = accounts[0].1.clone();
732        let mut accounts_map = HashMap::new();
733        for (pubkey, account) in accounts {
734            accounts_map.insert(*pubkey, account.clone());
735        }
736        let callbacks = TestCallbacks {
737            accounts_map,
738            ..Default::default()
739        };
740        let mut account_loader: AccountLoader<TestCallbacks> = (&callbacks).into();
741        account_loader.feature_set = Arc::new(feature_set.clone());
742        load_transaction(
743            &mut account_loader,
744            &sanitized_tx,
745            Ok(ValidatedTransactionDetails {
746                loaded_fee_payer_account: LoadedTransactionAccount {
747                    account: fee_payer_account,
748                    ..LoadedTransactionAccount::default()
749                },
750                ..ValidatedTransactionDetails::default()
751            }),
752            error_metrics,
753            rent_collector,
754        )
755    }
756
757    /// get a feature set with all features activated
758    /// with the optional except of 'exclude'
759    fn all_features_except(exclude: Option<&[Pubkey]>) -> FeatureSet {
760        let mut features = FeatureSet::all_enabled();
761        if let Some(exclude) = exclude {
762            features.active.retain(|k, _v| !exclude.contains(k));
763        }
764        features
765    }
766
767    fn new_unchecked_sanitized_message(message: Message) -> SanitizedMessage {
768        SanitizedMessage::Legacy(LegacyMessage::new(
769            message,
770            &ReservedAccountKeys::empty_key_set(),
771        ))
772    }
773
774    fn load_accounts_aux_test(
775        tx: Transaction,
776        accounts: &[TransactionAccount],
777        error_metrics: &mut TransactionErrorMetrics,
778    ) -> TransactionLoadResult {
779        load_accounts_with_features_and_rent(
780            tx,
781            accounts,
782            &RentCollector::default(),
783            error_metrics,
784            &mut FeatureSet::all_enabled(),
785        )
786    }
787
788    fn load_accounts_with_excluded_features(
789        tx: Transaction,
790        accounts: &[TransactionAccount],
791        error_metrics: &mut TransactionErrorMetrics,
792        exclude_features: Option<&[Pubkey]>,
793    ) -> TransactionLoadResult {
794        load_accounts_with_features_and_rent(
795            tx,
796            accounts,
797            &RentCollector::default(),
798            error_metrics,
799            &mut all_features_except(exclude_features),
800        )
801    }
802
803    #[test]
804    fn test_load_accounts_unknown_program_id() {
805        let mut accounts: Vec<TransactionAccount> = Vec::new();
806        let mut error_metrics = TransactionErrorMetrics::default();
807
808        let keypair = Keypair::new();
809        let key0 = keypair.pubkey();
810        let key1 = Pubkey::from([5u8; 32]);
811
812        let account = AccountSharedData::new(1, 0, &Pubkey::default());
813        accounts.push((key0, account));
814
815        let account = AccountSharedData::new(2, 1, &Pubkey::default());
816        accounts.push((key1, account));
817
818        let instructions = vec![CompiledInstruction::new(1, &(), vec![0])];
819        let tx = Transaction::new_with_compiled_instructions(
820            &[&keypair],
821            &[],
822            Hash::default(),
823            vec![Pubkey::default()],
824            instructions,
825        );
826
827        let load_results = load_accounts_aux_test(tx, &accounts, &mut error_metrics);
828
829        assert_eq!(error_metrics.account_not_found.0, 1);
830        assert!(matches!(
831            load_results,
832            TransactionLoadResult::FeesOnly(FeesOnlyTransaction {
833                load_error: TransactionError::ProgramAccountNotFound,
834                ..
835            }),
836        ));
837    }
838
839    #[test]
840    fn test_load_accounts_no_loaders() {
841        let mut accounts: Vec<TransactionAccount> = Vec::new();
842        let mut error_metrics = TransactionErrorMetrics::default();
843
844        let keypair = Keypair::new();
845        let key0 = keypair.pubkey();
846        let key1 = Pubkey::from([5u8; 32]);
847
848        let mut account = AccountSharedData::new(1, 0, &Pubkey::default());
849        account.set_rent_epoch(1);
850        accounts.push((key0, account));
851
852        let mut account = AccountSharedData::new(2, 1, &Pubkey::default());
853        account.set_rent_epoch(1);
854        accounts.push((key1, account));
855
856        let instructions = vec![CompiledInstruction::new(2, &(), vec![0, 1])];
857        let tx = Transaction::new_with_compiled_instructions(
858            &[&keypair],
859            &[key1],
860            Hash::default(),
861            vec![native_loader::id()],
862            instructions,
863        );
864
865        let loaded_accounts =
866            load_accounts_with_excluded_features(tx, &accounts, &mut error_metrics, None);
867
868        assert_eq!(error_metrics.account_not_found.0, 0);
869        match &loaded_accounts {
870            TransactionLoadResult::Loaded(loaded_transaction) => {
871                assert_eq!(loaded_transaction.accounts.len(), 3);
872                assert_eq!(loaded_transaction.accounts[0].1, accounts[0].1);
873                assert_eq!(loaded_transaction.program_indices.len(), 1);
874                assert_eq!(loaded_transaction.program_indices[0].len(), 0);
875            }
876            TransactionLoadResult::FeesOnly(fees_only_tx) => panic!("{}", fees_only_tx.load_error),
877            TransactionLoadResult::NotLoaded(e) => panic!("{e}"),
878        }
879    }
880
881    #[test]
882    fn test_load_accounts_bad_owner() {
883        let mut accounts: Vec<TransactionAccount> = Vec::new();
884        let mut error_metrics = TransactionErrorMetrics::default();
885
886        let keypair = Keypair::new();
887        let key0 = keypair.pubkey();
888        let key1 = Pubkey::from([5u8; 32]);
889
890        let account = AccountSharedData::new(1, 0, &Pubkey::default());
891        accounts.push((key0, account));
892
893        let mut account = AccountSharedData::new(40, 1, &Pubkey::default());
894        account.set_owner(bpf_loader_upgradeable::id());
895        account.set_executable(true);
896        accounts.push((key1, account));
897
898        let instructions = vec![CompiledInstruction::new(1, &(), vec![0])];
899        let tx = Transaction::new_with_compiled_instructions(
900            &[&keypair],
901            &[],
902            Hash::default(),
903            vec![key1],
904            instructions,
905        );
906
907        let load_results = load_accounts_aux_test(tx, &accounts, &mut error_metrics);
908
909        assert_eq!(error_metrics.account_not_found.0, 1);
910        assert!(matches!(
911            load_results,
912            TransactionLoadResult::FeesOnly(FeesOnlyTransaction {
913                load_error: TransactionError::ProgramAccountNotFound,
914                ..
915            }),
916        ));
917    }
918
919    #[test]
920    fn test_load_accounts_not_executable() {
921        let mut accounts: Vec<TransactionAccount> = Vec::new();
922        let mut error_metrics = TransactionErrorMetrics::default();
923
924        let keypair = Keypair::new();
925        let key0 = keypair.pubkey();
926        let key1 = Pubkey::from([5u8; 32]);
927
928        let account = AccountSharedData::new(1, 0, &Pubkey::default());
929        accounts.push((key0, account));
930
931        let account = AccountSharedData::new(40, 0, &native_loader::id());
932        accounts.push((key1, account));
933
934        let instructions = vec![CompiledInstruction::new(1, &(), vec![0])];
935        let tx = Transaction::new_with_compiled_instructions(
936            &[&keypair],
937            &[],
938            Hash::default(),
939            vec![key1],
940            instructions,
941        );
942
943        let mut feature_set = FeatureSet::all_enabled();
944        feature_set.deactivate(&feature_set::remove_accounts_executable_flag_checks::id());
945        let load_results = load_accounts_with_features_and_rent(
946            tx,
947            &accounts,
948            &RentCollector::default(),
949            &mut error_metrics,
950            &mut feature_set,
951        );
952
953        assert_eq!(error_metrics.invalid_program_for_execution.0, 1);
954        assert!(matches!(
955            load_results,
956            TransactionLoadResult::FeesOnly(FeesOnlyTransaction {
957                load_error: TransactionError::InvalidProgramForExecution,
958                ..
959            }),
960        ));
961    }
962
963    #[test]
964    fn test_load_accounts_multiple_loaders() {
965        let mut accounts: Vec<TransactionAccount> = Vec::new();
966        let mut error_metrics = TransactionErrorMetrics::default();
967
968        let keypair = Keypair::new();
969        let key0 = keypair.pubkey();
970        let key1 = bpf_loader_upgradeable::id();
971        let key2 = Pubkey::from([6u8; 32]);
972
973        let mut account = AccountSharedData::new(1, 0, &Pubkey::default());
974        account.set_rent_epoch(1);
975        accounts.push((key0, account));
976
977        let mut account = AccountSharedData::new(40, 1, &Pubkey::default());
978        account.set_executable(true);
979        account.set_rent_epoch(1);
980        account.set_owner(native_loader::id());
981        accounts.push((key1, account));
982
983        let mut account = AccountSharedData::new(41, 1, &Pubkey::default());
984        account.set_executable(true);
985        account.set_rent_epoch(1);
986        account.set_owner(key1);
987        accounts.push((key2, account));
988
989        let instructions = vec![
990            CompiledInstruction::new(1, &(), vec![0]),
991            CompiledInstruction::new(2, &(), vec![0]),
992        ];
993        let tx = Transaction::new_with_compiled_instructions(
994            &[&keypair],
995            &[],
996            Hash::default(),
997            vec![key1, key2],
998            instructions,
999        );
1000
1001        let loaded_accounts =
1002            load_accounts_with_excluded_features(tx, &accounts, &mut error_metrics, None);
1003
1004        assert_eq!(error_metrics.account_not_found.0, 0);
1005        match &loaded_accounts {
1006            TransactionLoadResult::Loaded(loaded_transaction) => {
1007                assert_eq!(loaded_transaction.accounts.len(), 3);
1008                assert_eq!(loaded_transaction.accounts[0].1, accounts[0].1);
1009                assert_eq!(loaded_transaction.program_indices.len(), 2);
1010                assert_eq!(loaded_transaction.program_indices[0], &[1]);
1011                assert_eq!(loaded_transaction.program_indices[1], &[2]);
1012            }
1013            TransactionLoadResult::FeesOnly(fees_only_tx) => panic!("{}", fees_only_tx.load_error),
1014            TransactionLoadResult::NotLoaded(e) => panic!("{e}"),
1015        }
1016    }
1017
1018    fn load_accounts_no_store(
1019        accounts: &[TransactionAccount],
1020        tx: Transaction,
1021        account_overrides: Option<&AccountOverrides>,
1022    ) -> TransactionLoadResult {
1023        let tx = SanitizedTransaction::from_transaction_for_tests(tx);
1024
1025        let mut error_metrics = TransactionErrorMetrics::default();
1026        let mut accounts_map = HashMap::new();
1027        for (pubkey, account) in accounts {
1028            accounts_map.insert(*pubkey, account.clone());
1029        }
1030        let callbacks = TestCallbacks {
1031            accounts_map,
1032            ..Default::default()
1033        };
1034        let mut account_loader = AccountLoader::new_with_account_cache_capacity(
1035            account_overrides,
1036            &callbacks,
1037            Arc::new(FeatureSet::all_enabled()),
1038            0,
1039        );
1040        load_transaction(
1041            &mut account_loader,
1042            &tx,
1043            Ok(ValidatedTransactionDetails::default()),
1044            &mut error_metrics,
1045            &RentCollector::default(),
1046        )
1047    }
1048
1049    #[test]
1050    fn test_instructions() {
1051        solana_logger::setup();
1052        let instructions_key = solana_sdk_ids::sysvar::instructions::id();
1053        let keypair = Keypair::new();
1054        let instructions = vec![CompiledInstruction::new(1, &(), vec![0, 1])];
1055        let tx = Transaction::new_with_compiled_instructions(
1056            &[&keypair],
1057            &[solana_pubkey::new_rand(), instructions_key],
1058            Hash::default(),
1059            vec![native_loader::id()],
1060            instructions,
1061        );
1062
1063        let load_results = load_accounts_no_store(&[], tx, None);
1064        assert!(matches!(
1065            load_results,
1066            TransactionLoadResult::FeesOnly(FeesOnlyTransaction {
1067                load_error: TransactionError::ProgramAccountNotFound,
1068                ..
1069            }),
1070        ));
1071    }
1072
1073    #[test]
1074    fn test_overrides() {
1075        solana_logger::setup();
1076        let mut account_overrides = AccountOverrides::default();
1077        let slot_history_id = sysvar::slot_history::id();
1078        let account = AccountSharedData::new(42, 0, &Pubkey::default());
1079        account_overrides.set_slot_history(Some(account));
1080
1081        let keypair = Keypair::new();
1082        let account = AccountSharedData::new(1_000_000, 0, &Pubkey::default());
1083
1084        let instructions = vec![CompiledInstruction::new(2, &(), vec![0])];
1085        let tx = Transaction::new_with_compiled_instructions(
1086            &[&keypair],
1087            &[slot_history_id],
1088            Hash::default(),
1089            vec![native_loader::id()],
1090            instructions,
1091        );
1092
1093        let loaded_accounts =
1094            load_accounts_no_store(&[(keypair.pubkey(), account)], tx, Some(&account_overrides));
1095        match &loaded_accounts {
1096            TransactionLoadResult::Loaded(loaded_transaction) => {
1097                assert_eq!(loaded_transaction.accounts[0].0, keypair.pubkey());
1098                assert_eq!(loaded_transaction.accounts[1].0, slot_history_id);
1099                assert_eq!(loaded_transaction.accounts[1].1.lamports(), 42);
1100            }
1101            TransactionLoadResult::FeesOnly(fees_only_tx) => panic!("{}", fees_only_tx.load_error),
1102            TransactionLoadResult::NotLoaded(e) => panic!("{e}"),
1103        }
1104    }
1105
1106    #[test]
1107    fn test_accumulate_and_check_loaded_account_data_size() {
1108        let mut error_metrics = TransactionErrorMetrics::default();
1109        let mut accumulated_data_size: Saturating<u32> = Saturating(0);
1110        let data_size: usize = 123;
1111        let requested_data_size_limit = NonZeroU32::new(data_size as u32).unwrap();
1112
1113        // OK - loaded data size is up to limit
1114        assert!(accumulate_and_check_loaded_account_data_size(
1115            &mut accumulated_data_size,
1116            data_size,
1117            requested_data_size_limit,
1118            &mut error_metrics
1119        )
1120        .is_ok());
1121        assert_eq!(data_size as u32, accumulated_data_size.0);
1122
1123        // fail - loading more data that would exceed limit
1124        let another_byte: usize = 1;
1125        assert_eq!(
1126            accumulate_and_check_loaded_account_data_size(
1127                &mut accumulated_data_size,
1128                another_byte,
1129                requested_data_size_limit,
1130                &mut error_metrics
1131            ),
1132            Err(TransactionError::MaxLoadedAccountsDataSizeExceeded)
1133        );
1134    }
1135
1136    struct ValidateFeePayerTestParameter {
1137        is_nonce: bool,
1138        payer_init_balance: u64,
1139        fee: u64,
1140        expected_result: Result<()>,
1141        payer_post_balance: u64,
1142    }
1143    fn validate_fee_payer_account(
1144        test_parameter: ValidateFeePayerTestParameter,
1145        rent_collector: &RentCollector,
1146    ) {
1147        let payer_account_keys = Keypair::new();
1148        let mut account = if test_parameter.is_nonce {
1149            AccountSharedData::new_data(
1150                test_parameter.payer_init_balance,
1151                &NonceVersions::new(NonceState::Initialized(nonce::state::Data::default())),
1152                &system_program::id(),
1153            )
1154            .unwrap()
1155        } else {
1156            AccountSharedData::new(test_parameter.payer_init_balance, 0, &system_program::id())
1157        };
1158        let result = validate_fee_payer(
1159            &payer_account_keys.pubkey(),
1160            &mut account,
1161            0,
1162            &mut TransactionErrorMetrics::default(),
1163            rent_collector,
1164            test_parameter.fee,
1165        );
1166
1167        assert_eq!(result, test_parameter.expected_result);
1168        assert_eq!(account.lamports(), test_parameter.payer_post_balance);
1169    }
1170
1171    #[test]
1172    fn test_validate_fee_payer() {
1173        let rent_collector = RentCollector::new(
1174            0,
1175            EpochSchedule::default(),
1176            500_000.0,
1177            Rent {
1178                lamports_per_byte_year: 1,
1179                ..Rent::default()
1180            },
1181        );
1182        let min_balance = rent_collector.rent.minimum_balance(NonceState::size());
1183        let fee = 5_000;
1184
1185        // If payer account has sufficient balance, expect successful fee deduction,
1186        // regardless feature gate status, or if payer is nonce account.
1187        {
1188            for (is_nonce, min_balance) in [(true, min_balance), (false, 0)] {
1189                validate_fee_payer_account(
1190                    ValidateFeePayerTestParameter {
1191                        is_nonce,
1192                        payer_init_balance: min_balance + fee,
1193                        fee,
1194                        expected_result: Ok(()),
1195                        payer_post_balance: min_balance,
1196                    },
1197                    &rent_collector,
1198                );
1199            }
1200        }
1201
1202        // If payer account has no balance, expected AccountNotFound Error
1203        // regardless feature gate status, or if payer is nonce account.
1204        {
1205            for is_nonce in [true, false] {
1206                validate_fee_payer_account(
1207                    ValidateFeePayerTestParameter {
1208                        is_nonce,
1209                        payer_init_balance: 0,
1210                        fee,
1211                        expected_result: Err(TransactionError::AccountNotFound),
1212                        payer_post_balance: 0,
1213                    },
1214                    &rent_collector,
1215                );
1216            }
1217        }
1218
1219        // If payer account has insufficient balance, expect InsufficientFundsForFee error
1220        // regardless feature gate status, or if payer is nonce account.
1221        {
1222            for (is_nonce, min_balance) in [(true, min_balance), (false, 0)] {
1223                validate_fee_payer_account(
1224                    ValidateFeePayerTestParameter {
1225                        is_nonce,
1226                        payer_init_balance: min_balance + fee - 1,
1227                        fee,
1228                        expected_result: Err(TransactionError::InsufficientFundsForFee),
1229                        payer_post_balance: min_balance + fee - 1,
1230                    },
1231                    &rent_collector,
1232                );
1233            }
1234        }
1235
1236        // normal payer account has balance of u64::MAX, so does fee; since it does not  require
1237        // min_balance, expect successful fee deduction, regardless of feature gate status
1238        {
1239            validate_fee_payer_account(
1240                ValidateFeePayerTestParameter {
1241                    is_nonce: false,
1242                    payer_init_balance: u64::MAX,
1243                    fee: u64::MAX,
1244                    expected_result: Ok(()),
1245                    payer_post_balance: 0,
1246                },
1247                &rent_collector,
1248            );
1249        }
1250    }
1251
1252    #[test]
1253    fn test_validate_nonce_fee_payer_with_checked_arithmetic() {
1254        let rent_collector = RentCollector::new(
1255            0,
1256            EpochSchedule::default(),
1257            500_000.0,
1258            Rent {
1259                lamports_per_byte_year: 1,
1260                ..Rent::default()
1261            },
1262        );
1263
1264        // nonce payer account has balance of u64::MAX, so does fee; due to nonce account
1265        // requires additional min_balance, expect InsufficientFundsForFee error if feature gate is
1266        // enabled
1267        validate_fee_payer_account(
1268            ValidateFeePayerTestParameter {
1269                is_nonce: true,
1270                payer_init_balance: u64::MAX,
1271                fee: u64::MAX,
1272                expected_result: Err(TransactionError::InsufficientFundsForFee),
1273                payer_post_balance: u64::MAX,
1274            },
1275            &rent_collector,
1276        );
1277    }
1278
1279    #[test]
1280    fn test_construct_instructions_account() {
1281        let loaded_message = LoadedMessage {
1282            message: Cow::Owned(solana_message::v0::Message::default()),
1283            loaded_addresses: Cow::Owned(LoadedAddresses::default()),
1284            is_writable_account_cache: vec![false],
1285        };
1286        let message = SanitizedMessage::V0(loaded_message);
1287        let shared_data = construct_instructions_account(&message);
1288        let expected = AccountSharedData::from(Account {
1289            data: construct_instructions_data(&message.decompile_instructions()),
1290            owner: sysvar::id(),
1291            ..Account::default()
1292        });
1293        assert_eq!(shared_data, expected);
1294    }
1295
1296    #[test]
1297    fn test_load_transaction_accounts_fee_payer() {
1298        let fee_payer_address = Pubkey::new_unique();
1299        let message = Message {
1300            account_keys: vec![fee_payer_address],
1301            header: MessageHeader::default(),
1302            instructions: vec![],
1303            recent_blockhash: Hash::default(),
1304        };
1305
1306        let sanitized_message = new_unchecked_sanitized_message(message);
1307        let mut mock_bank = TestCallbacks::default();
1308
1309        let fee_payer_balance = 200;
1310        let mut fee_payer_account = AccountSharedData::default();
1311        fee_payer_account.set_lamports(fee_payer_balance);
1312        mock_bank
1313            .accounts_map
1314            .insert(fee_payer_address, fee_payer_account.clone());
1315        let mut account_loader = (&mock_bank).into();
1316        let fee_payer_rent_debit = 42;
1317
1318        let mut error_metrics = TransactionErrorMetrics::default();
1319
1320        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1321            sanitized_message,
1322            vec![Signature::new_unique()],
1323            false,
1324        );
1325        let result = load_transaction_accounts(
1326            &mut account_loader,
1327            sanitized_transaction.message(),
1328            LoadedTransactionAccount {
1329                loaded_size: fee_payer_account.data().len(),
1330                account: fee_payer_account.clone(),
1331                rent_collected: fee_payer_rent_debit,
1332            },
1333            &ComputeBudgetLimits::default(),
1334            &mut error_metrics,
1335            &RentCollector::default(),
1336        );
1337
1338        let expected_rent_debits = {
1339            let mut rent_debits = RentDebits::default();
1340            rent_debits.insert(&fee_payer_address, fee_payer_rent_debit, fee_payer_balance);
1341            rent_debits
1342        };
1343        assert_eq!(
1344            result.unwrap(),
1345            LoadedTransactionAccounts {
1346                accounts: vec![(fee_payer_address, fee_payer_account)],
1347                program_indices: vec![],
1348                rent: fee_payer_rent_debit,
1349                rent_debits: expected_rent_debits,
1350                loaded_accounts_data_size: 0,
1351            }
1352        );
1353    }
1354
1355    #[test]
1356    fn test_load_transaction_accounts_native_loader() {
1357        let key1 = Keypair::new();
1358        let message = Message {
1359            account_keys: vec![key1.pubkey(), native_loader::id()],
1360            header: MessageHeader::default(),
1361            instructions: vec![CompiledInstruction {
1362                program_id_index: 1,
1363                accounts: vec![0],
1364                data: vec![],
1365            }],
1366            recent_blockhash: Hash::default(),
1367        };
1368
1369        let sanitized_message = new_unchecked_sanitized_message(message);
1370        let mut mock_bank = TestCallbacks::default();
1371        mock_bank
1372            .accounts_map
1373            .insert(native_loader::id(), AccountSharedData::default());
1374        let mut fee_payer_account = AccountSharedData::default();
1375        fee_payer_account.set_lamports(200);
1376        mock_bank
1377            .accounts_map
1378            .insert(key1.pubkey(), fee_payer_account.clone());
1379        let mut account_loader = (&mock_bank).into();
1380
1381        let mut error_metrics = TransactionErrorMetrics::default();
1382
1383        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1384            sanitized_message,
1385            vec![Signature::new_unique()],
1386            false,
1387        );
1388        let result = load_transaction_accounts(
1389            &mut account_loader,
1390            sanitized_transaction.message(),
1391            LoadedTransactionAccount {
1392                account: fee_payer_account.clone(),
1393                ..LoadedTransactionAccount::default()
1394            },
1395            &ComputeBudgetLimits::default(),
1396            &mut error_metrics,
1397            &RentCollector::default(),
1398        );
1399
1400        assert_eq!(
1401            result.unwrap(),
1402            LoadedTransactionAccounts {
1403                accounts: vec![
1404                    (key1.pubkey(), fee_payer_account),
1405                    (
1406                        native_loader::id(),
1407                        mock_bank.accounts_map[&native_loader::id()].clone()
1408                    )
1409                ],
1410                program_indices: vec![vec![]],
1411                rent: 0,
1412                rent_debits: RentDebits::default(),
1413                loaded_accounts_data_size: 0,
1414            }
1415        );
1416    }
1417
1418    #[test]
1419    fn test_load_transaction_accounts_program_account_no_data() {
1420        let key1 = Keypair::new();
1421        let key2 = Keypair::new();
1422
1423        let message = Message {
1424            account_keys: vec![key1.pubkey(), key2.pubkey()],
1425            header: MessageHeader::default(),
1426            instructions: vec![CompiledInstruction {
1427                program_id_index: 1,
1428                accounts: vec![0, 1],
1429                data: vec![],
1430            }],
1431            recent_blockhash: Hash::default(),
1432        };
1433
1434        let sanitized_message = new_unchecked_sanitized_message(message);
1435        let mut mock_bank = TestCallbacks::default();
1436        let mut account_data = AccountSharedData::default();
1437        account_data.set_lamports(200);
1438        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1439        let mut account_loader = (&mock_bank).into();
1440
1441        let mut error_metrics = TransactionErrorMetrics::default();
1442
1443        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1444            sanitized_message,
1445            vec![Signature::new_unique()],
1446            false,
1447        );
1448        let result = load_transaction_accounts(
1449            &mut account_loader,
1450            sanitized_transaction.message(),
1451            LoadedTransactionAccount::default(),
1452            &ComputeBudgetLimits::default(),
1453            &mut error_metrics,
1454            &RentCollector::default(),
1455        );
1456
1457        assert_eq!(result.err(), Some(TransactionError::ProgramAccountNotFound));
1458    }
1459
1460    #[test]
1461    fn test_load_transaction_accounts_invalid_program_for_execution() {
1462        let key1 = Keypair::new();
1463        let key2 = Keypair::new();
1464
1465        let message = Message {
1466            account_keys: vec![key1.pubkey(), key2.pubkey()],
1467            header: MessageHeader::default(),
1468            instructions: vec![CompiledInstruction {
1469                program_id_index: 0,
1470                accounts: vec![0, 1],
1471                data: vec![],
1472            }],
1473            recent_blockhash: Hash::default(),
1474        };
1475
1476        let sanitized_message = new_unchecked_sanitized_message(message);
1477        let mut mock_bank = TestCallbacks::default();
1478        let mut account_data = AccountSharedData::default();
1479        account_data.set_lamports(200);
1480        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1481        let mut account_loader = (&mock_bank).into();
1482
1483        let mut error_metrics = TransactionErrorMetrics::default();
1484
1485        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1486            sanitized_message,
1487            vec![Signature::new_unique()],
1488            false,
1489        );
1490        let result = load_transaction_accounts(
1491            &mut account_loader,
1492            sanitized_transaction.message(),
1493            LoadedTransactionAccount::default(),
1494            &ComputeBudgetLimits::default(),
1495            &mut error_metrics,
1496            &RentCollector::default(),
1497        );
1498
1499        assert_eq!(
1500            result.err(),
1501            Some(TransactionError::InvalidProgramForExecution)
1502        );
1503    }
1504
1505    #[test]
1506    fn test_load_transaction_accounts_native_loader_owner() {
1507        let key1 = Keypair::new();
1508        let key2 = Keypair::new();
1509
1510        let message = Message {
1511            account_keys: vec![key2.pubkey(), key1.pubkey()],
1512            header: MessageHeader::default(),
1513            instructions: vec![CompiledInstruction {
1514                program_id_index: 1,
1515                accounts: vec![0],
1516                data: vec![],
1517            }],
1518            recent_blockhash: Hash::default(),
1519        };
1520
1521        let sanitized_message = new_unchecked_sanitized_message(message);
1522        let mut mock_bank = TestCallbacks::default();
1523        let mut account_data = AccountSharedData::default();
1524        account_data.set_owner(native_loader::id());
1525        account_data.set_lamports(1);
1526        account_data.set_executable(true);
1527        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1528
1529        let mut fee_payer_account = AccountSharedData::default();
1530        fee_payer_account.set_lamports(200);
1531        mock_bank
1532            .accounts_map
1533            .insert(key2.pubkey(), fee_payer_account.clone());
1534        let mut account_loader = (&mock_bank).into();
1535
1536        let mut error_metrics = TransactionErrorMetrics::default();
1537
1538        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1539            sanitized_message,
1540            vec![Signature::new_unique()],
1541            false,
1542        );
1543        let result = load_transaction_accounts(
1544            &mut account_loader,
1545            sanitized_transaction.message(),
1546            LoadedTransactionAccount {
1547                account: fee_payer_account.clone(),
1548                ..LoadedTransactionAccount::default()
1549            },
1550            &ComputeBudgetLimits::default(),
1551            &mut error_metrics,
1552            &RentCollector::default(),
1553        );
1554
1555        assert_eq!(
1556            result.unwrap(),
1557            LoadedTransactionAccounts {
1558                accounts: vec![
1559                    (key2.pubkey(), fee_payer_account),
1560                    (
1561                        key1.pubkey(),
1562                        mock_bank.accounts_map[&key1.pubkey()].clone()
1563                    ),
1564                ],
1565                program_indices: vec![vec![1]],
1566                rent: 0,
1567                rent_debits: RentDebits::default(),
1568                loaded_accounts_data_size: 0,
1569            }
1570        );
1571    }
1572
1573    #[test]
1574    fn test_load_transaction_accounts_program_account_not_found_after_all_checks() {
1575        let key1 = Keypair::new();
1576        let key2 = Keypair::new();
1577
1578        let message = Message {
1579            account_keys: vec![key2.pubkey(), key1.pubkey()],
1580            header: MessageHeader::default(),
1581            instructions: vec![CompiledInstruction {
1582                program_id_index: 1,
1583                accounts: vec![0],
1584                data: vec![],
1585            }],
1586            recent_blockhash: Hash::default(),
1587        };
1588
1589        let sanitized_message = new_unchecked_sanitized_message(message);
1590        let mut mock_bank = TestCallbacks::default();
1591        let mut account_data = AccountSharedData::default();
1592        account_data.set_executable(true);
1593        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1594
1595        let mut account_data = AccountSharedData::default();
1596        account_data.set_lamports(200);
1597        mock_bank.accounts_map.insert(key2.pubkey(), account_data);
1598        let mut account_loader = (&mock_bank).into();
1599
1600        let mut error_metrics = TransactionErrorMetrics::default();
1601
1602        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1603            sanitized_message,
1604            vec![Signature::new_unique()],
1605            false,
1606        );
1607        let result = load_transaction_accounts(
1608            &mut account_loader,
1609            sanitized_transaction.message(),
1610            LoadedTransactionAccount::default(),
1611            &ComputeBudgetLimits::default(),
1612            &mut error_metrics,
1613            &RentCollector::default(),
1614        );
1615
1616        assert_eq!(result.err(), Some(TransactionError::ProgramAccountNotFound));
1617    }
1618
1619    #[test]
1620    fn test_load_transaction_accounts_program_account_invalid_program_for_execution_last_check() {
1621        let key1 = Keypair::new();
1622        let key2 = Keypair::new();
1623        let key3 = Keypair::new();
1624
1625        let message = Message {
1626            account_keys: vec![key2.pubkey(), key1.pubkey()],
1627            header: MessageHeader::default(),
1628            instructions: vec![CompiledInstruction {
1629                program_id_index: 1,
1630                accounts: vec![0],
1631                data: vec![],
1632            }],
1633            recent_blockhash: Hash::default(),
1634        };
1635
1636        let sanitized_message = new_unchecked_sanitized_message(message);
1637        let mut mock_bank = TestCallbacks::default();
1638        let mut account_data = AccountSharedData::default();
1639        account_data.set_lamports(1);
1640        account_data.set_executable(true);
1641        account_data.set_owner(key3.pubkey());
1642        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1643
1644        let mut account_data = AccountSharedData::default();
1645        account_data.set_lamports(200);
1646        mock_bank.accounts_map.insert(key2.pubkey(), account_data);
1647        mock_bank
1648            .accounts_map
1649            .insert(key3.pubkey(), AccountSharedData::default());
1650        let mut account_loader = (&mock_bank).into();
1651
1652        let mut error_metrics = TransactionErrorMetrics::default();
1653
1654        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1655            sanitized_message,
1656            vec![Signature::new_unique()],
1657            false,
1658        );
1659        let result = load_transaction_accounts(
1660            &mut account_loader,
1661            sanitized_transaction.message(),
1662            LoadedTransactionAccount::default(),
1663            &ComputeBudgetLimits::default(),
1664            &mut error_metrics,
1665            &RentCollector::default(),
1666        );
1667
1668        assert_eq!(
1669            result.err(),
1670            Some(TransactionError::InvalidProgramForExecution)
1671        );
1672    }
1673
1674    #[test]
1675    fn test_load_transaction_accounts_program_success_complete() {
1676        let key1 = Keypair::new();
1677        let key2 = Keypair::new();
1678        let key3 = Keypair::new();
1679
1680        let message = Message {
1681            account_keys: vec![key2.pubkey(), key1.pubkey()],
1682            header: MessageHeader::default(),
1683            instructions: vec![CompiledInstruction {
1684                program_id_index: 1,
1685                accounts: vec![0],
1686                data: vec![],
1687            }],
1688            recent_blockhash: Hash::default(),
1689        };
1690
1691        let sanitized_message = new_unchecked_sanitized_message(message);
1692        let mut mock_bank = TestCallbacks::default();
1693        let mut account_data = AccountSharedData::default();
1694        account_data.set_lamports(1);
1695        account_data.set_executable(true);
1696        account_data.set_owner(key3.pubkey());
1697        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1698
1699        let mut fee_payer_account = AccountSharedData::default();
1700        fee_payer_account.set_lamports(200);
1701        mock_bank
1702            .accounts_map
1703            .insert(key2.pubkey(), fee_payer_account.clone());
1704
1705        let mut account_data = AccountSharedData::default();
1706        account_data.set_lamports(1);
1707        account_data.set_executable(true);
1708        account_data.set_owner(native_loader::id());
1709        mock_bank.accounts_map.insert(key3.pubkey(), account_data);
1710        let mut account_loader = (&mock_bank).into();
1711
1712        let mut error_metrics = TransactionErrorMetrics::default();
1713
1714        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1715            sanitized_message,
1716            vec![Signature::new_unique()],
1717            false,
1718        );
1719        let result = load_transaction_accounts(
1720            &mut account_loader,
1721            sanitized_transaction.message(),
1722            LoadedTransactionAccount {
1723                account: fee_payer_account.clone(),
1724                ..LoadedTransactionAccount::default()
1725            },
1726            &ComputeBudgetLimits::default(),
1727            &mut error_metrics,
1728            &RentCollector::default(),
1729        );
1730
1731        assert_eq!(
1732            result.unwrap(),
1733            LoadedTransactionAccounts {
1734                accounts: vec![
1735                    (key2.pubkey(), fee_payer_account),
1736                    (
1737                        key1.pubkey(),
1738                        mock_bank.accounts_map[&key1.pubkey()].clone()
1739                    ),
1740                ],
1741                program_indices: vec![vec![1]],
1742                rent: 0,
1743                rent_debits: RentDebits::default(),
1744                loaded_accounts_data_size: 0,
1745            }
1746        );
1747    }
1748
1749    #[test]
1750    fn test_load_transaction_accounts_program_builtin_saturating_add() {
1751        let key1 = Keypair::new();
1752        let key2 = Keypair::new();
1753        let key3 = Keypair::new();
1754        let key4 = Keypair::new();
1755
1756        let message = Message {
1757            account_keys: vec![key2.pubkey(), key1.pubkey(), key4.pubkey()],
1758            header: MessageHeader::default(),
1759            instructions: vec![
1760                CompiledInstruction {
1761                    program_id_index: 1,
1762                    accounts: vec![0],
1763                    data: vec![],
1764                },
1765                CompiledInstruction {
1766                    program_id_index: 1,
1767                    accounts: vec![2],
1768                    data: vec![],
1769                },
1770            ],
1771            recent_blockhash: Hash::default(),
1772        };
1773
1774        let sanitized_message = new_unchecked_sanitized_message(message);
1775        let mut mock_bank = TestCallbacks::default();
1776        let mut account_data = AccountSharedData::default();
1777        account_data.set_lamports(1);
1778        account_data.set_executable(true);
1779        account_data.set_owner(key3.pubkey());
1780        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1781
1782        let mut fee_payer_account = AccountSharedData::default();
1783        fee_payer_account.set_lamports(200);
1784        mock_bank
1785            .accounts_map
1786            .insert(key2.pubkey(), fee_payer_account.clone());
1787
1788        let mut account_data = AccountSharedData::default();
1789        account_data.set_lamports(1);
1790        account_data.set_executable(true);
1791        account_data.set_owner(native_loader::id());
1792        mock_bank.accounts_map.insert(key3.pubkey(), account_data);
1793        let mut account_loader = (&mock_bank).into();
1794
1795        let mut error_metrics = TransactionErrorMetrics::default();
1796
1797        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1798            sanitized_message,
1799            vec![Signature::new_unique()],
1800            false,
1801        );
1802        let result = load_transaction_accounts(
1803            &mut account_loader,
1804            sanitized_transaction.message(),
1805            LoadedTransactionAccount {
1806                account: fee_payer_account.clone(),
1807                ..LoadedTransactionAccount::default()
1808            },
1809            &ComputeBudgetLimits::default(),
1810            &mut error_metrics,
1811            &RentCollector::default(),
1812        );
1813
1814        let mut account_data = AccountSharedData::default();
1815        account_data.set_rent_epoch(RENT_EXEMPT_RENT_EPOCH);
1816        assert_eq!(
1817            result.unwrap(),
1818            LoadedTransactionAccounts {
1819                accounts: vec![
1820                    (key2.pubkey(), fee_payer_account),
1821                    (
1822                        key1.pubkey(),
1823                        mock_bank.accounts_map[&key1.pubkey()].clone()
1824                    ),
1825                    (key4.pubkey(), account_data),
1826                ],
1827                program_indices: vec![vec![1], vec![1]],
1828                rent: 0,
1829                rent_debits: RentDebits::default(),
1830                loaded_accounts_data_size: 0,
1831            }
1832        );
1833    }
1834
1835    #[test]
1836    fn test_rent_state_list_len() {
1837        let mint_keypair = Keypair::new();
1838        let mut bank = TestCallbacks::default();
1839        let recipient = Pubkey::new_unique();
1840        let last_block_hash = Hash::new_unique();
1841
1842        let mut system_data = AccountSharedData::default();
1843        system_data.set_lamports(1);
1844        system_data.set_executable(true);
1845        system_data.set_owner(native_loader::id());
1846        bank.accounts_map
1847            .insert(Pubkey::new_from_array([0u8; 32]), system_data);
1848
1849        let mut mint_data = AccountSharedData::default();
1850        mint_data.set_lamports(2);
1851        bank.accounts_map.insert(mint_keypair.pubkey(), mint_data);
1852        bank.accounts_map
1853            .insert(recipient, AccountSharedData::default());
1854        let mut account_loader = (&bank).into();
1855
1856        let tx = transfer(
1857            &mint_keypair,
1858            &recipient,
1859            sol_to_lamports(1.),
1860            last_block_hash,
1861        );
1862        let num_accounts = tx.message().account_keys.len();
1863        let sanitized_tx = SanitizedTransaction::from_transaction_for_tests(tx);
1864        let mut error_metrics = TransactionErrorMetrics::default();
1865        let load_result = load_transaction(
1866            &mut account_loader,
1867            &sanitized_tx.clone(),
1868            Ok(ValidatedTransactionDetails::default()),
1869            &mut error_metrics,
1870            &RentCollector::default(),
1871        );
1872
1873        let TransactionLoadResult::Loaded(loaded_transaction) = load_result else {
1874            panic!("transaction loading failed");
1875        };
1876
1877        let compute_budget = ComputeBudget::new(u64::from(
1878            compute_budget_limits::DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT,
1879        ));
1880        let rent_collector = RentCollector::default();
1881        let transaction_context = TransactionContext::new(
1882            loaded_transaction.accounts,
1883            rent_collector.get_rent().clone(),
1884            compute_budget.max_instruction_stack_depth,
1885            compute_budget.max_instruction_trace_length,
1886        );
1887
1888        assert_eq!(
1889            TransactionAccountStateInfo::new(
1890                &transaction_context,
1891                sanitized_tx.message(),
1892                &rent_collector,
1893            )
1894            .len(),
1895            num_accounts,
1896        );
1897    }
1898
1899    #[test]
1900    fn test_load_accounts_success() {
1901        let key1 = Keypair::new();
1902        let key2 = Keypair::new();
1903        let key3 = Keypair::new();
1904        let key4 = Keypair::new();
1905
1906        let message = Message {
1907            account_keys: vec![key2.pubkey(), key1.pubkey(), key4.pubkey()],
1908            header: MessageHeader::default(),
1909            instructions: vec![
1910                CompiledInstruction {
1911                    program_id_index: 1,
1912                    accounts: vec![0],
1913                    data: vec![],
1914                },
1915                CompiledInstruction {
1916                    program_id_index: 1,
1917                    accounts: vec![2],
1918                    data: vec![],
1919                },
1920            ],
1921            recent_blockhash: Hash::default(),
1922        };
1923
1924        let sanitized_message = new_unchecked_sanitized_message(message);
1925        let mut mock_bank = TestCallbacks::default();
1926        let mut account_data = AccountSharedData::default();
1927        account_data.set_lamports(1);
1928        account_data.set_executable(true);
1929        account_data.set_owner(key3.pubkey());
1930        mock_bank.accounts_map.insert(key1.pubkey(), account_data);
1931
1932        let mut fee_payer_account = AccountSharedData::default();
1933        fee_payer_account.set_lamports(200);
1934        mock_bank
1935            .accounts_map
1936            .insert(key2.pubkey(), fee_payer_account.clone());
1937
1938        let mut account_data = AccountSharedData::default();
1939        account_data.set_lamports(1);
1940        account_data.set_executable(true);
1941        account_data.set_owner(native_loader::id());
1942        mock_bank.accounts_map.insert(key3.pubkey(), account_data);
1943        let mut account_loader = (&mock_bank).into();
1944
1945        let mut error_metrics = TransactionErrorMetrics::default();
1946
1947        let sanitized_transaction = SanitizedTransaction::new_for_tests(
1948            sanitized_message,
1949            vec![Signature::new_unique()],
1950            false,
1951        );
1952        let validation_result = Ok(ValidatedTransactionDetails {
1953            loaded_fee_payer_account: LoadedTransactionAccount {
1954                account: fee_payer_account,
1955                ..LoadedTransactionAccount::default()
1956            },
1957            ..ValidatedTransactionDetails::default()
1958        });
1959
1960        let load_result = load_transaction(
1961            &mut account_loader,
1962            &sanitized_transaction,
1963            validation_result,
1964            &mut error_metrics,
1965            &RentCollector::default(),
1966        );
1967
1968        let mut account_data = AccountSharedData::default();
1969        account_data.set_rent_epoch(RENT_EXEMPT_RENT_EPOCH);
1970
1971        let TransactionLoadResult::Loaded(loaded_transaction) = load_result else {
1972            panic!("transaction loading failed");
1973        };
1974        assert_eq!(
1975            loaded_transaction,
1976            LoadedTransaction {
1977                accounts: vec![
1978                    (
1979                        key2.pubkey(),
1980                        mock_bank.accounts_map[&key2.pubkey()].clone()
1981                    ),
1982                    (
1983                        key1.pubkey(),
1984                        mock_bank.accounts_map[&key1.pubkey()].clone()
1985                    ),
1986                    (key4.pubkey(), account_data),
1987                ],
1988                program_indices: vec![vec![1], vec![1]],
1989                fee_details: FeeDetails::default(),
1990                rollback_accounts: RollbackAccounts::default(),
1991                compute_budget_limits: ComputeBudgetLimits::default(),
1992                rent: 0,
1993                rent_debits: RentDebits::default(),
1994                loaded_accounts_data_size: 0,
1995            }
1996        );
1997    }
1998
1999    #[test]
2000    fn test_load_accounts_error() {
2001        let mock_bank = TestCallbacks::default();
2002        let mut account_loader = (&mock_bank).into();
2003        let rent_collector = RentCollector::default();
2004
2005        let message = Message {
2006            account_keys: vec![Pubkey::new_from_array([0; 32])],
2007            header: MessageHeader::default(),
2008            instructions: vec![CompiledInstruction {
2009                program_id_index: 0,
2010                accounts: vec![],
2011                data: vec![],
2012            }],
2013            recent_blockhash: Hash::default(),
2014        };
2015
2016        let sanitized_message = new_unchecked_sanitized_message(message);
2017        let sanitized_transaction = SanitizedTransaction::new_for_tests(
2018            sanitized_message,
2019            vec![Signature::new_unique()],
2020            false,
2021        );
2022
2023        let validation_result = Ok(ValidatedTransactionDetails::default());
2024        let load_result = load_transaction(
2025            &mut account_loader,
2026            &sanitized_transaction,
2027            validation_result.clone(),
2028            &mut TransactionErrorMetrics::default(),
2029            &rent_collector,
2030        );
2031
2032        assert!(matches!(
2033            load_result,
2034            TransactionLoadResult::FeesOnly(FeesOnlyTransaction {
2035                load_error: TransactionError::ProgramAccountNotFound,
2036                ..
2037            }),
2038        ));
2039
2040        let validation_result = Err(TransactionError::InvalidWritableAccount);
2041
2042        let load_result = load_transaction(
2043            &mut account_loader,
2044            &sanitized_transaction,
2045            validation_result,
2046            &mut TransactionErrorMetrics::default(),
2047            &rent_collector,
2048        );
2049
2050        assert!(matches!(
2051            load_result,
2052            TransactionLoadResult::NotLoaded(TransactionError::InvalidWritableAccount),
2053        ));
2054    }
2055
2056    #[test]
2057    fn test_collect_rent_from_account() {
2058        let feature_set = FeatureSet::all_enabled();
2059        let rent_collector = RentCollector {
2060            epoch: 1,
2061            ..RentCollector::default()
2062        };
2063
2064        let address = Pubkey::new_unique();
2065        let min_exempt_balance = rent_collector.rent.minimum_balance(0);
2066        let mut account = AccountSharedData::from(Account {
2067            lamports: min_exempt_balance,
2068            ..Account::default()
2069        });
2070
2071        assert_eq!(
2072            collect_rent_from_account(&feature_set, &rent_collector, &address, &mut account),
2073            CollectedInfo::default()
2074        );
2075        assert_eq!(account.rent_epoch(), RENT_EXEMPT_RENT_EPOCH);
2076    }
2077
2078    #[test]
2079    fn test_collect_rent_from_account_rent_paying() {
2080        let feature_set = FeatureSet::all_enabled();
2081        let rent_collector = RentCollector {
2082            epoch: 1,
2083            ..RentCollector::default()
2084        };
2085
2086        let address = Pubkey::new_unique();
2087        let mut account = AccountSharedData::from(Account {
2088            lamports: 1,
2089            ..Account::default()
2090        });
2091
2092        assert_eq!(
2093            collect_rent_from_account(&feature_set, &rent_collector, &address, &mut account),
2094            CollectedInfo::default()
2095        );
2096        assert_eq!(account.rent_epoch(), 0);
2097        assert_eq!(account.lamports(), 1);
2098    }
2099
2100    #[test]
2101    fn test_collect_rent_from_account_rent_enabled() {
2102        let feature_set =
2103            all_features_except(Some(&[feature_set::disable_rent_fees_collection::id()]));
2104        let rent_collector = RentCollector {
2105            epoch: 1,
2106            ..RentCollector::default()
2107        };
2108
2109        let address = Pubkey::new_unique();
2110        let mut account = AccountSharedData::from(Account {
2111            lamports: 1,
2112            data: vec![0],
2113            ..Account::default()
2114        });
2115
2116        assert_eq!(
2117            collect_rent_from_account(&feature_set, &rent_collector, &address, &mut account),
2118            CollectedInfo {
2119                rent_amount: 1,
2120                account_data_len_reclaimed: 1
2121            }
2122        );
2123        assert_eq!(account.rent_epoch(), 0);
2124        assert_eq!(account.lamports(), 0);
2125    }
2126
2127    // Ensure `TransactionProcessingCallback::inspect_account()` is called when
2128    // loading accounts for transaction processing.
2129    #[test]
2130    fn test_inspect_account_non_fee_payer() {
2131        let mut mock_bank = TestCallbacks::default();
2132
2133        let address0 = Pubkey::new_unique(); // <-- fee payer
2134        let address1 = Pubkey::new_unique(); // <-- initially alive
2135        let address2 = Pubkey::new_unique(); // <-- initially dead
2136        let address3 = Pubkey::new_unique(); // <-- program
2137
2138        let mut account0 = AccountSharedData::default();
2139        account0.set_lamports(1_000_000_000);
2140        mock_bank.accounts_map.insert(address0, account0.clone());
2141
2142        let mut account1 = AccountSharedData::default();
2143        account1.set_lamports(2_000_000_000);
2144        mock_bank.accounts_map.insert(address1, account1.clone());
2145
2146        // account2 *not* added to the bank's accounts_map
2147
2148        let mut account3 = AccountSharedData::default();
2149        account3.set_lamports(4_000_000_000);
2150        account3.set_executable(true);
2151        account3.set_owner(bpf_loader::id());
2152        mock_bank.accounts_map.insert(address3, account3.clone());
2153        let mut account_loader = (&mock_bank).into();
2154
2155        let message = Message {
2156            account_keys: vec![address0, address1, address2, address3],
2157            header: MessageHeader::default(),
2158            instructions: vec![
2159                CompiledInstruction {
2160                    program_id_index: 3,
2161                    accounts: vec![0],
2162                    data: vec![],
2163                },
2164                CompiledInstruction {
2165                    program_id_index: 3,
2166                    accounts: vec![1, 2],
2167                    data: vec![],
2168                },
2169                CompiledInstruction {
2170                    program_id_index: 3,
2171                    accounts: vec![1],
2172                    data: vec![],
2173                },
2174            ],
2175            recent_blockhash: Hash::new_unique(),
2176        };
2177        let sanitized_message = new_unchecked_sanitized_message(message);
2178        let sanitized_transaction = SanitizedTransaction::new_for_tests(
2179            sanitized_message,
2180            vec![Signature::new_unique()],
2181            false,
2182        );
2183        let validation_result = Ok(ValidatedTransactionDetails {
2184            loaded_fee_payer_account: LoadedTransactionAccount {
2185                account: account0.clone(),
2186                ..LoadedTransactionAccount::default()
2187            },
2188            ..ValidatedTransactionDetails::default()
2189        });
2190        let _load_results = load_transaction(
2191            &mut account_loader,
2192            &sanitized_transaction,
2193            validation_result,
2194            &mut TransactionErrorMetrics::default(),
2195            &RentCollector::default(),
2196        );
2197
2198        // ensure the loaded accounts are inspected
2199        let mut actual_inspected_accounts: Vec<_> = mock_bank
2200            .inspected_accounts
2201            .borrow()
2202            .iter()
2203            .map(|(k, v)| (*k, v.clone()))
2204            .collect();
2205        actual_inspected_accounts.sort_unstable_by(|a, b| a.0.cmp(&b.0));
2206
2207        let mut expected_inspected_accounts = vec![
2208            // *not* key0, since it is loaded during fee payer validation
2209            (address1, vec![(Some(account1), true)]),
2210            (address2, vec![(None, true)]),
2211            (
2212                address3,
2213                vec![(Some(account3.clone()), false), (Some(account3), false)],
2214            ),
2215            (bpf_loader::id(), vec![(None, false)]),
2216        ];
2217        expected_inspected_accounts.sort_unstable_by(|a, b| a.0.cmp(&b.0));
2218
2219        assert_eq!(actual_inspected_accounts, expected_inspected_accounts,);
2220    }
2221
2222    #[test]
2223    fn test_load_transaction_accounts_data_sizes() {
2224        let mut mock_bank = TestCallbacks::default();
2225
2226        let loader_v2 = bpf_loader::id();
2227        let loader_v3 = bpf_loader_upgradeable::id();
2228        let program1_keypair = Keypair::new();
2229        let program1 = program1_keypair.pubkey();
2230        let program2 = Pubkey::new_unique();
2231        let programdata2 = Pubkey::new_unique();
2232        use solana_account::state_traits::StateMut;
2233
2234        let program2_size = std::mem::size_of::<UpgradeableLoaderState>() as u32;
2235        let mut program2_account = AccountSharedData::default();
2236        program2_account.set_owner(loader_v3);
2237        program2_account.set_lamports(LAMPORTS_PER_SOL);
2238        program2_account.set_executable(true);
2239        program2_account.set_data(vec![0; program2_size as usize]);
2240        program2_account
2241            .set_state(&UpgradeableLoaderState::Program {
2242                programdata_address: programdata2,
2243            })
2244            .unwrap();
2245        mock_bank.accounts_map.insert(program2, program2_account);
2246        let mut programdata2_account = AccountSharedData::default();
2247        programdata2_account.set_owner(loader_v3);
2248        programdata2_account.set_lamports(LAMPORTS_PER_SOL);
2249        programdata2_account.set_data(vec![0; program2_size as usize]);
2250        programdata2_account
2251            .set_state(&UpgradeableLoaderState::ProgramData {
2252                slot: 0,
2253                upgrade_authority_address: None,
2254            })
2255            .unwrap();
2256        let mut programdata = programdata2_account.data().to_vec();
2257        let mut file =
2258            File::open("tests/example-programs/hello-solana/hello_solana_program.so").unwrap();
2259        file.read_to_end(&mut programdata).unwrap();
2260        let programdata2_size = programdata.len() as u32;
2261        programdata2_account.set_data(programdata);
2262        mock_bank
2263            .accounts_map
2264            .insert(programdata2, programdata2_account);
2265
2266        let mut next_size = 1;
2267        let mut make_account = |pubkey, owner, executable| {
2268            let size = next_size;
2269            let account = AccountSharedData::create(
2270                LAMPORTS_PER_SOL,
2271                vec![0; size],
2272                owner,
2273                executable,
2274                u64::MAX,
2275            );
2276
2277            mock_bank.accounts_map.insert(pubkey, account.clone());
2278
2279            // accounts are counted at most twice
2280            // by multiplying account size by 4, we ensure all totals are unique
2281            next_size *= 4;
2282
2283            (size as u32, account)
2284        };
2285
2286        let fee_payer_keypair = Keypair::new();
2287        let fee_payer = fee_payer_keypair.pubkey();
2288        let (fee_payer_size, fee_payer_account) =
2289            make_account(fee_payer, system_program::id(), false);
2290
2291        let account1 = Pubkey::new_unique();
2292        let (account1_size, _) = make_account(account1, program1, false);
2293
2294        let account2 = Pubkey::new_unique();
2295        let (account2_size, _) = make_account(account2, program2, false);
2296
2297        let (native_loader_size, _) = make_account(native_loader::id(), native_loader::id(), true);
2298        let (bpf_loader_size, _) = make_account(loader_v2, native_loader::id(), true);
2299        let (upgradeable_loader_size, _) = make_account(loader_v3, native_loader::id(), true);
2300
2301        let (program1_size, _) = make_account(program1, loader_v2, true);
2302
2303        let mut program_accounts = HashMap::new();
2304        program_accounts.insert(program1, (&loader_v2, 0));
2305        program_accounts.insert(program2, (&loader_v3, 0));
2306
2307        let test_transaction_data_size = |transaction, expected_size| {
2308            let mut account_loader = AccountLoader::new_with_account_cache_capacity(
2309                None,
2310                &mock_bank,
2311                Arc::<FeatureSet>::default(),
2312                0,
2313            );
2314
2315            let loaded_transaction_accounts = load_transaction_accounts(
2316                &mut account_loader,
2317                &transaction,
2318                LoadedTransactionAccount {
2319                    account: fee_payer_account.clone(),
2320                    loaded_size: fee_payer_size as usize,
2321                    rent_collected: 0,
2322                },
2323                &ComputeBudgetLimits::default(),
2324                &mut TransactionErrorMetrics::default(),
2325                &RentCollector::default(),
2326            )
2327            .unwrap();
2328
2329            assert_eq!(
2330                loaded_transaction_accounts.loaded_accounts_data_size,
2331                expected_size
2332            );
2333        };
2334
2335        let test_data_size = |instructions: Vec<_>, expected_size| {
2336            let transaction = SanitizedTransaction::from_transaction_for_tests(
2337                Transaction::new_signed_with_payer(
2338                    &instructions,
2339                    Some(&fee_payer),
2340                    &[&fee_payer_keypair],
2341                    Hash::default(),
2342                ),
2343            );
2344
2345            test_transaction_data_size(transaction, expected_size)
2346        };
2347
2348        for account_meta in [AccountMeta::new, AccountMeta::new_readonly] {
2349            // one program plus loader
2350            let ixns = vec![Instruction::new_with_bytes(program1, &[], vec![])];
2351            test_data_size(ixns, program1_size + bpf_loader_size + fee_payer_size);
2352
2353            // two programs, two loaders, two accounts
2354            let ixns = vec![
2355                Instruction::new_with_bytes(program1, &[], vec![account_meta(account1, false)]),
2356                Instruction::new_with_bytes(program2, &[], vec![account_meta(account2, false)]),
2357            ];
2358            test_data_size(
2359                ixns,
2360                account1_size
2361                    + account2_size
2362                    + program1_size
2363                    + program2_size
2364                    + bpf_loader_size
2365                    + upgradeable_loader_size
2366                    + fee_payer_size,
2367            );
2368
2369            // program and loader counted once
2370            let ixns = vec![
2371                Instruction::new_with_bytes(program2, &[], vec![]),
2372                Instruction::new_with_bytes(program2, &[], vec![]),
2373            ];
2374            test_data_size(
2375                ixns,
2376                program2_size + upgradeable_loader_size + fee_payer_size,
2377            );
2378
2379            // native loader not counted if loader
2380            let ixns = vec![Instruction::new_with_bytes(bpf_loader::id(), &[], vec![])];
2381            test_data_size(ixns, bpf_loader_size + fee_payer_size);
2382
2383            // native loader counted if instruction
2384            let ixns = vec![Instruction::new_with_bytes(
2385                bpf_loader::id(),
2386                &[],
2387                vec![account_meta(native_loader::id(), false)],
2388            )];
2389            test_data_size(ixns, bpf_loader_size + native_loader_size + fee_payer_size);
2390
2391            // native loader counted if invoked
2392            let ixns = vec![Instruction::new_with_bytes(
2393                native_loader::id(),
2394                &[],
2395                vec![],
2396            )];
2397            test_data_size(ixns, native_loader_size + fee_payer_size);
2398
2399            // native loader counted once if invoked and instruction
2400            let ixns = vec![Instruction::new_with_bytes(
2401                native_loader::id(),
2402                &[],
2403                vec![account_meta(native_loader::id(), false)],
2404            )];
2405            test_data_size(ixns, native_loader_size + fee_payer_size);
2406
2407            // loader counted twice if included in instruction
2408            let ixns = vec![Instruction::new_with_bytes(
2409                program2,
2410                &[],
2411                vec![account_meta(bpf_loader_upgradeable::id(), false)],
2412            )];
2413            test_data_size(
2414                ixns,
2415                upgradeable_loader_size * 2 + program2_size + fee_payer_size,
2416            );
2417
2418            // loader counted twice even if included first
2419            let ixns = vec![
2420                Instruction::new_with_bytes(bpf_loader_upgradeable::id(), &[], vec![]),
2421                Instruction::new_with_bytes(program2, &[], vec![]),
2422            ];
2423            test_data_size(
2424                ixns,
2425                upgradeable_loader_size * 2 + program2_size + fee_payer_size,
2426            );
2427
2428            // cover that case with multiple loaders to be sure
2429            let ixns = vec![
2430                Instruction::new_with_bytes(
2431                    program1,
2432                    &[],
2433                    vec![
2434                        account_meta(bpf_loader::id(), false),
2435                        account_meta(bpf_loader_upgradeable::id(), false),
2436                    ],
2437                ),
2438                Instruction::new_with_bytes(program2, &[], vec![account_meta(account1, false)]),
2439                Instruction::new_with_bytes(
2440                    bpf_loader_upgradeable::id(),
2441                    &[],
2442                    vec![account_meta(account1, false)],
2443                ),
2444            ];
2445            test_data_size(
2446                ixns,
2447                account1_size
2448                    + program1_size
2449                    + program2_size
2450                    + bpf_loader_size * 2
2451                    + upgradeable_loader_size * 2
2452                    + fee_payer_size,
2453            );
2454
2455            // fee-payer counted once
2456            let ixns = vec![Instruction::new_with_bytes(
2457                program1,
2458                &[],
2459                vec![account_meta(fee_payer, false)],
2460            )];
2461            test_data_size(ixns, program1_size + bpf_loader_size + fee_payer_size);
2462
2463            // programdata as instruction account counts it once
2464            let ixns = vec![Instruction::new_with_bytes(
2465                program2,
2466                &[],
2467                vec![account_meta(programdata2, false)],
2468            )];
2469            test_data_size(
2470                ixns,
2471                program2_size + programdata2_size + upgradeable_loader_size + fee_payer_size,
2472            );
2473
2474            // program and programdata as instruction accounts behaves the same
2475            let ixns = vec![Instruction::new_with_bytes(
2476                program2,
2477                &[],
2478                vec![
2479                    account_meta(program2, false),
2480                    account_meta(programdata2, false),
2481                ],
2482            )];
2483            test_data_size(
2484                ixns,
2485                program2_size + programdata2_size + upgradeable_loader_size + fee_payer_size,
2486            );
2487        }
2488    }
2489}