diff --git a/client/src/rpc_response.rs b/client/src/rpc_response.rs index 79a3429a478fb9..dbbf810ea14161 100644 --- a/client/src/rpc_response.rs +++ b/client/src/rpc_response.rs @@ -541,3 +541,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/core/src/validator.rs b/core/src/validator.rs index 818e835d435ac9..9d06c9d61577e4 100644 --- a/core/src/validator.rs +++ b/core/src/validator.rs @@ -845,6 +845,7 @@ impl Validator { leader_schedule_cache.clone(), connection_cache.clone(), max_complete_transaction_status_slot, + prioritization_fee_cache.clone(), )), if !config.rpc_config.full_api { None diff --git a/docs/src/developing/clients/jsonrpc-api.md b/docs/src/developing/clients/jsonrpc-api.md index 852d7d618369d6..ae0f4e1daf4d37 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) @@ -2114,6 +2115,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/src/rpc.rs b/rpc/src/rpc.rs index ea04301e4dbdee..cafe347f884c35 100644 --- a/rpc/src/rpc.rs +++ b/rpc/src/rpc.rs @@ -49,6 +49,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, }, @@ -72,7 +73,7 @@ use { sysvar::stake_history, transaction::{ self, AddressLoader, MessageHash, SanitizedTransaction, TransactionError, - VersionedTransaction, + VersionedTransaction, MAX_TX_ACCOUNT_LOCKS, }, }, solana_send_transaction_service::{ @@ -200,6 +201,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 {} @@ -305,6 +307,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(); ( @@ -325,6 +328,7 @@ impl JsonRpcRequestProcessor { max_slots, leader_schedule_cache, max_complete_transaction_status_slot, + prioritization_fee_cache, }, receiver, ) @@ -389,6 +393,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()), } } @@ -2156,6 +2161,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]) { @@ -3402,6 +3422,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; @@ -3989,6 +4016,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) + } } } @@ -4597,6 +4647,7 @@ pub mod tests { solana_sdk::{ account::{Account, WritableAccount}, clock::MAX_RECENT_BLOCKHASHES, + compute_budget::ComputeBudgetInstruction, fee_calculator::{FeeRateGovernor, DEFAULT_BURN_PERCENT}, hash::{hash, Hash}, instruction::InstructionError, @@ -4733,6 +4784,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; @@ -4949,6 +5001,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() } @@ -6311,6 +6377,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::( @@ -6581,6 +6648,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::( @@ -8212,6 +8280,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(); @@ -8421,50 +8490,165 @@ pub mod tests { } #[test] - fn test_get_fee_for_message() { + 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(); - let bank = rpc.working_bank(); - // Slot hashes is necessary for processing versioned txs. - bank.set_sysvar_for_tests(&SlotHashes::default()); - // Correct blockhash is needed because fees are specific to blockhashes - let recent_blockhash = bank.last_blockhash(); + 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 legacy_msg = VersionedMessage::Legacy(Message { - header: MessageHeader { - num_required_signatures: 1, - ..MessageHeader::default() - }, - recent_blockhash, - account_keys: vec![Pubkey::new_unique()], - ..Message::default() - }); + 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( - "getFeeForMessage", - Some(json!([base64::encode(&serialize(&legacy_msg).unwrap())])), - ); - let response: RpcResponse = parse_success_result(rpc.handle_request_sync(request)); - assert_eq!(response.value, TEST_SIGNATURE_FEE); - } + 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 v0_msg = VersionedMessage::V0(v0::Message { - header: MessageHeader { - num_required_signatures: 1, - ..MessageHeader::default() + 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, }, - recent_blockhash, - account_keys: vec![Pubkey::new_unique()], - ..v0::Message::default() - }); + RpcPrioritizationFee { + slot: slot1, + prioritization_fee: 0, + }, + ], + ); - let request = create_test_request( - "getFeeForMessage", - Some(json!([base64::encode(&serialize(&v0_msg).unwrap())])), - ); - let response: RpcResponse = parse_success_result(rpc.handle_request_sync(request)); - assert_eq!(response.value, TEST_SIGNATURE_FEE); - } + 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 61380e73d2ec38..a1acec205e2302 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, }, @@ -355,6 +356,7 @@ impl JsonRpcService { leader_schedule_cache: Arc, connection_cache: Arc, current_transaction_status_slot: Arc, + prioritization_fee_cache: Arc, ) -> Self { info!("rpc bound to {:?}", rpc_addr); info!("rpc configuration: {:?}", config); @@ -460,6 +462,7 @@ impl JsonRpcService { max_slots, leader_schedule_cache, current_transaction_status_slot, + prioritization_fee_cache, ); let leader_info = @@ -641,6 +644,7 @@ mod tests { Arc::new(LeaderScheduleCache::default()), connection_cache, Arc::new(AtomicU64::default()), + Arc::new(PrioritizationFeeCache::default()), ); let thread = rpc_service.thread_hdl.thread(); assert_eq!(thread.name().unwrap(), "solJsonRpcSvc"); diff --git a/runtime/src/prioritization_fee_cache.rs b/runtime/src/prioritization_fee_cache.rs index 1399544af81dff..944f35e19519a9 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() + .get_prioritization_fees(&[]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees(&[write_account_a]) + .is_empty()); + assert!(prioritization_fee_cache + .get_prioritization_fees(&[write_account_b]) .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(&[write_account_c]) .is_empty()); assert!(prioritization_fee_cache - .get_account_prioritization_fees(&write_account_b) + .get_prioritization_fees(&[write_account_a, write_account_b]) .is_empty()); assert!(prioritization_fee_cache - .get_account_prioritization_fees(&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 { 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) + hashmap_of(vec![(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![(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!( - vec![9], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_c) + 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) + hashmap_of(vec![(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![(2, 3), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), ); assert_eq!( - vec![9], - prioritization_fee_cache.get_account_prioritization_fees(&write_account_c) + 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), - ); - 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), + 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_eq!( + hashmap_of(vec![(3, 6), (2, 3), (1, 2)]), + prioritization_fee_cache.get_prioritization_fees(&[write_account_a]), + ); + 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, + ]), ); } }