global: snapshot

This commit is contained in:
nym21
2026-03-11 16:11:20 +01:00
parent 984122f394
commit 71dd7e9852
36 changed files with 752 additions and 681 deletions

View File

@@ -1,7 +1,7 @@
use std::path::Path;
use brk_cohort::{
AddressGroups, ByAmountRange, ByGreatEqualAmount, ByLowerThanAmount, Filter, Filtered,
AddressGroups, AmountRange, OverAmount, UnderAmount, Filter, Filtered,
};
use brk_error::Result;
use brk_traversable::Traversable;
@@ -41,9 +41,9 @@ impl AddressCohorts {
let none = |f: Filter, name: &'static str| create(f, name, false);
Ok(Self(AddressGroups {
amount_range: ByAmountRange::try_new(&full)?,
lt_amount: ByLowerThanAmount::try_new(&none)?,
ge_amount: ByGreatEqualAmount::try_new(&none)?,
amount_range: AmountRange::try_new(&full)?,
under_amount: UnderAmount::try_new(&none)?,
over_amount: OverAmount::try_new(&none)?,
}))
}
@@ -56,9 +56,9 @@ impl AddressCohorts {
let pairs: Vec<_> = self
.0
.ge_amount
.over_amount
.iter_mut()
.chain(self.0.lt_amount.iter_mut())
.chain(self.0.under_amount.iter_mut())
.map(|vecs| {
let filter = vecs.filter().clone();
(

View File

@@ -1,8 +1,8 @@
use std::path::Path;
use brk_cohort::{
ByAgeRange, ByAmountRange, ByClass, ByEpoch, ByGreatEqualAmount, ByLowerThanAmount, ByMaxAge,
ByMinAge, BySpendableType, CohortContext, Filter, Filtered, Term,
AgeRange, AmountRange, Class, ByEpoch, OverAmount, UnderAmount, UnderAge,
OverAge, SpendableType, CohortContext, Filter, Filtered, Term,
};
use brk_error::Result;
use brk_traversable::Traversable;
@@ -39,18 +39,18 @@ pub struct UTXOCohorts<M: StorageMode = Rw> {
pub all: UTXOCohortVecs<AllCohortMetrics<M>>,
pub sth: UTXOCohortVecs<ExtendedAdjustedCohortMetrics<M>>,
pub lth: UTXOCohortVecs<ExtendedCohortMetrics<M>>,
pub age_range: ByAgeRange<UTXOCohortVecs<BasicCohortMetrics<M>>>,
pub max_age: ByMaxAge<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub min_age: ByMinAge<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub age_range: AgeRange<UTXOCohortVecs<BasicCohortMetrics<M>>>,
pub under_age: UnderAge<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub over_age: OverAge<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub epoch: ByEpoch<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub class: ByClass<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub ge_amount: ByGreatEqualAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub amount_range: ByAmountRange<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub lt_amount: ByLowerThanAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub class: Class<UTXOCohortVecs<CoreCohortMetrics<M>>>,
pub over_amount: OverAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub amount_range: AmountRange<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub under_amount: UnderAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
#[traversable(rename = "type")]
pub type_: BySpendableType<UTXOCohortVecs<TypeCohortMetrics<M>>>,
pub type_: SpendableType<UTXOCohortVecs<TypeCohortMetrics<M>>>,
pub profitability: ProfitabilityMetrics<M>,
pub matured: ByAgeRange<AmountPerBlock<M>>,
pub matured: AgeRange<AmountPerBlock<M>>,
#[traversable(skip)]
pub(super) fenwick: CostBasisFenwick,
/// Cached partition_point positions for tick_tock boundary searches.
@@ -104,7 +104,7 @@ impl UTXOCohorts<Rw> {
))
};
let age_range = ByAgeRange::try_new(&basic_separate)?;
let age_range = AgeRange::try_new(&basic_separate)?;
let core_separate =
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<CoreCohortMetrics>> {
@@ -124,7 +124,7 @@ impl UTXOCohorts<Rw> {
};
let epoch = ByEpoch::try_new(&core_separate)?;
let class = ByClass::try_new(&core_separate)?;
let class = Class::try_new(&core_separate)?;
// Helper for separate cohorts with MinimalCohortMetrics + MinimalRealizedState
let minimal_separate =
@@ -144,7 +144,7 @@ impl UTXOCohorts<Rw> {
))
};
let amount_range = ByAmountRange::try_new(&minimal_separate)?;
let amount_range = AmountRange::try_new(&minimal_separate)?;
let type_separate =
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<TypeCohortMetrics>> {
@@ -163,7 +163,7 @@ impl UTXOCohorts<Rw> {
))
};
let type_ = BySpendableType::try_new(&type_separate)?;
let type_ = SpendableType::try_new(&type_separate)?;
// Phase 3: Import "all" cohort with pre-imported supply.
let all = UTXOCohortVecs::new(
@@ -221,11 +221,11 @@ impl UTXOCohorts<Rw> {
))
};
// max_age: CoreCohortMetrics (no state, aggregates from age_range)
let max_age = ByMaxAge::try_new(&core_no_state)?;
// under_age: CoreCohortMetrics (no state, aggregates from age_range)
let under_age = UnderAge::try_new(&core_no_state)?;
// min_age: CoreCohortMetrics (no state, aggregates from age_range)
let min_age = ByMinAge::try_new(&core_no_state)?;
// over_age: CoreCohortMetrics (no state, aggregates from age_range)
let over_age = OverAge::try_new(&core_no_state)?;
let minimal_no_state =
|f: Filter, name: &'static str| -> Result<UTXOCohortVecs<MinimalCohortMetrics>> {
@@ -243,10 +243,10 @@ impl UTXOCohorts<Rw> {
))
};
let lt_amount = ByLowerThanAmount::try_new(&minimal_no_state)?;
let ge_amount = ByGreatEqualAmount::try_new(&minimal_no_state)?;
let under_amount = UnderAmount::try_new(&minimal_no_state)?;
let over_amount = OverAmount::try_new(&minimal_no_state)?;
let matured = ByAgeRange::try_new(&|_f: Filter,
let matured = AgeRange::try_new(&|_f: Filter,
name: &'static str|
-> Result<AmountPerBlock> {
AmountPerBlock::forced_import(db, &format!("utxo_{name}_matured"), v, indexes)
@@ -259,12 +259,12 @@ impl UTXOCohorts<Rw> {
epoch,
class,
type_,
max_age,
min_age,
under_age,
over_age,
age_range,
amount_range,
lt_amount,
ge_amount,
under_amount,
over_amount,
profitability,
matured,
fenwick: CostBasisFenwick::new(),
@@ -325,7 +325,7 @@ impl UTXOCohorts<Rw> {
pub(crate) fn push_maturation(
&mut self,
height: Height,
matured: &ByAgeRange<Sats>,
matured: &AgeRange<Sats>,
) -> Result<()> {
for (v, &sats) in self.matured.iter_mut().zip(matured.iter()) {
v.sats.height.truncate_push(height, sats)?;
@@ -398,11 +398,11 @@ impl UTXOCohorts<Rw> {
sth,
lth,
age_range,
max_age,
min_age,
ge_amount,
under_age,
over_age,
over_amount,
amount_range,
lt_amount,
under_amount,
..
} = self;
@@ -424,21 +424,21 @@ impl UTXOCohorts<Rw> {
lth.metrics.compute_base_from_others(si, &sources, exit)
}),
Box::new(|| {
min_age.par_iter_mut().try_for_each(|vecs| {
over_age.par_iter_mut().try_for_each(|vecs| {
let sources = filter_sources_from(ar.iter(), Some(&vecs.metrics.filter));
vecs.metrics.compute_from_base_sources(si, &sources, exit)
})
}),
Box::new(|| {
max_age.par_iter_mut().try_for_each(|vecs| {
under_age.par_iter_mut().try_for_each(|vecs| {
let sources = filter_sources_from(ar.iter(), Some(&vecs.metrics.filter));
vecs.metrics.compute_from_base_sources(si, &sources, exit)
})
}),
Box::new(|| {
ge_amount
over_amount
.par_iter_mut()
.chain(lt_amount.par_iter_mut())
.chain(under_amount.par_iter_mut())
.try_for_each(|vecs| {
let sources =
filter_minimal_sources_from(amr.iter(), Some(&vecs.metrics.filter));
@@ -471,10 +471,10 @@ impl UTXOCohorts<Rw> {
all.push(&mut self.all);
all.push(&mut self.sth);
all.push(&mut self.lth);
all.extend(self.max_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
all.extend(self.min_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
all.extend(self.under_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
all.extend(self.over_age.iter_mut().map(|x| x as &mut dyn DynCohortVecs));
all.extend(
self.ge_amount
self.over_amount
.iter_mut()
.map(|x| x as &mut dyn DynCohortVecs),
);
@@ -491,7 +491,7 @@ impl UTXOCohorts<Rw> {
.map(|x| x as &mut dyn DynCohortVecs),
);
all.extend(
self.lt_amount
self.under_amount
.iter_mut()
.map(|x| x as &mut dyn DynCohortVecs),
);
@@ -563,11 +563,11 @@ impl UTXOCohorts<Rw> {
sth,
lth,
age_range,
max_age,
min_age,
ge_amount,
under_age,
over_age,
over_amount,
amount_range,
lt_amount,
under_amount,
epoch,
class,
type_,
@@ -610,19 +610,19 @@ impl UTXOCohorts<Rw> {
})
}),
Box::new(|| {
max_age.par_iter_mut().try_for_each(|v| {
under_age.par_iter_mut().try_for_each(|v| {
v.metrics
.compute_rest_part2(blocks, prices, starting_indexes, ss, exit)
})
}),
Box::new(|| {
min_age.par_iter_mut().try_for_each(|v| {
over_age.par_iter_mut().try_for_each(|v| {
v.metrics
.compute_rest_part2(blocks, prices, starting_indexes, ss, exit)
})
}),
Box::new(|| {
ge_amount
over_amount
.par_iter_mut()
.try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit))
}),
@@ -644,7 +644,7 @@ impl UTXOCohorts<Rw> {
.try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit))
}),
Box::new(|| {
lt_amount
under_amount
.par_iter_mut()
.try_for_each(|v| v.metrics.compute_rest_part2(prices, starting_indexes, exit))
}),
@@ -674,13 +674,13 @@ impl UTXOCohorts<Rw> {
for v in self.age_range.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut());
}
for v in self.max_age.iter_mut() {
for v in self.under_age.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut());
}
for v in self.min_age.iter_mut() {
for v in self.over_age.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut());
}
for v in self.ge_amount.iter_mut() {
for v in self.over_amount.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut());
}
for v in self.epoch.iter_mut() {
@@ -692,7 +692,7 @@ impl UTXOCohorts<Rw> {
for v in self.amount_range.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut());
}
for v in self.lt_amount.iter_mut() {
for v in self.under_amount.iter_mut() {
vecs.extend(v.metrics.collect_all_vecs_mut());
}
for v in self.type_.iter_mut() {
@@ -764,10 +764,10 @@ impl UTXOCohorts<Rw> {
self.all.metrics.validate_computed_versions(base_version)?;
self.sth.metrics.validate_computed_versions(base_version)?;
self.lth.metrics.validate_computed_versions(base_version)?;
for v in self.min_age.iter_mut() {
for v in self.over_age.iter_mut() {
v.metrics.validate_computed_versions(base_version)?;
}
for v in self.max_age.iter_mut() {
for v in self.under_age.iter_mut() {
v.metrics.validate_computed_versions(base_version)?;
}
Ok(())

View File

@@ -121,8 +121,8 @@ fn push_profitability(
bucket.truncate_push(height, Sats::from(sats), raw_usd_to_dollars(usd_raw))?;
}
// ByProfit: forward cumulative sum over ranges[0..15], pushed in reverse.
// profit[0] (breakeven) = sum(0..=14), ..., profit[14] (_1000pct) = ranges[0]
// Profit: forward cumulative sum over ranges[0..15], pushed in reverse.
// profit[0] (breakeven) = sum(0..=13), ..., profit[13] (_500pct) = ranges[0]
let profit_arr = metrics.profit.as_array_mut();
let mut cum_sats = 0u64;
let mut cum_usd = 0u128;
@@ -133,8 +133,8 @@ fn push_profitability(
.truncate_push(height, Sats::from(cum_sats), raw_usd_to_dollars(cum_usd))?;
}
// ByLoss: backward cumulative sum over ranges[15..25], pushed in reverse.
// loss[0] (breakeven) = sum(15..=24), ..., loss[9] (_90pct) = ranges[24]
// Loss: backward cumulative sum over ranges[15..25], pushed in reverse.
// loss[0] (breakeven) = sum(15..=24), ..., loss[8] (_80pct) = ranges[24]
let loss_arr = metrics.loss.as_array_mut();
let loss_count = loss_arr.len();
cum_sats = 0;

View File

@@ -1,4 +1,4 @@
use brk_cohort::{AGE_BOUNDARIES, ByAgeRange};
use brk_cohort::{AGE_BOUNDARIES, AgeRange};
use brk_types::{CostBasisSnapshot, ONE_HOUR_IN_SEC, Sats, Timestamp};
use vecdb::{Rw, unlikely};
@@ -22,9 +22,9 @@ impl UTXOCohorts<Rw> {
&mut self,
chain_state: &[BlockState],
timestamp: Timestamp,
) -> ByAgeRange<Sats> {
) -> AgeRange<Sats> {
if chain_state.is_empty() {
return ByAgeRange::default();
return AgeRange::default();
}
let prev_timestamp = chain_state.last().unwrap().timestamp;
@@ -32,7 +32,7 @@ impl UTXOCohorts<Rw> {
// Skip if no time has passed
if elapsed == 0 {
return ByAgeRange::default();
return AgeRange::default();
}
let mut matured = [Sats::ZERO; 21];
@@ -96,6 +96,6 @@ impl UTXOCohorts<Rw> {
}
}
ByAgeRange::from_array(matured)
AgeRange::from_array(matured)
}
}

View File

@@ -62,7 +62,7 @@ impl CoreCohortMetrics {
vecs
}
/// Aggregate Core-tier fields from CohortMetricsBase sources (e.g. age_range → max_age/min_age).
/// Aggregate Core-tier fields from CohortMetricsBase sources (e.g. age_range → under_age/over_age).
pub(crate) fn compute_from_base_sources<T: CohortMetricsBase>(
&mut self,
starting_indexes: &Indexes,

View File

@@ -1,4 +1,4 @@
use brk_cohort::{ByLoss, ByProfit, ByProfitabilityRange};
use brk_cohort::{Loss, Profit, ProfitabilityRange};
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, Sats, Version};
@@ -66,9 +66,9 @@ impl ProfitabilityBucket {
/// All profitability metrics: 25 ranges + 15 profit thresholds + 10 loss thresholds.
#[derive(Traversable)]
pub struct ProfitabilityMetrics<M: StorageMode = Rw> {
pub range: ByProfitabilityRange<ProfitabilityBucket<M>>,
pub profit: ByProfit<ProfitabilityBucket<M>>,
pub loss: ByLoss<ProfitabilityBucket<M>>,
pub range: ProfitabilityRange<ProfitabilityBucket<M>>,
pub profit: Profit<ProfitabilityBucket<M>>,
pub loss: Loss<ProfitabilityBucket<M>>,
}
impl<M: StorageMode> ProfitabilityMetrics<M> {
@@ -88,15 +88,15 @@ impl ProfitabilityMetrics {
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let range = ByProfitabilityRange::try_new(|name| {
let range = ProfitabilityRange::try_new(|name| {
ProfitabilityBucket::forced_import(db, name, version, indexes)
})?;
let profit = ByProfit::try_new(|name| {
let profit = Profit::try_new(|name| {
ProfitabilityBucket::forced_import(db, name, version, indexes)
})?;
let loss = ByLoss::try_new(|name| {
let loss = Loss::try_new(|name| {
ProfitabilityBucket::forced_import(db, name, version, indexes)
})?;

View File

@@ -151,7 +151,7 @@ impl RealizedOps for MinimalRealizedState {
}
/// Core realized state: extends Minimal with sent_in_profit/loss tracking.
/// Used by CoreCohortMetrics cohorts (epoch, class, max_age, min_age — ~59 separate cohorts).
/// Used by CoreCohortMetrics cohorts (epoch, class, under_age, over_age — ~59 separate cohorts).
#[derive(Debug, Default, Clone)]
pub struct CoreRealizedState {
minimal: MinimalRealizedState,

View File

@@ -1,14 +1,14 @@
use std::ops::{Add, AddAssign};
use brk_cohort::{ByAmountRange, GroupedByType};
use brk_cohort::{AmountRange, ByType};
use brk_types::{OutputType, Sats, SupplyState};
use vecdb::unlikely;
#[derive(Default, Debug)]
pub struct Transacted {
pub spendable_supply: SupplyState,
pub by_type: GroupedByType<SupplyState>,
pub by_size_group: ByAmountRange<SupplyState>,
pub by_type: ByType<SupplyState>,
pub by_size_group: AmountRange<SupplyState>,
}
impl Transacted {