use brk_types::{CpfpClusterChunk, CpfpClusterTxIndex, FeeRate, Sats, VSize};
use rustc_hash::{FxBuildHasher, FxHashSet};
pub struct ChunkInput<'a> {
pub fee: Sats,
pub vsize: VSize,
pub parents: &'a [CpfpClusterTxIndex],
}
pub fn linearize(items: &[ChunkInput<'_>]) -> Vec<CpfpClusterChunk> {
let n = items.len();
if n == 0 {
return Vec::new();
}
let mut remaining: Vec<bool> = vec![true; n];
let mut chunks: Vec<CpfpClusterChunk> = Vec::new();
while remaining.iter().any(|&r| r) {
let mut best: Option<(FeeRate, FxHashSet<u32>)> = None;
for i in 0..n {
if !remaining[i] {
continue;
}
let mut anc: FxHashSet<u32> =
FxHashSet::with_capacity_and_hasher(8, FxBuildHasher);
let mut stack: Vec<u32> = vec![i as u32];
while let Some(x) = stack.pop() {
if !anc.insert(x) {
continue;
}
for &p in items[x as usize].parents {
let pu: u32 = u32::from(p);
if remaining[pu as usize] && !anc.contains(&pu) {
stack.push(pu);
}
}
}
let mut fee = Sats::ZERO;
let mut vsize = VSize::from(0u64);
for &x in &anc {
fee += items[x as usize].fee;
vsize += items[x as usize].vsize;
}
let rate = FeeRate::from((fee, vsize));
match &best {
Some((br, _)) if *br >= rate => {}
_ => best = Some((rate, anc)),
}
}
let (rate, set) = best.expect("at least one remaining tx");
let mut indices: Vec<u32> = set.into_iter().collect();
indices.sort_unstable();
for &x in &indices {
remaining[x as usize] = false;
}
let txs: Vec<CpfpClusterTxIndex> =
indices.into_iter().map(CpfpClusterTxIndex::from).collect();
chunks.push(CpfpClusterChunk { txs, feerate: rate });
}
chunks
}