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#[cfg(test)]
18mod template_limits_tests;
19
20pub use block_template::policy::Policy;
22pub use mempool::model::frontier::{Frontier, feerate_key::FeerateTransactionKey, search_tree::SearchTree};
23
24#[cfg(test)]
25pub mod testutils;
26
27pub struct MiningCounters {
28 pub creation_time: Instant,
29
30 pub high_priority_tx_counts: AtomicU64,
32 pub low_priority_tx_counts: AtomicU64,
33 pub block_tx_counts: AtomicU64,
34 pub tx_accepted_counts: AtomicU64,
35 pub tx_evicted_counts: AtomicU64,
36 pub input_counts: AtomicU64,
37 pub output_counts: AtomicU64,
38
39 pub ready_txs_sample: AtomicU64,
41 pub txs_sample: AtomicU64,
42 pub orphans_sample: AtomicU64,
43 pub accepted_sample: AtomicU64,
44}
45
46impl Default for MiningCounters {
47 fn default() -> Self {
48 Self {
49 creation_time: Instant::now(),
50 high_priority_tx_counts: Default::default(),
51 low_priority_tx_counts: Default::default(),
52 block_tx_counts: Default::default(),
53 tx_accepted_counts: Default::default(),
54 tx_evicted_counts: Default::default(),
55 input_counts: Default::default(),
56 output_counts: Default::default(),
57 ready_txs_sample: Default::default(),
58 txs_sample: Default::default(),
59 orphans_sample: Default::default(),
60 accepted_sample: Default::default(),
61 }
62 }
63}
64
65impl MiningCounters {
66 pub fn snapshot(&self) -> MempoolCountersSnapshot {
67 MempoolCountersSnapshot {
68 elapsed_time: (Instant::now().saturating_duration_since(self.creation_time)),
69 high_priority_tx_counts: self.high_priority_tx_counts.load(Ordering::Relaxed),
70 low_priority_tx_counts: self.low_priority_tx_counts.load(Ordering::Relaxed),
71 block_tx_counts: self.block_tx_counts.load(Ordering::Relaxed),
72 tx_accepted_counts: self.tx_accepted_counts.load(Ordering::Relaxed),
73 tx_evicted_counts: self.tx_evicted_counts.load(Ordering::Relaxed),
74 input_counts: self.input_counts.load(Ordering::Relaxed),
75 output_counts: self.output_counts.load(Ordering::Relaxed),
76 ready_txs_sample: self.ready_txs_sample.load(Ordering::Relaxed),
77 txs_sample: self.txs_sample.load(Ordering::Relaxed),
78 orphans_sample: self.orphans_sample.load(Ordering::Relaxed),
79 accepted_sample: self.accepted_sample.load(Ordering::Relaxed),
80 }
81 }
82
83 pub fn p2p_tx_count_sample(&self) -> P2pTxCountSample {
84 P2pTxCountSample {
85 elapsed_time: (Instant::now().saturating_duration_since(self.creation_time)),
86 low_priority_tx_counts: self.low_priority_tx_counts.load(Ordering::Relaxed),
87 }
88 }
89
90 pub fn increase_tx_counts(&self, value: u64, priority: Priority) {
91 match priority {
92 Priority::Low => {
93 self.low_priority_tx_counts.fetch_add(value, Ordering::Relaxed);
94 }
95 Priority::High => {
96 self.high_priority_tx_counts.fetch_add(value, Ordering::Relaxed);
97 }
98 }
99 }
100}
101
102#[derive(Debug, PartialEq, Eq)]
103pub struct MempoolCountersSnapshot {
104 pub elapsed_time: Duration,
105 pub high_priority_tx_counts: u64,
106 pub low_priority_tx_counts: u64,
107 pub block_tx_counts: u64,
108 pub tx_accepted_counts: u64,
109 pub tx_evicted_counts: u64,
110 pub input_counts: u64,
111 pub output_counts: u64,
112 pub ready_txs_sample: u64,
113 pub txs_sample: u64,
114 pub orphans_sample: u64,
115 pub accepted_sample: u64,
116}
117
118impl MempoolCountersSnapshot {
119 pub fn in_tx_counts(&self) -> u64 {
120 #[allow(clippy::arithmetic_side_effects, reason = "ARITH-SAFETY(COUNTER)")]
121 {
122 self.high_priority_tx_counts + self.low_priority_tx_counts
123 }
124 }
125
126 pub fn has_tps_activity(&self) -> bool {
128 self.tx_accepted_counts > 0 || self.block_tx_counts > 0 || self.low_priority_tx_counts > 0 || self.high_priority_tx_counts > 0
129 }
130
131 pub fn u_tps(&self) -> f64 {
134 let elapsed = self.elapsed_time.as_secs_f64();
135 if elapsed != 0f64 { self.tx_accepted_counts as f64 / elapsed } else { 0f64 }
136 }
137
138 pub fn e_tps(&self) -> f64 {
144 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 {
147 accepted_txs as f64 / total_txs as f64
148 } else {
149 1f64 }
151 }
152}
153
154impl core::ops::Sub for &MempoolCountersSnapshot {
155 type Output = MempoolCountersSnapshot;
156
157 fn sub(self, rhs: Self) -> Self::Output {
158 Self::Output {
159 elapsed_time: self.elapsed_time.saturating_sub(rhs.elapsed_time),
160 high_priority_tx_counts: self.high_priority_tx_counts.saturating_sub(rhs.high_priority_tx_counts),
161 low_priority_tx_counts: self.low_priority_tx_counts.saturating_sub(rhs.low_priority_tx_counts),
162 block_tx_counts: self.block_tx_counts.saturating_sub(rhs.block_tx_counts),
163 tx_accepted_counts: self.tx_accepted_counts.saturating_sub(rhs.tx_accepted_counts),
164 tx_evicted_counts: self.tx_evicted_counts.saturating_sub(rhs.tx_evicted_counts),
165 input_counts: self.input_counts.saturating_sub(rhs.input_counts),
166 output_counts: self.output_counts.saturating_sub(rhs.output_counts),
167 #[allow(clippy::arithmetic_side_effects, reason = "ARITH-SAFETY(COUNTER)")]
168 ready_txs_sample: (self.ready_txs_sample + rhs.ready_txs_sample) / 2,
169 #[allow(clippy::arithmetic_side_effects, reason = "ARITH-SAFETY(COUNTER)")]
170 txs_sample: (self.txs_sample + rhs.txs_sample) / 2,
171 #[allow(clippy::arithmetic_side_effects, reason = "ARITH-SAFETY(COUNTER)")]
172 orphans_sample: (self.orphans_sample + rhs.orphans_sample) / 2,
173 #[allow(clippy::arithmetic_side_effects, reason = "ARITH-SAFETY(COUNTER)")]
174 accepted_sample: (self.accepted_sample + rhs.accepted_sample) / 2,
175 }
176 }
177}
178
179pub struct P2pTxCountSample {
181 pub elapsed_time: Duration,
182 pub low_priority_tx_counts: u64,
183}
184
185impl core::ops::Sub for &P2pTxCountSample {
186 type Output = P2pTxCountSample;
187
188 fn sub(self, rhs: Self) -> Self::Output {
189 Self::Output {
190 elapsed_time: self.elapsed_time.saturating_sub(rhs.elapsed_time),
191 low_priority_tx_counts: self.low_priority_tx_counts.saturating_sub(rhs.low_priority_tx_counts),
192 }
193 }
194}