computer: snapshot

This commit is contained in:
nym21
2026-03-09 01:37:08 +01:00
parent c2240c7a60
commit 0bff57fb43
7 changed files with 119 additions and 19 deletions

View File

@@ -17,7 +17,7 @@ use crate::{
metrics::{
AllCohortMetrics, BasicCohortMetrics, CohortMetricsBase, CoreCohortMetrics,
ExtendedAdjustedCohortMetrics, ExtendedCohortMetrics, ImportConfig,
MinimalCohortMetrics, ProfitabilityMetrics, SupplyMetrics,
MinimalCohortMetrics, ProfitabilityMetrics, RealizedFullAccum, SupplyMetrics,
},
state::UTXOCohortState,
},
@@ -44,6 +44,7 @@ pub struct UTXOCohorts<M: StorageMode = Rw> {
pub ge_amount: ByGreatEqualAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub amount_range: ByAmountRange<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub lt_amount: ByLowerThanAmount<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
#[traversable(rename = "type")]
pub type_: BySpendableType<UTXOCohortVecs<MinimalCohortMetrics<M>>>,
pub profitability: ProfitabilityMetrics<M>,
pub matured: ByAgeRange<ValueFromHeight<M>>,
@@ -707,7 +708,7 @@ impl UTXOCohorts<Rw> {
.try_for_each(|v| v.write_state(height, cleanup))
}
/// Get minimum height from all separate cohorts' + profitability height-indexed vectors.
/// Get minimum height from all separate cohorts' + profitability + overlapping realized height-indexed vectors.
pub(crate) fn min_separate_stateful_height_len(&self) -> Height {
self.iter_separate()
.map(|v| Height::from(v.min_stateful_height_len()))
@@ -715,6 +716,9 @@ impl UTXOCohorts<Rw> {
.min()
.unwrap_or_default()
.min(Height::from(self.profitability.min_stateful_height_len()))
.min(Height::from(self.all.metrics.realized.min_stateful_height_len()))
.min(Height::from(self.sth.metrics.realized.min_stateful_height_len()))
.min(Height::from(self.lth.metrics.realized.min_stateful_height_len()))
}
/// Import state for all separate cohorts at or before given height.
@@ -761,6 +765,38 @@ impl UTXOCohorts<Rw> {
}
Ok(())
}
/// Aggregate RealizedFull fields from age_range states and push to all/sth/lth.
/// Called during the block loop after separate cohorts' truncate_push but before reset.
pub(crate) fn push_overlapping_realized_full(&mut self, height: Height) -> Result<()> {
let Self {
all, sth, lth, age_range, ..
} = self;
let sth_filter = &sth.metrics.filter;
let mut all_acc = RealizedFullAccum::default();
let mut sth_acc = RealizedFullAccum::default();
let mut lth_acc = RealizedFullAccum::default();
for ar in age_range.iter() {
if let Some(state) = ar.state.as_ref() {
let r = &state.realized;
all_acc.add(r);
if sth_filter.includes(&ar.metrics.filter) {
sth_acc.add(r);
} else {
lth_acc.add(r);
}
}
}
all.metrics.realized.push_from_accum(&all_acc, height)?;
sth.metrics.realized.push_from_accum(&sth_acc, height)?;
lth.metrics.realized.push_from_accum(&lth_acc, height)?;
Ok(())
}
}
/// Filter source cohorts by an optional filter.

View File

@@ -157,10 +157,6 @@ impl<M: CohortMetricsBase + Traversable> DynCohortVecs for UTXOCohortVecs<M> {
) -> Result<()> {
self.metrics
.compute_rest_part1(blocks, prices, starting_indexes, exit)?;
if self.state.is_some() {
self.metrics
.compute_net_sentiment_height(starting_indexes, exit)?;
}
Ok(())
}

View File

@@ -506,6 +506,7 @@ fn push_cohort_states(
height_price: Cents,
is_day_boundary: bool,
) -> Result<()> {
// Phase 1: push + unrealized (no reset yet — states still needed for aggregation)
let (r1, r2) = rayon::join(
|| {
utxo_cohorts
@@ -517,7 +518,6 @@ fn push_cohort_states(
height_price,
is_day_boundary,
)?;
v.reset_single_iteration_values();
Ok(())
})
},
@@ -531,12 +531,23 @@ fn push_cohort_states(
height_price,
is_day_boundary,
)?;
v.reset_single_iteration_values();
Ok(())
})
},
);
r1?;
r2?;
// Phase 2: aggregate age_range realized states → push to overlapping cohorts' RealizedFull
utxo_cohorts.push_overlapping_realized_full(height)?;
// Phase 3: reset per-block values
utxo_cohorts
.iter_separate_mut()
.for_each(|v| v.reset_single_iteration_values());
address_cohorts
.iter_separate_mut()
.for_each(|v| v.reset_single_iteration_values());
Ok(())
}

View File

@@ -22,7 +22,6 @@ pub struct ExtendedAdjustedCohortMetrics<M: StorageMode = Rw> {
#[deref_mut]
#[traversable(flatten)]
pub inner: ExtendedCohortMetrics<M>,
#[traversable(flatten)]
pub adjusted: Box<RealizedAdjusted<M>>,
}

View File

@@ -52,7 +52,8 @@ pub use cost_basis::CostBasis;
pub use profitability::ProfitabilityMetrics;
pub use outputs::OutputsMetrics;
pub use realized::{
RealizedAdjusted, RealizedBase, RealizedCore, RealizedFull, RealizedLike, RealizedMinimal,
RealizedAdjusted, RealizedBase, RealizedCore, RealizedFull, RealizedFullAccum, RealizedLike,
RealizedMinimal,
};
pub use relative::{
RelativeForAll, RelativeToAll, RelativeWithExtended,
@@ -189,16 +190,9 @@ pub trait CohortMetricsBase: CohortMetricsState<Realized = RealizedState> + Send
self.unrealized_mut()
.compute_rest(prices, starting_indexes, exit)?;
Ok(())
}
fn compute_net_sentiment_height(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.unrealized_mut()
.compute_net_sentiment_height(starting_indexes, exit)?;
Ok(())
}

View File

@@ -298,6 +298,47 @@ impl RealizedFull {
Ok(())
}
pub(crate) fn push_from_accum(
&mut self,
accum: &RealizedFullAccum,
height: Height,
) -> Result<()> {
self.profit_value_created
.height
.truncate_push(height, accum.profit_value_created)?;
self.profit_value_destroyed
.height
.truncate_push(height, accum.profit_value_destroyed)?;
self.loss_value_created
.height
.truncate_push(height, accum.loss_value_created)?;
self.loss_value_destroyed
.height
.truncate_push(height, accum.loss_value_destroyed)?;
self.cap_raw.truncate_push(height, accum.cap_raw)?;
self.investor_cap_raw
.truncate_push(height, accum.investor_cap_raw)?;
let investor_price = {
let cap = accum.cap_raw.as_u128();
if cap == 0 {
Cents::ZERO
} else {
Cents::new((accum.investor_cap_raw / cap) as u64)
}
};
self.investor_price
.cents
.height
.truncate_push(height, investor_price)?;
self.peak_regret
.height
.truncate_push(height, accum.peak_regret)?;
Ok(())
}
pub(crate) fn compute_rest_part1(
&mut self,
blocks: &blocks::Vecs,
@@ -626,3 +667,26 @@ impl RealizedFull {
Ok(())
}
}
#[derive(Default)]
pub struct RealizedFullAccum {
pub(crate) profit_value_created: Cents,
pub(crate) profit_value_destroyed: Cents,
pub(crate) loss_value_created: Cents,
pub(crate) loss_value_destroyed: Cents,
pub(crate) cap_raw: CentsSats,
pub(crate) investor_cap_raw: CentsSquaredSats,
pub(crate) peak_regret: Cents,
}
impl RealizedFullAccum {
pub(crate) fn add(&mut self, state: &RealizedState) {
self.profit_value_created += state.profit_value_created();
self.profit_value_destroyed += state.profit_value_destroyed();
self.loss_value_created += state.loss_value_created();
self.loss_value_destroyed += state.loss_value_destroyed();
self.cap_raw += state.cap_raw();
self.investor_cap_raw += state.investor_cap_raw();
self.peak_regret += state.peak_regret();
}
}

View File

@@ -7,7 +7,7 @@ mod minimal;
pub use adjusted::RealizedAdjusted;
pub use base::RealizedBase;
pub use self::core::RealizedCore;
pub use full::RealizedFull;
pub use full::{RealizedFull, RealizedFullAccum};
pub use minimal::RealizedMinimal;
use brk_error::Result;