From 9b8bed86f9cfb64b71e7ec2c0f7e7f1f91500091 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Thu, 1 Sep 2022 16:12:12 -0700 Subject: [PATCH] Add getRecentPrioritizationFees RPC endpoint (#27278) * Plumb priority_fee_cache into rpc * Add PrioritizationFeeCache api * Add getRecentPrioritizationFees rpc endpoint * Use MAX_TX_ACCOUNT_LOCKS to limit input keys * Remove unused cache apis * Map fee data by slot, and make rpc account inputs optional * Add priority_fee_cache to rpc test framework, and add test * Add endpoint to jsonrpc docs * Update docs/src/developing/clients/jsonrpc-api.md * Update docs/src/developing/clients/jsonrpc-api.md --- core/src/validator.rs | 1 + docs/src/developing/clients/jsonrpc-api.md | 60 ++++ rpc-client-api/src/response.rs | 6 + rpc/src/rpc.rs | 234 ++++++++++++- rpc/src/rpc_service.rs | 4 + runtime/src/prioritization_fee_cache.rs | 379 ++++++++++----------- 6 files changed, 484 insertions(+), 200 deletions(-) diff --git a/core/src/validator.rs b/core/src/validator.rs index d52bdbcd1..57102f124 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/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index e84a51e9f..fd5924a38 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 a transaction locking all 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 diff --git a/rpc-client-api/src/response.rs b/rpc-client-api/src/response.rs index 12cb5c631..29ce96166 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 8d5d12f03..2a01b9f8f 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, }, @@ -71,7 +72,7 @@ use { sysvar::stake_history, transaction::{ self, AddressLoader, MessageHash, SanitizedTransaction, TransactionError, - VersionedTransaction, + VersionedTransaction, MAX_TX_ACCOUNT_LOCKS, }, }, solana_send_transaction_service::{ @@ -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()), } } @@ -2177,6 +2182,21 @@ 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, + ) -> Result> { + Ok(self + .prioritization_fee_cache + .get_prioritization_fees(&pubkeys) + .into_iter() + .map(|(slot, prioritization_fee)| RpcPrioritizationFee { + slot, + prioritization_fee, + }) + .collect()) + } } fn optimize_filters(filters: &mut [RpcFilterType]) { @@ -3416,6 +3436,13 @@ 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: Option>, + ) -> Result>; } pub struct FullImpl; @@ -3992,6 +4019,29 @@ 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: Option>, + ) -> Result> { + let pubkey_strs = pubkey_strs.unwrap_or_default(); + debug!( + "get_recent_prioritization_fees rpc request received: {:?} pubkeys", + pubkey_strs.len() + ); + if pubkey_strs.len() > MAX_TX_ACCOUNT_LOCKS { + return Err(Error::invalid_params(format!( + "Too many inputs provided; max {}", + MAX_TX_ACCOUNT_LOCKS + ))); + } + let pubkeys = pubkey_strs + .into_iter() + .map(|pubkey_str| verify_pubkey(&pubkey_str)) + .collect::>>()?; + meta.get_recent_prioritization_fees(pubkeys) + } } } @@ -4594,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, @@ -4726,6 +4777,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; @@ -4938,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() } @@ -6300,6 +6366,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 +6636,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 +8264,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(); @@ -8403,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, + }, + ], + ); + } } diff --git a/rpc/src/rpc_service.rs b/rpc/src/rpc_service.rs index 97b6fb45b..823818b25 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(); diff --git a/runtime/src/prioritization_fee_cache.rs b/runtime/src/prioritization_fee_cache.rs index 3ecf11cdc..90e66e522 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,37 +348,26 @@ 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 { + 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(|| 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)) + 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((*slot, fee)) + }) }) .flatten() .collect() @@ -546,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] @@ -572,239 +560,232 @@ 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) + .get_prioritization_fees(&[]) .is_empty()); assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_b) + .get_prioritization_fees(&[write_account_a]) .is_empty()); assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_c) + .get_prioritization_fees(&[write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees(&[write_account_c]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees(&[write_account_a, write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees(&[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(5, &write_account_a, &write_account_b), + build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b), build_sanitized_transaction_for_test( - 0, + 1, &Pubkey::new_unique(), &Pubkey::new_unique(), ), ]; - prioritization_fee_cache.update(bank1.clone(), txs.iter()); + sync_update(&mut prioritization_fee_cache, bank1, txs.iter()); // before block is marked as completed assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_a) + .get_prioritization_fees(&[]) .is_empty()); assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_b) + .get_prioritization_fees(&[write_account_a]) .is_empty()); assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_c) + .get_prioritization_fees(&[write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees(&[write_account_c]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees(&[write_account_a, write_account_b]) + .is_empty()); + assert!(prioritization_fee_cache + .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, bank1.slot()); + sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 1); assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_a) + hashmap_of(vec![(1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_b) + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) + ); + assert_eq!( + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) + ); + assert_eq!( + hashmap_of(vec![(1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) + ); + assert_eq!( + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache + .get_prioritization_fees(&[write_account_a, write_account_b]) + ); + assert_eq!( + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[ + write_account_a, + write_account_b, + write_account_c + ]) ); - 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(4, &write_account_b, &write_account_c), build_sanitized_transaction_for_test( - 0, + 3, &Pubkey::new_unique(), &Pubkey::new_unique(), ), ]; - prioritization_fee_cache.update(bank2.clone(), txs.iter()); + sync_update(&mut prioritization_fee_cache, bank2, txs.iter()); // before block is marked as completed assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_a) + hashmap_of(vec![(1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]) ); assert_eq!( - vec![5], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_b) + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]) + ); + assert_eq!( + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]) + ); + assert_eq!( + hashmap_of(vec![(1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]) + ); + assert_eq!( + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache + .get_prioritization_fees(&[write_account_a, write_account_b]) + ); + assert_eq!( + hashmap_of(vec![(1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[ + write_account_a, + write_account_b, + write_account_c + ]) ); - 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()); + sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 2); 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), + hashmap_of(vec![(2, 3), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_eq!( - vec![9], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_c) + hashmap_of(vec![(2, 3), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache + .get_prioritization_fees(&[write_account_a, write_account_b]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[ + 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(2, &write_account_a, &write_account_c), + build_sanitized_transaction_for_test(6, &write_account_a, &write_account_c), build_sanitized_transaction_for_test( - 0, + 5, &Pubkey::new_unique(), &Pubkey::new_unique(), ), ]; - prioritization_fee_cache.update(bank3.clone(), txs.iter()); + sync_update(&mut prioritization_fee_cache, bank3, 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), + hashmap_of(vec![(2, 3), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]), ); assert_eq!( - vec![9], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_c) + hashmap_of(vec![(2, 3), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache + .get_prioritization_fees(&[write_account_a, write_account_b]), + ); + assert_eq!( + hashmap_of(vec![(2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[ + write_account_a, + write_account_b, + 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), + sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 3); + assert_eq!( + hashmap_of(vec![(3, 5), (2, 3), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[]), ); - assert_vec_eq( - &mut vec![5, 9], - &mut prioritization_fee_cache.get_account_prioritization_fees(&write_account_b), + 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![9, 2], - &mut prioritization_fee_cache.get_account_prioritization_fees(&write_account_c), + assert_eq!( + hashmap_of(vec![(3, 5), (2, 4), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_b]), + ); + assert_eq!( + hashmap_of(vec![(3, 6), (2, 4), (1, 1)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_c]), + ); + assert_eq!( + hashmap_of(vec![(3, 6), (2, 4), (1, 2)]), + prioritization_fee_cache + .get_prioritization_fees(&[write_account_a, write_account_b]), + ); + 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, + ]), ); } }