mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-20 23:48:10 -07:00
mempool: fixes
This commit is contained in:
@@ -35,9 +35,9 @@ use brk_error::Result;
|
||||
use brk_oracle::Histogram;
|
||||
use brk_rpc::Client;
|
||||
use brk_types::{
|
||||
AddrBytes, AddrMempoolStats, BlockTemplate, BlockTemplateDiff, FeeRate, MempoolBlock,
|
||||
MempoolInfo, MempoolRecentTx, NextBlockHash, OutpointPrefix, Timestamp, Transaction, TxOut,
|
||||
Txid, TxidPrefix, Vin, Vout,
|
||||
AddrBytes, AddrMempoolStats, BlockTemplate, BlockTemplateDiff, BlockTemplateDiffEntry, FeeRate,
|
||||
MempoolBlock, MempoolInfo, MempoolRecentTx, NextBlockHash, OutpointPrefix, Timestamp,
|
||||
Transaction, TxOut, Txid, TxidPrefix, Vin, Vout,
|
||||
};
|
||||
use parking_lot::{RwLock, RwLockReadGuard};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
@@ -138,18 +138,41 @@ impl Mempool {
|
||||
|
||||
/// Delta of the projected next block since `since`. `None` when
|
||||
/// `since` has aged out of the rebuilder's history (server should
|
||||
/// 404 → client falls back to `block_template`). `removed` is just
|
||||
/// txids; `added` carries full bodies so clients can patch their
|
||||
/// local view in one round trip.
|
||||
/// 404 → client falls back to `block_template`).
|
||||
///
|
||||
/// `order` walks the new template in template order; each entry is
|
||||
/// either a `Retained` index into the prior template (which the
|
||||
/// client cached when it obtained `since`) or a `New` inline body.
|
||||
/// `removed` is the convenience list of txids that left.
|
||||
pub fn block_template_diff(&self, since: NextBlockHash) -> Option<BlockTemplateDiff> {
|
||||
let past = self.0.rebuilder.historical_block0(since)?;
|
||||
let prior_index: FxHashMap<Txid, u32> = past
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, txid)| (*txid, idx as u32))
|
||||
.collect();
|
||||
let snap = self.snapshot();
|
||||
let current: FxHashSet<Txid> = snap.block0_txids().collect();
|
||||
let state = self.read();
|
||||
let mut order = Vec::with_capacity(snap.blocks.first().map_or(0, Vec::len));
|
||||
let mut current: FxHashSet<Txid> = FxHashSet::default();
|
||||
for txid in snap.block0_txids() {
|
||||
current.insert(txid);
|
||||
match prior_index.get(&txid) {
|
||||
Some(&idx) => order.push(BlockTemplateDiffEntry::Retained(idx)),
|
||||
None => {
|
||||
let tx = Self::lookup_body(&state, &txid)
|
||||
.expect("snapshot tx body must be in txs or graveyard");
|
||||
order.push(BlockTemplateDiffEntry::New(tx));
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(state);
|
||||
let removed = past.into_iter().filter(|t| !current.contains(t)).collect();
|
||||
Some(BlockTemplateDiff {
|
||||
hash: snap.next_block_hash,
|
||||
since,
|
||||
added: self.collect_txs(current.difference(&past).copied()),
|
||||
removed: past.difference(¤t).copied().collect(),
|
||||
order,
|
||||
removed,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -157,10 +180,25 @@ impl Mempool {
|
||||
let state = self.read();
|
||||
txids
|
||||
.into_iter()
|
||||
.filter_map(|txid| state.txs.get(&txid).cloned())
|
||||
.map(|txid| {
|
||||
Self::lookup_body(&state, &txid)
|
||||
.expect("snapshot tx body must be in txs or graveyard")
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Body for a txid in a published snapshot. Graveyard fallback
|
||||
/// covers the eviction race: an Applier may have buried the tx
|
||||
/// after the snapshot was built. Burial retention (1h) >> snapshot
|
||||
/// cycle (~1s), so reachability is guaranteed.
|
||||
fn lookup_body(state: &State, txid: &Txid) -> Option<Transaction> {
|
||||
state
|
||||
.txs
|
||||
.get(txid)
|
||||
.or_else(|| state.graveyard.get(txid).map(|t| &t.tx))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn addr_state_hash(&self, addr: &AddrBytes) -> u64 {
|
||||
self.read().addrs.stats_hash(addr)
|
||||
}
|
||||
|
||||
@@ -27,8 +27,10 @@ const HISTORY: usize = 10;
|
||||
#[derive(Default)]
|
||||
pub struct Rebuilder {
|
||||
snapshot: RwLock<Arc<Snapshot>>,
|
||||
/// Past block-0 txid sets keyed by `next_block_hash`, oldest first.
|
||||
history: RwLock<VecDeque<(NextBlockHash, FxHashSet<Txid>)>>,
|
||||
/// Past block-0 txid lists keyed by `next_block_hash`, oldest first.
|
||||
/// Ordered so `block_template_diff` can emit `Retained(prior_index)`
|
||||
/// entries that line up with the client's cached prior template.
|
||||
history: RwLock<VecDeque<(NextBlockHash, Vec<Txid>)>>,
|
||||
rebuild_count: AtomicU64,
|
||||
}
|
||||
|
||||
@@ -40,13 +42,13 @@ impl Rebuilder {
|
||||
/// is the driver loop's job.
|
||||
pub fn tick(&self, lock: &RwLock<State>, gbt_txids: &[Txid], min_fee: FeeRate) {
|
||||
let snap = Self::build_snapshot(lock, gbt_txids, min_fee);
|
||||
let block0_set: FxHashSet<Txid> = snap.block0_txids().collect();
|
||||
let block0: Vec<Txid> = snap.block0_txids().collect();
|
||||
let next_hash = snap.next_block_hash;
|
||||
*self.snapshot.write() = Arc::new(snap);
|
||||
|
||||
let mut hist = self.history.write();
|
||||
hist.retain(|(h, _)| *h != next_hash);
|
||||
hist.push_back((next_hash, block0_set));
|
||||
hist.push_back((next_hash, block0));
|
||||
while hist.len() > HISTORY {
|
||||
hist.pop_front();
|
||||
}
|
||||
@@ -55,15 +57,15 @@ impl Rebuilder {
|
||||
self.rebuild_count.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Past block-0 txid set for `hash`, or `None` if it has aged out
|
||||
/// (or was never seen). Used by `block_template_diff` to decide
|
||||
/// 200 vs 404.
|
||||
pub fn historical_block0(&self, hash: NextBlockHash) -> Option<FxHashSet<Txid>> {
|
||||
/// Past block-0 ordered txid list for `hash`, or `None` if it has
|
||||
/// aged out (or was never seen). Used by `block_template_diff` to
|
||||
/// decide 200 vs 404 and to resolve `Retained(prior_index)` entries.
|
||||
pub fn historical_block0(&self, hash: NextBlockHash) -> Option<Vec<Txid>> {
|
||||
self.history
|
||||
.read()
|
||||
.iter()
|
||||
.find(|(h, _)| *h == hash)
|
||||
.map(|(_, set)| set.clone())
|
||||
.map(|(_, block0)| block0.clone())
|
||||
}
|
||||
|
||||
pub fn rebuild_count(&self) -> u64 {
|
||||
|
||||
Reference in New Issue
Block a user