use std::{
collections::VecDeque,
sync::{
Arc,
atomic::{AtomicU64, Ordering},
},
};
use brk_types::{FeeRate, NextBlockHash, Txid, TxidPrefix};
use parking_lot::RwLock;
use rustc_hash::FxHashSet;
use crate::State;
use super::{Partitioner, Snapshot, TxIndex};
const NUM_BLOCKS: usize = 8;
const HISTORY: usize = 10;
#[derive(Default)]
pub struct Rebuilder {
snapshot: RwLock<Arc<Snapshot>>,
history: RwLock<VecDeque<(NextBlockHash, Vec<Txid>)>>,
rebuild_count: AtomicU64,
}
impl Rebuilder {
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: Vec<Txid> = snap.block0_txids().collect();
let next_hash = snap.next_block_hash;
let mut hist = self.history.write();
hist.retain(|(h, _)| *h != next_hash);
hist.push_back((next_hash, block0));
while hist.len() > HISTORY {
hist.pop_front();
}
drop(hist);
*self.snapshot.write() = Arc::new(snap);
self.rebuild_count.fetch_add(1, Ordering::Relaxed);
}
pub fn historical_block0(&self, hash: NextBlockHash) -> Option<Vec<Txid>> {
self.history
.read()
.iter()
.find(|(h, _)| *h == hash)
.map(|(_, block0)| block0.clone())
}
pub fn rebuild_count(&self) -> u64 {
self.rebuild_count.load(Ordering::Relaxed)
}
fn build_snapshot(
lock: &RwLock<State>,
gbt_txids: &[Txid],
min_fee: FeeRate,
) -> Snapshot {
let (txs, prefix_to_idx) = {
let state = lock.read();
Snapshot::build_txs(&state.txs)
};
let block0: Vec<TxIndex> = gbt_txids
.iter()
.filter_map(|txid| prefix_to_idx.get(&TxidPrefix::from(txid)).copied())
.collect();
let excluded: FxHashSet<TxIndex> = block0.iter().copied().collect();
let rest = Partitioner::partition(&txs, &excluded, NUM_BLOCKS.saturating_sub(1));
let mut blocks = Vec::with_capacity(NUM_BLOCKS);
blocks.push(block0);
blocks.extend(rest);
Snapshot::build(txs, blocks, prefix_to_idx, min_fee)
}
pub fn snapshot(&self) -> Arc<Snapshot> {
self.snapshot.read().clone()
}
}