global: snapshot

This commit is contained in:
nym21
2026-03-18 12:51:31 +01:00
parent b397b811f9
commit 455dc683eb
14 changed files with 198 additions and 329 deletions

View File

@@ -1085,40 +1085,6 @@ pub struct CapGrossInvestorLossMvrvNetPeakPriceProfitSellSoprPattern {
pub sopr: AdjustedRatioValuePattern,
}
/// Pattern struct for repeated tree structure.
pub struct AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern {
pub average: SeriesPattern1<StoredU64>,
pub cumulative: SeriesPattern1<StoredU64>,
pub max: SeriesPattern1<StoredU64>,
pub median: SeriesPattern1<StoredU64>,
pub min: SeriesPattern1<StoredU64>,
pub pct10: SeriesPattern1<StoredU64>,
pub pct25: SeriesPattern1<StoredU64>,
pub pct75: SeriesPattern1<StoredU64>,
pub pct90: SeriesPattern1<StoredU64>,
pub rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern,
pub sum: SeriesPattern1<StoredU64>,
}
impl AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
average: SeriesPattern1::new(client.clone(), _m(&acc, "average")),
cumulative: SeriesPattern1::new(client.clone(), _m(&acc, "cumulative")),
max: SeriesPattern1::new(client.clone(), _m(&acc, "max")),
median: SeriesPattern1::new(client.clone(), _m(&acc, "median")),
min: SeriesPattern1::new(client.clone(), _m(&acc, "min")),
pct10: SeriesPattern1::new(client.clone(), _m(&acc, "pct10")),
pct25: SeriesPattern1::new(client.clone(), _m(&acc, "pct25")),
pct75: SeriesPattern1::new(client.clone(), _m(&acc, "pct75")),
pct90: SeriesPattern1::new(client.clone(), _m(&acc, "pct90")),
rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), acc.clone()),
sum: SeriesPattern1::new(client.clone(), _m(&acc, "sum")),
}
}
}
/// Pattern struct for repeated tree structure.
pub struct AverageBaseCumulativeMaxMedianMinPct10Pct25Pct75Pct90SumPattern2 {
pub average: _1m1w1y24hPattern<StoredU64>,
@@ -2498,6 +2464,24 @@ impl CentsSatsUsdPattern {
}
}
/// Pattern struct for repeated tree structure.
pub struct CumulativeRollingSumPattern {
pub cumulative: SeriesPattern1<StoredU64>,
pub rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern,
pub sum: SeriesPattern1<StoredU64>,
}
impl CumulativeRollingSumPattern {
/// Create a new pattern node with accumulated series name.
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
Self {
cumulative: SeriesPattern1::new(client.clone(), _m(&acc, "cumulative")),
rolling: AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern::new(client.clone(), acc.clone()),
sum: SeriesPattern1::new(client.clone(), _m(&acc, "sum")),
}
}
}
/// Pattern struct for repeated tree structure.
pub struct DeltaHalfTotalPattern {
pub delta: AbsoluteRatePattern,
@@ -3418,7 +3402,7 @@ impl SeriesTree_Transactions_Volume {
pub struct SeriesTree_Inputs {
pub raw: SeriesTree_Inputs_Raw,
pub spent: SeriesTree_Inputs_Spent,
pub count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern,
pub count: CumulativeRollingSumPattern,
}
impl SeriesTree_Inputs {
@@ -3426,7 +3410,7 @@ impl SeriesTree_Inputs {
Self {
raw: SeriesTree_Inputs_Raw::new(client.clone(), format!("{base_path}_raw")),
spent: SeriesTree_Inputs_Spent::new(client.clone(), format!("{base_path}_spent")),
count: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new(client.clone(), "input_count".to_string()),
count: CumulativeRollingSumPattern::new(client.clone(), "input_count".to_string()),
}
}
}
@@ -3520,14 +3504,14 @@ impl SeriesTree_Outputs_Spent {
/// Series tree node.
pub struct SeriesTree_Outputs_Count {
pub total: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern,
pub total: CumulativeRollingSumPattern,
pub unspent: SeriesPattern1<StoredU64>,
}
impl SeriesTree_Outputs_Count {
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
Self {
total: AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern::new(client.clone(), "output_count".to_string()),
total: CumulativeRollingSumPattern::new(client.clone(), "output_count".to_string()),
unspent: SeriesPattern1::new(client.clone(), "utxo_count_bis".to_string()),
}
}

View File

@@ -67,8 +67,8 @@ pub(crate) fn process_blocks(
let height_to_first_txout_index = &indexer.vecs.outputs.first_txout_index;
let height_to_first_txin_index = &indexer.vecs.inputs.first_txin_index;
let height_to_tx_count = &transactions.count.total.base.height;
let height_to_output_count = &outputs.count.total.full.sum.height;
let height_to_input_count = &inputs.count.full.sum.height;
let height_to_output_count = &outputs.count.total.sum.height;
let height_to_input_count = &inputs.count.sum.height;
let tx_index_to_output_count = &indexes.tx_index.output_count;
let tx_index_to_input_count = &indexes.tx_index.input_count;

View File

@@ -16,17 +16,15 @@ impl Vecs {
exit: &Exit,
) -> Result<()> {
let window_starts = blocks.lookback.window_starts();
self.0
.compute(starting_indexes.height, &window_starts, exit, |full| {
full.compute_with_skip(
starting_indexes.height,
&indexes.tx_index.input_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
exit,
0,
)
})?;
self.0.compute(
starting_indexes.height,
&indexes.tx_index.input_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
&window_starts,
exit,
0,
)?;
Ok(())
}

View File

@@ -1,17 +1,15 @@
//! PerBlockAggregated - PerBlockDistributionFull (distribution + sum + cumulative) + RollingComplete.
//!
//! For metrics aggregated per-block from finer-grained sources (e.g., per-tx data),
//! where we want full per-block stats plus rolling window stats.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use brk_types::Height;
use schemars::JsonSchema;
use vecdb::{Database, Exit, Rw, StorageMode};
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, VecIndex, VecValue, Version};
use crate::{
indexes,
internal::{CachedWindowStarts, PerBlockDistributionFull, NumericValue, RollingComplete, WindowStarts},
internal::{
CachedWindowStarts, NumericValue, PerBlock, RollingComplete, WindowStarts,
algo::compute_aggregations,
},
};
#[derive(Traversable)]
@@ -19,8 +17,8 @@ pub struct PerBlockAggregated<T, M: StorageMode = Rw>
where
T: NumericValue + JsonSchema,
{
#[traversable(flatten)]
pub full: PerBlockDistributionFull<T, M>,
pub sum: PerBlock<T, M>,
pub cumulative: PerBlock<T, M>,
pub rolling: RollingComplete<T, M>,
}
@@ -35,34 +33,63 @@ where
indexes: &indexes::Vecs,
cached_starts: &CachedWindowStarts,
) -> Result<Self> {
let full = PerBlockDistributionFull::forced_import(db, name, version, indexes)?;
let sum = PerBlock::forced_import(db, &format!("{name}_sum"), version, indexes)?;
let cumulative =
PerBlock::forced_import(db, &format!("{name}_cumulative"), version, indexes)?;
let rolling = RollingComplete::forced_import(
db,
name,
version,
indexes,
&full.cumulative.height,
&cumulative.height,
cached_starts,
)?;
Ok(Self { full, rolling })
Ok(Self {
sum,
cumulative,
rolling,
})
}
/// Compute PerBlockDistributionFull stats via closure, then rolling distribution from the per-block sum.
pub(crate) fn compute(
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute<A>(
&mut self,
max_from: Height,
source: &impl ReadableVec<A, T>,
first_indexes: &impl ReadableVec<Height, A>,
count_indexes: &impl ReadableVec<Height, brk_types::StoredU64>,
windows: &WindowStarts<'_>,
exit: &Exit,
compute_full: impl FnOnce(&mut PerBlockDistributionFull<T>) -> Result<()>,
skip_count: usize,
) -> Result<()>
where
T: From<f64> + Default + Copy + Ord,
f64: From<T>,
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
{
compute_full(&mut self.full)?;
compute_aggregations(
max_from,
source,
first_indexes,
count_indexes,
exit,
skip_count,
None,
None,
None,
None,
None,
Some(&mut self.sum.height),
Some(&mut self.cumulative.height),
None,
None,
None,
None,
None,
)?;
self.rolling
.compute(max_from, windows, &self.full.sum.height, exit)?;
.compute(max_from, windows, &self.sum.height, exit)?;
Ok(())
}
}

View File

@@ -1,73 +0,0 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::Height;
use schemars::JsonSchema;
use vecdb::{
Database, Exit, ReadableVec, Rw, StorageMode,
VecIndex, VecValue, Version,
};
use crate::{
indexes,
internal::{ComputedVecValue, NumericValue, PerBlock, algo::compute_aggregations},
};
use super::PerBlockDistribution;
#[derive(Traversable)]
pub struct PerBlockDistributionFull<T: ComputedVecValue + PartialOrd + JsonSchema, M: StorageMode = Rw> {
pub sum: PerBlock<T, M>,
pub cumulative: PerBlock<T, M>,
#[traversable(flatten)]
pub distribution: PerBlockDistribution<T, M>,
}
impl<T: NumericValue + JsonSchema> PerBlockDistributionFull<T> {
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self {
distribution: PerBlockDistribution::forced_import(db, name, version, indexes)?,
sum: PerBlock::forced_import(db, &format!("{name}_sum"), version, indexes)?,
cumulative: PerBlock::forced_import(db, &format!("{name}_cumulative"), version, indexes)?,
})
}
pub(crate) fn compute_with_skip<A>(
&mut self,
max_from: Height,
source: &impl ReadableVec<A, T>,
first_indexes: &impl ReadableVec<Height, A>,
count_indexes: &impl ReadableVec<Height, brk_types::StoredU64>,
exit: &Exit,
skip_count: usize,
) -> Result<()>
where
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
{
let d = &mut self.distribution.0;
compute_aggregations(
max_from,
source,
first_indexes,
count_indexes,
exit,
skip_count,
None,
None,
Some(&mut d.min.height),
Some(&mut d.max.height),
Some(&mut d.average.height),
Some(&mut self.sum.height),
Some(&mut self.cumulative.height),
Some(&mut d.median.height),
Some(&mut d.pct10.height),
Some(&mut d.pct25.height),
Some(&mut d.pct75.height),
Some(&mut d.pct90.height),
)
}
}

View File

@@ -3,7 +3,6 @@ mod base;
mod cumulative;
mod cumulative_sum;
mod distribution;
mod distribution_full;
mod full;
mod lazy_distribution;
mod lazy_rolling;
@@ -17,7 +16,6 @@ pub use base::*;
pub use cumulative::*;
pub use cumulative_sum::*;
pub use distribution::*;
pub use distribution_full::*;
pub use full::*;
pub use lazy_distribution::*;
pub use lazy_rolling::*;

View File

@@ -1,5 +1,6 @@
use brk_traversable::Traversable;
use brk_types::{Dollars, Height, StoredF32, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{DeltaChange, DeltaRate, LazyDeltaVec, LazyVecFrom1, ReadableCloneableVec, VecValue};
@@ -7,7 +8,7 @@ use crate::{
indexes,
internal::{
BpsType, CachedWindowStarts, CentsType, DerivedResolutions, LazyPerBlock, NumericValue,
Resolutions, Windows,
Percent, Resolutions, Windows,
},
};
@@ -31,16 +32,14 @@ where
/// Single-slot lazy delta percent: BPS delta + lazy ratio + lazy percent views.
///
/// Mirrors `PercentPerBlock<B>` but with lazy delta for the BPS source.
#[derive(Clone, Traversable)]
pub struct LazyDeltaPercentFromHeight<S, B>
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyDeltaPercentFromHeight<S, B>(
pub Percent<LazyDeltaFromHeight<S, B, DeltaRate>, LazyPerBlock<StoredF32, B>>,
)
where
S: VecValue,
B: BpsType,
{
pub bps: LazyDeltaFromHeight<S, B, DeltaRate>,
pub ratio: LazyPerBlock<StoredF32, B>,
pub percent: LazyPerBlock<StoredF32, B>,
}
B: BpsType;
/// Lazy rolling deltas for all 4 window durations (24h, 1w, 1m, 1y).
///
@@ -151,11 +150,11 @@ where
)),
};
let rate = LazyDeltaPercentFromHeight {
let rate = LazyDeltaPercentFromHeight(Percent {
bps,
ratio,
percent,
};
});
(absolute, rate)
};
@@ -304,11 +303,11 @@ where
)),
};
let rate = LazyDeltaPercentFromHeight {
let rate = LazyDeltaPercentFromHeight(Percent {
bps,
ratio,
percent,
};
});
(absolute, rate)
};

View File

@@ -19,22 +19,20 @@ impl Vecs {
exit: &Exit,
) -> Result<()> {
let window_starts = blocks.lookback.window_starts();
self.total
.compute(starting_indexes.height, &window_starts, exit, |full| {
full.compute_with_skip(
starting_indexes.height,
&indexes.tx_index.output_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
exit,
0,
)
})?;
self.total.compute(
starting_indexes.height,
&indexes.tx_index.output_count,
&indexer.vecs.transactions.first_tx_index,
&indexes.height.tx_index_count,
&window_starts,
exit,
0,
)?;
self.unspent.height.compute_transform3(
starting_indexes.height,
&self.total.full.cumulative.height,
&inputs_count.full.cumulative.height,
&self.total.cumulative.height,
&inputs_count.cumulative.height,
&scripts_count.op_return.cumulative.height,
|(h, output_count, input_count, op_return_count, ..)| {
let block_count = u64::from(h + 1_usize);

View File

@@ -39,14 +39,14 @@ impl Vecs {
self.taproot.compute_binary::<_, _, RatioU64Bp16>(
starting_indexes.height,
&count.p2tr.base.height,
&outputs_count.total.full.sum.height,
&outputs_count.total.sum.height,
exit,
)?;
self.segwit.compute_binary::<_, _, RatioU64Bp16>(
starting_indexes.height,
&count.segwit.base.height,
&outputs_count.total.full.sum.height,
&outputs_count.total.sum.height,
exit,
)?;

View File

@@ -50,7 +50,7 @@ impl Vecs {
.height
.compute_binary::<_, Timestamp, PerSec>(
starting_indexes.height,
&inputs_count.full.sum.height,
&inputs_count.sum.height,
&blocks.interval.base,
exit,
)?;
@@ -58,7 +58,7 @@ impl Vecs {
.height
.compute_binary::<_, Timestamp, PerSec>(
starting_indexes.height,
&outputs_count.total.full.sum.height,
&outputs_count.total.sum.height,
&blocks.interval.base,
exit,
)?;