mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-26 02:08:10 -07:00
global: MASSIVE snapshot
This commit is contained in:
@@ -3,7 +3,7 @@ use brk_types::{Height, Sats};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, GenericStoredVec, TypedVecIterator, VecIndex};
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{blocks, indexes, price, scripts, utils::OptionExt, ComputeIndexes};
|
||||
use crate::{blocks, indexes, price, scripts, ComputeIndexes};
|
||||
|
||||
impl Vecs {
|
||||
pub fn compute(
|
||||
@@ -15,99 +15,97 @@ impl Vecs {
|
||||
price: Option<&price::Vecs>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
// Validate computed versions against dependencies
|
||||
let opreturn_dep_version = scripts.value.height_to_opreturn_value.version();
|
||||
self.height_to_opreturn
|
||||
.validate_computed_version_or_reset(opreturn_dep_version)?;
|
||||
|
||||
let unspendable_dep_version = self.height_to_opreturn.version()
|
||||
+ blocks
|
||||
.rewards
|
||||
.indexes_to_unclaimed_rewards
|
||||
.sats
|
||||
.height
|
||||
.u()
|
||||
.version();
|
||||
self.height_to_unspendable
|
||||
.validate_computed_version_or_reset(unspendable_dep_version)?;
|
||||
|
||||
// 1. Copy per-block opreturn values from scripts
|
||||
let scripts_target = scripts.value.height_to_opreturn_value.len();
|
||||
if scripts_target > 0 {
|
||||
let target_height = Height::from(scripts_target - 1);
|
||||
let current_len = self.height_to_opreturn.len();
|
||||
let starting_height = Height::from(current_len.min(starting_indexes.height.to_usize()));
|
||||
|
||||
if starting_height <= target_height {
|
||||
let mut opreturn_value_iter = scripts.value.height_to_opreturn_value.into_iter();
|
||||
|
||||
for h in starting_height.to_usize()..=target_height.to_usize() {
|
||||
let height = Height::from(h);
|
||||
let value = opreturn_value_iter.get_unwrap(height);
|
||||
self.height_to_opreturn.truncate_push(height, value)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.height_to_opreturn.write()?;
|
||||
|
||||
// 2. Compute per-block unspendable = opreturn + unclaimed_rewards + genesis (at height 0)
|
||||
let opreturn_target = self.height_to_opreturn.len();
|
||||
if opreturn_target > 0 {
|
||||
let target_height = Height::from(opreturn_target - 1);
|
||||
let current_len = self.height_to_unspendable.len();
|
||||
let starting_height = Height::from(current_len.min(starting_indexes.height.to_usize()));
|
||||
|
||||
if starting_height <= target_height {
|
||||
let mut opreturn_iter = self.height_to_opreturn.into_iter();
|
||||
let mut unclaimed_rewards_iter = blocks
|
||||
.rewards
|
||||
.indexes_to_unclaimed_rewards
|
||||
.sats
|
||||
.height
|
||||
.u()
|
||||
.into_iter();
|
||||
|
||||
for h in starting_height.to_usize()..=target_height.to_usize() {
|
||||
let height = Height::from(h);
|
||||
|
||||
// Genesis block 50 BTC is unspendable (only at height 0)
|
||||
let genesis = if height == Height::ZERO {
|
||||
Sats::FIFTY_BTC
|
||||
} else {
|
||||
Sats::ZERO
|
||||
};
|
||||
|
||||
// Per-block opreturn value
|
||||
let opreturn = opreturn_iter.get_unwrap(height);
|
||||
|
||||
// Per-block unclaimed rewards
|
||||
let unclaimed = unclaimed_rewards_iter.get_unwrap(height);
|
||||
|
||||
let unspendable = genesis + opreturn + unclaimed;
|
||||
self.height_to_unspendable
|
||||
.truncate_push(height, unspendable)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.height_to_unspendable.write()?;
|
||||
|
||||
// Compute index aggregations
|
||||
self.indexes_to_opreturn.compute_rest(
|
||||
// 1. Compute opreturn supply - copy per-block opreturn values from scripts
|
||||
self.indexes_to_opreturn.compute_all(
|
||||
indexes,
|
||||
price,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.height_to_opreturn),
|
||||
|height_vec| {
|
||||
// Validate computed versions against dependencies
|
||||
// KISS: height is now inside indexes_to_opreturn_value.sats.height
|
||||
let opreturn_dep_version =
|
||||
scripts.value.indexes_to_opreturn_value.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.indexes_to_opreturn_value.sats.height.len();
|
||||
if scripts_target > 0 {
|
||||
let target_height = Height::from(scripts_target - 1);
|
||||
let current_len = height_vec.len();
|
||||
let starting_height =
|
||||
Height::from(current_len.min(starting_indexes.height.to_usize()));
|
||||
|
||||
if starting_height <= target_height {
|
||||
let mut opreturn_value_iter =
|
||||
scripts.value.indexes_to_opreturn_value.sats.height.into_iter();
|
||||
|
||||
for h in starting_height.to_usize()..=target_height.to_usize() {
|
||||
let height = Height::from(h);
|
||||
let value = opreturn_value_iter.get_unwrap(height);
|
||||
height_vec.truncate_push(height, value)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
height_vec.write()?;
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
self.indexes_to_unspendable.compute_rest(
|
||||
// 2. Compute unspendable supply = opreturn + unclaimed_rewards + genesis (at height 0)
|
||||
// Get reference to opreturn height vec for computing unspendable
|
||||
let opreturn_height = &self.indexes_to_opreturn.sats.height;
|
||||
let unclaimed_height = &blocks.rewards.indexes_to_unclaimed_rewards.sats.height;
|
||||
|
||||
self.indexes_to_unspendable.compute_all(
|
||||
indexes,
|
||||
price,
|
||||
starting_indexes,
|
||||
exit,
|
||||
Some(&self.height_to_unspendable),
|
||||
|height_vec| {
|
||||
// KISS: height is now a concrete field (no Option)
|
||||
let unspendable_dep_version =
|
||||
opreturn_height.version() + unclaimed_height.version();
|
||||
height_vec.validate_computed_version_or_reset(unspendable_dep_version)?;
|
||||
|
||||
let opreturn_target = opreturn_height.len();
|
||||
if opreturn_target > 0 {
|
||||
let target_height = Height::from(opreturn_target - 1);
|
||||
let current_len = height_vec.len();
|
||||
let starting_height =
|
||||
Height::from(current_len.min(starting_indexes.height.to_usize()));
|
||||
|
||||
if starting_height <= target_height {
|
||||
let mut opreturn_iter = opreturn_height.into_iter();
|
||||
// KISS: height is now a concrete field (no Option)
|
||||
let mut unclaimed_rewards_iter = unclaimed_height.into_iter();
|
||||
|
||||
for h in starting_height.to_usize()..=target_height.to_usize() {
|
||||
let height = Height::from(h);
|
||||
|
||||
// Genesis block 50 BTC is unspendable (only at height 0)
|
||||
let genesis = if height == Height::ZERO {
|
||||
Sats::FIFTY_BTC
|
||||
} else {
|
||||
Sats::ZERO
|
||||
};
|
||||
|
||||
// Per-block opreturn value
|
||||
let opreturn = opreturn_iter.get_unwrap(height);
|
||||
|
||||
// Per-block unclaimed rewards
|
||||
let unclaimed = unclaimed_rewards_iter.get_unwrap(height);
|
||||
|
||||
let unspendable = genesis + opreturn + unclaimed;
|
||||
height_vec.truncate_push(height, unspendable)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
height_vec.write()?;
|
||||
Ok(())
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::Version;
|
||||
use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec};
|
||||
use vecdb::Database;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedValueVecsFromHeight, Source, VecBuilderOptions},
|
||||
};
|
||||
use crate::{indexes, internal::ValueBlockSumCum};
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(
|
||||
@@ -15,33 +12,23 @@ impl Vecs {
|
||||
indexes: &indexes::Vecs,
|
||||
compute_dollars: bool,
|
||||
) -> Result<Self> {
|
||||
let height_to_opreturn = EagerVec::forced_import(db, "opreturn_supply", version)?;
|
||||
|
||||
let indexes_to_opreturn = ComputedValueVecsFromHeight::forced_import(
|
||||
let indexes_to_opreturn = ValueBlockSumCum::forced_import(
|
||||
db,
|
||||
"opreturn_supply",
|
||||
Source::Vec(height_to_opreturn.boxed_clone()),
|
||||
version,
|
||||
VecBuilderOptions::default().add_last().add_cumulative(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
compute_dollars,
|
||||
)?;
|
||||
|
||||
let height_to_unspendable = EagerVec::forced_import(db, "unspendable_supply", version)?;
|
||||
|
||||
let indexes_to_unspendable = ComputedValueVecsFromHeight::forced_import(
|
||||
let indexes_to_unspendable = ValueBlockSumCum::forced_import(
|
||||
db,
|
||||
"unspendable_supply",
|
||||
Source::Vec(height_to_unspendable.boxed_clone()),
|
||||
version,
|
||||
VecBuilderOptions::default().add_last().add_cumulative(),
|
||||
compute_dollars,
|
||||
indexes,
|
||||
compute_dollars,
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
height_to_opreturn,
|
||||
height_to_unspendable,
|
||||
indexes_to_opreturn,
|
||||
indexes_to_unspendable,
|
||||
})
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Sats};
|
||||
use vecdb::{EagerVec, PcoVec};
|
||||
|
||||
use crate::internal::ComputedValueVecsFromHeight;
|
||||
use crate::internal::ValueBlockSumCum;
|
||||
|
||||
/// Burned/unspendable supply metrics
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
pub height_to_opreturn: EagerVec<PcoVec<Height, Sats>>,
|
||||
pub height_to_unspendable: EagerVec<PcoVec<Height, Sats>>,
|
||||
pub indexes_to_opreturn: ComputedValueVecsFromHeight,
|
||||
pub indexes_to_unspendable: ComputedValueVecsFromHeight,
|
||||
pub indexes_to_opreturn: ValueBlockSumCum,
|
||||
pub indexes_to_unspendable: ValueBlockSumCum,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use vecdb::{IterableCloneableVec, LazyVecFrom1};
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
distribution,
|
||||
internal::{DollarsIdentity, LazyValueVecsFromDateIndex, SatsIdentity, SatsToBitcoin},
|
||||
internal::{DollarsIdentity, LazyValueDateLast, SatsIdentity, SatsToBitcoin},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -38,8 +38,8 @@ impl Vecs {
|
||||
)
|
||||
});
|
||||
|
||||
// Create lazy identity wrapper around the FULL supply (not half!)
|
||||
let indexes = LazyValueVecsFromDateIndex::from_source::<
|
||||
// Create lazy identity wrapper around the FULL supply (not half!) - KISS
|
||||
let indexes = LazyValueDateLast::from_source::<
|
||||
SatsIdentity,
|
||||
SatsToBitcoin,
|
||||
DollarsIdentity,
|
||||
|
||||
@@ -2,13 +2,13 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Dollars, Height, Sats};
|
||||
use vecdb::LazyVecFrom1;
|
||||
|
||||
use crate::internal::LazyValueVecsFromDateIndex;
|
||||
use crate::internal::LazyValueDateLast;
|
||||
|
||||
/// Circulating supply - lazy references to distribution's actual supply
|
||||
/// Circulating supply - lazy references to distribution's actual supply (KISS)
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
pub height_to_sats: LazyVecFrom1<Height, Sats, Height, Sats>,
|
||||
pub height_to_btc: LazyVecFrom1<Height, Bitcoin, Height, Sats>,
|
||||
pub height_to_usd: Option<LazyVecFrom1<Height, Dollars, Height, Dollars>>,
|
||||
pub indexes: LazyValueVecsFromDateIndex,
|
||||
pub indexes: LazyValueDateLast,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_error::Result;
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{blocks, distribution, utils::OptionExt, ComputeIndexes};
|
||||
use crate::{blocks, distribution, ComputeIndexes};
|
||||
|
||||
impl Vecs {
|
||||
pub fn compute(
|
||||
@@ -21,15 +21,12 @@ impl Vecs {
|
||||
.indexes_to_supply;
|
||||
|
||||
self.indexes.compute_all(starting_indexes, exit, |v| {
|
||||
// KISS: dateindex.sum is now a concrete field
|
||||
v.compute_transform2(
|
||||
starting_indexes.dateindex,
|
||||
blocks
|
||||
.rewards
|
||||
.indexes_to_subsidy
|
||||
.sats
|
||||
.dateindex
|
||||
.unwrap_sum(),
|
||||
circulating_supply.sats.dateindex.u(),
|
||||
&blocks.rewards.indexes_to_subsidy.sats.dateindex.sum_cum.sum.0,
|
||||
// KISS: dateindex is no longer Option
|
||||
&circulating_supply.sats_dateindex,
|
||||
|(i, subsidy_1d_sum, supply, ..)| {
|
||||
let inflation = if *supply > 0 {
|
||||
365.0 * *subsidy_1d_sum as f64 / *supply as f64 * 100.0
|
||||
|
||||
@@ -3,20 +3,15 @@ use brk_types::Version;
|
||||
use vecdb::Database;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions},
|
||||
};
|
||||
use crate::{indexes, internal::ComputedVecsDateAverage};
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
|
||||
let indexes_to_inflation_rate = ComputedVecsFromDateIndex::forced_import(
|
||||
let indexes_to_inflation_rate = ComputedVecsDateAverage::forced_import(
|
||||
db,
|
||||
"inflation_rate",
|
||||
Source::Compute,
|
||||
version,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_average(),
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::StoredF32;
|
||||
|
||||
use crate::internal::ComputedVecsFromDateIndex;
|
||||
use crate::internal::ComputedVecsDateAverage;
|
||||
|
||||
/// Inflation rate metrics
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
pub indexes: ComputedVecsFromDateIndex<StoredF32>,
|
||||
pub indexes: ComputedVecsDateAverage<StoredF32>,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use vecdb::{IterableCloneableVec, LazyVecFrom1};
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
distribution,
|
||||
internal::{DollarsIdentity, LazyVecsFromDateIndex},
|
||||
internal::{DollarsIdentity, LazyDateLast},
|
||||
};
|
||||
|
||||
impl Vecs {
|
||||
@@ -22,12 +22,12 @@ impl Vecs {
|
||||
})
|
||||
});
|
||||
|
||||
// Market cap by indexes (lazy from distribution's supply in USD)
|
||||
// Market cap by indexes (lazy from distribution's supply in USD) - KISS
|
||||
let indexes = supply_metrics.indexes_to_supply.dollars.as_ref().map(|d| {
|
||||
LazyVecsFromDateIndex::from_computed::<DollarsIdentity>(
|
||||
// KISS: dateindex is no longer Option, use from_source
|
||||
LazyDateLast::from_source::<DollarsIdentity>(
|
||||
"market_cap",
|
||||
version,
|
||||
d.dateindex.as_ref().map(|v| v.boxed_clone()),
|
||||
d,
|
||||
)
|
||||
});
|
||||
|
||||
@@ -2,12 +2,12 @@ use brk_traversable::Traversable;
|
||||
use brk_types::{Dollars, Height};
|
||||
use vecdb::LazyVecFrom1;
|
||||
|
||||
use crate::internal::LazyVecsFromDateIndex;
|
||||
use crate::internal::LazyDateLast;
|
||||
|
||||
/// Market cap metrics - lazy references to supply in USD
|
||||
/// Market cap metrics - lazy references to supply in USD (KISS)
|
||||
/// (market_cap = circulating_supply * price, already computed in distribution)
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
pub height: Option<LazyVecFrom1<Height, Dollars, Height, Dollars>>,
|
||||
pub indexes: Option<LazyVecsFromDateIndex<Dollars, Dollars>>,
|
||||
pub indexes: Option<LazyDateLast<Dollars, Dollars>>,
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_error::Result;
|
||||
use vecdb::Exit;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{distribution, transactions, utils::OptionExt, ComputeIndexes};
|
||||
use crate::{distribution, transactions, ComputeIndexes};
|
||||
|
||||
impl Vecs {
|
||||
pub fn compute(
|
||||
@@ -20,17 +20,13 @@ impl Vecs {
|
||||
.supply
|
||||
.indexes_to_supply;
|
||||
|
||||
// BTC velocity
|
||||
// BTC velocity - KISS: dateindex is no longer Option
|
||||
self.indexes_to_btc
|
||||
.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_divide(
|
||||
starting_indexes.dateindex,
|
||||
transactions
|
||||
.volume
|
||||
.indexes_to_annualized_volume_btc
|
||||
.dateindex
|
||||
.u(),
|
||||
circulating_supply.bitcoin.dateindex.u(),
|
||||
&transactions.volume.indexes_to_annualized_volume_btc.dateindex,
|
||||
&*circulating_supply.bitcoin.dateindex,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
@@ -38,18 +34,14 @@ impl Vecs {
|
||||
|
||||
// USD velocity
|
||||
if let Some(usd_velocity) = self.indexes_to_usd.as_mut()
|
||||
&& let Some(volume_usd) = transactions
|
||||
.volume
|
||||
.indexes_to_annualized_volume_usd
|
||||
.dateindex
|
||||
.as_ref()
|
||||
&& let Some(supply_usd) = circulating_supply.dollars.as_ref()
|
||||
{
|
||||
// KISS: dateindex is no longer Option
|
||||
usd_velocity.compute_all(starting_indexes, exit, |v| {
|
||||
v.compute_divide(
|
||||
starting_indexes.dateindex,
|
||||
volume_usd,
|
||||
supply_usd.dateindex.u(),
|
||||
&transactions.volume.indexes_to_annualized_volume_usd.dateindex,
|
||||
&supply_usd.dateindex,
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
|
||||
@@ -3,10 +3,7 @@ use brk_types::Version;
|
||||
use vecdb::Database;
|
||||
|
||||
use super::Vecs;
|
||||
use crate::{
|
||||
indexes,
|
||||
internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions},
|
||||
};
|
||||
use crate::{indexes, internal::ComputedVecsDateAverage};
|
||||
|
||||
impl Vecs {
|
||||
pub fn forced_import(
|
||||
@@ -15,23 +12,19 @@ impl Vecs {
|
||||
indexes: &indexes::Vecs,
|
||||
compute_dollars: bool,
|
||||
) -> Result<Self> {
|
||||
let indexes_to_btc = ComputedVecsFromDateIndex::forced_import(
|
||||
let indexes_to_btc = ComputedVecsDateAverage::forced_import(
|
||||
db,
|
||||
"btc_velocity",
|
||||
Source::Compute,
|
||||
version,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_average(),
|
||||
)?;
|
||||
|
||||
let indexes_to_usd = compute_dollars.then(|| {
|
||||
ComputedVecsFromDateIndex::forced_import(
|
||||
ComputedVecsDateAverage::forced_import(
|
||||
db,
|
||||
"usd_velocity",
|
||||
Source::Compute,
|
||||
version,
|
||||
indexes,
|
||||
VecBuilderOptions::default().add_average(),
|
||||
)
|
||||
.unwrap()
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::StoredF64;
|
||||
|
||||
use crate::internal::ComputedVecsFromDateIndex;
|
||||
use crate::internal::ComputedVecsDateAverage;
|
||||
|
||||
/// Velocity metrics (annualized volume / circulating supply)
|
||||
#[derive(Clone, Traversable)]
|
||||
pub struct Vecs {
|
||||
pub indexes_to_btc: ComputedVecsFromDateIndex<StoredF64>,
|
||||
pub indexes_to_usd: Option<ComputedVecsFromDateIndex<StoredF64>>,
|
||||
pub indexes_to_btc: ComputedVecsDateAverage<StoredF64>,
|
||||
pub indexes_to_usd: Option<ComputedVecsDateAverage<StoredF64>>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user