1use crate::types::{EntryId, LockPoints};
8use bitcoin::{Amount, Transaction, Txid, Weight, Wtxid};
9use slotmap::{DefaultKey, SlotMap};
10use std::collections::{BTreeSet, HashMap, HashSet};
11use std::sync::Arc;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
18pub struct AncestorScoreKey {
19 pub neg_feerate_frac: (i64, i64),
22 pub txid: Txid,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
31pub struct DescendantScoreKey {
32 pub neg_feerate_frac: (i64, i64),
34 pub time: i64,
36}
37
38pub struct TxMemPoolEntry {
48 pub tx: Arc<Transaction>,
50
51 pub fee: Amount,
53
54 pub modified_fee: Amount,
56
57 pub tx_weight: Weight,
59
60 pub time: i64,
62
63 pub entry_height: u32,
65
66 pub entry_block_mtp: i64,
68
69 pub entry_block_hash: bitcoin::BlockHash,
71
72 pub entry_sequence: u64,
74
75 pub spends_coinbase: bool,
77
78 pub sigop_cost: i64,
80
81 pub lock_points: LockPoints,
83
84 pub count_with_ancestors: u64,
87
88 pub size_with_ancestors: i64,
90
91 pub fees_with_ancestors: Amount,
93
94 pub sigops_with_ancestors: i64,
96
97 pub count_with_descendants: u64,
99
100 pub size_with_descendants: i64,
102
103 pub fees_with_descendants: Amount,
105
106 pub parents: HashSet<EntryId>,
109
110 pub children: HashSet<EntryId>,
112
113 pub cached_ancestor_key: AncestorScoreKey,
116
117 pub cached_descendant_key: DescendantScoreKey,
119
120 pub idx_randomized: Option<usize>,
122}
123
124impl TxMemPoolEntry {
125 pub fn vsize(&self) -> i64 {
127 self.tx_weight.to_vbytes_ceil() as i64
128 }
129
130 pub fn feerate(&self) -> i64 {
132 (self.modified_fee.to_sat() as i64 * 1_000_000) / self.vsize()
133 }
134
135 pub fn ancestor_feerate(&self) -> i64 {
137 (self.fees_with_ancestors.to_sat() as i64 * 1_000_000) / self.size_with_ancestors
138 }
139
140 pub fn descendant_feerate(&self) -> i64 {
142 (self.fees_with_descendants.to_sat() as i64 * 1_000_000) / self.size_with_descendants
143 }
144
145 pub fn signals_rbf(&self) -> bool {
150 const RBF_THRESHOLD: u32 = 0xfffffffe;
152
153 self.tx
154 .input
155 .iter()
156 .any(|txin| txin.sequence.to_consensus_u32() < RBF_THRESHOLD)
157 }
158}
159
160pub struct MemPoolArena {
164 entries: SlotMap<DefaultKey, TxMemPoolEntry>,
166
167 by_txid: HashMap<Txid, EntryId>,
170
171 by_wtxid: HashMap<Wtxid, EntryId>,
173
174 by_ancestor_score: BTreeSet<(AncestorScoreKey, EntryId)>,
178
179 by_descendant_score: BTreeSet<(DescendantScoreKey, EntryId)>,
182
183 by_entry_time: BTreeSet<(i64, EntryId)>,
186}
187
188impl MemPoolArena {
189 pub fn new() -> Self {
191 Self {
192 entries: SlotMap::new(),
193 by_txid: HashMap::new(),
194 by_wtxid: HashMap::new(),
195 by_ancestor_score: BTreeSet::new(),
196 by_descendant_score: BTreeSet::new(),
197 by_entry_time: BTreeSet::new(),
198 }
199 }
200
201 pub fn insert(&mut self, mut entry: TxMemPoolEntry) -> EntryId {
205 let anc_key = compute_ancestor_key(&entry);
207 let desc_key = compute_descendant_key(&entry);
208 entry.cached_ancestor_key = anc_key;
209 entry.cached_descendant_key = desc_key;
210
211 let txid = entry.tx.compute_txid();
212 let wtxid = entry.tx.compute_wtxid();
213 let time = entry.time;
214
215 let id = EntryId(self.entries.insert(entry));
217
218 self.by_txid.insert(txid, id);
220 self.by_wtxid.insert(wtxid, id);
221 self.by_ancestor_score.insert((anc_key, id));
222 self.by_descendant_score.insert((desc_key, id));
223 self.by_entry_time.insert((time, id));
224
225 id
226 }
227
228 pub fn update_ancestor_state(
232 &mut self,
233 id: EntryId,
234 size_delta: i64,
235 fee_delta: bitcoin::SignedAmount,
236 count_delta: i64,
237 sigops_delta: i64,
238 ) {
239 let entry = &self.entries[id.0];
240
241 let old_anc_key = entry.cached_ancestor_key;
243 let old_desc_key = entry.cached_descendant_key;
244
245 self.by_ancestor_score.remove(&(old_anc_key, id));
247 self.by_descendant_score.remove(&(old_desc_key, id));
248
249 let entry = &mut self.entries[id.0];
251 entry.size_with_ancestors += size_delta;
252 entry.fees_with_ancestors =
253 (bitcoin::SignedAmount::from_sat(entry.fees_with_ancestors.to_sat() as i64)
254 + fee_delta)
255 .to_unsigned()
256 .expect("Ancestor fees cannot go negative");
257 entry.count_with_ancestors = (entry.count_with_ancestors as i64 + count_delta) as u64;
258 entry.sigops_with_ancestors += sigops_delta;
259
260 let new_anc_key = compute_ancestor_key(entry);
262 let new_desc_key = compute_descendant_key(entry);
263
264 entry.cached_ancestor_key = new_anc_key;
266 entry.cached_descendant_key = new_desc_key;
267
268 self.by_ancestor_score.insert((new_anc_key, id));
270 self.by_descendant_score.insert((new_desc_key, id));
271 }
272
273 pub fn update_descendant_state(
275 &mut self,
276 id: EntryId,
277 size_delta: i64,
278 fee_delta: bitcoin::SignedAmount,
279 count_delta: i64,
280 ) {
281 let entry = &self.entries[id.0];
282
283 let old_desc_key = entry.cached_descendant_key;
285
286 self.by_descendant_score.remove(&(old_desc_key, id));
288
289 let entry = &mut self.entries[id.0];
291 entry.size_with_descendants += size_delta;
292 entry.fees_with_descendants =
293 (bitcoin::SignedAmount::from_sat(entry.fees_with_descendants.to_sat() as i64)
294 + fee_delta)
295 .to_unsigned()
296 .expect("Descendant fees cannot go negative");
297 entry.count_with_descendants = (entry.count_with_descendants as i64 + count_delta) as u64;
298
299 let new_desc_key = compute_descendant_key(entry);
301 entry.cached_descendant_key = new_desc_key;
302
303 self.by_descendant_score.insert((new_desc_key, id));
305 }
306
307 pub fn update_modified_fee(&mut self, id: EntryId, new_modified_fee: Amount) {
309 let entry = &self.entries[id.0];
310
311 let old_anc_key = entry.cached_ancestor_key;
313 let old_desc_key = entry.cached_descendant_key;
314
315 self.by_ancestor_score.remove(&(old_anc_key, id));
317 self.by_descendant_score.remove(&(old_desc_key, id));
318
319 let entry = &mut self.entries[id.0];
321 let old_fee = entry.modified_fee;
322 entry.modified_fee = new_modified_fee;
323
324 let fee_delta =
326 Amount::from_sat((new_modified_fee.to_sat() as i64 - old_fee.to_sat() as i64) as u64);
327 entry.fees_with_ancestors = Amount::from_sat(
328 (entry.fees_with_ancestors.to_sat() as i64 + fee_delta.to_sat() as i64) as u64,
329 );
330 entry.fees_with_descendants = Amount::from_sat(
331 (entry.fees_with_descendants.to_sat() as i64 + fee_delta.to_sat() as i64) as u64,
332 );
333
334 let new_anc_key = compute_ancestor_key(entry);
336 let new_desc_key = compute_descendant_key(entry);
337 entry.cached_ancestor_key = new_anc_key;
338 entry.cached_descendant_key = new_desc_key;
339
340 self.by_ancestor_score.insert((new_anc_key, id));
342 self.by_descendant_score.insert((new_desc_key, id));
343 }
344
345 pub fn get(&self, id: EntryId) -> Option<&TxMemPoolEntry> {
347 self.entries.get(id.0)
348 }
349
350 pub fn get_mut(&mut self, id: EntryId) -> Option<&mut TxMemPoolEntry> {
352 self.entries.get_mut(id.0)
353 }
354
355 pub fn get_by_txid(&self, txid: &Txid) -> Option<EntryId> {
357 self.by_txid.get(txid).copied()
358 }
359
360 pub fn get_by_wtxid(&self, wtxid: &Wtxid) -> Option<EntryId> {
362 self.by_wtxid.get(wtxid).copied()
363 }
364
365 pub fn remove(&mut self, id: EntryId) -> Option<TxMemPoolEntry> {
369 let entry = self.entries.remove(id.0)?;
370
371 self.by_txid.remove(&entry.tx.compute_txid());
373 self.by_wtxid.remove(&entry.tx.compute_wtxid());
374 self.by_ancestor_score
375 .remove(&(entry.cached_ancestor_key, id));
376 self.by_descendant_score
377 .remove(&(entry.cached_descendant_key, id));
378 self.by_entry_time.remove(&(entry.time, id));
379
380 Some(entry)
381 }
382
383 pub fn iter_by_ancestor_score(&self) -> impl Iterator<Item = (EntryId, &TxMemPoolEntry)> {
387 self.by_ancestor_score
388 .iter()
389 .map(|(_, id)| (*id, &self.entries[id.0]))
390 }
391
392 pub fn iter_by_descendant_score(&self) -> impl Iterator<Item = (EntryId, &TxMemPoolEntry)> {
396 self.by_descendant_score
397 .iter()
398 .map(|(_, id)| (*id, &self.entries[id.0]))
399 }
400
401 pub fn iter_by_entry_time(&self) -> impl Iterator<Item = (EntryId, &TxMemPoolEntry)> {
403 self.by_entry_time
404 .iter()
405 .map(|(_, id)| (*id, &self.entries[id.0]))
406 }
407
408 pub fn len(&self) -> usize {
410 self.entries.len()
411 }
412
413 pub fn is_empty(&self) -> bool {
415 self.entries.is_empty()
416 }
417}
418
419impl Default for MemPoolArena {
420 fn default() -> Self {
421 Self::new()
422 }
423}
424
425fn compute_ancestor_key(entry: &TxMemPoolEntry) -> AncestorScoreKey {
426 let entry_feerate = entry.feerate();
427 let ancestor_feerate = entry.ancestor_feerate();
428 let min_feerate = std::cmp::min(entry_feerate, ancestor_feerate);
429
430 AncestorScoreKey {
431 neg_feerate_frac: (-min_feerate, entry.size_with_ancestors),
432 txid: entry.tx.compute_txid(),
433 }
434}
435
436fn compute_descendant_key(entry: &TxMemPoolEntry) -> DescendantScoreKey {
437 let entry_feerate = entry.feerate();
438 let desc_feerate = entry.descendant_feerate();
439 let max_feerate = std::cmp::max(entry_feerate, desc_feerate);
440
441 DescendantScoreKey {
442 neg_feerate_frac: (-max_feerate, entry.size_with_descendants),
443 time: entry.time,
444 }
445}
446
447#[cfg(test)]
448mod tests {
449 #[allow(unused_imports)]
450 use super::*;
451
452 }