mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -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();
|
||||
(
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
})?;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user