From 0d1ad0dc1d5ed0e16948b944beb32e586562b6e9 Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Thu, 20 Jun 2024 12:22:19 -0700 Subject: [PATCH] Reuse compute budget processing (#1700) * refactor: reuse compute budget limits * fix tests --- Cargo.lock | 1 + accounts-db/Cargo.toml | 1 + accounts-db/src/accounts.rs | 5 ++ compute-budget/src/compute_budget.rs | 28 +++--- .../src/compute_budget_processor.rs | 2 +- core/src/banking_stage/consume_worker.rs | 11 +++ program-runtime/src/timings.rs | 12 --- svm/src/account_loader.rs | 44 ++++----- svm/src/transaction_error_metrics.rs | 7 ++ svm/src/transaction_processor.rs | 90 ++++++++++++------- 10 files changed, 115 insertions(+), 86 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36274246ef..6879907277 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5511,6 +5511,7 @@ dependencies = [ "smallvec", "solana-accounts-db", "solana-bucket-map", + "solana-compute-budget", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-inline-spl", diff --git a/accounts-db/Cargo.toml b/accounts-db/Cargo.toml index 16bcd03e7f..14de0cf183 100644 --- a/accounts-db/Cargo.toml +++ b/accounts-db/Cargo.toml @@ -65,6 +65,7 @@ rand_chacha = { workspace = true } serde_bytes = { workspace = true } # See order-crates-for-publishing.py for using this unusual `path = "."` solana-accounts-db = { path = ".", features = ["dev-context-only-utils"] } +solana-compute-budget = { workspace = true } solana-logger = { workspace = true } solana-sdk = { workspace = true, features = ["dev-context-only-utils"] } solana-svm = { workspace = true, features = ["dev-context-only-utils"] } diff --git a/accounts-db/src/accounts.rs b/accounts-db/src/accounts.rs index be168b3ede..1f87be1ae8 100644 --- a/accounts-db/src/accounts.rs +++ b/accounts-db/src/accounts.rs @@ -822,6 +822,7 @@ mod tests { use { super::*, assert_matches::assert_matches, + solana_compute_budget::compute_budget_processor::ComputeBudgetLimits, solana_sdk::{ account::{AccountSharedData, WritableAccount}, address_lookup_table::state::LookupTableMeta, @@ -1566,6 +1567,7 @@ mod tests { program_indices: vec![], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1576,6 +1578,7 @@ mod tests { program_indices: vec![], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1829,6 +1832,7 @@ mod tests { nonce: nonce.clone(), fee_payer_account: from_account_pre.clone(), }, + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1928,6 +1932,7 @@ mod tests { rollback_accounts: RollbackAccounts::SameNonceAndFeePayer { nonce: nonce.clone(), }, + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, diff --git a/compute-budget/src/compute_budget.rs b/compute-budget/src/compute_budget.rs index e24f4b9f18..24eeb46815 100644 --- a/compute-budget/src/compute_budget.rs +++ b/compute-budget/src/compute_budget.rs @@ -1,9 +1,4 @@ -use { - crate::compute_budget_processor::{ - self, process_compute_budget_instructions, DEFAULT_HEAP_COST, - }, - solana_sdk::{instruction::CompiledInstruction, pubkey::Pubkey, transaction::Result}, -}; +use crate::compute_budget_processor::{self, ComputeBudgetLimits, DEFAULT_HEAP_COST}; #[cfg(all(RUSTC_WITH_SPECIALIZATION, feature = "frozen-abi"))] impl ::solana_frozen_abi::abi_example::AbiExample for ComputeBudget { @@ -136,6 +131,16 @@ impl Default for ComputeBudget { } } +impl From for ComputeBudget { + fn from(compute_budget_limits: ComputeBudgetLimits) -> Self { + ComputeBudget { + compute_unit_limit: u64::from(compute_budget_limits.compute_unit_limit), + heap_size: compute_budget_limits.updated_heap_bytes, + ..ComputeBudget::default() + } + } +} + impl ComputeBudget { pub fn new(compute_unit_limit: u64) -> Self { ComputeBudget { @@ -186,17 +191,6 @@ impl ComputeBudget { } } - pub fn try_from_instructions<'a>( - instructions: impl Iterator, - ) -> Result { - let compute_budget_limits = process_compute_budget_instructions(instructions)?; - Ok(ComputeBudget { - compute_unit_limit: u64::from(compute_budget_limits.compute_unit_limit), - heap_size: compute_budget_limits.updated_heap_bytes, - ..ComputeBudget::default() - }) - } - /// Returns cost of the Poseidon hash function for the given number of /// inputs is determined by the following quadratic function: /// diff --git a/compute-budget/src/compute_budget_processor.rs b/compute-budget/src/compute_budget_processor.rs index af60bbe22c..edd56e382a 100644 --- a/compute-budget/src/compute_budget_processor.rs +++ b/compute-budget/src/compute_budget_processor.rs @@ -23,7 +23,7 @@ pub const MIN_HEAP_FRAME_BYTES: u32 = HEAP_LENGTH as u32; /// anyone in Mainnet-beta today. It can be set by set_loaded_accounts_data_size_limit instruction pub const MAX_LOADED_ACCOUNTS_DATA_SIZE_BYTES: u32 = 64 * 1024 * 1024; -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct ComputeBudgetLimits { pub updated_heap_bytes: u32, pub compute_unit_limit: u32, diff --git a/core/src/banking_stage/consume_worker.rs b/core/src/banking_stage/consume_worker.rs index 4a4b4e729b..f83ca6724d 100644 --- a/core/src/banking_stage/consume_worker.rs +++ b/core/src/banking_stage/consume_worker.rs @@ -318,6 +318,7 @@ impl ConsumeWorkerMetrics { invalid_account_for_fee, invalid_account_index, invalid_program_for_execution, + invalid_compute_budget, not_allowed_during_cluster_maintenance, invalid_writable_account, invalid_rent_paying_account, @@ -371,6 +372,9 @@ impl ConsumeWorkerMetrics { self.error_metrics .invalid_program_for_execution .fetch_add(*invalid_program_for_execution, Ordering::Relaxed); + self.error_metrics + .invalid_compute_budget + .fetch_add(*invalid_compute_budget, Ordering::Relaxed); self.error_metrics .not_allowed_during_cluster_maintenance .fetch_add(*not_allowed_during_cluster_maintenance, Ordering::Relaxed); @@ -561,6 +565,7 @@ struct ConsumeWorkerTransactionErrorMetrics { invalid_account_for_fee: AtomicUsize, invalid_account_index: AtomicUsize, invalid_program_for_execution: AtomicUsize, + invalid_compute_budget: AtomicUsize, not_allowed_during_cluster_maintenance: AtomicUsize, invalid_writable_account: AtomicUsize, invalid_rent_paying_account: AtomicUsize, @@ -644,6 +649,12 @@ impl ConsumeWorkerTransactionErrorMetrics { .swap(0, Ordering::Relaxed), i64 ), + ( + "invalid_compute_budget", + self.invalid_compute_budget + .swap(0, Ordering::Relaxed), + i64 + ), ( "not_allowed_during_cluster_maintenance", self.not_allowed_during_cluster_maintenance diff --git a/program-runtime/src/timings.rs b/program-runtime/src/timings.rs index 9a831deb3c..5255c24094 100644 --- a/program-runtime/src/timings.rs +++ b/program-runtime/src/timings.rs @@ -241,13 +241,6 @@ eager_macro_rules! { $eager_1 .feature_set_clone_us, i64 ), - ( - "execute_accessories_compute_budget_process_transaction_us", - $self - .execute_accessories - .compute_budget_process_transaction_us, - i64 - ), ( "execute_accessories_get_executors_us", $self.execute_accessories.get_executors_us, @@ -348,7 +341,6 @@ impl ExecuteProcessInstructionTimings { #[derive(Default, Debug)] pub struct ExecuteAccessoryTimings { pub feature_set_clone_us: u64, - pub compute_budget_process_transaction_us: u64, pub get_executors_us: u64, pub process_message_us: u64, pub update_executors_us: u64, @@ -358,10 +350,6 @@ pub struct ExecuteAccessoryTimings { impl ExecuteAccessoryTimings { pub fn accumulate(&mut self, other: &ExecuteAccessoryTimings) { saturating_add_assign!(self.feature_set_clone_us, other.feature_set_clone_us); - saturating_add_assign!( - self.compute_budget_process_transaction_us, - other.compute_budget_process_transaction_us - ); saturating_add_assign!(self.get_executors_us, other.get_executors_us); saturating_add_assign!(self.process_message_us, other.process_message_us); saturating_add_assign!(self.update_executors_us, other.update_executors_us); diff --git a/svm/src/account_loader.rs b/svm/src/account_loader.rs index 217fe43011..c62963c09e 100644 --- a/svm/src/account_loader.rs +++ b/svm/src/account_loader.rs @@ -6,7 +6,9 @@ use { transaction_processing_callback::TransactionProcessingCallback, }, itertools::Itertools, - solana_compute_budget::compute_budget_processor::process_compute_budget_instructions, + solana_compute_budget::compute_budget_processor::{ + process_compute_budget_instructions, ComputeBudgetLimits, + }, solana_program_runtime::loaded_programs::{ProgramCacheEntry, ProgramCacheForTxBatch}, solana_sdk::{ account::{Account, AccountSharedData, ReadableAccount, WritableAccount}, @@ -45,6 +47,7 @@ pub struct CheckedTransactionDetails { #[cfg_attr(feature = "dev-context-only-utils", derive(Default))] pub struct ValidatedTransactionDetails { pub rollback_accounts: RollbackAccounts, + pub compute_budget_limits: ComputeBudgetLimits, pub fee_details: FeeDetails, pub fee_payer_account: AccountSharedData, pub fee_payer_rent_debit: u64, @@ -56,6 +59,7 @@ pub struct LoadedTransaction { pub program_indices: TransactionProgramIndices, pub fee_details: FeeDetails, pub rollback_accounts: RollbackAccounts, + pub compute_budget_limits: ComputeBudgetLimits, pub rent: TransactionRent, pub rent_debits: RentDebits, pub loaded_accounts_data_size: usize, @@ -358,6 +362,7 @@ fn load_transaction_accounts( program_indices, fee_details: tx_details.fee_details, rollback_accounts: tx_details.rollback_accounts, + compute_budget_limits: tx_details.compute_budget_limits, rent: tx_rent, rent_debits, loaded_accounts_data_size: accumulated_accounts_data_size, @@ -1140,10 +1145,9 @@ mod tests { &mock_bank, sanitized_transaction.message(), ValidatedTransactionDetails { - rollback_accounts: RollbackAccounts::default(), - fee_details: FeeDetails::default(), fee_payer_account: fee_payer_account_data.clone(), fee_payer_rent_debit, + ..ValidatedTransactionDetails::default() }, &mut error_metrics, None, @@ -1164,6 +1168,7 @@ mod tests { program_indices: vec![], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: fee_payer_rent_debit, rent_debits: expected_rent_debits, loaded_accounts_data_size: 0, @@ -1208,10 +1213,8 @@ mod tests { &mock_bank, sanitized_transaction.message(), ValidatedTransactionDetails { - rollback_accounts: RollbackAccounts::default(), - fee_details: FeeDetails::default(), fee_payer_account: fee_payer_account_data.clone(), - fee_payer_rent_debit: 0, + ..ValidatedTransactionDetails::default() }, &mut error_metrics, None, @@ -1233,6 +1236,7 @@ mod tests { program_indices: vec![vec![]], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1416,10 +1420,8 @@ mod tests { &mock_bank, sanitized_transaction.message(), ValidatedTransactionDetails { - rollback_accounts: RollbackAccounts::default(), - fee_details: FeeDetails::default(), fee_payer_account: fee_payer_account_data.clone(), - fee_payer_rent_debit: 0, + ..ValidatedTransactionDetails::default() }, &mut error_metrics, None, @@ -1440,6 +1442,7 @@ mod tests { ], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), program_indices: vec![vec![1]], rent: 0, rent_debits: RentDebits::default(), @@ -1598,10 +1601,8 @@ mod tests { &mock_bank, sanitized_transaction.message(), ValidatedTransactionDetails { - rollback_accounts: RollbackAccounts::default(), - fee_details: FeeDetails::default(), fee_payer_account: fee_payer_account_data.clone(), - fee_payer_rent_debit: 0, + ..ValidatedTransactionDetails::default() }, &mut error_metrics, None, @@ -1627,6 +1628,7 @@ mod tests { program_indices: vec![vec![2, 1]], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1689,10 +1691,8 @@ mod tests { &mock_bank, sanitized_transaction.message(), ValidatedTransactionDetails { - rollback_accounts: RollbackAccounts::default(), - fee_details: FeeDetails::default(), fee_payer_account: fee_payer_account_data.clone(), - fee_payer_rent_debit: 0, + ..ValidatedTransactionDetails::default() }, &mut error_metrics, None, @@ -1721,6 +1721,7 @@ mod tests { program_indices: vec![vec![3, 1], vec![3, 1]], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1841,10 +1842,8 @@ mod tests { false, ); let validation_result = Ok(ValidatedTransactionDetails { - rollback_accounts: RollbackAccounts::default(), - fee_details: FeeDetails::default(), fee_payer_account: fee_payer_account_data, - fee_payer_rent_debit: 0, + ..ValidatedTransactionDetails::default() }); let results = load_accounts( @@ -1884,6 +1883,7 @@ mod tests { program_indices: vec![vec![3, 1], vec![3, 1]], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1915,13 +1915,7 @@ mod tests { false, ); - let validation_result = Ok(ValidatedTransactionDetails { - rollback_accounts: RollbackAccounts::default(), - fee_details: FeeDetails::default(), - fee_payer_account: AccountSharedData::default(), - fee_payer_rent_debit: 0, - }); - + let validation_result = Ok(ValidatedTransactionDetails::default()); let result = load_accounts( &mock_bank, &[sanitized_transaction.clone()], diff --git a/svm/src/transaction_error_metrics.rs b/svm/src/transaction_error_metrics.rs index ebe4952b4e..d0f848205d 100644 --- a/svm/src/transaction_error_metrics.rs +++ b/svm/src/transaction_error_metrics.rs @@ -16,6 +16,7 @@ pub struct TransactionErrorMetrics { pub invalid_account_for_fee: usize, pub invalid_account_index: usize, pub invalid_program_for_execution: usize, + pub invalid_compute_budget: usize, pub not_allowed_during_cluster_maintenance: usize, pub invalid_writable_account: usize, pub invalid_rent_paying_account: usize, @@ -50,6 +51,7 @@ impl TransactionErrorMetrics { self.invalid_program_for_execution, other.invalid_program_for_execution ); + saturating_add_assign!(self.invalid_compute_budget, other.invalid_compute_budget); saturating_add_assign!( self.not_allowed_during_cluster_maintenance, other.not_allowed_during_cluster_maintenance @@ -127,6 +129,11 @@ impl TransactionErrorMetrics { self.invalid_program_for_execution as i64, i64 ), + ( + "invalid_compute_budget", + self.invalid_compute_budget as i64, + i64 + ), ( "not_allowed_during_cluster_maintenance", self.not_allowed_during_cluster_maintenance as i64, diff --git a/svm/src/transaction_processor.rs b/svm/src/transaction_processor.rs index f76d6310e6..fcbc2bef72 100644 --- a/svm/src/transaction_processor.rs +++ b/svm/src/transaction_processor.rs @@ -42,7 +42,7 @@ use { include_loaded_accounts_data_size_in_fee_calculation, remove_rounding_in_fee_calculation, FeatureSet, }, - fee::FeeStructure, + fee::{FeeBudgetLimits, FeeStructure}, hash::Hash, inner_instruction::{InnerInstruction, InnerInstructionsList}, instruction::{CompiledInstruction, TRANSACTION_LEVEL_STACK_HEIGHT}, @@ -298,31 +298,9 @@ impl TransactionBatchProcessor { .map(|(load_result, tx)| match load_result { Err(e) => TransactionExecutionResult::NotExecuted(e.clone()), Ok(loaded_transaction) => { - let compute_budget = if let Some(compute_budget) = config.compute_budget { - compute_budget - } else { - let mut compute_budget_process_transaction_time = - Measure::start("compute_budget_process_transaction_time"); - let maybe_compute_budget = ComputeBudget::try_from_instructions( - tx.message().program_instructions_iter(), - ); - compute_budget_process_transaction_time.stop(); - saturating_add_assign!( - execute_timings - .execute_accessories - .compute_budget_process_transaction_us, - compute_budget_process_transaction_time.as_us() - ); - if let Err(err) = maybe_compute_budget { - return TransactionExecutionResult::NotExecuted(err); - } - maybe_compute_budget.unwrap() - }; - let result = self.execute_loaded_transaction( tx, loaded_transaction, - compute_budget, &mut execute_timings, &mut error_metrics, &mut program_cache_for_tx_batch.borrow_mut(), @@ -438,6 +416,14 @@ impl TransactionBatchProcessor { rent_collector: &RentCollector, error_counters: &mut TransactionErrorMetrics, ) -> transaction::Result { + let compute_budget_limits = process_compute_budget_instructions( + message.program_instructions_iter(), + ) + .map_err(|err| { + error_counters.invalid_compute_budget += 1; + err + })?; + let fee_payer_address = message.fee_payer(); let Some(mut fee_payer_account) = callbacks.get_account_shared_data(fee_payer_address) else { @@ -459,12 +445,11 @@ impl TransactionBatchProcessor { lamports_per_signature, } = checked_details; + let fee_budget_limits = FeeBudgetLimits::from(compute_budget_limits); let fee_details = fee_structure.calculate_fee_details( message, lamports_per_signature, - &process_compute_budget_instructions(message.program_instructions_iter()) - .unwrap_or_default() - .into(), + &fee_budget_limits, feature_set.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()), feature_set.is_active(&remove_rounding_in_fee_calculation::id()), ); @@ -494,6 +479,7 @@ impl TransactionBatchProcessor { fee_payer_account, fee_payer_rent_debit, rollback_accounts, + compute_budget_limits, }) } @@ -709,7 +695,6 @@ impl TransactionBatchProcessor { &self, tx: &SanitizedTransaction, loaded_transaction: &mut LoadedTransaction, - compute_budget: ComputeBudget, execute_timings: &mut ExecuteTimings, error_metrics: &mut TransactionErrorMetrics, program_cache_for_tx_batch: &mut ProgramCacheForTxBatch, @@ -738,6 +723,10 @@ impl TransactionBatchProcessor { let lamports_before_tx = transaction_accounts_lamports_sum(&transaction_accounts, tx.message()).unwrap_or(0); + let compute_budget = config + .compute_budget + .unwrap_or_else(|| ComputeBudget::from(loaded_transaction.compute_budget_limits)); + let mut transaction_context = TransactionContext::new( transaction_accounts, rent.clone(), @@ -989,6 +978,7 @@ mod tests { account_loader::ValidatedTransactionDetails, nonce_info::NoncePartial, rollback_accounts::RollbackAccounts, }, + solana_compute_budget::compute_budget_processor::ComputeBudgetLimits, solana_program_runtime::loaded_programs::{BlockRelation, ProgramCacheEntryType}, solana_sdk::{ account::{create_account_shared_data_for_test, WritableAccount}, @@ -1149,6 +1139,7 @@ mod tests { program_indices: vec![vec![0]], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 32, @@ -1162,7 +1153,6 @@ mod tests { let result = batch_processor.execute_loaded_transaction( &sanitized_transaction, &mut loaded_transaction, - ComputeBudget::default(), &mut ExecuteTimings::default(), &mut TransactionErrorMetrics::default(), &mut program_cache_for_tx_batch, @@ -1184,7 +1174,6 @@ mod tests { let result = batch_processor.execute_loaded_transaction( &sanitized_transaction, &mut loaded_transaction, - ComputeBudget::default(), &mut ExecuteTimings::default(), &mut TransactionErrorMetrics::default(), &mut program_cache_for_tx_batch, @@ -1214,7 +1203,6 @@ mod tests { let result = batch_processor.execute_loaded_transaction( &sanitized_transaction, &mut loaded_transaction, - ComputeBudget::default(), &mut ExecuteTimings::default(), &mut TransactionErrorMetrics::default(), &mut program_cache_for_tx_batch, @@ -1276,6 +1264,7 @@ mod tests { program_indices: vec![vec![0]], fee_details: FeeDetails::default(), rollback_accounts: RollbackAccounts::default(), + compute_budget_limits: ComputeBudgetLimits::default(), rent: 0, rent_debits: RentDebits::default(), loaded_accounts_data_size: 0, @@ -1290,7 +1279,6 @@ mod tests { let _ = batch_processor.execute_loaded_transaction( &sanitized_transaction, &mut loaded_transaction, - ComputeBudget::default(), &mut ExecuteTimings::default(), &mut error_metrics, &mut program_cache_for_tx_batch, @@ -1954,6 +1942,8 @@ mod tests { Some(&Pubkey::new_unique()), &Hash::new_unique(), )); + let compute_budget_limits = + process_compute_budget_instructions(message.program_instructions_iter()).unwrap(); let fee_payer_address = message.fee_payer(); let current_epoch = 42; let rent_collector = RentCollector { @@ -2016,6 +2006,7 @@ mod tests { fee_payer_rent_debit, fee_payer_rent_epoch ), + compute_budget_limits, fee_details: FeeDetails::new_for_tests(transaction_fee, priority_fee, false), fee_payer_rent_debit, fee_payer_account: post_validation_fee_payer_account, @@ -2031,6 +2022,8 @@ mod tests { Some(&Pubkey::new_unique()), &Hash::new_unique(), )); + let compute_budget_limits = + process_compute_budget_instructions(message.program_instructions_iter()).unwrap(); let fee_payer_address = message.fee_payer(); let mut rent_collector = RentCollector::default(); rent_collector.rent.lamports_per_byte_year = 1_000_000; @@ -2085,6 +2078,7 @@ mod tests { fee_payer_rent_debit, 0, // rent epoch ), + compute_budget_limits, fee_details: FeeDetails::new_for_tests(transaction_fee, 0, false), fee_payer_rent_debit, fee_payer_account: post_validation_fee_payer_account, @@ -2220,6 +2214,37 @@ mod tests { assert_eq!(result, Err(TransactionError::InvalidAccountForFee)); } + #[test] + fn test_validate_transaction_fee_payer_invalid_compute_budget() { + let lamports_per_signature = 5000; + let message = new_unchecked_sanitized_message(Message::new( + &[ + ComputeBudgetInstruction::set_compute_unit_limit(2000u32), + ComputeBudgetInstruction::set_compute_unit_limit(42u32), + ], + Some(&Pubkey::new_unique()), + )); + + let mock_bank = MockBankCallback::default(); + let mut error_counters = TransactionErrorMetrics::default(); + let batch_processor = TransactionBatchProcessor::::default(); + let result = batch_processor.validate_transaction_fee_payer( + &mock_bank, + &message, + CheckedTransactionDetails { + nonce: None, + lamports_per_signature, + }, + &FeatureSet::default(), + &FeeStructure::default(), + &RentCollector::default(), + &mut error_counters, + ); + + assert_eq!(error_counters.invalid_compute_budget, 1); + assert_eq!(result, Err(TransactionError::DuplicateInstruction(1u8))); + } + #[test] fn test_validate_transaction_fee_payer_is_nonce() { let feature_set = FeatureSet::default(); @@ -2234,6 +2259,8 @@ mod tests { Some(&Pubkey::new_unique()), &Hash::new_unique(), )); + let compute_budget_limits = + process_compute_budget_instructions(message.program_instructions_iter()).unwrap(); let fee_payer_address = message.fee_payer(); let min_balance = Rent::default().minimum_balance(nonce::State::size()); let transaction_fee = lamports_per_signature; @@ -2292,6 +2319,7 @@ mod tests { 0, // fee_payer_rent_debit 0, // fee_payer_rent_epoch ), + compute_budget_limits, fee_details: FeeDetails::new_for_tests(transaction_fee, priority_fee, false), fee_payer_rent_debit: 0, // rent due fee_payer_account: post_validation_fee_payer_account,