mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -1087,34 +1087,34 @@ pub struct CapGrossInvestorLossMvrvNetPeakPriceProfitSellSoprPattern {
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct AverageCumulativeMaxMedianMinPct10Pct25Pct75Pct90RollingSumPattern {
|
||||
pub average: SeriesPattern18<StoredU64>,
|
||||
pub cumulative: SeriesPattern18<StoredU64>,
|
||||
pub max: SeriesPattern18<StoredU64>,
|
||||
pub median: SeriesPattern18<StoredU64>,
|
||||
pub min: SeriesPattern18<StoredU64>,
|
||||
pub pct10: SeriesPattern18<StoredU64>,
|
||||
pub pct25: SeriesPattern18<StoredU64>,
|
||||
pub pct75: SeriesPattern18<StoredU64>,
|
||||
pub pct90: SeriesPattern18<StoredU64>,
|
||||
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: SeriesPattern18<StoredU64>,
|
||||
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: SeriesPattern18::new(client.clone(), _m(&acc, "average")),
|
||||
cumulative: SeriesPattern18::new(client.clone(), _m(&acc, "cumulative")),
|
||||
max: SeriesPattern18::new(client.clone(), _m(&acc, "max")),
|
||||
median: SeriesPattern18::new(client.clone(), _m(&acc, "median")),
|
||||
min: SeriesPattern18::new(client.clone(), _m(&acc, "min")),
|
||||
pct10: SeriesPattern18::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct25: SeriesPattern18::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct75: SeriesPattern18::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct90: SeriesPattern18::new(client.clone(), _m(&acc, "pct90")),
|
||||
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: SeriesPattern18::new(client.clone(), _m(&acc, "sum")),
|
||||
sum: SeriesPattern1::new(client.clone(), _m(&acc, "sum")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1260,6 +1260,34 @@ impl AverageMaxMedianMinPct10Pct25Pct75Pct90SumPattern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2 {
|
||||
pub average: SeriesPattern18<Weight>,
|
||||
pub max: SeriesPattern18<Weight>,
|
||||
pub median: SeriesPattern18<Weight>,
|
||||
pub min: SeriesPattern18<Weight>,
|
||||
pub pct10: SeriesPattern18<Weight>,
|
||||
pub pct25: SeriesPattern18<Weight>,
|
||||
pub pct75: SeriesPattern18<Weight>,
|
||||
pub pct90: SeriesPattern18<Weight>,
|
||||
}
|
||||
|
||||
impl AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2 {
|
||||
/// Create a new pattern node with accumulated series name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
average: SeriesPattern18::new(client.clone(), _m(&acc, "average")),
|
||||
max: SeriesPattern18::new(client.clone(), _m(&acc, "max")),
|
||||
median: SeriesPattern18::new(client.clone(), _m(&acc, "median")),
|
||||
min: SeriesPattern18::new(client.clone(), _m(&acc, "min")),
|
||||
pct10: SeriesPattern18::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct25: SeriesPattern18::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct75: SeriesPattern18::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct90: SeriesPattern18::new(client.clone(), _m(&acc, "pct90")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct BaseCapitulationCumulativeNegativeSumToValuePattern {
|
||||
pub base: CentsUsdPattern2,
|
||||
@@ -1286,28 +1314,28 @@ pub struct BpsCentsPercentilesRatioSatsSmaStdUsdPattern {
|
||||
|
||||
/// Pattern struct for repeated tree structure.
|
||||
pub struct AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern<T> {
|
||||
pub average: SeriesPattern18<T>,
|
||||
pub max: SeriesPattern18<T>,
|
||||
pub median: SeriesPattern18<T>,
|
||||
pub min: SeriesPattern18<T>,
|
||||
pub pct10: SeriesPattern18<T>,
|
||||
pub pct25: SeriesPattern18<T>,
|
||||
pub pct75: SeriesPattern18<T>,
|
||||
pub pct90: SeriesPattern18<T>,
|
||||
pub average: SeriesPattern1<T>,
|
||||
pub max: SeriesPattern1<T>,
|
||||
pub median: SeriesPattern1<T>,
|
||||
pub min: SeriesPattern1<T>,
|
||||
pub pct10: SeriesPattern1<T>,
|
||||
pub pct25: SeriesPattern1<T>,
|
||||
pub pct75: SeriesPattern1<T>,
|
||||
pub pct90: SeriesPattern1<T>,
|
||||
}
|
||||
|
||||
impl<T: DeserializeOwned> AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern<T> {
|
||||
/// Create a new pattern node with accumulated series name.
|
||||
pub fn new(client: Arc<BrkClientBase>, acc: String) -> Self {
|
||||
Self {
|
||||
average: SeriesPattern18::new(client.clone(), _m(&acc, "average")),
|
||||
max: SeriesPattern18::new(client.clone(), _m(&acc, "max")),
|
||||
median: SeriesPattern18::new(client.clone(), _m(&acc, "median")),
|
||||
min: SeriesPattern18::new(client.clone(), _m(&acc, "min")),
|
||||
pct10: SeriesPattern18::new(client.clone(), _m(&acc, "pct10")),
|
||||
pct25: SeriesPattern18::new(client.clone(), _m(&acc, "pct25")),
|
||||
pct75: SeriesPattern18::new(client.clone(), _m(&acc, "pct75")),
|
||||
pct90: SeriesPattern18::new(client.clone(), _m(&acc, "pct90")),
|
||||
average: SeriesPattern1::new(client.clone(), _m(&acc, "average")),
|
||||
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")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3086,14 +3114,14 @@ impl SeriesTree_Blocks_Weight {
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Blocks_Count {
|
||||
pub target: SeriesPattern1<StoredU64>,
|
||||
pub target: _1m1w1y24hPattern<StoredU64>,
|
||||
pub total: BaseCumulativeSumPattern2,
|
||||
}
|
||||
|
||||
impl SeriesTree_Blocks_Count {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
target: SeriesPattern1::new(client.clone(), "block_count_target".to_string()),
|
||||
target: _1m1w1y24hPattern::new(client.clone(), "block_count_target".to_string()),
|
||||
total: BaseCumulativeSumPattern2::new(client.clone(), "block_count".to_string()),
|
||||
}
|
||||
}
|
||||
@@ -3198,17 +3226,17 @@ impl SeriesTree_Blocks_Lookback {
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Blocks_Fullness {
|
||||
pub bps: _1m1w1y24hBasePattern<BasisPoints16>,
|
||||
pub ratio: SeriesPattern1<StoredF32>,
|
||||
pub percent: SeriesPattern1<StoredF32>,
|
||||
pub bps: SeriesPattern18<BasisPoints16>,
|
||||
pub ratio: SeriesPattern18<StoredF32>,
|
||||
pub percent: SeriesPattern18<StoredF32>,
|
||||
}
|
||||
|
||||
impl SeriesTree_Blocks_Fullness {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
bps: _1m1w1y24hBasePattern::new(client.clone(), "block_fullness_bps".to_string()),
|
||||
ratio: SeriesPattern1::new(client.clone(), "block_fullness_ratio".to_string()),
|
||||
percent: SeriesPattern1::new(client.clone(), "block_fullness".to_string()),
|
||||
bps: SeriesPattern18::new(client.clone(), "block_fullness_bps".to_string()),
|
||||
ratio: SeriesPattern18::new(client.clone(), "block_fullness_ratio".to_string()),
|
||||
percent: SeriesPattern18::new(client.clone(), "block_fullness".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3302,14 +3330,31 @@ impl SeriesTree_Transactions_Count {
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Transactions_Size {
|
||||
pub vsize: _6bBlockTxPattern<VSize>,
|
||||
pub weight: _6bBlockTxPattern<Weight>,
|
||||
pub weight: SeriesTree_Transactions_Size_Weight,
|
||||
}
|
||||
|
||||
impl SeriesTree_Transactions_Size {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
vsize: _6bBlockTxPattern::new(client.clone(), "tx_vsize".to_string()),
|
||||
weight: _6bBlockTxPattern::new(client.clone(), "tx_weight".to_string()),
|
||||
weight: SeriesTree_Transactions_Size_Weight::new(client.clone(), format!("{base_path}_weight")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Transactions_Size_Weight {
|
||||
pub tx_index: SeriesPattern19<Weight>,
|
||||
pub block: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2,
|
||||
pub _6b: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2,
|
||||
}
|
||||
|
||||
impl SeriesTree_Transactions_Size_Weight {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
tx_index: SeriesPattern19::new(client.clone(), "tx_weight".to_string()),
|
||||
block: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2::new(client.clone(), "tx_weight".to_string()),
|
||||
_6b: AverageMaxMedianMinPct10Pct25Pct75Pct90Pattern2::new(client.clone(), "tx_weight_6b".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3353,7 +3398,6 @@ impl SeriesTree_Transactions_Versions {
|
||||
/// Series tree node.
|
||||
pub struct SeriesTree_Transactions_Volume {
|
||||
pub transfer_volume: BaseCumulativeSumPattern4,
|
||||
pub output_volume: BaseCumulativeSumPattern4,
|
||||
pub tx_per_sec: SeriesPattern1<StoredF32>,
|
||||
pub outputs_per_sec: SeriesPattern1<StoredF32>,
|
||||
pub inputs_per_sec: SeriesPattern1<StoredF32>,
|
||||
@@ -3363,7 +3407,6 @@ impl SeriesTree_Transactions_Volume {
|
||||
pub fn new(client: Arc<BrkClientBase>, base_path: String) -> Self {
|
||||
Self {
|
||||
transfer_volume: BaseCumulativeSumPattern4::new(client.clone(), "transfer_volume_bis".to_string()),
|
||||
output_volume: BaseCumulativeSumPattern4::new(client.clone(), "output_volume".to_string()),
|
||||
tx_per_sec: SeriesPattern1::new(client.clone(), "tx_per_sec".to_string()),
|
||||
outputs_per_sec: SeriesPattern1::new(client.clone(), "outputs_per_sec".to_string()),
|
||||
inputs_per_sec: SeriesPattern1::new(client.clone(), "inputs_per_sec".to_string()),
|
||||
|
||||
@@ -5,7 +5,10 @@ use vecdb::Database;
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BlockCountTarget, CachedWindowStarts, PerBlockCumulativeWithSums, ConstantVecs},
|
||||
internal::{
|
||||
BlockCountTarget24h, BlockCountTarget1w, BlockCountTarget1m, BlockCountTarget1y,
|
||||
CachedWindowStarts, PerBlockCumulativeWithSums, ConstantVecs, Windows,
|
||||
},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -16,11 +19,12 @@ impl Vecs {
|
||||
cached_starts: &CachedWindowStarts,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
target: ConstantVecs::new::<BlockCountTarget>(
|
||||
"block_count_target",
|
||||
version,
|
||||
indexes,
|
||||
),
|
||||
target: Windows {
|
||||
_24h: ConstantVecs::new::<BlockCountTarget24h>("block_count_target_24h", version, indexes),
|
||||
_1w: ConstantVecs::new::<BlockCountTarget1w>("block_count_target_1w", version, indexes),
|
||||
_1m: ConstantVecs::new::<BlockCountTarget1m>("block_count_target_1m", version, indexes),
|
||||
_1y: ConstantVecs::new::<BlockCountTarget1y>("block_count_target_1y", version, indexes),
|
||||
},
|
||||
total: PerBlockCumulativeWithSums::forced_import(
|
||||
db,
|
||||
"block_count",
|
||||
|
||||
@@ -2,10 +2,10 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{StoredU32, StoredU64};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{PerBlockCumulativeWithSums, ConstantVecs};
|
||||
use crate::internal::{PerBlockCumulativeWithSums, ConstantVecs, Windows};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub target: ConstantVecs<StoredU64>,
|
||||
pub target: Windows<ConstantVecs<StoredU64>>,
|
||||
pub total: PerBlockCumulativeWithSums<StoredU32, StoredU64, M>,
|
||||
}
|
||||
|
||||
@@ -26,20 +26,12 @@ pub const DB_NAME: &str = "blocks";
|
||||
|
||||
pub(crate) const TARGET_BLOCKS_PER_DAY_F64: f64 = 144.0;
|
||||
pub(crate) const TARGET_BLOCKS_PER_DAY_F32: f32 = 144.0;
|
||||
pub(crate) const TARGET_BLOCKS_PER_MINUTE10: u64 = 1;
|
||||
pub(crate) const TARGET_BLOCKS_PER_MINUTE30: u64 = 3;
|
||||
pub(crate) const TARGET_BLOCKS_PER_HOUR1: u64 = 6;
|
||||
pub(crate) const TARGET_BLOCKS_PER_HOUR4: u64 = 24;
|
||||
pub(crate) const TARGET_BLOCKS_PER_HOUR12: u64 = 72;
|
||||
pub(crate) const TARGET_BLOCKS_PER_DAY: u64 = 144;
|
||||
pub(crate) const TARGET_BLOCKS_PER_DAY3: u64 = 3 * TARGET_BLOCKS_PER_DAY;
|
||||
pub(crate) const TARGET_BLOCKS_PER_WEEK: u64 = 7 * TARGET_BLOCKS_PER_DAY;
|
||||
pub(crate) const TARGET_BLOCKS_PER_MONTH: u64 = 30 * TARGET_BLOCKS_PER_DAY;
|
||||
pub(crate) const TARGET_BLOCKS_PER_QUARTER: u64 = 3 * TARGET_BLOCKS_PER_MONTH;
|
||||
pub(crate) const TARGET_BLOCKS_PER_SEMESTER: u64 = 2 * TARGET_BLOCKS_PER_QUARTER;
|
||||
pub(crate) const TARGET_BLOCKS_PER_YEAR: u64 = 2 * TARGET_BLOCKS_PER_SEMESTER;
|
||||
pub(crate) const TARGET_BLOCKS_PER_DECADE: u64 = 10 * TARGET_BLOCKS_PER_YEAR;
|
||||
pub(crate) const TARGET_BLOCKS_PER_HALVING: u64 = 210_000;
|
||||
pub(crate) const ONE_TERA_HASH: f64 = 1_000_000_000_000.0;
|
||||
|
||||
#[derive(Traversable)]
|
||||
|
||||
@@ -12,16 +12,12 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.fullness
|
||||
.compute(starting_indexes.height, exit, |vec| {
|
||||
vec.compute_transform(
|
||||
starting_indexes.height,
|
||||
&indexer.vecs.blocks.weight,
|
||||
|(h, weight, ..)| (h, BasisPoints16::from(weight.fullness())),
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
})?;
|
||||
self.fullness.bps.compute_transform(
|
||||
starting_indexes.height,
|
||||
&indexer.vecs.blocks.weight,
|
||||
|(h, weight, ..)| (h, BasisPoints16::from(weight.fullness())),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use super::Vecs;
|
||||
use crate::{
|
||||
blocks::SizeVecs,
|
||||
indexes,
|
||||
internal::{CachedWindowStarts, LazyPerBlockRolling, PercentPerBlockRollingAverage, VBytesToWeight},
|
||||
internal::{CachedWindowStarts, LazyPerBlockRolling, PercentVec, VBytesToWeight},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -25,13 +25,7 @@ impl Vecs {
|
||||
indexes,
|
||||
);
|
||||
|
||||
let fullness = PercentPerBlockRollingAverage::forced_import(
|
||||
db,
|
||||
"block_fullness",
|
||||
version,
|
||||
indexes,
|
||||
cached_starts,
|
||||
)?;
|
||||
let fullness = PercentVec::forced_import(db, "block_fullness", version)?;
|
||||
|
||||
Ok(Self { weight, fullness })
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPoints16, StoredU64, Weight};
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{LazyPerBlockRolling, PercentPerBlockRollingAverage};
|
||||
use crate::internal::{LazyPerBlockRolling, PercentVec};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub weight: LazyPerBlockRolling<Weight, StoredU64>,
|
||||
pub fullness: PercentPerBlockRollingAverage<BasisPoints16, M>,
|
||||
pub fullness: PercentVec<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
let height_to_input_count = &inputs.count.full.sum;
|
||||
let height_to_output_count = &outputs.count.total.full.sum.height;
|
||||
let height_to_input_count = &inputs.count.full.sum.height;
|
||||
let tx_index_to_output_count = &indexes.tx_index.output_count;
|
||||
let tx_index_to_input_count = &indexes.tx_index.input_count;
|
||||
|
||||
|
||||
@@ -35,12 +35,14 @@ pub(super) fn compute(
|
||||
gini.bps
|
||||
.height
|
||||
.validate_computed_version_or_reset(source_version)?;
|
||||
gini.bps.height.truncate_if_needed_at(
|
||||
gini.bps
|
||||
.height
|
||||
.len()
|
||||
.min(starting_indexes.height.to_usize()),
|
||||
)?;
|
||||
|
||||
let min_len = gini
|
||||
.bps
|
||||
.height
|
||||
.len()
|
||||
.min(starting_indexes.height.to_usize());
|
||||
|
||||
gini.bps.height.truncate_if_needed_at(min_len)?;
|
||||
|
||||
let total_heights = supply_vecs
|
||||
.iter()
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{
|
||||
CheckedSub, Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableVec, Ro, Rw, StorageMode,
|
||||
StoredVec, VecIndex, VecValue, Version,
|
||||
};
|
||||
|
||||
use crate::internal::{
|
||||
ComputedVecValue, DistributionStats,
|
||||
algo::{compute_aggregations, compute_aggregations_nblock_window},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Distribution<I: VecIndex, T: ComputedVecValue + JsonSchema, M: StorageMode = Rw> {
|
||||
pub average: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub min: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub max: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub pct10: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub pct25: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub median: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub pct75: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub pct90: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
}
|
||||
|
||||
impl<I: VecIndex, T: ComputedVecValue + JsonSchema> Distribution<I, T> {
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
|
||||
let s = DistributionStats::<()>::SUFFIXES;
|
||||
Ok(Self {
|
||||
average: EagerVec::forced_import(db, &format!("{name}_{}", s[0]), version)?,
|
||||
min: EagerVec::forced_import(db, &format!("{name}_{}", s[1]), version)?,
|
||||
max: EagerVec::forced_import(db, &format!("{name}_{}", s[2]), version)?,
|
||||
pct10: EagerVec::forced_import(db, &format!("{name}_{}", s[3]), version)?,
|
||||
pct25: EagerVec::forced_import(db, &format!("{name}_{}", s[4]), version)?,
|
||||
median: EagerVec::forced_import(db, &format!("{name}_{}", s[5]), version)?,
|
||||
pct75: EagerVec::forced_import(db, &format!("{name}_{}", s[6]), version)?,
|
||||
pct90: EagerVec::forced_import(db, &format!("{name}_{}", s[7]), version)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute distribution stats, skipping first N items from all calculations.
|
||||
///
|
||||
/// Use `skip_count: 1` to exclude coinbase transactions from fee/feerate stats.
|
||||
pub(crate) fn compute_with_skip<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>,
|
||||
exit: &Exit,
|
||||
skip_count: usize,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
|
||||
{
|
||||
compute_aggregations(
|
||||
max_from,
|
||||
source,
|
||||
first_indexes,
|
||||
count_indexes,
|
||||
exit,
|
||||
skip_count,
|
||||
None, // first
|
||||
None, // last
|
||||
Some(&mut self.min),
|
||||
Some(&mut self.max),
|
||||
Some(&mut self.average),
|
||||
None, // sum
|
||||
None, // cumulative
|
||||
Some(&mut self.median),
|
||||
Some(&mut self.pct10),
|
||||
Some(&mut self.pct25),
|
||||
Some(&mut self.pct75),
|
||||
Some(&mut self.pct90),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute distribution stats from a fixed n-block rolling window.
|
||||
///
|
||||
/// 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> + Sized),
|
||||
first_indexes: &impl ReadableVec<I, A>,
|
||||
count_indexes: &impl ReadableVec<I, brk_types::StoredU64>,
|
||||
n_blocks: usize,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: CheckedSub,
|
||||
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
|
||||
{
|
||||
compute_aggregations_nblock_window(
|
||||
max_from,
|
||||
source,
|
||||
first_indexes,
|
||||
count_indexes,
|
||||
n_blocks,
|
||||
exit,
|
||||
&mut self.min,
|
||||
&mut self.max,
|
||||
&mut self.average,
|
||||
&mut self.median,
|
||||
&mut self.pct10,
|
||||
&mut self.pct25,
|
||||
&mut self.pct75,
|
||||
&mut self.pct90,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn read_only_clone(&self) -> Distribution<I, T, Ro> {
|
||||
Distribution {
|
||||
average: StoredVec::read_only_clone(&self.average),
|
||||
min: StoredVec::read_only_clone(&self.min),
|
||||
max: StoredVec::read_only_clone(&self.max),
|
||||
pct10: StoredVec::read_only_clone(&self.pct10),
|
||||
pct25: StoredVec::read_only_clone(&self.pct25),
|
||||
median: StoredVec::read_only_clone(&self.median),
|
||||
pct75: StoredVec::read_only_clone(&self.pct75),
|
||||
pct90: StoredVec::read_only_clone(&self.pct90),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{
|
||||
Database, EagerVec, Exit, ImportableVec, PcoVec, ReadableVec, Ro, Rw, StorageMode, StoredVec,
|
||||
VecIndex, VecValue, Version,
|
||||
};
|
||||
|
||||
use crate::internal::{ComputedVecValue, algo::compute_aggregations};
|
||||
|
||||
use super::Distribution;
|
||||
|
||||
/// Full stats aggregate: sum + cumulative + distribution
|
||||
#[derive(Traversable)]
|
||||
pub struct DistributionFull<I: VecIndex, T: ComputedVecValue + JsonSchema, M: StorageMode = Rw> {
|
||||
pub sum: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
pub cumulative: M::Stored<EagerVec<PcoVec<I, T>>>,
|
||||
#[traversable(flatten)]
|
||||
pub distribution: Distribution<I, T, M>,
|
||||
}
|
||||
|
||||
impl<I: VecIndex, T: ComputedVecValue + JsonSchema> DistributionFull<I, T> {
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
|
||||
Ok(Self {
|
||||
distribution: Distribution::forced_import(db, name, version)?,
|
||||
sum: EagerVec::forced_import(db, &format!("{name}_sum"), version)?,
|
||||
cumulative: EagerVec::forced_import(db, &format!("{name}_cumulative"), version)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute all stats, skipping first N items from all calculations.
|
||||
///
|
||||
/// Use `skip_count: 1` to exclude coinbase transactions from fee/feerate stats.
|
||||
pub(crate) fn compute_with_skip<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>,
|
||||
exit: &Exit,
|
||||
skip_count: usize,
|
||||
) -> Result<()>
|
||||
where
|
||||
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
|
||||
{
|
||||
compute_aggregations(
|
||||
max_from,
|
||||
source,
|
||||
first_indexes,
|
||||
count_indexes,
|
||||
exit,
|
||||
skip_count,
|
||||
None, // first
|
||||
None, // last
|
||||
Some(&mut self.distribution.min),
|
||||
Some(&mut self.distribution.max),
|
||||
Some(&mut self.distribution.average),
|
||||
Some(&mut self.sum),
|
||||
Some(&mut self.cumulative),
|
||||
Some(&mut self.distribution.median),
|
||||
Some(&mut self.distribution.pct10),
|
||||
Some(&mut self.distribution.pct25),
|
||||
Some(&mut self.distribution.pct75),
|
||||
Some(&mut self.distribution.pct90),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn read_only_clone(&self) -> DistributionFull<I, T, Ro> {
|
||||
DistributionFull {
|
||||
distribution: self.distribution.read_only_clone(),
|
||||
sum: StoredVec::read_only_clone(&self.sum),
|
||||
cumulative: StoredVec::read_only_clone(&self.cumulative),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
mod distribution;
|
||||
mod distribution_full;
|
||||
mod lazy_distribution;
|
||||
|
||||
pub use distribution::*;
|
||||
pub use distribution_full::*;
|
||||
pub use lazy_distribution::*;
|
||||
@@ -4,10 +4,12 @@ mod per_resolution;
|
||||
mod window_24h;
|
||||
mod windows;
|
||||
mod windows_from_1w;
|
||||
mod percent;
|
||||
mod windows_to_1m;
|
||||
|
||||
pub use constant::*;
|
||||
pub use distribution_stats::*;
|
||||
pub use percent::*;
|
||||
pub use per_resolution::*;
|
||||
pub use window_24h::*;
|
||||
pub use windows::*;
|
||||
|
||||
8
crates/brk_computer/src/internal/containers/percent.rs
Normal file
8
crates/brk_computer/src/internal/containers/percent.rs
Normal file
@@ -0,0 +1,8 @@
|
||||
use brk_traversable::Traversable;
|
||||
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Percent<A, B = A, C = B> {
|
||||
pub bps: A,
|
||||
pub ratio: B,
|
||||
pub percent: C,
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
mod aggregate;
|
||||
pub(crate) mod algo;
|
||||
mod amount;
|
||||
mod containers;
|
||||
@@ -9,7 +8,6 @@ mod indexes;
|
||||
mod traits;
|
||||
mod transform;
|
||||
|
||||
pub(crate) use aggregate::*;
|
||||
pub(crate) use amount::*;
|
||||
pub(crate) use containers::*;
|
||||
pub(crate) use per_block::*;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! PerBlockAggregated - DistributionFull (distribution + sum + cumulative) + RollingComplete.
|
||||
//! 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.
|
||||
@@ -11,7 +11,7 @@ use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{CachedWindowStarts, DistributionFull, NumericValue, RollingComplete, WindowStarts},
|
||||
internal::{CachedWindowStarts, PerBlockDistributionFull, NumericValue, RollingComplete, WindowStarts},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
@@ -20,7 +20,7 @@ where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
#[traversable(flatten)]
|
||||
pub full: DistributionFull<Height, T, M>,
|
||||
pub full: PerBlockDistributionFull<T, M>,
|
||||
pub rolling: RollingComplete<T, M>,
|
||||
}
|
||||
|
||||
@@ -35,26 +35,26 @@ where
|
||||
indexes: &indexes::Vecs,
|
||||
cached_starts: &CachedWindowStarts,
|
||||
) -> Result<Self> {
|
||||
let full = DistributionFull::forced_import(db, name, version)?;
|
||||
let full = PerBlockDistributionFull::forced_import(db, name, version, indexes)?;
|
||||
let rolling = RollingComplete::forced_import(
|
||||
db,
|
||||
name,
|
||||
version,
|
||||
indexes,
|
||||
&full.cumulative,
|
||||
&full.cumulative.height,
|
||||
cached_starts,
|
||||
)?;
|
||||
|
||||
Ok(Self { full, rolling })
|
||||
}
|
||||
|
||||
/// Compute DistributionFull stats via closure, then rolling distribution from the per-block sum.
|
||||
/// Compute PerBlockDistributionFull stats via closure, then rolling distribution from the per-block sum.
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
exit: &Exit,
|
||||
compute_full: impl FnOnce(&mut DistributionFull<Height, T>) -> Result<()>,
|
||||
compute_full: impl FnOnce(&mut PerBlockDistributionFull<T>) -> Result<()>,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: From<f64> + Default + Copy + Ord,
|
||||
@@ -62,7 +62,7 @@ where
|
||||
{
|
||||
compute_full(&mut self.full)?;
|
||||
self.rolling
|
||||
.compute(max_from, windows, &self.full.sum, exit)?;
|
||||
.compute(max_from, windows, &self.full.sum.height, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::Height;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{
|
||||
CheckedSub, Database, Exit, ReadableVec, Rw, StorageMode,
|
||||
VecIndex, VecValue, Version,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
ComputedVecValue, DistributionStats, NumericValue, PerBlock,
|
||||
algo::{compute_aggregations, compute_aggregations_nblock_window},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct PerBlockDistribution<T: ComputedVecValue + PartialOrd + JsonSchema, M: StorageMode = Rw>(
|
||||
pub DistributionStats<PerBlock<T, M>>,
|
||||
);
|
||||
|
||||
impl<T: NumericValue + JsonSchema> PerBlockDistribution<T> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self(DistributionStats::try_from_fn(|suffix| {
|
||||
PerBlock::forced_import(db, &format!("{name}_{suffix}"), 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 s = &mut self.0;
|
||||
compute_aggregations(
|
||||
max_from,
|
||||
source,
|
||||
first_indexes,
|
||||
count_indexes,
|
||||
exit,
|
||||
skip_count,
|
||||
None,
|
||||
None,
|
||||
Some(&mut s.min.height),
|
||||
Some(&mut s.max.height),
|
||||
Some(&mut s.average.height),
|
||||
None,
|
||||
None,
|
||||
Some(&mut s.median.height),
|
||||
Some(&mut s.pct10.height),
|
||||
Some(&mut s.pct25.height),
|
||||
Some(&mut s.pct75.height),
|
||||
Some(&mut s.pct90.height),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_nblocks<A>(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
source: &(impl ReadableVec<A, T> + Sized),
|
||||
first_indexes: &impl ReadableVec<Height, A>,
|
||||
count_indexes: &impl ReadableVec<Height, brk_types::StoredU64>,
|
||||
n_blocks: usize,
|
||||
exit: &Exit,
|
||||
) -> Result<()>
|
||||
where
|
||||
T: CheckedSub,
|
||||
A: VecIndex + VecValue + brk_types::CheckedSub<A>,
|
||||
{
|
||||
let s = &mut self.0;
|
||||
compute_aggregations_nblock_window(
|
||||
max_from,
|
||||
source,
|
||||
first_indexes,
|
||||
count_indexes,
|
||||
n_blocks,
|
||||
exit,
|
||||
&mut s.min.height,
|
||||
&mut s.max.height,
|
||||
&mut s.average.height,
|
||||
&mut s.median.height,
|
||||
&mut s.pct10.height,
|
||||
&mut s.pct25.height,
|
||||
&mut s.pct75.height,
|
||||
&mut s.pct90.height,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
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),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ use brk_types::{Height, Version};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{LazyVecFrom1, ReadableCloneableVec, UnaryTransform, VecIndex};
|
||||
|
||||
use crate::internal::{ComputedVecValue, Distribution, DistributionStats};
|
||||
use crate::internal::{ComputedVecValue, PerBlockDistribution, DistributionStats};
|
||||
|
||||
/// Lazy analog of `Distribution<I, T>`: 8 `LazyVecFrom1` fields,
|
||||
/// each derived by transforming the corresponding field of a source `Distribution<I, S1T>`.
|
||||
/// Lazy analog of `Distribution<T>`: 8 `LazyVecFrom1` fields,
|
||||
/// each derived by transforming the corresponding field of a source `PerBlockDistribution<S1T>`.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyDistribution<I, T, S1T>
|
||||
where
|
||||
@@ -27,54 +27,54 @@ where
|
||||
impl<T, S1T> LazyDistribution<Height, T, S1T>
|
||||
where
|
||||
T: ComputedVecValue + JsonSchema + 'static,
|
||||
S1T: ComputedVecValue + JsonSchema,
|
||||
S1T: ComputedVecValue + PartialOrd + JsonSchema,
|
||||
{
|
||||
pub(crate) fn from_distribution<F: UnaryTransform<S1T, T>>(
|
||||
name: &str,
|
||||
version: Version,
|
||||
source: &Distribution<Height, S1T>,
|
||||
source: &PerBlockDistribution<S1T>,
|
||||
) -> Self {
|
||||
let s = DistributionStats::<()>::SUFFIXES;
|
||||
Self {
|
||||
average: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[0]),
|
||||
version,
|
||||
source.average.read_only_boxed_clone(),
|
||||
source.average.height.read_only_boxed_clone(),
|
||||
),
|
||||
min: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[1]),
|
||||
version,
|
||||
source.min.read_only_boxed_clone(),
|
||||
source.min.height.read_only_boxed_clone(),
|
||||
),
|
||||
max: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[2]),
|
||||
version,
|
||||
source.max.read_only_boxed_clone(),
|
||||
source.max.height.read_only_boxed_clone(),
|
||||
),
|
||||
pct10: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[3]),
|
||||
version,
|
||||
source.pct10.read_only_boxed_clone(),
|
||||
source.pct10.height.read_only_boxed_clone(),
|
||||
),
|
||||
pct25: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[4]),
|
||||
version,
|
||||
source.pct25.read_only_boxed_clone(),
|
||||
source.pct25.height.read_only_boxed_clone(),
|
||||
),
|
||||
median: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[5]),
|
||||
version,
|
||||
source.median.read_only_boxed_clone(),
|
||||
source.median.height.read_only_boxed_clone(),
|
||||
),
|
||||
pct75: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[6]),
|
||||
version,
|
||||
source.pct75.read_only_boxed_clone(),
|
||||
source.pct75.height.read_only_boxed_clone(),
|
||||
),
|
||||
pct90: LazyVecFrom1::transformed::<F>(
|
||||
&format!("{name}_{}", s[7]),
|
||||
version,
|
||||
source.pct90.read_only_boxed_clone(),
|
||||
source.pct90.height.read_only_boxed_clone(),
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,13 @@ mod aggregated;
|
||||
mod base;
|
||||
mod cumulative;
|
||||
mod cumulative_sum;
|
||||
mod distribution;
|
||||
mod distribution_full;
|
||||
mod full;
|
||||
mod lazy_distribution;
|
||||
mod lazy_rolling;
|
||||
mod resolutions;
|
||||
mod rolling;
|
||||
mod lazy_rolling;
|
||||
mod full;
|
||||
mod rolling_average;
|
||||
mod with_deltas;
|
||||
|
||||
@@ -13,9 +16,12 @@ pub use aggregated::*;
|
||||
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::*;
|
||||
pub use resolutions::*;
|
||||
pub use rolling::*;
|
||||
pub use lazy_rolling::*;
|
||||
pub use full::*;
|
||||
pub use rolling_average::*;
|
||||
pub use with_deltas::*;
|
||||
|
||||
@@ -2,11 +2,11 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{LazyVecFrom1, ReadableBoxedVec, ReadableCloneableVec, UnaryTransform};
|
||||
use vecdb::{LazyVecFrom1, ReadOnlyClone, ReadableBoxedVec, ReadableCloneableVec, UnaryTransform};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{PerBlock, ComputedVecValue, DerivedResolutions, NumericValue},
|
||||
internal::{ComputedVecValue, DerivedResolutions, NumericValue, PerBlock},
|
||||
};
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(merge)]
|
||||
@@ -38,7 +38,9 @@ where
|
||||
{
|
||||
Self {
|
||||
height: LazyVecFrom1::transformed::<F>(name, version, height_source),
|
||||
resolutions: Box::new(DerivedResolutions::from_computed::<F>(name, version, source)),
|
||||
resolutions: Box::new(DerivedResolutions::from_computed::<F>(
|
||||
name, version, source,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,3 +88,14 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S1T> ReadOnlyClone for LazyPerBlock<T, S1T>
|
||||
where
|
||||
T: ComputedVecValue + PartialOrd + JsonSchema,
|
||||
S1T: ComputedVecValue,
|
||||
{
|
||||
type ReadOnly = Self;
|
||||
fn read_only_clone(&self) -> Self {
|
||||
self.clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, StoredF32, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{
|
||||
BinaryTransform, Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode, VecValue,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, algo::ComputeDrawdown},
|
||||
internal::{BpsType, Percent, algo::ComputeDrawdown},
|
||||
};
|
||||
|
||||
use crate::internal::{PerBlock, LazyPerBlock};
|
||||
use crate::internal::{LazyPerBlock, PerBlock};
|
||||
|
||||
/// Basis-point storage with both ratio and percentage float views.
|
||||
///
|
||||
@@ -18,12 +19,11 @@ use crate::internal::{PerBlock, LazyPerBlock};
|
||||
/// exposes two lazy StoredF32 views:
|
||||
/// - `ratio`: bps / 10000 (e.g., 4523 bps -> 0.4523)
|
||||
/// - `percent`: bps / 100 (e.g., 4523 bps -> 45.23%)
|
||||
#[derive(Traversable)]
|
||||
pub struct PercentPerBlock<B: BpsType, M: StorageMode = Rw> {
|
||||
pub bps: PerBlock<B, M>,
|
||||
pub ratio: LazyPerBlock<StoredF32, B>,
|
||||
pub percent: LazyPerBlock<StoredF32, B>,
|
||||
}
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct PercentPerBlock<B: BpsType, M: StorageMode = Rw>(
|
||||
pub Percent<PerBlock<B, M>, LazyPerBlock<StoredF32, B>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> PercentPerBlock<B> {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -44,11 +44,11 @@ impl<B: BpsType> PercentPerBlock<B> {
|
||||
|
||||
let percent = LazyPerBlock::from_computed::<B::ToPercent>(name, version, bps_clone, &bps);
|
||||
|
||||
Ok(Self {
|
||||
Ok(Self(Percent {
|
||||
bps,
|
||||
ratio,
|
||||
percent,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn compute_binary<S1T, S2T, F>(
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{ReadableCloneableVec, UnaryTransform};
|
||||
|
||||
use crate::internal::{BpsType, LazyPerBlock, PercentPerBlock};
|
||||
use crate::internal::{BpsType, LazyPerBlock, Percent, PercentPerBlock};
|
||||
|
||||
/// Fully lazy variant of `PercentPerBlock` — no stored vecs.
|
||||
///
|
||||
/// BPS values are lazily derived from a source `PercentPerBlock` via a unary transform,
|
||||
/// and ratio/percent float views are chained from the lazy BPS.
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct LazyPercentPerBlock<B: BpsType> {
|
||||
pub bps: LazyPerBlock<B, B>,
|
||||
pub ratio: LazyPerBlock<StoredF32, B>,
|
||||
pub percent: LazyPerBlock<StoredF32, B>,
|
||||
}
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct LazyPercentPerBlock<B: BpsType>(
|
||||
pub Percent<LazyPerBlock<B, B>, LazyPerBlock<StoredF32, B>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> LazyPercentPerBlock<B> {
|
||||
/// Create from a stored `PercentPerBlock` source via a BPS-to-BPS unary transform.
|
||||
@@ -37,10 +37,10 @@ impl<B: BpsType> LazyPercentPerBlock<B> {
|
||||
|
||||
let percent = LazyPerBlock::from_lazy::<B::ToPercent, B>(name, version, &bps);
|
||||
|
||||
Self {
|
||||
Self(Percent {
|
||||
bps,
|
||||
ratio,
|
||||
percent,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
mod base;
|
||||
mod lazy;
|
||||
mod lazy_windows;
|
||||
mod rolling_average;
|
||||
mod vec;
|
||||
mod windows;
|
||||
|
||||
pub use base::*;
|
||||
pub use lazy::*;
|
||||
pub use lazy_windows::*;
|
||||
pub use rolling_average::*;
|
||||
pub use vec::*;
|
||||
pub use windows::*;
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, StoredF32, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{BpsType, CachedWindowStarts},
|
||||
};
|
||||
|
||||
use crate::internal::{PerBlockRollingAverage, LazyPerBlock};
|
||||
|
||||
/// Like PercentPerBlock but with rolling average stats on the bps data.
|
||||
#[derive(Traversable)]
|
||||
pub struct PercentPerBlockRollingAverage<B: BpsType, M: StorageMode = Rw> {
|
||||
pub bps: PerBlockRollingAverage<B, M>,
|
||||
pub ratio: LazyPerBlock<StoredF32, B>,
|
||||
pub percent: LazyPerBlock<StoredF32, B>,
|
||||
}
|
||||
|
||||
impl<B: BpsType> PercentPerBlockRollingAverage<B> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
cached_starts: &CachedWindowStarts,
|
||||
) -> Result<Self> {
|
||||
let bps = PerBlockRollingAverage::forced_import(
|
||||
db,
|
||||
&format!("{name}_bps"),
|
||||
version,
|
||||
indexes,
|
||||
cached_starts,
|
||||
)?;
|
||||
|
||||
let ratio = LazyPerBlock::from_height_source::<B::ToRatio>(
|
||||
&format!("{name}_ratio"),
|
||||
version,
|
||||
bps.base.read_only_boxed_clone(),
|
||||
indexes,
|
||||
);
|
||||
|
||||
let percent = LazyPerBlock::from_height_source::<B::ToPercent>(
|
||||
name,
|
||||
version,
|
||||
bps.base.read_only_boxed_clone(),
|
||||
indexes,
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
bps,
|
||||
ratio,
|
||||
percent,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
compute_height: impl FnOnce(&mut EagerVec<PcoVec<Height, B>>) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
self.bps.compute(max_from, exit, compute_height)
|
||||
}
|
||||
}
|
||||
43
crates/brk_computer/src/internal/per_block/percent/vec.rs
Normal file
43
crates/brk_computer/src/internal/per_block/percent/vec.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, StoredF32, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{
|
||||
Database, EagerVec, ImportableVec, LazyVecFrom1, PcoVec, ReadableCloneableVec, Rw, StorageMode,
|
||||
};
|
||||
|
||||
use crate::internal::{BpsType, Percent};
|
||||
|
||||
/// Lightweight percent container: BPS height vec + lazy ratio + lazy percent.
|
||||
/// No resolutions, no rolling stats.
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub struct PercentVec<B: BpsType, M: StorageMode = Rw>(
|
||||
pub Percent<M::Stored<EagerVec<PcoVec<Height, B>>>, LazyVecFrom1<Height, StoredF32, Height, B>>,
|
||||
);
|
||||
|
||||
impl<B: BpsType> PercentVec<B> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
) -> brk_error::Result<Self> {
|
||||
let bps: EagerVec<PcoVec<Height, B>> =
|
||||
EagerVec::forced_import(db, &format!("{name}_bps"), version)?;
|
||||
let bps_clone = bps.read_only_boxed_clone();
|
||||
|
||||
let ratio = LazyVecFrom1::transformed::<B::ToRatio>(
|
||||
&format!("{name}_ratio"),
|
||||
version,
|
||||
bps_clone.clone(),
|
||||
);
|
||||
|
||||
let percent = LazyVecFrom1::transformed::<B::ToPercent>(name, version, bps_clone);
|
||||
|
||||
Ok(Self(Percent {
|
||||
bps,
|
||||
ratio,
|
||||
percent,
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,36 @@
|
||||
//! 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 6 blocks.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Indexes, TxIndex};
|
||||
use brk_types::{Indexes, TxIndex};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode, Version};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedVecValue, Distribution, NumericValue},
|
||||
internal::{ComputedVecValue, NumericValue, PerBlockDistribution},
|
||||
};
|
||||
|
||||
/// 6-block rolling window distribution with 8 distribution stat vecs.
|
||||
#[derive(Traversable)]
|
||||
pub struct BlockRollingDistribution<T, M: StorageMode = Rw>
|
||||
where
|
||||
T: ComputedVecValue + PartialOrd + JsonSchema,
|
||||
{
|
||||
pub _6b: Distribution<Height, T, M>,
|
||||
pub _6b: PerBlockDistribution<T, M>,
|
||||
}
|
||||
|
||||
impl<T> BlockRollingDistribution<T>
|
||||
where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
_6b: Distribution::forced_import(db, &format!("{name}_6b"), version)?,
|
||||
_6b: PerBlockDistribution::forced_import(db, &format!("{name}_6b"), version, indexes)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -41,20 +40,28 @@ pub struct TxDerivedDistribution<T, M: StorageMode = Rw>
|
||||
where
|
||||
T: ComputedVecValue + PartialOrd + JsonSchema,
|
||||
{
|
||||
pub block: Distribution<Height, T, M>,
|
||||
pub block: PerBlockDistribution<T, M>,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: BlockRollingDistribution<T, M>,
|
||||
pub distribution: BlockRollingDistribution<T, M>,
|
||||
}
|
||||
|
||||
impl<T> TxDerivedDistribution<T>
|
||||
where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
|
||||
let block = Distribution::forced_import(db, name, version)?;
|
||||
let rolling = BlockRollingDistribution::forced_import(db, name, version)?;
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let block = PerBlockDistribution::forced_import(db, name, version, indexes)?;
|
||||
let distribution = BlockRollingDistribution::forced_import(db, name, version, indexes)?;
|
||||
|
||||
Ok(Self { block, rolling })
|
||||
Ok(Self {
|
||||
block,
|
||||
distribution,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn derive_from(
|
||||
@@ -72,10 +79,6 @@ where
|
||||
self.derive_from_with_skip(indexer, indexes, starting_indexes, tx_index_source, exit, 0)
|
||||
}
|
||||
|
||||
/// Derive from source, skipping first N transactions per block from per-block stats.
|
||||
///
|
||||
/// Use `skip_count: 1` to exclude coinbase transactions from fee/feerate stats.
|
||||
/// Rolling window distributions do NOT skip (negligible impact over many blocks).
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn derive_from_with_skip(
|
||||
&mut self,
|
||||
@@ -90,7 +93,6 @@ where
|
||||
T: Copy + Ord + From<f64> + Default,
|
||||
f64: From<T>,
|
||||
{
|
||||
// Per-block distribution (supports skip for coinbase exclusion)
|
||||
self.block.compute_with_skip(
|
||||
starting_indexes.height,
|
||||
tx_index_source,
|
||||
@@ -100,8 +102,7 @@ where
|
||||
skip_count,
|
||||
)?;
|
||||
|
||||
// 6-block rolling: true distribution from all txs in last 6 blocks
|
||||
self.rolling._6b.compute_from_nblocks(
|
||||
self.distribution._6b.compute_from_nblocks(
|
||||
starting_indexes.height,
|
||||
tx_index_source,
|
||||
&indexer.vecs.transactions.first_tx_index,
|
||||
|
||||
@@ -29,9 +29,9 @@ impl<T> PerTxDistribution<T>
|
||||
where
|
||||
T: NumericValue + JsonSchema,
|
||||
{
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
|
||||
let tx_index = EagerVec::forced_import(db, name, version)?;
|
||||
let distribution = TxDerivedDistribution::forced_import(db, name, version)?;
|
||||
let distribution = TxDerivedDistribution::forced_import(db, name, version, indexes)?;
|
||||
Ok(Self {
|
||||
tx_index,
|
||||
distribution,
|
||||
|
||||
@@ -14,8 +14,6 @@ where
|
||||
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
|
||||
@@ -24,13 +22,13 @@ where
|
||||
{
|
||||
pub block: LazyDistribution<Height, T, S1T>,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: LazyBlockRollingDistribution<T, S1T>,
|
||||
pub distribution: LazyBlockRollingDistribution<T, S1T>,
|
||||
}
|
||||
|
||||
impl<T, S1T> LazyTxDerivedDistribution<T, S1T>
|
||||
where
|
||||
T: ComputedVecValue + JsonSchema + 'static,
|
||||
S1T: ComputedVecValue + JsonSchema,
|
||||
S1T: ComputedVecValue + PartialOrd + JsonSchema,
|
||||
{
|
||||
pub(crate) fn from_tx_derived<F: UnaryTransform<S1T, T>>(
|
||||
name: &str,
|
||||
@@ -38,13 +36,16 @@ where
|
||||
source: &TxDerivedDistribution<S1T>,
|
||||
) -> Self {
|
||||
let block = LazyDistribution::from_distribution::<F>(name, version, &source.block);
|
||||
let rolling = LazyBlockRollingDistribution {
|
||||
let distribution = LazyBlockRollingDistribution {
|
||||
_6b: LazyDistribution::from_distribution::<F>(
|
||||
&format!("{name}_6b"),
|
||||
version,
|
||||
&source.rolling._6b,
|
||||
&source.distribution._6b,
|
||||
),
|
||||
};
|
||||
Self { block, rolling }
|
||||
Self {
|
||||
block,
|
||||
distribution,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,9 +32,10 @@ where
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
tx_index: LazyVecFrom2<TxIndex, T, TxIndex, S1, TxIndex, S2>,
|
||||
) -> Result<Self> {
|
||||
let distribution = TxDerivedDistribution::forced_import(db, name, version)?;
|
||||
let distribution = TxDerivedDistribution::forced_import(db, name, version, indexes)?;
|
||||
Ok(Self {
|
||||
tx_index,
|
||||
distribution,
|
||||
|
||||
@@ -28,4 +28,4 @@ pub use ratio::{
|
||||
RatioCentsSignedDollarsBps32, RatioDiffCentsBps32, RatioDiffDollarsBps32, RatioDiffF32Bps32,
|
||||
RatioDollarsBp16, RatioDollarsBp32, RatioDollarsBps32, RatioSatsBp16, RatioU64Bp16,
|
||||
};
|
||||
pub use specialized::{BlockCountTarget, OhlcCentsToDollars, OhlcCentsToSats};
|
||||
pub use specialized::{BlockCountTarget24h, BlockCountTarget1w, BlockCountTarget1m, BlockCountTarget1y, OhlcCentsToDollars, OhlcCentsToSats};
|
||||
|
||||
@@ -1,132 +1,36 @@
|
||||
use brk_types::{
|
||||
Close, Day1, Day3, Epoch, Halving, Height, High, Hour1, Hour4, Hour12, Low,
|
||||
Minute10, Minute30, Month1, Month3, Month6, OHLCCents, OHLCDollars, OHLCSats, Open, StoredU64,
|
||||
Week1, Year1, Year10,
|
||||
Close, Day1, Day3, Epoch, Halving, Height, High, Hour1, Hour4, Hour12, Low, Minute10, Minute30,
|
||||
Month1, Month3, Month6, OHLCCents, OHLCDollars, OHLCSats, Open, StoredU64, Week1, Year1,
|
||||
Year10,
|
||||
};
|
||||
use vecdb::UnaryTransform;
|
||||
|
||||
use super::CentsUnsignedToSats;
|
||||
use crate::blocks::{
|
||||
TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DAY3, TARGET_BLOCKS_PER_DECADE,
|
||||
TARGET_BLOCKS_PER_HALVING, TARGET_BLOCKS_PER_HOUR1, TARGET_BLOCKS_PER_HOUR4,
|
||||
TARGET_BLOCKS_PER_HOUR12, TARGET_BLOCKS_PER_MINUTE10, TARGET_BLOCKS_PER_MINUTE30,
|
||||
TARGET_BLOCKS_PER_MONTH, TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER,
|
||||
TARGET_BLOCKS_PER_WEEK, TARGET_BLOCKS_PER_YEAR,
|
||||
TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_MONTH, TARGET_BLOCKS_PER_WEEK, TARGET_BLOCKS_PER_YEAR,
|
||||
};
|
||||
|
||||
pub struct BlockCountTarget;
|
||||
|
||||
impl UnaryTransform<Height, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Height) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_DAY)
|
||||
}
|
||||
macro_rules! const_block_target {
|
||||
($name:ident, $value:expr) => {
|
||||
pub struct $name;
|
||||
const_block_target!(@impl $name, $value, Height, Minute10, Minute30, Hour1, Hour4, Hour12, Day1, Day3, Week1, Month1, Month3, Month6, Year1, Year10, Halving, Epoch);
|
||||
};
|
||||
(@impl $name:ident, $value:expr, $($idx:ty),*) => {
|
||||
$(
|
||||
impl UnaryTransform<$idx, StoredU64> for $name {
|
||||
#[inline(always)]
|
||||
fn apply(_: $idx) -> StoredU64 {
|
||||
StoredU64::from($value)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl UnaryTransform<Minute10, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Minute10) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_MINUTE10)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Minute30, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Minute30) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_MINUTE30)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Hour1, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Hour1) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_HOUR1)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Hour4, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Hour4) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_HOUR4)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Hour12, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Hour12) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_HOUR12)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Day1, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Day1) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_DAY)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Day3, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Day3) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_DAY3)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Week1, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Week1) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_WEEK)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Month1, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Month1) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_MONTH)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Month3, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Month3) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_QUARTER)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Month6, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Month6) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_SEMESTER)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Year1, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Year1) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_YEAR)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Year10, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Year10) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_DECADE)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Halving, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Halving) -> StoredU64 {
|
||||
StoredU64::from(TARGET_BLOCKS_PER_HALVING)
|
||||
}
|
||||
}
|
||||
|
||||
impl UnaryTransform<Epoch, StoredU64> for BlockCountTarget {
|
||||
#[inline(always)]
|
||||
fn apply(_: Epoch) -> StoredU64 {
|
||||
StoredU64::from(2016u64)
|
||||
}
|
||||
}
|
||||
const_block_target!(BlockCountTarget24h, TARGET_BLOCKS_PER_DAY);
|
||||
const_block_target!(BlockCountTarget1w, TARGET_BLOCKS_PER_WEEK);
|
||||
const_block_target!(BlockCountTarget1m, TARGET_BLOCKS_PER_MONTH);
|
||||
const_block_target!(BlockCountTarget1y, TARGET_BLOCKS_PER_YEAR);
|
||||
|
||||
pub struct OhlcCentsToDollars;
|
||||
|
||||
|
||||
@@ -33,8 +33,8 @@ impl Vecs {
|
||||
|
||||
self.unspent.height.compute_transform3(
|
||||
starting_indexes.height,
|
||||
&self.total.full.cumulative,
|
||||
&inputs_count.full.cumulative,
|
||||
&self.total.full.cumulative.height,
|
||||
&inputs_count.full.cumulative.height,
|
||||
&scripts_count.op_return.cumulative.height,
|
||||
|(h, output_count, input_count, op_return_count, ..)| {
|
||||
let block_count = u64::from(h + 1_usize);
|
||||
|
||||
@@ -39,14 +39,14 @@ impl Vecs {
|
||||
self.taproot.compute_binary::<_, _, RatioU64Bp16>(
|
||||
starting_indexes.height,
|
||||
&count.p2tr.base.height,
|
||||
&outputs_count.total.full.sum,
|
||||
&outputs_count.total.full.sum.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.segwit.compute_binary::<_, _, RatioU64Bp16>(
|
||||
starting_indexes.height,
|
||||
&count.segwit.base.height,
|
||||
&outputs_count.total.full.sum,
|
||||
&outputs_count.total.full.sum.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -3,19 +3,19 @@ use brk_types::Version;
|
||||
use vecdb::{Database, EagerVec, ImportableVec};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::internal::PerTxDistribution;
|
||||
use crate::{indexes, internal::PerTxDistribution};
|
||||
|
||||
/// Bump this when fee/feerate aggregation logic changes (e.g., skip coinbase).
|
||||
const VERSION: Version = Version::new(2);
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version) -> Result<Self> {
|
||||
pub(crate) fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
Ok(Self {
|
||||
input_value: EagerVec::forced_import(db, "input_value", version)?,
|
||||
output_value: EagerVec::forced_import(db, "output_value", version)?,
|
||||
fee: PerTxDistribution::forced_import(db, "fee", v)?,
|
||||
fee_rate: PerTxDistribution::forced_import(db, "fee_rate", v)?,
|
||||
fee: PerTxDistribution::forced_import(db, "fee", v, indexes)?,
|
||||
fee_rate: PerTxDistribution::forced_import(db, "fee_rate", v, indexes)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ impl Vecs {
|
||||
let version = parent_version;
|
||||
|
||||
let count = CountVecs::forced_import(&db, version, indexer, indexes, cached_starts)?;
|
||||
let size = SizeVecs::forced_import(&db, version, indexer)?;
|
||||
let fees = FeesVecs::forced_import(&db, version)?;
|
||||
let size = SizeVecs::forced_import(&db, version, indexer, indexes)?;
|
||||
let fees = FeesVecs::forced_import(&db, version, indexes)?;
|
||||
let versions = VersionsVecs::forced_import(&db, version, indexes, cached_starts)?;
|
||||
let volume = VolumeVecs::forced_import(&db, version, indexes, cached_starts)?;
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ use brk_types::{TxIndex, VSize, Version, Weight};
|
||||
use vecdb::{Database, LazyVecFrom2, ReadableCloneableVec};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::internal::{LazyPerTxDistribution, LazyPerTxDistributionTransformed, VSizeToWeight};
|
||||
use crate::{indexes, internal::{LazyPerTxDistribution, LazyPerTxDistributionTransformed, VSizeToWeight}};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
indexer: &Indexer,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let tx_index_to_vsize = LazyVecFrom2::init(
|
||||
"tx_vsize",
|
||||
@@ -23,7 +24,7 @@ impl Vecs {
|
||||
);
|
||||
|
||||
let vsize =
|
||||
LazyPerTxDistribution::forced_import(db, "tx_vsize", version, tx_index_to_vsize)?;
|
||||
LazyPerTxDistribution::forced_import(db, "tx_vsize", version, indexes, tx_index_to_vsize)?;
|
||||
|
||||
let tx_index_to_weight = LazyVecFrom2::init(
|
||||
"tx_weight",
|
||||
|
||||
@@ -22,44 +22,21 @@ impl Vecs {
|
||||
starting_indexes: &Indexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
// sent_sum and received_sum are independent — parallelize
|
||||
let (r1, r2) = rayon::join(
|
||||
|| {
|
||||
self.transfer_volume.compute(
|
||||
self.transfer_volume.compute(
|
||||
starting_indexes.height,
|
||||
prices,
|
||||
exit,
|
||||
|sats_vec| {
|
||||
Ok(sats_vec.compute_filtered_sum_from_indexes(
|
||||
starting_indexes.height,
|
||||
prices,
|
||||
&indexer.vecs.transactions.first_tx_index,
|
||||
&indexes.height.tx_index_count,
|
||||
&fees_vecs.input_value,
|
||||
|sats| !sats.is_max(),
|
||||
exit,
|
||||
|sats_vec| {
|
||||
Ok(sats_vec.compute_filtered_sum_from_indexes(
|
||||
starting_indexes.height,
|
||||
&indexer.vecs.transactions.first_tx_index,
|
||||
&indexes.height.tx_index_count,
|
||||
&fees_vecs.input_value,
|
||||
|sats| !sats.is_max(),
|
||||
exit,
|
||||
)?)
|
||||
},
|
||||
)
|
||||
)?)
|
||||
},
|
||||
|| {
|
||||
self.output_volume.compute(
|
||||
starting_indexes.height,
|
||||
prices,
|
||||
exit,
|
||||
|sats_vec| {
|
||||
Ok(sats_vec.compute_sum_from_indexes(
|
||||
starting_indexes.height,
|
||||
&indexer.vecs.transactions.first_tx_index,
|
||||
&indexes.height.tx_index_count,
|
||||
&fees_vecs.output_value,
|
||||
exit,
|
||||
)?)
|
||||
},
|
||||
)
|
||||
},
|
||||
);
|
||||
r1?;
|
||||
r2?;
|
||||
)?;
|
||||
|
||||
self.tx_per_sec
|
||||
.height
|
||||
@@ -73,7 +50,7 @@ impl Vecs {
|
||||
.height
|
||||
.compute_binary::<_, Timestamp, PerSec>(
|
||||
starting_indexes.height,
|
||||
&inputs_count.full.sum,
|
||||
&inputs_count.full.sum.height,
|
||||
&blocks.interval.base,
|
||||
exit,
|
||||
)?;
|
||||
@@ -81,7 +58,7 @@ impl Vecs {
|
||||
.height
|
||||
.compute_binary::<_, Timestamp, PerSec>(
|
||||
starting_indexes.height,
|
||||
&outputs_count.total.full.sum,
|
||||
&outputs_count.total.full.sum.height,
|
||||
&blocks.interval.base,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -24,13 +24,6 @@ impl Vecs {
|
||||
indexes,
|
||||
cached_starts,
|
||||
)?,
|
||||
output_volume: AmountPerBlockCumulativeWithSums::forced_import(
|
||||
db,
|
||||
"output_volume",
|
||||
version,
|
||||
indexes,
|
||||
cached_starts,
|
||||
)?,
|
||||
tx_per_sec: PerBlock::forced_import(db, "tx_per_sec", version + v2, indexes)?,
|
||||
outputs_per_sec: PerBlock::forced_import(
|
||||
db,
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::internal::{AmountPerBlockCumulativeWithSums, PerBlock};
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub transfer_volume: AmountPerBlockCumulativeWithSums<M>,
|
||||
pub output_volume: AmountPerBlockCumulativeWithSums<M>,
|
||||
pub tx_per_sec: PerBlock<StoredF32, M>,
|
||||
pub outputs_per_sec: PerBlock<StoredF32, M>,
|
||||
pub inputs_per_sec: PerBlock<StoredF32, M>,
|
||||
|
||||
Reference in New Issue
Block a user