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::instructions_processor::process_compute_budget_instructions,
8 solana_sdk::{
9 clock::{BankId, Slot},
10 pubkey::Pubkey,
11 transaction::SanitizedTransaction,
12 },
13 solana_svm_transaction::svm_message::SVMMessage,
14 std::{
15 collections::{BTreeMap, HashMap},
16 sync::{
17 atomic::{AtomicU64, Ordering},
18 Arc, RwLock,
19 },
20 thread::{sleep, Builder, JoinHandle},
21 time::Duration,
22 },
23};
24
25const MAX_NUM_RECENT_BLOCKS: u64 = 150;
29
30const MAX_UNFINALIZED_SLOTS: u64 = 128;
32
33type UnfinalizedPrioritizationFees = BTreeMap<Slot, HashMap<BankId, PrioritizationFee>>;
34
35#[derive(Debug, Default)]
36struct PrioritizationFeeCacheMetrics {
37 successful_transaction_update_count: AtomicU64,
39
40 purged_duplicated_bank_count: AtomicU64,
42
43 total_update_elapsed_us: AtomicU64,
45
46 total_cache_lock_elapsed_us: AtomicU64,
48
49 total_entry_update_elapsed_us: AtomicU64,
51
52 total_block_finalize_elapsed_us: AtomicU64,
54}
55
56impl PrioritizationFeeCacheMetrics {
57 fn accumulate_successful_transaction_update_count(&self, val: u64) {
58 self.successful_transaction_update_count
59 .fetch_add(val, Ordering::Relaxed);
60 }
61
62 fn accumulate_total_purged_duplicated_bank_count(&self, val: u64) {
63 self.purged_duplicated_bank_count
64 .fetch_add(val, Ordering::Relaxed);
65 }
66
67 fn accumulate_total_update_elapsed_us(&self, val: u64) {
68 self.total_update_elapsed_us
69 .fetch_add(val, Ordering::Relaxed);
70 }
71
72 fn accumulate_total_cache_lock_elapsed_us(&self, val: u64) {
73 self.total_cache_lock_elapsed_us
74 .fetch_add(val, Ordering::Relaxed);
75 }
76
77 fn accumulate_total_entry_update_elapsed_us(&self, val: u64) {
78 self.total_entry_update_elapsed_us
79 .fetch_add(val, Ordering::Relaxed);
80 }
81
82 fn accumulate_total_block_finalize_elapsed_us(&self, val: u64) {
83 self.total_block_finalize_elapsed_us
84 .fetch_add(val, Ordering::Relaxed);
85 }
86
87 fn report(&self, slot: Slot) {
88 datapoint_info!(
89 "block_prioritization_fee_counters",
90 ("slot", slot as i64, i64),
91 (
92 "successful_transaction_update_count",
93 self.successful_transaction_update_count
94 .swap(0, Ordering::Relaxed) as i64,
95 i64
96 ),
97 (
98 "purged_duplicated_bank_count",
99 self.purged_duplicated_bank_count.swap(0, Ordering::Relaxed) as i64,
100 i64
101 ),
102 (
103 "total_update_elapsed_us",
104 self.total_update_elapsed_us.swap(0, Ordering::Relaxed) as i64,
105 i64
106 ),
107 (
108 "total_cache_lock_elapsed_us",
109 self.total_cache_lock_elapsed_us.swap(0, Ordering::Relaxed) as i64,
110 i64
111 ),
112 (
113 "total_entry_update_elapsed_us",
114 self.total_entry_update_elapsed_us
115 .swap(0, Ordering::Relaxed) as i64,
116 i64
117 ),
118 (
119 "total_block_finalize_elapsed_us",
120 self.total_block_finalize_elapsed_us
121 .swap(0, Ordering::Relaxed) as i64,
122 i64
123 ),
124 );
125 }
126}
127
128#[derive(Debug)]
129enum CacheServiceUpdate {
130 TransactionUpdate {
131 slot: Slot,
132 bank_id: BankId,
133 transaction_fee: u64,
134 writable_accounts: Vec<Pubkey>,
135 },
136 BankFinalized {
137 slot: Slot,
138 bank_id: BankId,
139 },
140 Exit,
141}
142
143#[derive(Debug)]
147pub struct PrioritizationFeeCache {
148 cache: Arc<RwLock<BTreeMap<Slot, PrioritizationFee>>>,
149 service_thread: Option<JoinHandle<()>>,
150 sender: Sender<CacheServiceUpdate>,
151 metrics: Arc<PrioritizationFeeCacheMetrics>,
152}
153
154impl Default for PrioritizationFeeCache {
155 fn default() -> Self {
156 Self::new(MAX_NUM_RECENT_BLOCKS)
157 }
158}
159
160impl Drop for PrioritizationFeeCache {
161 fn drop(&mut self) {
162 let _ = self.sender.send(CacheServiceUpdate::Exit);
163 self.service_thread
164 .take()
165 .unwrap()
166 .join()
167 .expect("Prioritization fee cache servicing thread failed to join");
168 }
169}
170
171impl PrioritizationFeeCache {
172 pub fn new(capacity: u64) -> Self {
173 let cache = Arc::new(RwLock::new(BTreeMap::new()));
174 let (sender, receiver) = unbounded();
175 let metrics = Arc::new(PrioritizationFeeCacheMetrics::default());
176
177 let service_thread = Some(
178 Builder::new()
179 .name("solPrFeeCachSvc".to_string())
180 .spawn({
181 let cache = cache.clone();
182 let metrics = metrics.clone();
183 move || Self::service_loop(cache, capacity as usize, receiver, metrics)
184 })
185 .unwrap(),
186 );
187
188 PrioritizationFeeCache {
189 cache,
190 service_thread,
191 sender,
192 metrics,
193 }
194 }
195
196 pub fn update<'a>(&self, bank: &Bank, txs: impl Iterator<Item = &'a SanitizedTransaction>) {
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 = process_compute_budget_instructions(
209 SVMMessage::program_instructions_iter(sanitized_transaction),
210 &bank.feature_set,
211 );
212
213 let message = sanitized_transaction.message();
214 let lock_result = validate_account_locks(
215 message.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 = message
231 .account_keys()
232 .iter()
233 .enumerate()
234 .filter(|(index, _)| message.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_sdk::{
444 compute_budget::ComputeBudgetInstruction,
445 message::Message,
446 pubkey::Pubkey,
447 system_instruction,
448 transaction::{SanitizedTransaction, Transaction},
449 },
450 };
451
452 fn build_sanitized_transaction_for_test(
453 compute_unit_price: u64,
454 signer_account: &Pubkey,
455 write_account: &Pubkey,
456 ) -> SanitizedTransaction {
457 let transaction = Transaction::new_unsigned(Message::new(
458 &[
459 system_instruction::transfer(signer_account, write_account, 1),
460 ComputeBudgetInstruction::set_compute_unit_price(compute_unit_price),
461 ],
462 Some(signer_account),
463 ));
464
465 SanitizedTransaction::from_transaction_for_tests(transaction)
466 }
467
468 fn sync_update<'a>(
470 prioritization_fee_cache: &PrioritizationFeeCache,
471 bank: Arc<Bank>,
472 txs: impl ExactSizeIterator<Item = &'a SanitizedTransaction>,
473 ) {
474 let expected_update_count = prioritization_fee_cache
475 .metrics
476 .successful_transaction_update_count
477 .load(Ordering::Relaxed)
478 .saturating_add(txs.len() as u64);
479
480 prioritization_fee_cache.update(&bank, txs);
481
482 while prioritization_fee_cache
484 .metrics
485 .successful_transaction_update_count
486 .load(Ordering::Relaxed)
487 != expected_update_count
488 {
489 std::thread::sleep(std::time::Duration::from_millis(10));
490 }
491 }
492
493 fn sync_finalize_priority_fee_for_test(
495 prioritization_fee_cache: &PrioritizationFeeCache,
496 slot: Slot,
497 bank_id: BankId,
498 ) {
499 prioritization_fee_cache.finalize_priority_fee(slot, bank_id);
501
502 loop {
504 let cache = prioritization_fee_cache.cache.read().unwrap();
505 if let Some(slot_cache) = cache.get(&slot) {
506 if slot_cache.is_finalized() {
507 return;
508 }
509 }
510 drop(cache);
511
512 std::thread::sleep(std::time::Duration::from_millis(10));
513 }
514 }
515
516 #[test]
517 fn test_prioritization_fee_cache_update() {
518 solana_logger::setup();
519 let write_account_a = Pubkey::new_unique();
520 let write_account_b = Pubkey::new_unique();
521 let write_account_c = Pubkey::new_unique();
522
523 let txs = vec![
533 build_sanitized_transaction_for_test(5, &write_account_a, &write_account_b),
534 build_sanitized_transaction_for_test(9, &write_account_b, &write_account_c),
535 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_c),
536 ];
537
538 let bank = Arc::new(Bank::default_for_tests());
539 let slot = bank.slot();
540
541 let prioritization_fee_cache = PrioritizationFeeCache::default();
542 sync_update(&prioritization_fee_cache, bank.clone(), txs.iter());
543
544 {
546 let lock = prioritization_fee_cache.cache.read().unwrap();
547 assert!(lock.get(&slot).is_none());
548 }
549
550 {
552 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, slot, bank.bank_id());
553 let lock = prioritization_fee_cache.cache.read().unwrap();
554 let fee = lock.get(&slot).unwrap();
555 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
556 assert!(fee.get_writable_account_fee(&write_account_a).is_none());
557 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
558 assert!(fee.get_writable_account_fee(&write_account_c).is_none());
559 }
560 }
561
562 #[test]
563 fn test_available_block_count() {
564 let prioritization_fee_cache = PrioritizationFeeCache::default();
565
566 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
567 let bank0 = Bank::new_for_benches(&genesis_config);
568 let bank_forks = BankForks::new_rw_arc(bank0);
569 let bank = bank_forks.read().unwrap().working_bank();
570 let collector = solana_sdk::pubkey::new_rand();
571
572 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 1));
573 sync_update(
574 &prioritization_fee_cache,
575 bank1.clone(),
576 vec![build_sanitized_transaction_for_test(
577 1,
578 &Pubkey::new_unique(),
579 &Pubkey::new_unique(),
580 )]
581 .iter(),
582 );
583 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 1, bank1.bank_id());
584
585 let bank2 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 2));
587 let txs = vec![build_sanitized_transaction_for_test(
588 1,
589 &Pubkey::new_unique(),
590 &Pubkey::new_unique(),
591 )];
592 sync_update(&prioritization_fee_cache, bank2.clone(), txs.iter());
593
594 let bank3 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 3));
595 sync_update(
596 &prioritization_fee_cache,
597 bank3.clone(),
598 vec![build_sanitized_transaction_for_test(
599 1,
600 &Pubkey::new_unique(),
601 &Pubkey::new_unique(),
602 )]
603 .iter(),
604 );
605 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 3, bank3.bank_id());
606
607 assert_eq!(2, prioritization_fee_cache.available_block_count());
609 }
610
611 #[test]
612 fn test_get_prioritization_fees() {
613 solana_logger::setup();
614 let write_account_a = Pubkey::new_unique();
615 let write_account_b = Pubkey::new_unique();
616 let write_account_c = Pubkey::new_unique();
617
618 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
619 let bank0 = Bank::new_for_benches(&genesis_config);
620 let bank_forks = BankForks::new_rw_arc(bank0);
621 let bank = bank_forks.read().unwrap().working_bank();
622 let collector = solana_sdk::pubkey::new_rand();
623 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 1));
624 let bank2 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 2));
625 let bank3 = Arc::new(Bank::new_from_parent(bank, &collector, 3));
626
627 let prioritization_fee_cache = PrioritizationFeeCache::default();
628
629 assert!(prioritization_fee_cache
631 .get_prioritization_fees(&[])
632 .is_empty());
633 assert!(prioritization_fee_cache
634 .get_prioritization_fees(&[write_account_a])
635 .is_empty());
636 assert!(prioritization_fee_cache
637 .get_prioritization_fees(&[write_account_b])
638 .is_empty());
639 assert!(prioritization_fee_cache
640 .get_prioritization_fees(&[write_account_c])
641 .is_empty());
642 assert!(prioritization_fee_cache
643 .get_prioritization_fees(&[write_account_a, write_account_b])
644 .is_empty());
645 assert!(prioritization_fee_cache
646 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
647 .is_empty());
648
649 {
651 let txs = vec![
652 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
653 build_sanitized_transaction_for_test(
654 1,
655 &Pubkey::new_unique(),
656 &Pubkey::new_unique(),
657 ),
658 ];
659 sync_update(&prioritization_fee_cache, bank1.clone(), txs.iter());
660 assert!(prioritization_fee_cache
662 .get_prioritization_fees(&[])
663 .is_empty());
664 assert!(prioritization_fee_cache
665 .get_prioritization_fees(&[write_account_a])
666 .is_empty());
667 assert!(prioritization_fee_cache
668 .get_prioritization_fees(&[write_account_b])
669 .is_empty());
670 assert!(prioritization_fee_cache
671 .get_prioritization_fees(&[write_account_c])
672 .is_empty());
673 assert!(prioritization_fee_cache
674 .get_prioritization_fees(&[write_account_a, write_account_b])
675 .is_empty());
676 assert!(prioritization_fee_cache
677 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
678 .is_empty());
679 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 1, bank1.bank_id());
681 assert_eq!(
682 vec![(1, 1)],
683 prioritization_fee_cache.get_prioritization_fees(&[])
684 );
685 assert_eq!(
686 vec![(1, 2)],
687 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
688 );
689 assert_eq!(
690 vec![(1, 2)],
691 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
692 );
693 assert_eq!(
694 vec![(1, 1)],
695 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
696 );
697 assert_eq!(
698 vec![(1, 2)],
699 prioritization_fee_cache
700 .get_prioritization_fees(&[write_account_a, write_account_b])
701 );
702 assert_eq!(
703 vec![(1, 2)],
704 prioritization_fee_cache.get_prioritization_fees(&[
705 write_account_a,
706 write_account_b,
707 write_account_c
708 ])
709 );
710 }
711
712 {
714 let txs = vec![
715 build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c),
716 build_sanitized_transaction_for_test(
717 3,
718 &Pubkey::new_unique(),
719 &Pubkey::new_unique(),
720 ),
721 ];
722 sync_update(&prioritization_fee_cache, bank2.clone(), txs.iter());
723 assert_eq!(
725 vec![(1, 1)],
726 prioritization_fee_cache.get_prioritization_fees(&[])
727 );
728 assert_eq!(
729 vec![(1, 2)],
730 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
731 );
732 assert_eq!(
733 vec![(1, 2)],
734 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
735 );
736 assert_eq!(
737 vec![(1, 1)],
738 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
739 );
740 assert_eq!(
741 vec![(1, 2)],
742 prioritization_fee_cache
743 .get_prioritization_fees(&[write_account_a, write_account_b])
744 );
745 assert_eq!(
746 vec![(1, 2)],
747 prioritization_fee_cache.get_prioritization_fees(&[
748 write_account_a,
749 write_account_b,
750 write_account_c
751 ])
752 );
753 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 2, bank2.bank_id());
755 assert_eq!(
756 vec![(1, 1), (2, 3)],
757 prioritization_fee_cache.get_prioritization_fees(&[]),
758 );
759 assert_eq!(
760 vec![(1, 2), (2, 3)],
761 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
762 );
763 assert_eq!(
764 vec![(1, 2), (2, 4)],
765 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
766 );
767 assert_eq!(
768 vec![(1, 1), (2, 4)],
769 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
770 );
771 assert_eq!(
772 vec![(1, 2), (2, 4)],
773 prioritization_fee_cache
774 .get_prioritization_fees(&[write_account_a, write_account_b]),
775 );
776 assert_eq!(
777 vec![(1, 2), (2, 4)],
778 prioritization_fee_cache.get_prioritization_fees(&[
779 write_account_a,
780 write_account_b,
781 write_account_c,
782 ]),
783 );
784 }
785
786 {
788 let txs = vec![
789 build_sanitized_transaction_for_test(6, &write_account_a, &write_account_c),
790 build_sanitized_transaction_for_test(
791 5,
792 &Pubkey::new_unique(),
793 &Pubkey::new_unique(),
794 ),
795 ];
796 sync_update(&prioritization_fee_cache, bank3.clone(), txs.iter());
797 assert_eq!(
799 vec![(1, 1), (2, 3)],
800 prioritization_fee_cache.get_prioritization_fees(&[]),
801 );
802 assert_eq!(
803 vec![(1, 2), (2, 3)],
804 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
805 );
806 assert_eq!(
807 vec![(1, 2), (2, 4)],
808 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
809 );
810 assert_eq!(
811 vec![(1, 1), (2, 4)],
812 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
813 );
814 assert_eq!(
815 vec![(1, 2), (2, 4)],
816 prioritization_fee_cache
817 .get_prioritization_fees(&[write_account_a, write_account_b]),
818 );
819 assert_eq!(
820 vec![(1, 2), (2, 4)],
821 prioritization_fee_cache.get_prioritization_fees(&[
822 write_account_a,
823 write_account_b,
824 write_account_c,
825 ]),
826 );
827 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 3, bank3.bank_id());
829 assert_eq!(
830 vec![(1, 1), (2, 3), (3, 5)],
831 prioritization_fee_cache.get_prioritization_fees(&[]),
832 );
833 assert_eq!(
834 vec![(1, 2), (2, 3), (3, 6)],
835 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
836 );
837 assert_eq!(
838 vec![(1, 2), (2, 4), (3, 5)],
839 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
840 );
841 assert_eq!(
842 vec![(1, 1), (2, 4), (3, 6)],
843 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
844 );
845 assert_eq!(
846 vec![(1, 2), (2, 4), (3, 6)],
847 prioritization_fee_cache
848 .get_prioritization_fees(&[write_account_a, write_account_b]),
849 );
850 assert_eq!(
851 vec![(1, 2), (2, 4), (3, 6)],
852 prioritization_fee_cache.get_prioritization_fees(&[
853 write_account_a,
854 write_account_b,
855 write_account_c,
856 ]),
857 );
858 }
859 }
860
861 #[test]
862 fn test_purge_duplicated_bank() {
863 solana_logger::setup();
866 let write_account_a = Pubkey::new_unique();
867 let write_account_b = Pubkey::new_unique();
868 let write_account_c = Pubkey::new_unique();
869
870 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
871 let bank0 = Bank::new_for_benches(&genesis_config);
872 let bank_forks = BankForks::new_rw_arc(bank0);
873 let bank = bank_forks.read().unwrap().working_bank();
874 let collector = solana_sdk::pubkey::new_rand();
875 let slot: Slot = 999;
876 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, slot));
877 let bank2 = Arc::new(Bank::new_from_parent(bank, &collector, slot + 1));
878
879 let prioritization_fee_cache = PrioritizationFeeCache::default();
880
881 {
883 let txs = vec![
884 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
885 build_sanitized_transaction_for_test(
886 1,
887 &Pubkey::new_unique(),
888 &Pubkey::new_unique(),
889 ),
890 ];
891 sync_update(&prioritization_fee_cache, bank1.clone(), txs.iter());
892 }
893
894 {
896 let txs = vec![
897 build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c),
898 build_sanitized_transaction_for_test(
899 3,
900 &Pubkey::new_unique(),
901 &Pubkey::new_unique(),
902 ),
903 ];
904 sync_update(&prioritization_fee_cache, bank2.clone(), txs.iter());
905 }
906
907 {
909 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, slot, bank1.bank_id());
910
911 assert_eq!(
913 vec![(slot, 1)],
914 prioritization_fee_cache.get_prioritization_fees(&[])
915 );
916 assert_eq!(
917 vec![(slot, 2)],
918 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
919 );
920 assert_eq!(
921 vec![(slot, 2)],
922 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
923 );
924 assert_eq!(
925 vec![(slot, 1)],
926 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
927 );
928 assert_eq!(
929 vec![(slot, 2)],
930 prioritization_fee_cache
931 .get_prioritization_fees(&[write_account_a, write_account_b])
932 );
933 assert_eq!(
934 vec![(slot, 2)],
935 prioritization_fee_cache.get_prioritization_fees(&[
936 write_account_a,
937 write_account_b,
938 write_account_c
939 ])
940 );
941 }
942 }
943}