diff --git a/core/src/banking_stage/packet_deserializer.rs b/core/src/banking_stage/packet_deserializer.rs index a405b626568..5064fb2b2a4 100644 --- a/core/src/banking_stage/packet_deserializer.rs +++ b/core/src/banking_stage/packet_deserializer.rs @@ -9,6 +9,7 @@ use { crossbeam_channel::RecvTimeoutError, solana_perf::packet::PacketBatch, solana_runtime::bank_forks::BankForks, + solana_sdk::feature_set, std::{ sync::{Arc, RwLock}, time::{Duration, Instant}, @@ -55,8 +56,10 @@ impl PacketDeserializer { // Note: this can be removed after feature `round_compute_unit_price` is activated in // mainnet-beta - let _working_bank = self.bank_forks.read().unwrap().working_bank(); - let round_compute_unit_price_enabled = false; // TODO get from working_bank.feature_set + let working_bank = self.bank_forks.read().unwrap().working_bank(); + let round_compute_unit_price_enabled = working_bank + .feature_set + .is_active(&feature_set::round_compute_unit_price::id()); Ok(Self::deserialize_and_collect_packets( packet_count, diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index 7f00f4386dc..2d073f697e7 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -175,6 +175,7 @@ impl ComputeBudget { support_request_units_deprecated: bool, enable_request_heap_frame_ix: bool, support_set_loaded_accounts_data_size_limit_ix: bool, + round_compute_unit_price: bool, ) -> Result { let mut num_non_compute_budget_instructions: usize = 0; let mut updated_compute_unit_limit = None; @@ -221,8 +222,13 @@ impl ComputeBudget { if prioritization_fee.is_some() { return Err(duplicate_instruction_error); } - prioritization_fee = - Some(PrioritizationFeeType::ComputeUnitPrice(micro_lamports)); + prioritization_fee = Some(PrioritizationFeeType::ComputeUnitPrice( + if round_compute_unit_price { + Self::round_prioritization_fee(micro_lamports) + } else { + micro_lamports + }, + )); } Ok(ComputeBudgetInstruction::SetLoadedAccountsDataSizeLimit(bytes)) if support_set_loaded_accounts_data_size_limit_ix => @@ -276,6 +282,15 @@ impl ComputeBudget { .map(|fee_type| PrioritizationFeeDetails::new(fee_type, self.compute_unit_limit)) .unwrap_or_default()) } + + // https://github.com/solana-labs/solana/issues/31453 to round compute-unit-price, in micro-lamports, + // down to its nearest 1_000 micro-lamport. + const PRIORITY_FEE_TICK_SIZE: u64 = 1_000; + fn round_prioritization_fee(micro_lamports: u64) -> u64 { + micro_lamports + .saturating_div(Self::PRIORITY_FEE_TICK_SIZE) + .saturating_mul(Self::PRIORITY_FEE_TICK_SIZE) + } } #[cfg(test)] @@ -308,6 +323,7 @@ mod tests { false, /*not support request_units_deprecated*/ $enable_request_heap_frame_ix, $support_set_loaded_accounts_data_size_limit_ix, + false, // not support round_compute_unit_price, it is tested separately ); assert_eq!($expected_result, result); assert_eq!(compute_budget, $expected_budget); @@ -674,6 +690,115 @@ mod tests { ); } + #[test] + fn test_set_compute_unit_price_instruction() { + fn test_set_compute_unit_price( + instructions: &[Instruction], + expected_result: Result, + support_round_compute_unit_price: bool, + ) { + let payer_keypair = Keypair::new(); + let tx = SanitizedTransaction::from_transaction_for_tests(Transaction::new( + &[&payer_keypair], + Message::new(instructions, Some(&payer_keypair.pubkey())), + Hash::default(), + )); + let mut compute_budget = ComputeBudget::default(); + let result = compute_budget.process_instructions( + tx.message().program_instructions_iter(), + true, // default_units_per_instruction + true, // support_request_units_deprecated + true, // enable_request_heap_frame_ix + true, // support_set_loaded_accounts_data_size_limit_ix + support_round_compute_unit_price, + ); + assert_eq!(expected_result, result); + } + + for support_round_compute_unit_price in [true, false] { + test_set_compute_unit_price( + &[], + Ok(PrioritizationFeeDetails::default()), + support_round_compute_unit_price, + ); + } + + for support_round_compute_unit_price in [true, false] { + test_set_compute_unit_price( + &[ComputeBudgetInstruction::set_compute_unit_price(0)], + Ok(PrioritizationFeeDetails::new( + PrioritizationFeeType::ComputeUnitPrice(0), + 0, + )), + support_round_compute_unit_price, + ); + } + + for support_round_compute_unit_price in [true, false] { + let cu_price = ComputeBudget::PRIORITY_FEE_TICK_SIZE - 1; + let expected_cu_price = if support_round_compute_unit_price { + 0 + } else { + cu_price + }; + test_set_compute_unit_price( + &[ComputeBudgetInstruction::set_compute_unit_price(cu_price)], + Ok(PrioritizationFeeDetails::new( + PrioritizationFeeType::ComputeUnitPrice(expected_cu_price), + 0, + )), + support_round_compute_unit_price, + ); + } + + for support_round_compute_unit_price in [true, false] { + test_set_compute_unit_price( + &[ComputeBudgetInstruction::set_compute_unit_price( + ComputeBudget::PRIORITY_FEE_TICK_SIZE, + )], + Ok(PrioritizationFeeDetails::new( + PrioritizationFeeType::ComputeUnitPrice(ComputeBudget::PRIORITY_FEE_TICK_SIZE), + 0, + )), + support_round_compute_unit_price, + ); + } + + for support_round_compute_unit_price in [true, false] { + let cu_price = ComputeBudget::PRIORITY_FEE_TICK_SIZE + 1; + let expected_cu_price = if support_round_compute_unit_price { + ComputeBudget::PRIORITY_FEE_TICK_SIZE + } else { + cu_price + }; + test_set_compute_unit_price( + &[ComputeBudgetInstruction::set_compute_unit_price(cu_price)], + Ok(PrioritizationFeeDetails::new( + PrioritizationFeeType::ComputeUnitPrice(expected_cu_price), + 0, + )), + support_round_compute_unit_price, + ); + } + + for support_round_compute_unit_price in [true, false] { + let cu_price = 3 * ComputeBudget::PRIORITY_FEE_TICK_SIZE - 1; + let expected_cu_price = if support_round_compute_unit_price { + 2 * ComputeBudget::PRIORITY_FEE_TICK_SIZE + } else { + cu_price + }; + test_set_compute_unit_price( + &[ComputeBudgetInstruction::set_compute_unit_price(cu_price)], + Ok(PrioritizationFeeDetails::new( + PrioritizationFeeType::ComputeUnitPrice(expected_cu_price), + 0, + )), + support_round_compute_unit_price, + ); + } + } + #[test] fn test_process_loaded_accounts_data_size_limit_instruction() { let enable_request_heap_frame_ix: bool = true; @@ -835,4 +960,37 @@ mod tests { ); } } + + #[test] + fn test_round_prioritization_fee() { + assert_eq!( + ComputeBudget::round_prioritization_fee(1), + 0, + "less than 1_000 MICRO_LAMPORTS should round down to zero" + ); + + assert_eq!( + ComputeBudget::round_prioritization_fee(ComputeBudget::PRIORITY_FEE_TICK_SIZE - 1), + 0, + "less than 1_000 MICRO_LAMPORTS should round down to zero" + ); + + assert_eq!( + ComputeBudget::round_prioritization_fee(ComputeBudget::PRIORITY_FEE_TICK_SIZE), + ComputeBudget::PRIORITY_FEE_TICK_SIZE, + "1_000 MICRO_LAMPORTS should round to itself" + ); + + assert_eq!( + ComputeBudget::round_prioritization_fee(ComputeBudget::PRIORITY_FEE_TICK_SIZE + 1), + ComputeBudget::PRIORITY_FEE_TICK_SIZE, + "more than 1_000 MICRO_LAMPORTS should round down to the nearest" + ); + + assert_eq!( + ComputeBudget::round_prioritization_fee(ComputeBudget::PRIORITY_FEE_TICK_SIZE * 3 - 1), + ComputeBudget::PRIORITY_FEE_TICK_SIZE * 2, + "more than 1_000 MICRO_LAMPORTS should round down to the nearest" + ); + } } diff --git a/programs/sbf/tests/programs.rs b/programs/sbf/tests/programs.rs index 9a3910f4f7d..5a43b6459d6 100644 --- a/programs/sbf/tests/programs.rs +++ b/programs/sbf/tests/programs.rs @@ -3833,7 +3833,8 @@ fn test_program_fees() { true, true, true, - false, + true, + true, ); bank_client .send_and_confirm_message(&[&mint_keypair], message) @@ -3844,7 +3845,7 @@ fn test_program_fees() { let pre_balance = bank_client.get_balance(&mint_keypair.pubkey()).unwrap(); let message = Message::new( &[ - ComputeBudgetInstruction::set_compute_unit_price(1), + ComputeBudgetInstruction::set_compute_unit_price(1_000_000_000), Instruction::new_with_bytes(program_id, &[], vec![]), ], Some(&mint_keypair.pubkey()), @@ -3859,7 +3860,8 @@ fn test_program_fees() { true, true, true, - false, + true, + true, ); assert!(expected_normal_fee < expected_prioritized_fee); diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 48324ad0c12..f13648d32c0 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -8660,7 +8660,7 @@ pub mod tests { let account0 = Pubkey::new_unique(); let account1 = Pubkey::new_unique(); let account2 = Pubkey::new_unique(); - let price0 = 42; + let price0 = 40_000; let transactions = vec![ Transaction::new_unsigned(Message::new( &[ @@ -8720,7 +8720,7 @@ pub mod tests { rpc.advance_bank_to_confirmed_slot(1); let slot1 = rpc.working_bank().slot(); - let price1 = 11; + let price1 = 1_000; let transactions = vec![ Transaction::new_unsigned(Message::new( &[ diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index d12f5405ad2..ee97f9d0b0d 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -37,8 +37,8 @@ use { self, add_set_tx_loaded_accounts_data_size_instruction, enable_request_heap_frame_ix, 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, + round_compute_unit_price, simplify_writable_program_account_check, + use_default_units_in_fee_calculation, FeatureSet, }, fee::FeeStructure, genesis_config::ClusterType, @@ -256,6 +256,7 @@ impl Accounts { !feature_set.is_active(&remove_deprecated_request_unit_ix::id()), true, // don't reject txs that use request heap size ix feature_set.is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()), + feature_set.is_active(&round_compute_unit_price::id()), ); // sanitize against setting size limit to zero NonZeroUsize::new(compute_budget.loaded_accounts_data_size_limit).map_or( @@ -732,6 +733,7 @@ impl Accounts { 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()), + feature_set.is_active(&round_compute_unit_price::id()), ) } else { return (Err(TransactionError::BlockhashNotFound), None); @@ -1770,6 +1772,7 @@ mod tests { true, true, false, + false, ); assert_eq!(fee, lamports_per_signature); @@ -4333,6 +4336,7 @@ mod tests { true, true, false, + false, ); assert_eq!(fee, lamports_per_signature + prioritization_fee); diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index c65e3da439c..7a85be898bd 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -130,7 +130,7 @@ use { enable_early_verification_of_account_modifications, enable_request_heap_frame_ix, 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, + round_compute_unit_price, use_default_units_in_fee_calculation, FeatureSet, }, fee::FeeStructure, fee_calculator::{FeeCalculator, FeeRateGovernor}, @@ -4561,6 +4561,7 @@ impl Bank { .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()), + self.feature_set.is_active(&round_compute_unit_price::id()), )) } @@ -4612,6 +4613,7 @@ impl Bank { .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()), + self.feature_set.is_active(&round_compute_unit_price::id()), ) } @@ -5602,6 +5604,7 @@ impl Bank { true, // don't reject txs that use request heap size ix self.feature_set .is_active(&add_set_tx_loaded_accounts_data_size_instruction::id()), + self.feature_set.is_active(&round_compute_unit_price::id()), ); compute_budget_process_transaction_time.stop(); saturating_add_assign!( @@ -5898,6 +5901,7 @@ impl Bank { } /// Calculate fee for `SanitizedMessage` + #[allow(clippy::too_many_arguments)] pub fn calculate_fee( message: &SanitizedMessage, lamports_per_signature: u64, @@ -5908,6 +5912,7 @@ impl Bank { enable_request_heap_frame_ix: bool, support_set_accounts_data_size_limit_ix: bool, include_loaded_account_data_size_in_fee: bool, + support_round_compute_unit_price: bool, ) -> u64 { // Fee based on compute units and signatures let congestion_multiplier = if lamports_per_signature == 0 { @@ -5928,6 +5933,7 @@ impl Bank { support_request_units_deprecated, enable_request_heap_frame_ix, support_set_accounts_data_size_limit_ix, + support_round_compute_unit_price, ) .unwrap_or_default(); let prioritization_fee = prioritization_fee_details.get_fee(); @@ -6013,6 +6019,7 @@ impl Bank { .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()), + self.feature_set.is_active(&round_compute_unit_price::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 7e937b62034..8738937ea3b 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -3010,6 +3010,7 @@ fn test_bank_tx_compute_unit_fee() { true, true, false, + false, ); let (expected_fee_collected, expected_fee_burned) = @@ -3195,6 +3196,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() { true, true, false, + false, ); assert_eq!( bank.get_balance(&mint_keypair.pubkey()), @@ -3217,6 +3219,7 @@ fn test_bank_blockhash_compute_unit_fee_structure() { true, true, false, + false, ); assert_eq!( bank.get_balance(&mint_keypair.pubkey()), @@ -3334,6 +3337,7 @@ fn test_filter_program_errors_and_collect_compute_unit_fee() { true, true, false, + false, ) * 2 ) .0 @@ -10268,6 +10272,7 @@ fn test_calculate_fee() { true, support_set_accounts_data_size_limit_ix, false, + false, ), 0 ); @@ -10289,6 +10294,7 @@ fn test_calculate_fee() { true, support_set_accounts_data_size_limit_ix, false, + false, ), 1 ); @@ -10315,6 +10321,7 @@ fn test_calculate_fee() { true, support_set_accounts_data_size_limit_ix, false, + false, ), 4 ); @@ -10346,6 +10353,7 @@ fn test_calculate_fee_compute_units() { true, support_set_accounts_data_size_limit_ix, false, + false, ), max_fee + lamports_per_signature ); @@ -10369,6 +10377,7 @@ fn test_calculate_fee_compute_units() { true, support_set_accounts_data_size_limit_ix, false, + false, ), max_fee + 3 * lamports_per_signature ); @@ -10414,6 +10423,7 @@ fn test_calculate_fee_compute_units() { true, support_set_accounts_data_size_limit_ix, false, + false, ); assert_eq!( fee, @@ -10431,12 +10441,7 @@ fn test_calculate_prioritization_fee() { }; let request_units = 1_000_000_u32; - let request_unit_price = 2_000_000_000_u64; - let prioritization_fee_details = PrioritizationFeeDetails::new( - PrioritizationFeeType::ComputeUnitPrice(request_unit_price), - request_units as u64, - ); - let prioritization_fee = prioritization_fee_details.get_fee(); + let request_unit_price = 2_000_999_u64; let message = SanitizedMessage::try_from(Message::new( &[ @@ -10447,20 +10452,46 @@ fn test_calculate_prioritization_fee() { )) .unwrap(); - let fee = Bank::calculate_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 + assert_eq!( + Bank::calculate_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 + false, // not rounding compute-unit-price + ), + fee_structure.lamports_per_signature + + PrioritizationFeeDetails::new( + PrioritizationFeeType::ComputeUnitPrice(request_unit_price), + request_units as u64, + ) + .get_fee() ); + assert_eq!( - fee, - fee_structure.lamports_per_signature + prioritization_fee + Bank::calculate_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, // rounding compute-unit-price + ), + fee_structure.lamports_per_signature + + PrioritizationFeeDetails::new( + PrioritizationFeeType::ComputeUnitPrice(2_000_000_u64), + request_units as u64, + ) + .get_fee() ); } @@ -10506,6 +10537,7 @@ fn test_calculate_fee_secp256k1() { true, support_set_accounts_data_size_limit_ix, false, + false, ), 2 ); @@ -10530,6 +10562,7 @@ fn test_calculate_fee_secp256k1() { true, support_set_accounts_data_size_limit_ix, false, + false, ), 11 ); @@ -12231,6 +12264,7 @@ fn test_calculate_fee_with_congestion_multiplier() { true, true, false, + false, ), signature_fee * signature_count ); @@ -12256,6 +12290,7 @@ fn test_calculate_fee_with_congestion_multiplier() { true, true, false, + false, ), signature_fee * signature_count / denominator ); @@ -12299,6 +12334,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() { enable_request_heap_frame_ix, true, false, + false, ), signature_fee + request_cu * lamports_per_cu ); @@ -12317,6 +12353,7 @@ fn test_calculate_fee_with_request_heap_frame_flag() { enable_request_heap_frame_ix, true, false, + false, ), signature_fee ); diff --git a/runtime/src/cost_model.rs b/runtime/src/cost_model.rs index 1ab8b80dc01..255ee6b631b 100644 --- a/runtime/src/cost_model.rs +++ b/runtime/src/cost_model.rs @@ -15,7 +15,7 @@ use { feature_set::{ add_set_tx_loaded_accounts_data_size_instruction, include_loaded_accounts_data_size_in_fee_calculation, - remove_deprecated_request_unit_ix, FeatureSet, + remove_deprecated_request_unit_ix, round_compute_unit_price, FeatureSet, }, instruction::CompiledInstruction, program_utils::limited_deserialize, @@ -120,6 +120,7 @@ impl CostModel { !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()), + feature_set.is_active(&round_compute_unit_price::id()), ); // if failed to process compute_budget instructions, the transaction will not be executed diff --git a/runtime/src/prioritization_fee_cache.rs b/runtime/src/prioritization_fee_cache.rs index e48a950c114..89810a66ad8 100644 --- a/runtime/src/prioritization_fee_cache.rs +++ b/runtime/src/prioritization_fee_cache.rs @@ -8,7 +8,8 @@ use { lru::LruCache, solana_measure::measure, solana_sdk::{ - clock::Slot, pubkey::Pubkey, saturating_add_assign, transaction::SanitizedTransaction, + clock::Slot, feature_set, pubkey::Pubkey, saturating_add_assign, + transaction::SanitizedTransaction, }, std::{ collections::HashMap, @@ -212,7 +213,9 @@ impl PrioritizationFeeCache { continue; } - let round_compute_unit_price_enabled = false; // TODO: bank.feture_set.is_active(round_compute_unit_price) + let round_compute_unit_price_enabled = bank + .feature_set + .is_active(&feature_set::round_compute_unit_price::id()); let priority_details = sanitized_transaction .get_transaction_priority_details(round_compute_unit_price_enabled); let account_locks = sanitized_transaction @@ -472,7 +475,7 @@ mod tests { let write_account_c = Pubkey::new_unique(); // Set up test with 3 transactions, in format of [fee, write-accounts...], - // Shall expect fee cache is updated in following sequence: + // Shall expect fee cache is updated in following sequence (fee in lamport): // transaction block minimum prioritization fee cache // [fee, write_accounts...] --> [block, account_a, account_b, account_c] // ----------------------------------------------------------------------- @@ -481,9 +484,9 @@ mod tests { // [2, a, c ] --> [2, 2, 5, 2 ] // let txs = vec![ - build_sanitized_transaction_for_test(5, &write_account_a, &write_account_b), - build_sanitized_transaction_for_test(9, &write_account_b, &write_account_c), - build_sanitized_transaction_for_test(2, &write_account_a, &write_account_c), + build_sanitized_transaction_for_test(5_000_000_000, &write_account_a, &write_account_b), + build_sanitized_transaction_for_test(9_000_000_000, &write_account_b, &write_account_c), + build_sanitized_transaction_for_test(2_000_000_000, &write_account_a, &write_account_c), ]; let bank = Arc::new(Bank::default_for_tests()); @@ -499,10 +502,19 @@ mod tests { &slot, ); let fee = fee.lock().unwrap(); - assert_eq!(2, fee.get_min_transaction_fee().unwrap()); - assert_eq!(2, fee.get_writable_account_fee(&write_account_a).unwrap()); - assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap()); - assert_eq!(2, fee.get_writable_account_fee(&write_account_c).unwrap()); + assert_eq!(2_000_000_000, fee.get_min_transaction_fee().unwrap()); + assert_eq!( + 2_000_000_000, + fee.get_writable_account_fee(&write_account_a).unwrap() + ); + assert_eq!( + 5_000_000_000, + fee.get_writable_account_fee(&write_account_b).unwrap() + ); + assert_eq!( + 2_000_000_000, + fee.get_writable_account_fee(&write_account_c).unwrap() + ); // assert unknown account d fee assert!(fee .get_writable_account_fee(&Pubkey::new_unique()) @@ -517,9 +529,12 @@ mod tests { &slot, ); let fee = fee.lock().unwrap(); - assert_eq!(2, fee.get_min_transaction_fee().unwrap()); + assert_eq!(2_000_000_000, fee.get_min_transaction_fee().unwrap()); assert!(fee.get_writable_account_fee(&write_account_a).is_none()); - assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap()); + assert_eq!( + 5_000_000_000, + fee.get_writable_account_fee(&write_account_b).unwrap() + ); assert!(fee.get_writable_account_fee(&write_account_c).is_none()); } } @@ -596,9 +611,13 @@ mod tests { // Assert after add one transaction for slot 1 { let txs = vec![ - build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b), build_sanitized_transaction_for_test( - 1, + 2_000_000_000, + &write_account_a, + &write_account_b, + ), + build_sanitized_transaction_for_test( + 1_000_000_000, &Pubkey::new_unique(), &Pubkey::new_unique(), ), @@ -626,28 +645,28 @@ mod tests { // after block is completed sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 1); assert_eq!( - hashmap_of(vec![(1, 1)]), + hashmap_of(vec![(1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) ); assert_eq!( - hashmap_of(vec![(1, 1)]), + hashmap_of(vec![(1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, @@ -659,9 +678,13 @@ mod tests { // Assert after add one transaction for slot 2 { let txs = vec![ - build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c), build_sanitized_transaction_for_test( - 3, + 4_000_000_000, + &write_account_b, + &write_account_c, + ), + build_sanitized_transaction_for_test( + 3_000_000_000, &Pubkey::new_unique(), &Pubkey::new_unique(), ), @@ -669,28 +692,28 @@ mod tests { sync_update(&mut prioritization_fee_cache, bank2, txs.iter()); // before block is marked as completed assert_eq!( - hashmap_of(vec![(1, 1)]), + hashmap_of(vec![(1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) ); assert_eq!( - hashmap_of(vec![(1, 1)]), + hashmap_of(vec![(1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]) ); assert_eq!( - hashmap_of(vec![(1, 2)]), + hashmap_of(vec![(1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, @@ -700,28 +723,28 @@ mod tests { // after block is completed sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 2); assert_eq!( - hashmap_of(vec![(2, 3), (1, 1)]), + hashmap_of(vec![(2, 3_000_000_000), (1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_eq!( - hashmap_of(vec![(2, 3), (1, 2)]), + hashmap_of(vec![(2, 3_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 2)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 1)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 2)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 2)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, @@ -733,9 +756,13 @@ mod tests { // Assert after add one transaction for slot 3 { let txs = vec![ - build_sanitized_transaction_for_test(6, &write_account_a, &write_account_c), build_sanitized_transaction_for_test( - 5, + 6_000_000_000, + &write_account_a, + &write_account_c, + ), + build_sanitized_transaction_for_test( + 5_000_000_000, &Pubkey::new_unique(), &Pubkey::new_unique(), ), @@ -743,28 +770,28 @@ mod tests { sync_update(&mut prioritization_fee_cache, bank3, txs.iter()); // before block is marked as completed assert_eq!( - hashmap_of(vec![(2, 3), (1, 1)]), + hashmap_of(vec![(2, 3_000_000_000), (1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_eq!( - hashmap_of(vec![(2, 3), (1, 2)]), + hashmap_of(vec![(2, 3_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 2)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 1)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 1_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 2)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]), ); assert_eq!( - hashmap_of(vec![(2, 4), (1, 2)]), + hashmap_of(vec![(2, 4_000_000_000), (1, 2_000_000_000)]), prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, @@ -774,28 +801,52 @@ mod tests { // after block is completed sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 3); assert_eq!( - hashmap_of(vec![(3, 5), (2, 3), (1, 1)]), + hashmap_of(vec![ + (3, 5_000_000_000), + (2, 3_000_000_000), + (1, 1_000_000_000) + ]), prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_eq!( - hashmap_of(vec![(3, 6), (2, 3), (1, 2)]), + hashmap_of(vec![ + (3, 6_000_000_000), + (2, 3_000_000_000), + (1, 2_000_000_000) + ]), prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); assert_eq!( - hashmap_of(vec![(3, 5), (2, 4), (1, 2)]), + hashmap_of(vec![ + (3, 5_000_000_000), + (2, 4_000_000_000), + (1, 2_000_000_000) + ]), prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); assert_eq!( - hashmap_of(vec![(3, 6), (2, 4), (1, 1)]), + hashmap_of(vec![ + (3, 6_000_000_000), + (2, 4_000_000_000), + (1, 1_000_000_000) + ]), prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); assert_eq!( - hashmap_of(vec![(3, 6), (2, 4), (1, 2)]), + hashmap_of(vec![ + (3, 6_000_000_000), + (2, 4_000_000_000), + (1, 2_000_000_000) + ]), prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]), ); assert_eq!( - hashmap_of(vec![(3, 6), (2, 4), (1, 2)]), + hashmap_of(vec![ + (3, 6_000_000_000), + (2, 4_000_000_000), + (1, 2_000_000_000) + ]), prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, diff --git a/runtime/src/transaction_priority_details.rs b/runtime/src/transaction_priority_details.rs index d454fe8a8bd..4cfc1a1e9b1 100644 --- a/runtime/src/transaction_priority_details.rs +++ b/runtime/src/transaction_priority_details.rs @@ -21,7 +21,7 @@ pub trait GetTransactionPriorityDetails { fn process_compute_budget_instruction<'a>( instructions: impl Iterator, - _round_compute_unit_price_enabled: bool, + round_compute_unit_price_enabled: bool, ) -> Option { let mut compute_budget = ComputeBudget::default(); let prioritization_fee_details = compute_budget @@ -31,7 +31,7 @@ pub trait GetTransactionPriorityDetails { false, // stop supporting prioritization by request_units_deprecated instruction true, // enable request heap frame instruction true, // enable support set accounts data size instruction - // TODO: round_compute_unit_price_enabled: bool + round_compute_unit_price_enabled, ) .ok()?; Some(TransactionPriorityDetails { diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 6957b951e80..87b6f74d1cc 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -672,6 +672,10 @@ pub mod last_restart_slot_sysvar { solana_sdk::declare_id!("HooKD5NC9QNxk25QuzCssB8ecrEzGt6eXEPBUxWp1LaR"); } +pub mod round_compute_unit_price { + solana_sdk::declare_id!("6J6GS57v5q4CnPrLgDMsyZLFfpPEBPZ66h8efDEpesPk"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -835,6 +839,7 @@ lazy_static! { (checked_arithmetic_in_fee_validation::id(), "checked arithmetic in fee validation #31273"), (bpf_account_data_direct_mapping::id(), "use memory regions to map account data into the rbpf vm instead of copying the data"), (last_restart_slot_sysvar::id(), "enable new sysvar last_restart_slot"), + (round_compute_unit_price::id(), "round down compute-unit-price to the nearest 1_000 micro-lamports #31453"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()