use brk_types::{FundedAddrData, Height, OutputType, Sats};
use crate::distribution::{block::TrackingStatus, vecs::AddrMetricsVecs};
use super::{AddrTypeToActivityCounts, AddrTypeToAddrCount, ExposedAddrState, ReusedAddrState};
#[derive(Debug, Default)]
pub struct AddrMetricsState {
pub funded: AddrTypeToAddrCount,
pub empty: AddrTypeToAddrCount,
pub activity: AddrTypeToActivityCounts,
pub reused: ReusedAddrState,
pub respent: ReusedAddrState,
pub exposed: ExposedAddrState,
}
#[derive(Debug)]
pub struct AddrReceivePreState {
pub was_funded: bool,
pub was_reused: bool,
pub was_respent: bool,
pub was_pubkey_exposed: bool,
pub prev_funded_txo_count: u32,
pub exposed_contribution: Sats,
pub reused_contribution: Sats,
pub respent_contribution: Sats,
}
impl AddrReceivePreState {
#[inline]
pub fn capture(addr_data: &FundedAddrData, output_type: OutputType) -> Self {
Self {
was_funded: addr_data.is_funded(),
was_reused: addr_data.is_reused(),
was_respent: addr_data.is_respent(),
was_pubkey_exposed: addr_data.is_pubkey_exposed(output_type),
prev_funded_txo_count: addr_data.funded_txo_count,
exposed_contribution: addr_data.exposed_supply_contribution(output_type),
reused_contribution: addr_data.reused_supply_contribution(),
respent_contribution: addr_data.respent_supply_contribution(),
}
}
}
#[derive(Debug)]
pub struct AddrSendPreState {
pub was_reused: bool,
pub was_respent: bool,
pub was_pubkey_exposed: bool,
pub exposed_contribution: Sats,
pub reused_contribution: Sats,
pub respent_contribution: Sats,
}
impl AddrSendPreState {
#[inline]
pub fn capture(addr_data: &FundedAddrData, output_type: OutputType) -> Self {
Self {
was_reused: addr_data.is_reused(),
was_respent: addr_data.is_respent(),
was_pubkey_exposed: addr_data.is_pubkey_exposed(output_type),
exposed_contribution: addr_data.exposed_supply_contribution(output_type),
reused_contribution: addr_data.reused_supply_contribution(),
respent_contribution: addr_data.respent_supply_contribution(),
}
}
}
impl AddrMetricsState {
#[inline]
pub(crate) fn reset_per_block(&mut self) {
self.activity.reset();
self.reused.reset_per_block();
self.respent.reset_per_block();
}
#[inline]
pub(crate) fn on_receive_applied(
&mut self,
output_type: OutputType,
status: TrackingStatus,
addr_data: &FundedAddrData,
pre: &AddrReceivePreState,
output_count: u32,
) {
let activity = self.activity.get_mut_unwrap(output_type);
activity.receiving += 1;
match status {
TrackingStatus::New => {
*self.funded.get_mut_unwrap(output_type) += 1;
}
TrackingStatus::WasEmpty => {
activity.reactivated += 1;
*self.funded.get_mut_unwrap(output_type) += 1;
*self.empty.get_mut_unwrap(output_type) -= 1;
}
TrackingStatus::Tracked => {}
}
self.reused
.on_receive_as_reused(output_type, addr_data, pre, output_count);
self.respent
.on_receive_as_respent(output_type, addr_data, pre, output_count);
self.exposed.on_receive(output_type, addr_data, pre, status);
}
#[inline]
pub(crate) fn on_send_applied(
&mut self,
output_type: OutputType,
addr_data: &FundedAddrData,
pre: &AddrSendPreState,
is_first_encounter: bool,
also_received: bool,
will_be_empty: bool,
) {
if is_first_encounter {
let activity = self.activity.get_mut_unwrap(output_type);
activity.sending += 1;
if also_received {
activity.bidirectional += 1;
}
}
if will_be_empty {
*self.funded.get_mut_unwrap(output_type) -= 1;
*self.empty.get_mut_unwrap(output_type) += 1;
}
self.reused.on_send_as_reused(
output_type,
addr_data,
pre,
is_first_encounter,
also_received,
will_be_empty,
);
self.respent.on_send_as_respent(
output_type,
addr_data,
pre,
is_first_encounter,
also_received,
will_be_empty,
);
self.exposed
.on_send(output_type, addr_data, pre, will_be_empty);
}
}
impl From<(&AddrMetricsVecs, Height)> for AddrMetricsState {
#[inline]
fn from((vecs, starting_height): (&AddrMetricsVecs, Height)) -> Self {
Self {
funded: AddrTypeToAddrCount::from((&vecs.funded, starting_height)),
empty: AddrTypeToAddrCount::from((&vecs.empty, starting_height)),
activity: AddrTypeToActivityCounts::default(),
reused: ReusedAddrState::from((&vecs.reused, starting_height)),
respent: ReusedAddrState::from((&vecs.respent, starting_height)),
exposed: ExposedAddrState::from((&vecs.exposed, starting_height)),
}
}
}