mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-24 06:39:58 -07:00
global: snapshot
This commit is contained in:
@@ -36,7 +36,7 @@ impl Vecs {
|
||||
|
||||
self.thermo_cap.height.compute_transform(
|
||||
starting_indexes.height,
|
||||
&mining.rewards.subsidy.usd.cumulative.height,
|
||||
&mining.rewards.subsidy.cumulative.usd.height,
|
||||
|(i, v, ..)| (i, v),
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -30,8 +30,8 @@ use super::{
|
||||
vecs::Vecs,
|
||||
},
|
||||
BIP30_DUPLICATE_HEIGHT_1, BIP30_DUPLICATE_HEIGHT_2, BIP30_ORIGINAL_HEIGHT_1,
|
||||
BIP30_ORIGINAL_HEIGHT_2, ComputeContext, FLUSH_INTERVAL, TxInReaders, TxOutReaders,
|
||||
IndexToTxIndexBuf, VecsReaders,
|
||||
BIP30_ORIGINAL_HEIGHT_2, ComputeContext, FLUSH_INTERVAL, IndexToTxIndexBuf, TxInReaders,
|
||||
TxOutReaders, VecsReaders,
|
||||
};
|
||||
|
||||
/// Process all blocks from starting_height to last_height.
|
||||
@@ -278,7 +278,7 @@ pub(crate) fn process_blocks(
|
||||
let outputs_handle = scope.spawn(|| {
|
||||
// Process outputs (receive)
|
||||
process_outputs(
|
||||
&txoutindex_to_txindex,
|
||||
txoutindex_to_txindex,
|
||||
&txoutdata_vec,
|
||||
&first_addressindexes,
|
||||
&cache,
|
||||
|
||||
@@ -82,6 +82,7 @@ impl ActivityMetrics {
|
||||
/// Get minimum length across height-indexed vectors.
|
||||
pub(crate) fn min_len(&self) -> usize {
|
||||
self.sent
|
||||
.base
|
||||
.sats
|
||||
.height
|
||||
.len()
|
||||
@@ -97,7 +98,7 @@ impl ActivityMetrics {
|
||||
satblocks_destroyed: Sats,
|
||||
satdays_destroyed: Sats,
|
||||
) -> Result<()> {
|
||||
self.sent.sats.height.truncate_push(height, sent)?;
|
||||
self.sent.base.sats.height.truncate_push(height, sent)?;
|
||||
self.satblocks_destroyed
|
||||
.truncate_push(height, satblocks_destroyed)?;
|
||||
self.satdays_destroyed
|
||||
@@ -108,7 +109,7 @@ impl ActivityMetrics {
|
||||
/// Returns a parallel iterator over all vecs for parallel writing.
|
||||
pub(crate) fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.sent.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.sent.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.satblocks_destroyed as &mut dyn AnyStoredVec,
|
||||
&mut self.satdays_destroyed as &mut dyn AnyStoredVec,
|
||||
]
|
||||
@@ -128,11 +129,11 @@ impl ActivityMetrics {
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sent.sats.height.compute_sum_of_others(
|
||||
self.sent.base.sats.height.compute_sum_of_others(
|
||||
starting_indexes.height,
|
||||
&others
|
||||
.iter()
|
||||
.map(|v| &v.sent.sats.height)
|
||||
.map(|v| &v.sent.base.sats.height)
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
@@ -168,8 +169,8 @@ impl ActivityMetrics {
|
||||
self.sent_14d_ema.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent.sats.height,
|
||||
&self.sent.usd.height,
|
||||
&self.sent.base.sats.height,
|
||||
&self.sent.base.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -582,8 +582,8 @@ impl RealizedBase {
|
||||
.min(self.loss_value_created.height.len())
|
||||
.min(self.loss_value_destroyed.height.len())
|
||||
.min(self.peak_regret.height.len())
|
||||
.min(self.sent_in_profit.sats.height.len())
|
||||
.min(self.sent_in_loss.sats.height.len())
|
||||
.min(self.sent_in_profit.base.sats.height.len())
|
||||
.min(self.sent_in_loss.base.sats.height.len())
|
||||
}
|
||||
|
||||
/// Push realized state values to height-indexed vectors.
|
||||
@@ -619,10 +619,12 @@ impl RealizedBase {
|
||||
.height
|
||||
.truncate_push(height, state.peak_regret().to_dollars())?;
|
||||
self.sent_in_profit
|
||||
.base
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.sent_in_profit())?;
|
||||
self.sent_in_loss
|
||||
.base
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.sent_in_loss())?;
|
||||
@@ -644,8 +646,8 @@ impl RealizedBase {
|
||||
&mut self.loss_value_created.height,
|
||||
&mut self.loss_value_destroyed.height,
|
||||
&mut self.peak_regret.height,
|
||||
&mut self.sent_in_profit.sats.height,
|
||||
&mut self.sent_in_loss.sats.height,
|
||||
&mut self.sent_in_profit.base.sats.height,
|
||||
&mut self.sent_in_loss.base.sats.height,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -778,19 +780,19 @@ impl RealizedBase {
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
self.sent_in_profit.sats.height.compute_sum_of_others(
|
||||
self.sent_in_profit.base.sats.height.compute_sum_of_others(
|
||||
starting_indexes.height,
|
||||
&others
|
||||
.iter()
|
||||
.map(|v| &v.sent_in_profit.sats.height)
|
||||
.map(|v| &v.sent_in_profit.base.sats.height)
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
self.sent_in_loss.sats.height.compute_sum_of_others(
|
||||
self.sent_in_loss.base.sats.height.compute_sum_of_others(
|
||||
starting_indexes.height,
|
||||
&others
|
||||
.iter()
|
||||
.map(|v| &v.sent_in_loss.sats.height)
|
||||
.map(|v| &v.sent_in_loss.base.sats.height)
|
||||
.collect::<Vec<_>>(),
|
||||
exit,
|
||||
)?;
|
||||
@@ -1045,15 +1047,15 @@ impl RealizedBase {
|
||||
self.sent_in_profit_14d_ema.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent_in_profit.sats.height,
|
||||
&self.sent_in_profit.usd.height,
|
||||
&self.sent_in_profit.base.sats.height,
|
||||
&self.sent_in_profit.base.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
self.sent_in_loss_14d_ema.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&blocks.count.height_2w_ago,
|
||||
&self.sent_in_loss.sats.height,
|
||||
&self.sent_in_loss.usd.height,
|
||||
&self.sent_in_loss.base.sats.height,
|
||||
&self.sent_in_loss.base.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ impl SupplyMetrics {
|
||||
/// Returns a parallel iterator over all vecs for parallel writing.
|
||||
pub(crate) fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.total.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.total.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.total.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.total.base.usd.height as &mut dyn AnyStoredVec,
|
||||
]
|
||||
.into_par_iter()
|
||||
}
|
||||
|
||||
@@ -236,10 +236,10 @@ impl UnrealizedBase {
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
vec![
|
||||
&mut self.supply_in_profit.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_profit.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_profit.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_profit.base.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.sats.height as &mut dyn AnyStoredVec,
|
||||
&mut self.supply_in_loss.base.usd.height as &mut dyn AnyStoredVec,
|
||||
&mut self.unrealized_profit.height,
|
||||
&mut self.unrealized_loss.height,
|
||||
&mut self.invested_capital_in_profit.height,
|
||||
|
||||
@@ -9,11 +9,11 @@ pub struct DistributionStats<A, B = A, C = A, D = A, E = A, F = A, G = A, H = A>
|
||||
pub average: A,
|
||||
pub min: B,
|
||||
pub max: C,
|
||||
pub p10: D,
|
||||
pub p25: E,
|
||||
pub pct10: D,
|
||||
pub pct25: E,
|
||||
pub median: F,
|
||||
pub p75: G,
|
||||
pub p90: H,
|
||||
pub pct75: G,
|
||||
pub pct90: H,
|
||||
}
|
||||
|
||||
impl<A> DistributionStats<A> {
|
||||
@@ -22,11 +22,11 @@ impl<A> DistributionStats<A> {
|
||||
f(&mut self.average)?;
|
||||
f(&mut self.min)?;
|
||||
f(&mut self.max)?;
|
||||
f(&mut self.p10)?;
|
||||
f(&mut self.p25)?;
|
||||
f(&mut self.pct10)?;
|
||||
f(&mut self.pct25)?;
|
||||
f(&mut self.median)?;
|
||||
f(&mut self.p75)?;
|
||||
f(&mut self.p90)?;
|
||||
f(&mut self.pct75)?;
|
||||
f(&mut self.pct90)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ impl<A> DistributionStats<A> {
|
||||
f(&self.average)
|
||||
.min(f(&self.min))
|
||||
.min(f(&self.max))
|
||||
.min(f(&self.p10))
|
||||
.min(f(&self.p25))
|
||||
.min(f(&self.pct10))
|
||||
.min(f(&self.pct25))
|
||||
.min(f(&self.median))
|
||||
.min(f(&self.p75))
|
||||
.min(f(&self.p90))
|
||||
.min(f(&self.pct75))
|
||||
.min(f(&self.pct90))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
mod rolling_full;
|
||||
mod rolling_sum;
|
||||
mod windows;
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Sats, Version};
|
||||
use vecdb::{Database, ReadableCloneableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin},
|
||||
};
|
||||
|
||||
pub use rolling_full::*;
|
||||
pub use rolling_sum::*;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct ByUnit<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
}
|
||||
|
||||
impl ByUnit {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let sats = ComputedFromHeightLast::forced_import(db, name, version, indexes)?;
|
||||
|
||||
let btc = LazyFromHeightLast::from_computed::<SatsToBitcoin>(
|
||||
&format!("{name}_btc"),
|
||||
version,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd =
|
||||
ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), version, indexes)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, DistributionStats, WindowStarts, Windows},
|
||||
traits::compute_rolling_distribution_from_starts,
|
||||
};
|
||||
|
||||
/// One window slot: sum + 8 distribution stats, each a ByUnit.
|
||||
///
|
||||
/// Tree: `sum.sats.height`, `average.sats.height`, etc.
|
||||
#[derive(Traversable)]
|
||||
pub struct RollingFullSlot<M: StorageMode = Rw> {
|
||||
pub sum: ByUnit<M>,
|
||||
#[traversable(flatten)]
|
||||
pub distribution: DistributionStats<ByUnit<M>>,
|
||||
}
|
||||
|
||||
impl RollingFullSlot {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
sum: ByUnit::forced_import(db, &format!("{name}_sum"), version, indexes)?,
|
||||
distribution: DistributionStats {
|
||||
average: ByUnit::forced_import(db, &format!("{name}_average"), version, indexes)?,
|
||||
min: ByUnit::forced_import(db, &format!("{name}_min"), version, indexes)?,
|
||||
max: ByUnit::forced_import(db, &format!("{name}_max"), version, indexes)?,
|
||||
pct10: ByUnit::forced_import(db, &format!("{name}_p10"), version, indexes)?,
|
||||
pct25: ByUnit::forced_import(db, &format!("{name}_p25"), version, indexes)?,
|
||||
median: ByUnit::forced_import(db, &format!("{name}_median"), version, indexes)?,
|
||||
pct75: ByUnit::forced_import(db, &format!("{name}_p75"), version, indexes)?,
|
||||
pct90: ByUnit::forced_import(db, &format!("{name}_p90"), version, indexes)?,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
starts: &impl ReadableVec<Height, Height>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sum.sats.height.compute_rolling_sum(max_from, starts, sats_source, exit)?;
|
||||
self.sum.usd.height.compute_rolling_sum(max_from, starts, usd_source, exit)?;
|
||||
|
||||
let d = &mut self.distribution;
|
||||
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, starts, sats_source,
|
||||
&mut d.average.sats.height, &mut d.min.sats.height,
|
||||
&mut d.max.sats.height, &mut d.pct10.sats.height,
|
||||
&mut d.pct25.sats.height, &mut d.median.sats.height,
|
||||
&mut d.pct75.sats.height, &mut d.pct90.sats.height, exit,
|
||||
)?;
|
||||
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, starts, usd_source,
|
||||
&mut d.average.usd.height, &mut d.min.usd.height,
|
||||
&mut d.max.usd.height, &mut d.pct10.usd.height,
|
||||
&mut d.pct25.usd.height, &mut d.median.usd.height,
|
||||
&mut d.pct75.usd.height, &mut d.pct90.usd.height, exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Rolling sum + distribution across 4 windows, window-first.
|
||||
///
|
||||
/// Tree: `_24h.sum.sats.height`, `_24h.average.sats.height`, etc.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct RollingFullByUnit<M: StorageMode = Rw>(pub Windows<RollingFullSlot<M>>);
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl RollingFullByUnit {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
Ok(Self(Windows {
|
||||
_24h: RollingFullSlot::forced_import(db, &format!("{name}_24h"), v, indexes)?,
|
||||
_7d: RollingFullSlot::forced_import(db, &format!("{name}_7d"), v, indexes)?,
|
||||
_30d: RollingFullSlot::forced_import(db, &format!("{name}_30d"), v, indexes)?,
|
||||
_1y: RollingFullSlot::forced_import(db, &format!("{name}_1y"), v, indexes)?,
|
||||
}))
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (slot, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
slot.compute(max_from, starts, sats_source, usd_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, WindowStarts, Windows},
|
||||
};
|
||||
|
||||
/// Rolling sum only, window-first then unit.
|
||||
///
|
||||
/// Tree: `_24h.sats.height`, `_24h.btc.height`, etc.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct RollingSumByUnit<M: StorageMode = Rw>(pub Windows<ByUnit<M>>);
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
impl RollingSumByUnit {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
Ok(Self(Windows::<ByUnit>::forced_import(db, &format!("{name}_sum"), v, indexes)?))
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rolling_sum(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
sats_source: &impl ReadableVec<Height, Sats>,
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
for (w, starts) in self.0.as_mut_array().into_iter().zip(windows.as_array()) {
|
||||
w.sats.height.compute_rolling_sum(max_from, starts, sats_source, exit)?;
|
||||
w.usd.height.compute_rolling_sum(max_from, starts, usd_source, exit)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::Version;
|
||||
use vecdb::Database;
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ByUnit, Windows},
|
||||
};
|
||||
|
||||
impl Windows<ByUnit> {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
_24h: ByUnit::forced_import(db, &format!("{name}_24h"), version, indexes)?,
|
||||
_7d: ByUnit::forced_import(db, &format!("{name}_7d"), version, indexes)?,
|
||||
_30d: ByUnit::forced_import(db, &format!("{name}_30d"), version, indexes)?,
|
||||
_1y: ByUnit::forced_import(db, &format!("{name}_1y"), version, indexes)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ where
|
||||
{
|
||||
pub height: M::Stored<EagerVec<PcoVec<Height, T>>>,
|
||||
pub cumulative: ComputedFromHeightLast<T, M>,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: RollingFull<T, M>,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
mod by_unit;
|
||||
mod constant;
|
||||
mod cumulative;
|
||||
mod cumulative_rolling_full;
|
||||
@@ -21,6 +22,7 @@ mod value_lazy_computed_cumulative;
|
||||
mod value_lazy_last;
|
||||
mod value_sum_cumulative;
|
||||
|
||||
pub use by_unit::*;
|
||||
pub use constant::*;
|
||||
pub use cumulative::*;
|
||||
pub use cumulative_rolling_full::*;
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
//! Stored value type for Last pattern from Height.
|
||||
//!
|
||||
//! Both sats and USD are stored eagerly at the height level.
|
||||
//! Used for rolling-window sums where USD = sum(usd_per_block),
|
||||
//! NOT sats * current_price.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin},
|
||||
internal::ByUnit,
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
#[derive(Traversable)]
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct StoredValueFromHeightLast<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
pub base: ByUnit<M>,
|
||||
}
|
||||
|
||||
impl StoredValueFromHeightLast {
|
||||
@@ -31,19 +27,9 @@ impl StoredValueFromHeightLast {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
|
||||
let sats = ComputedFromHeightLast::forced_import(db, name, v, indexes)?;
|
||||
|
||||
let btc = LazyFromHeightLast::from_computed::<SatsToBitcoin>(
|
||||
&format!("{name}_btc"),
|
||||
v,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd = ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), v, indexes)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
Ok(Self {
|
||||
base: ByUnit::forced_import(db, name, v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute_rolling_sum(
|
||||
@@ -54,10 +40,12 @@ impl StoredValueFromHeightLast {
|
||||
usd_source: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sats
|
||||
self.base
|
||||
.sats
|
||||
.height
|
||||
.compute_rolling_sum(max_from, window_starts, sats_source, exit)?;
|
||||
self.usd
|
||||
self.base
|
||||
.usd
|
||||
.height
|
||||
.compute_rolling_sum(max_from, window_starts, usd_source, exit)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
//! Rolling average values from Height - stores sats and dollars, btc is lazy.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, Exit, ReadableCloneableVec, ReadableVec, Rw, StorageMode};
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin},
|
||||
internal::ByUnit,
|
||||
};
|
||||
|
||||
const VERSION: Version = Version::ZERO;
|
||||
|
||||
/// Rolling average values indexed by height - sats (stored), btc (lazy), usd (stored).
|
||||
#[derive(Traversable)]
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct ValueEmaFromHeight<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
pub base: ByUnit<M>,
|
||||
}
|
||||
|
||||
impl ValueEmaFromHeight {
|
||||
@@ -28,27 +27,11 @@ impl ValueEmaFromHeight {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
|
||||
let sats = ComputedFromHeightLast::forced_import(db, name, v, indexes)?;
|
||||
|
||||
let btc = LazyFromHeightLast::from_computed::<SatsToBitcoin>(
|
||||
&format!("{name}_btc"),
|
||||
v,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd = ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
&format!("{name}_usd"),
|
||||
v,
|
||||
indexes,
|
||||
)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
Ok(Self {
|
||||
base: ByUnit::forced_import(db, name, v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute rolling average for both sats and dollars in one call.
|
||||
pub(crate) fn compute_rolling_average(
|
||||
&mut self,
|
||||
starting_height: Height,
|
||||
@@ -57,10 +40,12 @@ impl ValueEmaFromHeight {
|
||||
dollars_source: &(impl ReadableVec<Height, Dollars> + Sync),
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sats
|
||||
self.base
|
||||
.sats
|
||||
.height
|
||||
.compute_rolling_average(starting_height, window_starts, sats_source, exit)?;
|
||||
self.usd
|
||||
self.base
|
||||
.usd
|
||||
.height
|
||||
.compute_rolling_average(starting_height, window_starts, dollars_source, exit)?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,30 +1,23 @@
|
||||
//! Value type for Full pattern from Height.
|
||||
//!
|
||||
//! Height-level USD stats are stored (eagerly computed from sats × price).
|
||||
//! Uses CumFull: stored base + cumulative + rolling windows.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode};
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
ComputedFromHeightCumulativeFull, LazyFromHeightLast, SatsToBitcoin, SatsToDollars,
|
||||
WindowStarts,
|
||||
},
|
||||
internal::{ByUnit, RollingFullByUnit, SatsToDollars, WindowStarts},
|
||||
prices,
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct ValueFromHeightFull<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightCumulativeFull<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightCumulativeFull<Dollars, M>,
|
||||
pub base: ByUnit<M>,
|
||||
pub cumulative: ByUnit<M>,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: RollingFullByUnit<M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::TWO; // Bumped for stored height dollars
|
||||
const VERSION: Version = Version::TWO;
|
||||
|
||||
impl ValueFromHeightFull {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -35,19 +28,11 @@ impl ValueFromHeightFull {
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
|
||||
let sats = ComputedFromHeightCumulativeFull::forced_import(db, name, v, indexes)?;
|
||||
|
||||
let btc = LazyFromHeightLast::from_height_source::<SatsToBitcoin>(
|
||||
&format!("{name}_btc"),
|
||||
v,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
indexes,
|
||||
);
|
||||
|
||||
let usd =
|
||||
ComputedFromHeightCumulativeFull::forced_import(db, &format!("{name}_usd"), v, indexes)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
Ok(Self {
|
||||
base: ByUnit::forced_import(db, name, v, indexes)?,
|
||||
cumulative: ByUnit::forced_import(db, &format!("{name}_cumulative"), v, indexes)?,
|
||||
rolling: RollingFullByUnit::forced_import(db, name, v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
@@ -58,15 +43,36 @@ impl ValueFromHeightFull {
|
||||
exit: &Exit,
|
||||
compute_sats: impl FnOnce(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
self.sats.compute(max_from, windows, exit, compute_sats)?;
|
||||
compute_sats(&mut self.base.sats.height)?;
|
||||
|
||||
self.usd.compute(max_from, windows, exit, |vec| {
|
||||
Ok(vec.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
self.cumulative
|
||||
.sats
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.height
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
max_from,
|
||||
&self.sats.height,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd,
|
||||
exit,
|
||||
)?)
|
||||
})
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
|
||||
self.rolling.compute(
|
||||
max_from,
|
||||
windows,
|
||||
&self.base.sats.height,
|
||||
&self.base.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
//! Value type for Last pattern from Height.
|
||||
//!
|
||||
//! Height-level USD value is stored (eagerly computed from sats × price).
|
||||
//! Day1 last is stored since it requires finding the last value within each date.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, Exit, ReadableCloneableVec, Rw, StorageMode};
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes, prices,
|
||||
internal::{ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin, SatsToDollars},
|
||||
internal::{ByUnit, SatsToDollars},
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct ValueFromHeightLast<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightLast<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
pub base: ByUnit<M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::TWO; // Bumped for stored height dollars
|
||||
const VERSION: Version = Version::TWO;
|
||||
|
||||
impl ValueFromHeightLast {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -30,35 +27,20 @@ impl ValueFromHeightLast {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
|
||||
let sats = ComputedFromHeightLast::forced_import(db, name, v, indexes)?;
|
||||
|
||||
let btc = LazyFromHeightLast::from_computed::<SatsToBitcoin>(
|
||||
&format!("{name}_btc"),
|
||||
v,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
&sats,
|
||||
);
|
||||
|
||||
let usd = ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), v, indexes)?;
|
||||
|
||||
Ok(Self {
|
||||
sats,
|
||||
btc,
|
||||
usd,
|
||||
base: ByUnit::forced_import(db, name, v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Eagerly compute USD height values: sats[h] * price[h].
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.usd.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
self.base.usd.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
max_from,
|
||||
&self.sats.height,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -21,6 +21,7 @@ pub struct ValueFromHeightLastRolling<M: StorageMode = Rw> {
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub value: ValueFromHeight<M>,
|
||||
#[traversable(flatten)]
|
||||
pub rolling: StoredValueRollingWindows<M>,
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,21 @@
|
||||
//! Value type with stored sats height + cumulative, stored usd, lazy btc.
|
||||
//!
|
||||
//! - Sats: stored height + cumulative (ComputedFromHeightCumulative)
|
||||
//! - BTC: lazy transform from sats (LazyFromHeightLast)
|
||||
//! - USD: stored (eagerly computed from price × sats)
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, Exit, ReadableCloneableVec, Rw, StorageMode};
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{
|
||||
ComputedFromHeightCumulative, ComputedFromHeightLast, LazyFromHeightLast, SatsToBitcoin,
|
||||
SatsToDollars,
|
||||
},
|
||||
internal::{ByUnit, SatsToDollars},
|
||||
prices,
|
||||
};
|
||||
|
||||
/// Value wrapper with stored sats height + cumulative, lazy btc + stored usd.
|
||||
#[derive(Traversable)]
|
||||
pub struct LazyComputedValueFromHeightCumulative<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightCumulative<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightLast<Dollars, M>,
|
||||
pub base: ByUnit<M>,
|
||||
pub cumulative: ByUnit<M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::ONE; // Bumped for stored height dollars
|
||||
const VERSION: Version = Version::ONE;
|
||||
|
||||
impl LazyComputedValueFromHeightCumulative {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -37,35 +26,37 @@ impl LazyComputedValueFromHeightCumulative {
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
|
||||
let sats = ComputedFromHeightCumulative::forced_import(db, name, v, indexes)?;
|
||||
|
||||
let btc = LazyFromHeightLast::from_height_source::<SatsToBitcoin>(
|
||||
&format!("{name}_btc"),
|
||||
v,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
indexes,
|
||||
);
|
||||
|
||||
let usd = ComputedFromHeightLast::forced_import(db, &format!("{name}_usd"), v, indexes)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
Ok(Self {
|
||||
base: ByUnit::forced_import(db, name, v, indexes)?,
|
||||
cumulative: ByUnit::forced_import(db, &format!("{name}_cumulative"), v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Compute cumulative + USD from already-filled sats height vec.
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.sats.compute_rest(max_from, exit)?;
|
||||
self.cumulative
|
||||
.sats
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
max_from,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
|
||||
self.usd.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
max_from,
|
||||
&self.sats.height,
|
||||
&prices.price.usd,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
//! Value type for SumCumulative pattern from Height.
|
||||
//!
|
||||
//! Height-level USD sum is stored (eagerly computed from sats × price).
|
||||
//! Uses CumSum: stored base + cumulative + rolling sum windows.
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, ReadableCloneableVec, Rw, StorageMode};
|
||||
use brk_types::{Dollars, Height, Sats, Version};
|
||||
use vecdb::{Database, EagerVec, Exit, PcoVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
indexes, prices,
|
||||
internal::{
|
||||
ComputedFromHeightCumulativeSum, LazyFromHeightLast, SatsToBitcoin, SatsToDollars,
|
||||
WindowStarts,
|
||||
},
|
||||
indexes,
|
||||
internal::{ByUnit, RollingSumByUnit, SatsToDollars, WindowStarts},
|
||||
prices,
|
||||
};
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct ValueFromHeightSumCumulative<M: StorageMode = Rw> {
|
||||
pub sats: ComputedFromHeightCumulativeSum<Sats, M>,
|
||||
pub btc: LazyFromHeightLast<Bitcoin, Sats>,
|
||||
pub usd: ComputedFromHeightCumulativeSum<Dollars, M>,
|
||||
pub base: ByUnit<M>,
|
||||
pub cumulative: ByUnit<M>,
|
||||
pub sum: RollingSumByUnit<M>,
|
||||
}
|
||||
|
||||
const VERSION: Version = Version::TWO; // Bumped for stored height dollars
|
||||
const VERSION: Version = Version::TWO;
|
||||
|
||||
impl ValueFromHeightSumCumulative {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -34,19 +27,11 @@ impl ValueFromHeightSumCumulative {
|
||||
) -> Result<Self> {
|
||||
let v = version + VERSION;
|
||||
|
||||
let sats = ComputedFromHeightCumulativeSum::forced_import(db, name, v, indexes)?;
|
||||
|
||||
let btc = LazyFromHeightLast::from_height_source::<SatsToBitcoin>(
|
||||
&format!("{name}_btc"),
|
||||
v,
|
||||
sats.height.read_only_boxed_clone(),
|
||||
indexes,
|
||||
);
|
||||
|
||||
let usd =
|
||||
ComputedFromHeightCumulativeSum::forced_import(db, &format!("{name}_usd"), v, indexes)?;
|
||||
|
||||
Ok(Self { sats, btc, usd })
|
||||
Ok(Self {
|
||||
base: ByUnit::forced_import(db, name, v, indexes)?,
|
||||
cumulative: ByUnit::forced_import(db, &format!("{name}_cumulative"), v, indexes)?,
|
||||
sum: RollingSumByUnit::forced_import(db, name, v, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
@@ -57,15 +42,36 @@ impl ValueFromHeightSumCumulative {
|
||||
exit: &Exit,
|
||||
compute_sats: impl FnOnce(&mut EagerVec<PcoVec<Height, Sats>>) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
self.sats.compute(max_from, windows, exit, compute_sats)?;
|
||||
compute_sats(&mut self.base.sats.height)?;
|
||||
|
||||
self.usd.compute(max_from, windows, exit, |vec| {
|
||||
Ok(vec.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
self.cumulative
|
||||
.sats
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.sats.height, exit)?;
|
||||
|
||||
self.base
|
||||
.usd
|
||||
.height
|
||||
.compute_binary::<Sats, Dollars, SatsToDollars>(
|
||||
max_from,
|
||||
&self.sats.height,
|
||||
&self.base.sats.height,
|
||||
&prices.price.usd,
|
||||
exit,
|
||||
)?)
|
||||
})
|
||||
)?;
|
||||
|
||||
self.cumulative
|
||||
.usd
|
||||
.height
|
||||
.compute_cumulative(max_from, &self.base.usd.height, exit)?;
|
||||
|
||||
self.sum.compute_rolling_sum(
|
||||
max_from,
|
||||
windows,
|
||||
&self.base.sats.height,
|
||||
&self.base.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Day1, Day3, DifficultyEpoch, HalvingEpoch, Height, Hour1, Hour4, Hour12, Minute1, Minute5,
|
||||
Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
|
||||
Day1, Day3, DifficultyEpoch, FromCoarserIndex, HalvingEpoch, Height, Hour1, Hour4, Hour12,
|
||||
Minute1, Minute5, Minute10, Minute30, Month1, Month3, Month6, Version, Week1, Year1, Year10,
|
||||
};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{LazyAggVec, ReadOnlyClone, ReadableBoxedVec, ReadableCloneableVec};
|
||||
use vecdb::{
|
||||
Cursor, LazyAggVec, ReadOnlyClone, ReadableBoxedVec, ReadableCloneableVec, VecIndex, VecValue,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
indexes, indexes_from,
|
||||
@@ -77,13 +79,45 @@ where
|
||||
};
|
||||
}
|
||||
|
||||
fn for_each_range_from_coarser<
|
||||
I: VecIndex,
|
||||
O: VecValue,
|
||||
S1I: VecIndex + FromCoarserIndex<I>,
|
||||
S2T: VecValue,
|
||||
>(
|
||||
from: usize,
|
||||
to: usize,
|
||||
source: &ReadableBoxedVec<S1I, O>,
|
||||
mapping: &ReadableBoxedVec<I, S2T>,
|
||||
f: &mut dyn FnMut(O),
|
||||
) {
|
||||
let mapping_len = mapping.len();
|
||||
let source_len = source.len();
|
||||
let mut cursor = Cursor::from_dyn(&**source);
|
||||
for i in from..to {
|
||||
if i >= mapping_len {
|
||||
break;
|
||||
}
|
||||
let target = S1I::max_from(I::from(i), source_len);
|
||||
if cursor.position() <= target {
|
||||
cursor.advance(target - cursor.position());
|
||||
if let Some(v) = cursor.next() {
|
||||
f(v);
|
||||
}
|
||||
} else if let Some(v) = source.collect_one_at(target) {
|
||||
f(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! epoch {
|
||||
($idx:ident) => {
|
||||
LazyAggVec::from_source(
|
||||
LazyAggVec::new(
|
||||
name,
|
||||
v,
|
||||
height_source.clone(),
|
||||
indexes.$idx.identity.read_only_boxed_clone(),
|
||||
for_each_range_from_coarser,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{
|
||||
Database, Exit, ReadableVec, Ro, Rw, StorageMode, VecIndex, VecValue, Version,
|
||||
Database, Exit, ReadableVec, Ro, Rw, VecIndex, VecValue, Version,
|
||||
};
|
||||
|
||||
use crate::internal::{
|
||||
AverageVec, ComputedVecValue, MaxVec, MedianVec, MinVec, Pct10Vec, Pct25Vec, Pct75Vec,
|
||||
Pct90Vec,
|
||||
AverageVec, ComputedVecValue, DistributionStats, MaxVec, MedianVec, MinVec, Pct10Vec,
|
||||
Pct25Vec, Pct75Vec, Pct90Vec,
|
||||
};
|
||||
|
||||
/// Distribution stats (average + min + max + percentiles) — flat 8-field struct.
|
||||
#[derive(Traversable)]
|
||||
pub struct Distribution<I: VecIndex, T: ComputedVecValue + JsonSchema, M: StorageMode = Rw> {
|
||||
pub average: AverageVec<I, T, M>,
|
||||
#[traversable(flatten)]
|
||||
pub min: MinVec<I, T, M>,
|
||||
#[traversable(flatten)]
|
||||
pub max: MaxVec<I, T, M>,
|
||||
pub pct10: Pct10Vec<I, T, M>,
|
||||
pub pct25: Pct25Vec<I, T, M>,
|
||||
pub median: MedianVec<I, T, M>,
|
||||
pub pct75: Pct75Vec<I, T, M>,
|
||||
pub pct90: Pct90Vec<I, T, M>,
|
||||
}
|
||||
/// Distribution stats (average + min + max + percentiles) — concrete vec type alias.
|
||||
pub type Distribution<I, T, M = Rw> = DistributionStats<
|
||||
AverageVec<I, T, M>,
|
||||
MinVec<I, T, M>,
|
||||
MaxVec<I, T, M>,
|
||||
Pct10Vec<I, T, M>,
|
||||
Pct25Vec<I, T, M>,
|
||||
MedianVec<I, T, M>,
|
||||
Pct75Vec<I, T, M>,
|
||||
Pct90Vec<I, T, M>,
|
||||
>;
|
||||
|
||||
impl<I: VecIndex, T: ComputedVecValue + JsonSchema> Distribution<I, T> {
|
||||
pub(crate) fn forced_import(db: &Database, name: &str, version: Version) -> Result<Self> {
|
||||
@@ -111,7 +107,7 @@ impl<I: VecIndex, T: ComputedVecValue + JsonSchema> Distribution<I, T> {
|
||||
}
|
||||
|
||||
pub fn read_only_clone(&self) -> Distribution<I, T, Ro> {
|
||||
Distribution {
|
||||
DistributionStats {
|
||||
average: self.average.read_only_clone(),
|
||||
min: self.min.read_only_clone(),
|
||||
max: self.max.read_only_clone(),
|
||||
|
||||
@@ -41,11 +41,11 @@ where
|
||||
average: RollingWindows::forced_import(db, &format!("{name}_average"), v, indexes)?,
|
||||
min: RollingWindows::forced_import(db, &format!("{name}_min"), v, indexes)?,
|
||||
max: RollingWindows::forced_import(db, &format!("{name}_max"), v, indexes)?,
|
||||
p10: RollingWindows::forced_import(db, &format!("{name}_p10"), v, indexes)?,
|
||||
p25: RollingWindows::forced_import(db, &format!("{name}_p25"), v, indexes)?,
|
||||
pct10: RollingWindows::forced_import(db, &format!("{name}_p10"), v, indexes)?,
|
||||
pct25: RollingWindows::forced_import(db, &format!("{name}_p25"), v, indexes)?,
|
||||
median: RollingWindows::forced_import(db, &format!("{name}_median"), v, indexes)?,
|
||||
p75: RollingWindows::forced_import(db, &format!("{name}_p75"), v, indexes)?,
|
||||
p90: RollingWindows::forced_import(db, &format!("{name}_p90"), v, indexes)?,
|
||||
pct75: RollingWindows::forced_import(db, &format!("{name}_p75"), v, indexes)?,
|
||||
pct90: RollingWindows::forced_import(db, &format!("{name}_p90"), v, indexes)?,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -69,30 +69,30 @@ where
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, windows._24h, source,
|
||||
&mut self.0.average._24h.height, &mut self.0.min._24h.height,
|
||||
&mut self.0.max._24h.height, &mut self.0.p10._24h.height,
|
||||
&mut self.0.p25._24h.height, &mut self.0.median._24h.height,
|
||||
&mut self.0.p75._24h.height, &mut self.0.p90._24h.height, exit,
|
||||
&mut self.0.max._24h.height, &mut self.0.pct10._24h.height,
|
||||
&mut self.0.pct25._24h.height, &mut self.0.median._24h.height,
|
||||
&mut self.0.pct75._24h.height, &mut self.0.pct90._24h.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, windows._7d, source,
|
||||
&mut self.0.average._7d.height, &mut self.0.min._7d.height,
|
||||
&mut self.0.max._7d.height, &mut self.0.p10._7d.height,
|
||||
&mut self.0.p25._7d.height, &mut self.0.median._7d.height,
|
||||
&mut self.0.p75._7d.height, &mut self.0.p90._7d.height, exit,
|
||||
&mut self.0.max._7d.height, &mut self.0.pct10._7d.height,
|
||||
&mut self.0.pct25._7d.height, &mut self.0.median._7d.height,
|
||||
&mut self.0.pct75._7d.height, &mut self.0.pct90._7d.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, windows._30d, source,
|
||||
&mut self.0.average._30d.height, &mut self.0.min._30d.height,
|
||||
&mut self.0.max._30d.height, &mut self.0.p10._30d.height,
|
||||
&mut self.0.p25._30d.height, &mut self.0.median._30d.height,
|
||||
&mut self.0.p75._30d.height, &mut self.0.p90._30d.height, exit,
|
||||
&mut self.0.max._30d.height, &mut self.0.pct10._30d.height,
|
||||
&mut self.0.pct25._30d.height, &mut self.0.median._30d.height,
|
||||
&mut self.0.pct75._30d.height, &mut self.0.pct90._30d.height, exit,
|
||||
)?;
|
||||
compute_rolling_distribution_from_starts(
|
||||
max_from, windows._1y, source,
|
||||
&mut self.0.average._1y.height, &mut self.0.min._1y.height,
|
||||
&mut self.0.max._1y.height, &mut self.0.p10._1y.height,
|
||||
&mut self.0.p25._1y.height, &mut self.0.median._1y.height,
|
||||
&mut self.0.p75._1y.height, &mut self.0.p90._1y.height, exit,
|
||||
&mut self.0.max._1y.height, &mut self.0.pct10._1y.height,
|
||||
&mut self.0.pct25._1y.height, &mut self.0.median._1y.height,
|
||||
&mut self.0.pct75._1y.height, &mut self.0.pct90._1y.height, exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
mod block_count_target;
|
||||
mod cents_to_dollars;
|
||||
mod cents_to_sats;
|
||||
mod ohlc_cents_to_dollars;
|
||||
mod ohlc_cents_to_sats;
|
||||
|
||||
mod dollar_halve;
|
||||
mod dollar_identity;
|
||||
mod dollar_plus;
|
||||
mod dollar_times_tenths;
|
||||
mod dollars_to_sats_fract;
|
||||
mod f32_identity;
|
||||
mod ohlc_cents_to_dollars;
|
||||
mod ohlc_cents_to_sats;
|
||||
mod percentage_diff_close_dollars;
|
||||
mod percentage_dollars_f32;
|
||||
mod percentage_dollars_f32_neg;
|
||||
@@ -18,7 +17,7 @@ mod percentage_u32_f32;
|
||||
mod price_times_ratio;
|
||||
mod ratio32;
|
||||
mod ratio64;
|
||||
|
||||
mod ratio_u64_f32;
|
||||
mod return_f32_tenths;
|
||||
mod return_i8;
|
||||
mod return_u16;
|
||||
@@ -52,13 +51,12 @@ pub use percentage_dollars_f32_neg::*;
|
||||
pub use percentage_sats_f64::*;
|
||||
pub use percentage_u32_f32::*;
|
||||
pub use price_times_ratio::*;
|
||||
|
||||
pub use ratio32::*;
|
||||
pub use ratio64::*;
|
||||
pub use ratio_u64_f32::*;
|
||||
pub use return_f32_tenths::*;
|
||||
pub use return_i8::*;
|
||||
pub use return_u16::*;
|
||||
|
||||
pub use sat_halve::*;
|
||||
pub use sat_halve_to_bitcoin::*;
|
||||
pub use sat_identity::*;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
use brk_types::{StoredF32, StoredU64};
|
||||
use vecdb::BinaryTransform;
|
||||
|
||||
/// (StoredU64, StoredU64) -> StoredF32 ratio (a/b)
|
||||
/// Used for adoption ratio calculations (script_count / total_outputs)
|
||||
pub struct RatioU64F32;
|
||||
|
||||
impl BinaryTransform<StoredU64, StoredU64, StoredF32> for RatioU64F32 {
|
||||
#[inline(always)]
|
||||
fn apply(numerator: StoredU64, denominator: StoredU64) -> StoredF32 {
|
||||
if *denominator > 0 {
|
||||
StoredF32::from(*numerator as f64 / *denominator as f64)
|
||||
} else {
|
||||
StoredF32::from(0.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ impl Vecs {
|
||||
) -> Result<()> {
|
||||
self.puell_multiple.height.compute_divide(
|
||||
starting_indexes.height,
|
||||
&rewards.coinbase.usd.height,
|
||||
&rewards.coinbase.base.usd.height,
|
||||
&rewards.subsidy_usd_1y_sma.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -31,8 +31,8 @@ impl Vecs {
|
||||
self.hashrate.compute(
|
||||
&blocks.count,
|
||||
&blocks.difficulty,
|
||||
&self.rewards.coinbase.sats.rolling.sum._24h.height,
|
||||
&self.rewards.coinbase.usd.rolling.sum._24h.height,
|
||||
&self.rewards.coinbase.rolling._24h.sum.sats.height,
|
||||
&self.rewards.coinbase.rolling._24h.sum.usd.height,
|
||||
starting_indexes,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -84,8 +84,8 @@ impl Vecs {
|
||||
|vec| {
|
||||
vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.coinbase.sats.height,
|
||||
&self.fees.sats.height,
|
||||
&self.coinbase.base.sats.height,
|
||||
&self.fees.base.sats.height,
|
||||
|(height, coinbase, fees, ..)| {
|
||||
(
|
||||
height,
|
||||
@@ -109,7 +109,7 @@ impl Vecs {
|
||||
|vec| {
|
||||
vec.compute_transform(
|
||||
starting_indexes.height,
|
||||
&self.subsidy.sats.height,
|
||||
&self.subsidy.base.sats.height,
|
||||
|(height, subsidy, ..)| {
|
||||
let halving = HalvingEpoch::from(height);
|
||||
let expected = Sats::FIFTY_BTC / 2_usize.pow(halving.to_usize() as u32);
|
||||
@@ -124,42 +124,42 @@ impl Vecs {
|
||||
// All-time cumulative fee dominance
|
||||
self.fee_dominance.height.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.fees.sats.cumulative.height,
|
||||
&self.coinbase.sats.cumulative.height,
|
||||
&self.fees.cumulative.sats.height,
|
||||
&self.coinbase.cumulative.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// Rolling fee dominance = sum(fees) / sum(coinbase) * 100
|
||||
self.fee_dominance_24h.height.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.fees.sats.rolling.sum._24h.height,
|
||||
&self.coinbase.sats.rolling.sum._24h.height,
|
||||
&self.fees.rolling._24h.sum.sats.height,
|
||||
&self.coinbase.rolling._24h.sum.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
self.fee_dominance_7d.height.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.fees.sats.rolling.sum._7d.height,
|
||||
&self.coinbase.sats.rolling.sum._7d.height,
|
||||
&self.fees.rolling._7d.sum.sats.height,
|
||||
&self.coinbase.rolling._7d.sum.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
self.fee_dominance_30d.height.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.fees.sats.rolling.sum._30d.height,
|
||||
&self.coinbase.sats.rolling.sum._30d.height,
|
||||
&self.fees.rolling._30d.sum.sats.height,
|
||||
&self.coinbase.rolling._30d.sum.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
self.fee_dominance_1y.height.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.fees.sats.rolling.sum._1y.height,
|
||||
&self.coinbase.sats.rolling.sum._1y.height,
|
||||
&self.fees.rolling._1y.sum.sats.height,
|
||||
&self.coinbase.rolling._1y.sum.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// All-time cumulative subsidy dominance
|
||||
self.subsidy_dominance.height.compute_percentage(
|
||||
starting_indexes.height,
|
||||
&self.subsidy.sats.cumulative.height,
|
||||
&self.coinbase.sats.cumulative.height,
|
||||
&self.subsidy.cumulative.sats.height,
|
||||
&self.coinbase.cumulative.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -193,7 +193,7 @@ impl Vecs {
|
||||
self.subsidy_usd_1y_sma.height.compute_rolling_average(
|
||||
starting_indexes.height,
|
||||
&count_vecs.height_1y_ago,
|
||||
&self.coinbase.usd.height,
|
||||
&self.coinbase.base.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -237,7 +237,7 @@ impl Vecs {
|
||||
Ok(vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.blocks_mined.height,
|
||||
&mining.rewards.subsidy.sats.height,
|
||||
&mining.rewards.subsidy.base.sats.height,
|
||||
|(h, mask, val, ..)| (h, MaskSats::apply(mask, val)),
|
||||
exit,
|
||||
)?)
|
||||
@@ -253,7 +253,7 @@ impl Vecs {
|
||||
Ok(vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.blocks_mined.height,
|
||||
&mining.rewards.fees.sats.height,
|
||||
&mining.rewards.fees.base.sats.height,
|
||||
|(h, mask, val, ..)| (h, MaskSats::apply(mask, val)),
|
||||
exit,
|
||||
)?)
|
||||
@@ -269,7 +269,7 @@ impl Vecs {
|
||||
Ok(vec.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.blocks_mined.height,
|
||||
&mining.rewards.coinbase.sats.height,
|
||||
&mining.rewards.coinbase.base.sats.height,
|
||||
|(h, mask, val, ..)| (h, MaskSats::apply(mask, val)),
|
||||
exit,
|
||||
)?)
|
||||
|
||||
56
crates/brk_computer/src/scripts/adoption.rs
Normal file
56
crates/brk_computer/src/scripts/adoption.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, Version};
|
||||
use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{ComputeIndexes, indexes, internal::{ComputedFromHeightLast, RatioU64F32}, outputs};
|
||||
|
||||
use super::count::Vecs as CountVecs;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub taproot: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub segwit: ComputedFromHeightLast<StoredF32, M>,
|
||||
}
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
taproot: ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
"taproot_adoption",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
segwit: ComputedFromHeightLast::forced_import(db, "segwit_adoption", version, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
count: &CountVecs,
|
||||
outputs_count: &outputs::CountVecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.taproot.compute_binary::<_, _, RatioU64F32>(
|
||||
starting_indexes.height,
|
||||
&count.p2tr.height,
|
||||
&outputs_count.total_count.full.sum_cumulative.sum.0,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.segwit.compute_binary::<_, _, RatioU64F32>(
|
||||
starting_indexes.height,
|
||||
&count.segwit.height,
|
||||
&outputs_count.total_count.full.sum_cumulative.sum.0,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -17,11 +17,14 @@ impl Vecs {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.count
|
||||
.compute(indexer, &blocks.count, &outputs.count, starting_indexes, exit)?;
|
||||
.compute(indexer, &blocks.count, starting_indexes, exit)?;
|
||||
|
||||
self.value
|
||||
.compute(indexer, &blocks.count, prices, starting_indexes, exit)?;
|
||||
|
||||
self.adoption
|
||||
.compute(&self.count, &outputs.count, starting_indexes, exit)?;
|
||||
|
||||
let _lock = exit.lock();
|
||||
self.db.compact()?;
|
||||
Ok(())
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::StoredF32;
|
||||
use brk_types::StoredU64;
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{ComputeIndexes, blocks, outputs};
|
||||
use crate::{ComputeIndexes, blocks};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
indexer: &Indexer,
|
||||
count_vecs: &blocks::CountVecs,
|
||||
outputs_count: &outputs::CountVecs,
|
||||
starting_indexes: &ComputeIndexes,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
@@ -151,37 +149,6 @@ impl Vecs {
|
||||
)?)
|
||||
})?;
|
||||
|
||||
// Adoption ratios: per-block ratio of script type / total outputs
|
||||
self.taproot_adoption.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.p2tr.height,
|
||||
&outputs_count.total_count.full.sum_cumulative.sum.0,
|
||||
|(h, p2tr, total, ..)| {
|
||||
let ratio = if *total > 0 {
|
||||
StoredF32::from(*p2tr as f64 / *total as f64)
|
||||
} else {
|
||||
StoredF32::from(0.0)
|
||||
};
|
||||
(h, ratio)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.segwit_adoption.height.compute_transform2(
|
||||
starting_indexes.height,
|
||||
&self.segwit.height,
|
||||
&outputs_count.total_count.full.sum_cumulative.sum.0,
|
||||
|(h, segwit, total, ..)| {
|
||||
let ratio = if *total > 0 {
|
||||
StoredF32::from(*segwit as f64 / *total as f64)
|
||||
} else {
|
||||
StoredF32::from(0.0)
|
||||
};
|
||||
(h, ratio)
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@ use brk_types::Version;
|
||||
use vecdb::Database;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedFromHeightCumulativeSum, ComputedFromHeightLast},
|
||||
};
|
||||
use crate::{indexes, internal::ComputedFromHeightCumulativeSum};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -58,18 +55,6 @@ impl Vecs {
|
||||
indexes,
|
||||
)?,
|
||||
segwit,
|
||||
taproot_adoption: ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
"taproot_adoption",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
segwit_adoption: ComputedFromHeightLast::forced_import(
|
||||
db,
|
||||
"segwit_adoption",
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{StoredF32, StoredU64};
|
||||
use brk_types::StoredU64;
|
||||
use vecdb::{Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedFromHeightCumulativeSum, ComputedFromHeightLast};
|
||||
use crate::internal::ComputedFromHeightCumulativeSum;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
@@ -23,8 +23,4 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
// Aggregate counts
|
||||
/// SegWit output count (p2wpkh + p2wsh + p2tr)
|
||||
pub segwit: ComputedFromHeightCumulativeSum<StoredU64, M>,
|
||||
|
||||
// Adoption ratios (stored per-block, lazy period views)
|
||||
pub taproot_adoption: ComputedFromHeightLast<StoredF32, M>,
|
||||
pub segwit_adoption: ComputedFromHeightLast<StoredF32, M>,
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ use vecdb::{Database, PAGE_SIZE};
|
||||
|
||||
use crate::indexes;
|
||||
|
||||
use super::{CountVecs, ValueVecs, Vecs};
|
||||
use super::{AdoptionVecs, CountVecs, ValueVecs, Vecs};
|
||||
|
||||
impl Vecs {
|
||||
pub(crate) fn forced_import(
|
||||
@@ -22,8 +22,9 @@ impl Vecs {
|
||||
|
||||
let count = CountVecs::forced_import(&db, version, indexes)?;
|
||||
let value = ValueVecs::forced_import(&db, version, indexes)?;
|
||||
let adoption = AdoptionVecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
let this = Self { db, count, value };
|
||||
let this = Self { db, count, value, adoption };
|
||||
|
||||
this.db.retain_regions(
|
||||
this.iter_any_exportable()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod adoption;
|
||||
pub mod count;
|
||||
pub mod value;
|
||||
|
||||
@@ -7,6 +8,7 @@ mod import;
|
||||
use brk_traversable::Traversable;
|
||||
use vecdb::{Database, Rw, StorageMode};
|
||||
|
||||
pub use adoption::Vecs as AdoptionVecs;
|
||||
pub use count::Vecs as CountVecs;
|
||||
pub use value::Vecs as ValueVecs;
|
||||
|
||||
@@ -19,4 +21,5 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
|
||||
pub count: CountVecs<M>,
|
||||
pub value: ValueVecs<M>,
|
||||
pub adoption: AdoptionVecs<M>,
|
||||
}
|
||||
|
||||
@@ -22,11 +22,11 @@ impl Vecs {
|
||||
.compute(starting_indexes.height, &window_starts, prices, exit, |height_vec| {
|
||||
// Validate computed versions against dependencies
|
||||
|
||||
let opreturn_dep_version = scripts.value.opreturn.sats.height.version();
|
||||
let opreturn_dep_version = scripts.value.opreturn.base.sats.height.version();
|
||||
height_vec.validate_computed_version_or_reset(opreturn_dep_version)?;
|
||||
|
||||
// Copy per-block opreturn values from scripts
|
||||
let scripts_target = scripts.value.opreturn.sats.height.len();
|
||||
let scripts_target = scripts.value.opreturn.base.sats.height.len();
|
||||
if scripts_target > 0 {
|
||||
let target_height = Height::from(scripts_target - 1);
|
||||
let current_len = height_vec.len();
|
||||
@@ -36,7 +36,7 @@ impl Vecs {
|
||||
if starting_height <= target_height {
|
||||
let start = starting_height.to_usize();
|
||||
let end = target_height.to_usize() + 1;
|
||||
scripts.value.opreturn.sats.height.fold_range_at(
|
||||
scripts.value.opreturn.base.sats.height.fold_range_at(
|
||||
start, end, start,
|
||||
|idx, value| {
|
||||
height_vec.truncate_push(Height::from(idx), value).unwrap();
|
||||
@@ -52,8 +52,8 @@ impl Vecs {
|
||||
|
||||
// 2. Compute unspendable supply = opreturn + unclaimed_rewards + genesis (at height 0)
|
||||
// Get reference to opreturn height vec for computing unspendable
|
||||
let opreturn_height = &self.opreturn.sats.height;
|
||||
let unclaimed_height = &mining.rewards.unclaimed_rewards.sats.height;
|
||||
let opreturn_height = &self.opreturn.base.sats.height;
|
||||
let unclaimed_height = &mining.rewards.unclaimed_rewards.base.sats.height;
|
||||
|
||||
self.unspendable
|
||||
.compute(starting_indexes.height, &window_starts, prices, exit, |height_vec| {
|
||||
|
||||
Reference in New Issue
Block a user