global: MASSIVE snapshot

This commit is contained in:
nym21
2026-01-02 19:08:20 +01:00
parent ac6175688d
commit 3e9b1cc2b2
462 changed files with 34975 additions and 20072 deletions
+60
View File
@@ -0,0 +1,60 @@
use brk_error::Result;
use brk_indexer::Indexer;
use vecdb::Exit;
use crate::{ComputeIndexes, indexes, price, transactions};
use super::Vecs;
impl Vecs {
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
transactions: &transactions::Vecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
exit: &Exit,
) -> Result<()> {
// Core block metrics
self.count
.compute(indexer, indexes, &self.time, starting_indexes, exit)?;
self.interval.compute(indexes, starting_indexes, exit)?;
self.size
.compute(indexer, indexes, starting_indexes, exit)?;
self.weight
.compute(indexer, indexes, starting_indexes, exit)?;
// Time metrics (timestamps)
self.time.compute(indexes, starting_indexes, exit)?;
// Epoch metrics
self.difficulty.compute(indexes, starting_indexes, exit)?;
self.halving.compute(indexes, starting_indexes, exit)?;
// Rewards depends on count and transactions fees
self.rewards.compute(
indexer,
indexes,
&self.count,
&transactions.fees,
starting_indexes,
price,
exit,
)?;
// Mining depends on count and rewards
self.mining.compute(
indexer,
indexes,
&self.count,
&self.rewards,
starting_indexes,
exit,
)?;
let _lock = exit.lock();
self.db.compact()?;
Ok(())
}
}
@@ -0,0 +1,85 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{Height, StoredU32};
use vecdb::{Exit, TypedVecIterator};
use super::super::time;
use super::Vecs;
use crate::{indexes, ComputeIndexes};
impl Vecs {
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
time: &time::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
let mut height_to_timestamp_fixed_iter =
time.height_to_timestamp_fixed.into_iter();
let mut prev = Height::ZERO;
self.height_to_24h_block_count.compute_transform(
starting_indexes.height,
&time.height_to_timestamp_fixed,
|(h, t, ..)| {
while t.difference_in_days_between(height_to_timestamp_fixed_iter.get_unwrap(prev))
> 0
{
prev.increment();
if prev > h {
unreachable!()
}
}
(h, StoredU32::from(*h + 1 - *prev))
},
exit,
)?;
self.indexes_to_block_count
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_range(
starting_indexes.height,
&indexer.vecs.block.height_to_weight,
|h| (h, StoredU32::from(1_u32)),
exit,
)?;
Ok(())
})?;
self.indexes_to_1w_block_count
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_block_count.dateindex.unwrap_sum(),
7,
exit,
)?;
Ok(())
})?;
self.indexes_to_1m_block_count
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_block_count.dateindex.unwrap_sum(),
30,
exit,
)?;
Ok(())
})?;
self.indexes_to_1y_block_count
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_block_count.dateindex.unwrap_sum(),
365,
exit,
)?;
Ok(())
})?;
Ok(())
}
}
@@ -0,0 +1,108 @@
use brk_error::Result;
use brk_types::{StoredU64, Version};
use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1};
use super::Vecs;
use crate::{
blocks::{
TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DECADE, TARGET_BLOCKS_PER_MONTH,
TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, TARGET_BLOCKS_PER_WEEK,
TARGET_BLOCKS_PER_YEAR,
},
indexes,
internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v0 = Version::ZERO;
let last = || VecBuilderOptions::default().add_last();
let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative();
Ok(Self {
dateindex_to_block_count_target: LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.dateindex_to_dateindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DAY)),
),
weekindex_to_block_count_target: LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.weekindex_to_weekindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_WEEK)),
),
monthindex_to_block_count_target: LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.monthindex_to_monthindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_MONTH)),
),
quarterindex_to_block_count_target: LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.quarterindex_to_quarterindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_QUARTER)),
),
semesterindex_to_block_count_target: LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.semesterindex_to_semesterindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_SEMESTER)),
),
yearindex_to_block_count_target: LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.yearindex_to_yearindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_YEAR)),
),
decadeindex_to_block_count_target: LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.decadeindex_to_decadeindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DECADE)),
),
height_to_24h_block_count: EagerVec::forced_import(
db,
"24h_block_count",
version + v0,
)?,
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
db,
"block_count",
Source::Compute,
version + v0,
indexes,
sum_cum(),
)?,
indexes_to_1w_block_count: ComputedVecsFromDateIndex::forced_import(
db,
"1w_block_count",
Source::Compute,
version + v0,
indexes,
last(),
)?,
indexes_to_1m_block_count: ComputedVecsFromDateIndex::forced_import(
db,
"1m_block_count",
Source::Compute,
version + v0,
indexes,
last(),
)?,
indexes_to_1y_block_count: ComputedVecsFromDateIndex::forced_import(
db,
"1y_block_count",
Source::Compute,
version + v0,
indexes,
last(),
)?,
})
}
}
@@ -0,0 +1,24 @@
use brk_traversable::Traversable;
use brk_types::{
DateIndex, DecadeIndex, MonthIndex, QuarterIndex, SemesterIndex,
StoredU32, StoredU64, WeekIndex, YearIndex,
};
use vecdb::LazyVecFrom1;
use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight};
#[derive(Clone, Traversable)]
pub struct Vecs {
pub dateindex_to_block_count_target: LazyVecFrom1<DateIndex, StoredU64, DateIndex, DateIndex>,
pub weekindex_to_block_count_target: LazyVecFrom1<WeekIndex, StoredU64, WeekIndex, WeekIndex>,
pub monthindex_to_block_count_target: LazyVecFrom1<MonthIndex, StoredU64, MonthIndex, MonthIndex>,
pub quarterindex_to_block_count_target: LazyVecFrom1<QuarterIndex, StoredU64, QuarterIndex, QuarterIndex>,
pub semesterindex_to_block_count_target: LazyVecFrom1<SemesterIndex, StoredU64, SemesterIndex, SemesterIndex>,
pub yearindex_to_block_count_target: LazyVecFrom1<YearIndex, StoredU64, YearIndex, YearIndex>,
pub decadeindex_to_block_count_target: LazyVecFrom1<DecadeIndex, StoredU64, DecadeIndex, DecadeIndex>,
pub height_to_24h_block_count: vecdb::EagerVec<vecdb::PcoVec<brk_types::Height, StoredU32>>,
pub indexes_to_block_count: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_1w_block_count: ComputedVecsFromDateIndex<StoredU32>,
pub indexes_to_1m_block_count: ComputedVecsFromDateIndex<StoredU32>,
pub indexes_to_1y_block_count: ComputedVecsFromDateIndex<StoredU32>,
}
@@ -0,0 +1,63 @@
use brk_error::Result;
use brk_types::StoredU32;
use vecdb::{Exit, TypedVecIterator};
use super::Vecs;
use super::super::TARGET_BLOCKS_PER_DAY_F32;
use crate::{indexes, ComputeIndexes};
impl Vecs {
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
let mut height_to_difficultyepoch_iter =
indexes.block.height_to_difficultyepoch.into_iter();
self.indexes_to_difficultyepoch
.compute_all(starting_indexes, exit, |vec| {
let mut height_count_iter = indexes.time.dateindex_to_height_count.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&indexes.time.dateindex_to_first_height,
|(di, height, ..)| {
(
di,
height_to_difficultyepoch_iter
.get_unwrap(height + (*height_count_iter.get_unwrap(di) - 1)),
)
},
exit,
)?;
Ok(())
})?;
self.indexes_to_blocks_before_next_difficulty_adjustment
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_transform(
starting_indexes.height,
&indexes.block.height_to_height,
|(h, ..)| (h, StoredU32::from(h.left_before_next_diff_adj())),
exit,
)?;
Ok(())
})?;
self.indexes_to_days_before_next_difficulty_adjustment
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_transform(
starting_indexes.height,
self.indexes_to_blocks_before_next_difficulty_adjustment
.height
.as_ref()
.unwrap(),
|(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()),
exit,
)?;
Ok(())
})?;
Ok(())
}
}
@@ -4,8 +4,8 @@ use vecdb::Database;
use super::Vecs;
use crate::{
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
indexes,
internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
@@ -23,15 +23,6 @@ impl Vecs {
indexes,
last(),
)?,
indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import(
db,
"halvingepoch",
Source::Compute,
version + v0,
indexes,
last(),
)?,
// Countdown metrics (moved from mining)
indexes_to_blocks_before_next_difficulty_adjustment:
ComputedVecsFromHeight::forced_import(
db,
@@ -50,22 +41,6 @@ impl Vecs {
indexes,
last(),
)?,
indexes_to_blocks_before_next_halving: ComputedVecsFromHeight::forced_import(
db,
"blocks_before_next_halving",
Source::Compute,
version + v2,
indexes,
last(),
)?,
indexes_to_days_before_next_halving: ComputedVecsFromHeight::forced_import(
db,
"days_before_next_halving",
Source::Compute,
version + v2,
indexes,
last(),
)?,
})
}
}
@@ -0,0 +1,12 @@
use brk_traversable::Traversable;
use brk_types::{DifficultyEpoch, StoredF32, StoredU32};
use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight};
/// Difficulty epoch metrics and countdown
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex<DifficultyEpoch>,
pub indexes_to_blocks_before_next_difficulty_adjustment: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_days_before_next_difficulty_adjustment: ComputedVecsFromHeight<StoredF32>,
}
@@ -3,7 +3,8 @@ use brk_types::StoredU32;
use vecdb::{Exit, TypedVecIterator};
use super::Vecs;
use crate::{chain::TARGET_BLOCKS_PER_DAY_F32, indexes, ComputeIndexes};
use super::super::TARGET_BLOCKS_PER_DAY_F32;
use crate::{indexes, ComputeIndexes};
impl Vecs {
pub fn compute(
@@ -12,26 +13,6 @@ impl Vecs {
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
let mut height_to_difficultyepoch_iter =
indexes.block.height_to_difficultyepoch.into_iter();
self.indexes_to_difficultyepoch
.compute_all(starting_indexes, exit, |vec| {
let mut height_count_iter = indexes.time.dateindex_to_height_count.into_iter();
vec.compute_transform(
starting_indexes.dateindex,
&indexes.time.dateindex_to_first_height,
|(di, height, ..)| {
(
di,
height_to_difficultyepoch_iter
.get_unwrap(height + (*height_count_iter.get_unwrap(di) - 1)),
)
},
exit,
)?;
Ok(())
})?;
let mut height_to_halvingepoch_iter = indexes.block.height_to_halvingepoch.into_iter();
self.indexes_to_halvingepoch
.compute_all(starting_indexes, exit, |vec| {
@@ -51,32 +32,6 @@ impl Vecs {
Ok(())
})?;
// Countdown metrics (moved from mining)
self.indexes_to_blocks_before_next_difficulty_adjustment
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_transform(
starting_indexes.height,
&indexes.block.height_to_height,
|(h, ..)| (h, StoredU32::from(h.left_before_next_diff_adj())),
exit,
)?;
Ok(())
})?;
self.indexes_to_days_before_next_difficulty_adjustment
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_transform(
starting_indexes.height,
self.indexes_to_blocks_before_next_difficulty_adjustment
.height
.as_ref()
.unwrap(),
|(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()),
exit,
)?;
Ok(())
})?;
self.indexes_to_blocks_before_next_halving.compute_all(
indexes,
starting_indexes,
@@ -0,0 +1,44 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let v0 = Version::ZERO;
let v2 = Version::TWO;
let last = || VecBuilderOptions::default().add_last();
Ok(Self {
indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import(
db,
"halvingepoch",
Source::Compute,
version + v0,
indexes,
last(),
)?,
indexes_to_blocks_before_next_halving: ComputedVecsFromHeight::forced_import(
db,
"blocks_before_next_halving",
Source::Compute,
version + v2,
indexes,
last(),
)?,
indexes_to_days_before_next_halving: ComputedVecsFromHeight::forced_import(
db,
"days_before_next_halving",
Source::Compute,
version + v2,
indexes,
last(),
)?,
})
}
}
@@ -0,0 +1,12 @@
use brk_traversable::Traversable;
use brk_types::{HalvingEpoch, StoredF32, StoredU32};
use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight};
/// Halving epoch metrics and countdown
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_halvingepoch: ComputedVecsFromDateIndex<HalvingEpoch>,
pub indexes_to_blocks_before_next_halving: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_days_before_next_halving: ComputedVecsFromHeight<StoredF32>,
}
+62
View File
@@ -0,0 +1,62 @@
use std::path::Path;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_traversable::Traversable;
use brk_types::Version;
use vecdb::{Database, PAGE_SIZE};
use crate::{indexes, price};
use super::{
CountVecs, DifficultyVecs, HalvingVecs, IntervalVecs, MiningVecs,
RewardsVecs, SizeVecs, TimeVecs, Vecs, WeightVecs,
};
impl Vecs {
pub fn forced_import(
parent_path: &Path,
parent_version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let db = Database::open(&parent_path.join(super::DB_NAME))?;
db.set_min_len(PAGE_SIZE * 50_000_000)?;
let version = parent_version + Version::ZERO;
let compute_dollars = price.is_some();
let count = CountVecs::forced_import(&db, version, indexes)?;
let interval = IntervalVecs::forced_import(&db, version, indexer, indexes)?;
let size = SizeVecs::forced_import(&db, version, indexer, indexes)?;
let weight = WeightVecs::forced_import(&db, version, indexer, indexes)?;
let time = TimeVecs::forced_import(&db, version, indexer, indexes)?;
let mining = MiningVecs::forced_import(&db, version, indexer, indexes)?;
let rewards = RewardsVecs::forced_import(&db, version, indexes, compute_dollars)?;
let difficulty = DifficultyVecs::forced_import(&db, version, indexes)?;
let halving = HalvingVecs::forced_import(&db, version, indexes)?;
let this = Self {
db,
count,
interval,
size,
weight,
time,
mining,
rewards,
difficulty,
halving,
};
this.db.retain_regions(
this.iter_any_exportable()
.flat_map(|v| v.region_names())
.collect(),
)?;
this.db.compact()?;
Ok(this)
}
}
@@ -0,0 +1,23 @@
use brk_error::Result;
use vecdb::Exit;
use super::Vecs;
use crate::{ComputeIndexes, indexes};
impl Vecs {
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.indexes_to_block_interval.compute_rest(
indexes,
starting_indexes,
exit,
Some(&self.height_to_interval),
)?;
Ok(())
}
}
@@ -0,0 +1,56 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{CheckedSub, Height, Timestamp, Version};
use vecdb::{Database, IterableCloneableVec, LazyVecFrom1};
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v0 = Version::ZERO;
let stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
};
let height_to_interval = LazyVecFrom1::init(
"interval",
version + v0,
indexer.vecs.block.height_to_timestamp.boxed_clone(),
|height: Height, timestamp_iter| {
let timestamp = timestamp_iter.get(height)?;
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
timestamp_iter
.get(prev_h)
.map_or(Timestamp::ZERO, |prev_t| {
timestamp.checked_sub(prev_t).unwrap_or(Timestamp::ZERO)
})
});
Some(interval)
},
);
Ok(Self {
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
db,
"block_interval",
Source::Vec(height_to_interval.boxed_clone()),
version + v0,
indexes,
stats(),
)?,
height_to_interval,
})
}
}
@@ -0,0 +1,11 @@
use brk_traversable::Traversable;
use brk_types::{Height, Timestamp};
use vecdb::LazyVecFrom1;
use crate::internal::ComputedVecsFromHeight;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub height_to_interval: LazyVecFrom1<Height, Timestamp, Height, Timestamp>,
pub indexes_to_block_interval: ComputedVecsFromHeight<Timestamp>,
}
@@ -4,8 +4,8 @@ use brk_types::{StoredF32, StoredF64};
use vecdb::Exit;
use super::Vecs;
use super::super::{count, rewards, ONE_TERA_HASH, TARGET_BLOCKS_PER_DAY_F64};
use crate::{
chain::{block, coinbase, ONE_TERA_HASH, TARGET_BLOCKS_PER_DAY_F64},
indexes,
utils::OptionExt,
ComputeIndexes,
@@ -16,8 +16,8 @@ impl Vecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
block_vecs: &block::Vecs,
coinbase_vecs: &coinbase::Vecs,
count_vecs: &count::Vecs,
rewards_vecs: &rewards::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
@@ -44,7 +44,7 @@ impl Vecs {
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_transform2(
starting_indexes.height,
&block_vecs.height_to_24h_block_count,
&count_vecs.height_to_24h_block_count,
self.indexes_to_difficulty_as_hash.height.u(),
|(i, block_count_sum, difficulty_as_hash, ..)| {
(
@@ -123,10 +123,16 @@ impl Vecs {
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_transform2(
starting_indexes.height,
&coinbase_vecs.height_to_24h_coinbase_usd_sum,
&rewards_vecs.height_to_24h_coinbase_usd_sum,
self.indexes_to_hash_rate.height.u(),
|(i, coinbase_sum, hashrate, ..)| {
(i, (*coinbase_sum / (*hashrate / ONE_TERA_HASH)).into())
let hashrate_ths = *hashrate / ONE_TERA_HASH;
let price = if hashrate_ths == 0.0 {
StoredF32::NAN
} else {
(*coinbase_sum / hashrate_ths).into()
};
(i, price)
},
exit,
)?;
@@ -148,13 +154,16 @@ impl Vecs {
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_transform2(
starting_indexes.height,
&coinbase_vecs.height_to_24h_coinbase_sum,
&rewards_vecs.height_to_24h_coinbase_sum,
self.indexes_to_hash_rate.height.u(),
|(i, coinbase_sum, hashrate, ..)| {
(
i,
(*coinbase_sum as f64 / (*hashrate / ONE_TERA_HASH)).into(),
)
let hashrate_ths = *hashrate / ONE_TERA_HASH;
let value = if hashrate_ths == 0.0 {
StoredF32::NAN
} else {
StoredF32::from(*coinbase_sum as f64 / hashrate_ths)
};
(i, value)
},
exit,
)?;
@@ -5,7 +5,7 @@ use vecdb::{Database, IterableCloneableVec};
use super::Vecs;
use crate::{
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
indexes,
};
@@ -1,7 +1,7 @@
use brk_traversable::Traversable;
use brk_types::{StoredF32, StoredF64};
use crate::grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight};
use crate::internal::{ComputedVecsFromDateIndex, ComputedVecsFromHeight};
/// Mining-related metrics: hash rate, hash price, hash value, difficulty
#[derive(Clone, Traversable)]
@@ -1,25 +1,30 @@
pub mod block;
pub mod coinbase;
mod compute;
pub mod epoch;
mod import;
pub mod count;
pub mod difficulty;
pub mod halving;
pub mod interval;
pub mod mining;
pub mod output_type;
pub mod transaction;
pub mod volume;
pub mod rewards;
pub mod size;
pub mod time;
pub mod weight;
mod compute;
mod import;
use brk_traversable::Traversable;
use vecdb::Database;
pub use block::Vecs as BlockVecs;
pub use coinbase::Vecs as CoinbaseVecs;
pub use epoch::Vecs as EpochVecs;
pub use count::Vecs as CountVecs;
pub use difficulty::Vecs as DifficultyVecs;
pub use halving::Vecs as HalvingVecs;
pub use interval::Vecs as IntervalVecs;
pub use mining::Vecs as MiningVecs;
pub use output_type::Vecs as OutputTypeVecs;
pub use transaction::Vecs as TransactionVecs;
pub use volume::Vecs as VolumeVecs;
pub use rewards::Vecs as RewardsVecs;
pub use size::Vecs as SizeVecs;
pub use time::Vecs as TimeVecs;
pub use weight::Vecs as WeightVecs;
pub const DB_NAME: &str = "chain";
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;
@@ -32,16 +37,18 @@ 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 ONE_TERA_HASH: f64 = 1_000_000_000_000.0;
/// Main chain metrics struct composed of sub-modules
#[derive(Clone, Traversable)]
pub struct Vecs {
#[traversable(skip)]
pub(crate) db: Database,
pub block: BlockVecs,
pub epoch: EpochVecs,
pub count: CountVecs,
pub interval: IntervalVecs,
pub size: SizeVecs,
pub weight: WeightVecs,
pub time: TimeVecs,
pub mining: MiningVecs,
pub coinbase: CoinbaseVecs,
pub transaction: TransactionVecs,
pub output_type: OutputTypeVecs,
pub volume: VolumeVecs,
pub rewards: RewardsVecs,
pub difficulty: DifficultyVecs,
pub halving: HalvingVecs,
}
@@ -5,11 +5,12 @@ use vecdb::{Exit, IterableVec, TypedVecIterator, VecIndex};
use super::Vecs;
use crate::{
transactions,
ComputeIndexes,
chain::{block, transaction},
indexes, price,
utils::OptionExt,
};
use super::super::count;
impl Vecs {
#[allow(clippy::too_many_arguments)]
@@ -17,8 +18,8 @@ impl Vecs {
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
block_vecs: &block::Vecs,
transaction_vecs: &transaction::Vecs,
count_vecs: &count::Vecs,
transactions_fees: &transactions::FeesVecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
exit: &Exit,
@@ -61,7 +62,7 @@ impl Vecs {
.into_iter();
self.height_to_24h_coinbase_sum.compute_transform(
starting_indexes.height,
&block_vecs.height_to_24h_block_count,
&count_vecs.height_to_24h_block_count,
|(h, count, ..)| {
let range = *h - (*count - 1)..=*h;
let sum = range
@@ -82,7 +83,7 @@ impl Vecs {
{
self.height_to_24h_coinbase_usd_sum.compute_transform(
starting_indexes.height,
&block_vecs.height_to_24h_block_count,
&count_vecs.height_to_24h_block_count,
|(h, count, ..)| {
let range = *h - (*count - 1)..=*h;
let sum = range
@@ -100,7 +101,7 @@ impl Vecs {
vec.compute_transform2(
starting_indexes.height,
self.indexes_to_coinbase.sats.height.u(),
transaction_vecs.indexes_to_fee.sats.height.unwrap_sum(),
transactions_fees.indexes_to_fee.sats.height.unwrap_sum(),
|(height, coinbase, fees, ..)| {
(
height,
@@ -135,33 +136,18 @@ impl Vecs {
},
)?;
self.indexes_to_inflation_rate
.compute_all(starting_indexes, exit, |v| {
v.compute_transform2(
starting_indexes.dateindex,
self.indexes_to_subsidy.sats.dateindex.unwrap_sum(),
self.indexes_to_subsidy.sats.dateindex.unwrap_cumulative(),
|(i, subsidy_1d_sum, subsidy_cumulative, ..)| {
(
i,
(365.0 * *subsidy_1d_sum as f64 / *subsidy_cumulative as f64 * 100.0)
.into(),
)
},
exit,
)?;
Ok(())
})?;
self.dateindex_to_fee_dominance.compute_transform2(
starting_indexes.dateindex,
transaction_vecs.indexes_to_fee.sats.dateindex.unwrap_sum(),
transactions_fees.indexes_to_fee.sats.dateindex.unwrap_sum(),
self.indexes_to_coinbase.sats.dateindex.unwrap_sum(),
|(i, fee, coinbase, ..)| {
(
i,
StoredF32::from(u64::from(fee) as f64 / u64::from(coinbase) as f64 * 100.0),
)
let coinbase_f64 = u64::from(coinbase) as f64;
let dominance = if coinbase_f64 == 0.0 {
StoredF32::NAN
} else {
StoredF32::from(u64::from(fee) as f64 / coinbase_f64 * 100.0)
};
(i, dominance)
},
exit,
)?;
@@ -171,15 +157,18 @@ impl Vecs {
self.indexes_to_subsidy.sats.dateindex.unwrap_sum(),
self.indexes_to_coinbase.sats.dateindex.unwrap_sum(),
|(i, subsidy, coinbase, ..)| {
(
i,
StoredF32::from(u64::from(subsidy) as f64 / u64::from(coinbase) as f64 * 100.0),
)
let coinbase_f64 = u64::from(coinbase) as f64;
let dominance = if coinbase_f64 == 0.0 {
StoredF32::NAN
} else {
StoredF32::from(u64::from(subsidy) as f64 / coinbase_f64 * 100.0)
};
(i, dominance)
},
exit,
)?;
if self.indexes_to_subsidy_usd_1y_sma.is_some() {
if let Some(sma) = self.indexes_to_subsidy_usd_1y_sma.as_mut() {
let date_to_coinbase_usd_sum = self
.indexes_to_coinbase
.dollars
@@ -188,36 +177,15 @@ impl Vecs {
.dateindex
.unwrap_sum();
self.indexes_to_subsidy_usd_1y_sma
.as_mut()
.unwrap()
.compute_all(starting_indexes, exit, |v| {
v.compute_sma(
starting_indexes.dateindex,
date_to_coinbase_usd_sum,
365,
exit,
)?;
Ok(())
})?;
self.indexes_to_puell_multiple
.as_mut()
.unwrap()
.compute_all(starting_indexes, exit, |v| {
v.compute_divide(
starting_indexes.dateindex,
date_to_coinbase_usd_sum,
self.indexes_to_subsidy_usd_1y_sma
.as_ref()
.unwrap()
.dateindex
.as_ref()
.unwrap(),
exit,
)?;
Ok(())
})?;
sma.compute_all(starting_indexes, exit, |v| {
v.compute_sma(
starting_indexes.dateindex,
date_to_coinbase_usd_sum,
365,
exit,
)?;
Ok(())
})?;
}
Ok(())
@@ -4,7 +4,7 @@ use vecdb::{Database, EagerVec, ImportableVec};
use super::Vecs;
use crate::{
grouped::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, Source, VecBuilderOptions},
internal::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, Source, VecBuilderOptions},
indexes,
};
@@ -84,26 +84,6 @@ impl Vecs {
)
})
.transpose()?,
indexes_to_puell_multiple: compute_dollars
.then(|| {
ComputedVecsFromDateIndex::forced_import(
db,
"puell_multiple",
Source::Compute,
version + v0,
indexes,
last(),
)
})
.transpose()?,
indexes_to_inflation_rate: ComputedVecsFromDateIndex::forced_import(
db,
"inflation_rate",
Source::Compute,
version + v0,
indexes,
last(),
)?,
})
}
}
@@ -2,7 +2,7 @@ use brk_traversable::Traversable;
use brk_types::{DateIndex, Dollars, Height, Sats, StoredF32};
use vecdb::{EagerVec, PcoVec};
use crate::grouped::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex};
use crate::internal::{ComputedValueVecsFromHeight, ComputedVecsFromDateIndex};
/// Coinbase/subsidy/rewards metrics
#[derive(Clone, Traversable)]
@@ -15,6 +15,4 @@ pub struct Vecs {
pub dateindex_to_fee_dominance: EagerVec<PcoVec<DateIndex, StoredF32>>,
pub dateindex_to_subsidy_dominance: EagerVec<PcoVec<DateIndex, StoredF32>>,
pub indexes_to_subsidy_usd_1y_sma: Option<ComputedVecsFromDateIndex<Dollars>>,
pub indexes_to_puell_multiple: Option<ComputedVecsFromDateIndex<StoredF32>>,
pub indexes_to_inflation_rate: ComputedVecsFromDateIndex<StoredF32>,
}
@@ -0,0 +1,32 @@
use brk_error::Result;
use brk_indexer::Indexer;
use vecdb::Exit;
use super::Vecs;
use crate::{indexes, ComputeIndexes};
impl Vecs {
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.indexes_to_block_size.compute_rest(
indexes,
starting_indexes,
exit,
Some(&indexer.vecs.block.height_to_total_size),
)?;
self.indexes_to_block_vbytes.compute_rest(
indexes,
starting_indexes,
exit,
Some(&self.height_to_vbytes),
)?;
Ok(())
}
}
@@ -0,0 +1,60 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{Height, StoredU64, Version};
use vecdb::{Database, IterableCloneableVec, LazyVecFrom1, VecIndex};
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v0 = Version::ZERO;
let full_stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
.add_sum()
.add_cumulative()
};
let height_to_vbytes = LazyVecFrom1::init(
"vbytes",
version + v0,
indexer.vecs.block.height_to_weight.boxed_clone(),
|height: Height, weight_iter| {
weight_iter
.get_at(height.to_usize())
.map(|w| StoredU64::from(w.to_vbytes_floor()))
},
);
Ok(Self {
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
db,
"block_size",
Source::Vec(indexer.vecs.block.height_to_total_size.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?,
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
db,
"block_vbytes",
Source::Vec(height_to_vbytes.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?,
height_to_vbytes,
})
}
}
@@ -0,0 +1,12 @@
use brk_traversable::Traversable;
use brk_types::{Height, StoredU64, Weight};
use vecdb::LazyVecFrom1;
use crate::internal::ComputedVecsFromHeight;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub height_to_vbytes: LazyVecFrom1<Height, StoredU64, Height, Weight>,
pub indexes_to_block_size: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_block_vbytes: ComputedVecsFromHeight<StoredU64>,
}
@@ -0,0 +1,62 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::Timestamp;
use vecdb::{Exit, TypedVecIterator};
use super::Vecs;
use crate::{indexes, ComputeIndexes};
impl Vecs {
/// Compute height-to-time fields early, before indexes are computed.
/// These are needed by indexes::block to compute height_to_dateindex.
pub fn compute_early(
&mut self,
indexer: &Indexer,
starting_height: brk_types::Height,
exit: &Exit,
) -> Result<()> {
let mut prev_timestamp_fixed = None;
self.height_to_timestamp_fixed.compute_transform(
starting_height,
&indexer.vecs.block.height_to_timestamp,
|(h, timestamp, height_to_timestamp_fixed_iter)| {
if prev_timestamp_fixed.is_none()
&& let Some(prev_h) = h.decremented()
{
prev_timestamp_fixed.replace(
height_to_timestamp_fixed_iter
.into_iter()
.get_unwrap(prev_h),
);
}
let timestamp_fixed =
prev_timestamp_fixed.map_or(timestamp, |prev_d| prev_d.max(timestamp));
prev_timestamp_fixed.replace(timestamp_fixed);
(h, timestamp_fixed)
},
exit,
)?;
Ok(())
}
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.timeindexes_to_timestamp
.compute_all(starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.dateindex,
&indexes.time.dateindex_to_date,
|(di, d, ..)| (di, Timestamp::from(d)),
exit,
)?;
Ok(())
})?;
Ok(())
}
}
@@ -0,0 +1,61 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{Date, DifficultyEpoch, Height, Version};
use vecdb::{
Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1, LazyVecFrom2, VecIndex,
};
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
) -> Result<Self> {
let height_to_timestamp_fixed =
EagerVec::forced_import(db, "timestamp_fixed", version + Version::ZERO)?;
Ok(Self {
height_to_date: LazyVecFrom1::init(
"date",
version + Version::ZERO,
indexer.vecs.block.height_to_timestamp.boxed_clone(),
|height: Height, timestamp_iter| {
timestamp_iter.get_at(height.to_usize()).map(Date::from)
},
),
height_to_date_fixed: LazyVecFrom1::init(
"date_fixed",
version + Version::ZERO,
height_to_timestamp_fixed.boxed_clone(),
|height: Height, timestamp_iter| timestamp_iter.get(height).map(Date::from),
),
height_to_timestamp_fixed,
difficultyepoch_to_timestamp: LazyVecFrom2::init(
"timestamp",
version + Version::ZERO,
indexes.block.difficultyepoch_to_first_height.boxed_clone(),
indexer.vecs.block.height_to_timestamp.boxed_clone(),
|di: DifficultyEpoch, first_height_iter, timestamp_iter| {
first_height_iter
.get(di)
.and_then(|h: Height| timestamp_iter.get(h))
},
),
timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import(
db,
"timestamp",
Source::Compute,
version + Version::ZERO,
indexes,
VecBuilderOptions::default().add_first(),
)?,
})
}
}
@@ -0,0 +1,16 @@
use brk_traversable::Traversable;
use brk_types::{Date, DifficultyEpoch, Height, Timestamp};
use vecdb::{EagerVec, LazyVecFrom1, LazyVecFrom2, PcoVec};
use crate::internal::ComputedVecsFromDateIndex;
/// Timestamp and date metrics for blocks
#[derive(Clone, Traversable)]
pub struct Vecs {
pub height_to_date: LazyVecFrom1<Height, Date, Height, Timestamp>,
pub height_to_date_fixed: LazyVecFrom1<Height, Date, Height, Timestamp>,
pub height_to_timestamp_fixed: EagerVec<PcoVec<Height, Timestamp>>,
pub difficultyepoch_to_timestamp:
LazyVecFrom2<DifficultyEpoch, Timestamp, DifficultyEpoch, Height, Height, Timestamp>,
pub timeindexes_to_timestamp: ComputedVecsFromDateIndex<Timestamp>,
}
@@ -0,0 +1,25 @@
use brk_error::Result;
use brk_indexer::Indexer;
use vecdb::Exit;
use super::Vecs;
use crate::{indexes, ComputeIndexes};
impl Vecs {
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
self.indexes_to_block_weight.compute_rest(
indexes,
starting_indexes,
exit,
Some(&indexer.vecs.block.height_to_weight),
)?;
Ok(())
}
}
@@ -0,0 +1,50 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::Version;
use vecdb::{Database, IterableCloneableVec};
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromHeight, LazyVecsFromHeight, Source, VecBuilderOptions, WeightToFullness},
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v0 = Version::ZERO;
let full_stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
.add_sum()
.add_cumulative()
};
let indexes_to_block_weight = ComputedVecsFromHeight::forced_import(
db,
"block_weight",
Source::Vec(indexer.vecs.block.height_to_weight.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?;
let indexes_to_block_fullness = LazyVecsFromHeight::from_computed::<WeightToFullness>(
"block_fullness",
version + v0,
indexer.vecs.block.height_to_weight.boxed_clone(),
&indexes_to_block_weight,
);
Ok(Self {
indexes_to_block_weight,
indexes_to_block_fullness,
})
}
}
@@ -0,0 +1,5 @@
mod compute;
mod import;
mod vecs;
pub use vecs::Vecs;
@@ -0,0 +1,11 @@
use brk_traversable::Traversable;
use brk_types::{StoredF32, Weight};
use crate::internal::{ComputedVecsFromHeight, LazyVecsFromHeight};
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_block_weight: ComputedVecsFromHeight<Weight>,
/// Block fullness as percentage of max block weight (0-100%)
pub indexes_to_block_fullness: LazyVecsFromHeight<StoredF32, Weight>,
}
@@ -1,160 +0,0 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{CheckedSub, Height, StoredU32, StoredU64, Timestamp};
use vecdb::{Exit, TypedVecIterator};
use super::Vecs;
use crate::{ComputeIndexes, indexes};
impl Vecs {
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
let mut height_to_timestamp_fixed_iter =
indexes.block.height_to_timestamp_fixed.into_iter();
let mut prev = Height::ZERO;
self.height_to_24h_block_count.compute_transform(
starting_indexes.height,
&indexes.block.height_to_timestamp_fixed,
|(h, t, ..)| {
while t.difference_in_days_between(height_to_timestamp_fixed_iter.get_unwrap(prev))
> 0
{
prev.increment();
if prev > h {
unreachable!()
}
}
(h, StoredU32::from(*h + 1 - *prev))
},
exit,
)?;
self.indexes_to_block_count
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_range(
starting_indexes.height,
&indexer.vecs.block.height_to_weight,
|h| (h, StoredU32::from(1_u32)),
exit,
)?;
Ok(())
})?;
self.indexes_to_1w_block_count
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_block_count.dateindex.unwrap_sum(),
7,
exit,
)?;
Ok(())
})?;
self.indexes_to_1m_block_count
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_block_count.dateindex.unwrap_sum(),
30,
exit,
)?;
Ok(())
})?;
self.indexes_to_1y_block_count
.compute_all(starting_indexes, exit, |v| {
v.compute_sum(
starting_indexes.dateindex,
self.indexes_to_block_count.dateindex.unwrap_sum(),
365,
exit,
)?;
Ok(())
})?;
let mut height_to_timestamp_iter = indexer.vecs.block.height_to_timestamp.iter()?;
self.height_to_interval.compute_transform(
starting_indexes.height,
&indexer.vecs.block.height_to_timestamp,
|(height, timestamp, ..)| {
let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| {
let prev_timestamp = height_to_timestamp_iter.get_unwrap(prev_h);
timestamp
.checked_sub(prev_timestamp)
.unwrap_or(Timestamp::ZERO)
});
(height, interval)
},
exit,
)?;
self.indexes_to_block_interval.compute_rest(
indexes,
starting_indexes,
exit,
Some(&self.height_to_interval),
)?;
self.indexes_to_block_weight.compute_rest(
indexes,
starting_indexes,
exit,
Some(&indexer.vecs.block.height_to_weight),
)?;
self.indexes_to_block_size.compute_rest(
indexes,
starting_indexes,
exit,
Some(&indexer.vecs.block.height_to_total_size),
)?;
self.height_to_vbytes.compute_transform(
starting_indexes.height,
&indexer.vecs.block.height_to_weight,
|(h, w, ..)| {
(
h,
StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()),
)
},
exit,
)?;
self.indexes_to_block_vbytes.compute_rest(
indexes,
starting_indexes,
exit,
Some(&self.height_to_vbytes),
)?;
// Timestamp metrics (moved from epoch)
self.timeindexes_to_timestamp
.compute_all(starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.dateindex,
&indexes.time.dateindex_to_date,
|(di, d, ..)| (di, Timestamp::from(d)),
exit,
)?;
Ok(())
})?;
let mut height_to_timestamp_iter = indexer.vecs.block.height_to_timestamp.iter()?;
self.difficultyepoch_to_timestamp.compute_transform(
starting_indexes.difficultyepoch,
&indexes.block.difficultyepoch_to_first_height,
|(i, h, ..)| (i, height_to_timestamp_iter.get_unwrap(h)),
exit,
)?;
Ok(())
}
}
@@ -1,180 +0,0 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{StoredU64, Version};
use vecdb::{Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1};
use super::Vecs;
use crate::{
chain::{
TARGET_BLOCKS_PER_DAY, TARGET_BLOCKS_PER_DECADE, TARGET_BLOCKS_PER_MONTH,
TARGET_BLOCKS_PER_QUARTER, TARGET_BLOCKS_PER_SEMESTER, TARGET_BLOCKS_PER_WEEK,
TARGET_BLOCKS_PER_YEAR,
},
grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
indexes,
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
) -> Result<Self> {
let v0 = Version::ZERO;
let last = || VecBuilderOptions::default().add_last();
let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative();
let stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
};
let full_stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
.add_sum()
.add_cumulative()
};
let dateindex_to_block_count_target = LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.dateindex_to_dateindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DAY)),
);
let weekindex_to_block_count_target = LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.weekindex_to_weekindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_WEEK)),
);
let monthindex_to_block_count_target = LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.monthindex_to_monthindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_MONTH)),
);
let quarterindex_to_block_count_target = LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.quarterindex_to_quarterindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_QUARTER)),
);
let semesterindex_to_block_count_target = LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.semesterindex_to_semesterindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_SEMESTER)),
);
let yearindex_to_block_count_target = LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.yearindex_to_yearindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_YEAR)),
);
let decadeindex_to_block_count_target = LazyVecFrom1::init(
"block_count_target",
version + v0,
indexes.time.decadeindex_to_decadeindex.boxed_clone(),
|_, _| Some(StoredU64::from(TARGET_BLOCKS_PER_DECADE)),
);
let height_to_interval = EagerVec::forced_import(db, "interval", version + v0)?;
let height_to_vbytes = EagerVec::forced_import(db, "vbytes", version + v0)?;
Ok(Self {
dateindex_to_block_count_target,
weekindex_to_block_count_target,
monthindex_to_block_count_target,
quarterindex_to_block_count_target,
semesterindex_to_block_count_target,
yearindex_to_block_count_target,
decadeindex_to_block_count_target,
height_to_interval: height_to_interval.clone(),
height_to_24h_block_count: EagerVec::forced_import(
db,
"24h_block_count",
version + v0,
)?,
height_to_vbytes: height_to_vbytes.clone(),
indexes_to_block_count: ComputedVecsFromHeight::forced_import(
db,
"block_count",
Source::Compute,
version + v0,
indexes,
sum_cum(),
)?,
indexes_to_1w_block_count: ComputedVecsFromDateIndex::forced_import(
db,
"1w_block_count",
Source::Compute,
version + v0,
indexes,
last(),
)?,
indexes_to_1m_block_count: ComputedVecsFromDateIndex::forced_import(
db,
"1m_block_count",
Source::Compute,
version + v0,
indexes,
last(),
)?,
indexes_to_1y_block_count: ComputedVecsFromDateIndex::forced_import(
db,
"1y_block_count",
Source::Compute,
version + v0,
indexes,
last(),
)?,
indexes_to_block_interval: ComputedVecsFromHeight::forced_import(
db,
"block_interval",
Source::Vec(height_to_interval.boxed_clone()),
version + v0,
indexes,
stats(),
)?,
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
db,
"block_size",
Source::Vec(indexer.vecs.block.height_to_total_size.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?,
indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import(
db,
"block_vbytes",
Source::Vec(height_to_vbytes.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?,
indexes_to_block_weight: ComputedVecsFromHeight::forced_import(
db,
"block_weight",
Source::Vec(indexer.vecs.block.height_to_weight.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?,
// Timestamp metrics (moved from epoch)
difficultyepoch_to_timestamp: EagerVec::forced_import(db, "timestamp", version + v0)?,
timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import(
db,
"timestamp",
Source::Compute,
version + v0,
indexes,
VecBuilderOptions::default().add_first(),
)?,
})
}
}
@@ -1,37 +0,0 @@
use brk_traversable::Traversable;
use brk_types::{
DateIndex, DecadeIndex, DifficultyEpoch, Height, MonthIndex, QuarterIndex, SemesterIndex,
StoredU32, StoredU64, Timestamp, WeekIndex, Weight, YearIndex,
};
use vecdb::{EagerVec, LazyVecFrom1, PcoVec};
use crate::grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight};
/// Block-related metrics: count, interval, size, weight, vbytes, timestamps
#[derive(Clone, Traversable)]
pub struct Vecs {
pub dateindex_to_block_count_target: LazyVecFrom1<DateIndex, StoredU64, DateIndex, DateIndex>,
pub weekindex_to_block_count_target: LazyVecFrom1<WeekIndex, StoredU64, WeekIndex, WeekIndex>,
pub monthindex_to_block_count_target:
LazyVecFrom1<MonthIndex, StoredU64, MonthIndex, MonthIndex>,
pub quarterindex_to_block_count_target:
LazyVecFrom1<QuarterIndex, StoredU64, QuarterIndex, QuarterIndex>,
pub semesterindex_to_block_count_target:
LazyVecFrom1<SemesterIndex, StoredU64, SemesterIndex, SemesterIndex>,
pub yearindex_to_block_count_target: LazyVecFrom1<YearIndex, StoredU64, YearIndex, YearIndex>,
pub decadeindex_to_block_count_target:
LazyVecFrom1<DecadeIndex, StoredU64, DecadeIndex, DecadeIndex>,
pub height_to_interval: EagerVec<PcoVec<Height, Timestamp>>,
pub height_to_24h_block_count: EagerVec<PcoVec<Height, StoredU32>>,
pub height_to_vbytes: EagerVec<PcoVec<Height, StoredU64>>,
pub indexes_to_block_count: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_1w_block_count: ComputedVecsFromDateIndex<StoredU32>,
pub indexes_to_1m_block_count: ComputedVecsFromDateIndex<StoredU32>,
pub indexes_to_1y_block_count: ComputedVecsFromDateIndex<StoredU32>,
pub indexes_to_block_interval: ComputedVecsFromHeight<Timestamp>,
pub indexes_to_block_size: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_block_vbytes: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_block_weight: ComputedVecsFromHeight<Weight>,
pub difficultyepoch_to_timestamp: EagerVec<PcoVec<DifficultyEpoch, Timestamp>>,
pub timeindexes_to_timestamp: ComputedVecsFromDateIndex<Timestamp>,
}
-63
View File
@@ -1,63 +0,0 @@
use brk_error::Result;
use brk_indexer::Indexer;
use vecdb::Exit;
use crate::{indexes, price, txins, ComputeIndexes};
use super::Vecs;
impl Vecs {
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
txins: &txins::Vecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
exit: &Exit,
) -> Result<()> {
// Independent computations first
self.block.compute(indexer, indexes, starting_indexes, exit)?;
self.epoch.compute(indexes, starting_indexes, exit)?;
self.transaction.compute(indexer, indexes, txins, starting_indexes, price, exit)?;
// Coinbase depends on block and transaction
self.coinbase.compute(
indexer,
indexes,
&self.block,
&self.transaction,
starting_indexes,
price,
exit,
)?;
// Output type depends on transaction
self.output_type.compute(indexer, indexes, &self.transaction, starting_indexes, exit)?;
// Volume depends on transaction and coinbase
self.volume.compute(
indexer,
indexes,
&self.transaction,
&self.coinbase,
starting_indexes,
price,
exit,
)?;
// Mining depends on block and coinbase
self.mining.compute(
indexer,
indexes,
&self.block,
&self.coinbase,
starting_indexes,
exit,
)?;
let _lock = exit.lock();
self.db.compact()?;
Ok(())
}
}
@@ -1,16 +0,0 @@
use brk_traversable::Traversable;
use brk_types::{DifficultyEpoch, HalvingEpoch, StoredF32, StoredU32};
use crate::grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight};
/// Epoch metrics: difficulty epochs, halving epochs, and countdown to next epoch
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex<DifficultyEpoch>,
pub indexes_to_halvingepoch: ComputedVecsFromDateIndex<HalvingEpoch>,
// Countdown metrics (moved from mining)
pub indexes_to_blocks_before_next_difficulty_adjustment: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_days_before_next_difficulty_adjustment: ComputedVecsFromHeight<StoredF32>,
pub indexes_to_blocks_before_next_halving: ComputedVecsFromHeight<StoredU32>,
pub indexes_to_days_before_next_halving: ComputedVecsFromHeight<StoredF32>,
}
@@ -1,131 +0,0 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
grouped::{ComputedVecsFromHeight, Source, VecBuilderOptions},
indexes,
};
impl Vecs {
pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let v0 = Version::ZERO;
let last = || VecBuilderOptions::default().add_last();
let full_stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
.add_sum()
.add_cumulative()
};
Ok(Self {
indexes_to_p2a_count: ComputedVecsFromHeight::forced_import(
db,
"p2a_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2ms_count: ComputedVecsFromHeight::forced_import(
db,
"p2ms_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2pk33_count: ComputedVecsFromHeight::forced_import(
db,
"p2pk33_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2pk65_count: ComputedVecsFromHeight::forced_import(
db,
"p2pk65_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2pkh_count: ComputedVecsFromHeight::forced_import(
db,
"p2pkh_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2sh_count: ComputedVecsFromHeight::forced_import(
db,
"p2sh_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2tr_count: ComputedVecsFromHeight::forced_import(
db,
"p2tr_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2wpkh_count: ComputedVecsFromHeight::forced_import(
db,
"p2wpkh_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_p2wsh_count: ComputedVecsFromHeight::forced_import(
db,
"p2wsh_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_opreturn_count: ComputedVecsFromHeight::forced_import(
db,
"opreturn_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_emptyoutput_count: ComputedVecsFromHeight::forced_import(
db,
"emptyoutput_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_unknownoutput_count: ComputedVecsFromHeight::forced_import(
db,
"unknownoutput_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_exact_utxo_count: ComputedVecsFromHeight::forced_import(
db,
"exact_utxo_count",
Source::Compute,
version + v0,
indexes,
last(),
)?,
})
}
}
@@ -1,141 +0,0 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{FeeRate, Sats, StoredU64, TxVersion};
use vecdb::{Exit, TypedVecIterator, unlikely};
use super::Vecs;
use crate::{ComputeIndexes, grouped::ComputedVecsFromHeight, indexes, price, txins};
impl Vecs {
pub fn compute(
&mut self,
indexer: &Indexer,
indexes: &indexes::Vecs,
txins: &txins::Vecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
exit: &Exit,
) -> Result<()> {
self.indexes_to_tx_count
.compute_all(indexes, starting_indexes, exit, |v| {
v.compute_count_from_indexes(
starting_indexes.height,
&indexer.vecs.tx.height_to_first_txindex,
&indexer.vecs.tx.txindex_to_txid,
exit,
)?;
Ok(())
})?;
self.indexes_to_input_count.compute_rest(
indexer,
indexes,
starting_indexes,
exit,
Some(&indexes.transaction.txindex_to_input_count),
)?;
self.indexes_to_output_count.compute_rest(
indexer,
indexes,
starting_indexes,
exit,
Some(&indexes.transaction.txindex_to_output_count),
)?;
let compute_indexes_to_tx_vany =
|indexes_to_tx_vany: &mut ComputedVecsFromHeight<StoredU64>, txversion: TxVersion| {
let mut txindex_to_txversion_iter = indexer.vecs.tx.txindex_to_txversion.iter()?;
indexes_to_tx_vany.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_filtered_count_from_indexes(
starting_indexes.height,
&indexer.vecs.tx.height_to_first_txindex,
&indexer.vecs.tx.txindex_to_txid,
|txindex| {
let v = txindex_to_txversion_iter.get_unwrap(txindex);
v == txversion
},
exit,
)?;
Ok(())
})
};
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v1, TxVersion::ONE)?;
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v2, TxVersion::TWO)?;
compute_indexes_to_tx_vany(&mut self.indexes_to_tx_v3, TxVersion::THREE)?;
self.txindex_to_input_value.compute_sum_from_indexes(
starting_indexes.txindex,
&indexer.vecs.tx.txindex_to_first_txinindex,
&indexes.transaction.txindex_to_input_count,
&txins.txinindex_to_value,
exit,
)?;
self.txindex_to_output_value.compute_sum_from_indexes(
starting_indexes.txindex,
&indexer.vecs.tx.txindex_to_first_txoutindex,
&indexes.transaction.txindex_to_output_count,
&indexer.vecs.txout.txoutindex_to_value,
exit,
)?;
self.txindex_to_fee.compute_transform2(
starting_indexes.txindex,
&self.txindex_to_input_value,
&self.txindex_to_output_value,
|(i, input, output, ..)| {
let fee = if unlikely(input.is_max()) {
Sats::ZERO
} else {
input - output
};
(i, fee)
},
exit,
)?;
self.txindex_to_fee_rate.compute_transform2(
starting_indexes.txindex,
&self.txindex_to_fee,
&self.txindex_to_vsize,
|(txindex, fee, vsize, ..)| (txindex, FeeRate::from((fee, vsize))),
exit,
)?;
self.indexes_to_fee.compute_rest(
indexer,
indexes,
starting_indexes,
exit,
Some(&self.txindex_to_fee),
price,
)?;
self.indexes_to_fee_rate.compute_rest(
indexer,
indexes,
starting_indexes,
exit,
Some(&self.txindex_to_fee_rate),
)?;
self.indexes_to_tx_weight.compute_rest(
indexer,
indexes,
starting_indexes,
exit,
Some(&self.txindex_to_weight),
)?;
self.indexes_to_tx_vsize.compute_rest(
indexer,
indexes,
starting_indexes,
exit,
Some(&self.txindex_to_vsize),
)?;
Ok(())
}
}
@@ -1,180 +0,0 @@
use brk_error::Result;
use brk_indexer::Indexer;
use brk_types::{StoredBool, TxIndex, VSize, Version, Weight};
use vecdb::{
Database, EagerVec, ImportableVec, IterableCloneableVec, LazyVecFrom1, LazyVecFrom2, VecIndex,
};
use super::Vecs;
use crate::{
grouped::{
ComputedValueVecsFromTxindex, ComputedVecsFromHeight, ComputedVecsFromTxindex, Source,
VecBuilderOptions,
},
indexes, price,
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexer: &Indexer,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let v0 = Version::ZERO;
let stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
};
let full_stats = || {
VecBuilderOptions::default()
.add_average()
.add_minmax()
.add_percentiles()
.add_sum()
.add_cumulative()
};
let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative();
let txindex_to_weight = LazyVecFrom2::init(
"weight",
version + v0,
indexer.vecs.tx.txindex_to_base_size.boxed_clone(),
indexer.vecs.tx.txindex_to_total_size.boxed_clone(),
|index: TxIndex, txindex_to_base_size_iter, txindex_to_total_size_iter| {
let index = index.to_usize();
txindex_to_base_size_iter.get_at(index).map(|base_size| {
let total_size = txindex_to_total_size_iter.get_at_unwrap(index);
let wu = usize::from(base_size) * 3 + usize::from(total_size);
Weight::from(bitcoin::Weight::from_wu_usize(wu))
})
},
);
let txindex_to_vsize = LazyVecFrom1::init(
"vsize",
version + v0,
txindex_to_weight.boxed_clone(),
|index: TxIndex, iter| iter.get(index).map(VSize::from),
);
let txindex_to_is_coinbase = LazyVecFrom2::init(
"is_coinbase",
version + v0,
indexer.vecs.tx.txindex_to_height.boxed_clone(),
indexer.vecs.tx.height_to_first_txindex.boxed_clone(),
|index: TxIndex, txindex_to_height_iter, height_to_first_txindex_iter| {
txindex_to_height_iter.get(index).map(|height| {
let txindex = height_to_first_txindex_iter.get_unwrap(height);
StoredBool::from(index == txindex)
})
},
);
let txindex_to_input_value = EagerVec::forced_import(db, "input_value", version + v0)?;
let txindex_to_output_value = EagerVec::forced_import(db, "output_value", version + v0)?;
let txindex_to_fee = EagerVec::forced_import(db, "fee", version + v0)?;
let txindex_to_fee_rate = EagerVec::forced_import(db, "fee_rate", version + v0)?;
Ok(Self {
indexes_to_tx_count: ComputedVecsFromHeight::forced_import(
db,
"tx_count",
Source::Compute,
version + v0,
indexes,
full_stats(),
)?,
indexes_to_tx_v1: ComputedVecsFromHeight::forced_import(
db,
"tx_v1",
Source::Compute,
version + v0,
indexes,
sum_cum(),
)?,
indexes_to_tx_v2: ComputedVecsFromHeight::forced_import(
db,
"tx_v2",
Source::Compute,
version + v0,
indexes,
sum_cum(),
)?,
indexes_to_tx_v3: ComputedVecsFromHeight::forced_import(
db,
"tx_v3",
Source::Compute,
version + v0,
indexes,
sum_cum(),
)?,
indexes_to_tx_vsize: ComputedVecsFromTxindex::forced_import(
db,
"tx_vsize",
Source::Vec(txindex_to_vsize.boxed_clone()),
version + v0,
indexes,
stats(),
)?,
indexes_to_tx_weight: ComputedVecsFromTxindex::forced_import(
db,
"tx_weight",
Source::Vec(txindex_to_weight.boxed_clone()),
version + v0,
indexes,
stats(),
)?,
indexes_to_input_count: ComputedVecsFromTxindex::forced_import(
db,
"input_count",
Source::Vec(indexes.transaction.txindex_to_input_count.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?,
indexes_to_output_count: ComputedVecsFromTxindex::forced_import(
db,
"output_count",
Source::Vec(indexes.transaction.txindex_to_output_count.boxed_clone()),
version + v0,
indexes,
full_stats(),
)?,
txindex_to_is_coinbase,
txindex_to_vsize,
txindex_to_weight,
txindex_to_input_value,
txindex_to_output_value,
txindex_to_fee: txindex_to_fee.clone(),
txindex_to_fee_rate: txindex_to_fee_rate.clone(),
indexes_to_fee: ComputedValueVecsFromTxindex::forced_import(
db,
"fee",
indexer,
indexes,
Source::Vec(txindex_to_fee.boxed_clone()),
version + v0,
price,
VecBuilderOptions::default()
.add_sum()
.add_cumulative()
.add_percentiles()
.add_minmax()
.add_average(),
)?,
indexes_to_fee_rate: ComputedVecsFromTxindex::forced_import(
db,
"fee_rate",
Source::Vec(txindex_to_fee_rate.boxed_clone()),
version + v0,
indexes,
stats(),
)?,
})
}
}
@@ -1,28 +0,0 @@
use brk_traversable::Traversable;
use brk_types::{FeeRate, Height, Sats, StoredBool, StoredU32, StoredU64, TxIndex, VSize, Weight};
use vecdb::{EagerVec, LazyVecFrom1, LazyVecFrom2, PcoVec};
use crate::grouped::{ComputedValueVecsFromTxindex, ComputedVecsFromHeight, ComputedVecsFromTxindex};
/// Transaction-related metrics
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_tx_count: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_v1: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_v2: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_v3: ComputedVecsFromHeight<StoredU64>,
pub indexes_to_tx_vsize: ComputedVecsFromTxindex<VSize>,
pub indexes_to_tx_weight: ComputedVecsFromTxindex<Weight>,
pub indexes_to_input_count: ComputedVecsFromTxindex<StoredU64>,
pub indexes_to_output_count: ComputedVecsFromTxindex<StoredU64>,
pub txindex_to_is_coinbase: LazyVecFrom2<TxIndex, StoredBool, TxIndex, Height, Height, TxIndex>,
pub txindex_to_vsize: LazyVecFrom1<TxIndex, VSize, TxIndex, Weight>,
pub txindex_to_weight: LazyVecFrom2<TxIndex, Weight, TxIndex, StoredU32, TxIndex, StoredU32>,
/// Value == 0 when Coinbase
pub txindex_to_input_value: EagerVec<PcoVec<TxIndex, Sats>>,
pub txindex_to_output_value: EagerVec<PcoVec<TxIndex, Sats>>,
pub txindex_to_fee: EagerVec<PcoVec<TxIndex, Sats>>,
pub txindex_to_fee_rate: EagerVec<PcoVec<TxIndex, FeeRate>>,
pub indexes_to_fee: ComputedValueVecsFromTxindex,
pub indexes_to_fee_rate: ComputedVecsFromTxindex<FeeRate>,
}
-588
View File
@@ -1,588 +0,0 @@
use std::path::Path;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Bitcoin, CheckedSub, Dollars, StoredF32, StoredF64, Version};
use vecdb::{Database, Exit, PAGE_SIZE, TypedVecIterator};
use crate::{grouped::ComputedVecsFromDateIndex, utils::OptionExt};
use super::{
ComputeIndexes, chain,
grouped::{
ComputedRatioVecsFromDateIndex, ComputedValueVecsFromHeight, ComputedVecsFromHeight,
Source, VecBuilderOptions,
},
indexes, price, stateful,
};
pub const DB_NAME: &str = "cointime";
#[derive(Clone, Traversable)]
pub struct Vecs {
db: Database,
pub indexes_to_coinblocks_created: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_coinblocks_stored: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_liveliness: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_vaultedness: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_activity_to_vaultedness_ratio: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_vaulted_supply: ComputedValueVecsFromHeight,
pub indexes_to_active_supply: ComputedValueVecsFromHeight,
pub indexes_to_thermo_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_investor_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_vaulted_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_active_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_vaulted_price: ComputedVecsFromHeight<Dollars>,
pub indexes_to_vaulted_price_ratio: ComputedRatioVecsFromDateIndex,
pub indexes_to_active_price: ComputedVecsFromHeight<Dollars>,
pub indexes_to_active_price_ratio: ComputedRatioVecsFromDateIndex,
pub indexes_to_true_market_mean: ComputedVecsFromHeight<Dollars>,
pub indexes_to_true_market_mean_ratio: ComputedRatioVecsFromDateIndex,
pub indexes_to_cointime_value_destroyed: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_cointime_value_created: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_cointime_value_stored: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_cointime_price: ComputedVecsFromHeight<Dollars>,
pub indexes_to_cointime_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_cointime_price_ratio: ComputedRatioVecsFromDateIndex,
pub indexes_to_cointime_adj_inflation_rate: ComputedVecsFromDateIndex<StoredF32>,
pub indexes_to_cointime_adj_tx_btc_velocity: ComputedVecsFromDateIndex<StoredF64>,
pub indexes_to_cointime_adj_tx_usd_velocity: ComputedVecsFromDateIndex<StoredF64>,
// pub indexes_to_thermo_cap_rel_to_investor_cap: ComputedValueVecsFromHeight,
}
impl Vecs {
pub fn forced_import(
parent_path: &Path,
parent_version: Version,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let db = Database::open(&parent_path.join(DB_NAME))?;
db.set_min_len(PAGE_SIZE * 1_000_000)?;
let compute_dollars = price.is_some();
let v0 = parent_version;
let v1 = parent_version + Version::ONE;
let last = || VecBuilderOptions::default().add_last();
let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative();
macro_rules! computed_h {
($name:expr, $opts:expr) => {
ComputedVecsFromHeight::forced_import(
&db,
$name,
Source::Compute,
v0,
indexes,
$opts,
)?
};
($name:expr, $v:expr, $opts:expr) => {
ComputedVecsFromHeight::forced_import(
&db,
$name,
Source::Compute,
$v,
indexes,
$opts,
)?
};
}
macro_rules! computed_di {
($name:expr, $opts:expr) => {
ComputedVecsFromDateIndex::forced_import(
&db,
$name,
Source::Compute,
v0,
indexes,
$opts,
)?
};
}
macro_rules! ratio_di {
($name:expr, $source:expr) => {
ComputedRatioVecsFromDateIndex::forced_import(
&db,
$name,
Some($source),
v0,
indexes,
true,
price,
)?
};
}
macro_rules! value_h {
($name:expr) => {
ComputedValueVecsFromHeight::forced_import(
&db,
$name,
Source::Compute,
v1,
last(),
compute_dollars,
indexes,
)?
};
}
// Extract price vecs before struct literal so they can be used as sources for ratios
let indexes_to_vaulted_price = computed_h!("vaulted_price", last());
let indexes_to_active_price = computed_h!("active_price", last());
let indexes_to_true_market_mean = computed_h!("true_market_mean", last());
let indexes_to_cointime_price = computed_h!("cointime_price", last());
let this = Self {
indexes_to_coinblocks_created: computed_h!("coinblocks_created", sum_cum()),
indexes_to_coinblocks_stored: computed_h!("coinblocks_stored", sum_cum()),
indexes_to_liveliness: computed_h!("liveliness", last()),
indexes_to_vaultedness: computed_h!("vaultedness", last()),
indexes_to_activity_to_vaultedness_ratio: computed_h!(
"activity_to_vaultedness_ratio",
last()
),
indexes_to_vaulted_supply: value_h!("vaulted_supply"),
indexes_to_active_supply: value_h!("active_supply"),
indexes_to_thermo_cap: computed_h!("thermo_cap", v1, last()),
indexes_to_investor_cap: computed_h!("investor_cap", v1, last()),
indexes_to_vaulted_cap: computed_h!("vaulted_cap", v1, last()),
indexes_to_active_cap: computed_h!("active_cap", v1, last()),
indexes_to_vaulted_price_ratio: ratio_di!("vaulted_price", &indexes_to_vaulted_price),
indexes_to_vaulted_price,
indexes_to_active_price_ratio: ratio_di!("active_price", &indexes_to_active_price),
indexes_to_active_price,
indexes_to_true_market_mean_ratio: ratio_di!(
"true_market_mean",
&indexes_to_true_market_mean
),
indexes_to_true_market_mean,
indexes_to_cointime_value_destroyed: computed_h!("cointime_value_destroyed", sum_cum()),
indexes_to_cointime_value_created: computed_h!("cointime_value_created", sum_cum()),
indexes_to_cointime_value_stored: computed_h!("cointime_value_stored", sum_cum()),
indexes_to_cointime_cap: computed_h!("cointime_cap", last()),
indexes_to_cointime_price_ratio: ratio_di!(
"cointime_price",
&indexes_to_cointime_price
),
indexes_to_cointime_price,
indexes_to_cointime_adj_inflation_rate: computed_di!(
"cointime_adj_inflation_rate",
last()
),
indexes_to_cointime_adj_tx_btc_velocity: computed_di!(
"cointime_adj_tx_btc_velocity",
last()
),
indexes_to_cointime_adj_tx_usd_velocity: computed_di!(
"cointime_adj_tx_usd_velocity",
last()
),
db,
};
this.db.retain_regions(
this.iter_any_exportable()
.flat_map(|v| v.region_names())
.collect(),
)?;
this.db.compact()?;
Ok(this)
}
#[allow(clippy::too_many_arguments)]
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
chain: &chain::Vecs,
stateful: &stateful::Vecs,
exit: &Exit,
) -> Result<()> {
self.compute_(indexes, starting_indexes, price, chain, stateful, exit)?;
let _lock = exit.lock();
self.db.compact()?;
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn compute_(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
chain: &chain::Vecs,
stateful: &stateful::Vecs,
exit: &Exit,
) -> Result<()> {
let circulating_supply = &stateful.utxo_cohorts.all.metrics.supply.height_to_supply;
self.indexes_to_coinblocks_created
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
circulating_supply,
|(i, v, ..)| (i, StoredF64::from(Bitcoin::from(v))),
exit,
)?;
Ok(())
})?;
let indexes_to_coinblocks_destroyed = &stateful
.utxo_cohorts
.all
.metrics
.activity
.indexes_to_coinblocks_destroyed;
self.indexes_to_coinblocks_stored
.compute_all(indexes, starting_indexes, exit, |vec| {
let mut coinblocks_destroyed_iter = indexes_to_coinblocks_destroyed
.height
.as_ref()
.unwrap()
.into_iter();
vec.compute_transform(
starting_indexes.height,
self.indexes_to_coinblocks_created.height.u(),
|(i, created, ..)| {
let destroyed = coinblocks_destroyed_iter.get_unwrap(i);
(i, created.checked_sub(destroyed).unwrap())
},
exit,
)?;
Ok(())
})?;
self.indexes_to_liveliness
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
indexes_to_coinblocks_destroyed
.height_extra
.unwrap_cumulative(),
self.indexes_to_coinblocks_created
.height_extra
.unwrap_cumulative(),
exit,
)?;
Ok(())
})?;
let liveliness = &self.indexes_to_liveliness;
self.indexes_to_vaultedness
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
liveliness.height.u(),
|(i, v, ..)| (i, StoredF64::from(1.0).checked_sub(v).unwrap()),
exit,
)?;
Ok(())
})?;
let vaultedness = &self.indexes_to_vaultedness;
self.indexes_to_activity_to_vaultedness_ratio.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_divide(
starting_indexes.height,
liveliness.height.u(),
vaultedness.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_vaulted_supply.compute_all(
indexes,
price,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
circulating_supply,
vaultedness.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_active_supply.compute_all(
indexes,
price,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
circulating_supply,
liveliness.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_cointime_adj_inflation_rate
.compute_all(starting_indexes, exit, |v| {
v.compute_multiply(
starting_indexes.dateindex,
self.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
chain.coinbase.indexes_to_inflation_rate.dateindex.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_cointime_adj_tx_btc_velocity
.compute_all(starting_indexes, exit, |v| {
v.compute_multiply(
starting_indexes.dateindex,
self.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
chain.volume.indexes_to_tx_btc_velocity.dateindex.u(),
exit,
)?;
Ok(())
})?;
if let Some(price) = price {
let realized_cap = &stateful
.utxo_cohorts
.all
.metrics
.realized
.u()
.height_to_realized_cap;
let realized_price = stateful
.utxo_cohorts
.all
.metrics
.realized
.u()
.indexes_to_realized_price
.height
.u();
self.indexes_to_thermo_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
chain
.coinbase.indexes_to_subsidy
.dollars
.as_ref()
.unwrap()
.height_extra
.unwrap_cumulative(),
|(i, v, ..)| (i, v),
exit,
)?;
Ok(())
})?;
self.indexes_to_investor_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_subtract(
starting_indexes.height,
realized_cap,
self.indexes_to_thermo_cap.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_vaulted_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
realized_cap,
self.indexes_to_vaultedness.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_active_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
realized_cap,
self.indexes_to_liveliness.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_vaulted_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
realized_price,
self.indexes_to_vaultedness.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_vaulted_price_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_vaulted_price.dateindex.unwrap_last()),
)?;
self.indexes_to_active_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
realized_price,
self.indexes_to_liveliness.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_active_price_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_active_price.dateindex.unwrap_last()),
)?;
self.indexes_to_true_market_mean.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_divide(
starting_indexes.height,
self.indexes_to_investor_cap.height.u(),
&self.indexes_to_active_supply.bitcoin.height,
exit,
)?;
Ok(())
},
)?;
self.indexes_to_true_market_mean_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_true_market_mean.dateindex.unwrap_last()),
)?;
self.indexes_to_cointime_value_destroyed.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
// TODO: Another example when the callback should be applied to each index, instead of to base then merging from more granular to less
// The price taken won't be correct for time based indexes
vec.compute_multiply(
starting_indexes.height,
&price.chainindexes_to_price_close.height,
indexes_to_coinblocks_destroyed.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_cointime_value_created.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
&price.chainindexes_to_price_close.height,
self.indexes_to_coinblocks_created.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_cointime_value_stored.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
&price.chainindexes_to_price_close.height,
self.indexes_to_coinblocks_stored.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_cointime_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
self.indexes_to_cointime_value_destroyed
.height_extra
.unwrap_cumulative(),
self.indexes_to_coinblocks_stored
.height_extra
.unwrap_cumulative(),
exit,
)?;
Ok(())
})?;
self.indexes_to_cointime_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
self.indexes_to_cointime_price.height.u(),
circulating_supply,
exit,
)?;
Ok(())
})?;
self.indexes_to_cointime_price_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_cointime_price.dateindex.unwrap_last()),
)?;
self.indexes_to_cointime_adj_tx_usd_velocity.compute_all(
starting_indexes,
exit,
|v| {
v.compute_multiply(
starting_indexes.dateindex,
self.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
chain.volume.indexes_to_tx_usd_velocity.dateindex.u(),
exit,
)?;
Ok(())
},
)?;
}
Ok(())
}
}
@@ -0,0 +1,98 @@
use brk_error::Result;
use brk_types::{Bitcoin, CheckedSub, StoredF64};
use vecdb::{Exit, TypedVecIterator};
use super::Vecs;
use crate::{distribution, indexes, utils::OptionExt, ComputeIndexes};
impl Vecs {
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
distribution: &distribution::Vecs,
exit: &Exit,
) -> Result<()> {
let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.height_to_supply;
self.indexes_to_coinblocks_created
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
circulating_supply,
|(i, v, ..)| (i, StoredF64::from(Bitcoin::from(v))),
exit,
)?;
Ok(())
})?;
let indexes_to_coinblocks_destroyed = &distribution
.utxo_cohorts
.all
.metrics
.activity
.indexes_to_coinblocks_destroyed;
self.indexes_to_coinblocks_stored
.compute_all(indexes, starting_indexes, exit, |vec| {
let mut coinblocks_destroyed_iter = indexes_to_coinblocks_destroyed
.height
.as_ref()
.unwrap()
.into_iter();
vec.compute_transform(
starting_indexes.height,
self.indexes_to_coinblocks_created.height.u(),
|(i, created, ..)| {
let destroyed = coinblocks_destroyed_iter.get_unwrap(i);
(i, created.checked_sub(destroyed).unwrap())
},
exit,
)?;
Ok(())
})?;
self.indexes_to_liveliness
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
indexes_to_coinblocks_destroyed
.height_extra
.unwrap_cumulative(),
self.indexes_to_coinblocks_created
.height_extra
.unwrap_cumulative(),
exit,
)?;
Ok(())
})?;
self.indexes_to_vaultedness
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
self.indexes_to_liveliness.height.u(),
|(i, v, ..)| (i, StoredF64::from(1.0).checked_sub(v).unwrap()),
exit,
)?;
Ok(())
})?;
self.indexes_to_activity_to_vaultedness_ratio.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_divide(
starting_indexes.height,
self.indexes_to_liveliness.height.u(),
self.indexes_to_vaultedness.height.u(),
exit,
)?;
Ok(())
},
)?;
Ok(())
}
}
@@ -0,0 +1,40 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let last = || VecBuilderOptions::default().add_last();
let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative();
macro_rules! computed_h {
($name:expr, $opts:expr) => {
ComputedVecsFromHeight::forced_import(
db,
$name,
Source::Compute,
version,
indexes,
$opts,
)?
};
}
Ok(Self {
indexes_to_coinblocks_created: computed_h!("coinblocks_created", sum_cum()),
indexes_to_coinblocks_stored: computed_h!("coinblocks_stored", sum_cum()),
indexes_to_liveliness: computed_h!("liveliness", last()),
indexes_to_vaultedness: computed_h!("vaultedness", last()),
indexes_to_activity_to_vaultedness_ratio: computed_h!(
"activity_to_vaultedness_ratio",
last()
),
})
}
}
@@ -0,0 +1,5 @@
mod compute;
mod import;
mod vecs;
pub use vecs::Vecs;
@@ -0,0 +1,13 @@
use brk_traversable::Traversable;
use brk_types::StoredF64;
use crate::internal::ComputedVecsFromHeight;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_coinblocks_created: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_coinblocks_stored: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_liveliness: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_vaultedness: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_activity_to_vaultedness_ratio: ComputedVecsFromHeight<StoredF64>,
}
@@ -0,0 +1,66 @@
use brk_error::Result;
use vecdb::Exit;
use super::Vecs;
use super::super::activity;
use crate::{supply, ComputeIndexes, utils::OptionExt};
impl Vecs {
pub fn compute(
&mut self,
starting_indexes: &ComputeIndexes,
supply: &supply::Vecs,
activity: &activity::Vecs,
has_price: bool,
exit: &Exit,
) -> Result<()> {
self.indexes_to_cointime_adj_inflation_rate
.compute_all(starting_indexes, exit, |v| {
v.compute_multiply(
starting_indexes.dateindex,
activity
.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
supply.inflation.indexes.dateindex.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_cointime_adj_tx_btc_velocity
.compute_all(starting_indexes, exit, |v| {
v.compute_multiply(
starting_indexes.dateindex,
activity
.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
supply.velocity.indexes_to_btc.dateindex.u(),
exit,
)?;
Ok(())
})?;
if has_price {
self.indexes_to_cointime_adj_tx_usd_velocity.compute_all(
starting_indexes,
exit,
|v| {
v.compute_multiply(
starting_indexes.dateindex,
activity
.indexes_to_activity_to_vaultedness_ratio
.dateindex
.unwrap_last(),
supply.velocity.indexes_to_usd.u().dateindex.u(),
exit,
)?;
Ok(())
},
)?;
}
Ok(())
}
}
@@ -0,0 +1,34 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromDateIndex, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let last = || VecBuilderOptions::default().add_last();
macro_rules! computed_di {
($name:expr) => {
ComputedVecsFromDateIndex::forced_import(
db,
$name,
Source::Compute,
version,
indexes,
last(),
)?
};
}
Ok(Self {
indexes_to_cointime_adj_inflation_rate: computed_di!("cointime_adj_inflation_rate"),
indexes_to_cointime_adj_tx_btc_velocity: computed_di!("cointime_adj_tx_btc_velocity"),
indexes_to_cointime_adj_tx_usd_velocity: computed_di!("cointime_adj_tx_usd_velocity"),
})
}
}
@@ -0,0 +1,5 @@
mod compute;
mod import;
mod vecs;
pub use vecs::Vecs;
@@ -0,0 +1,11 @@
use brk_traversable::Traversable;
use brk_types::{StoredF32, StoredF64};
use crate::internal::ComputedVecsFromDateIndex;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_cointime_adj_inflation_rate: ComputedVecsFromDateIndex<StoredF32>,
pub indexes_to_cointime_adj_tx_btc_velocity: ComputedVecsFromDateIndex<StoredF64>,
pub indexes_to_cointime_adj_tx_usd_velocity: ComputedVecsFromDateIndex<StoredF64>,
}
@@ -0,0 +1,115 @@
use brk_error::Result;
use brk_types::Dollars;
use vecdb::Exit;
use super::super::{activity, value};
use super::Vecs;
use crate::{ComputeIndexes, blocks, distribution, indexes, utils::OptionExt};
impl Vecs {
#[allow(clippy::too_many_arguments)]
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
blocks: &blocks::Vecs,
distribution: &distribution::Vecs,
activity: &activity::Vecs,
value: &value::Vecs,
exit: &Exit,
) -> Result<()> {
let realized_cap = &distribution
.utxo_cohorts
.all
.metrics
.realized
.u()
.height_to_realized_cap;
let circulating_supply = &distribution
.utxo_cohorts
.all
.metrics
.supply
.height_to_supply_value
.bitcoin;
self.indexes_to_thermo_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform(
starting_indexes.height,
blocks
.rewards
.indexes_to_subsidy
.dollars
.as_ref()
.unwrap()
.height_extra
.unwrap_cumulative(),
|(i, v, ..)| (i, v),
exit,
)?;
Ok(())
})?;
self.indexes_to_investor_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_subtract(
starting_indexes.height,
realized_cap,
self.indexes_to_thermo_cap.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_vaulted_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
realized_cap,
activity.indexes_to_vaultedness.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_active_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
realized_cap,
activity.indexes_to_liveliness.height.u(),
exit,
)?;
Ok(())
})?;
// cointime_cap = (cointime_value_destroyed_cumulative * circulating_supply) / coinblocks_stored_cumulative
self.indexes_to_cointime_cap
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_transform3(
starting_indexes.height,
value
.indexes_to_cointime_value_destroyed
.height_extra
.unwrap_cumulative(),
circulating_supply,
activity
.indexes_to_coinblocks_stored
.height_extra
.unwrap_cumulative(),
|(i, destroyed, supply, stored, ..)| {
let destroyed: f64 = *destroyed;
let supply: f64 = supply.into();
let stored: f64 = *stored;
(i, Dollars::from(destroyed * supply / stored))
},
exit,
)?;
Ok(())
})?;
Ok(())
}
}
@@ -0,0 +1,36 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let last = || VecBuilderOptions::default().add_last();
macro_rules! computed_h {
($name:expr) => {
ComputedVecsFromHeight::forced_import(
db,
$name,
Source::Compute,
version,
indexes,
last(),
)?
};
}
Ok(Self {
indexes_to_thermo_cap: computed_h!("thermo_cap"),
indexes_to_investor_cap: computed_h!("investor_cap"),
indexes_to_vaulted_cap: computed_h!("vaulted_cap"),
indexes_to_active_cap: computed_h!("active_cap"),
indexes_to_cointime_cap: computed_h!("cointime_cap"),
})
}
}
@@ -0,0 +1,5 @@
mod compute;
mod import;
mod vecs;
pub use vecs::Vecs;
@@ -0,0 +1,13 @@
use brk_traversable::Traversable;
use brk_types::Dollars;
use crate::internal::ComputedVecsFromHeight;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_thermo_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_investor_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_vaulted_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_active_cap: ComputedVecsFromHeight<Dollars>,
pub indexes_to_cointime_cap: ComputedVecsFromHeight<Dollars>,
}
@@ -0,0 +1,82 @@
use brk_error::Result;
use vecdb::Exit;
use super::Vecs;
use crate::{blocks, distribution, indexes, price, supply, ComputeIndexes};
impl Vecs {
#[allow(clippy::too_many_arguments)]
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
blocks: &blocks::Vecs,
supply_vecs: &supply::Vecs,
distribution: &distribution::Vecs,
exit: &Exit,
) -> Result<()> {
// Activity computes first (liveliness, vaultedness, etc.)
self.activity
.compute(indexes, starting_indexes, distribution, exit)?;
// Supply computes next (depends on activity)
self.supply.compute(
indexes,
starting_indexes,
price,
distribution,
&self.activity,
exit,
)?;
// Adjusted velocity metrics (BTC) - can compute without price
self.adjusted.compute(
starting_indexes,
supply_vecs,
&self.activity,
price.is_some(),
exit,
)?;
// Price-dependent metrics
if let Some(price) = price {
// Value computes (cointime value destroyed/created/stored)
self.value.compute(
indexes,
starting_indexes,
price,
distribution,
&self.activity,
exit,
)?;
// Cap computes (thermo, investor, vaulted, active, cointime caps)
self.cap.compute(
indexes,
starting_indexes,
blocks,
distribution,
&self.activity,
&self.value,
exit,
)?;
// Pricing computes (all prices derived from caps)
self.pricing.compute(
indexes,
starting_indexes,
price,
distribution,
&self.activity,
&self.supply,
&self.cap,
exit,
)?;
}
let _lock = exit.lock();
self.db.compact()?;
Ok(())
}
}
@@ -0,0 +1,53 @@
use std::path::Path;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::Version;
use vecdb::{Database, PAGE_SIZE};
use super::{
ActivityVecs, AdjustedVecs, CapVecs, PricingVecs, SupplyVecs, ValueVecs, Vecs, DB_NAME,
};
use crate::{indexes, price};
impl Vecs {
pub fn forced_import(
parent_path: &Path,
parent_version: Version,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let db = Database::open(&parent_path.join(DB_NAME))?;
db.set_min_len(PAGE_SIZE * 1_000_000)?;
let compute_dollars = price.is_some();
let v0 = parent_version;
let v1 = parent_version + Version::ONE;
let activity = ActivityVecs::forced_import(&db, v0, indexes)?;
let supply = SupplyVecs::forced_import(&db, v1, indexes, compute_dollars)?;
let value = ValueVecs::forced_import(&db, v1, indexes)?;
let cap = CapVecs::forced_import(&db, v1, indexes)?;
let pricing = PricingVecs::forced_import(&db, v0, indexes, price)?;
let adjusted = AdjustedVecs::forced_import(&db, v0, indexes)?;
let this = Self {
db,
activity,
supply,
value,
cap,
pricing,
adjusted,
};
this.db.retain_regions(
this.iter_any_exportable()
.flat_map(|v| v.region_names())
.collect(),
)?;
this.db.compact()?;
Ok(this)
}
}
+34
View File
@@ -0,0 +1,34 @@
pub mod activity;
pub mod adjusted;
pub mod cap;
pub mod pricing;
pub mod supply;
pub mod value;
mod compute;
mod import;
use brk_traversable::Traversable;
use vecdb::Database;
pub use activity::Vecs as ActivityVecs;
pub use adjusted::Vecs as AdjustedVecs;
pub use cap::Vecs as CapVecs;
pub use pricing::Vecs as PricingVecs;
pub use supply::Vecs as SupplyVecs;
pub use value::Vecs as ValueVecs;
pub const DB_NAME: &str = "cointime";
#[derive(Clone, Traversable)]
pub struct Vecs {
#[traversable(skip)]
pub(crate) db: Database,
pub activity: ActivityVecs,
pub supply: SupplyVecs,
pub value: ValueVecs,
pub cap: CapVecs,
pub pricing: PricingVecs,
pub adjusted: AdjustedVecs,
}
@@ -0,0 +1,111 @@
use brk_error::Result;
use vecdb::Exit;
use super::super::{activity, cap, supply};
use super::Vecs;
use crate::{distribution, indexes, price, utils::OptionExt, ComputeIndexes};
impl Vecs {
#[allow(clippy::too_many_arguments)]
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
price: &price::Vecs,
distribution: &distribution::Vecs,
activity: &activity::Vecs,
supply: &supply::Vecs,
cap: &cap::Vecs,
exit: &Exit,
) -> Result<()> {
let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.height_to_supply_value.bitcoin;
let realized_price = distribution
.utxo_cohorts
.all
.metrics
.realized
.u()
.indexes_to_realized_price
.height
.u();
self.indexes_to_vaulted_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
realized_price,
activity.indexes_to_vaultedness.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_vaulted_price_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_vaulted_price.dateindex.unwrap_last()),
)?;
self.indexes_to_active_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_multiply(
starting_indexes.height,
realized_price,
activity.indexes_to_liveliness.height.u(),
exit,
)?;
Ok(())
})?;
self.indexes_to_active_price_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_active_price.dateindex.unwrap_last()),
)?;
self.indexes_to_true_market_mean.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_divide(
starting_indexes.height,
cap.indexes_to_investor_cap.height.u(),
&supply.indexes_to_active_supply.bitcoin.height,
exit,
)?;
Ok(())
},
)?;
self.indexes_to_true_market_mean_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_true_market_mean.dateindex.unwrap_last()),
)?;
// cointime_price = cointime_cap / circulating_supply
self.indexes_to_cointime_price
.compute_all(indexes, starting_indexes, exit, |vec| {
vec.compute_divide(
starting_indexes.height,
cap.indexes_to_cointime_cap.height.u(),
circulating_supply,
exit,
)?;
Ok(())
})?;
self.indexes_to_cointime_price_ratio.compute_rest(
price,
starting_indexes,
exit,
Some(self.indexes_to_cointime_price.dateindex.unwrap_last()),
)?;
Ok(())
}
}
@@ -0,0 +1,70 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
indexes, price,
internal::{ComputedRatioVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
) -> Result<Self> {
let last = || VecBuilderOptions::default().add_last();
macro_rules! computed_h {
($name:expr) => {
ComputedVecsFromHeight::forced_import(
db,
$name,
Source::Compute,
version,
indexes,
last(),
)?
};
}
// Extract price vecs before struct literal so they can be used as sources for ratios
let indexes_to_vaulted_price = computed_h!("vaulted_price");
let indexes_to_active_price = computed_h!("active_price");
let indexes_to_true_market_mean = computed_h!("true_market_mean");
let indexes_to_cointime_price = computed_h!("cointime_price");
macro_rules! ratio_di {
($name:expr, $source:expr) => {
ComputedRatioVecsFromDateIndex::forced_import(
db,
$name,
Some($source),
version,
indexes,
true,
price,
)?
};
}
Ok(Self {
indexes_to_vaulted_price_ratio: ratio_di!("vaulted_price", &indexes_to_vaulted_price),
indexes_to_vaulted_price,
indexes_to_active_price_ratio: ratio_di!("active_price", &indexes_to_active_price),
indexes_to_active_price,
indexes_to_true_market_mean_ratio: ratio_di!(
"true_market_mean",
&indexes_to_true_market_mean
),
indexes_to_true_market_mean,
indexes_to_cointime_price_ratio: ratio_di!(
"cointime_price",
&indexes_to_cointime_price
),
indexes_to_cointime_price,
})
}
}
@@ -0,0 +1,5 @@
mod compute;
mod import;
mod vecs;
pub use vecs::Vecs;
@@ -0,0 +1,16 @@
use brk_traversable::Traversable;
use brk_types::Dollars;
use crate::internal::{ComputedRatioVecsFromDateIndex, ComputedVecsFromHeight};
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_vaulted_price: ComputedVecsFromHeight<Dollars>,
pub indexes_to_vaulted_price_ratio: ComputedRatioVecsFromDateIndex,
pub indexes_to_active_price: ComputedVecsFromHeight<Dollars>,
pub indexes_to_active_price_ratio: ComputedRatioVecsFromDateIndex,
pub indexes_to_true_market_mean: ComputedVecsFromHeight<Dollars>,
pub indexes_to_true_market_mean_ratio: ComputedRatioVecsFromDateIndex,
pub indexes_to_cointime_price: ComputedVecsFromHeight<Dollars>,
pub indexes_to_cointime_price_ratio: ComputedRatioVecsFromDateIndex,
}
@@ -0,0 +1,54 @@
use brk_error::Result;
use vecdb::Exit;
use super::Vecs;
use super::super::activity;
use crate::{distribution, indexes, price, ComputeIndexes, utils::OptionExt};
impl Vecs {
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
price: Option<&price::Vecs>,
distribution: &distribution::Vecs,
activity: &activity::Vecs,
exit: &Exit,
) -> Result<()> {
let circulating_supply = &distribution.utxo_cohorts.all.metrics.supply.height_to_supply;
self.indexes_to_vaulted_supply.compute_all(
indexes,
price,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
circulating_supply,
activity.indexes_to_vaultedness.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_active_supply.compute_all(
indexes,
price,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
circulating_supply,
activity.indexes_to_liveliness.height.u(),
exit,
)?;
Ok(())
},
)?;
Ok(())
}
}
@@ -0,0 +1,39 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
indexes,
internal::{ComputedValueVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(
db: &Database,
version: Version,
indexes: &indexes::Vecs,
compute_dollars: bool,
) -> Result<Self> {
let last = || VecBuilderOptions::default().add_last();
macro_rules! value_h {
($name:expr) => {
ComputedValueVecsFromHeight::forced_import(
db,
$name,
Source::Compute,
version,
last(),
compute_dollars,
indexes,
)?
};
}
Ok(Self {
indexes_to_vaulted_supply: value_h!("vaulted_supply"),
indexes_to_active_supply: value_h!("active_supply"),
})
}
}
@@ -0,0 +1,5 @@
mod compute;
mod import;
mod vecs;
pub use vecs::Vecs;
@@ -0,0 +1,9 @@
use brk_traversable::Traversable;
use crate::internal::ComputedValueVecsFromHeight;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_vaulted_supply: ComputedValueVecsFromHeight,
pub indexes_to_active_supply: ComputedValueVecsFromHeight,
}
@@ -0,0 +1,72 @@
use brk_error::Result;
use vecdb::Exit;
use super::super::activity;
use super::Vecs;
use crate::{distribution, indexes, price, utils::OptionExt, ComputeIndexes};
impl Vecs {
pub fn compute(
&mut self,
indexes: &indexes::Vecs,
starting_indexes: &ComputeIndexes,
price: &price::Vecs,
distribution: &distribution::Vecs,
activity: &activity::Vecs,
exit: &Exit,
) -> Result<()> {
let indexes_to_coinblocks_destroyed = &distribution
.utxo_cohorts
.all
.metrics
.activity
.indexes_to_coinblocks_destroyed;
self.indexes_to_cointime_value_destroyed.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
&price.usd.chainindexes_to_price_close.height,
indexes_to_coinblocks_destroyed.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_cointime_value_created.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
&price.usd.chainindexes_to_price_close.height,
activity.indexes_to_coinblocks_created.height.u(),
exit,
)?;
Ok(())
},
)?;
self.indexes_to_cointime_value_stored.compute_all(
indexes,
starting_indexes,
exit,
|vec| {
vec.compute_multiply(
starting_indexes.height,
&price.usd.chainindexes_to_price_close.height,
activity.indexes_to_coinblocks_stored.height.u(),
exit,
)?;
Ok(())
},
)?;
Ok(())
}
}
@@ -0,0 +1,34 @@
use brk_error::Result;
use brk_types::Version;
use vecdb::Database;
use super::Vecs;
use crate::{
indexes,
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
};
impl Vecs {
pub fn forced_import(db: &Database, version: Version, indexes: &indexes::Vecs) -> Result<Self> {
let sum_cum = || VecBuilderOptions::default().add_sum().add_cumulative();
macro_rules! computed_h {
($name:expr) => {
ComputedVecsFromHeight::forced_import(
db,
$name,
Source::Compute,
version,
indexes,
sum_cum(),
)?
};
}
Ok(Self {
indexes_to_cointime_value_destroyed: computed_h!("cointime_value_destroyed"),
indexes_to_cointime_value_created: computed_h!("cointime_value_created"),
indexes_to_cointime_value_stored: computed_h!("cointime_value_stored"),
})
}
}
@@ -0,0 +1,5 @@
mod compute;
mod import;
mod vecs;
pub use vecs::Vecs;
@@ -0,0 +1,11 @@
use brk_traversable::Traversable;
use brk_types::StoredF64;
use crate::internal::ComputedVecsFromHeight;
#[derive(Clone, Traversable)]
pub struct Vecs {
pub indexes_to_cointime_value_destroyed: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_cointime_value_created: ComputedVecsFromHeight<StoredF64>,
pub indexes_to_cointime_value_stored: ComputedVecsFromHeight<StoredF64>,
}
+1 -1
View File
@@ -2,7 +2,7 @@ use brk_traversable::Traversable;
use brk_types::{StoredF32, StoredI16, StoredU16, Version};
use super::{
grouped::{ConstantVecs, ReturnF32Tenths, ReturnI16, ReturnU16},
internal::{ConstantVecs, ReturnF32Tenths, ReturnI16, ReturnU16},
indexes,
};
@@ -10,9 +10,8 @@ use vecdb::{
};
use crate::{
ComputeIndexes,
grouped::{ComputedVecsFromHeight, Source, VecBuilderOptions},
indexes,
ComputeIndexes, indexes,
internal::{ComputedVecsFromHeight, Source, VecBuilderOptions},
};
/// Address count per address type (runtime state).
@@ -75,18 +74,6 @@ impl AddressTypeToHeightToAddressCount {
})?))
}
pub fn write(&mut self) -> Result<()> {
self.p2pk65.write()?;
self.p2pk33.write()?;
self.p2pkh.write()?;
self.p2sh.write()?;
self.p2wpkh.write()?;
self.p2wsh.write()?;
self.p2tr.write()?;
self.p2a.write()?;
Ok(())
}
/// Returns a parallel iterator over all vecs for parallel writing.
pub fn par_iter_mut(&mut self) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
let inner = &mut self.0;
@@ -103,15 +90,15 @@ impl AddressTypeToHeightToAddressCount {
.into_par_iter()
}
pub fn safe_write(&mut self, exit: &Exit) -> Result<()> {
self.p2pk65.safe_write(exit)?;
self.p2pk33.safe_write(exit)?;
self.p2pkh.safe_write(exit)?;
self.p2sh.safe_write(exit)?;
self.p2wpkh.safe_write(exit)?;
self.p2wsh.safe_write(exit)?;
self.p2tr.safe_write(exit)?;
self.p2a.safe_write(exit)?;
pub fn write(&mut self) -> Result<()> {
self.p2pk65.write()?;
self.p2pk33.write()?;
self.p2pkh.write()?;
self.p2sh.write()?;
self.p2wpkh.write()?;
self.p2wsh.write()?;
self.p2tr.write()?;
self.p2a.write()?;
Ok(())
}
@@ -2,7 +2,7 @@ use brk_cohort::ByAddressType;
use brk_types::{AnyAddressDataIndexEnum, LoadedAddressData, OutputType, TypeIndex};
use vecdb::GenericStoredVec;
use crate::stateful::{
use crate::distribution::{
address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs},
compute::VecsReaders,
};
@@ -1,6 +1,6 @@
use brk_types::{LoadedAddressData, OutputType, TypeIndex};
use crate::stateful::address::AddressTypeToTypeIndexMap;
use crate::distribution::address::AddressTypeToTypeIndexMap;
use super::super::cohort::{
EmptyAddressDataWithSource, LoadedAddressDataWithSource, WithAddressDataSource,
@@ -4,7 +4,7 @@ use brk_types::{
OutputType, TypeIndex,
};
use crate::stateful::{AddressTypeToTypeIndexMap, AddressesDataVecs};
use crate::distribution::{AddressTypeToTypeIndexMap, AddressesDataVecs};
use super::with_source::{EmptyAddressDataWithSource, LoadedAddressDataWithSource};
@@ -2,7 +2,7 @@ use brk_cohort::{AmountBucket, ByAddressType};
use brk_types::{Dollars, Sats, TypeIndex};
use rustc_hash::FxHashMap;
use crate::stateful::{address::AddressTypeToVec, cohorts::AddressCohorts};
use crate::distribution::{address::AddressTypeToVec, cohorts::AddressCohorts};
use super::super::cache::{AddressLookup, TrackingStatus};
@@ -3,7 +3,7 @@ use brk_error::Result;
use brk_types::{CheckedSub, Dollars, Height, Sats, Timestamp, TypeIndex};
use vecdb::{VecIndex, unlikely};
use crate::stateful::{address::HeightToAddressTypeToVec, cohorts::AddressCohorts};
use crate::distribution::{address::HeightToAddressTypeToVec, cohorts::AddressCohorts};
use super::super::cache::AddressLookup;
@@ -1,4 +1,4 @@
use crate::stateful::address::AddressTypeToTypeIndexMap;
use crate::distribution::address::AddressTypeToTypeIndexMap;
use super::with_source::{EmptyAddressDataWithSource, LoadedAddressDataWithSource, TxIndexVec};
@@ -3,13 +3,13 @@ use brk_types::{Height, OutputType, Sats, TxIndex, TypeIndex};
use rayon::prelude::*;
use rustc_hash::FxHashMap;
use crate::stateful::{
use crate::distribution::{
address::{AddressTypeToTypeIndexMap, AddressesDataVecs, AnyAddressIndexesVecs},
compute::VecsReaders,
state::Transacted,
};
use crate::stateful::address::HeightToAddressTypeToVec;
use crate::distribution::address::HeightToAddressTypeToVec;
use super::super::{
cache::{AddressCache, load_uncached_address_data},
@@ -1,7 +1,7 @@
use brk_cohort::ByAddressType;
use brk_types::{Sats, TxIndex, TypeIndex};
use crate::stateful::{
use crate::distribution::{
address::{
AddressTypeToTypeIndexMap, AddressTypeToVec, AddressesDataVecs, AnyAddressIndexesVecs,
},
@@ -10,9 +10,9 @@ use derive_deref::{Deref, DerefMut};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Database, Exit, IterableVec};
use crate::{ComputeIndexes, indexes, price, stateful::DynCohortVecs};
use crate::{ComputeIndexes, indexes, price, distribution::DynCohortVecs};
use crate::stateful::metrics::SupplyMetrics;
use crate::distribution::metrics::SupplyMetrics;
use super::{super::traits::CohortVecs, vecs::AddressCohortVecs};
@@ -164,13 +164,21 @@ impl AddressCohorts {
}
/// Get minimum height from all separate cohorts' height-indexed vectors.
pub fn min_separate_height_vecs_len(&self) -> Height {
pub fn min_separate_stateful_height_len(&self) -> Height {
self.iter_separate()
.map(|v| Height::from(v.min_height_vecs_len()))
.map(|v| Height::from(v.min_stateful_height_len()))
.min()
.unwrap_or_default()
}
/// Get minimum dateindex from all separate cohorts' dateindex-indexed vectors.
pub fn min_separate_stateful_dateindex_len(&self) -> usize {
self.iter_separate()
.map(|v| v.min_stateful_dateindex_len())
.min()
.unwrap_or(usize::MAX)
}
/// Import state for all separate cohorts at or before given height.
/// Returns true if all imports succeeded and returned the expected height.
pub fn import_separate_states(&mut self, height: Height) -> bool {

Some files were not shown because too many files have changed in this diff Show More