diff --git a/runtime/src/prioritization_fee.rs b/runtime/src/prioritization_fee.rs index 9befdd31a61b2b..9e05c7c80f72be 100644 --- a/runtime/src/prioritization_fee.rs +++ b/runtime/src/prioritization_fee.rs @@ -23,14 +23,14 @@ struct PrioritizationFeeMetrics { // Count of attempted update on finalized PrioritizationFee attempted_update_on_finalized_fee_count: Saturating, - // Total prioritization fees included in this slot. + // Total transaction fees of non-vote transactions included in this slot. total_prioritization_fee: Saturating, - // The minimum prioritization fee of prioritized transactions in this slot. - min_prioritization_fee: Option, + // The minimum compute unit price of prioritized transactions in this slot. + min_compute_unit_price: Option, - // The maximum prioritization fee of prioritized transactions in this slot. - max_prioritization_fee: u64, + // The maximum compute unit price of prioritized transactions in this slot. + max_compute_unit_price: u64, // Accumulated time spent on tracking prioritization fee for each slot. total_update_elapsed_us: Saturating, @@ -49,8 +49,8 @@ impl PrioritizationFeeMetrics { self.attempted_update_on_finalized_fee_count += val; } - fn update_prioritization_fee(&mut self, fee: u64) { - if fee == 0 { + fn update_compute_unit_price(&mut self, cu_price: u64) { + if cu_price == 0 { self.non_prioritized_transactions_count += 1; return; } @@ -58,11 +58,11 @@ impl PrioritizationFeeMetrics { // update prioritized transaction fee metrics. self.prioritized_transactions_count += 1; - self.max_prioritization_fee = self.max_prioritization_fee.max(fee); + self.max_compute_unit_price = self.max_compute_unit_price.max(cu_price); - self.min_prioritization_fee = Some( - self.min_prioritization_fee - .map_or(fee, |min_fee| min_fee.min(fee)), + self.min_compute_unit_price = Some( + self.min_compute_unit_price + .map_or(cu_price, |min_cu_price| min_cu_price.min(cu_price)), ); } @@ -75,8 +75,8 @@ impl PrioritizationFeeMetrics { attempted_update_on_finalized_fee_count: Saturating(attempted_update_on_finalized_fee_count), total_prioritization_fee: Saturating(total_prioritization_fee), - min_prioritization_fee, - max_prioritization_fee, + min_compute_unit_price, + max_compute_unit_price, total_update_elapsed_us: Saturating(total_update_elapsed_us), } = self; datapoint_info!( @@ -113,11 +113,11 @@ impl PrioritizationFeeMetrics { i64 ), ( - "min_prioritization_fee", - min_prioritization_fee.unwrap_or(0) as i64, + "min_compute_unit_price", + min_compute_unit_price.unwrap_or(0) as i64, i64 ), - ("max_prioritization_fee", max_prioritization_fee as i64, i64), + ("max_compute_unit_price", max_compute_unit_price as i64, i64), ( "total_update_elapsed_us", total_update_elapsed_us as i64, @@ -144,11 +144,11 @@ pub enum PrioritizationFeeError { /// Block minimum prioritization fee stats, includes the minimum prioritization fee for a transaction in this /// block; and the minimum fee for each writable account in all transactions in this block. The only relevant /// write account minimum fees are those greater than the block minimum transaction fee, because the minimum fee needed to land -/// a transaction is determined by Max( min_transaction_fee, min_writable_account_fees(key), ...) +/// a transaction is determined by Max( min_compute_unit_price, min_writable_account_fees(key), ...) #[derive(Debug)] pub struct PrioritizationFee { // The minimum prioritization fee of transactions that landed in this block. - min_transaction_fee: u64, + min_compute_unit_price: u64, // The minimum prioritization fee of each writable account in transactions in this block. min_writable_account_fees: HashMap, @@ -164,7 +164,7 @@ pub struct PrioritizationFee { impl Default for PrioritizationFee { fn default() -> Self { PrioritizationFee { - min_transaction_fee: u64::MAX, + min_compute_unit_price: u64::MAX, min_writable_account_fees: HashMap::new(), is_finalized: false, metrics: PrioritizationFeeMetrics::default(), @@ -174,25 +174,30 @@ impl Default for PrioritizationFee { impl PrioritizationFee { /// Update self for minimum transaction fee in the block and minimum fee for each writable account. - pub fn update(&mut self, transaction_fee: u64, writable_accounts: Vec) { + pub fn update( + &mut self, + compute_unit_price: u64, + prioritization_fee: u64, + writable_accounts: Vec, + ) { let (_, update_us) = measure_us!({ if !self.is_finalized { - if transaction_fee < self.min_transaction_fee { - self.min_transaction_fee = transaction_fee; + if compute_unit_price < self.min_compute_unit_price { + self.min_compute_unit_price = compute_unit_price; } for write_account in writable_accounts { self.min_writable_account_fees .entry(write_account) .and_modify(|write_lock_fee| { - *write_lock_fee = std::cmp::min(*write_lock_fee, transaction_fee) + *write_lock_fee = std::cmp::min(*write_lock_fee, compute_unit_price) }) - .or_insert(transaction_fee); + .or_insert(compute_unit_price); } self.metrics - .accumulate_total_prioritization_fee(transaction_fee); - self.metrics.update_prioritization_fee(transaction_fee); + .accumulate_total_prioritization_fee(prioritization_fee); + self.metrics.update_compute_unit_price(compute_unit_price); } else { self.metrics .increment_attempted_update_on_finalized_fee_count(1); @@ -207,7 +212,7 @@ impl PrioritizationFee { fn prune_irrelevant_writable_accounts(&mut self) { self.metrics.total_writable_accounts_count = self.get_writable_accounts_count() as u64; self.min_writable_account_fees - .retain(|_, account_fee| account_fee > &mut self.min_transaction_fee); + .retain(|_, account_fee| account_fee > &mut self.min_compute_unit_price); self.metrics.relevant_writable_accounts_count = self.get_writable_accounts_count() as u64; } @@ -220,8 +225,8 @@ impl PrioritizationFee { Ok(()) } - pub fn get_min_transaction_fee(&self) -> Option { - (self.min_transaction_fee != u64::MAX).then_some(self.min_transaction_fee) + pub fn get_min_compute_unit_price(&self) -> Option { + (self.min_compute_unit_price != u64::MAX).then_some(self.min_compute_unit_price) } pub fn get_writable_account_fee(&self, key: &Pubkey) -> Option { @@ -250,22 +255,23 @@ mod tests { use {super::*, solana_pubkey::Pubkey}; #[test] - fn test_update_prioritization_fee() { + fn test_update_compute_unit_price() { solana_logger::setup(); let write_account_a = Pubkey::new_unique(); let write_account_b = Pubkey::new_unique(); let write_account_c = Pubkey::new_unique(); + let tx_fee = 10; let mut prioritization_fee = PrioritizationFee::default(); - assert!(prioritization_fee.get_min_transaction_fee().is_none()); + assert!(prioritization_fee.get_min_compute_unit_price().is_none()); // Assert for 1st transaction - // [fee, write_accounts...] --> [block, account_a, account_b, account_c] + // [cu_px, write_accounts...] --> [block, account_a, account_b, account_c] // ----------------------------------------------------------------------- // [5, a, b ] --> [5, 5, 5, nil ] { - prioritization_fee.update(5, vec![write_account_a, write_account_b]); - assert_eq!(5, prioritization_fee.get_min_transaction_fee().unwrap()); + prioritization_fee.update(5, tx_fee, vec![write_account_a, write_account_b]); + assert_eq!(5, prioritization_fee.get_min_compute_unit_price().unwrap()); assert_eq!( 5, prioritization_fee @@ -284,12 +290,12 @@ mod tests { } // Assert for second transaction: - // [fee, write_accounts...] --> [block, account_a, account_b, account_c] + // [cu_px, write_accounts...] --> [block, account_a, account_b, account_c] // ----------------------------------------------------------------------- // [9, b, c ] --> [5, 5, 5, 9 ] { - prioritization_fee.update(9, vec![write_account_b, write_account_c]); - assert_eq!(5, prioritization_fee.get_min_transaction_fee().unwrap()); + prioritization_fee.update(9, tx_fee, vec![write_account_b, write_account_c]); + assert_eq!(5, prioritization_fee.get_min_compute_unit_price().unwrap()); assert_eq!( 5, prioritization_fee @@ -311,12 +317,12 @@ mod tests { } // Assert for third transaction: - // [fee, write_accounts...] --> [block, account_a, account_b, account_c] + // [cu_px, write_accounts...] --> [block, account_a, account_b, account_c] // ----------------------------------------------------------------------- // [2, a, c ] --> [2, 2, 5, 2 ] { - prioritization_fee.update(2, vec![write_account_a, write_account_c]); - assert_eq!(2, prioritization_fee.get_min_transaction_fee().unwrap()); + prioritization_fee.update(2, tx_fee, vec![write_account_a, write_account_c]); + assert_eq!(2, prioritization_fee.get_min_compute_unit_price().unwrap()); assert_eq!( 2, prioritization_fee @@ -341,7 +347,7 @@ mod tests { { prioritization_fee.prune_irrelevant_writable_accounts(); assert_eq!(1, prioritization_fee.min_writable_account_fees.len()); - assert_eq!(2, prioritization_fee.get_min_transaction_fee().unwrap()); + assert_eq!(2, prioritization_fee.get_min_compute_unit_price().unwrap()); assert!(prioritization_fee .get_writable_account_fee(&write_account_a) .is_none()); @@ -357,6 +363,25 @@ mod tests { } } + #[test] + fn test_total_prioritization_fee() { + let mut prioritization_fee = PrioritizationFee::default(); + prioritization_fee.update(0, 10, vec![]); + assert_eq!(10, prioritization_fee.metrics.total_prioritization_fee.0); + + prioritization_fee.update(10, u64::MAX, vec![]); + assert_eq!( + u64::MAX, + prioritization_fee.metrics.total_prioritization_fee.0 + ); + + prioritization_fee.update(10, 100, vec![]); + assert_eq!( + u64::MAX, + prioritization_fee.metrics.total_prioritization_fee.0 + ); + } + #[test] fn test_mark_block_completed() { let mut prioritization_fee = PrioritizationFee::default(); diff --git a/runtime/src/prioritization_fee_cache.rs b/runtime/src/prioritization_fee_cache.rs index 9631ef86e4fb6a..6d63e040a5c122 100644 --- a/runtime/src/prioritization_fee_cache.rs +++ b/runtime/src/prioritization_fee_cache.rs @@ -1,5 +1,5 @@ use { - crate::{bank::Bank, prioritization_fee::*}, + crate::{bank::Bank, prioritization_fee::PrioritizationFee}, crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError}, log::*, solana_accounts_db::account_locks::validate_account_locks, @@ -47,6 +47,9 @@ struct PrioritizationFeeCacheMetrics { // Accumulated time spent on finalizing block prioritization fees. total_block_finalize_elapsed_us: AtomicU64, + + // Accumulated time spent on calculate transaction fees. + total_calculate_prioritization_fee_elapsed_us: AtomicU64, } impl PrioritizationFeeCacheMetrics { @@ -80,6 +83,11 @@ impl PrioritizationFeeCacheMetrics { .fetch_add(val, Ordering::Relaxed); } + fn accumulate_total_calculate_prioritization_fee_elapsed_us(&self, val: u64) { + self.total_calculate_prioritization_fee_elapsed_us + .fetch_add(val, Ordering::Relaxed); + } + fn report(&self, slot: Slot) { datapoint_info!( "block_prioritization_fee_counters", @@ -117,6 +125,12 @@ impl PrioritizationFeeCacheMetrics { .swap(0, Ordering::Relaxed) as i64, i64 ), + ( + "total_calculate_prioritization_fee_elapsed_us", + self.total_calculate_prioritization_fee_elapsed_us + .swap(0, Ordering::Relaxed) as i64, + i64 + ), ); } } @@ -126,7 +140,8 @@ enum CacheServiceUpdate { TransactionUpdate { slot: Slot, bank_id: BankId, - transaction_fee: u64, + compute_unit_price: u64, + prioritization_fee: u64, writable_accounts: Vec, }, BankFinalized { @@ -233,11 +248,21 @@ impl PrioritizationFeeCache { .map(|(_, key)| *key) .collect(); + let (prioritization_fee, calculate_prioritization_fee_us) = measure_us!({ + solana_fee_structure::FeeBudgetLimits::from(compute_budget_limits) + .prioritization_fee + }); + self.metrics + .accumulate_total_calculate_prioritization_fee_elapsed_us( + calculate_prioritization_fee_us, + ); + self.sender .send(CacheServiceUpdate::TransactionUpdate { slot: bank.slot(), bank_id: bank.bank_id(), - transaction_fee: compute_budget_limits.compute_unit_price, + compute_unit_price: compute_budget_limits.compute_unit_price, + prioritization_fee, writable_accounts, }) .unwrap_or_else(|err| { @@ -271,7 +296,8 @@ impl PrioritizationFeeCache { unfinalized: &mut UnfinalizedPrioritizationFees, slot: Slot, bank_id: BankId, - transaction_fee: u64, + compute_unit_price: u64, + prioritization_fee: u64, writable_accounts: Vec, metrics: &PrioritizationFeeCacheMetrics, ) { @@ -280,7 +306,7 @@ impl PrioritizationFeeCache { .or_default() .entry(bank_id) .or_default() - .update(transaction_fee, writable_accounts)); + .update(compute_unit_price, prioritization_fee, writable_accounts)); metrics.accumulate_total_entry_update_elapsed_us(entry_update_us); metrics.accumulate_successful_transaction_update_count(1); } @@ -374,13 +400,15 @@ impl PrioritizationFeeCache { CacheServiceUpdate::TransactionUpdate { slot, bank_id, - transaction_fee, + compute_unit_price, + prioritization_fee, writable_accounts, } => Self::update_cache( &mut unfinalized, slot, bank_id, - transaction_fee, + compute_unit_price, + prioritization_fee, writable_accounts, &metrics, ), @@ -414,7 +442,7 @@ impl PrioritizationFeeCache { .iter() .map(|(slot, slot_prioritization_fee)| { let mut fee = slot_prioritization_fee - .get_min_transaction_fee() + .get_min_compute_unit_price() .unwrap_or_default(); for account_key in account_keys { if let Some(account_fee) = @@ -549,7 +577,7 @@ mod tests { sync_finalize_priority_fee_for_test(&prioritization_fee_cache, slot, bank.bank_id()); let lock = prioritization_fee_cache.cache.read().unwrap(); let fee = lock.get(&slot).unwrap(); - assert_eq!(2, fee.get_min_transaction_fee().unwrap()); + assert_eq!(2, fee.get_min_compute_unit_price().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!(fee.get_writable_account_fee(&write_account_c).is_none());