1use {
2 crate::{
3 bank::Bank, prioritization_fee::*,
4 transaction_priority_details::GetTransactionPriorityDetails,
5 },
6 crossbeam_channel::{unbounded, Receiver, Sender},
7 log::*,
8 lru::LruCache,
9 solana_measure::measure,
10 solana_sdk::{
11 clock::Slot, pubkey::Pubkey, saturating_add_assign, transaction::SanitizedTransaction,
12 },
13 std::{
14 collections::HashMap,
15 sync::{
16 atomic::{AtomicU64, Ordering},
17 Arc, Mutex, RwLock,
18 },
19 thread::{Builder, JoinHandle},
20 },
21};
22
23const MAX_NUM_RECENT_BLOCKS: u64 = 150;
27
28#[derive(Debug, Default)]
29struct PrioritizationFeeCacheMetrics {
30 successful_transaction_update_count: AtomicU64,
32
33 total_update_elapsed_us: AtomicU64,
35
36 total_cache_lock_elapsed_us: AtomicU64,
38
39 total_entry_lock_elapsed_us: AtomicU64,
41
42 total_entry_update_elapsed_us: AtomicU64,
44
45 total_block_finalize_elapsed_us: AtomicU64,
47}
48
49impl PrioritizationFeeCacheMetrics {
50 fn accumulate_successful_transaction_update_count(&self, val: u64) {
51 self.successful_transaction_update_count
52 .fetch_add(val, Ordering::Relaxed);
53 }
54
55 fn accumulate_total_update_elapsed_us(&self, val: u64) {
56 self.total_update_elapsed_us
57 .fetch_add(val, Ordering::Relaxed);
58 }
59
60 fn accumulate_total_cache_lock_elapsed_us(&self, val: u64) {
61 self.total_cache_lock_elapsed_us
62 .fetch_add(val, Ordering::Relaxed);
63 }
64
65 fn accumulate_total_entry_lock_elapsed_us(&self, val: u64) {
66 self.total_entry_lock_elapsed_us
67 .fetch_add(val, Ordering::Relaxed);
68 }
69
70 fn accumulate_total_entry_update_elapsed_us(&self, val: u64) {
71 self.total_entry_update_elapsed_us
72 .fetch_add(val, Ordering::Relaxed);
73 }
74
75 fn accumulate_total_block_finalize_elapsed_us(&self, val: u64) {
76 self.total_block_finalize_elapsed_us
77 .fetch_add(val, Ordering::Relaxed);
78 }
79
80 fn report(&self, slot: Slot) {
81 datapoint_info!(
82 "block_prioritization_fee_counters",
83 ("slot", slot as i64, i64),
84 (
85 "successful_transaction_update_count",
86 self.successful_transaction_update_count
87 .swap(0, Ordering::Relaxed) as i64,
88 i64
89 ),
90 (
91 "total_update_elapsed_us",
92 self.total_update_elapsed_us.swap(0, Ordering::Relaxed) as i64,
93 i64
94 ),
95 (
96 "total_cache_lock_elapsed_us",
97 self.total_cache_lock_elapsed_us.swap(0, Ordering::Relaxed) as i64,
98 i64
99 ),
100 (
101 "total_entry_lock_elapsed_us",
102 self.total_entry_lock_elapsed_us.swap(0, Ordering::Relaxed) as i64,
103 i64
104 ),
105 (
106 "total_entry_update_elapsed_us",
107 self.total_entry_update_elapsed_us
108 .swap(0, Ordering::Relaxed) as i64,
109 i64
110 ),
111 (
112 "total_block_finalize_elapsed_us",
113 self.total_block_finalize_elapsed_us
114 .swap(0, Ordering::Relaxed) as i64,
115 i64
116 ),
117 );
118 }
119}
120
121enum CacheServiceUpdate {
122 TransactionUpdate {
123 slot: Slot,
124 transaction_fee: u64,
125 writable_accounts: Arc<Vec<Pubkey>>,
126 },
127 BankFrozen {
128 slot: Slot,
129 },
130 Exit,
131}
132
133pub struct PrioritizationFeeCache {
137 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
138 service_thread: Option<JoinHandle<()>>,
139 sender: Sender<CacheServiceUpdate>,
140 metrics: Arc<PrioritizationFeeCacheMetrics>,
141}
142
143impl Default for PrioritizationFeeCache {
144 fn default() -> Self {
145 Self::new(MAX_NUM_RECENT_BLOCKS)
146 }
147}
148
149impl Drop for PrioritizationFeeCache {
150 fn drop(&mut self) {
151 let _ = self.sender.send(CacheServiceUpdate::Exit);
152 self.service_thread
153 .take()
154 .unwrap()
155 .join()
156 .expect("Prioritization fee cache servicing thread failed to join");
157 }
158}
159
160impl PrioritizationFeeCache {
161 pub fn new(capacity: u64) -> Self {
162 let metrics = Arc::new(PrioritizationFeeCacheMetrics::default());
163 let (sender, receiver) = unbounded();
164 let cache = Arc::new(RwLock::new(LruCache::new(capacity as usize)));
165
166 let cache_clone = cache.clone();
167 let metrics_clone = metrics.clone();
168 let service_thread = Some(
169 Builder::new()
170 .name("prioritization-fee-cache-servicing-thread".to_string())
171 .spawn(move || {
172 Self::service_loop(cache_clone, receiver, metrics_clone);
173 })
174 .unwrap(),
175 );
176
177 PrioritizationFeeCache {
178 cache,
179 service_thread,
180 sender,
181 metrics,
182 }
183 }
184
185 fn get_prioritization_fee(
187 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
188 slot: &Slot,
189 ) -> Arc<Mutex<PrioritizationFee>> {
190 let mut cache = cache.write().unwrap();
191 match cache.get(slot) {
192 Some(entry) => Arc::clone(entry),
193 None => {
194 let entry = Arc::new(Mutex::new(PrioritizationFee::default()));
195 cache.put(*slot, Arc::clone(&entry));
196 entry
197 }
198 }
199 }
200
201 pub fn update<'a>(&self, bank: Arc<Bank>, txs: impl Iterator<Item = &'a SanitizedTransaction>) {
205 let mut successful_transaction_update_count: u64 = 0;
206 let (_, send_updates_time) = measure!(
207 {
208 for sanitized_transaction in txs {
209 if sanitized_transaction.is_simple_vote_transaction() {
212 continue;
213 }
214
215 let priority_details = sanitized_transaction.get_transaction_priority_details();
216 let account_locks = sanitized_transaction
217 .get_account_locks(bank.get_transaction_account_lock_limit());
218
219 if priority_details.is_none() || account_locks.is_err() {
220 continue;
221 }
222
223 let writable_accounts = Arc::new(
224 account_locks
225 .unwrap()
226 .writable
227 .iter()
228 .map(|key| **key)
229 .collect::<Vec<_>>(),
230 );
231
232 self.sender
233 .send(CacheServiceUpdate::TransactionUpdate {
234 slot: bank.slot(),
235 transaction_fee: priority_details.unwrap().priority,
236 writable_accounts,
237 })
238 .unwrap_or_else(|err| {
239 warn!(
240 "prioritization fee cache transaction updates failed: {:?}",
241 err
242 );
243 });
244 saturating_add_assign!(successful_transaction_update_count, 1)
245 }
246 },
247 "send_updates",
248 );
249
250 self.metrics
251 .accumulate_total_update_elapsed_us(send_updates_time.as_us());
252 self.metrics
253 .accumulate_successful_transaction_update_count(successful_transaction_update_count);
254 }
255
256 pub fn finalize_priority_fee(&self, slot: Slot) {
259 self.sender
260 .send(CacheServiceUpdate::BankFrozen { slot })
261 .unwrap_or_else(|err| {
262 warn!(
263 "prioritization fee cache signalling bank frozen failed: {:?}",
264 err
265 )
266 });
267 }
268
269 fn update_cache(
272 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
273 slot: &Slot,
274 transaction_fee: u64,
275 writable_accounts: Arc<Vec<Pubkey>>,
276 metrics: Arc<PrioritizationFeeCacheMetrics>,
277 ) {
278 let (block_prioritization_fee, cache_lock_time) =
279 measure!(Self::get_prioritization_fee(cache, slot), "cache_lock_time");
280
281 let (mut block_prioritization_fee, entry_lock_time) =
282 measure!(block_prioritization_fee.lock().unwrap(), "entry_lock_time");
283
284 let (_, entry_update_time) = measure!(
285 block_prioritization_fee.update(transaction_fee, &writable_accounts),
286 "entry_update_time"
287 );
288 metrics.accumulate_total_cache_lock_elapsed_us(cache_lock_time.as_us());
289 metrics.accumulate_total_entry_lock_elapsed_us(entry_lock_time.as_us());
290 metrics.accumulate_total_entry_update_elapsed_us(entry_update_time.as_us());
291 }
292
293 fn finalize_slot(
294 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
295 slot: &Slot,
296 metrics: Arc<PrioritizationFeeCacheMetrics>,
297 ) {
298 let (block_prioritization_fee, cache_lock_time) =
299 measure!(Self::get_prioritization_fee(cache, slot), "cache_lock_time");
300
301 let (mut block_prioritization_fee, entry_lock_time) =
302 measure!(block_prioritization_fee.lock().unwrap(), "entry_lock_time");
303
304 let (_, slot_finalize_time) = measure!(
308 block_prioritization_fee.mark_block_completed(),
309 "slot_finalize_time"
310 );
311 block_prioritization_fee.report_metrics(*slot);
312 metrics.accumulate_total_cache_lock_elapsed_us(cache_lock_time.as_us());
313 metrics.accumulate_total_entry_lock_elapsed_us(entry_lock_time.as_us());
314 metrics.accumulate_total_block_finalize_elapsed_us(slot_finalize_time.as_us());
315 }
316
317 fn service_loop(
318 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
319 receiver: Receiver<CacheServiceUpdate>,
320 metrics: Arc<PrioritizationFeeCacheMetrics>,
321 ) {
322 for update in receiver.iter() {
323 match update {
324 CacheServiceUpdate::TransactionUpdate {
325 slot,
326 transaction_fee,
327 writable_accounts,
328 } => Self::update_cache(
329 cache.clone(),
330 &slot,
331 transaction_fee,
332 writable_accounts,
333 metrics.clone(),
334 ),
335 CacheServiceUpdate::BankFrozen { slot } => {
336 Self::finalize_slot(cache.clone(), &slot, metrics.clone());
337
338 metrics.report(slot);
339 }
340 CacheServiceUpdate::Exit => {
341 break;
342 }
343 }
344 }
345 }
346
347 pub fn available_block_count(&self) -> usize {
349 self.cache
350 .read()
351 .unwrap()
352 .iter()
353 .filter(|(_slot, prioritization_fee)| prioritization_fee.lock().unwrap().is_finalized())
354 .count()
355 }
356
357 pub fn get_prioritization_fees(&self, account_keys: &[Pubkey]) -> HashMap<Slot, u64> {
358 self.cache
359 .read()
360 .unwrap()
361 .iter()
362 .filter_map(|(slot, prioritization_fee)| {
363 let prioritization_fee_read = prioritization_fee.lock().unwrap();
364 prioritization_fee_read.is_finalized().then(|| {
365 let mut fee = prioritization_fee_read
366 .get_min_transaction_fee()
367 .unwrap_or_default();
368 for account_key in account_keys {
369 if let Some(account_fee) =
370 prioritization_fee_read.get_writable_account_fee(account_key)
371 {
372 fee = std::cmp::max(fee, account_fee);
373 }
374 }
375 Some((*slot, fee))
376 })
377 })
378 .flatten()
379 .collect()
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use {
386 super::*,
387 crate::{
388 bank::Bank,
389 bank_forks::BankForks,
390 genesis_utils::{create_genesis_config, GenesisConfigInfo},
391 },
392 solana_sdk::{
393 compute_budget::ComputeBudgetInstruction,
394 message::Message,
395 pubkey::Pubkey,
396 system_instruction,
397 transaction::{SanitizedTransaction, Transaction},
398 },
399 };
400
401 fn build_sanitized_transaction_for_test(
402 compute_unit_price: u64,
403 signer_account: &Pubkey,
404 write_account: &Pubkey,
405 ) -> SanitizedTransaction {
406 let transaction = Transaction::new_unsigned(Message::new(
407 &[
408 system_instruction::transfer(signer_account, write_account, 1),
409 ComputeBudgetInstruction::set_compute_unit_price(compute_unit_price),
410 ],
411 Some(signer_account),
412 ));
413
414 SanitizedTransaction::try_from_legacy_transaction(transaction).unwrap()
415 }
416
417 fn sync_update<'a>(
419 prioritization_fee_cache: &mut PrioritizationFeeCache,
420 bank: Arc<Bank>,
421 txs: impl Iterator<Item = &'a SanitizedTransaction>,
422 ) {
423 prioritization_fee_cache.update(bank.clone(), txs);
424
425 let block_fee = PrioritizationFeeCache::get_prioritization_fee(
426 prioritization_fee_cache.cache.clone(),
427 &bank.slot(),
428 );
429
430 while block_fee
432 .lock()
433 .unwrap()
434 .get_min_transaction_fee()
435 .is_none()
436 {
437 std::thread::sleep(std::time::Duration::from_millis(100));
438 }
439 }
440
441 fn sync_finalize_priority_fee_for_test(
443 prioritization_fee_cache: &mut PrioritizationFeeCache,
444 slot: Slot,
445 ) {
446 prioritization_fee_cache.finalize_priority_fee(slot);
447 let fee = PrioritizationFeeCache::get_prioritization_fee(
448 prioritization_fee_cache.cache.clone(),
449 &slot,
450 );
451
452 while !fee.lock().unwrap().is_finalized() {
454 std::thread::sleep(std::time::Duration::from_millis(100));
455 }
456 }
457
458 #[test]
459 fn test_prioritization_fee_cache_update() {
460 solana_logger::setup();
461 let write_account_a = Pubkey::new_unique();
462 let write_account_b = Pubkey::new_unique();
463 let write_account_c = Pubkey::new_unique();
464
465 let txs = vec![
475 build_sanitized_transaction_for_test(5, &write_account_a, &write_account_b),
476 build_sanitized_transaction_for_test(9, &write_account_b, &write_account_c),
477 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_c),
478 ];
479
480 let bank = Arc::new(Bank::default_for_tests());
481 let slot = bank.slot();
482
483 let mut prioritization_fee_cache = PrioritizationFeeCache::default();
484 sync_update(&mut prioritization_fee_cache, bank, txs.iter());
485
486 {
488 let fee = PrioritizationFeeCache::get_prioritization_fee(
489 prioritization_fee_cache.cache.clone(),
490 &slot,
491 );
492 let fee = fee.lock().unwrap();
493 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
494 assert_eq!(2, fee.get_writable_account_fee(&write_account_a).unwrap());
495 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
496 assert_eq!(2, fee.get_writable_account_fee(&write_account_c).unwrap());
497 assert!(fee
499 .get_writable_account_fee(&Pubkey::new_unique())
500 .is_none());
501 }
502
503 {
505 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, slot);
506 let fee = PrioritizationFeeCache::get_prioritization_fee(
507 prioritization_fee_cache.cache.clone(),
508 &slot,
509 );
510 let fee = fee.lock().unwrap();
511 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
512 assert!(fee.get_writable_account_fee(&write_account_a).is_none());
513 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
514 assert!(fee.get_writable_account_fee(&write_account_c).is_none());
515 }
516 }
517
518 #[test]
519 fn test_available_block_count() {
520 let prioritization_fee_cache = PrioritizationFeeCache::default();
521
522 assert!(PrioritizationFeeCache::get_prioritization_fee(
523 prioritization_fee_cache.cache.clone(),
524 &1
525 )
526 .lock()
527 .unwrap()
528 .mark_block_completed()
529 .is_ok());
530 assert!(PrioritizationFeeCache::get_prioritization_fee(
531 prioritization_fee_cache.cache.clone(),
532 &2
533 )
534 .lock()
535 .unwrap()
536 .mark_block_completed()
537 .is_ok());
538 PrioritizationFeeCache::get_prioritization_fee(prioritization_fee_cache.cache.clone(), &3);
540
541 assert_eq!(2, prioritization_fee_cache.available_block_count());
543 }
544
545 fn hashmap_of(vec: Vec<(Slot, u64)>) -> HashMap<Slot, u64> {
546 vec.into_iter().collect()
547 }
548
549 #[test]
550 fn test_get_prioritization_fees() {
551 solana_logger::setup();
552 let write_account_a = Pubkey::new_unique();
553 let write_account_b = Pubkey::new_unique();
554 let write_account_c = Pubkey::new_unique();
555
556 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
557 let bank0 = Bank::new_for_benches(&genesis_config);
558 let bank_forks = BankForks::new(bank0);
559 let bank = bank_forks.working_bank();
560 let collector = solana_sdk::pubkey::new_rand();
561 let bank1 = Arc::new(Bank::new_from_parent(&bank, &collector, 1));
562 let bank2 = Arc::new(Bank::new_from_parent(&bank, &collector, 2));
563 let bank3 = Arc::new(Bank::new_from_parent(&bank, &collector, 3));
564
565 let mut prioritization_fee_cache = PrioritizationFeeCache::default();
566
567 assert!(prioritization_fee_cache
569 .get_prioritization_fees(&[])
570 .is_empty());
571 assert!(prioritization_fee_cache
572 .get_prioritization_fees(&[write_account_a])
573 .is_empty());
574 assert!(prioritization_fee_cache
575 .get_prioritization_fees(&[write_account_b])
576 .is_empty());
577 assert!(prioritization_fee_cache
578 .get_prioritization_fees(&[write_account_c])
579 .is_empty());
580 assert!(prioritization_fee_cache
581 .get_prioritization_fees(&[write_account_a, write_account_b])
582 .is_empty());
583 assert!(prioritization_fee_cache
584 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
585 .is_empty());
586
587 {
589 let txs = vec![
590 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
591 build_sanitized_transaction_for_test(
592 1,
593 &Pubkey::new_unique(),
594 &Pubkey::new_unique(),
595 ),
596 ];
597 sync_update(&mut prioritization_fee_cache, bank1, txs.iter());
598 assert!(prioritization_fee_cache
600 .get_prioritization_fees(&[])
601 .is_empty());
602 assert!(prioritization_fee_cache
603 .get_prioritization_fees(&[write_account_a])
604 .is_empty());
605 assert!(prioritization_fee_cache
606 .get_prioritization_fees(&[write_account_b])
607 .is_empty());
608 assert!(prioritization_fee_cache
609 .get_prioritization_fees(&[write_account_c])
610 .is_empty());
611 assert!(prioritization_fee_cache
612 .get_prioritization_fees(&[write_account_a, write_account_b])
613 .is_empty());
614 assert!(prioritization_fee_cache
615 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
616 .is_empty());
617 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 1);
619 assert_eq!(
620 hashmap_of(vec![(1, 1)]),
621 prioritization_fee_cache.get_prioritization_fees(&[])
622 );
623 assert_eq!(
624 hashmap_of(vec![(1, 2)]),
625 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
626 );
627 assert_eq!(
628 hashmap_of(vec![(1, 2)]),
629 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
630 );
631 assert_eq!(
632 hashmap_of(vec![(1, 1)]),
633 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
634 );
635 assert_eq!(
636 hashmap_of(vec![(1, 2)]),
637 prioritization_fee_cache
638 .get_prioritization_fees(&[write_account_a, write_account_b])
639 );
640 assert_eq!(
641 hashmap_of(vec![(1, 2)]),
642 prioritization_fee_cache.get_prioritization_fees(&[
643 write_account_a,
644 write_account_b,
645 write_account_c
646 ])
647 );
648 }
649
650 {
652 let txs = vec![
653 build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c),
654 build_sanitized_transaction_for_test(
655 3,
656 &Pubkey::new_unique(),
657 &Pubkey::new_unique(),
658 ),
659 ];
660 sync_update(&mut prioritization_fee_cache, bank2, txs.iter());
661 assert_eq!(
663 hashmap_of(vec![(1, 1)]),
664 prioritization_fee_cache.get_prioritization_fees(&[])
665 );
666 assert_eq!(
667 hashmap_of(vec![(1, 2)]),
668 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
669 );
670 assert_eq!(
671 hashmap_of(vec![(1, 2)]),
672 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
673 );
674 assert_eq!(
675 hashmap_of(vec![(1, 1)]),
676 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
677 );
678 assert_eq!(
679 hashmap_of(vec![(1, 2)]),
680 prioritization_fee_cache
681 .get_prioritization_fees(&[write_account_a, write_account_b])
682 );
683 assert_eq!(
684 hashmap_of(vec![(1, 2)]),
685 prioritization_fee_cache.get_prioritization_fees(&[
686 write_account_a,
687 write_account_b,
688 write_account_c
689 ])
690 );
691 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 2);
693 assert_eq!(
694 hashmap_of(vec![(2, 3), (1, 1)]),
695 prioritization_fee_cache.get_prioritization_fees(&[]),
696 );
697 assert_eq!(
698 hashmap_of(vec![(2, 3), (1, 2)]),
699 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
700 );
701 assert_eq!(
702 hashmap_of(vec![(2, 4), (1, 2)]),
703 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
704 );
705 assert_eq!(
706 hashmap_of(vec![(2, 4), (1, 1)]),
707 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
708 );
709 assert_eq!(
710 hashmap_of(vec![(2, 4), (1, 2)]),
711 prioritization_fee_cache
712 .get_prioritization_fees(&[write_account_a, write_account_b]),
713 );
714 assert_eq!(
715 hashmap_of(vec![(2, 4), (1, 2)]),
716 prioritization_fee_cache.get_prioritization_fees(&[
717 write_account_a,
718 write_account_b,
719 write_account_c,
720 ]),
721 );
722 }
723
724 {
726 let txs = vec![
727 build_sanitized_transaction_for_test(6, &write_account_a, &write_account_c),
728 build_sanitized_transaction_for_test(
729 5,
730 &Pubkey::new_unique(),
731 &Pubkey::new_unique(),
732 ),
733 ];
734 sync_update(&mut prioritization_fee_cache, bank3, txs.iter());
735 assert_eq!(
737 hashmap_of(vec![(2, 3), (1, 1)]),
738 prioritization_fee_cache.get_prioritization_fees(&[]),
739 );
740 assert_eq!(
741 hashmap_of(vec![(2, 3), (1, 2)]),
742 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
743 );
744 assert_eq!(
745 hashmap_of(vec![(2, 4), (1, 2)]),
746 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
747 );
748 assert_eq!(
749 hashmap_of(vec![(2, 4), (1, 1)]),
750 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
751 );
752 assert_eq!(
753 hashmap_of(vec![(2, 4), (1, 2)]),
754 prioritization_fee_cache
755 .get_prioritization_fees(&[write_account_a, write_account_b]),
756 );
757 assert_eq!(
758 hashmap_of(vec![(2, 4), (1, 2)]),
759 prioritization_fee_cache.get_prioritization_fees(&[
760 write_account_a,
761 write_account_b,
762 write_account_c,
763 ]),
764 );
765 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 3);
767 assert_eq!(
768 hashmap_of(vec![(3, 5), (2, 3), (1, 1)]),
769 prioritization_fee_cache.get_prioritization_fees(&[]),
770 );
771 assert_eq!(
772 hashmap_of(vec![(3, 6), (2, 3), (1, 2)]),
773 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
774 );
775 assert_eq!(
776 hashmap_of(vec![(3, 5), (2, 4), (1, 2)]),
777 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
778 );
779 assert_eq!(
780 hashmap_of(vec![(3, 6), (2, 4), (1, 1)]),
781 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
782 );
783 assert_eq!(
784 hashmap_of(vec![(3, 6), (2, 4), (1, 2)]),
785 prioritization_fee_cache
786 .get_prioritization_fees(&[write_account_a, write_account_b]),
787 );
788 assert_eq!(
789 hashmap_of(vec![(3, 6), (2, 4), (1, 2)]),
790 prioritization_fee_cache.get_prioritization_fees(&[
791 write_account_a,
792 write_account_b,
793 write_account_c,
794 ]),
795 );
796 }
797 }
798}