use std::collections::BinaryHeap;
use brk_types::FeeRate;
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
use super::{BLOCK_VSIZE, graph::Graph, heap_entry::HeapEntry, package::Package};
use crate::types::PoolIndex;
pub fn select_packages(graph: &mut Graph, num_blocks: usize) -> Vec<Package> {
let target_vsize = BLOCK_VSIZE * num_blocks as u64;
let mut total_vsize: u64 = 0;
let mut packages: Vec<Package> = Vec::new();
let mut heap: BinaryHeap<HeapEntry> = (0..graph.len())
.map(|i| HeapEntry::new(&graph[PoolIndex::from(i)]))
.collect();
while let Some(entry) = heap.pop() {
let node = &graph[entry.pool_index];
if node.selected {
continue;
}
let package_rate = FeeRate::from((node.ancestor_fee, node.ancestor_vsize));
let ancestors = select_with_ancestors(graph, entry.pool_index);
let mut package = Package::new(package_rate);
for pool_idx in ancestors {
let vsize = u64::from(graph[pool_idx].vsize);
package.add_tx(graph[pool_idx].tx_index, vsize);
update_descendants(graph, pool_idx, &mut heap);
}
total_vsize += package.vsize;
packages.push(package);
if total_vsize >= target_vsize {
break;
}
}
packages
}
fn select_with_ancestors(graph: &mut Graph, pool_idx: PoolIndex) -> SmallVec<[PoolIndex; 8]> {
let mut result: SmallVec<[PoolIndex; 8]> = SmallVec::new();
let mut stack: SmallVec<[(PoolIndex, bool); 16]> = smallvec::smallvec![(pool_idx, false)];
while let Some((idx, parents_done)) = stack.pop() {
if graph[idx].selected {
continue;
}
if parents_done {
graph[idx].selected = true;
result.push(idx);
} else {
stack.push((idx, true));
for &parent in &graph[idx].parents {
if !graph[parent].selected {
stack.push((parent, false));
}
}
}
}
result
}
fn update_descendants(
graph: &mut Graph,
selected_idx: PoolIndex,
heap: &mut BinaryHeap<HeapEntry>,
) {
let selected_fee = graph[selected_idx].fee;
let selected_vsize = graph[selected_idx].vsize;
let mut visited: FxHashSet<PoolIndex> = FxHashSet::default();
let mut stack: SmallVec<[PoolIndex; 16]> =
graph[selected_idx].children.iter().copied().collect();
while let Some(child_idx) = stack.pop() {
if !visited.insert(child_idx) {
continue;
}
let child = &mut graph[child_idx];
if child.selected {
continue;
}
child.ancestor_fee -= selected_fee;
child.ancestor_vsize -= selected_vsize;
child.generation += 1;
heap.push(HeapEntry::new(child));
stack.extend(child.children.iter().copied());
}
}