global: snapshot

This commit is contained in:
nym21
2026-02-28 23:14:01 +01:00
parent a2bd7ca299
commit 1750c06369
50 changed files with 122 additions and 192 deletions

View File

@@ -3,7 +3,7 @@ use brk_types::{Height, StoredU32, StoredU64};
use vecdb::{EagerVec, PcoVec, Rw, StorageMode};
use crate::internal::{
BlockWindowStarts, ComputedFromHeightCumulativeSum, ConstantVecs, RollingWindows, WindowStarts,
ComputedFromHeightCumulativeSum, ConstantVecs, RollingWindows, WindowStarts,
};
#[derive(Traversable)]
@@ -56,14 +56,6 @@ impl Vecs {
}
}
/// Get the 2 block-count rolling window start heights (1h, 24h) for tx-derived metrics.
pub fn block_window_starts(&self) -> BlockWindowStarts<'_> {
BlockWindowStarts {
_1h: &self.height_1h_ago,
_24h: &self.height_24h_ago,
}
}
pub fn start_vec(&self, days: usize) -> &EagerVec<PcoVec<Height, Height>> {
match days {
1 => &self.height_24h_ago,

View File

@@ -1,13 +0,0 @@
//! Base generic struct with 2 type parameters — one per rolling window duration.
//!
//! Foundation for tx-derived rolling window types (1h, 24h — actual time-based).
use brk_traversable::Traversable;
#[derive(Clone, Traversable)]
pub struct BlockWindows<A, B = A> {
#[traversable(rename = "1h")]
pub _1h: A,
#[traversable(rename = "24h")]
pub _24h: B,
}

View File

@@ -315,17 +315,17 @@ where
Ok(())
}
/// Compute distribution stats from windowed ranges of a source vec.
/// Compute distribution stats from a fixed n-block rolling window.
///
/// For each index `i`, reads all source items from groups `window_starts[i]..=i`
/// For each height `h`, aggregates all source items from blocks `max(0, h - n_blocks + 1)..=h`
/// and computes average, min, max, median, and percentiles across the full window.
#[allow(clippy::too_many_arguments)]
pub(crate) fn compute_aggregations_windowed<I, T, A>(
pub(crate) fn compute_aggregations_nblock_window<I, T, A>(
max_from: I,
source: &impl ReadableVec<A, T>,
first_indexes: &impl ReadableVec<I, A>,
count_indexes: &impl ReadableVec<I, StoredU64>,
window_starts: &impl ReadableVec<I, I>,
n_blocks: usize,
exit: &Exit,
min: &mut EagerVec<PcoVec<I, T>>,
max: &mut EagerVec<PcoVec<I, T>>,
@@ -342,7 +342,7 @@ where
A: VecIndex + VecValue + CheckedSub<A>,
{
let combined_version =
source.version() + first_indexes.version() + count_indexes.version() + window_starts.version();
source.version() + first_indexes.version() + count_indexes.version();
let mut idx = max_from;
for vec in [&mut *min, &mut *max, &mut *average, &mut *median, &mut *pct10, &mut *pct25, &mut *pct75, &mut *pct90] {
@@ -353,35 +353,30 @@ where
let start = index.to_usize();
let fi_len = first_indexes.len();
let first_indexes_batch: Vec<A> = first_indexes.collect_range_at(start, fi_len);
// Only fetch first_indexes from the earliest possible window start
let batch_start = start.saturating_sub(n_blocks - 1);
let first_indexes_batch: Vec<A> = first_indexes.collect_range_at(batch_start, fi_len);
let count_indexes_batch: Vec<StoredU64> = count_indexes.collect_range_at(start, fi_len);
let window_starts_batch: Vec<I> = window_starts.collect_range_at(start, fi_len);
let zero = T::from(0_usize);
let mut values: Vec<T> = Vec::new();
first_indexes_batch
count_indexes_batch
.iter()
.zip(count_indexes_batch.iter())
.zip(window_starts_batch.iter())
.enumerate()
.try_for_each(|(j, ((fi, ci), ws))| -> Result<()> {
.try_for_each(|(j, ci)| -> Result<()> {
let idx = start + j;
let window_start_offset = ws.to_usize();
// Window start: max(0, idx - n_blocks + 1)
let window_start = idx.saturating_sub(n_blocks - 1);
// Last tx index (exclusive) of current block
let count = u64::from(*ci) as usize;
let fi = first_indexes_batch[idx - batch_start];
let range_end_usize = fi.to_usize() + count;
// First tx index of the window start block
let range_start_usize = if window_start_offset >= start {
first_indexes_batch[window_start_offset - start].to_usize()
} else {
first_indexes
.collect_one_at(window_start_offset)
.unwrap()
.to_usize()
};
let range_start_usize = first_indexes_batch[window_start - batch_start].to_usize();
let effective_count = range_end_usize.saturating_sub(range_start_usize);

View File

@@ -1,4 +1,3 @@
mod block_windows;
mod compute;
mod distribution_stats;
mod eager_indexes;
@@ -8,9 +7,9 @@ mod multi;
mod single;
pub(crate) mod sliding_window;
mod traits;
mod transform;
mod windows;
pub(crate) use block_windows::*;
pub(crate) use compute::*;
pub(crate) use distribution_stats::*;
pub(crate) use eager_indexes::*;
@@ -19,4 +18,5 @@ pub(crate) use lazy_eager_indexes::*;
pub(crate) use multi::*;
pub(crate) use single::*;
pub(crate) use traits::*;
pub use transform::*;
pub(crate) use windows::*;

View File

@@ -12,7 +12,7 @@ use vecdb::{Database, EagerVec, Exit, ImportableVec, PcoVec, Rw, StorageMode, Ve
use crate::{
ComputeIndexes, indexes,
internal::{BlockWindowStarts, ComputedVecValue, NumericValue, TxDerivedDistribution},
internal::{ComputedVecValue, NumericValue, TxDerivedDistribution},
};
#[derive(Traversable)]
@@ -44,7 +44,6 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
exit: &Exit,
skip_count: usize,
) -> Result<()>
@@ -56,7 +55,6 @@ where
indexer,
indexes,
starting_indexes,
block_windows,
&self.txindex,
exit,
skip_count,

View File

@@ -9,7 +9,7 @@ use vecdb::{Database, Exit, LazyVecFrom2, ReadableVec, Rw, StorageMode, Version}
use crate::{
ComputeIndexes, indexes,
internal::{BlockWindowStarts, ComputedVecValue, NumericValue, TxDerivedDistribution},
internal::{ComputedVecValue, NumericValue, TxDerivedDistribution},
};
#[derive(Traversable)]
@@ -48,7 +48,6 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
exit: &Exit,
) -> Result<()>
where
@@ -60,7 +59,6 @@ where
indexer,
indexes,
starting_indexes,
block_windows,
&self.txindex,
exit,
)

View File

@@ -1,7 +1,7 @@
//! TxDerivedDistribution - per-block + rolling window distribution stats from tx-level data.
//!
//! Computes true distribution stats (average, min, max, median, percentiles) by reading
//! actual tx values for each scope: current block, last 1h, last 24h.
//! actual tx values for each scope: current block, last 6 blocks.
use brk_error::Result;
use brk_indexer::Indexer;
@@ -14,7 +14,7 @@ use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, Version};
use crate::{
ComputeIndexes, indexes,
internal::{
BlockRollingDistribution, BlockWindowStarts, ComputedVecValue, Distribution, NumericValue,
BlockRollingDistribution, ComputedVecValue, Distribution, NumericValue,
},
};
@@ -44,7 +44,6 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
txindex_source: &impl ReadableVec<TxIndex, T>,
exit: &Exit,
) -> Result<()>
@@ -56,7 +55,6 @@ where
indexer,
indexes,
starting_indexes,
block_windows,
txindex_source,
exit,
0,
@@ -73,7 +71,6 @@ where
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
block_windows: &BlockWindowStarts<'_>,
txindex_source: &impl ReadableVec<TxIndex, T>,
exit: &Exit,
skip_count: usize,
@@ -92,23 +89,13 @@ where
skip_count,
)?;
// 1h rolling: true distribution from all txs in last hour
self.rolling._1h.compute_from_window(
// 6-block rolling: true distribution from all txs in last 6 blocks
self.rolling._6b.compute_from_nblocks(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
block_windows._1h,
exit,
)?;
// 24h rolling: true distribution from all txs in last 24 hours
self.rolling._24h.compute_from_window(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
block_windows._24h,
6,
exit,
)?;

View File

@@ -72,28 +72,27 @@ impl<I: VecIndex, T: ComputedVecValue + JsonSchema> Distribution<I, T> {
)
}
/// Compute distribution stats from all items in a rolling window of groups.
/// Compute distribution stats from a fixed n-block rolling window.
///
/// For each index `i`, reads all source items from groups `window_starts[i]..=i`
/// and computes distribution stats across the entire window.
pub(crate) fn compute_from_window<A>(
/// For each index `i`, aggregates all source items from blocks `max(0, i - n_blocks + 1)..=i`.
pub(crate) fn compute_from_nblocks<A>(
&mut self,
max_from: I,
source: &impl ReadableVec<A, T>,
first_indexes: &impl ReadableVec<I, A>,
count_indexes: &impl ReadableVec<I, brk_types::StoredU64>,
window_starts: &impl ReadableVec<I, I>,
n_blocks: usize,
exit: &Exit,
) -> Result<()>
where
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
{
crate::internal::compute_aggregations_windowed(
crate::internal::compute_aggregations_nblock_window(
max_from,
source,
first_indexes,
count_indexes,
window_starts,
n_blocks,
exit,
&mut self.min.0,
&mut self.max.0,

View File

@@ -3,11 +3,9 @@
mod group;
mod height;
mod rolling;
mod transform;
mod vec;
pub use group::*;
pub use height::*;
pub use rolling::*;
pub use transform::*;
pub use vec::*;

View File

@@ -1,31 +1,22 @@
//! Block-count-based rolling window starts and distribution — 1h and 24h (actual time-based).
//!
//! Uses stored height-ago vecs (`height_1h_ago`, `height_24h_ago`) for accurate
//! time-based window starts.
//! Block-count-based rolling distribution — 6-block window.
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::Height;
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{Database, EagerVec, PcoVec, Rw, StorageMode, Version};
use vecdb::{Database, Rw, StorageMode, Version};
use crate::internal::{BlockWindows, ComputedVecValue, Distribution, NumericValue};
use crate::internal::{ComputedVecValue, Distribution, NumericValue};
/// Rolling window start heights for tx-derived metrics (1h, 24h).
pub struct BlockWindowStarts<'a> {
pub _1h: &'a EagerVec<PcoVec<Height, Height>>,
pub _24h: &'a EagerVec<PcoVec<Height, Height>>,
}
/// 2 rolling window distributions (1h, 24h), each with 8 distribution stat vecs.
#[derive(Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct BlockRollingDistribution<T, M: StorageMode = Rw>(
pub BlockWindows<Distribution<Height, T, M>>,
)
/// Single 6-block rolling window distribution with 8 distribution stat vecs.
#[derive(Traversable)]
pub struct BlockRollingDistribution<T, M: StorageMode = Rw>
where
T: ComputedVecValue + PartialOrd + JsonSchema;
T: ComputedVecValue + PartialOrd + JsonSchema,
{
#[traversable(rename = "6b")]
pub _6b: Distribution<Height, T, M>,
}
impl<T> BlockRollingDistribution<T>
where
@@ -36,9 +27,8 @@ where
name: &str,
version: Version,
) -> Result<Self> {
Ok(Self(BlockWindows {
_1h: Distribution::forced_import(db, &format!("{name}_1h"), version)?,
_24h: Distribution::forced_import(db, &format!("{name}_24h"), version)?,
}))
Ok(Self {
_6b: Distribution::forced_import(db, &format!("{name}_6b"), version)?,
})
}
}

View File

@@ -27,17 +27,16 @@ impl Vecs {
self.versions
.compute(indexer, &blocks.count, starting_indexes, exit)?;
// Size computes next (uses BlockWindowStarts for 1h/24h rolling)
// Size computes next (uses 6-block rolling window)
self.size
.compute(indexer, indexes, &blocks.count, starting_indexes, exit)?;
.compute(indexer, indexes, starting_indexes, exit)?;
// Fees depends on size, blocks (window starts)
// Fees depends on size
self.fees.compute(
indexer,
indexes,
inputs,
&self.size,
blocks,
starting_indexes,
exit,
)?;

View File

@@ -5,7 +5,7 @@ use vecdb::{Exit, unlikely};
use super::super::size;
use super::Vecs;
use crate::{ComputeIndexes, blocks, indexes, inputs};
use crate::{ComputeIndexes, indexes, inputs};
impl Vecs {
#[allow(clippy::too_many_arguments)]
@@ -15,7 +15,6 @@ impl Vecs {
indexes: &indexes::Vecs,
txins: &inputs::Vecs,
size_vecs: &size::Vecs,
blocks: &blocks::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
@@ -58,14 +57,11 @@ impl Vecs {
exit,
)?;
let block_windows = blocks.count.block_window_starts();
// Skip coinbase (first tx per block) since it has fee=0
self.fee.derive_from_with_skip(
indexer,
indexes,
starting_indexes,
&block_windows,
exit,
1,
)?;
@@ -75,7 +71,6 @@ impl Vecs {
indexer,
indexes,
starting_indexes,
&block_windows,
exit,
1,
)?;

View File

@@ -3,24 +3,21 @@ use brk_indexer::Indexer;
use vecdb::Exit;
use super::Vecs;
use crate::{blocks, indexes, ComputeIndexes};
use crate::{indexes, ComputeIndexes};
impl Vecs {
pub(crate) fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
count_vecs: &blocks::CountVecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
let block_windows = count_vecs.block_window_starts();
self.weight
.derive_from(indexer, indexes, starting_indexes, &block_windows, exit)?;
.derive_from(indexer, indexes, starting_indexes, exit)?;
self.vsize
.derive_from(indexer, indexes, starting_indexes, &block_windows, exit)?;
.derive_from(indexer, indexes, starting_indexes, exit)?;
Ok(())
}