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 safecoin_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 let priority_details = sanitized_transaction.get_transaction_priority_details();
210 let account_locks = sanitized_transaction
211 .get_account_locks(bank.get_transaction_account_lock_limit());
212
213 if priority_details.is_none() || account_locks.is_err() {
214 continue;
215 }
216 let priority_details = priority_details.unwrap();
217
218 if priority_details.compute_unit_limit == 0 {
221 continue;
222 }
223
224 let writable_accounts = Arc::new(
225 account_locks
226 .unwrap()
227 .writable
228 .iter()
229 .map(|key| **key)
230 .collect::<Vec<_>>(),
231 );
232
233 self.sender
234 .send(CacheServiceUpdate::TransactionUpdate {
235 slot: bank.slot(),
236 transaction_fee: priority_details.priority,
237 writable_accounts,
238 })
239 .unwrap_or_else(|err| {
240 warn!(
241 "prioritization fee cache transaction updates failed: {:?}",
242 err
243 );
244 });
245 saturating_add_assign!(successful_transaction_update_count, 1)
246 }
247 },
248 "send_updates",
249 );
250
251 self.metrics
252 .accumulate_total_update_elapsed_us(send_updates_time.as_us());
253 self.metrics
254 .accumulate_successful_transaction_update_count(successful_transaction_update_count);
255 }
256
257 pub fn finalize_priority_fee(&self, slot: Slot) {
260 self.sender
261 .send(CacheServiceUpdate::BankFrozen { slot })
262 .unwrap_or_else(|err| {
263 warn!(
264 "prioritization fee cache signalling bank frozen failed: {:?}",
265 err
266 )
267 });
268 }
269
270 fn update_cache(
273 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
274 slot: &Slot,
275 transaction_fee: u64,
276 writable_accounts: Arc<Vec<Pubkey>>,
277 metrics: Arc<PrioritizationFeeCacheMetrics>,
278 ) {
279 let (block_prioritization_fee, cache_lock_time) =
280 measure!(Self::get_prioritization_fee(cache, slot), "cache_lock_time");
281
282 let (mut block_prioritization_fee, entry_lock_time) =
283 measure!(block_prioritization_fee.lock().unwrap(), "entry_lock_time");
284
285 let (_, entry_update_time) = measure!(
286 block_prioritization_fee.update(transaction_fee, &writable_accounts),
287 "entry_update_time"
288 );
289 metrics.accumulate_total_cache_lock_elapsed_us(cache_lock_time.as_us());
290 metrics.accumulate_total_entry_lock_elapsed_us(entry_lock_time.as_us());
291 metrics.accumulate_total_entry_update_elapsed_us(entry_update_time.as_us());
292 }
293
294 fn finalize_slot(
295 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
296 slot: &Slot,
297 metrics: Arc<PrioritizationFeeCacheMetrics>,
298 ) {
299 let (block_prioritization_fee, cache_lock_time) =
300 measure!(Self::get_prioritization_fee(cache, slot), "cache_lock_time");
301
302 let (mut block_prioritization_fee, entry_lock_time) =
303 measure!(block_prioritization_fee.lock().unwrap(), "entry_lock_time");
304
305 let (_, slot_finalize_time) = measure!(
309 block_prioritization_fee.mark_block_completed(),
310 "slot_finalize_time"
311 );
312 block_prioritization_fee.report_metrics(*slot);
313 metrics.accumulate_total_cache_lock_elapsed_us(cache_lock_time.as_us());
314 metrics.accumulate_total_entry_lock_elapsed_us(entry_lock_time.as_us());
315 metrics.accumulate_total_block_finalize_elapsed_us(slot_finalize_time.as_us());
316 }
317
318 fn service_loop(
319 cache: Arc<RwLock<LruCache<Slot, Arc<Mutex<PrioritizationFee>>>>>,
320 receiver: Receiver<CacheServiceUpdate>,
321 metrics: Arc<PrioritizationFeeCacheMetrics>,
322 ) {
323 for update in receiver.iter() {
324 match update {
325 CacheServiceUpdate::TransactionUpdate {
326 slot,
327 transaction_fee,
328 writable_accounts,
329 } => Self::update_cache(
330 cache.clone(),
331 &slot,
332 transaction_fee,
333 writable_accounts,
334 metrics.clone(),
335 ),
336 CacheServiceUpdate::BankFrozen { slot } => {
337 Self::finalize_slot(cache.clone(), &slot, metrics.clone());
338
339 metrics.report(slot);
340 }
341 CacheServiceUpdate::Exit => {
342 break;
343 }
344 }
345 }
346 }
347
348 pub fn available_block_count(&self) -> usize {
350 self.cache
351 .read()
352 .unwrap()
353 .iter()
354 .filter(|(_slot, prioritization_fee)| prioritization_fee.lock().unwrap().is_finalized())
355 .count()
356 }
357
358 pub fn get_prioritization_fees(&self, account_keys: &[Pubkey]) -> HashMap<Slot, u64> {
359 self.cache
360 .read()
361 .unwrap()
362 .iter()
363 .filter_map(|(slot, prioritization_fee)| {
364 let prioritization_fee_read = prioritization_fee.lock().unwrap();
365 prioritization_fee_read.is_finalized().then(|| {
366 let mut fee = prioritization_fee_read
367 .get_min_transaction_fee()
368 .unwrap_or_default();
369 for account_key in account_keys {
370 if let Some(account_fee) =
371 prioritization_fee_read.get_writable_account_fee(account_key)
372 {
373 fee = std::cmp::max(fee, account_fee);
374 }
375 }
376 Some((*slot, fee))
377 })
378 })
379 .flatten()
380 .collect()
381 }
382}
383
384#[cfg(test)]
385mod tests {
386 use {
387 super::*,
388 crate::{
389 bank::Bank,
390 bank_forks::BankForks,
391 genesis_utils::{create_genesis_config, GenesisConfigInfo},
392 },
393 solana_sdk::{
394 compute_budget::ComputeBudgetInstruction,
395 message::Message,
396 pubkey::Pubkey,
397 system_instruction,
398 transaction::{SanitizedTransaction, Transaction},
399 },
400 };
401
402 fn build_sanitized_transaction_for_test(
403 compute_unit_price: u64,
404 signer_account: &Pubkey,
405 write_account: &Pubkey,
406 ) -> SanitizedTransaction {
407 let transaction = Transaction::new_unsigned(Message::new(
408 &[
409 system_instruction::transfer(signer_account, write_account, 1),
410 ComputeBudgetInstruction::set_compute_unit_price(compute_unit_price),
411 ],
412 Some(signer_account),
413 ));
414
415 SanitizedTransaction::try_from_legacy_transaction(transaction).unwrap()
416 }
417
418 fn sync_update<'a>(
420 prioritization_fee_cache: &mut PrioritizationFeeCache,
421 bank: Arc<Bank>,
422 txs: impl Iterator<Item = &'a SanitizedTransaction>,
423 ) {
424 prioritization_fee_cache.update(bank.clone(), txs);
425
426 let block_fee = PrioritizationFeeCache::get_prioritization_fee(
427 prioritization_fee_cache.cache.clone(),
428 &bank.slot(),
429 );
430
431 while block_fee
433 .lock()
434 .unwrap()
435 .get_min_transaction_fee()
436 .is_none()
437 {
438 std::thread::sleep(std::time::Duration::from_millis(100));
439 }
440 }
441
442 fn sync_finalize_priority_fee_for_test(
444 prioritization_fee_cache: &mut PrioritizationFeeCache,
445 slot: Slot,
446 ) {
447 prioritization_fee_cache.finalize_priority_fee(slot);
448 let fee = PrioritizationFeeCache::get_prioritization_fee(
449 prioritization_fee_cache.cache.clone(),
450 &slot,
451 );
452
453 while !fee.lock().unwrap().is_finalized() {
455 std::thread::sleep(std::time::Duration::from_millis(100));
456 }
457 }
458
459 #[test]
460 fn test_prioritization_fee_cache_update() {
461 solana_logger::setup();
462 let write_account_a = Pubkey::new_unique();
463 let write_account_b = Pubkey::new_unique();
464 let write_account_c = Pubkey::new_unique();
465
466 let txs = vec![
476 build_sanitized_transaction_for_test(5, &write_account_a, &write_account_b),
477 build_sanitized_transaction_for_test(9, &write_account_b, &write_account_c),
478 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_c),
479 ];
480
481 let bank = Arc::new(Bank::default_for_tests());
482 let slot = bank.slot();
483
484 let mut prioritization_fee_cache = PrioritizationFeeCache::default();
485 sync_update(&mut prioritization_fee_cache, bank, txs.iter());
486
487 {
489 let fee = PrioritizationFeeCache::get_prioritization_fee(
490 prioritization_fee_cache.cache.clone(),
491 &slot,
492 );
493 let fee = fee.lock().unwrap();
494 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
495 assert_eq!(2, fee.get_writable_account_fee(&write_account_a).unwrap());
496 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
497 assert_eq!(2, fee.get_writable_account_fee(&write_account_c).unwrap());
498 assert!(fee
500 .get_writable_account_fee(&Pubkey::new_unique())
501 .is_none());
502 }
503
504 {
506 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, slot);
507 let fee = PrioritizationFeeCache::get_prioritization_fee(
508 prioritization_fee_cache.cache.clone(),
509 &slot,
510 );
511 let fee = fee.lock().unwrap();
512 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
513 assert!(fee.get_writable_account_fee(&write_account_a).is_none());
514 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
515 assert!(fee.get_writable_account_fee(&write_account_c).is_none());
516 }
517 }
518
519 #[test]
520 fn test_available_block_count() {
521 let prioritization_fee_cache = PrioritizationFeeCache::default();
522
523 assert!(PrioritizationFeeCache::get_prioritization_fee(
524 prioritization_fee_cache.cache.clone(),
525 &1
526 )
527 .lock()
528 .unwrap()
529 .mark_block_completed()
530 .is_ok());
531 assert!(PrioritizationFeeCache::get_prioritization_fee(
532 prioritization_fee_cache.cache.clone(),
533 &2
534 )
535 .lock()
536 .unwrap()
537 .mark_block_completed()
538 .is_ok());
539 PrioritizationFeeCache::get_prioritization_fee(prioritization_fee_cache.cache.clone(), &3);
541
542 assert_eq!(2, prioritization_fee_cache.available_block_count());
544 }
545
546 fn hashmap_of(vec: Vec<(Slot, u64)>) -> HashMap<Slot, u64> {
547 vec.into_iter().collect()
548 }
549
550 #[test]
551 fn test_get_prioritization_fees() {
552 solana_logger::setup();
553 let write_account_a = Pubkey::new_unique();
554 let write_account_b = Pubkey::new_unique();
555 let write_account_c = Pubkey::new_unique();
556
557 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
558 let bank0 = Bank::new_for_benches(&genesis_config);
559 let bank_forks = BankForks::new(bank0);
560 let bank = bank_forks.working_bank();
561 let collector = solana_sdk::pubkey::new_rand();
562 let bank1 = Arc::new(Bank::new_from_parent(&bank, &collector, 1));
563 let bank2 = Arc::new(Bank::new_from_parent(&bank, &collector, 2));
564 let bank3 = Arc::new(Bank::new_from_parent(&bank, &collector, 3));
565
566 let mut prioritization_fee_cache = PrioritizationFeeCache::default();
567
568 assert!(prioritization_fee_cache
570 .get_prioritization_fees(&[])
571 .is_empty());
572 assert!(prioritization_fee_cache
573 .get_prioritization_fees(&[write_account_a])
574 .is_empty());
575 assert!(prioritization_fee_cache
576 .get_prioritization_fees(&[write_account_b])
577 .is_empty());
578 assert!(prioritization_fee_cache
579 .get_prioritization_fees(&[write_account_c])
580 .is_empty());
581 assert!(prioritization_fee_cache
582 .get_prioritization_fees(&[write_account_a, write_account_b])
583 .is_empty());
584 assert!(prioritization_fee_cache
585 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
586 .is_empty());
587
588 {
590 let txs = vec![
591 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
592 build_sanitized_transaction_for_test(
593 1,
594 &Pubkey::new_unique(),
595 &Pubkey::new_unique(),
596 ),
597 ];
598 sync_update(&mut prioritization_fee_cache, bank1, txs.iter());
599 assert!(prioritization_fee_cache
601 .get_prioritization_fees(&[])
602 .is_empty());
603 assert!(prioritization_fee_cache
604 .get_prioritization_fees(&[write_account_a])
605 .is_empty());
606 assert!(prioritization_fee_cache
607 .get_prioritization_fees(&[write_account_b])
608 .is_empty());
609 assert!(prioritization_fee_cache
610 .get_prioritization_fees(&[write_account_c])
611 .is_empty());
612 assert!(prioritization_fee_cache
613 .get_prioritization_fees(&[write_account_a, write_account_b])
614 .is_empty());
615 assert!(prioritization_fee_cache
616 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
617 .is_empty());
618 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 1);
620 assert_eq!(
621 hashmap_of(vec![(1, 1)]),
622 prioritization_fee_cache.get_prioritization_fees(&[])
623 );
624 assert_eq!(
625 hashmap_of(vec![(1, 2)]),
626 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
627 );
628 assert_eq!(
629 hashmap_of(vec![(1, 2)]),
630 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
631 );
632 assert_eq!(
633 hashmap_of(vec![(1, 1)]),
634 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
635 );
636 assert_eq!(
637 hashmap_of(vec![(1, 2)]),
638 prioritization_fee_cache
639 .get_prioritization_fees(&[write_account_a, write_account_b])
640 );
641 assert_eq!(
642 hashmap_of(vec![(1, 2)]),
643 prioritization_fee_cache.get_prioritization_fees(&[
644 write_account_a,
645 write_account_b,
646 write_account_c
647 ])
648 );
649 }
650
651 {
653 let txs = vec![
654 build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c),
655 build_sanitized_transaction_for_test(
656 3,
657 &Pubkey::new_unique(),
658 &Pubkey::new_unique(),
659 ),
660 ];
661 sync_update(&mut prioritization_fee_cache, bank2, txs.iter());
662 assert_eq!(
664 hashmap_of(vec![(1, 1)]),
665 prioritization_fee_cache.get_prioritization_fees(&[])
666 );
667 assert_eq!(
668 hashmap_of(vec![(1, 2)]),
669 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
670 );
671 assert_eq!(
672 hashmap_of(vec![(1, 2)]),
673 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
674 );
675 assert_eq!(
676 hashmap_of(vec![(1, 1)]),
677 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
678 );
679 assert_eq!(
680 hashmap_of(vec![(1, 2)]),
681 prioritization_fee_cache
682 .get_prioritization_fees(&[write_account_a, write_account_b])
683 );
684 assert_eq!(
685 hashmap_of(vec![(1, 2)]),
686 prioritization_fee_cache.get_prioritization_fees(&[
687 write_account_a,
688 write_account_b,
689 write_account_c
690 ])
691 );
692 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 2);
694 assert_eq!(
695 hashmap_of(vec![(2, 3), (1, 1)]),
696 prioritization_fee_cache.get_prioritization_fees(&[]),
697 );
698 assert_eq!(
699 hashmap_of(vec![(2, 3), (1, 2)]),
700 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
701 );
702 assert_eq!(
703 hashmap_of(vec![(2, 4), (1, 2)]),
704 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
705 );
706 assert_eq!(
707 hashmap_of(vec![(2, 4), (1, 1)]),
708 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
709 );
710 assert_eq!(
711 hashmap_of(vec![(2, 4), (1, 2)]),
712 prioritization_fee_cache
713 .get_prioritization_fees(&[write_account_a, write_account_b]),
714 );
715 assert_eq!(
716 hashmap_of(vec![(2, 4), (1, 2)]),
717 prioritization_fee_cache.get_prioritization_fees(&[
718 write_account_a,
719 write_account_b,
720 write_account_c,
721 ]),
722 );
723 }
724
725 {
727 let txs = vec![
728 build_sanitized_transaction_for_test(6, &write_account_a, &write_account_c),
729 build_sanitized_transaction_for_test(
730 5,
731 &Pubkey::new_unique(),
732 &Pubkey::new_unique(),
733 ),
734 ];
735 sync_update(&mut prioritization_fee_cache, bank3, txs.iter());
736 assert_eq!(
738 hashmap_of(vec![(2, 3), (1, 1)]),
739 prioritization_fee_cache.get_prioritization_fees(&[]),
740 );
741 assert_eq!(
742 hashmap_of(vec![(2, 3), (1, 2)]),
743 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
744 );
745 assert_eq!(
746 hashmap_of(vec![(2, 4), (1, 2)]),
747 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
748 );
749 assert_eq!(
750 hashmap_of(vec![(2, 4), (1, 1)]),
751 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
752 );
753 assert_eq!(
754 hashmap_of(vec![(2, 4), (1, 2)]),
755 prioritization_fee_cache
756 .get_prioritization_fees(&[write_account_a, write_account_b]),
757 );
758 assert_eq!(
759 hashmap_of(vec![(2, 4), (1, 2)]),
760 prioritization_fee_cache.get_prioritization_fees(&[
761 write_account_a,
762 write_account_b,
763 write_account_c,
764 ]),
765 );
766 sync_finalize_priority_fee_for_test(&mut prioritization_fee_cache, 3);
768 assert_eq!(
769 hashmap_of(vec![(3, 5), (2, 3), (1, 1)]),
770 prioritization_fee_cache.get_prioritization_fees(&[]),
771 );
772 assert_eq!(
773 hashmap_of(vec![(3, 6), (2, 3), (1, 2)]),
774 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
775 );
776 assert_eq!(
777 hashmap_of(vec![(3, 5), (2, 4), (1, 2)]),
778 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
779 );
780 assert_eq!(
781 hashmap_of(vec![(3, 6), (2, 4), (1, 1)]),
782 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
783 );
784 assert_eq!(
785 hashmap_of(vec![(3, 6), (2, 4), (1, 2)]),
786 prioritization_fee_cache
787 .get_prioritization_fees(&[write_account_a, write_account_b]),
788 );
789 assert_eq!(
790 hashmap_of(vec![(3, 6), (2, 4), (1, 2)]),
791 prioritization_fee_cache.get_prioritization_fees(&[
792 write_account_a,
793 write_account_b,
794 write_account_c,
795 ]),
796 );
797 }
798 }
799}