global: snapshot

This commit is contained in:
nym21
2026-01-10 18:43:18 +01:00
parent 3bc0615000
commit 6f45ec13f3
311 changed files with 6916 additions and 7664 deletions

View File

@@ -0,0 +1,124 @@
//! TxDerivedDistribution - computes TxIndex data to height Distribution + dateindex MinMaxAverage + lazy aggregations.
//!
//! Note: Percentiles are computed at height level only. DateIndex and coarser
//! periods only have average+min+max since computing percentiles across all
//! transactions per day would be expensive.
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::{DateIndex, DifficultyEpoch, Height, TxIndex, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{CollectableVec, Database, Exit, IterableCloneableVec};
use crate::{
ComputeIndexes, indexes,
internal::{
ComputedVecValue, LazyDateDerivedDistribution, Distribution, LazyDistribution, MinMaxAverage,
NumericValue,
},
};
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct TxDerivedDistribution<T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
pub height: Distribution<Height, T>,
pub difficultyepoch: LazyDistribution<DifficultyEpoch, T, Height, DifficultyEpoch>,
pub dateindex: MinMaxAverage<DateIndex, T>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub dates: LazyDateDerivedDistribution<T>,
}
const VERSION: Version = Version::ZERO;
impl<T> TxDerivedDistribution<T>
where
T: NumericValue + JsonSchema,
{
pub fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let height = Distribution::forced_import(db, name, version + VERSION)?;
let dateindex = MinMaxAverage::forced_import(db, name, version + VERSION)?;
let v = version + VERSION;
let difficultyepoch =
LazyDistribution::<DifficultyEpoch, T, Height, DifficultyEpoch>::from_distribution(
name,
v,
height.boxed_average(),
height.boxed_min(),
height.boxed_max(),
indexes.difficultyepoch.identity.boxed_clone(),
);
let dates = LazyDateDerivedDistribution::from_sources(
name,
v,
dateindex.boxed_average(),
dateindex.boxed_min(),
dateindex.boxed_max(),
indexes,
);
Ok(Self {
height,
difficultyepoch,
dateindex,
dates,
})
}
pub fn derive_from(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
txindex_source: &impl CollectableVec<TxIndex, T>,
exit: &Exit,
) -> Result<()> {
self.derive_from_with_skip(indexer, indexes, starting_indexes, txindex_source, exit, 0)
}
/// Derive from source, skipping first N transactions per block from all calculations.
///
/// Use `skip_count: 1` to exclude coinbase transactions from fee/feerate stats.
pub fn derive_from_with_skip(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
txindex_source: &impl CollectableVec<TxIndex, T>,
exit: &Exit,
skip_count: usize,
) -> Result<()> {
self.height.compute_with_skip(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
exit,
skip_count,
)?;
self.dateindex.compute(
starting_indexes.dateindex,
&self.height.average().0,
&indexes.dateindex.first_height,
&indexes.dateindex.height_count,
exit,
)?;
Ok(())
}
}

View File

@@ -0,0 +1,122 @@
//! TxDerivedFull - aggregates from TxIndex to height Full + dateindex Stats + lazy date periods.
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::{DateIndex, DifficultyEpoch, Height, TxIndex, Version};
use derive_more::{Deref, DerefMut};
use schemars::JsonSchema;
use vecdb::{CollectableVec, Database, Exit, IterableCloneableVec};
use crate::{
indexes, ComputeIndexes,
internal::{ComputedVecValue, LazyDateDerivedFull, Full, LazyFull, NumericValue, Stats},
};
/// Aggregates from TxIndex to height/dateindex with full stats.
#[derive(Clone, Deref, DerefMut, Traversable)]
#[traversable(merge)]
pub struct TxDerivedFull<T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
{
pub height: Full<Height, T>,
pub difficultyepoch: LazyFull<DifficultyEpoch, T, Height, DifficultyEpoch>,
pub dateindex: Stats<DateIndex, T>,
#[deref]
#[deref_mut]
#[traversable(flatten)]
pub dates: LazyDateDerivedFull<T>,
}
const VERSION: Version = Version::ZERO;
impl<T> TxDerivedFull<T>
where
T: NumericValue + JsonSchema,
{
pub fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let height = Full::forced_import(db, name, version + VERSION)?;
let dateindex = Stats::forced_import(db, name, version + VERSION)?;
let v = version + VERSION;
let difficultyepoch =
LazyFull::<DifficultyEpoch, T, Height, DifficultyEpoch>::from_stats_aggregate(
name,
v,
height.boxed_average(),
height.boxed_min(),
height.boxed_max(),
height.boxed_sum(),
height.boxed_cumulative(),
indexes.difficultyepoch.identity.boxed_clone(),
);
let dates = LazyDateDerivedFull::from_sources(
name,
v,
dateindex.boxed_average(),
dateindex.boxed_min(),
dateindex.boxed_max(),
dateindex.boxed_sum(),
dateindex.boxed_cumulative(),
indexes,
);
Ok(Self {
height,
difficultyepoch,
dateindex,
dates,
})
}
pub fn derive_from(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
txindex_source: &impl CollectableVec<TxIndex, T>,
exit: &Exit,
) -> Result<()> {
self.derive_from_with_skip(indexer, indexes, starting_indexes, txindex_source, exit, 0)
}
/// Derive from source, skipping first N transactions per block from all calculations.
///
/// Use `skip_count: 1` to exclude coinbase transactions from fee/feerate stats.
pub fn derive_from_with_skip(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
txindex_source: &impl CollectableVec<TxIndex, T>,
exit: &Exit,
skip_count: usize,
) -> Result<()> {
self.height.compute_with_skip(
starting_indexes.height,
txindex_source,
&indexer.vecs.transactions.first_txindex,
&indexes.height.txindex_count,
exit,
skip_count,
)?;
self.dateindex.compute(
starting_indexes.dateindex,
&self.height.average().0,
&indexes.dateindex.first_height,
&indexes.dateindex.height_count,
exit,
)?;
Ok(())
}
}

View File

@@ -0,0 +1,75 @@
//! Lazy transform of TxDerivedFull.
use brk_traversable::Traversable;
use brk_types::{
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex,
Version, WeekIndex, YearIndex,
};
use schemars::JsonSchema;
use vecdb::{IterableCloneableVec, UnaryTransform};
use crate::internal::{ComputedVecValue, TxDerivedFull, LazyTransformFull, LazyTransformStats};
#[derive(Clone, Traversable)]
#[traversable(merge)]
pub struct LazyTxDerivedFull<T, S1T = T>
where
T: ComputedVecValue + PartialOrd + JsonSchema,
S1T: ComputedVecValue,
{
pub height: LazyTransformFull<Height, T, S1T>,
pub difficultyepoch: LazyTransformStats<DifficultyEpoch, T, S1T>,
pub dateindex: LazyTransformStats<DateIndex, T, S1T>,
pub weekindex: LazyTransformStats<WeekIndex, T, S1T>,
pub monthindex: LazyTransformStats<MonthIndex, T, S1T>,
pub quarterindex: LazyTransformStats<QuarterIndex, T, S1T>,
pub semesterindex: LazyTransformStats<SemesterIndex, T, S1T>,
pub yearindex: LazyTransformStats<YearIndex, T, S1T>,
pub decadeindex: LazyTransformStats<DecadeIndex, T, S1T>,
}
const VERSION: Version = Version::ZERO;
impl<T, S1T> LazyTxDerivedFull<T, S1T>
where
T: ComputedVecValue + JsonSchema + 'static,
S1T: ComputedVecValue + JsonSchema,
{
pub fn from_computed<F: UnaryTransform<S1T, T>>(
name: &str,
version: Version,
source: &TxDerivedFull<S1T>,
) -> Self {
let v = version + VERSION;
macro_rules! period {
($p:ident) => {
LazyTransformStats::from_boxed::<F>(
name, v,
source.$p.average.boxed_clone(), source.$p.min.boxed_clone(),
source.$p.max.boxed_clone(), source.$p.sum.boxed_clone(),
source.$p.cumulative.boxed_clone(),
)
};
}
Self {
height: LazyTransformFull::from_stats_aggregate::<F>(name, v, &source.height),
difficultyepoch: period!(difficultyepoch),
dateindex: LazyTransformStats::from_boxed::<F>(
name, v,
source.dateindex.boxed_average(),
source.dateindex.boxed_min(),
source.dateindex.boxed_max(),
source.dateindex.boxed_sum(),
source.dateindex.boxed_cumulative(),
),
weekindex: period!(weekindex),
monthindex: period!(monthindex),
quarterindex: period!(quarterindex),
semesterindex: period!(semesterindex),
yearindex: period!(yearindex),
decadeindex: period!(decadeindex),
}
}
}

View File

@@ -0,0 +1,9 @@
mod distribution;
mod full;
mod lazy_full;
mod value_full;
pub use distribution::*;
pub use full::*;
pub use lazy_full::*;
pub use value_full::*;

View File

@@ -0,0 +1,101 @@
//! Value type for Full pattern from TxIndex.
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, Sats, TxIndex, Version};
use vecdb::{CollectableVec, Database, Exit, IterableCloneableVec};
use crate::{
ComputeIndexes, indexes,
internal::{TxDerivedFull, ValueDollarsFromTxFull, LazyTxDerivedFull, SatsToBitcoin},
price,
};
#[derive(Clone, Traversable)]
pub struct ValueTxDerivedFull {
pub sats: TxDerivedFull<Sats>,
pub bitcoin: LazyTxDerivedFull<Bitcoin, Sats>,
pub dollars: Option<ValueDollarsFromTxFull>,
}
const VERSION: Version = Version::ZERO;
impl ValueTxDerivedFull {
pub fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
indexer: &Indexer,
price: Option<&price::Vecs>,
sats_txindex: &impl IterableCloneableVec<TxIndex, Sats>,
) -> Result<Self> {
let v = version + VERSION;
let sats = TxDerivedFull::forced_import(db, name, v, indexes)?;
let bitcoin =
LazyTxDerivedFull::from_computed::<SatsToBitcoin>(&format!("{name}_btc"), v, &sats);
let dollars = price
.map(|price| {
ValueDollarsFromTxFull::forced_import(
db,
&format!("{name}_usd"),
v,
indexes,
&sats.height,
price.usd.split.close.height.boxed_clone(),
sats_txindex.boxed_clone(),
indexer.vecs.transactions.height.boxed_clone(),
)
})
.transpose()?;
Ok(Self {
sats,
bitcoin,
dollars,
})
}
pub fn derive_from(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
txindex_source: &impl CollectableVec<TxIndex, Sats>,
exit: &Exit,
) -> Result<()> {
self.derive_from_with_skip(indexer, indexes, starting_indexes, txindex_source, exit, 0)
}
/// Derive from source, skipping first N transactions per block from all calculations.
///
/// Use `skip_count: 1` to exclude coinbase transactions from fee/feerate stats.
pub fn derive_from_with_skip(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
txindex_source: &impl CollectableVec<TxIndex, Sats>,
exit: &Exit,
skip_count: usize,
) -> Result<()> {
self.sats.derive_from_with_skip(
indexer,
indexes,
starting_indexes,
txindex_source,
exit,
skip_count,
)?;
if let Some(dollars) = self.dollars.as_mut() {
dollars.derive_from(indexer, indexes, starting_indexes, exit)?;
}
Ok(())
}
}