diff --git a/cost-model/src/cost_model.rs b/cost-model/src/cost_model.rs index 0fb631140..a6e7bc917 100644 --- a/cost-model/src/cost_model.rs +++ b/cost-model/src/cost_model.rs @@ -17,6 +17,7 @@ use { include_loaded_accounts_data_size_in_fee_calculation, remove_deprecated_request_unit_ix, FeatureSet, }, + fee::FeeStructure, instruction::CompiledInstruction, program_utils::limited_deserialize, pubkey::Pubkey, @@ -26,8 +27,6 @@ use { }, }; -const ACCOUNT_DATA_COST_PAGE_SIZE: u64 = 32_u64.saturating_mul(1024); - pub struct CostModel; impl CostModel { @@ -57,10 +56,10 @@ impl CostModel { // limit of 64MB; which will convert to (64M/32K)*8CU = 16_000 CUs // pub fn calculate_loaded_accounts_data_size_cost(compute_budget: &ComputeBudget) -> u64 { - (compute_budget.loaded_accounts_data_size_limit as u64) - .saturating_add(ACCOUNT_DATA_COST_PAGE_SIZE.saturating_sub(1)) - .saturating_div(ACCOUNT_DATA_COST_PAGE_SIZE) - .saturating_mul(compute_budget.heap_cost) + FeeStructure::calculate_memory_usage_cost( + compute_budget.loaded_accounts_data_size_limit, + compute_budget.heap_cost, + ) } fn get_signature_cost(transaction: &SanitizedTransaction) -> u64 { @@ -209,6 +208,7 @@ mod tests { super::*, solana_sdk::{ compute_budget::{self, ComputeBudgetInstruction}, + fee::ACCOUNT_DATA_COST_PAGE_SIZE, hash::Hash, instruction::CompiledInstruction, message::Message, diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index 7f00f4386..e8174aec7 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -4,6 +4,12 @@ use { borsh::try_from_slice_unchecked, compute_budget::{self, ComputeBudgetInstruction}, entrypoint::HEAP_LENGTH as MIN_HEAP_FRAME_BYTES, + feature_set::{ + add_set_tx_loaded_accounts_data_size_instruction, enable_request_heap_frame_ix, + remove_deprecated_request_unit_ix, use_default_units_in_fee_calculation, FeatureSet, + }, + fee::FeeBudgetLimits, + genesis_config::ClusterType, instruction::{CompiledInstruction, InstructionError}, pubkey::Pubkey, transaction::TransactionError, @@ -276,6 +282,39 @@ impl ComputeBudget { .map(|fee_type| PrioritizationFeeDetails::new(fee_type, self.compute_unit_limit)) .unwrap_or_default()) } + + pub fn fee_budget_limits<'a>( + instructions: impl Iterator, + feature_set: &FeatureSet, + maybe_cluster_type: Option, + ) -> FeeBudgetLimits { + let mut compute_budget = Self::default(); + + // A cluster specific feature gate, when not activated it keeps v1.13 behavior in mainnet-beta; + // once activated for v1.14+, it allows compute_budget::request_heap_frame and + // compute_budget::set_compute_unit_price co-exist in same transaction. + let enable_request_heap_frame_ix = feature_set + .is_active(&enable_request_heap_frame_ix::id()) + || maybe_cluster_type + .and_then(|cluster_type| (cluster_type != ClusterType::MainnetBeta).then_some(0)) + .is_some(); + let prioritization_fee_details = compute_budget + .process_instructions( + instructions, + feature_set.is_active(&use_default_units_in_fee_calculation::id()), + !feature_set.is_active(&remove_deprecated_request_unit_ix::id()), + enable_request_heap_frame_ix, + feature_set.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()), + ) + .unwrap_or_default(); + + FeeBudgetLimits { + loaded_accounts_data_size_limit: compute_budget.loaded_accounts_data_size_limit, + heap_cost: compute_budget.heap_cost, + compute_unit_limit: compute_budget.compute_unit_limit, + prioritization_fee: prioritization_fee_details.get_fee(), + } + } } #[cfg(test)] diff --git a/programs/sbf/tests/programs.rs b/programs/sbf/tests/programs.rs index 373c7c3e1..a3f033062 100644 --- a/programs/sbf/tests/programs.rs +++ b/programs/sbf/tests/programs.rs @@ -40,7 +40,7 @@ use { clock::MAX_PROCESSING_AGE, compute_budget::ComputeBudgetInstruction, entrypoint::MAX_PERMITTED_DATA_INCREASE, - feature_set::{self, FeatureSet}, + feature_set::{self, remove_deprecated_request_unit_ix, FeatureSet}, fee::FeeStructure, loader_instruction, message::{v0::LoadedAddresses, SanitizedMessage}, @@ -3824,15 +3824,19 @@ fn test_program_fees() { Some(&mint_keypair.pubkey()), ); + let mut feature_set = FeatureSet::all_enabled(); + feature_set.deactivate(&remove_deprecated_request_unit_ix::id()); + let sanitized_message = SanitizedMessage::try_from(message.clone()).unwrap(); let expected_normal_fee = Bank::calculate_fee( &sanitized_message, congestion_multiplier, &fee_structure, - true, - false, - true, - true, + &ComputeBudget::fee_budget_limits( + sanitized_message.program_instructions_iter(), + &feature_set, + None, + ), true, false, ); @@ -3851,14 +3855,17 @@ fn test_program_fees() { Some(&mint_keypair.pubkey()), ); let sanitized_message = SanitizedMessage::try_from(message.clone()).unwrap(); + let mut feature_set = FeatureSet::all_enabled(); + feature_set.deactivate(&remove_deprecated_request_unit_ix::id()); let expected_prioritized_fee = Bank::calculate_fee( &sanitized_message, congestion_multiplier, &fee_structure, - true, - false, - true, - true, + &ComputeBudget::fee_budget_limits( + sanitized_message.program_instructions_iter(), + &feature_set, + None, + ), true, false, ); diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index a9c3b22fc..f89c5d41e 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -36,11 +36,10 @@ use { bpf_loader_upgradeable::{self, UpgradeableLoaderState}, clock::{BankId, Slot}, feature_set::{ - self, add_set_tx_loaded_accounts_data_size_instruction, enable_request_heap_frame_ix, + self, add_set_tx_loaded_accounts_data_size_instruction, include_loaded_accounts_data_size_in_fee_calculation, remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix, - simplify_writable_program_account_check, use_default_units_in_fee_calculation, - FeatureSet, + simplify_writable_program_account_check, FeatureSet, }, fee::FeeStructure, genesis_config::ClusterType, @@ -727,11 +726,8 @@ impl Accounts { tx.message(), lamports_per_signature, fee_structure, - feature_set.is_active(&use_default_units_in_fee_calculation::id()), - !feature_set.is_active(&remove_deprecated_request_unit_ix::id()), + &ComputeBudget::fee_budget_limits(tx.message().program_instructions_iter(), feature_set, Some(self.accounts_db.expected_cluster_type())), feature_set.is_active(&remove_congestion_multiplier_from_fee_calculation::id()), - feature_set.is_active(&enable_request_heap_frame_ix::id()) || self.accounts_db.expected_cluster_type() != ClusterType::MainnetBeta, - feature_set.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()), feature_set.is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()), ) } else { @@ -1761,14 +1757,19 @@ mod tests { instructions, ); + let mut feature_set = FeatureSet::all_enabled(); + feature_set.deactivate(&remove_deprecated_request_unit_ix::id()); + + let message = SanitizedMessage::try_from(tx.message().clone()).unwrap(); let fee = Bank::calculate_fee( - &SanitizedMessage::try_from(tx.message().clone()).unwrap(), + &message, lamports_per_signature, &FeeStructure::default(), - true, - false, - true, - true, + &ComputeBudget::fee_budget_limits( + message.program_instructions_iter(), + &feature_set, + None, + ), true, false, ); @@ -4324,14 +4325,19 @@ mod tests { Hash::default(), ); + let mut feature_set = FeatureSet::all_enabled(); + feature_set.deactivate(&remove_deprecated_request_unit_ix::id()); + + let message = SanitizedMessage::try_from(tx.message().clone()).unwrap(); let fee = Bank::calculate_fee( - &SanitizedMessage::try_from(tx.message().clone()).unwrap(), + &message, lamports_per_signature, &FeeStructure::default(), - true, - false, - true, - true, + &ComputeBudget::fee_budget_limits( + message.program_instructions_iter(), + &feature_set, + None, + ), true, false, ); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index cadcf3056..a159685d0 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -96,7 +96,7 @@ use { ThreadPool, ThreadPoolBuilder, }, solana_bpf_loader_program::syscalls::create_program_runtime_environment, - solana_cost_model::{cost_model::CostModel, cost_tracker::CostTracker}, + solana_cost_model::cost_tracker::CostTracker, solana_measure::{measure, measure::Measure, measure_us}, solana_perf::perf_libs, solana_program_runtime::{ @@ -131,10 +131,10 @@ use { feature, feature_set::{ self, add_set_tx_loaded_accounts_data_size_instruction, - enable_early_verification_of_account_modifications, enable_request_heap_frame_ix, + enable_early_verification_of_account_modifications, include_loaded_accounts_data_size_in_fee_calculation, remove_congestion_multiplier_from_fee_calculation, remove_deprecated_request_unit_ix, - use_default_units_in_fee_calculation, FeatureSet, + FeatureSet, }, fee::FeeStructure, fee_calculator::{FeeCalculator, FeeRateGovernor}, @@ -267,6 +267,7 @@ pub struct BankRc { #[cfg(RUSTC_WITH_SPECIALIZATION)] use solana_frozen_abi::abi_example::AbiExample; +use solana_sdk::fee::FeeBudgetLimits; #[cfg(RUSTC_WITH_SPECIALIZATION)] impl AbiExample for BankRc { @@ -4226,23 +4227,7 @@ impl Bank { NoncePartial::new(address, account).lamports_per_signature() }) })?; - Some(Self::calculate_fee( - message, - lamports_per_signature, - &self.fee_structure, - self.feature_set - .is_active(&use_default_units_in_fee_calculation::id()), - !self - .feature_set - .is_active(&remove_deprecated_request_unit_ix::id()), - self.feature_set - .is_active(&remove_congestion_multiplier_from_fee_calculation::id()), - self.enable_request_heap_frame_ix(), - self.feature_set - .is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()), - self.feature_set - .is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()), - )) + Some(self.get_fee_for_message_with_lamports_per_signature(message, lamports_per_signature)) } pub fn get_startup_verification_complete(&self) -> &Arc { @@ -4281,16 +4266,13 @@ impl Bank { message, lamports_per_signature, &self.fee_structure, - self.feature_set - .is_active(&use_default_units_in_fee_calculation::id()), - !self - .feature_set - .is_active(&remove_deprecated_request_unit_ix::id()), + &ComputeBudget::fee_budget_limits( + message.program_instructions_iter(), + &self.feature_set, + Some(self.cluster_type()), + ), self.feature_set .is_active(&remove_congestion_multiplier_from_fee_calculation::id()), - self.enable_request_heap_frame_ix(), - self.feature_set - .is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()), self.feature_set .is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()), ) @@ -5083,15 +5065,6 @@ impl Bank { } } - // A cluster specific feature gate, when not activated it keeps v1.13 behavior in mainnet-beta; - // once activated for v1.14+, it allows compute_budget::request_heap_frame and - // compute_budget::set_compute_unit_price co-exist in same transaction. - fn enable_request_heap_frame_ix(&self) -> bool { - self.feature_set - .is_active(&enable_request_heap_frame_ix::id()) - || self.cluster_type() != ClusterType::MainnetBeta - } - fn replenish_program_cache( &self, program_accounts_map: &HashMap, @@ -5556,11 +5529,8 @@ impl Bank { message: &SanitizedMessage, lamports_per_signature: u64, fee_structure: &FeeStructure, - use_default_units_per_instruction: bool, - support_request_units_deprecated: bool, + budget_limits: &FeeBudgetLimits, remove_congestion_multiplier: bool, - enable_request_heap_frame_ix: bool, - support_set_accounts_data_size_limit_ix: bool, include_loaded_account_data_size_in_fee: bool, ) -> u64 { // Fee based on compute units and signatures @@ -5574,17 +5544,6 @@ impl Bank { BASE_CONGESTION / current_congestion }; - let mut compute_budget = ComputeBudget::default(); - let prioritization_fee_details = compute_budget - .process_instructions( - message.program_instructions_iter(), - use_default_units_per_instruction, - support_request_units_deprecated, - enable_request_heap_frame_ix, - support_set_accounts_data_size_limit_ix, - ) - .unwrap_or_default(); - let prioritization_fee = prioritization_fee_details.get_fee(); let signature_fee = message .num_signatures() .saturating_mul(fee_structure.lamports_per_signature); @@ -5595,12 +5554,15 @@ impl Bank { // `compute_fee` covers costs for both requested_compute_units and // requested_loaded_account_data_size let loaded_accounts_data_size_cost = if include_loaded_account_data_size_in_fee { - CostModel::calculate_loaded_accounts_data_size_cost(&compute_budget) + FeeStructure::calculate_memory_usage_cost( + budget_limits.loaded_accounts_data_size_limit, + budget_limits.heap_cost, + ) } else { 0_u64 }; let total_compute_units = - loaded_accounts_data_size_cost.saturating_add(compute_budget.compute_unit_limit); + loaded_accounts_data_size_cost.saturating_add(budget_limits.compute_unit_limit); let compute_fee = fee_structure .compute_fee_bins .iter() @@ -5614,7 +5576,8 @@ impl Bank { .unwrap_or_default() }); - ((prioritization_fee + ((budget_limits + .prioritization_fee .saturating_add(signature_fee) .saturating_add(write_lock_fee) .saturating_add(compute_fee) as f64) @@ -5653,22 +5616,9 @@ impl Bank { let lamports_per_signature = lamports_per_signature.ok_or(TransactionError::BlockhashNotFound)?; - let fee = Self::calculate_fee( + let fee = self.get_fee_for_message_with_lamports_per_signature( tx.message(), lamports_per_signature, - &self.fee_structure, - self.feature_set - .is_active(&use_default_units_in_fee_calculation::id()), - !self - .feature_set - .is_active(&remove_deprecated_request_unit_ix::id()), - self.feature_set - .is_active(&remove_congestion_multiplier_from_fee_calculation::id()), - self.enable_request_heap_frame_ix(), - self.feature_set - .is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()), - self.feature_set - .is_active(&include_loaded_accounts_data_size_in_fee_calculation::id()), ); // In case of instruction error, even though no accounts diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index f92fc21b3..019013b23 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -60,7 +60,7 @@ use { entrypoint::MAX_PERMITTED_DATA_INCREASE, epoch_schedule::{EpochSchedule, MINIMUM_SLOTS_PER_EPOCH}, feature::{self, Feature}, - feature_set::{self, FeatureSet}, + feature_set::{self, enable_request_heap_frame_ix, FeatureSet}, fee::FeeStructure, fee_calculator::FeeRateGovernor, genesis_config::{create_genesis_config, ClusterType, GenesisConfig}, @@ -2870,19 +2870,16 @@ fn test_bank_tx_compute_unit_fee() { } = create_genesis_config_with_leader(mint, &leader, 3); genesis_config.fee_rate_governor = FeeRateGovernor::new(4, 0); // something divisible by 2 - let expected_fee_paid = Bank::calculate_fee( + let expected_fee_paid = calculate_test_fee( &SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(), genesis_config .fee_rate_governor .create_fee_calculator() .lamports_per_signature, &FeeStructure::default(), - true, false, true, true, - true, - false, ); let (expected_fee_collected, expected_fee_burned) = @@ -3058,16 +3055,13 @@ fn test_bank_blockhash_compute_unit_fee_structure() { let tx = system_transaction::transfer(&mint_keypair, &key, 1, cheap_blockhash); assert_eq!(bank.process_transaction(&tx), Ok(())); assert_eq!(bank.get_balance(&key), 1); - let cheap_fee = Bank::calculate_fee( + let cheap_fee = calculate_test_fee( &SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(), cheap_lamports_per_signature, &FeeStructure::default(), - true, false, true, true, - true, - false, ); assert_eq!( bank.get_balance(&mint_keypair.pubkey()), @@ -3080,16 +3074,13 @@ fn test_bank_blockhash_compute_unit_fee_structure() { let tx = system_transaction::transfer(&mint_keypair, &key, 1, expensive_blockhash); assert_eq!(bank.process_transaction(&tx), Ok(())); assert_eq!(bank.get_balance(&key), 1); - let expensive_fee = Bank::calculate_fee( + let expensive_fee = calculate_test_fee( &SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(), expensive_lamports_per_signature, &FeeStructure::default(), - true, false, true, true, - true, - false, ); assert_eq!( bank.get_balance(&mint_keypair.pubkey()), @@ -3193,7 +3184,7 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() { + bank .fee_rate_governor .burn( - Bank::calculate_fee( + calculate_test_fee( &SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))) .unwrap(), genesis_config @@ -3201,12 +3192,9 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() { .create_fee_calculator() .lamports_per_signature, &FeeStructure::default(), - true, false, true, true, - true, - false, ) * 2 ) .0 @@ -10122,6 +10110,37 @@ fn test_call_precomiled_program() { bank.process_transaction(&tx).unwrap(); } +fn calculate_test_fee( + message: &SanitizedMessage, + lamports_per_signature: u64, + fee_structure: &FeeStructure, + support_set_accounts_data_size_limit_ix: bool, + enable_request_heap_frame_ix: bool, + remove_congestion_multiplier: bool, +) -> u64 { + let mut feature_set = FeatureSet::all_enabled(); + feature_set.deactivate(&remove_deprecated_request_unit_ix::id()); + + if !support_set_accounts_data_size_limit_ix { + feature_set.deactivate(&include_loaded_accounts_data_size_in_fee_calculation::id()); + } + + if !enable_request_heap_frame_ix { + feature_set.deactivate(&enable_request_heap_frame_ix::id()); + } + + let budget_limits = + ComputeBudget::fee_budget_limits(message.program_instructions_iter(), &feature_set, None); + Bank::calculate_fee( + message, + lamports_per_signature, + fee_structure, + &budget_limits, + remove_congestion_multiplier, + false, + ) +} + #[test] fn test_calculate_fee() { // Default: no fee. @@ -10129,19 +10148,16 @@ fn test_calculate_fee() { SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(); for support_set_accounts_data_size_limit_ix in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, 0, &FeeStructure { lamports_per_signature: 0, ..FeeStructure::default() }, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ), 0 ); @@ -10150,19 +10166,16 @@ fn test_calculate_fee() { // One signature, a fee. for support_set_accounts_data_size_limit_ix in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, 1, &FeeStructure { lamports_per_signature: 1, ..FeeStructure::default() }, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ), 1 ); @@ -10176,19 +10189,16 @@ fn test_calculate_fee() { let message = SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&key0))).unwrap(); for support_set_accounts_data_size_limit_ix in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, 2, &FeeStructure { lamports_per_signature: 2, ..FeeStructure::default() }, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ), 4 ); @@ -10210,16 +10220,13 @@ fn test_calculate_fee_compute_units() { SanitizedMessage::try_from(Message::new(&[], Some(&Pubkey::new_unique()))).unwrap(); for support_set_accounts_data_size_limit_ix in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, 1, &fee_structure, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ), max_fee + lamports_per_signature ); @@ -10233,16 +10240,13 @@ fn test_calculate_fee_compute_units() { SanitizedMessage::try_from(Message::new(&[ix0, ix1], Some(&Pubkey::new_unique()))).unwrap(); for support_set_accounts_data_size_limit_ix in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, 1, &fee_structure, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ), max_fee + 3 * lamports_per_signature ); @@ -10278,16 +10282,13 @@ fn test_calculate_fee_compute_units() { )) .unwrap(); for support_set_accounts_data_size_limit_ix in [true, false] { - let fee = Bank::calculate_fee( + let fee = calculate_test_fee( &message, 1, &fee_structure, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ); assert_eq!( fee, @@ -10321,16 +10322,13 @@ fn test_calculate_prioritization_fee() { )) .unwrap(); - let fee = Bank::calculate_fee( + let fee = calculate_test_fee( &message, fee_structure.lamports_per_signature, &fee_structure, - true, // use_default_units_per_instruction - false, // not support_request_units_deprecated - true, // remove_congestion_multiplier - true, // enable_request_heap_frame_ix - true, // support_set_accounts_data_size_limit_ix, - false, // include_loaded_account_data_size_in_fee + true, + true, + true, ); assert_eq!( fee, @@ -10370,16 +10368,13 @@ fn test_calculate_fee_secp256k1() { .unwrap(); for support_set_accounts_data_size_limit_ix in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, 1, &fee_structure, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ), 2 ); @@ -10394,16 +10389,13 @@ fn test_calculate_fee_secp256k1() { .unwrap(); for support_set_accounts_data_size_limit_ix in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, 1, &fee_structure, - true, - false, - true, - true, support_set_accounts_data_size_limit_ix, - false, + true, + true, ), 11 ); @@ -12051,16 +12043,13 @@ fn test_calculate_fee_with_congestion_multiplier() { // congestion_multiplier has no effect on fee. for remove_congestion_multiplier in [true, false] { assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, cheap_lamports_per_signature, &fee_structure, true, - false, + true, remove_congestion_multiplier, - true, - true, - false, ), signature_fee * signature_count ); @@ -12076,16 +12065,13 @@ fn test_calculate_fee_with_congestion_multiplier() { }; assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, expensive_lamports_per_signature, &fee_structure, true, - false, + true, remove_congestion_multiplier, - true, - true, - false, ), signature_fee * signature_count / denominator ); @@ -12119,16 +12105,13 @@ fn test_calculate_fee_with_request_heap_frame_flag() { // into transaction fee let mut enable_request_heap_frame_ix = true; assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, lamports_per_signature, &fee_structure, true, - false, - true, enable_request_heap_frame_ix, true, - false, ), signature_fee + request_cu * lamports_per_cu ); @@ -12137,16 +12120,13 @@ fn test_calculate_fee_with_request_heap_frame_flag() { // into transaction fee enable_request_heap_frame_ix = false; assert_eq!( - Bank::calculate_fee( + calculate_test_fee( &message, lamports_per_signature, &fee_structure, true, - false, - true, enable_request_heap_frame_ix, true, - false, ), signature_fee ); diff --git a/sdk/src/fee.rs b/sdk/src/fee.rs index 27556b63a..c308e871d 100644 --- a/sdk/src/fee.rs +++ b/sdk/src/fee.rs @@ -11,6 +11,13 @@ pub struct FeeBin { pub fee: u64, } +pub struct FeeBudgetLimits { + pub loaded_accounts_data_size_limit: usize, + pub heap_cost: u64, + pub compute_unit_limit: u64, + pub prioritization_fee: u64, +} + /// Information used to calculate fees #[derive(Debug, Clone, Eq, PartialEq)] pub struct FeeStructure { @@ -22,6 +29,8 @@ pub struct FeeStructure { pub compute_fee_bins: Vec, } +pub const ACCOUNT_DATA_COST_PAGE_SIZE: u64 = 32_u64.saturating_mul(1024); + impl FeeStructure { pub fn new( sol_per_signature: f64, @@ -53,6 +62,16 @@ impl FeeStructure { .unwrap_or_default(), ) } + + pub fn calculate_memory_usage_cost( + loaded_accounts_data_size_limit: usize, + heap_cost: u64, + ) -> u64 { + (loaded_accounts_data_size_limit as u64) + .saturating_add(ACCOUNT_DATA_COST_PAGE_SIZE.saturating_sub(1)) + .saturating_div(ACCOUNT_DATA_COST_PAGE_SIZE) + .saturating_mul(heap_cost) + } } impl Default for FeeStructure {