diff --git a/crates/brk_mempool/examples/mempool.rs b/crates/brk_mempool/examples/mempool.rs index 85b1873b5..7a5e9bbd8 100644 --- a/crates/brk_mempool/examples/mempool.rs +++ b/crates/brk_mempool/examples/mempool.rs @@ -32,7 +32,7 @@ fn main() -> Result<()> { "info.count={} txs={} unresolved={} addrs={} outpoints={} \ graveyard.tombstones={} graveyard.order={} \ snap.txs.len={} snap.blocks={} snap.blocks_txs={} \ - rebuilds={} skip.clean={}", + rebuilds={}", info_count, stats.txs, stats.unresolved, @@ -44,7 +44,6 @@ fn main() -> Result<()> { snapshot.blocks.len(), blocks_tx_total, stats.rebuilds, - stats.skip_cleans, ); } } diff --git a/crates/brk_mempool/src/diagnostics.rs b/crates/brk_mempool/src/diagnostics.rs index 4e25aed86..e5ea086ff 100644 --- a/crates/brk_mempool/src/diagnostics.rs +++ b/crates/brk_mempool/src/diagnostics.rs @@ -13,7 +13,6 @@ pub struct MempoolStats { pub graveyard_tombstones: usize, pub graveyard_order: usize, pub rebuilds: u64, - pub skip_cleans: u64, } impl From<&Mempool> for MempoolStats { @@ -28,7 +27,6 @@ impl From<&Mempool> for MempoolStats { graveyard_tombstones: state.graveyard.tombstones_len(), graveyard_order: state.graveyard.order_len(), rebuilds: rebuilder.rebuild_count(), - skip_cleans: rebuilder.skip_clean_count(), } } } diff --git a/crates/brk_mempool/src/lib.rs b/crates/brk_mempool/src/lib.rs index f311d46c0..eea10ab88 100644 --- a/crates/brk_mempool/src/lib.rs +++ b/crates/brk_mempool/src/lib.rs @@ -354,9 +354,9 @@ impl Mempool { min_fee, } = Fetcher::fetch(client, state)?; let pulled = Preparer::prepare(&live_txids, new_entries, new_txs, state); - let changed = Applier::apply(state, rebuilder, pulled); + Applier::apply(state, rebuilder, pulled); Prevouts::fill(state, resolver); - rebuilder.tick(state, changed, &gbt_txids, min_fee); + rebuilder.tick(state, &gbt_txids, min_fee); Ok(()) } diff --git a/crates/brk_mempool/src/steps/applier.rs b/crates/brk_mempool/src/steps/applier.rs index b1da85e82..70b876a60 100644 --- a/crates/brk_mempool/src/steps/applier.rs +++ b/crates/brk_mempool/src/steps/applier.rs @@ -14,23 +14,17 @@ use crate::{ pub struct Applier; impl Applier { - /// Returns true iff anything changed. - /// /// `rebuilder` supplies the previous cycle's snapshot. Burial reads /// each tomb's `chunk_rate` from the snapshot (always-fresh, /// package-aware via local linearization). The fallback to /// `entry.fee_rate()` is unreachable in steady state - every burial /// target was alive at the previous tick, so the snapshot has it. - pub fn apply(lock: &RwLock, rebuilder: &Rebuilder, pulled: TxsPulled) -> bool { + pub fn apply(lock: &RwLock, rebuilder: &Rebuilder, pulled: TxsPulled) { let TxsPulled { added, removed } = pulled; - let has_changes = !added.is_empty() || !removed.is_empty(); - let mut state = lock.write(); Self::bury_removals(&mut state, rebuilder, removed); Self::publish_additions(&mut state, added); state.graveyard.evict_old(); - - has_changes } fn bury_removals( diff --git a/crates/brk_mempool/src/steps/rebuilder/mod.rs b/crates/brk_mempool/src/steps/rebuilder/mod.rs index 86b9355ca..1ab1514cc 100644 --- a/crates/brk_mempool/src/steps/rebuilder/mod.rs +++ b/crates/brk_mempool/src/steps/rebuilder/mod.rs @@ -2,7 +2,7 @@ use std::{ collections::VecDeque, sync::{ Arc, - atomic::{AtomicBool, AtomicU64, Ordering}, + atomic::{AtomicU64, Ordering}, }, }; @@ -29,31 +29,16 @@ pub struct Rebuilder { snapshot: RwLock>, /// Past block-0 txid sets keyed by `next_block_hash`, oldest first. history: RwLock)>>, - dirty: AtomicBool, rebuild_count: AtomicU64, - skip_clean: AtomicU64, } impl Rebuilder { - /// Mark dirty if the cycle changed mempool state, then rebuild iff - /// the dirty bit is set. Cycle pacing is the driver loop's job; the - /// rebuild itself is pure CPU on already-fetched data. The dirty - /// bit is cleared only after the snapshot is published, so a panic - /// in `build_snapshot` retries on the next cycle. - pub fn tick( - &self, - lock: &RwLock, - changed: bool, - gbt_txids: &[Txid], - min_fee: FeeRate, - ) { - if changed { - self.dirty.store(true, Ordering::Release); - } - if !self.dirty.load(Ordering::Acquire) { - self.skip_clean.fetch_add(1, Ordering::Relaxed); - return; - } + /// Rebuild the snapshot every cycle. The build is pure CPU on + /// already-fetched data and `min_fee` participates in the result, + /// so a "skip if no add/remove" gate would freeze the served fees + /// when Core's `mempoolminfee` drifts on a quiet pool. Cycle pacing + /// is the driver loop's job. + pub fn tick(&self, lock: &RwLock, gbt_txids: &[Txid], min_fee: FeeRate) { let snap = Self::build_snapshot(lock, gbt_txids, min_fee); let block0_set: FxHashSet = snap.block0_txids().collect(); let next_hash = snap.next_block_hash; @@ -67,7 +52,6 @@ impl Rebuilder { } drop(hist); - self.dirty.store(false, Ordering::Release); self.rebuild_count.fetch_add(1, Ordering::Relaxed); } @@ -86,10 +70,6 @@ impl Rebuilder { self.rebuild_count.load(Ordering::Relaxed) } - pub fn skip_clean_count(&self) -> u64 { - self.skip_clean.load(Ordering::Relaxed) - } - fn build_snapshot( lock: &RwLock, gbt_txids: &[Txid],