1use {
2 crate::{bank::Bank, compute_budget_details::GetComputeBudgetDetails, prioritization_fee::*},
3 crossbeam_channel::{unbounded, Receiver, Sender},
4 dashmap::DashMap,
5 log::*,
6 lru::LruCache,
7 miraland_measure::measure,
8 miraland_sdk::{
9 clock::{BankId, Slot},
10 pubkey::Pubkey,
11 transaction::SanitizedTransaction,
12 },
13 std::{
14 collections::HashMap,
15 sync::{
16 atomic::{AtomicU64, Ordering},
17 Arc, 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 purged_duplicated_bank_count: AtomicU64,
35
36 total_update_elapsed_us: AtomicU64,
38
39 total_cache_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_purged_duplicated_bank_count(&self, val: u64) {
56 self.purged_duplicated_bank_count
57 .fetch_add(val, Ordering::Relaxed);
58 }
59
60 fn accumulate_total_update_elapsed_us(&self, val: u64) {
61 self.total_update_elapsed_us
62 .fetch_add(val, Ordering::Relaxed);
63 }
64
65 fn accumulate_total_cache_lock_elapsed_us(&self, val: u64) {
66 self.total_cache_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 "purged_duplicated_bank_count",
92 self.purged_duplicated_bank_count.swap(0, Ordering::Relaxed) as i64,
93 i64
94 ),
95 (
96 "total_update_elapsed_us",
97 self.total_update_elapsed_us.swap(0, Ordering::Relaxed) as i64,
98 i64
99 ),
100 (
101 "total_cache_lock_elapsed_us",
102 self.total_cache_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 bank_id: BankId,
125 transaction_fee: u64,
126 writable_accounts: Arc<Vec<Pubkey>>,
127 },
128 BankFinalized {
129 slot: Slot,
130 bank_id: BankId,
131 },
132 Exit,
133}
134
135type SlotPrioritizationFee = DashMap<BankId, PrioritizationFee>;
138
139#[derive(Debug)]
143pub struct PrioritizationFeeCache {
144 cache: Arc<RwLock<LruCache<Slot, Arc<SlotPrioritizationFee>>>>,
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 metrics = Arc::new(PrioritizationFeeCacheMetrics::default());
170 let (sender, receiver) = unbounded();
171 let cache = Arc::new(RwLock::new(LruCache::new(capacity as usize)));
172
173 let cache_clone = cache.clone();
174 let metrics_clone = metrics.clone();
175 let service_thread = Some(
176 Builder::new()
177 .name("mlnPrFeeCachSvc".to_string())
178 .spawn(move || {
179 Self::service_loop(cache_clone, receiver, metrics_clone);
180 })
181 .unwrap(),
182 );
183
184 PrioritizationFeeCache {
185 cache,
186 service_thread,
187 sender,
188 metrics,
189 }
190 }
191
192 fn get_prioritization_fee(
194 cache: Arc<RwLock<LruCache<Slot, Arc<SlotPrioritizationFee>>>>,
195 slot: &Slot,
196 ) -> Arc<SlotPrioritizationFee> {
197 let mut cache = cache.write().unwrap();
198 match cache.get(slot) {
199 Some(entry) => Arc::clone(entry),
200 None => {
201 let entry = Arc::new(SlotPrioritizationFee::default());
202 cache.put(*slot, Arc::clone(&entry));
203 entry
204 }
205 }
206 }
207
208 pub fn update<'a>(&self, bank: &Bank, txs: impl Iterator<Item = &'a SanitizedTransaction>) {
212 let (_, send_updates_time) = measure!(
213 {
214 for sanitized_transaction in txs {
215 if sanitized_transaction.is_simple_vote_transaction() {
218 continue;
219 }
220
221 let round_compute_unit_price_enabled = false; let compute_budget_details = sanitized_transaction
223 .get_compute_budget_details(round_compute_unit_price_enabled);
224 let account_locks = sanitized_transaction
225 .get_account_locks(bank.get_transaction_account_lock_limit());
226
227 if compute_budget_details.is_none() || account_locks.is_err() {
228 continue;
229 }
230 let compute_budget_details = compute_budget_details.unwrap();
231
232 if compute_budget_details.compute_unit_limit == 0 {
235 continue;
236 }
237
238 let writable_accounts = Arc::new(
239 account_locks
240 .unwrap()
241 .writable
242 .iter()
243 .map(|key| **key)
244 .collect::<Vec<_>>(),
245 );
246
247 self.sender
248 .send(CacheServiceUpdate::TransactionUpdate {
249 slot: bank.slot(),
250 bank_id: bank.bank_id(),
251 transaction_fee: compute_budget_details.compute_unit_price,
252 writable_accounts,
253 })
254 .unwrap_or_else(|err| {
255 warn!(
256 "prioritization fee cache transaction updates failed: {:?}",
257 err
258 );
259 });
260 }
261 },
262 "send_updates",
263 );
264
265 self.metrics
266 .accumulate_total_update_elapsed_us(send_updates_time.as_us());
267 }
268
269 pub fn finalize_priority_fee(&self, slot: Slot, bank_id: BankId) {
272 self.sender
273 .send(CacheServiceUpdate::BankFinalized { slot, bank_id })
274 .unwrap_or_else(|err| {
275 warn!(
276 "prioritization fee cache signalling bank frozen failed: {:?}",
277 err
278 )
279 });
280 }
281
282 fn update_cache(
285 cache: Arc<RwLock<LruCache<Slot, Arc<SlotPrioritizationFee>>>>,
286 slot: &Slot,
287 bank_id: &BankId,
288 transaction_fee: u64,
289 writable_accounts: Arc<Vec<Pubkey>>,
290 metrics: Arc<PrioritizationFeeCacheMetrics>,
291 ) {
292 let (slot_prioritization_fee, cache_lock_time) =
293 measure!(Self::get_prioritization_fee(cache, slot), "cache_lock_time");
294
295 let (_, entry_update_time) = measure!(
296 {
297 let mut block_prioritization_fee = slot_prioritization_fee
298 .entry(*bank_id)
299 .or_insert(PrioritizationFee::default());
300 block_prioritization_fee.update(transaction_fee, &writable_accounts)
301 },
302 "entry_update_time"
303 );
304 metrics.accumulate_total_cache_lock_elapsed_us(cache_lock_time.as_us());
305 metrics.accumulate_total_entry_update_elapsed_us(entry_update_time.as_us());
306 metrics.accumulate_successful_transaction_update_count(1);
307 }
308
309 fn finalize_slot(
310 cache: Arc<RwLock<LruCache<Slot, Arc<SlotPrioritizationFee>>>>,
311 slot: &Slot,
312 bank_id: &BankId,
313 metrics: Arc<PrioritizationFeeCacheMetrics>,
314 ) {
315 let (slot_prioritization_fee, cache_lock_time) =
316 measure!(Self::get_prioritization_fee(cache, slot), "cache_lock_time");
317
318 let (result, slot_finalize_time) = measure!(
322 {
323 let pre_purge_bank_count = slot_prioritization_fee.len() as u64;
325 slot_prioritization_fee.retain(|id, _| id == bank_id);
326 let post_purge_bank_count = slot_prioritization_fee.len() as u64;
327 metrics.accumulate_total_purged_duplicated_bank_count(
328 pre_purge_bank_count.saturating_sub(post_purge_bank_count),
329 );
330 if pre_purge_bank_count > 0 && post_purge_bank_count == 0 {
333 warn!("Finalized bank has empty prioritization fee cache. slot {slot} bank id {bank_id}");
334 }
335
336 let mut block_prioritization_fee = slot_prioritization_fee
337 .entry(*bank_id)
338 .or_insert(PrioritizationFee::default());
339 let result = block_prioritization_fee.mark_block_completed();
340 block_prioritization_fee.report_metrics(*slot);
341 result
342 },
343 "slot_finalize_time"
344 );
345 metrics.accumulate_total_cache_lock_elapsed_us(cache_lock_time.as_us());
346 metrics.accumulate_total_block_finalize_elapsed_us(slot_finalize_time.as_us());
347
348 if let Err(err) = result {
349 error!(
350 "Unsuccessful finalizing slot {slot}, bank ID {bank_id}: {:?}",
351 err
352 );
353 }
354 }
355
356 fn service_loop(
357 cache: Arc<RwLock<LruCache<Slot, Arc<SlotPrioritizationFee>>>>,
358 receiver: Receiver<CacheServiceUpdate>,
359 metrics: Arc<PrioritizationFeeCacheMetrics>,
360 ) {
361 for update in receiver.iter() {
362 match update {
363 CacheServiceUpdate::TransactionUpdate {
364 slot,
365 bank_id,
366 transaction_fee,
367 writable_accounts,
368 } => Self::update_cache(
369 cache.clone(),
370 &slot,
371 &bank_id,
372 transaction_fee,
373 writable_accounts,
374 metrics.clone(),
375 ),
376 CacheServiceUpdate::BankFinalized { slot, bank_id } => {
377 Self::finalize_slot(cache.clone(), &slot, &bank_id, metrics.clone());
378
379 metrics.report(slot);
380 }
381 CacheServiceUpdate::Exit => {
382 break;
383 }
384 }
385 }
386 }
387
388 pub fn available_block_count(&self) -> usize {
390 self.cache
391 .read()
392 .unwrap()
393 .iter()
394 .filter(|(_slot, slot_prioritization_fee)| {
395 slot_prioritization_fee
396 .iter()
397 .any(|prioritization_fee| prioritization_fee.is_finalized())
398 })
399 .count()
400 }
401
402 pub fn get_prioritization_fees(&self, account_keys: &[Pubkey]) -> HashMap<Slot, u64> {
403 self.cache
404 .read()
405 .unwrap()
406 .iter()
407 .filter_map(|(slot, slot_prioritization_fee)| {
408 slot_prioritization_fee
409 .iter()
410 .find_map(|prioritization_fee| {
411 prioritization_fee.is_finalized().then(|| {
412 let mut fee = prioritization_fee
413 .get_min_transaction_fee()
414 .unwrap_or_default();
415 for account_key in account_keys {
416 if let Some(account_fee) =
417 prioritization_fee.get_writable_account_fee(account_key)
418 {
419 fee = std::cmp::max(fee, account_fee);
420 }
421 }
422 Some((*slot, fee))
423 })
424 })
425 })
426 .flatten()
427 .collect()
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use {
434 super::*,
435 crate::{
436 bank::Bank,
437 bank_forks::BankForks,
438 genesis_utils::{create_genesis_config, GenesisConfigInfo},
439 },
440 miraland_sdk::{
441 compute_budget::ComputeBudgetInstruction,
442 message::Message,
443 pubkey::Pubkey,
444 system_instruction,
445 transaction::{SanitizedTransaction, Transaction},
446 },
447 };
448
449 fn build_sanitized_transaction_for_test(
450 compute_unit_price: u64,
451 signer_account: &Pubkey,
452 write_account: &Pubkey,
453 ) -> 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 SanitizedTransaction::try_from_legacy_transaction(transaction).unwrap()
463 }
464
465 fn sync_update<'a>(
467 prioritization_fee_cache: &PrioritizationFeeCache,
468 bank: Arc<Bank>,
469 txs: impl Iterator<Item = &'a SanitizedTransaction> + ExactSizeIterator,
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(100));
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);
497 let fee = PrioritizationFeeCache::get_prioritization_fee(
498 prioritization_fee_cache.cache.clone(),
499 &slot,
500 );
501
502 while !fee
504 .get(&bank_id)
505 .map_or(false, |block_fee| block_fee.is_finalized())
506 {
507 std::thread::sleep(std::time::Duration::from_millis(100));
508 }
509 }
510
511 #[test]
512 fn test_prioritization_fee_cache_update() {
513 miraland_logger::setup();
514 let write_account_a = Pubkey::new_unique();
515 let write_account_b = Pubkey::new_unique();
516 let write_account_c = Pubkey::new_unique();
517
518 let txs = vec![
528 build_sanitized_transaction_for_test(5, &write_account_a, &write_account_b),
529 build_sanitized_transaction_for_test(9, &write_account_b, &write_account_c),
530 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_c),
531 ];
532
533 let bank = Arc::new(Bank::default_for_tests());
534 let slot = bank.slot();
535
536 let prioritization_fee_cache = PrioritizationFeeCache::default();
537 sync_update(&prioritization_fee_cache, bank.clone(), txs.iter());
538
539 {
541 let fee = PrioritizationFeeCache::get_prioritization_fee(
542 prioritization_fee_cache.cache.clone(),
543 &slot,
544 );
545 let fee = fee.get(&bank.bank_id()).unwrap();
546 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
547 assert_eq!(2, fee.get_writable_account_fee(&write_account_a).unwrap());
548 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
549 assert_eq!(2, fee.get_writable_account_fee(&write_account_c).unwrap());
550 assert!(fee
552 .get_writable_account_fee(&Pubkey::new_unique())
553 .is_none());
554 }
555
556 {
558 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, slot, bank.bank_id());
559 let fee = PrioritizationFeeCache::get_prioritization_fee(
560 prioritization_fee_cache.cache.clone(),
561 &slot,
562 );
563 let fee = fee.get(&bank.bank_id()).unwrap();
564 assert_eq!(2, fee.get_min_transaction_fee().unwrap());
565 assert!(fee.get_writable_account_fee(&write_account_a).is_none());
566 assert_eq!(5, fee.get_writable_account_fee(&write_account_b).unwrap());
567 assert!(fee.get_writable_account_fee(&write_account_c).is_none());
568 }
569 }
570
571 #[test]
572 fn test_available_block_count() {
573 let prioritization_fee_cache = PrioritizationFeeCache::default();
574
575 assert!(PrioritizationFeeCache::get_prioritization_fee(
576 prioritization_fee_cache.cache.clone(),
577 &1
578 )
579 .entry(1)
580 .or_default()
581 .mark_block_completed()
582 .is_ok());
583 assert!(PrioritizationFeeCache::get_prioritization_fee(
584 prioritization_fee_cache.cache.clone(),
585 &2
586 )
587 .entry(2)
588 .or_default()
589 .mark_block_completed()
590 .is_ok());
591 PrioritizationFeeCache::get_prioritization_fee(prioritization_fee_cache.cache.clone(), &3)
593 .entry(3)
594 .or_default();
595
596 assert_eq!(2, prioritization_fee_cache.available_block_count());
598 }
599
600 fn hashmap_of(vec: Vec<(Slot, u64)>) -> HashMap<Slot, u64> {
601 vec.into_iter().collect()
602 }
603
604 #[test]
605 fn test_get_prioritization_fees() {
606 miraland_logger::setup();
607 let write_account_a = Pubkey::new_unique();
608 let write_account_b = Pubkey::new_unique();
609 let write_account_c = Pubkey::new_unique();
610
611 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
612 let bank0 = Bank::new_for_benches(&genesis_config);
613 let bank_forks = BankForks::new_rw_arc(bank0);
614 let bank = bank_forks.read().unwrap().working_bank();
615 let collector = miraland_sdk::pubkey::new_rand();
616 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 1));
617 let bank2 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, 2));
618 let bank3 = Arc::new(Bank::new_from_parent(bank, &collector, 3));
619
620 let prioritization_fee_cache = PrioritizationFeeCache::default();
621
622 assert!(prioritization_fee_cache
624 .get_prioritization_fees(&[])
625 .is_empty());
626 assert!(prioritization_fee_cache
627 .get_prioritization_fees(&[write_account_a])
628 .is_empty());
629 assert!(prioritization_fee_cache
630 .get_prioritization_fees(&[write_account_b])
631 .is_empty());
632 assert!(prioritization_fee_cache
633 .get_prioritization_fees(&[write_account_c])
634 .is_empty());
635 assert!(prioritization_fee_cache
636 .get_prioritization_fees(&[write_account_a, write_account_b])
637 .is_empty());
638 assert!(prioritization_fee_cache
639 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
640 .is_empty());
641
642 {
644 let txs = vec![
645 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
646 build_sanitized_transaction_for_test(
647 1,
648 &Pubkey::new_unique(),
649 &Pubkey::new_unique(),
650 ),
651 ];
652 sync_update(&prioritization_fee_cache, bank1.clone(), txs.iter());
653 assert!(prioritization_fee_cache
655 .get_prioritization_fees(&[])
656 .is_empty());
657 assert!(prioritization_fee_cache
658 .get_prioritization_fees(&[write_account_a])
659 .is_empty());
660 assert!(prioritization_fee_cache
661 .get_prioritization_fees(&[write_account_b])
662 .is_empty());
663 assert!(prioritization_fee_cache
664 .get_prioritization_fees(&[write_account_c])
665 .is_empty());
666 assert!(prioritization_fee_cache
667 .get_prioritization_fees(&[write_account_a, write_account_b])
668 .is_empty());
669 assert!(prioritization_fee_cache
670 .get_prioritization_fees(&[write_account_a, write_account_b, write_account_c])
671 .is_empty());
672 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 1, bank1.bank_id());
674 assert_eq!(
675 hashmap_of(vec![(1, 1)]),
676 prioritization_fee_cache.get_prioritization_fees(&[])
677 );
678 assert_eq!(
679 hashmap_of(vec![(1, 2)]),
680 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
681 );
682 assert_eq!(
683 hashmap_of(vec![(1, 2)]),
684 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
685 );
686 assert_eq!(
687 hashmap_of(vec![(1, 1)]),
688 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
689 );
690 assert_eq!(
691 hashmap_of(vec![(1, 2)]),
692 prioritization_fee_cache
693 .get_prioritization_fees(&[write_account_a, write_account_b])
694 );
695 assert_eq!(
696 hashmap_of(vec![(1, 2)]),
697 prioritization_fee_cache.get_prioritization_fees(&[
698 write_account_a,
699 write_account_b,
700 write_account_c
701 ])
702 );
703 }
704
705 {
707 let txs = vec![
708 build_sanitized_transaction_for_test(4, &write_account_b, &write_account_c),
709 build_sanitized_transaction_for_test(
710 3,
711 &Pubkey::new_unique(),
712 &Pubkey::new_unique(),
713 ),
714 ];
715 sync_update(&prioritization_fee_cache, bank2.clone(), txs.iter());
716 assert_eq!(
718 hashmap_of(vec![(1, 1)]),
719 prioritization_fee_cache.get_prioritization_fees(&[])
720 );
721 assert_eq!(
722 hashmap_of(vec![(1, 2)]),
723 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
724 );
725 assert_eq!(
726 hashmap_of(vec![(1, 2)]),
727 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
728 );
729 assert_eq!(
730 hashmap_of(vec![(1, 1)]),
731 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
732 );
733 assert_eq!(
734 hashmap_of(vec![(1, 2)]),
735 prioritization_fee_cache
736 .get_prioritization_fees(&[write_account_a, write_account_b])
737 );
738 assert_eq!(
739 hashmap_of(vec![(1, 2)]),
740 prioritization_fee_cache.get_prioritization_fees(&[
741 write_account_a,
742 write_account_b,
743 write_account_c
744 ])
745 );
746 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 2, bank2.bank_id());
748 assert_eq!(
749 hashmap_of(vec![(2, 3), (1, 1)]),
750 prioritization_fee_cache.get_prioritization_fees(&[]),
751 );
752 assert_eq!(
753 hashmap_of(vec![(2, 3), (1, 2)]),
754 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
755 );
756 assert_eq!(
757 hashmap_of(vec![(2, 4), (1, 2)]),
758 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
759 );
760 assert_eq!(
761 hashmap_of(vec![(2, 4), (1, 1)]),
762 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
763 );
764 assert_eq!(
765 hashmap_of(vec![(2, 4), (1, 2)]),
766 prioritization_fee_cache
767 .get_prioritization_fees(&[write_account_a, write_account_b]),
768 );
769 assert_eq!(
770 hashmap_of(vec![(2, 4), (1, 2)]),
771 prioritization_fee_cache.get_prioritization_fees(&[
772 write_account_a,
773 write_account_b,
774 write_account_c,
775 ]),
776 );
777 }
778
779 {
781 let txs = vec![
782 build_sanitized_transaction_for_test(6, &write_account_a, &write_account_c),
783 build_sanitized_transaction_for_test(
784 5,
785 &Pubkey::new_unique(),
786 &Pubkey::new_unique(),
787 ),
788 ];
789 sync_update(&prioritization_fee_cache, bank3.clone(), txs.iter());
790 assert_eq!(
792 hashmap_of(vec![(2, 3), (1, 1)]),
793 prioritization_fee_cache.get_prioritization_fees(&[]),
794 );
795 assert_eq!(
796 hashmap_of(vec![(2, 3), (1, 2)]),
797 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
798 );
799 assert_eq!(
800 hashmap_of(vec![(2, 4), (1, 2)]),
801 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
802 );
803 assert_eq!(
804 hashmap_of(vec![(2, 4), (1, 1)]),
805 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
806 );
807 assert_eq!(
808 hashmap_of(vec![(2, 4), (1, 2)]),
809 prioritization_fee_cache
810 .get_prioritization_fees(&[write_account_a, write_account_b]),
811 );
812 assert_eq!(
813 hashmap_of(vec![(2, 4), (1, 2)]),
814 prioritization_fee_cache.get_prioritization_fees(&[
815 write_account_a,
816 write_account_b,
817 write_account_c,
818 ]),
819 );
820 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, 3, bank3.bank_id());
822 assert_eq!(
823 hashmap_of(vec![(3, 5), (2, 3), (1, 1)]),
824 prioritization_fee_cache.get_prioritization_fees(&[]),
825 );
826 assert_eq!(
827 hashmap_of(vec![(3, 6), (2, 3), (1, 2)]),
828 prioritization_fee_cache.get_prioritization_fees(&[write_account_a]),
829 );
830 assert_eq!(
831 hashmap_of(vec![(3, 5), (2, 4), (1, 2)]),
832 prioritization_fee_cache.get_prioritization_fees(&[write_account_b]),
833 );
834 assert_eq!(
835 hashmap_of(vec![(3, 6), (2, 4), (1, 1)]),
836 prioritization_fee_cache.get_prioritization_fees(&[write_account_c]),
837 );
838 assert_eq!(
839 hashmap_of(vec![(3, 6), (2, 4), (1, 2)]),
840 prioritization_fee_cache
841 .get_prioritization_fees(&[write_account_a, write_account_b]),
842 );
843 assert_eq!(
844 hashmap_of(vec![(3, 6), (2, 4), (1, 2)]),
845 prioritization_fee_cache.get_prioritization_fees(&[
846 write_account_a,
847 write_account_b,
848 write_account_c,
849 ]),
850 );
851 }
852 }
853
854 #[test]
855 fn test_purge_duplicated_bank() {
856 miraland_logger::setup();
859 let write_account_a = Pubkey::new_unique();
860 let write_account_b = Pubkey::new_unique();
861 let write_account_c = Pubkey::new_unique();
862
863 let GenesisConfigInfo { genesis_config, .. } = create_genesis_config(10_000);
864 let bank0 = Bank::new_for_benches(&genesis_config);
865 let bank_forks = BankForks::new_rw_arc(bank0);
866 let bank = bank_forks.read().unwrap().working_bank();
867 let collector = miraland_sdk::pubkey::new_rand();
868 let slot: Slot = 999;
869 let bank1 = Arc::new(Bank::new_from_parent(bank.clone(), &collector, slot));
870 let bank2 = Arc::new(Bank::new_from_parent(bank, &collector, slot));
871
872 let prioritization_fee_cache = PrioritizationFeeCache::default();
873
874 {
876 let txs = vec![
877 build_sanitized_transaction_for_test(2, &write_account_a, &write_account_b),
878 build_sanitized_transaction_for_test(
879 1,
880 &Pubkey::new_unique(),
881 &Pubkey::new_unique(),
882 ),
883 ];
884 sync_update(&prioritization_fee_cache, bank1.clone(), txs.iter());
885
886 let slot_prioritization_fee = PrioritizationFeeCache::get_prioritization_fee(
887 prioritization_fee_cache.cache.clone(),
888 &slot,
889 );
890 assert_eq!(1, slot_prioritization_fee.len());
891 assert!(slot_prioritization_fee.contains_key(&bank1.bank_id()));
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 let slot_prioritization_fee = PrioritizationFeeCache::get_prioritization_fee(
907 prioritization_fee_cache.cache.clone(),
908 &slot,
909 );
910 assert_eq!(2, slot_prioritization_fee.len());
911 assert!(slot_prioritization_fee.contains_key(&bank1.bank_id()));
912 assert!(slot_prioritization_fee.contains_key(&bank2.bank_id()));
913 }
914
915 {
917 sync_finalize_priority_fee_for_test(&prioritization_fee_cache, slot, bank1.bank_id());
918
919 let slot_prioritization_fee = PrioritizationFeeCache::get_prioritization_fee(
920 prioritization_fee_cache.cache.clone(),
921 &slot,
922 );
923 assert_eq!(1, slot_prioritization_fee.len());
924 assert!(slot_prioritization_fee.contains_key(&bank1.bank_id()));
925
926 assert_eq!(
928 hashmap_of(vec![(slot, 1)]),
929 prioritization_fee_cache.get_prioritization_fees(&[])
930 );
931 assert_eq!(
932 hashmap_of(vec![(slot, 2)]),
933 prioritization_fee_cache.get_prioritization_fees(&[write_account_a])
934 );
935 assert_eq!(
936 hashmap_of(vec![(slot, 2)]),
937 prioritization_fee_cache.get_prioritization_fees(&[write_account_b])
938 );
939 assert_eq!(
940 hashmap_of(vec![(slot, 1)]),
941 prioritization_fee_cache.get_prioritization_fees(&[write_account_c])
942 );
943 assert_eq!(
944 hashmap_of(vec![(slot, 2)]),
945 prioritization_fee_cache
946 .get_prioritization_fees(&[write_account_a, write_account_b])
947 );
948 assert_eq!(
949 hashmap_of(vec![(slot, 2)]),
950 prioritization_fee_cache.get_prioritization_fees(&[
951 write_account_a,
952 write_account_b,
953 write_account_c
954 ])
955 );
956 }
957 }
958}