use std::hash::{DefaultHasher, Hash, Hasher};
use brk_types::{AddrBytes, AddrMempoolStats, Transaction, TxOut, Txid};
use derive_more::Deref;
use rustc_hash::{FxHashMap, FxHashSet};
pub type AddrStats = (AddrMempoolStats, FxHashSet<Txid>);
#[derive(Default, Deref)]
pub struct AddrTracker(FxHashMap<AddrBytes, AddrStats>);
impl AddrTracker {
pub fn add_tx(&mut self, tx: &Transaction, txid: &Txid) {
self.update(tx, txid, true);
}
pub fn remove_tx(&mut self, tx: &Transaction, txid: &Txid) {
self.update(tx, txid, false);
}
pub fn stats_hash(&self, addr: &AddrBytes) -> u64 {
let Some((stats, _)) = self.0.get(addr) else {
return 0;
};
let mut hasher = DefaultHasher::new();
stats.hash(&mut hasher);
hasher.finish()
}
pub fn add_input(&mut self, txid: &Txid, prevout: &TxOut) {
let Some(bytes) = prevout.addr_bytes() else {
return;
};
let (stats, txids) = self.0.entry(bytes).or_default();
txids.insert(txid.clone());
stats.sending(prevout);
stats.update_tx_count(txids.len() as u32);
}
fn update(&mut self, tx: &Transaction, txid: &Txid, is_addition: bool) {
for txin in &tx.input {
let Some(prevout) = txin.prevout.as_ref() else {
continue;
};
let Some(bytes) = prevout.addr_bytes() else {
continue;
};
let (stats, txids) = self.0.entry(bytes).or_default();
if is_addition {
txids.insert(txid.clone());
stats.sending(prevout);
} else {
txids.remove(txid);
stats.sent(prevout);
}
stats.update_tx_count(txids.len() as u32);
}
for txout in &tx.output {
let Some(bytes) = txout.addr_bytes() else {
continue;
};
let (stats, txids) = self.0.entry(bytes).or_default();
if is_addition {
txids.insert(txid.clone());
stats.receiving(txout);
} else {
txids.remove(txid);
stats.received(txout);
}
stats.update_tx_count(txids.len() as u32);
}
}
}