global: snapshot

This commit is contained in:
nym21
2026-03-13 13:51:47 +01:00
parent 2b31c7f6b7
commit b2a1251774
27 changed files with 2131 additions and 1317 deletions

View File

@@ -329,11 +329,21 @@ fn resolve_branch_patterns(
}
/// Normalize fields for naming (same structure = same name).
/// Only erases leaf types when all leaves share the same type — this ensures
/// mixed-type signatures (e.g., StoredU32 raw + StoredU64 cumulative) get a
/// different name than same-type signatures that can be genericized.
fn normalize_fields_for_naming(fields: &[PatternField]) -> Vec<PatternField> {
let leaf_types: Vec<&str> = fields
.iter()
.filter(|f| !f.is_branch())
.map(|f| f.rust_type.as_str())
.collect();
let all_same = !leaf_types.is_empty() && leaf_types.iter().all(|t| *t == leaf_types[0]);
fields
.iter()
.map(|f| {
if f.is_branch() {
if f.is_branch() || !all_same {
f.clone()
} else {
PatternField {

File diff suppressed because it is too large Load Diff

View File

@@ -27,7 +27,7 @@ impl Vecs {
self.size
.compute(indexer, &self.lookback, starting_indexes, exit)?;
self.weight
.compute(indexer, &self.lookback, starting_indexes, exit)?;
.compute(indexer, starting_indexes, exit)?;
self.difficulty
.compute(indexer, indexes, starting_indexes, exit)?;
self.halving.compute(indexes, starting_indexes, exit)?;

View File

@@ -24,7 +24,7 @@ impl Vecs {
total: ComputedPerBlockCumulativeWithSums::forced_import(
db,
"block_count",
version,
version + Version::ONE,
indexes,
cached_starts,
)?,

View File

@@ -29,7 +29,7 @@ impl Vecs {
let count = CountVecs::forced_import(&db, version, indexes, cached_starts)?;
let interval = IntervalVecs::forced_import(&db, version, indexes, cached_starts)?;
let size = SizeVecs::forced_import(&db, version, indexes, cached_starts)?;
let weight = WeightVecs::forced_import(&db, version, indexes, cached_starts)?;
let weight = WeightVecs::forced_import(&db, version, indexes, cached_starts, &size)?;
let time = TimeVecs::forced_import(&db, version, indexes)?;
let difficulty = DifficultyVecs::forced_import(&db, version, indexer, indexes)?;
let halving = HalvingVecs::forced_import(&db, version, indexes)?;

View File

@@ -4,25 +4,14 @@ use brk_types::{BasisPoints16, Indexes};
use vecdb::Exit;
use super::Vecs;
use crate::blocks;
impl Vecs {
pub(crate) fn compute(
&mut self,
indexer: &Indexer,
lookback: &blocks::LookbackVecs,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let window_starts = lookback.window_starts();
self.weight.compute(
starting_indexes.height,
&window_starts,
&indexer.vecs.blocks.weight,
exit,
)?;
self.fullness
.compute(starting_indexes.height, exit, |vec| {
vec.compute_transform(

View File

@@ -4,8 +4,9 @@ use vecdb::Database;
use super::Vecs;
use crate::{
blocks::SizeVecs,
indexes,
internal::{CachedWindowStarts, ResolutionsFull, PercentPerBlockRollingAverage},
internal::{CachedWindowStarts, LazyResolutionsFull, PercentPerBlockRollingAverage, VBytesToWeight},
};
impl Vecs {
@@ -14,9 +15,15 @@ impl Vecs {
version: Version,
indexes: &indexes::Vecs,
cached_starts: &CachedWindowStarts,
size: &SizeVecs,
) -> Result<Self> {
let weight =
ResolutionsFull::forced_import(db, "block_weight", version, indexes, cached_starts)?;
let weight = LazyResolutionsFull::from_computed_per_block_full::<VBytesToWeight>(
"block_weight",
version,
&size.vbytes,
cached_starts,
indexes,
);
let fullness = PercentPerBlockRollingAverage::forced_import(
db,

View File

@@ -1,11 +1,11 @@
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, Weight};
use brk_types::{BasisPoints16, StoredU64, Weight};
use vecdb::{Rw, StorageMode};
use crate::internal::{ResolutionsFull, PercentPerBlockRollingAverage};
use crate::internal::{LazyResolutionsFull, PercentPerBlockRollingAverage};
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
pub weight: ResolutionsFull<Weight, M>,
pub weight: LazyResolutionsFull<Weight, StoredU64>,
pub fullness: PercentPerBlockRollingAverage<BasisPoints16, M>,
}

View File

@@ -0,0 +1,81 @@
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use schemars::JsonSchema;
use vecdb::{LazyVecFrom1, ReadableCloneableVec, UnaryTransform, VecIndex};
use crate::internal::{ComputedVecValue, Distribution, DistributionStats};
/// Lazy analog of `Distribution<I, T>`: 8 `LazyVecFrom1` fields,
/// each derived by transforming the corresponding field of a source `Distribution<I, S1T>`.
#[derive(Clone, Traversable)]
pub struct LazyDistribution<I, T, S1T>
where
I: VecIndex,
T: ComputedVecValue + JsonSchema,
S1T: ComputedVecValue,
{
pub average: LazyVecFrom1<I, T, I, S1T>,
pub min: LazyVecFrom1<I, T, I, S1T>,
pub max: LazyVecFrom1<I, T, I, S1T>,
pub pct10: LazyVecFrom1<I, T, I, S1T>,
pub pct25: LazyVecFrom1<I, T, I, S1T>,
pub median: LazyVecFrom1<I, T, I, S1T>,
pub pct75: LazyVecFrom1<I, T, I, S1T>,
pub pct90: LazyVecFrom1<I, T, I, S1T>,
}
impl<T, S1T> LazyDistribution<Height, T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_distribution<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &Distribution<Height, S1T>,
) -> Self {
let s = DistributionStats::<()>::SUFFIXES;
Self {
average: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[0]),
version,
source.average.read_only_boxed_clone(),
),
min: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[1]),
version,
source.min.read_only_boxed_clone(),
),
max: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[2]),
version,
source.max.read_only_boxed_clone(),
),
pct10: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[3]),
version,
source.pct10.read_only_boxed_clone(),
),
pct25: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[4]),
version,
source.pct25.read_only_boxed_clone(),
),
median: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[5]),
version,
source.median.read_only_boxed_clone(),
),
pct75: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[6]),
version,
source.pct75.read_only_boxed_clone(),
),
pct90: LazyVecFrom1::transformed::<F>(
&format!("{name}_{}", s[7]),
version,
source.pct90.read_only_boxed_clone(),
),
}
}
}

View File

@@ -1,5 +1,7 @@
mod distribution;
mod full;
mod lazy_distribution;
pub use distribution::*;
pub use full::*;
pub use lazy_distribution::*;

View File

@@ -0,0 +1,60 @@
use brk_traversable::Traversable;
use brk_types::Version;
use schemars::JsonSchema;
use vecdb::{ReadableCloneableVec, UnaryTransform};
use crate::{
indexes,
internal::{
CachedWindowStarts, ComputedPerBlockFull, ComputedVecValue, LazyPerBlock, LazyRollingFull,
NumericValue,
},
};
/// Lazy analog of `ResolutionsFull<T>`: lazy cumulative + lazy rolling full.
/// Derived by transforming a `ComputedPerBlockFull<S1T>`. Zero stored vecs.
#[derive(Clone, Traversable)]
pub struct LazyResolutionsFull<T, S1T>
where
T: NumericValue + JsonSchema,
S1T: ComputedVecValue + JsonSchema,
{
pub cumulative: LazyPerBlock<T, S1T>,
#[traversable(flatten)]
pub rolling: LazyRollingFull<T, S1T>,
}
impl<T, S1T> LazyResolutionsFull<T, S1T>
where
T: NumericValue + JsonSchema + 'static,
S1T: NumericValue + JsonSchema,
{
pub(crate) fn from_computed_per_block_full<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &ComputedPerBlockFull<S1T>,
cached_starts: &CachedWindowStarts,
indexes: &indexes::Vecs,
) -> Self {
let cumulative = LazyPerBlock::from_computed::<F>(
&format!("{name}_cumulative"),
version,
source.cumulative.height.read_only_boxed_clone(),
&source.cumulative,
);
let rolling = LazyRollingFull::from_rolling_full::<F>(
name,
version,
&cumulative.height,
&source.rolling,
cached_starts,
indexes,
);
Self {
cumulative,
rolling,
}
}
}

View File

@@ -5,6 +5,7 @@ mod cumulative;
mod cumulative_sum;
mod resolutions;
mod resolutions_full;
mod lazy_resolutions_full;
mod full;
mod rolling_average;
mod with_deltas;
@@ -16,6 +17,7 @@ pub use cumulative::*;
pub use cumulative_sum::*;
pub use resolutions::*;
pub use resolutions_full::*;
pub use lazy_resolutions_full::*;
pub use full::*;
pub use rolling_average::*;
pub use with_deltas::*;

View File

@@ -0,0 +1,75 @@
use brk_traversable::Traversable;
use brk_types::Version;
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{ReadableCloneableVec, UnaryTransform};
use crate::internal::{
ComputedVecValue, DistributionStats, LazyPerBlock, NumericValue, RollingDistribution, Windows,
};
/// Lazy analog of `RollingDistribution<T>`: `DistributionStats<Windows<LazyPerBlock<T, S1T>>>`.
/// 8 stats × 4 windows = 32 lazy vecs, zero stored.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(transparent)]
pub struct LazyRollingDistribution<T, S1T>(pub DistributionStats<Windows<LazyPerBlock<T, S1T>>>)
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue + JsonSchema;
impl<T, S1T> LazyRollingDistribution<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: NumericValue + JsonSchema,
{
pub(crate) fn from_rolling_distribution<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &RollingDistribution<S1T>,
) -> Self {
let s = &source.0;
macro_rules! map_stat {
($field:ident, $suffix:expr) => {{
let src = &s.$field;
Windows {
_24h: LazyPerBlock::from_computed::<F>(
&format!("{name}_{}_24h", $suffix),
version,
src._24h.height.read_only_boxed_clone(),
&src._24h,
),
_1w: LazyPerBlock::from_computed::<F>(
&format!("{name}_{}_1w", $suffix),
version,
src._1w.height.read_only_boxed_clone(),
&src._1w,
),
_1m: LazyPerBlock::from_computed::<F>(
&format!("{name}_{}_1m", $suffix),
version,
src._1m.height.read_only_boxed_clone(),
&src._1m,
),
_1y: LazyPerBlock::from_computed::<F>(
&format!("{name}_{}_1y", $suffix),
version,
src._1y.height.read_only_boxed_clone(),
&src._1y,
),
}
}};
}
Self(DistributionStats {
average: map_stat!(average, "average"),
min: map_stat!(min, "min"),
max: map_stat!(max, "max"),
pct10: map_stat!(pct10, "pct10"),
pct25: map_stat!(pct25, "pct25"),
median: map_stat!(median, "median"),
pct75: map_stat!(pct75, "pct75"),
pct90: map_stat!(pct90, "pct90"),
})
}
}

View File

@@ -0,0 +1,56 @@
use brk_traversable::Traversable;
use brk_types::Version;
use schemars::JsonSchema;
use vecdb::{ReadableCloneableVec, UnaryTransform};
use brk_types::Height;
use crate::{
indexes,
internal::{
CachedWindowStarts, ComputedVecValue, LazyRollingDistribution, LazyRollingSumsFromHeight,
NumericValue, RollingFull,
},
};
/// Lazy analog of `RollingFull<T>`: lazy rolling sums + lazy rolling distribution.
/// Zero stored vecs.
#[derive(Clone, Traversable)]
pub struct LazyRollingFull<T, S1T>
where
T: NumericValue + JsonSchema,
S1T: ComputedVecValue + JsonSchema,
{
pub sum: LazyRollingSumsFromHeight<T>,
#[traversable(flatten)]
pub distribution: LazyRollingDistribution<T, S1T>,
}
impl<T, S1T> LazyRollingFull<T, S1T>
where
T: NumericValue + JsonSchema + 'static,
S1T: NumericValue + JsonSchema,
{
pub(crate) fn from_rolling_full<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
cumulative: &(impl ReadableCloneableVec<Height, T> + 'static),
source: &RollingFull<S1T>,
cached_starts: &CachedWindowStarts,
indexes: &indexes::Vecs,
) -> Self {
let sum = LazyRollingSumsFromHeight::new(
&format!("{name}_sum"),
version,
cumulative,
cached_starts,
indexes,
);
let distribution = LazyRollingDistribution::from_rolling_distribution::<F>(
name,
version,
&source.distribution,
);
Self { sum, distribution }
}
}

View File

@@ -3,6 +3,8 @@ mod avgs;
mod delta;
mod distribution;
mod full;
mod lazy_distribution;
mod lazy_full;
mod sum;
mod sums;
mod windows;
@@ -12,6 +14,8 @@ pub use avgs::*;
pub use delta::*;
pub use distribution::*;
pub use full::*;
pub use lazy_distribution::*;
pub use lazy_full::*;
pub use sum::*;
pub use sums::*;
pub use windows::*;

View File

@@ -0,0 +1,50 @@
use brk_traversable::Traversable;
use brk_types::{Height, Version};
use schemars::JsonSchema;
use vecdb::UnaryTransform;
use crate::internal::{ComputedVecValue, LazyDistribution, TxDerivedDistribution};
#[derive(Clone, Traversable)]
pub struct LazyBlockRollingDistribution<T, S1T>
where
T: ComputedVecValue + JsonSchema,
S1T: ComputedVecValue,
{
pub _6b: LazyDistribution<Height, T, S1T>,
}
/// Lazy analog of `TxDerivedDistribution<T>`: per-block + 6-block rolling,
/// each derived by transforming the corresponding source distribution.
#[derive(Clone, Traversable)]
pub struct LazyTxDerivedDistribution<T, S1T>
where
T: ComputedVecValue + JsonSchema,
S1T: ComputedVecValue,
{
pub block: LazyDistribution<Height, T, S1T>,
#[traversable(flatten)]
pub rolling: LazyBlockRollingDistribution<T, S1T>,
}
impl<T, S1T> LazyTxDerivedDistribution<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub(crate) fn from_tx_derived<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &TxDerivedDistribution<S1T>,
) -> Self {
let block = LazyDistribution::from_distribution::<F>(name, version, &source.block);
let rolling = LazyBlockRollingDistribution {
_6b: LazyDistribution::from_distribution::<F>(
&format!("{name}_6b"),
version,
&source.rolling._6b,
),
};
Self { block, rolling }
}
}

View File

@@ -0,0 +1,43 @@
use brk_traversable::Traversable;
use brk_types::{TxIndex, Version};
use schemars::JsonSchema;
use vecdb::{LazyVecFrom2, UnaryTransform};
use crate::internal::{ComputedVecValue, LazyTxDerivedDistribution, TxDerivedDistribution};
/// Like `LazyPerTxDistribution` but with a lazy-derived distribution
/// (transformed from another type's distribution rather than eagerly computed).
#[derive(Clone, Traversable)]
pub struct LazyPerTxDistributionDerived<T, S1, S2, DSource>
where
T: ComputedVecValue + JsonSchema,
S1: ComputedVecValue,
S2: ComputedVecValue,
DSource: ComputedVecValue,
{
pub txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
#[traversable(flatten)]
pub distribution: LazyTxDerivedDistribution<T, DSource>,
}
impl<T, S1, S2, DSource> LazyPerTxDistributionDerived<T, S1, S2, DSource>
where
T: ComputedVecValue + JsonSchema + 'static,
S1: ComputedVecValue + JsonSchema,
S2: ComputedVecValue + JsonSchema,
DSource: ComputedVecValue + JsonSchema,
{
pub(crate) fn new<F: UnaryTransform<DSource, T>>(
name: &str,
version: Version,
txindex: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
source_distribution: &TxDerivedDistribution<DSource>,
) -> Self {
let distribution =
LazyTxDerivedDistribution::from_tx_derived::<F>(name, version, source_distribution);
Self {
txindex,
distribution,
}
}
}

View File

@@ -1,7 +1,11 @@
mod derived;
mod distribution;
mod lazy_derived;
mod lazy_distribution;
mod lazy_distribution_derived;
pub use derived::*;
pub use distribution::*;
pub use lazy_derived::*;
pub use lazy_distribution::*;
pub use lazy_distribution_derived::*;

View File

@@ -1,6 +1,6 @@
use std::marker::PhantomData;
use brk_types::{Bitcoin, Cents, Dollars, Sats, StoredF32, StoredI8, StoredU16, StoredU32};
use brk_types::{Bitcoin, Cents, Dollars, Sats, StoredF32, StoredI8, StoredU16, StoredU32, StoredU64, VSize, Weight};
use vecdb::{BinaryTransform, UnaryTransform, VecValue};
pub struct Identity<T>(PhantomData<T>);
@@ -87,3 +87,21 @@ impl<S, const V: i8> UnaryTransform<S, StoredI8> for ReturnI8<V> {
StoredI8::new(V)
}
}
pub struct VBytesToWeight;
impl UnaryTransform<StoredU64, Weight> for VBytesToWeight {
#[inline(always)]
fn apply(vbytes: StoredU64) -> Weight {
Weight::from(VSize::new(*vbytes))
}
}
pub struct VSizeToWeight;
impl UnaryTransform<VSize, Weight> for VSizeToWeight {
#[inline(always)]
fn apply(vsize: VSize) -> Weight {
Weight::from(vsize)
}
}

View File

@@ -7,7 +7,7 @@ mod specialized;
pub use arithmetic::{
HalveCents, HalveDollars, HalveSats, HalveSatsToBitcoin, Identity, MaskSats, ReturnF32Tenths,
ReturnI8, ReturnU16,
ReturnI8, ReturnU16, VBytesToWeight, VSizeToWeight,
};
pub use bps::{
Bp16ToFloat, Bp16ToPercent, Bp32ToFloat, Bp32ToPercent, Bps16ToFloat, Bps16ToPercent, Bps32ToFloat,

View File

@@ -34,7 +34,7 @@ impl Vecs {
let blocks_mined = ComputedPerBlockCumulativeWithSums::forced_import(
db,
&suffix("blocks_mined"),
version,
version + Version::ONE,
indexes,
cached_starts,
)?;

View File

@@ -14,9 +14,6 @@ impl Vecs {
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
self.weight
.derive_from(indexer, indexes, starting_indexes, exit)?;
self.vsize
.derive_from(indexer, indexes, starting_indexes, exit)?;

View File

@@ -4,7 +4,7 @@ use brk_types::{TxIndex, VSize, Version, Weight};
use vecdb::{Database, LazyVecFrom2, ReadableCloneableVec};
use super::Vecs;
use crate::internal::LazyPerTxDistribution;
use crate::internal::{LazyPerTxDistribution, LazyPerTxDistributionDerived, VSizeToWeight};
impl Vecs {
pub(crate) fn forced_import(
@@ -12,14 +12,6 @@ impl Vecs {
version: Version,
indexer: &Indexer,
) -> Result<Self> {
let txindex_to_weight = LazyVecFrom2::init(
"tx_weight",
version,
indexer.vecs.transactions.base_size.read_only_boxed_clone(),
indexer.vecs.transactions.total_size.read_only_boxed_clone(),
|_index: TxIndex, base_size, total_size| Weight::from_sizes(*base_size, *total_size),
);
let txindex_to_vsize = LazyVecFrom2::init(
"tx_vsize",
version,
@@ -30,19 +22,24 @@ impl Vecs {
},
);
Ok(Self {
vsize: LazyPerTxDistribution::forced_import(
db,
"tx_vsize",
version,
txindex_to_vsize,
)?,
weight: LazyPerTxDistribution::forced_import(
db,
"tx_weight",
version,
txindex_to_weight,
)?,
})
let vsize =
LazyPerTxDistribution::forced_import(db, "tx_vsize", version, txindex_to_vsize)?;
let txindex_to_weight = LazyVecFrom2::init(
"tx_weight",
version,
indexer.vecs.transactions.base_size.read_only_boxed_clone(),
indexer.vecs.transactions.total_size.read_only_boxed_clone(),
|_index: TxIndex, base_size, total_size| Weight::from_sizes(*base_size, *total_size),
);
let weight = LazyPerTxDistributionDerived::new::<VSizeToWeight>(
"tx_weight",
version,
txindex_to_weight,
&vsize.distribution,
);
Ok(Self { vsize, weight })
}
}

View File

@@ -2,10 +2,10 @@ use brk_traversable::Traversable;
use brk_types::{StoredU32, VSize, Weight};
use vecdb::{Rw, StorageMode};
use crate::internal::LazyPerTxDistribution;
use crate::internal::{LazyPerTxDistribution, LazyPerTxDistributionDerived};
#[derive(Traversable)]
pub struct Vecs<M: StorageMode = Rw> {
pub vsize: LazyPerTxDistribution<VSize, StoredU32, StoredU32, M>,
pub weight: LazyPerTxDistribution<Weight, StoredU32, StoredU32, M>,
pub weight: LazyPerTxDistributionDerived<Weight, StoredU32, StoredU32, VSize>,
}

View File

@@ -5,6 +5,8 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use vecdb::{CheckedSub, Formattable, Pco};
use crate::VSize;
/// Transaction or block weight in weight units (WU)
#[derive(
Debug,
@@ -66,6 +68,14 @@ impl From<Weight> for bitcoin::Weight {
}
}
impl From<VSize> for Weight {
/// Convert virtual bytes to weight units: `weight = vbytes * WITNESS_SCALE_FACTOR`.
#[inline]
fn from(vsize: VSize) -> Self {
Self(bitcoin::Weight::from_vb_unchecked(*vsize).to_wu())
}
}
impl From<usize> for Weight {
#[inline]
fn from(value: usize) -> Self {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff