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