Files
brk/crates/brk_computer/src/distribution/block/cache/lookup.rs
T
2026-03-28 11:56:51 +01:00

107 lines
4.0 KiB
Rust

use brk_types::{EmptyAddrData, FundedAddrData, OutputType, TypeIndex};
use crate::distribution::addr::AddrTypeToTypeIndexMap;
use super::super::cohort::WithAddrDataSource;
/// Tracking status of an address - determines cohort update strategy.
#[derive(Clone, Copy)]
pub enum TrackingStatus {
/// Brand new address (never seen before)
New,
/// Already tracked in a cohort (has existing balance)
Tracked,
/// Was in empty cache, now rejoining a cohort
WasEmpty,
}
/// Context for looking up and storing address data during block processing.
pub struct AddrLookup<'a> {
pub funded: &'a mut AddrTypeToTypeIndexMap<WithAddrDataSource<FundedAddrData>>,
pub empty: &'a mut AddrTypeToTypeIndexMap<WithAddrDataSource<EmptyAddrData>>,
}
impl<'a> AddrLookup<'a> {
pub(crate) fn get_or_create_for_receive(
&mut self,
output_type: OutputType,
type_index: TypeIndex,
) -> (&mut WithAddrDataSource<FundedAddrData>, TrackingStatus) {
use std::collections::hash_map::Entry;
let map = self.funded.get_mut(output_type).unwrap();
match map.entry(type_index) {
Entry::Occupied(entry) => {
// Addr is in cache. Need to determine if it's been processed
// by process_received (added to a cohort) or just funded this block.
//
// - If wrapper is New AND funded_txo_count == 0: hasn't received yet,
// was just created in process_outputs this block → New
// - If wrapper is New AND funded_txo_count > 0: received in previous
// block but still in cache (no flush) → Tracked
// - If wrapper is FromFunded: funded from storage → Tracked
// - If wrapper is FromEmpty AND utxo_count == 0: still empty → WasEmpty
// - If wrapper is FromEmpty AND utxo_count > 0: already received → Tracked
let status = match entry.get() {
WithAddrDataSource::New(data) => {
if data.funded_txo_count == 0 {
TrackingStatus::New
} else {
TrackingStatus::Tracked
}
}
WithAddrDataSource::FromFunded(..) => TrackingStatus::Tracked,
WithAddrDataSource::FromEmpty(_, data) => {
if data.utxo_count() == 0 {
TrackingStatus::WasEmpty
} else {
TrackingStatus::Tracked
}
}
};
(entry.into_mut(), status)
}
Entry::Vacant(entry) => {
if let Some(empty_data) =
self.empty.get_mut(output_type).unwrap().remove(&type_index)
{
return (entry.insert(empty_data.into()), TrackingStatus::WasEmpty);
}
(
entry.insert(WithAddrDataSource::New(FundedAddrData::default())),
TrackingStatus::New,
)
}
}
}
/// Get address data for a send operation (must exist in cache).
pub(crate) fn get_for_send(
&mut self,
output_type: OutputType,
type_index: TypeIndex,
) -> &mut WithAddrDataSource<FundedAddrData> {
self.funded
.get_mut(output_type)
.unwrap()
.get_mut(&type_index)
.expect("Addr must exist for send")
}
/// Move address from funded to empty set.
pub(crate) fn move_to_empty(&mut self, output_type: OutputType, type_index: TypeIndex) {
let data = self
.funded
.get_mut(output_type)
.unwrap()
.remove(&type_index)
.unwrap();
self.empty
.get_mut(output_type)
.unwrap()
.insert(type_index, data.into());
}
}