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