1use {
2 crate::{bank::Bank, prioritization_fee::*},
3 crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError},
4 log::*,
5 solana_accounts_db::account_locks::validate_account_locks,
6 solana_clock::{BankId, Slot},
7 solana_measure::measure_us,
8 solana_pubkey::Pubkey,
9 solana_runtime_transaction::transaction_with_meta::TransactionWithMeta,
10 std::{
11 collections::{BTreeMap, HashMap},
12 sync::{
13 atomic::{AtomicU64, Ordering},
14 Arc, RwLock,
15 },
16 thread::{sleep, Builder, JoinHandle},
17 time::Duration,
18 },
19};
20
21const MAX_NUM_RECENT_BLOCKS: u64 = 150;
25
26const MAX_UNFINALIZED_SLOTS: u64 = 128;
28
29type UnfinalizedPrioritizationFees = BTreeMap<Slot, HashMap<BankId, PrioritizationFee>>;
30
31#[derive(Debug, Default)]
32struct PrioritizationFeeCacheMetrics {
33 successful_transaction_update_count: AtomicU64,
35
36 purged_duplicated_bank_count: AtomicU64,
38
39 total_update_elapsed_us: AtomicU64,
41
42 total_cache_lock_elapsed_us: AtomicU64,
44
45 total_entry_update_elapsed_us: AtomicU64,
47
48 total_block_finalize_elapsed_us: AtomicU64,
50}
51
52impl PrioritizationFeeCacheMetrics {
53 fn accumulate_successful_transaction_update_count(&self, val: u64) {
54 self.successful_transaction_update_count
55 .fetch_add(val, Ordering::Relaxed);
56 }
57
58 fn accumulate_total_purged_duplicated_bank_count(&self, val: u64) {
59 self.purged_duplicated_bank_count
60 .fetch_add(val, Ordering::Relaxed);
61 }
62
63 fn accumulate_total_update_elapsed_us(&self, val: u64) {
64 self.total_update_elapsed_us
65 .fetch_add(val, Ordering::Relaxed);
66 }
67
68 fn accumulate_total_cache_lock_elapsed_us(&self, val: u64) {
69 self.total_cache_lock_elapsed_us
70 .fetch_add(val, Ordering::Relaxed);
71 }
72
73 fn accumulate_total_entry_update_elapsed_us(&self, val: u64) {
74 self.total_entry_update_elapsed_us
75 .fetch_add(val, Ordering::Relaxed);
76 }
77
78 fn accumulate_total_block_finalize_elapsed_us(&self, val: u64) {
79 self.total_block_finalize_elapsed_us
80 .fetch_add(val, Ordering::Relaxed);
81 }
82
83 fn report(&self, slot: Slot) {
84 datapoint_info!(
85 "block_prioritization_fee_counters",
86 ("slot", slot as i64, i64),
87 (
88 "successful_transaction_update_count",
89 self.successful_transaction_update_count
90 .swap(0, Ordering::Relaxed) as i64,
91 i64
92 ),
93 (
94 "purged_duplicated_bank_count",
95 self.purged_duplicated_bank_count.swap(0, Ordering::Relaxed) as i64,
96 i64
97 ),
98 (
99 "total_update_elapsed_us",
100 self.total_update_elapsed_us.swap(0, Ordering::Relaxed) as i64,
101 i64
102 ),
103 (
104 "total_cache_lock_elapsed_us",
105 self.total_cache_lock_elapsed_us.swap(0, Ordering::Relaxed) as i64,
106 i64
107 ),
108 (
109 "total_entry_update_elapsed_us",
110 self.total_entry_update_elapsed_us
111 .swap(0, Ordering::Relaxed) as i64,
112 i64
113 ),
114 (
115 "total_block_finalize_elapsed_us",
116 self.total_block_finalize_elapsed_us
117 .swap(0, Ordering::Relaxed) as i64,
118 i64
119 ),
120 );
121 }
122}
123
124#[derive(Debug)]
125enum CacheServiceUpdate {
126 TransactionUpdate {
127 slot: Slot,
128 bank_id: BankId,
129 transaction_fee: u64,
130 writable_accounts: Vec<Pubkey>,
131 },
132 BankFinalized {
133 slot: Slot,
134 bank_id: BankId,
135 },
136 Exit,
137}
138
139#[derive(Debug)]
143pub struct PrioritizationFeeCache {
144 cache: Arc<RwLock<BTreeMap<Slot, PrioritizationFee>>>,
145 service_thread: Option<JoinHandle<()>>,
146 sender: Sender<CacheServiceUpdate>,
147 metrics: Arc<PrioritizationFeeCacheMetrics>,
148}
149
150impl Default for PrioritizationFeeCache {
151 fn default() -> Self {
152 Self::new(MAX_NUM_RECENT_BLOCKS)
153 }
154}
155
156impl Drop for PrioritizationFeeCache {
157 fn drop(&mut self) {
158 let _ = self.sender.send(CacheServiceUpdate::Exit);
159 self.service_thread
160 .take()
161 .unwrap()
162 .join()
163 .expect("Prioritization fee cache servicing thread failed to join");
164 }
165}
166
167impl PrioritizationFeeCache {
168 pub fn new(capacity: u64) -> Self {
169 let cache = Arc::new(RwLock::new(BTreeMap::new()));
170 let (sender, receiver) = unbounded();
171 let metrics = Arc::new(PrioritizationFeeCacheMetrics::default());
172
173 let service_thread = Some(
174 Builder::new()
175 .name("solPrFeeCachSvc".to_string())
176 .spawn({
177 let cache = cache.clone();
178 let metrics = metrics.clone();
179 move || Self::service_loop(cache, capacity as usize, receiver, metrics)
180 })
181 .unwrap(),
182 );
183
184 PrioritizationFeeCache {
185 cache,
186 service_thread,
187 sender,
188 metrics,
189 }
190 }
191
192 pub fn update<'a, Tx: TransactionWithMeta + 'a>(
196 &self,
197 bank: &Bank,
198 txs: impl Iterator<Item = &'a Tx>,
199 ) {
200 let (_, send_updates_us) = measure_us!({
201 for sanitized_transaction in txs {
202 if sanitized_transaction.is_simple_vote_transaction() {
205 continue;
206 }
207
208 let compute_budget_limits = sanitized_transaction
209 .compute_budget_instruction_details()
210 .sanitize_and_convert_to_compute_budget_limits(&bank.feature_set);
211
212 let lock_result = validate_account_locks(
213 sanitized_transaction.account_keys(),
214 bank.get_transaction_account_lock_limit(),
215 );
216
217 if compute_budget_limits.is_err() || lock_result.is_err() {
218 continue;
219 }
220 let compute_budget_limits = compute_budget_limits.unwrap();
221
222 if compute_budget_limits.compute_unit_limit == 0 {
225 continue;
226 }
227
228 let writable_accounts = sanitized_transaction
229 .account_keys()
230 .iter()
231 .enumerate()
232 .filter(|(index, _)| sanitized_transaction.is_writable(*index))
233 .map(|(_, key)| *key)
234 .collect();
235
236 self.sender
237 .send(CacheServiceUpdate::TransactionUpdate {
238 slot: bank.slot(),
239 bank_id: bank.bank_id(),
240 transaction_fee: compute_budget_limits.compute_unit_price,
241 writable_accounts,
242 })
243 .unwrap_or_else(|err| {
244 warn!(
245 "prioritization fee cache transaction updates failed: {:?}",
246 err
247 );
248 });
249 }
250 });
251
252 self.metrics
253 .accumulate_total_update_elapsed_us(send_updates_us);
254 }
255
256 pub fn finalize_priority_fee(&self, slot: Slot, bank_id: BankId) {
259 self.sender
260 .send(CacheServiceUpdate::BankFinalized { slot, bank_id })
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(
271 unfinalized: &mut UnfinalizedPrioritizationFees,
272 slot: Slot,
273 bank_id: BankId,
274 transaction_fee: u64,
275 writable_accounts: Vec<Pubkey>,
276 metrics: &PrioritizationFeeCacheMetrics,
277 ) {
278 let (_, entry_update_us) = measure_us!(unfinalized
279 .entry(slot)
280 .or_default()
281 .entry(bank_id)
282 .or_default()
283 .update(transaction_fee, writable_accounts));
284 metrics.accumulate_total_entry_update_elapsed_us(entry_update_us);
285 metrics.accumulate_successful_transaction_update_count(1);
286 }
287
288 fn finalize_slot(
289 unfinalized: &mut UnfinalizedPrioritizationFees,
290 cache: &RwLock<BTreeMap<Slot, PrioritizationFee>>,
291 cache_max_size: usize,
292 slot: Slot,
293 bank_id: BankId,
294 metrics: &PrioritizationFeeCacheMetrics,
295 ) {
296 if unfinalized.is_empty() {
297 return;
298 }
299
300 let (slot_prioritization_fee, slot_finalize_us) = measure_us!({
304 *unfinalized =
306 unfinalized.split_off(&slot.checked_sub(MAX_UNFINALIZED_SLOTS).unwrap_or_default());
307
308 let Some(mut slot_prioritization_fee) = unfinalized.remove(&slot) else {
309 return;
310 };
311
312 let pre_purge_bank_count = slot_prioritization_fee.len() as u64;
314 let mut prioritization_fee = slot_prioritization_fee.remove(&bank_id);
315 let post_purge_bank_count = prioritization_fee.as_ref().map(|_| 1).unwrap_or(0);
316 metrics.accumulate_total_purged_duplicated_bank_count(
317 pre_purge_bank_count.saturating_sub(post_purge_bank_count),
318 );
319 if pre_purge_bank_count > 0 && post_purge_bank_count == 0 {
322 warn!("Finalized bank has empty prioritization fee cache. slot {slot} bank id {bank_id}");
323 }
324
325 if let Some(prioritization_fee) = &mut prioritization_fee {
326 if let Err(err) = prioritization_fee.mark_block_completed() {
327 error!(
328 "Unsuccessful finalizing slot {slot}, bank ID {bank_id}: {:?}",
329 err
330 );
331 }
332 prioritization_fee.report_metrics(slot);
333 }
334 prioritization_fee
335 });
336 metrics.accumulate_total_block_finalize_elapsed_us(slot_finalize_us);
337
338 if let Some(slot_prioritization_fee) = slot_prioritization_fee {
340 let (_, cache_lock_us) = measure_us!({
341 let mut cache = cache.write().unwrap();
342 while cache.len() >= cache_max_size {
343 cache.pop_first();
344 }
345 cache.insert(slot, slot_prioritization_fee);
346 });
347 metrics.accumulate_total_cache_lock_elapsed_us(cache_lock_us);
348 }
349 }
350
351 fn service_loop(
352 cache: Arc<RwLock<BTreeMap<Slot, PrioritizationFee>>>,
353 cache_max_size: usize,
354 receiver: Receiver<CacheServiceUpdate>,
355 metrics: Arc<PrioritizationFeeCacheMetrics>,
356 ) {
357 let mut unfinalized = UnfinalizedPrioritizationFees::new();
360
361 loop {
362 let update = match receiver.try_recv() {
363 Ok(update) => update,
364 Err(TryRecvError::Empty) => {
365 sleep(Duration::from_millis(5));
366 continue;
367 }
368 Err(err @ TryRecvError::Disconnected) => {
369 info!("PrioritizationFeeCache::service_loop() is stopping because: {err}");
370 break;
371 }
372 };
373 match update {
374 CacheServiceUpdate::TransactionUpdate {
375 slot,
376 bank_id,
377 transaction_fee,
378 writable_accounts,
379 } => Self::update_cache(
380 &mut unfinalized,
381 slot,
382 bank_id,
383 transaction_fee,
384 writable_accounts,
385 &metrics,
386 ),
387 CacheServiceUpdate::BankFinalized { slot, bank_id } => {
388 Self::finalize_slot(
389 &mut unfinalized,
390 &cache,
391 cache_max_size,
392 slot,
393 bank_id,
394 &metrics,
395 );
396 metrics.report(slot);
397 }
398 CacheServiceUpdate::Exit => {
399 break;
400 }
401 }
402 }
403 }
404
405 pub fn available_block_count(&self) -> usize {
407 self.cache.read().unwrap().len()
408 }
409
410 pub fn get_prioritization_fees(&self, account_keys: &[Pubkey]) -> Vec<(Slot, u64)> {
411 self.cache
412 .read()
413 .unwrap()
414 .iter()
415 .map(|(slot, slot_prioritization_fee)| {
416 let mut fee = slot_prioritization_fee
417 .get_min_transaction_fee()
418 .unwrap_or_default();
419 for account_key in account_keys {
420 if let Some(account_fee) =
421 slot_prioritization_fee.get_writable_account_fee(account_key)
422 {
423 fee = std::cmp::max(fee, account_fee);
424 }
425 }
426 (*slot, fee)
427 })
428 .collect()
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use {
435 super::*,
436 crate::{
437 bank::Bank,
438 bank_forks::BankForks,
439 genesis_utils::{create_genesis_config, GenesisConfigInfo},
440 },
441 solana_compute_budget_interface::ComputeBudgetInstruction,
442 solana_message::Message,
443 solana_pubkey::Pubkey,
444 solana_runtime_transaction::runtime_transaction::RuntimeTransaction,
445 solana_system_interface::instruction as system_instruction,
446 solana_transaction::{sanitized::SanitizedTransaction, Transaction},
447 };
448
449 fn build_sanitized_transaction_for_test(
450 compute_unit_price: u64,
451 signer_account: &Pubkey,
452 write_account: &Pubkey,
453 ) -> RuntimeTransaction<SanitizedTransaction> {
454 let transaction = Transaction::new_unsigned(Message::new(
455 &[
456 system_instruction::transfer(signer_account, write_account, 1),
457 ComputeBudgetInstruction::set_compute_unit_price(compute_unit_price),
458 ],
459 Some(signer_account),
460 ));
461
462 RuntimeTransaction::from_transaction_for_tests(transaction)
463 }
464
465 fn sync_update<'a>(
467 prioritization_fee_cache: &PrioritizationFeeCache,
468 bank: Arc<Bank>,
469 txs: impl ExactSizeIterator<Item = &'a RuntimeTransaction<SanitizedTransaction>>,
470 ) {
471 let expected_update_count = prioritization_fee_cache
472 .metrics
473 .successful_transaction_update_count
474 .load(Ordering::Relaxed)
475 .saturating_add(txs.len() as u64);
476
477 prioritization_fee_cache.update(&bank, txs);
478
479 while prioritization_fee_cache
481 .metrics
482 .successful_transaction_update_count
483 .load(Ordering::Relaxed)
484 != expected_update_count
485 {
486 std::thread::sleep(std::time::Duration::from_millis(10));
487 }
488 }
489
490 fn sync_finalize_priority_fee_for_test(
492 prioritization_fee_cache: &PrioritizationFeeCache,
493 slot: Slot,
494 bank_id: BankId,
495 ) {
496 prioritization_fee_cache.finalize_priority_fee(slot, bank_id);
498
499 loop {
501 let cache = prioritization_fee_cache.cache.read().unwrap();
502 if let Some(slot_cache) = cache.get(&slot) {
503 if slot_cache.is_finalized() {
504 return;
505 }
506 }
507 drop(cache);
508
509 std::thread::sleep(std::time::Duration::from_millis(10));
510 }
511 }
512
513 #[test]
514 fn test_prioritization_fee_cache_update() {
515 solana_logger::setup();
516 let write_account_a = Pubkey::new_unique();
517 let write_account_b = Pubkey::new_unique();
518 let write_account_c = Pubkey::new_unique();
519
520 let txs = vec![
530 build_sanitized_transaction_for_test(5, &write_account_a, &write_account_b),
531 build_sanitized_transaction_for_test(9, &write_account_b, &write_account_c),
532 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_c),
533 ];
534
535 let bank = Arc::new(Bank::default_for_tests());
536 let slot = bank.slot();
537
538 let prioritization_fee_cache = PrioritizationFeeCache::default();
539 sync_update(&prioritization_fee_cache, bank.clone(), txs.iter());
540
541 {
543 let lock = prioritization_fee_cache.cache.read().unwrap();
544 assert!(lock.get(&slot).is_none());
545 }
546
547 {
549 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, slot, bank.bank_id());
550 let lock = prioritization_fee_cache.cache.read().unwrap();
551 let fee = lock.get(&slot).unwrap();
552 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
553 assert!(fee.get_writable_account_fee(&write_account_a).is_none());
554 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
555 assert!(fee.get_writable_account_fee(&write_account_c).is_none());
556 }
557 }
558
559 #[test]
560 fn test_available_block_count() {
561 let prioritization_fee_cache = PrioritizationFeeCache::default();
562
563 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
564 let bank0 = Bank::new_for_benches(&genesis_config);
565 let bank_forks = BankForks::new_rw_arc(bank0);
566 let bank = bank_forks.read().unwrap().working_bank();
567 let collector = solana_pubkey::new_rand();
568
569 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 1));
570 sync_update(
571 &prioritization_fee_cache,
572 bank1.clone(),
573 vec![build_sanitized_transaction_for_test(
574 1,
575 &Pubkey::new_unique(),
576 &Pubkey::new_unique(),
577 )]
578 .iter(),
579 );
580 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 1, bank1.bank_id());
581
582 let bank2 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 2));
584 let txs = vec![build_sanitized_transaction_for_test(
585 1,
586 &Pubkey::new_unique(),
587 &Pubkey::new_unique(),
588 )];
589 sync_update(&prioritization_fee_cache, bank2.clone(), txs.iter());
590
591 let bank3 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 3));
592 sync_update(
593 &prioritization_fee_cache,
594 bank3.clone(),
595 vec![build_sanitized_transaction_for_test(
596 1,
597 &Pubkey::new_unique(),
598 &Pubkey::new_unique(),
599 )]
600 .iter(),
601 );
602 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 3, bank3.bank_id());
603
604 assert_eq!(2, prioritization_fee_cache.available_block_count());
606 }
607
608 #[test]
609 fn test_get_prioritization_fees() {
610 solana_logger::setup();
611 let write_account_a = Pubkey::new_unique();
612 let write_account_b = Pubkey::new_unique();
613 let write_account_c = Pubkey::new_unique();
614
615 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
616 let bank0 = Bank::new_for_benches(&genesis_config);
617 let bank_forks = BankForks::new_rw_arc(bank0);
618 let bank = bank_forks.read().unwrap().working_bank();
619 let collector = solana_pubkey::new_rand();
620 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 1));
621 let bank2 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 2));
622 let bank3 = Arc::new(Bank::new_from_parent(bank, &collector, 3));
623
624 let prioritization_fee_cache = PrioritizationFeeCache::default();
625
626 assert!(prioritization_fee_cache
628 .get_prioritization_fees(&[])
629 .is_empty());
630 assert!(prioritization_fee_cache
631 .get_prioritization_fees(&[write_account_a])
632 .is_empty());
633 assert!(prioritization_fee_cache
634 .get_prioritization_fees(&[write_account_b])
635 .is_empty());
636 assert!(prioritization_fee_cache
637 .get_prioritization_fees(&[write_account_c])
638 .is_empty());
639 assert!(prioritization_fee_cache
640 .get_prioritization_fees(&[write_account_a, write_account_b])
641 .is_empty());
642 assert!(prioritization_fee_cache
643 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
644 .is_empty());
645
646 {
648 let txs = vec![
649 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
650 build_sanitized_transaction_for_test(
651 1,
652 &Pubkey::new_unique(),
653 &Pubkey::new_unique(),
654 ),
655 ];
656 sync_update(&prioritization_fee_cache, bank1.clone(), txs.iter());
657 assert!(prioritization_fee_cache
659 .get_prioritization_fees(&[])
660 .is_empty());
661 assert!(prioritization_fee_cache
662 .get_prioritization_fees(&[write_account_a])
663 .is_empty());
664 assert!(prioritization_fee_cache
665 .get_prioritization_fees(&[write_account_b])
666 .is_empty());
667 assert!(prioritization_fee_cache
668 .get_prioritization_fees(&[write_account_c])
669 .is_empty());
670 assert!(prioritization_fee_cache
671 .get_prioritization_fees(&[write_account_a, write_account_b])
672 .is_empty());
673 assert!(prioritization_fee_cache
674 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
675 .is_empty());
676 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 1, bank1.bank_id());
678 assert_eq!(
679 vec![(1, 1)],
680 prioritization_fee_cache.get_prioritization_fees(&[])
681 );
682 assert_eq!(
683 vec![(1, 2)],
684 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
685 );
686 assert_eq!(
687 vec![(1, 2)],
688 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
689 );
690 assert_eq!(
691 vec![(1, 1)],
692 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
693 );
694 assert_eq!(
695 vec![(1, 2)],
696 prioritization_fee_cache
697 .get_prioritization_fees(&[write_account_a, write_account_b])
698 );
699 assert_eq!(
700 vec![(1, 2)],
701 prioritization_fee_cache.get_prioritization_fees(&[
702 write_account_a,
703 write_account_b,
704 write_account_c
705 ])
706 );
707 }
708
709 {
711 let txs = vec![
712 build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c),
713 build_sanitized_transaction_for_test(
714 3,
715 &Pubkey::new_unique(),
716 &Pubkey::new_unique(),
717 ),
718 ];
719 sync_update(&prioritization_fee_cache, bank2.clone(), txs.iter());
720 assert_eq!(
722 vec![(1, 1)],
723 prioritization_fee_cache.get_prioritization_fees(&[])
724 );
725 assert_eq!(
726 vec![(1, 2)],
727 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
728 );
729 assert_eq!(
730 vec![(1, 2)],
731 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
732 );
733 assert_eq!(
734 vec![(1, 1)],
735 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
736 );
737 assert_eq!(
738 vec![(1, 2)],
739 prioritization_fee_cache
740 .get_prioritization_fees(&[write_account_a, write_account_b])
741 );
742 assert_eq!(
743 vec![(1, 2)],
744 prioritization_fee_cache.get_prioritization_fees(&[
745 write_account_a,
746 write_account_b,
747 write_account_c
748 ])
749 );
750 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 2, bank2.bank_id());
752 assert_eq!(
753 vec![(1, 1), (2, 3)],
754 prioritization_fee_cache.get_prioritization_fees(&[]),
755 );
756 assert_eq!(
757 vec![(1, 2), (2, 3)],
758 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
759 );
760 assert_eq!(
761 vec![(1, 2), (2, 4)],
762 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
763 );
764 assert_eq!(
765 vec![(1, 1), (2, 4)],
766 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
767 );
768 assert_eq!(
769 vec![(1, 2), (2, 4)],
770 prioritization_fee_cache
771 .get_prioritization_fees(&[write_account_a, write_account_b]),
772 );
773 assert_eq!(
774 vec![(1, 2), (2, 4)],
775 prioritization_fee_cache.get_prioritization_fees(&[
776 write_account_a,
777 write_account_b,
778 write_account_c,
779 ]),
780 );
781 }
782
783 {
785 let txs = vec![
786 build_sanitized_transaction_for_test(6, &write_account_a, &write_account_c),
787 build_sanitized_transaction_for_test(
788 5,
789 &Pubkey::new_unique(),
790 &Pubkey::new_unique(),
791 ),
792 ];
793 sync_update(&prioritization_fee_cache, bank3.clone(), txs.iter());
794 assert_eq!(
796 vec![(1, 1), (2, 3)],
797 prioritization_fee_cache.get_prioritization_fees(&[]),
798 );
799 assert_eq!(
800 vec![(1, 2), (2, 3)],
801 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
802 );
803 assert_eq!(
804 vec![(1, 2), (2, 4)],
805 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
806 );
807 assert_eq!(
808 vec![(1, 1), (2, 4)],
809 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
810 );
811 assert_eq!(
812 vec![(1, 2), (2, 4)],
813 prioritization_fee_cache
814 .get_prioritization_fees(&[write_account_a, write_account_b]),
815 );
816 assert_eq!(
817 vec![(1, 2), (2, 4)],
818 prioritization_fee_cache.get_prioritization_fees(&[
819 write_account_a,
820 write_account_b,
821 write_account_c,
822 ]),
823 );
824 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 3, bank3.bank_id());
826 assert_eq!(
827 vec![(1, 1), (2, 3), (3, 5)],
828 prioritization_fee_cache.get_prioritization_fees(&[]),
829 );
830 assert_eq!(
831 vec![(1, 2), (2, 3), (3, 6)],
832 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
833 );
834 assert_eq!(
835 vec![(1, 2), (2, 4), (3, 5)],
836 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
837 );
838 assert_eq!(
839 vec![(1, 1), (2, 4), (3, 6)],
840 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
841 );
842 assert_eq!(
843 vec![(1, 2), (2, 4), (3, 6)],
844 prioritization_fee_cache
845 .get_prioritization_fees(&[write_account_a, write_account_b]),
846 );
847 assert_eq!(
848 vec![(1, 2), (2, 4), (3, 6)],
849 prioritization_fee_cache.get_prioritization_fees(&[
850 write_account_a,
851 write_account_b,
852 write_account_c,
853 ]),
854 );
855 }
856 }
857
858 #[test]
859 fn test_purge_duplicated_bank() {
860 solana_logger::setup();
863 let write_account_a = Pubkey::new_unique();
864 let write_account_b = Pubkey::new_unique();
865 let write_account_c = Pubkey::new_unique();
866
867 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
868 let bank0 = Bank::new_for_benches(&genesis_config);
869 let bank_forks = BankForks::new_rw_arc(bank0);
870 let bank = bank_forks.read().unwrap().working_bank();
871 let collector = solana_pubkey::new_rand();
872 let slot: Slot = 999;
873 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, slot));
874 let bank2 = Arc::new(Bank::new_from_parent(bank, &collector, slot + 1));
875
876 let prioritization_fee_cache = PrioritizationFeeCache::default();
877
878 {
880 let txs = vec![
881 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
882 build_sanitized_transaction_for_test(
883 1,
884 &Pubkey::new_unique(),
885 &Pubkey::new_unique(),
886 ),
887 ];
888 sync_update(&prioritization_fee_cache, bank1.clone(), txs.iter());
889 }
890
891 {
893 let txs = vec![
894 build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c),
895 build_sanitized_transaction_for_test(
896 3,
897 &Pubkey::new_unique(),
898 &Pubkey::new_unique(),
899 ),
900 ];
901 sync_update(&prioritization_fee_cache, bank2.clone(), txs.iter());
902 }
903
904 {
906 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, slot, bank1.bank_id());
907
908 assert_eq!(
910 vec![(slot, 1)],
911 prioritization_fee_cache.get_prioritization_fees(&[])
912 );
913 assert_eq!(
914 vec![(slot, 2)],
915 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
916 );
917 assert_eq!(
918 vec![(slot, 2)],
919 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
920 );
921 assert_eq!(
922 vec![(slot, 1)],
923 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
924 );
925 assert_eq!(
926 vec![(slot, 2)],
927 prioritization_fee_cache
928 .get_prioritization_fees(&[write_account_a, write_account_b])
929 );
930 assert_eq!(
931 vec![(slot, 2)],
932 prioritization_fee_cache.get_prioritization_fees(&[
933 write_account_a,
934 write_account_b,
935 write_account_c
936 ])
937 );
938 }
939 }
940}