use brk_types::{FeeRate, Sats, VSize};
use crate::{entry::Entry, types::SelectedTx};
#[derive(Debug, Clone, Default)]
pub struct BlockStats {
pub tx_count: u32,
pub total_vsize: VSize,
pub total_fee: Sats,
pub fee_range: [FeeRate; 7],
}
impl BlockStats {
pub fn min_fee_rate(&self) -> FeeRate {
self.fee_range[0]
}
pub fn median_fee_rate(&self) -> FeeRate {
self.fee_range[3]
}
pub fn max_fee_rate(&self) -> FeeRate {
self.fee_range[6]
}
}
pub fn compute_block_stats(selected: &[SelectedTx], entries: &[Option<Entry>]) -> BlockStats {
if selected.is_empty() {
return BlockStats::default();
}
let mut total_fee = Sats::default();
let mut total_vsize = VSize::default();
let mut fee_rates: Vec<FeeRate> = Vec::with_capacity(selected.len());
for sel in selected {
if let Some(entry) = &entries[sel.tx_index.as_usize()] {
total_fee += entry.fee;
total_vsize += entry.vsize;
fee_rates.push(sel.effective_fee_rate);
}
}
fee_rates.sort_unstable();
BlockStats {
tx_count: selected.len() as u32,
total_vsize,
total_fee,
fee_range: [
percentile(&fee_rates, 0),
percentile(&fee_rates, 10),
percentile(&fee_rates, 25),
percentile(&fee_rates, 50),
percentile(&fee_rates, 75),
percentile(&fee_rates, 90),
percentile(&fee_rates, 100),
],
}
}
fn percentile(sorted: &[FeeRate], p: usize) -> FeeRate {
if sorted.is_empty() {
return FeeRate::default();
}
let idx = (p * (sorted.len() - 1)) / 100;
sorted[idx]
}