1use std::{
2 sync::atomic::{AtomicU64, Ordering},
3 time::{Duration, Instant},
4};
5
6use mempool::tx::Priority;
7
8mod block_template;
9pub(crate) mod cache;
10pub mod errors;
11pub mod feerate;
12pub mod manager;
13mod manager_tests;
14pub mod mempool;
15pub mod model;
16pub mod monitor;
17
18pub use block_template::{policy::Policy, selector::RebalancingWeightedTransactionSelector};
20pub use mempool::model::frontier::{feerate_key::FeerateTransactionKey, search_tree::SearchTree, Frontier};
21
22#[cfg(test)]
23pub mod testutils;
24
25pub struct MiningCounters {
26 pub creation_time: Instant,
27
28 pub high_priority_tx_counts: AtomicU64,
30 pub low_priority_tx_counts: AtomicU64,
31 pub block_tx_counts: AtomicU64,
32 pub tx_accepted_counts: AtomicU64,
33 pub tx_evicted_counts: AtomicU64,
34 pub input_counts: AtomicU64,
35 pub output_counts: AtomicU64,
36
37 pub ready_txs_sample: AtomicU64,
39 pub txs_sample: AtomicU64,
40 pub orphans_sample: AtomicU64,
41 pub accepted_sample: AtomicU64,
42}
43
44impl Default for MiningCounters {
45 fn default() -> Self {
46 Self {
47 creation_time: Instant::now(),
48 high_priority_tx_counts: Default::default(),
49 low_priority_tx_counts: Default::default(),
50 block_tx_counts: Default::default(),
51 tx_accepted_counts: Default::default(),
52 tx_evicted_counts: Default::default(),
53 input_counts: Default::default(),
54 output_counts: Default::default(),
55 ready_txs_sample: Default::default(),
56 txs_sample: Default::default(),
57 orphans_sample: Default::default(),
58 accepted_sample: Default::default(),
59 }
60 }
61}
62
63impl MiningCounters {
64 pub fn snapshot(&self) -> MempoolCountersSnapshot {
65 MempoolCountersSnapshot {
66 elapsed_time: (Instant::now() - self.creation_time),
67 high_priority_tx_counts: self.high_priority_tx_counts.load(Ordering::Relaxed),
68 low_priority_tx_counts: self.low_priority_tx_counts.load(Ordering::Relaxed),
69 block_tx_counts: self.block_tx_counts.load(Ordering::Relaxed),
70 tx_accepted_counts: self.tx_accepted_counts.load(Ordering::Relaxed),
71 tx_evicted_counts: self.tx_evicted_counts.load(Ordering::Relaxed),
72 input_counts: self.input_counts.load(Ordering::Relaxed),
73 output_counts: self.output_counts.load(Ordering::Relaxed),
74 ready_txs_sample: self.ready_txs_sample.load(Ordering::Relaxed),
75 txs_sample: self.txs_sample.load(Ordering::Relaxed),
76 orphans_sample: self.orphans_sample.load(Ordering::Relaxed),
77 accepted_sample: self.accepted_sample.load(Ordering::Relaxed),
78 }
79 }
80
81 pub fn p2p_tx_count_sample(&self) -> P2pTxCountSample {
82 P2pTxCountSample {
83 elapsed_time: (Instant::now() - self.creation_time),
84 low_priority_tx_counts: self.low_priority_tx_counts.load(Ordering::Relaxed),
85 }
86 }
87
88 pub fn increase_tx_counts(&self, value: u64, priority: Priority) {
89 match priority {
90 Priority::Low => {
91 self.low_priority_tx_counts.fetch_add(value, Ordering::Relaxed);
92 }
93 Priority::High => {
94 self.high_priority_tx_counts.fetch_add(value, Ordering::Relaxed);
95 }
96 }
97 }
98}
99
100#[derive(Debug, PartialEq, Eq)]
101pub struct MempoolCountersSnapshot {
102 pub elapsed_time: Duration,
103 pub high_priority_tx_counts: u64,
104 pub low_priority_tx_counts: u64,
105 pub block_tx_counts: u64,
106 pub tx_accepted_counts: u64,
107 pub tx_evicted_counts: u64,
108 pub input_counts: u64,
109 pub output_counts: u64,
110 pub ready_txs_sample: u64,
111 pub txs_sample: u64,
112 pub orphans_sample: u64,
113 pub accepted_sample: u64,
114}
115
116impl MempoolCountersSnapshot {
117 pub fn in_tx_counts(&self) -> u64 {
118 self.high_priority_tx_counts + self.low_priority_tx_counts
119 }
120
121 pub fn has_tps_activity(&self) -> bool {
123 self.tx_accepted_counts > 0 || self.block_tx_counts > 0 || self.low_priority_tx_counts > 0 || self.high_priority_tx_counts > 0
124 }
125
126 pub fn u_tps(&self) -> f64 {
129 let elapsed = self.elapsed_time.as_secs_f64();
130 if elapsed != 0f64 {
131 self.tx_accepted_counts as f64 / elapsed
132 } else {
133 0f64
134 }
135 }
136
137 pub fn e_tps(&self) -> f64 {
143 let accepted_txs = u64::min(self.ready_txs_sample, self.tx_accepted_counts); let total_txs = u64::min(self.ready_txs_sample, self.block_tx_counts); if total_txs > 0 {
146 accepted_txs as f64 / total_txs as f64
147 } else {
148 1f64 }
150 }
151}
152
153impl core::ops::Sub for &MempoolCountersSnapshot {
154 type Output = MempoolCountersSnapshot;
155
156 fn sub(self, rhs: Self) -> Self::Output {
157 Self::Output {
158 elapsed_time: self.elapsed_time.saturating_sub(rhs.elapsed_time),
159 high_priority_tx_counts: self.high_priority_tx_counts.saturating_sub(rhs.high_priority_tx_counts),
160 low_priority_tx_counts: self.low_priority_tx_counts.saturating_sub(rhs.low_priority_tx_counts),
161 block_tx_counts: self.block_tx_counts.saturating_sub(rhs.block_tx_counts),
162 tx_accepted_counts: self.tx_accepted_counts.saturating_sub(rhs.tx_accepted_counts),
163 tx_evicted_counts: self.tx_evicted_counts.saturating_sub(rhs.tx_evicted_counts),
164 input_counts: self.input_counts.saturating_sub(rhs.input_counts),
165 output_counts: self.output_counts.saturating_sub(rhs.output_counts),
166 ready_txs_sample: (self.ready_txs_sample + rhs.ready_txs_sample) / 2,
167 txs_sample: (self.txs_sample + rhs.txs_sample) / 2,
168 orphans_sample: (self.orphans_sample + rhs.orphans_sample) / 2,
169 accepted_sample: (self.accepted_sample + rhs.accepted_sample) / 2,
170 }
171 }
172}
173
174pub struct P2pTxCountSample {
176 pub elapsed_time: Duration,
177 pub low_priority_tx_counts: u64,
178}
179
180impl core::ops::Sub for &P2pTxCountSample {
181 type Output = P2pTxCountSample;
182
183 fn sub(self, rhs: Self) -> Self::Output {
184 Self::Output {
185 elapsed_time: self.elapsed_time.saturating_sub(rhs.elapsed_time),
186 low_priority_tx_counts: self.low_priority_tx_counts.saturating_sub(rhs.low_priority_tx_counts),
187 }
188 }
189}