use brk_types::{FeeRate, MempoolBlock, Sats, VSize, get_weighted_percentile};
use super::{SnapTx, TxIndex};
const CORE_PERCENTILES: [f64; 7] = [0.0, 0.10, 0.25, 0.50, 0.75, 0.90, 1.00];
const PROJECTED_PERCENTILES: [f64; 7] = [0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95];
#[derive(Debug, Clone, Default)]
pub struct BlockStats {
pub tx_count: u32,
pub total_size: u64,
pub total_vsize: VSize,
pub total_fee: Sats,
pub fee_range: [FeeRate; 7],
}
impl BlockStats {
pub fn for_blocks(blocks: &[Vec<TxIndex>], txs: &[SnapTx]) -> Vec<Self> {
blocks
.iter()
.enumerate()
.map(|(i, block)| {
let pct = if i == 0 { CORE_PERCENTILES } else { PROJECTED_PERCENTILES };
Self::compute(block, txs, pct)
})
.collect()
}
fn compute(block: &[TxIndex], txs: &[SnapTx], percentiles: [f64; 7]) -> Self {
let mut total_fee = Sats::default();
let mut total_vsize = VSize::default();
let mut total_size: u64 = 0;
let mut rates: Vec<(FeeRate, VSize)> = Vec::with_capacity(block.len());
for &tx_index in block {
let Some(t) = txs.get(tx_index.as_usize()) else {
continue;
};
total_fee += t.fee;
total_vsize += t.vsize;
total_size += t.size;
rates.push((t.chunk_rate, t.vsize));
}
rates.sort_unstable_by_key(|(r, _)| *r);
let fee_range: [FeeRate; 7] = if rates.is_empty() {
[FeeRate::default(); 7]
} else {
percentiles.map(|p| get_weighted_percentile(&rates, p))
};
Self {
tx_count: rates.len() as u32,
total_size,
total_vsize,
total_fee,
fee_range,
}
}
}
impl From<&BlockStats> for MempoolBlock {
fn from(s: &BlockStats) -> Self {
Self::new(s.tx_count, s.total_size, s.total_vsize, s.total_fee, s.fee_range)
}
}