From 248fcc362dc34652e855601da1a2efc20e53d1d3 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 19 Aug 2022 14:39:07 -0600 Subject: [PATCH 01/10] Plumb priority_fee_cache into rpc --- core/src/validator.rs | 1 + rpc/src/rpc.rs | 9 +++++++++ rpc/src/rpc_service.rs | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/core/src/validator.rs b/core/src/validator.rs index d52bdbcd10c134..57102f124c0538 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -823,6 +823,7 @@ impl Validator { leader_schedule_cache.clone(), connection_cache.clone(), max_complete_transaction_status_slot, + prioritization_fee_cache.clone(), )?; ( diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 8d5d12f0330a3b..6b0c7e2f98b2b1 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -48,6 +48,7 @@ use { inline_spl_token::{SPL_TOKEN_ACCOUNT_MINT_OFFSET, SPL_TOKEN_ACCOUNT_OWNER_OFFSET}, inline_spl_token_2022::{self, ACCOUNTTYPE_ACCOUNT}, non_circulating_supply::calculate_non_circulating_supply, + prioritization_fee_cache::PrioritizationFeeCache, snapshot_config::SnapshotConfig, snapshot_utils, }, @@ -211,6 +212,7 @@ pub struct JsonRpcRequestProcessor { max_slots: Arc, leader_schedule_cache: Arc, max_complete_transaction_status_slot: Arc, + _prioritization_fee_cache: Arc, } impl Metadata for JsonRpcRequestProcessor {} @@ -316,6 +318,7 @@ impl JsonRpcRequestProcessor { max_slots: Arc, leader_schedule_cache: Arc, max_complete_transaction_status_slot: Arc, + _prioritization_fee_cache: Arc, ) -> (Self, Receiver) { let (sender, receiver) = unbounded(); ( @@ -336,6 +339,7 @@ impl JsonRpcRequestProcessor { max_slots, leader_schedule_cache, max_complete_transaction_status_slot, + _prioritization_fee_cache, }, receiver, ) @@ -400,6 +404,7 @@ impl JsonRpcRequestProcessor { max_slots: Arc::new(MaxSlots::default()), leader_schedule_cache: Arc::new(LeaderScheduleCache::new_from_bank(bank)), max_complete_transaction_status_slot: Arc::new(AtomicU64::default()), + _prioritization_fee_cache: Arc::new(PrioritizationFeeCache::default()), } } @@ -4726,6 +4731,7 @@ pub mod tests { max_slots.clone(), Arc::new(LeaderScheduleCache::new_from_bank(&bank)), max_complete_transaction_status_slot.clone(), + Arc::new(PrioritizationFeeCache::default()), ) .0; @@ -6300,6 +6306,7 @@ pub mod tests { Arc::new(MaxSlots::default()), Arc::new(LeaderScheduleCache::default()), Arc::new(AtomicU64::default()), + Arc::new(PrioritizationFeeCache::default()), ); let connection_cache = Arc::new(ConnectionCache::default()); SendTransactionService::new::( @@ -6569,6 +6576,7 @@ pub mod tests { Arc::new(MaxSlots::default()), Arc::new(LeaderScheduleCache::default()), Arc::new(AtomicU64::default()), + Arc::new(PrioritizationFeeCache::default()), ); let connection_cache = Arc::new(ConnectionCache::default()); SendTransactionService::new::( @@ -8196,6 +8204,7 @@ pub mod tests { Arc::new(MaxSlots::default()), Arc::new(LeaderScheduleCache::default()), Arc::new(AtomicU64::default()), + Arc::new(PrioritizationFeeCache::default()), ); let mut io = MetaIoHandler::default(); diff --git a/rpc/src/rpc_service.rs b/rpc/src/rpc_service.rs index 97b6fb45b7e2f0..823818b25b99de 100644 --- a/rpc/src/rpc_service.rs +++ b/rpc/src/rpc_service.rs @@ -30,6 +30,7 @@ use { solana_poh::poh_recorder::PohRecorder, solana_runtime::{ bank_forks::BankForks, commitment::BlockCommitmentCache, + prioritization_fee_cache::PrioritizationFeeCache, snapshot_archive_info::SnapshotArchiveInfoGetter, snapshot_config::SnapshotConfig, snapshot_utils, }, @@ -356,6 +357,7 @@ impl JsonRpcService { leader_schedule_cache: Arc, connection_cache: Arc, current_transaction_status_slot: Arc, + prioritization_fee_cache: Arc, ) -> Result { info!("rpc bound to {:?}", rpc_addr); info!("rpc configuration: {:?}", config); @@ -464,6 +466,7 @@ impl JsonRpcService { max_slots, leader_schedule_cache, current_transaction_status_slot, + prioritization_fee_cache, ); let leader_info = @@ -646,6 +649,7 @@ mod tests { Arc::new(LeaderScheduleCache::default()), connection_cache, Arc::new(AtomicU64::default()), + Arc::new(PrioritizationFeeCache::default()), ) .expect("assume successful JsonRpcService start"); let thread = rpc_service.thread_hdl.thread(); From 506cf7b72febb015259205b3c683ff140ec41d06 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 19 Aug 2022 15:23:23 -0600 Subject: [PATCH 02/10] Add PrioritizationFeeCache api --- runtime/src/prioritization_fee_cache.rs | 291 ++++++++++++++++++++++++ 1 file changed, 291 insertions(+) diff --git a/runtime/src/prioritization_fee_cache.rs b/runtime/src/prioritization_fee_cache.rs index 3ecf11cdc61b7f..4a41b5cdd3fac6 100644 --- a/runtime/src/prioritization_fee_cache.rs +++ b/runtime/src/prioritization_fee_cache.rs @@ -382,6 +382,31 @@ impl PrioritizationFeeCache { .flatten() .collect() } + + pub fn get_prioritization_fees_with_accounts(&self, account_keys: &[Pubkey]) -> Vec { + self.cache + .read() + .unwrap() + .iter() + .filter_map(|(_slot, prioritization_fee)| { + let prioritization_fee_read = prioritization_fee.lock().unwrap(); + prioritization_fee_read.is_finalized().then(|| { + let mut fee = prioritization_fee_read + .get_min_transaction_fee() + .unwrap_or_default(); + for account_key in account_keys { + if let Some(account_fee) = + prioritization_fee_read.get_writable_account_fee(account_key) + { + fee = std::cmp::max(fee, account_fee); + } + } + Some(fee) + }) + }) + .flatten() + .collect() + } } #[cfg(test)] @@ -808,4 +833,270 @@ mod tests { ); } } + + #[test] + fn test_get_prioritization_fees_with_accounts() { + 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 GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); + let bank0 = Bank::new_for_benches(&genesis_config); + let bank_forks = BankForks::new(bank0); + let bank = bank_forks.working_bank(); + let collector = solana_sdk::pubkey::new_rand(); + let bank1 = Arc::new(Bank::new_from_parent(&bank, &collector, 1)); + let bank2 = Arc::new(Bank::new_from_parent(&bank1, &collector, 2)); + let bank3 = Arc::new(Bank::new_from_parent(&bank2, &collector, 3)); + + let mut prioritization_fee_cache = PrioritizationFeeCache::default(); + + // Assert no minimum fee from empty cache + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_c]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[ + write_account_a, + write_account_b, + write_account_c + ]) + .is_empty()); + + // 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, + &Pubkey::new_unique(), + &Pubkey::new_unique(), + ), + ]; + prioritization_fee_cache.update(bank1, txs.iter()); + // before block is marked as completed + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_c]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[ + write_account_a, + write_account_b, + write_account_c + ]) + .is_empty()); + // after block is completed + sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 1); + assert_eq!( + vec![1], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_a]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_b]) + ); + assert_eq!( + vec![1], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_c]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + write_account_a, + write_account_b, + write_account_c + ]) + ); + } + + // 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, + &Pubkey::new_unique(), + &Pubkey::new_unique(), + ), + ]; + prioritization_fee_cache.update(bank2, txs.iter()); + // before block is marked as completed + assert_eq!( + vec![1], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_a]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_b]) + ); + assert_eq!( + vec![1], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_c]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + ); + assert_eq!( + vec![2], + prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + write_account_a, + write_account_b, + write_account_c + ]) + ); + // after block is completed + sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 2); + assert_vec_eq( + &mut vec![3, 1], + &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]), + ); + assert_vec_eq( + &mut vec![3, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a]), + ); + assert_vec_eq( + &mut vec![4, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_b]), + ); + assert_vec_eq( + &mut vec![4, 1], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_c]), + ); + assert_vec_eq( + &mut vec![4, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]), + ); + assert_vec_eq( + &mut vec![4, 2], + &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + write_account_a, + write_account_b, + write_account_c, + ]), + ); + } + + // 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, + &Pubkey::new_unique(), + &Pubkey::new_unique(), + ), + ]; + prioritization_fee_cache.update(bank3, txs.iter()); + // before block is marked as completed + assert_vec_eq( + &mut vec![3, 1], + &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]), + ); + assert_vec_eq( + &mut vec![3, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a]), + ); + assert_vec_eq( + &mut vec![4, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_b]), + ); + assert_vec_eq( + &mut vec![4, 1], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_c]), + ); + assert_vec_eq( + &mut vec![4, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]), + ); + assert_vec_eq( + &mut vec![4, 2], + &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + write_account_a, + write_account_b, + write_account_c, + ]), + ); + // after block is completed + sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 3); + assert_vec_eq( + &mut vec![5, 3, 1], + &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]), + ); + assert_vec_eq( + &mut vec![6, 3, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a]), + ); + assert_vec_eq( + &mut vec![5, 4, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_b]), + ); + assert_vec_eq( + &mut vec![6, 4, 1], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_c]), + ); + assert_vec_eq( + &mut vec![6, 4, 2], + &mut prioritization_fee_cache + .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]), + ); + assert_vec_eq( + &mut vec![6, 4, 2], + &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + write_account_a, + write_account_b, + write_account_c, + ]), + ); + } + } } From 3df52414b9d2f1e8b3f1ca3dcdd0cd2096ad6935 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 19 Aug 2022 15:44:57 -0600 Subject: [PATCH 03/10] Add getRecentPrioritizationFees rpc endpoint --- rpc/src/rpc.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 6b0c7e2f98b2b1..60d8449a290d49 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -212,7 +212,7 @@ pub struct JsonRpcRequestProcessor { max_slots: Arc, leader_schedule_cache: Arc, max_complete_transaction_status_slot: Arc, - _prioritization_fee_cache: Arc, + prioritization_fee_cache: Arc, } impl Metadata for JsonRpcRequestProcessor {} @@ -318,7 +318,7 @@ impl JsonRpcRequestProcessor { max_slots: Arc, leader_schedule_cache: Arc, max_complete_transaction_status_slot: Arc, - _prioritization_fee_cache: Arc, + prioritization_fee_cache: Arc, ) -> (Self, Receiver) { let (sender, receiver) = unbounded(); ( @@ -339,7 +339,7 @@ impl JsonRpcRequestProcessor { max_slots, leader_schedule_cache, max_complete_transaction_status_slot, - _prioritization_fee_cache, + prioritization_fee_cache, }, receiver, ) @@ -404,7 +404,7 @@ impl JsonRpcRequestProcessor { max_slots: Arc::new(MaxSlots::default()), leader_schedule_cache: Arc::new(LeaderScheduleCache::new_from_bank(bank)), max_complete_transaction_status_slot: Arc::new(AtomicU64::default()), - _prioritization_fee_cache: Arc::new(PrioritizationFeeCache::default()), + prioritization_fee_cache: Arc::new(PrioritizationFeeCache::default()), } } @@ -2182,6 +2182,19 @@ impl JsonRpcRequestProcessor { solana_stake_program::get_minimum_delegation(&bank.feature_set); Ok(new_response(&bank, stake_minimum_delegation)) } + + fn get_recent_prioritization_fees( + &self, + pubkeys: Vec, + config: RpcContextConfig, + ) -> Result>> { + let bank = self.get_bank_with_config(config)?; + Ok(new_response( + &bank, + self.prioritization_fee_cache + .get_prioritization_fees_with_accounts(&pubkeys), + )) + } } fn optimize_filters(filters: &mut [RpcFilterType]) { @@ -3421,6 +3434,14 @@ pub mod rpc_full { meta: Self::Metadata, config: Option, ) -> Result>; + + #[rpc(meta, name = "getRecentPrioritizationFees")] + fn get_recent_prioritization_fees( + &self, + meta: Self::Metadata, + pubkey_strs: Vec, + config: Option, + ) -> Result>>; } pub struct FullImpl; @@ -3997,6 +4018,30 @@ pub mod rpc_full { debug!("get_stake_minimum_delegation rpc request received"); meta.get_stake_minimum_delegation(config.unwrap_or_default()) } + + fn get_recent_prioritization_fees( + &self, + meta: Self::Metadata, + pubkey_strs: Vec, + config: Option, + ) -> Result>> { + debug!( + "get_recent_prioritization_fees rpc request received: {:?} pubkeys", + pubkey_strs.len() + ); + const MAX_FEE_ACCOUNTS: usize = 42; // TODO: what do we actually want here? + if pubkey_strs.len() > MAX_FEE_ACCOUNTS { + return Err(Error::invalid_params(format!( + "Too many inputs provided; max {}", + MAX_FEE_ACCOUNTS + ))); + } + let pubkeys = pubkey_strs + .into_iter() + .map(|pubkey_str| verify_pubkey(&pubkey_str)) + .collect::>>()?; + meta.get_recent_prioritization_fees(pubkeys, config.unwrap_or_default()) + } } } From b8393e2fe9cf6f0fdb95535ad4e072faadee813d Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 26 Aug 2022 13:37:57 -0600 Subject: [PATCH 04/10] Use MAX_TX_ACCOUNT_LOCKS to limit input keys --- rpc/src/rpc.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 60d8449a290d49..90010d2a162159 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -72,7 +72,7 @@ use { sysvar::stake_history, transaction::{ self, AddressLoader, MessageHash, SanitizedTransaction, TransactionError, - VersionedTransaction, + VersionedTransaction, MAX_TX_ACCOUNT_LOCKS, }, }, solana_send_transaction_service::{ @@ -4029,11 +4029,10 @@ pub mod rpc_full { "get_recent_prioritization_fees rpc request received: {:?} pubkeys", pubkey_strs.len() ); - const MAX_FEE_ACCOUNTS: usize = 42; // TODO: what do we actually want here? - if pubkey_strs.len() > MAX_FEE_ACCOUNTS { + if pubkey_strs.len() > MAX_TX_ACCOUNT_LOCKS { return Err(Error::invalid_params(format!( "Too many inputs provided; max {}", - MAX_FEE_ACCOUNTS + MAX_TX_ACCOUNT_LOCKS ))); } let pubkeys = pubkey_strs From 1baeb3885076876ad6f400f1f2e438b86639f33a Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 26 Aug 2022 13:44:41 -0600 Subject: [PATCH 05/10] Remove unused cache apis --- rpc/src/rpc.rs | 2 +- runtime/src/prioritization_fee_cache.rs | 401 +++--------------------- 2 files changed, 47 insertions(+), 356 deletions(-) diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 90010d2a162159..df0f826e10abac 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -2192,7 +2192,7 @@ impl JsonRpcRequestProcessor { Ok(new_response( &bank, self.prioritization_fee_cache - .get_prioritization_fees_with_accounts(&pubkeys), + .get_prioritization_fees(&pubkeys), )) } } diff --git a/runtime/src/prioritization_fee_cache.rs b/runtime/src/prioritization_fee_cache.rs index 4a41b5cdd3fac6..63ee37cb2a4a40 100644 --- a/runtime/src/prioritization_fee_cache.rs +++ b/runtime/src/prioritization_fee_cache.rs @@ -347,43 +347,7 @@ impl PrioritizationFeeCache { .count() } - /// Query block minimum fees from finalized blocks in cache, - /// Returns a vector of fee; call site can use it to produce - /// average, or top 5% etc. - pub fn get_prioritization_fees(&self) -> Vec { - self.cache - .read() - .unwrap() - .iter() - .filter_map(|(_slot, prioritization_fee)| { - let prioritization_fee_read = prioritization_fee.lock().unwrap(); - prioritization_fee_read - .is_finalized() - .then(|| prioritization_fee_read.get_min_transaction_fee()) - }) - .flatten() - .collect() - } - - /// Query given account minimum fees from finalized blocks in cache, - /// Returns a vector of fee; call site can use it to produce - /// average, or top 5% etc. - pub fn get_account_prioritization_fees(&self, account_key: &Pubkey) -> Vec { - self.cache - .read() - .unwrap() - .iter() - .filter_map(|(_slot, prioritization_fee)| { - let prioritization_fee_read = prioritization_fee.lock().unwrap(); - prioritization_fee_read - .is_finalized() - .then(|| prioritization_fee_read.get_writable_account_fee(account_key)) - }) - .flatten() - .collect() - } - - pub fn get_prioritization_fees_with_accounts(&self, account_keys: &[Pubkey]) -> Vec { + pub fn get_prioritization_fees(&self, account_keys: &[Pubkey]) -> Vec { self.cache .read() .unwrap() @@ -597,282 +561,22 @@ mod tests { // Assert no minimum fee from empty cache assert!(prioritization_fee_cache - .get_prioritization_fees() - .is_empty()); - - // Assert after add one transaction for slot 1 - { - let txs = vec![build_sanitized_transaction_for_test( - 5, - &write_account_a, - &write_account_b, - )]; - sync_update(&mut prioritization_fee_cache, bank1.clone(), txs.iter()); - assert_eq!( - 5, - PrioritizationFeeCache::get_prioritization_fee( - prioritization_fee_cache.cache.clone(), - &bank1.slot() - ) - .lock() - .unwrap() - .get_min_transaction_fee() - .unwrap() - ); - // before block is marked as completed - assert!(prioritization_fee_cache - .get_prioritization_fees() - .is_empty()); - // after block is completed - sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, bank1.slot()); - assert_eq!(vec![5], prioritization_fee_cache.get_prioritization_fees()); - } - - // Assert after add one transaction for slot 2 - { - let txs = vec![build_sanitized_transaction_for_test( - 9, - &write_account_b, - &write_account_c, - )]; - sync_update(&mut prioritization_fee_cache, bank2.clone(), txs.iter()); - assert_eq!( - 9, - PrioritizationFeeCache::get_prioritization_fee( - prioritization_fee_cache.cache.clone(), - &bank2.slot() - ) - .lock() - .unwrap() - .get_min_transaction_fee() - .unwrap() - ); - // before block is marked as completed - assert_eq!(vec![5], prioritization_fee_cache.get_prioritization_fees()); - // after block is completed - sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, bank2.slot()); - assert_vec_eq( - &mut vec![5, 9], - &mut prioritization_fee_cache.get_prioritization_fees(), - ); - } - - // Assert after add one transaction for slot 3 - { - let txs = vec![build_sanitized_transaction_for_test( - 2, - &write_account_a, - &write_account_c, - )]; - sync_update(&mut prioritization_fee_cache, bank3.clone(), txs.iter()); - assert_eq!( - 2, - PrioritizationFeeCache::get_prioritization_fee( - prioritization_fee_cache.cache.clone(), - &bank3.slot() - ) - .lock() - .unwrap() - .get_min_transaction_fee() - .unwrap() - ); - // before block is marked as completed - assert_vec_eq( - &mut vec![5, 9], - &mut prioritization_fee_cache.get_prioritization_fees(), - ); - // after block is completed - sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, bank3.slot()); - assert_vec_eq( - &mut vec![5, 9, 2], - &mut prioritization_fee_cache.get_prioritization_fees(), - ); - } - } - - #[test] - fn test_get_account_prioritization_fees() { - 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 GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); - let bank0 = Bank::new_for_benches(&genesis_config); - let bank_forks = BankForks::new(bank0); - let bank = bank_forks.working_bank(); - let collector = solana_sdk::pubkey::new_rand(); - let bank1 = Arc::new(Bank::new_from_parent(&bank, &collector, 1)); - let bank2 = Arc::new(Bank::new_from_parent(&bank, &collector, 2)); - let bank3 = Arc::new(Bank::new_from_parent(&bank, &collector, 3)); - - let mut prioritization_fee_cache = PrioritizationFeeCache::default(); - - // Assert no minimum fee from empty cache - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_a) - .is_empty()); - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_b) - .is_empty()); - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_c) - .is_empty()); - - // Assert after add one transaction for slot 1 - { - let txs = vec![ - build_sanitized_transaction_for_test(5, &write_account_a, &write_account_b), - build_sanitized_transaction_for_test( - 0, - &Pubkey::new_unique(), - &Pubkey::new_unique(), - ), - ]; - prioritization_fee_cache.update(bank1.clone(), txs.iter()); - // before block is marked as completed - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_a) - .is_empty()); - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_b) - .is_empty()); - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_c) - .is_empty()); - // after block is completed - sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, bank1.slot()); - assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_a) - ); - assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_b) - ); - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_c) - .is_empty()); - } - - // Assert after add one transaction for slot 2 - { - let txs = vec![ - build_sanitized_transaction_for_test(9, &write_account_b, &write_account_c), - build_sanitized_transaction_for_test( - 0, - &Pubkey::new_unique(), - &Pubkey::new_unique(), - ), - ]; - prioritization_fee_cache.update(bank2.clone(), txs.iter()); - // before block is marked as completed - assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_a) - ); - assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_b) - ); - assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_c) - .is_empty()); - // after block is completed - sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, bank2.slot()); - assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_a) - ); - assert_vec_eq( - &mut vec![5, 9], - &mut prioritization_fee_cache.get_account_prioritization_fees(&write_account_b), - ); - assert_eq!( - vec![9], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_c) - ); - } - - // Assert after add one transaction for slot 3 - { - let txs = vec![ - build_sanitized_transaction_for_test(2, &write_account_a, &write_account_c), - build_sanitized_transaction_for_test( - 0, - &Pubkey::new_unique(), - &Pubkey::new_unique(), - ), - ]; - prioritization_fee_cache.update(bank3.clone(), txs.iter()); - // before block is marked as completed - assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_a) - ); - assert_vec_eq( - &mut vec![5, 9], - &mut prioritization_fee_cache.get_account_prioritization_fees(&write_account_b), - ); - assert_eq!( - vec![9], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_c) - ); - // after block is completed - sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, bank3.slot()); - assert_vec_eq( - &mut vec![5, 2], - &mut prioritization_fee_cache.get_account_prioritization_fees(&write_account_a), - ); - assert_vec_eq( - &mut vec![5, 9], - &mut prioritization_fee_cache.get_account_prioritization_fees(&write_account_b), - ); - assert_vec_eq( - &mut vec![9, 2], - &mut prioritization_fee_cache.get_account_prioritization_fees(&write_account_c), - ); - } - } - - #[test] - fn test_get_prioritization_fees_with_accounts() { - 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 GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000); - let bank0 = Bank::new_for_benches(&genesis_config); - let bank_forks = BankForks::new(bank0); - let bank = bank_forks.working_bank(); - let collector = solana_sdk::pubkey::new_rand(); - let bank1 = Arc::new(Bank::new_from_parent(&bank, &collector, 1)); - let bank2 = Arc::new(Bank::new_from_parent(&bank1, &collector, 2)); - let bank3 = Arc::new(Bank::new_from_parent(&bank2, &collector, 3)); - - let mut prioritization_fee_cache = PrioritizationFeeCache::default(); - - // Assert no minimum fee from empty cache - assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[]) + .get_prioritization_fees(&[]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a]) + .get_prioritization_fees(&[write_account_a]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_b]) + .get_prioritization_fees(&[write_account_b]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_c]) + .get_prioritization_fees(&[write_account_c]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + .get_prioritization_fees(&[write_account_a, write_account_b]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[ - write_account_a, - write_account_b, - write_account_c - ]) + .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c]) .is_empty()); // Assert after add one transaction for slot 1 @@ -885,56 +589,52 @@ mod tests { &Pubkey::new_unique(), ), ]; - prioritization_fee_cache.update(bank1, txs.iter()); + sync_update(&mut prioritization_fee_cache, bank1, txs.iter()); // before block is marked as completed assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[]) + .get_prioritization_fees(&[]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a]) + .get_prioritization_fees(&[write_account_a]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_b]) + .get_prioritization_fees(&[write_account_b]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_c]) + .get_prioritization_fees(&[write_account_c]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + .get_prioritization_fees(&[write_account_a, write_account_b]) .is_empty()); assert!(prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[ - write_account_a, - write_account_b, - write_account_c - ]) + .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c]) .is_empty()); // after block is completed sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 1); assert_eq!( vec![1], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]) + prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( vec![2], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_a]) + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) ); assert_eq!( vec![2], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_b]) + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) ); assert_eq!( vec![1], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_c]) + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) ); assert_eq!( vec![2], prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + .get_prioritization_fees(&[write_account_a, write_account_b]) ); assert_eq!( vec![2], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c @@ -952,32 +652,32 @@ mod tests { &Pubkey::new_unique(), ), ]; - prioritization_fee_cache.update(bank2, txs.iter()); + sync_update(&mut prioritization_fee_cache, bank2, txs.iter()); // before block is marked as completed assert_eq!( vec![1], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]) + prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( vec![2], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_a]) + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) ); assert_eq!( vec![2], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_b]) + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) ); assert_eq!( vec![1], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[write_account_c]) + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) ); assert_eq!( vec![2], prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]) + .get_prioritization_fees(&[write_account_a, write_account_b]) ); assert_eq!( vec![2], - prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c @@ -987,31 +687,28 @@ mod tests { sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 2); assert_vec_eq( &mut vec![3, 1], - &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]), + &mut prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_vec_eq( &mut vec![3, 2], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); assert_vec_eq( &mut vec![4, 2], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_b]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); assert_vec_eq( &mut vec![4, 1], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_c]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); assert_vec_eq( &mut vec![4, 2], &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]), + .get_prioritization_fees(&[write_account_a, write_account_b]), ); assert_vec_eq( &mut vec![4, 2], - &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + &mut prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c, @@ -1029,35 +726,32 @@ mod tests { &Pubkey::new_unique(), ), ]; - prioritization_fee_cache.update(bank3, txs.iter()); + sync_update(&mut prioritization_fee_cache, bank3, txs.iter()); // before block is marked as completed assert_vec_eq( &mut vec![3, 1], - &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]), + &mut prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_vec_eq( &mut vec![3, 2], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); assert_vec_eq( &mut vec![4, 2], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_b]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); assert_vec_eq( &mut vec![4, 1], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_c]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); assert_vec_eq( &mut vec![4, 2], &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]), + .get_prioritization_fees(&[write_account_a, write_account_b]), ); assert_vec_eq( &mut vec![4, 2], - &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + &mut prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c, @@ -1067,31 +761,28 @@ mod tests { sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 3); assert_vec_eq( &mut vec![5, 3, 1], - &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[]), + &mut prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_vec_eq( &mut vec![6, 3, 2], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); assert_vec_eq( &mut vec![5, 4, 2], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_b]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); assert_vec_eq( &mut vec![6, 4, 1], - &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_c]), + &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); assert_vec_eq( &mut vec![6, 4, 2], &mut prioritization_fee_cache - .get_prioritization_fees_with_accounts(&[write_account_a, write_account_b]), + .get_prioritization_fees(&[write_account_a, write_account_b]), ); assert_vec_eq( &mut vec![6, 4, 2], - &mut prioritization_fee_cache.get_prioritization_fees_with_accounts(&[ + &mut prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c, From 7eb2be5b065595960c7575d17323d0048e442eb1 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Fri, 26 Aug 2022 16:40:42 -0600 Subject: [PATCH 06/10] Map fee data by slot, and make rpc account inputs optional --- rpc-client-api/src/response.rs | 6 + rpc/src/rpc.rs | 31 ++--- runtime/src/prioritization_fee_cache.rs | 145 ++++++++++++------------ 3 files changed, 94 insertions(+), 88 deletions(-) diff --git a/rpc-client-api/src/response.rs b/rpc-client-api/src/response.rs index 12cb5c631817c1..29ce96166c776c 100644 --- a/rpc-client-api/src/response.rs +++ b/rpc-client-api/src/response.rs @@ -544,3 +544,9 @@ pub struct RpcSnapshotSlotInfo { pub full: Slot, pub incremental: Option, } + +#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)] +pub struct RpcPrioritizationFee { + pub slot: Slot, + pub prioritization_fee: u64, +} diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index df0f826e10abac..8d60a6f446ba8d 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -2186,14 +2186,16 @@ impl JsonRpcRequestProcessor { fn get_recent_prioritization_fees( &self, pubkeys: Vec, - config: RpcContextConfig, - ) -> Result>> { - let bank = self.get_bank_with_config(config)?; - Ok(new_response( - &bank, - self.prioritization_fee_cache - .get_prioritization_fees(&pubkeys), - )) + ) -> Result> { + Ok(self + .prioritization_fee_cache + .get_prioritization_fees(&pubkeys) + .into_iter() + .map(|(slot, prioritization_fee)| RpcPrioritizationFee { + slot, + prioritization_fee, + }) + .collect()) } } @@ -3439,9 +3441,8 @@ pub mod rpc_full { fn get_recent_prioritization_fees( &self, meta: Self::Metadata, - pubkey_strs: Vec, - config: Option, - ) -> Result>>; + pubkey_strs: Option>, + ) -> Result>; } pub struct FullImpl; @@ -4022,9 +4023,9 @@ pub mod rpc_full { fn get_recent_prioritization_fees( &self, meta: Self::Metadata, - pubkey_strs: Vec, - config: Option, - ) -> Result>> { + pubkey_strs: Option>, + ) -> Result> { + let pubkey_strs = pubkey_strs.unwrap_or_default(); debug!( "get_recent_prioritization_fees rpc request received: {:?} pubkeys", pubkey_strs.len() @@ -4039,7 +4040,7 @@ pub mod rpc_full { .into_iter() .map(|pubkey_str| verify_pubkey(&pubkey_str)) .collect::>>()?; - meta.get_recent_prioritization_fees(pubkeys, config.unwrap_or_default()) + meta.get_recent_prioritization_fees(pubkeys) } } } diff --git a/runtime/src/prioritization_fee_cache.rs b/runtime/src/prioritization_fee_cache.rs index 63ee37cb2a4a40..90e66e522c85f3 100644 --- a/runtime/src/prioritization_fee_cache.rs +++ b/runtime/src/prioritization_fee_cache.rs @@ -11,6 +11,7 @@ use { clock::Slot, pubkey::Pubkey, saturating_add_assign, transaction::SanitizedTransaction, }, std::{ + collections::HashMap, sync::{ atomic::{AtomicU64, Ordering}, Arc, Mutex, RwLock, @@ -347,12 +348,12 @@ impl PrioritizationFeeCache { .count() } - pub fn get_prioritization_fees(&self, account_keys: &[Pubkey]) -> Vec { + pub fn get_prioritization_fees(&self, account_keys: &[Pubkey]) -> HashMap { self.cache .read() .unwrap() .iter() - .filter_map(|(_slot, prioritization_fee)| { + .filter_map(|(slot, prioritization_fee)| { let prioritization_fee_read = prioritization_fee.lock().unwrap(); prioritization_fee_read.is_finalized().then(|| { let mut fee = prioritization_fee_read @@ -365,7 +366,7 @@ impl PrioritizationFeeCache { fee = std::cmp::max(fee, account_fee); } } - Some(fee) + Some((*slot, fee)) }) }) .flatten() @@ -535,10 +536,8 @@ mod tests { assert_eq!(2, prioritization_fee_cache.available_block_count()); } - fn assert_vec_eq(expected: &mut Vec, actual: &mut Vec) { - expected.sort_unstable(); - actual.sort_unstable(); - assert_eq!(expected, actual); + fn hashmap_of(vec: Vec<(Slot, u64)>) -> HashMap { + vec.into_iter().collect() } #[test] @@ -612,28 +611,28 @@ mod tests { // after block is completed sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 1); assert_eq!( - vec![1], + hashmap_of(vec![(1, 1)]), prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) ); assert_eq!( - vec![1], + hashmap_of(vec![(1, 1)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, @@ -655,28 +654,28 @@ mod tests { sync_update(&mut prioritization_fee_cache, bank2, txs.iter()); // before block is marked as completed assert_eq!( - vec![1], + hashmap_of(vec![(1, 1)]), prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) ); assert_eq!( - vec![1], + hashmap_of(vec![(1, 1)]), prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]) ); assert_eq!( - vec![2], + hashmap_of(vec![(1, 2)]), prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, @@ -685,30 +684,30 @@ mod tests { ); // after block is completed sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 2); - assert_vec_eq( - &mut vec![3, 1], - &mut prioritization_fee_cache.get_prioritization_fees(&[]), + assert_eq!( + hashmap_of(vec![(2, 3), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]), ); - assert_vec_eq( - &mut vec![3, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), + assert_eq!( + hashmap_of(vec![(2, 3), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); - assert_vec_eq( - &mut vec![4, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); - assert_vec_eq( - &mut vec![4, 1], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), + assert_eq!( + hashmap_of(vec![(2, 4), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); - assert_vec_eq( - &mut vec![4, 2], - &mut prioritization_fee_cache + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]), ); - assert_vec_eq( - &mut vec![4, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[ + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c, @@ -728,30 +727,30 @@ mod tests { ]; sync_update(&mut prioritization_fee_cache, bank3, txs.iter()); // before block is marked as completed - assert_vec_eq( - &mut vec![3, 1], - &mut prioritization_fee_cache.get_prioritization_fees(&[]), + assert_eq!( + hashmap_of(vec![(2, 3), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]), ); - assert_vec_eq( - &mut vec![3, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), + assert_eq!( + hashmap_of(vec![(2, 3), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); - assert_vec_eq( - &mut vec![4, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); - assert_vec_eq( - &mut vec![4, 1], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), + assert_eq!( + hashmap_of(vec![(2, 4), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); - assert_vec_eq( - &mut vec![4, 2], - &mut prioritization_fee_cache + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]), ); - assert_vec_eq( - &mut vec![4, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[ + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c, @@ -759,30 +758,30 @@ mod tests { ); // after block is completed sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 3); - assert_vec_eq( - &mut vec![5, 3, 1], - &mut prioritization_fee_cache.get_prioritization_fees(&[]), + assert_eq!( + hashmap_of(vec![(3, 5), (2, 3), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]), ); - assert_vec_eq( - &mut vec![6, 3, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), + assert_eq!( + hashmap_of(vec![(3, 6), (2, 3), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); - assert_vec_eq( - &mut vec![5, 4, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), + assert_eq!( + hashmap_of(vec![(3, 5), (2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), ); - assert_vec_eq( - &mut vec![6, 4, 1], - &mut prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), + assert_eq!( + hashmap_of(vec![(3, 6), (2, 4), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), ); - assert_vec_eq( - &mut vec![6, 4, 2], - &mut prioritization_fee_cache + assert_eq!( + hashmap_of(vec![(3, 6), (2, 4), (1, 2)]), + prioritization_fee_cache .get_prioritization_fees(&[write_account_a, write_account_b]), ); - assert_vec_eq( - &mut vec![6, 4, 2], - &mut prioritization_fee_cache.get_prioritization_fees(&[ + assert_eq!( + hashmap_of(vec![(3, 6), (2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[ write_account_a, write_account_b, write_account_c, From acc54168d2e0999c99336d83a771c01fab4d4833 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Tue, 30 Aug 2022 15:15:09 -0600 Subject: [PATCH 07/10] Add priority_fee_cache to rpc test framework, and add test --- rpc/src/rpc.rs | 178 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/rpc/src/rpc.rs b/rpc/src/rpc.rs index 8d60a6f446ba8d..2a01b9f8f61827 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -4644,6 +4644,7 @@ pub mod tests { solana_sdk::{ account::{Account, WritableAccount}, clock::MAX_RECENT_BLOCKHASHES, + compute_budget::ComputeBudgetInstruction, fee_calculator::DEFAULT_BURN_PERCENT, hash::{hash, Hash}, instruction::InstructionError, @@ -4989,6 +4990,20 @@ pub mod tests { bank.store_account(vote_pubkey, &vote_account); } + fn update_prioritization_fee_cache(&self, transactions: Vec) { + let bank = self.working_bank(); + let prioritization_fee_cache = &self.meta.prioritization_fee_cache; + let transactions: Vec<_> = transactions + .into_iter() + .map(|tx| SanitizedTransaction::try_from_legacy_transaction(tx).unwrap()) + .collect(); + prioritization_fee_cache.update(bank, transactions.iter()); + } + + fn get_prioritization_fee_cache(&self) -> &PrioritizationFeeCache { + &self.meta.prioritization_fee_cache + } + fn working_bank(&self) -> Arc { self.bank_forks.read().unwrap().working_bank() } @@ -8457,4 +8472,167 @@ pub mod tests { expected_stake_minimum_delegation ); } + + #[test] + fn test_rpc_get_recent_prioritization_fees() { + fn wait_for_cache_blocks(cache: &PrioritizationFeeCache, num_blocks: usize) { + while cache.available_block_count() < num_blocks { + std::thread::sleep(std::time::Duration::from_millis(100)); + } + } + + fn assert_fee_vec_eq( + expected: &mut Vec, + actual: &mut Vec, + ) { + expected.sort_by(|a, b| a.slot.partial_cmp(&b.slot).unwrap()); + actual.sort_by(|a, b| a.slot.partial_cmp(&b.slot).unwrap()); + assert_eq!(expected, actual); + } + + let rpc = RpcHandler::start(); + assert_eq!( + rpc.get_prioritization_fee_cache().available_block_count(), + 0 + ); + let slot0 = rpc.working_bank().slot(); + let account0 = Pubkey::new_unique(); + let account1 = Pubkey::new_unique(); + let account2 = Pubkey::new_unique(); + let price0 = 42; + let transactions = vec![ + Transaction::new_unsigned(Message::new( + &[ + system_instruction::transfer(&account0, &account1, 1), + ComputeBudgetInstruction::set_compute_unit_price(price0), + ], + Some(&account0), + )), + Transaction::new_unsigned(Message::new( + &[system_instruction::transfer(&account0, &account2, 1)], + Some(&account0), + )), + ]; + rpc.update_prioritization_fee_cache(transactions); + let cache = rpc.get_prioritization_fee_cache(); + cache.finalize_priority_fee(slot0); + wait_for_cache_blocks(cache, 1); + + let request = create_test_request("getRecentPrioritizationFees", None); + let mut response: Vec = + parse_success_result(rpc.handle_request_sync(request)); + assert_fee_vec_eq( + &mut response, + &mut vec![RpcPrioritizationFee { + slot: slot0, + prioritization_fee: 0, + }], + ); + + let request = create_test_request( + "getRecentPrioritizationFees", + Some(json!([[account1.to_string()]])), + ); + let mut response: Vec = + parse_success_result(rpc.handle_request_sync(request)); + assert_fee_vec_eq( + &mut response, + &mut vec![RpcPrioritizationFee { + slot: slot0, + prioritization_fee: price0, + }], + ); + + let request = create_test_request( + "getRecentPrioritizationFees", + Some(json!([[account2.to_string()]])), + ); + let mut response: Vec = + parse_success_result(rpc.handle_request_sync(request)); + assert_fee_vec_eq( + &mut response, + &mut vec![RpcPrioritizationFee { + slot: slot0, + prioritization_fee: 0, + }], + ); + + rpc.advance_bank_to_confirmed_slot(1); + let slot1 = rpc.working_bank().slot(); + let price1 = 11; + let transactions = vec![ + Transaction::new_unsigned(Message::new( + &[ + system_instruction::transfer(&account0, &account2, 1), + ComputeBudgetInstruction::set_compute_unit_price(price1), + ], + Some(&account0), + )), + Transaction::new_unsigned(Message::new( + &[system_instruction::transfer(&account0, &account1, 1)], + Some(&account0), + )), + ]; + rpc.update_prioritization_fee_cache(transactions); + let cache = rpc.get_prioritization_fee_cache(); + cache.finalize_priority_fee(slot1); + wait_for_cache_blocks(cache, 2); + + let request = create_test_request("getRecentPrioritizationFees", None); + let mut response: Vec = + parse_success_result(rpc.handle_request_sync(request)); + assert_fee_vec_eq( + &mut response, + &mut vec![ + RpcPrioritizationFee { + slot: slot0, + prioritization_fee: 0, + }, + RpcPrioritizationFee { + slot: slot1, + prioritization_fee: 0, + }, + ], + ); + + let request = create_test_request( + "getRecentPrioritizationFees", + Some(json!([[account1.to_string()]])), + ); + let mut response: Vec = + parse_success_result(rpc.handle_request_sync(request)); + assert_fee_vec_eq( + &mut response, + &mut vec![ + RpcPrioritizationFee { + slot: slot0, + prioritization_fee: price0, + }, + RpcPrioritizationFee { + slot: slot1, + prioritization_fee: 0, + }, + ], + ); + + let request = create_test_request( + "getRecentPrioritizationFees", + Some(json!([[account2.to_string()]])), + ); + let mut response: Vec = + parse_success_result(rpc.handle_request_sync(request)); + assert_fee_vec_eq( + &mut response, + &mut vec![ + RpcPrioritizationFee { + slot: slot0, + prioritization_fee: 0, + }, + RpcPrioritizationFee { + slot: slot1, + prioritization_fee: price1, + }, + ], + ); + } } From 30998da8ba82631e2cc74984e1297786cf7c0f0c Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Tue, 30 Aug 2022 22:57:03 -0600 Subject: [PATCH 08/10] Add endpoint to jsonrpc docs --- docs/src/developing/clients/jsonrpc-api.md | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 4d19df8a4bea5f..4a96d65a39bc26 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -48,6 +48,7 @@ gives a convenient interface for the RPC methods. - [getMultipleAccounts](jsonrpc-api.md#getmultipleaccounts) - [getProgramAccounts](jsonrpc-api.md#getprogramaccounts) - [getRecentPerformanceSamples](jsonrpc-api.md#getrecentperformancesamples) +- [getRecentPrioritizationFees](jsonrpc-api.md#getrecentprioritizationfees) - [getSignaturesForAddress](jsonrpc-api.md#getsignaturesforaddress) - [getSignatureStatuses](jsonrpc-api.md#getsignaturestatuses) - [getSlot](jsonrpc-api.md#getslot) @@ -2096,6 +2097,65 @@ Result: } ``` +### getRecentPrioritizationFees + +Returns a list of minimum prioritization fees from recent blocks. Currently, a +node's prioritization-fee cache stores data from up to 150 blocks. + +#### Parameters: + +- `` - (optional) An array of account address strings. If this parameter is provided, the response will reflect the minimum prioritization fee to land transaction locking any of the provided accounts as writable. + +#### Results: + +An array of: + +- `RpcPrioritizationFee` + - `slot: ` - Slot in which minimum fee was observed + - `prioritizationFee: ` - Minimum fee paid for a successfully landed transaction + +#### Example: + +Request: + +```bash +// Request +curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d ' + {"jsonrpc":"2.0", "id":1, "method":"getRecentPrioritizationFees", "params": [["CxELquR1gPP8wHe33gZ4QxqGB3sZ9RSwsJ2KshVewkFY"]]} +' +``` + +Result: + +```json +{ + "jsonrpc": "2.0", + "result": [ + { + "slot": 348125, + "prioritizationFee": 0, + }, + { + "slot": 348126, + "prioritizationFee": 1000, + }, + { + "slot": 348127, + "prioritizationFee": 500, + }, + { + "slot": 348128, + "prioritizationFee": 0, + }, + { + "slot": 348129, + "prioritizationFee": 1234, + } + ], + "id": 1 +} +``` + ### getSignaturesForAddress Returns signatures for confirmed transactions that include the given address in From 1a606fe1cb3cc2da5c82efe258ae0d3cfc6c0fce Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 1 Sep 2022 10:42:38 -0600 Subject: [PATCH 09/10] Update docs/src/developing/clients/jsonrpc-api.md --- docs/src/developing/clients/jsonrpc-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 4a96d65a39bc26..2a75ecabe842bd 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -2104,7 +2104,7 @@ node's prioritization-fee cache stores data from up to 150 blocks. #### Parameters: -- `` - (optional) An array of account address strings. If this parameter is provided, the response will reflect the minimum prioritization fee to land transaction locking any of the provided accounts as writable. +- `` - (optional) An array of account address strings. If this parameter is provided, the response will reflect the minimum prioritization fee to land a transaction locking any of the provided accounts as writable. #### Results: From 537ba079f70165e65b99acce7c24344bdee39f55 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 1 Sep 2022 10:50:37 -0600 Subject: [PATCH 10/10] Update docs/src/developing/clients/jsonrpc-api.md --- docs/src/developing/clients/jsonrpc-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 2a75ecabe842bd..af8e947fcd771f 100644 --- a/docs/src/developing/clients/jsonrpc-api.md +++ b/docs/src/developing/clients/jsonrpc-api.md @@ -2104,7 +2104,7 @@ node's prioritization-fee cache stores data from up to 150 blocks. #### Parameters: -- `` - (optional) An array of account address strings. If this parameter is provided, the response will reflect the minimum prioritization fee to land a transaction locking any of the provided accounts as writable. +- `` - (optional) An array of account address strings. If this parameter is provided, the response will reflect the minimum prioritization fee to land a transaction locking all of the provided accounts as writable. #### Results: