diff --git a/Cargo.lock b/Cargo.lock index 9b10e6209..6e73bbfa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3899,8 +3899,6 @@ checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" [[package]] name = "seqdb" version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54ab988c96efa9d275ca2b12bf2d3c6adec993b8e82ea31a88c984abdaa14fa" dependencies = [ "libc", "log", @@ -4727,8 +4725,6 @@ checksum = "8f54a172d0620933a27a4360d3db3e2ae0dd6cceae9730751a036bbf182c4b23" [[package]] name = "vecdb" version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5c4ec34c376be3a41435eeb7672d0ea0e9c1d60c5d1d90218912588f91abea" dependencies = [ "ctrlc", "log", @@ -4747,8 +4743,6 @@ dependencies = [ [[package]] name = "vecdb_derive" version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778c4874c05822465e28cae6a7dead593a73124ec80afb85b85adae5ac883368" dependencies = [ "quote", "syn 2.0.106", diff --git a/Cargo.toml b/Cargo.toml index 39aa7d075..5e32acd6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,8 +52,8 @@ serde_bytes = "0.11.17" serde_derive = "1.0.219" serde_json = { version = "1.0.143", features = ["float_roundtrip"] } tokio = { version = "1.47.1", features = ["rt-multi-thread"] } -# vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]} -vecdb = { version = "0.2.5", features = ["derive"]} +vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]} +# vecdb = { version = "0.2.5", features = ["derive"]} zerocopy = "0.8.26" zerocopy-derive = "0.8.26" diff --git a/TODO.md b/TODO.md index 23896f4aa..233174667 100644 --- a/TODO.md +++ b/TODO.md @@ -12,7 +12,7 @@ - **add rollback of states (in stateful)** - add costs basis by percentile (percentile cost basis) back - add support for per index computation - - fix min feerate which is always ZERO due to coinbase transaction + - fix min fee_rate which is always ZERO due to coinbase transaction - before computing multiple sources check their length, panic if not equal - add oracle price dataset (https://utxo.live/oracle/UTXOracle.py) - add address counts relative to all datasets diff --git a/crates/brk_computer/src/blocks.rs b/crates/brk_computer/src/blocks.rs deleted file mode 100644 index f60464e36..000000000 --- a/crates/brk_computer/src/blocks.rs +++ /dev/null @@ -1,279 +0,0 @@ -use std::path::Path; - -use brk_error::Result; -use brk_indexer::Indexer; -use brk_structs::{ - CheckedSub, DifficultyEpoch, HalvingEpoch, Height, StoredU32, StoredU64, Timestamp, Version, - Weight, -}; -use vecdb::{AnyCollectableVec, Database, EagerVec, Exit, PAGE_SIZE, VecIterator}; - -use crate::grouped::Source; - -use super::{ - Indexes, - grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions}, - indexes, -}; - -const VERSION: Version = Version::ZERO; - -#[derive(Clone)] -pub struct Vecs { - db: Database, - - pub height_to_interval: EagerVec, - pub height_to_vbytes: EagerVec, - pub difficultyepoch_to_timestamp: EagerVec, - pub halvingepoch_to_timestamp: EagerVec, - pub timeindexes_to_timestamp: ComputedVecsFromDateIndex, - pub indexes_to_block_count: ComputedVecsFromHeight, - pub indexes_to_block_interval: ComputedVecsFromHeight, - pub indexes_to_block_size: ComputedVecsFromHeight, - pub indexes_to_block_vbytes: ComputedVecsFromHeight, - pub indexes_to_block_weight: ComputedVecsFromHeight, -} - -impl Vecs { - pub fn forced_import(parent: &Path, version: Version, indexes: &indexes::Vecs) -> Result { - let db = Database::open(&parent.join("blocks"))?; - db.set_min_len(PAGE_SIZE * 1_000_000)?; - - Ok(Self { - height_to_interval: EagerVec::forced_import_compressed( - &db, - "interval", - version + VERSION + Version::ZERO, - )?, - timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import( - &db, - "timestamp", - Source::Compute, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default().add_first(), - )?, - indexes_to_block_interval: ComputedVecsFromHeight::forced_import( - &db, - "block_interval", - Source::None, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default() - .add_percentiles() - .add_minmax() - .add_average(), - )?, - indexes_to_block_count: ComputedVecsFromHeight::forced_import( - &db, - "block_count", - Source::Compute, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default().add_sum().add_cumulative(), - )?, - indexes_to_block_weight: ComputedVecsFromHeight::forced_import( - &db, - "block_weight", - Source::None, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default() - .add_sum() - .add_minmax() - .add_average() - .add_percentiles() - .add_cumulative(), - )?, - indexes_to_block_size: ComputedVecsFromHeight::forced_import( - &db, - "block_size", - Source::Compute, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default() - .add_sum() - .add_minmax() - .add_average() - .add_percentiles() - .add_cumulative(), - )?, - height_to_vbytes: EagerVec::forced_import_compressed( - &db, - "vbytes", - version + VERSION + Version::ZERO, - )?, - indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import( - &db, - "block_vbytes", - Source::None, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default() - .add_sum() - .add_minmax() - .add_average() - .add_percentiles() - .add_cumulative(), - )?, - difficultyepoch_to_timestamp: EagerVec::forced_import_compressed( - &db, - "timestamp", - version + VERSION + Version::ZERO, - )?, - halvingepoch_to_timestamp: EagerVec::forced_import_compressed( - &db, - "timestamp", - version + VERSION + Version::ZERO, - )?, - - db, - }) - } - - pub fn compute( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &Indexes, - exit: &Exit, - ) -> Result<()> { - self.compute_(indexer, indexes, starting_indexes, exit)?; - self.db.flush_then_punch()?; - Ok(()) - } - - fn compute_( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &Indexes, - exit: &Exit, - ) -> Result<()> { - self.timeindexes_to_timestamp.compute_all( - indexer, - indexes, - starting_indexes, - exit, - |vec, _, indexes, starting_indexes, exit| { - vec.compute_transform( - starting_indexes.dateindex, - &indexes.dateindex_to_date, - |(di, d, ..)| (di, Timestamp::from(d)), - exit, - )?; - Ok(()) - }, - )?; - - self.indexes_to_block_count.compute_all( - indexer, - indexes, - starting_indexes, - exit, - |v, indexer, _, starting_indexes, exit| { - v.compute_range( - starting_indexes.height, - &indexer.vecs.height_to_weight, - |h| (h, StoredU32::from(1_u32)), - exit, - )?; - Ok(()) - }, - )?; - - let mut height_to_timestamp_iter = indexer.vecs.height_to_timestamp.iter(); - self.height_to_interval.compute_transform( - starting_indexes.height, - &indexer.vecs.height_to_timestamp, - |(height, timestamp, ..)| { - let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| { - let prev_timestamp = height_to_timestamp_iter.unwrap_get_inner(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.height_to_weight), - )?; - - self.indexes_to_block_size.compute_rest( - indexes, - starting_indexes, - exit, - Some(&indexer.vecs.height_to_total_size), - )?; - - self.height_to_vbytes.compute_transform( - starting_indexes.height, - &indexer.vecs.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), - )?; - - let mut height_to_timestamp_iter = indexer.vecs.height_to_timestamp.iter(); - - self.difficultyepoch_to_timestamp.compute_transform( - starting_indexes.difficultyepoch, - &indexes.difficultyepoch_to_first_height, - |(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)), - exit, - )?; - - self.halvingepoch_to_timestamp.compute_transform( - starting_indexes.halvingepoch, - &indexes.halvingepoch_to_first_height, - |(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)), - exit, - )?; - - Ok(()) - } - - pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> { - [ - vec![ - &self.height_to_interval as &dyn AnyCollectableVec, - &self.height_to_vbytes, - &self.difficultyepoch_to_timestamp, - &self.halvingepoch_to_timestamp, - ], - self.timeindexes_to_timestamp.vecs(), - self.indexes_to_block_count.vecs(), - self.indexes_to_block_interval.vecs(), - self.indexes_to_block_size.vecs(), - self.indexes_to_block_vbytes.vecs(), - self.indexes_to_block_weight.vecs(), - ] - .into_iter() - .flatten() - .collect::>() - } -} diff --git a/crates/brk_computer/src/transactions.rs b/crates/brk_computer/src/chain.rs similarity index 64% rename from crates/brk_computer/src/transactions.rs rename to crates/brk_computer/src/chain.rs index 6d7eef6c3..4609b3248 100644 --- a/crates/brk_computer/src/transactions.rs +++ b/crates/brk_computer/src/chain.rs @@ -3,8 +3,9 @@ use std::path::Path; use brk_error::Result; use brk_indexer::Indexer; use brk_structs::{ - CheckedSub, Feerate, HalvingEpoch, Height, InputIndex, OutputIndex, Sats, StoredBool, - StoredU32, StoredU64, TxIndex, TxVersion, Version, Weight, + CheckedSub, Date, DateIndex, DifficultyEpoch, Dollars, FeeRate, HalvingEpoch, Height, + InputIndex, OutputIndex, Sats, StoredBool, StoredF32, StoredF64, StoredU32, StoredU64, + Timestamp, TxIndex, TxVersion, Version, Weight, }; use vecdb::{ AnyCloneableIterableVec, AnyCollectableVec, AnyIterableVec, Database, EagerVec, Exit, @@ -12,25 +13,37 @@ use vecdb::{ }; use crate::grouped::{ - ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromHeight, - ComputedVecsFromTxindex, Source, VecBuilderOptions, + ComputedValueVecsFromHeight, ComputedValueVecsFromTxindex, ComputedVecsFromDateIndex, + ComputedVecsFromHeight, ComputedVecsFromTxindex, Source, VecBuilderOptions, }; use super::{Indexes, indexes, price}; const VERSION: Version = Version::ZERO; +const TARGET_BLOCKS_PER_DAY: f64 = 144.0; #[derive(Clone)] pub struct Vecs { db: Database, - // pub txindex_to_is_v1: LazyVec, - // pub txindex_to_is_v2: LazyVec, - // pub txindex_to_is_v3: LazyVec, + pub height_to_interval: EagerVec, + pub height_to_vbytes: EagerVec, + pub difficultyepoch_to_timestamp: EagerVec, + pub halvingepoch_to_timestamp: EagerVec, + pub timeindexes_to_timestamp: ComputedVecsFromDateIndex, + pub indexes_to_block_count: ComputedVecsFromHeight, + pub indexes_to_block_interval: ComputedVecsFromHeight, + pub indexes_to_block_size: ComputedVecsFromHeight, + pub indexes_to_block_vbytes: ComputedVecsFromHeight, + pub indexes_to_block_weight: ComputedVecsFromHeight, + pub indexes_to_difficulty: ComputedVecsFromHeight, + pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex, + pub indexes_to_halvingepoch: ComputedVecsFromDateIndex, + pub indexes_to_coinbase: ComputedValueVecsFromHeight, pub indexes_to_emptyoutput_count: ComputedVecsFromHeight, pub indexes_to_fee: ComputedValueVecsFromTxindex, - pub indexes_to_feerate: ComputedVecsFromTxindex, + pub indexes_to_fee_rate: ComputedVecsFromTxindex, /// Value == 0 when Coinbase pub txindex_to_input_value: LazyVecFrom3, @@ -65,8 +78,18 @@ pub struct Vecs { pub txindex_to_vsize: LazyVecFrom1, pub txindex_to_weight: LazyVecFrom2, pub txindex_to_fee: EagerVec, - pub txindex_to_feerate: EagerVec, + pub txindex_to_fee_rate: EagerVec, pub indexes_to_exact_utxo_count: ComputedVecsFromHeight, + pub dateindex_to_fee_dominance: EagerVec, + pub dateindex_to_subsidy_dominance: EagerVec, + pub indexes_to_subsidy_usd_1y_sma: Option>, + pub indexes_to_puell_multiple: Option>, + pub indexes_to_hash_rate: ComputedVecsFromDateIndex, + pub indexes_to_hash_rate_1w_sma: ComputedVecsFromDateIndex, + pub indexes_to_hash_rate_1m_sma: ComputedVecsFromDateIndex, + pub indexes_to_hash_rate_2m_sma: ComputedVecsFromDateIndex, + pub indexes_to_hash_rate_1y_sma: ComputedVecsFromDateIndex, + pub indexes_to_difficulty_as_hash: ComputedVecsFromDateIndex, } impl Vecs { @@ -77,7 +100,7 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, ) -> Result { - let db = Database::open(&parent.join("transactions"))?; + let db = Database::open(&parent.join("chain"))?; db.set_min_len(PAGE_SIZE * 10_000_000)?; let compute_dollars = price.is_some(); @@ -262,10 +285,131 @@ impl Vecs { let txindex_to_fee = EagerVec::forced_import_compressed(&db, "fee", version + VERSION + Version::ZERO)?; - let txindex_to_feerate = - EagerVec::forced_import_compressed(&db, "feerate", version + VERSION + Version::ZERO)?; + let txindex_to_fee_rate = + EagerVec::forced_import_compressed(&db, "fee_rate", version + VERSION + Version::ZERO)?; Ok(Self { + height_to_interval: EagerVec::forced_import_compressed( + &db, + "interval", + version + VERSION + Version::ZERO, + )?, + timeindexes_to_timestamp: ComputedVecsFromDateIndex::forced_import( + &db, + "timestamp", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_first(), + )?, + indexes_to_block_interval: ComputedVecsFromHeight::forced_import( + &db, + "block_interval", + Source::None, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default() + .add_percentiles() + .add_minmax() + .add_average(), + )?, + indexes_to_block_count: ComputedVecsFromHeight::forced_import( + &db, + "block_count", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_sum().add_cumulative(), + )?, + indexes_to_block_weight: ComputedVecsFromHeight::forced_import( + &db, + "block_weight", + Source::None, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default() + .add_sum() + .add_minmax() + .add_average() + .add_percentiles() + .add_cumulative(), + )?, + indexes_to_block_size: ComputedVecsFromHeight::forced_import( + &db, + "block_size", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default() + .add_sum() + .add_minmax() + .add_average() + .add_percentiles() + .add_cumulative(), + )?, + height_to_vbytes: EagerVec::forced_import_compressed( + &db, + "vbytes", + version + VERSION + Version::ZERO, + )?, + indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import( + &db, + "block_vbytes", + Source::None, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default() + .add_sum() + .add_minmax() + .add_average() + .add_percentiles() + .add_cumulative(), + )?, + difficultyepoch_to_timestamp: EagerVec::forced_import_compressed( + &db, + "timestamp", + version + VERSION + Version::ZERO, + )?, + halvingepoch_to_timestamp: EagerVec::forced_import_compressed( + &db, + "timestamp", + version + VERSION + Version::ZERO, + )?, + + dateindex_to_fee_dominance: EagerVec::forced_import_compressed( + &db, + "fee_dominance", + version + VERSION + Version::ZERO, + )?, + dateindex_to_subsidy_dominance: EagerVec::forced_import_compressed( + &db, + "subsidy_dominance", + version + VERSION + Version::ZERO, + )?, + indexes_to_difficulty: ComputedVecsFromHeight::forced_import( + &db, + "difficulty", + Source::None, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import( + &db, + "difficultyepoch", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import( + &db, + "halvingepoch", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, indexes_to_tx_count: ComputedVecsFromHeight::forced_import( &db, "tx_count", @@ -343,9 +487,9 @@ impl Vecs { .add_minmax() .add_average(), )?, - indexes_to_feerate: ComputedVecsFromTxindex::forced_import( + indexes_to_fee_rate: ComputedVecsFromTxindex::forced_import( &db, - "feerate", + "fee_rate", Source::None, version + VERSION + Version::ZERO, indexes, @@ -577,6 +721,77 @@ impl Vecs { indexes, VecBuilderOptions::default().add_last(), )?, + indexes_to_subsidy_usd_1y_sma: compute_dollars.then(|| { + ComputedVecsFromDateIndex::forced_import( + &db, + "subsidy_usd_1y_sma", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + ) + .unwrap() + }), + indexes_to_puell_multiple: compute_dollars.then(|| { + ComputedVecsFromDateIndex::forced_import( + &db, + "puell_multiple", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + ) + .unwrap() + }), + indexes_to_hash_rate: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_rate", + Source::Compute, + version + VERSION + Version::ONE, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_rate_1w_sma: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_rate_1w_sma", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_rate_1m_sma: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_rate_1m_sma", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_rate_2m_sma: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_rate_2m_sma", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_rate_1y_sma: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_rate_1y_sma", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_difficulty_as_hash: ComputedVecsFromDateIndex::forced_import( + &db, + "difficulty_as_hash", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + txindex_to_is_coinbase, inputindex_to_value, // indexes_to_input_value, @@ -584,7 +799,7 @@ impl Vecs { txindex_to_input_value, txindex_to_output_value, txindex_to_fee, - txindex_to_feerate, + txindex_to_fee_rate, txindex_to_vsize, txindex_to_weight, @@ -613,6 +828,167 @@ impl Vecs { price: Option<&price::Vecs>, exit: &Exit, ) -> Result<()> { + self.timeindexes_to_timestamp.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |vec, _, indexes, starting_indexes, exit| { + vec.compute_transform( + starting_indexes.dateindex, + &indexes.dateindex_to_date, + |(di, d, ..)| (di, Timestamp::from(d)), + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_block_count.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, indexer, _, starting_indexes, exit| { + v.compute_range( + starting_indexes.height, + &indexer.vecs.height_to_weight, + |h| (h, StoredU32::from(1_u32)), + exit, + )?; + Ok(()) + }, + )?; + + let mut height_to_timestamp_iter = indexer.vecs.height_to_timestamp.iter(); + self.height_to_interval.compute_transform( + starting_indexes.height, + &indexer.vecs.height_to_timestamp, + |(height, timestamp, ..)| { + let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| { + let prev_timestamp = height_to_timestamp_iter.unwrap_get_inner(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.height_to_weight), + )?; + + self.indexes_to_block_size.compute_rest( + indexes, + starting_indexes, + exit, + Some(&indexer.vecs.height_to_total_size), + )?; + + self.height_to_vbytes.compute_transform( + starting_indexes.height, + &indexer.vecs.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), + )?; + + let mut height_to_timestamp_iter = indexer.vecs.height_to_timestamp.iter(); + + self.difficultyepoch_to_timestamp.compute_transform( + starting_indexes.difficultyepoch, + &indexes.difficultyepoch_to_first_height, + |(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)), + exit, + )?; + + self.halvingepoch_to_timestamp.compute_transform( + starting_indexes.halvingepoch, + &indexes.halvingepoch_to_first_height, + |(i, h, ..)| (i, height_to_timestamp_iter.unwrap_get_inner(h)), + exit, + )?; + + let mut height_to_difficultyepoch_iter = indexes.height_to_difficultyepoch.into_iter(); + self.indexes_to_difficultyepoch.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |vec, _, indexes, starting_indexes, exit| { + let mut height_count_iter = indexes.dateindex_to_height_count.into_iter(); + vec.compute_transform( + starting_indexes.dateindex, + &indexes.dateindex_to_first_height, + |(di, height, ..)| { + ( + di, + height_to_difficultyepoch_iter.unwrap_get_inner( + height + (*height_count_iter.unwrap_get_inner(di) - 1), + ), + ) + }, + exit, + )?; + Ok(()) + }, + )?; + + let mut height_to_halvingepoch_iter = indexes.height_to_halvingepoch.into_iter(); + self.indexes_to_halvingepoch.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |vec, _, indexes, starting_indexes, exit| { + let mut height_count_iter = indexes.dateindex_to_height_count.into_iter(); + vec.compute_transform( + starting_indexes.dateindex, + &indexes.dateindex_to_first_height, + |(di, height, ..)| { + ( + di, + height_to_halvingepoch_iter.unwrap_get_inner( + height + (*height_count_iter.unwrap_get_inner(di) - 1), + ), + ) + }, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_difficulty.compute_rest( + indexes, + starting_indexes, + exit, + Some(&indexer.vecs.height_to_difficulty), + )?; + self.indexes_to_tx_count.compute_all( indexer, indexes, @@ -722,11 +1098,11 @@ impl Vecs { exit, )?; - self.txindex_to_feerate.compute_transform2( + 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))), + |(txindex, fee, vsize, ..)| (txindex, FeeRate::from((fee, vsize))), exit, )?; @@ -739,12 +1115,12 @@ impl Vecs { price, )?; - self.indexes_to_feerate.compute_rest( + self.indexes_to_fee_rate.compute_rest( indexer, indexes, starting_indexes, exit, - Some(&self.txindex_to_feerate), + Some(&self.txindex_to_fee_rate), )?; self.indexes_to_tx_weight.compute_rest( @@ -1085,25 +1461,241 @@ impl Vecs { }, )?; + self.dateindex_to_fee_dominance.compute_transform2( + starting_indexes.dateindex, + self.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), + ) + }, + exit, + )?; + self.dateindex_to_subsidy_dominance.compute_transform2( + starting_indexes.dateindex, + 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), + ) + }, + exit, + )?; + + self.indexes_to_difficulty_as_hash.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + let multiplier = 2.0_f64.powi(32) / 600.0; + v.compute_transform( + starting_indexes.dateindex, + self.indexes_to_difficulty.dateindex.unwrap_last(), + |(i, v, ..)| (i, StoredF32::from(*v * multiplier)), + exit, + )?; + Ok(()) + }, + )?; + + let now = Timestamp::now(); + let today = Date::from(now); + self.indexes_to_hash_rate.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_transform3( + starting_indexes.dateindex, + self.indexes_to_block_count.dateindex.unwrap_sum(), + self.indexes_to_difficulty_as_hash + .dateindex + .as_ref() + .unwrap(), + &indexes.dateindex_to_date, + |(i, block_count_sum, difficulty_as_hash, date, ..)| { + let target_multiplier = if date == today { + now.day_completion() + } else { + 1.0 + }; + ( + i, + StoredF64::from( + (f64::from(block_count_sum) + / (target_multiplier * TARGET_BLOCKS_PER_DAY)) + * f64::from(difficulty_as_hash), + ), + ) + }, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_hash_rate_1w_sma.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.as_ref().unwrap(), + 7, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_hash_rate_1m_sma.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.as_ref().unwrap(), + 30, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_hash_rate_2m_sma.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.as_ref().unwrap(), + 2 * 30, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_hash_rate_1y_sma.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + self.indexes_to_hash_rate.dateindex.as_ref().unwrap(), + 365, + exit, + )?; + Ok(()) + }, + )?; + + if self.indexes_to_subsidy_usd_1y_sma.is_some() { + let date_to_coinbase_usd_sum = self + .indexes_to_coinbase + .dollars + .as_ref() + .unwrap() + .dateindex + .unwrap_sum(); + + self.indexes_to_subsidy_usd_1y_sma + .as_mut() + .unwrap() + .compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_sma( + starting_indexes.dateindex, + date_to_coinbase_usd_sum, + 365, + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_puell_multiple + .as_mut() + .unwrap() + .compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + 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(()) + }, + )?; + } + Ok(()) } pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> { [ vec![ - &self.inputindex_to_value as &dyn AnyCollectableVec, + &self.height_to_interval as &dyn AnyCollectableVec, + &self.height_to_vbytes, + &self.difficultyepoch_to_timestamp, + &self.halvingepoch_to_timestamp, + &self.inputindex_to_value, &self.txindex_to_fee, - &self.txindex_to_feerate, + &self.txindex_to_fee_rate, &self.txindex_to_input_value, &self.txindex_to_is_coinbase, &self.txindex_to_output_value, &self.txindex_to_vsize, &self.txindex_to_weight, + &self.dateindex_to_fee_dominance, + &self.dateindex_to_subsidy_dominance, ], + self.indexes_to_hash_rate.vecs(), + self.indexes_to_hash_rate_1w_sma.vecs(), + self.indexes_to_hash_rate_1m_sma.vecs(), + self.indexes_to_hash_rate_2m_sma.vecs(), + self.indexes_to_hash_rate_1y_sma.vecs(), + self.timeindexes_to_timestamp.vecs(), + self.indexes_to_block_count.vecs(), + self.indexes_to_block_interval.vecs(), + self.indexes_to_block_size.vecs(), + self.indexes_to_block_vbytes.vecs(), + self.indexes_to_block_weight.vecs(), + self.indexes_to_difficulty.vecs(), + self.indexes_to_difficultyepoch.vecs(), + self.indexes_to_halvingepoch.vecs(), self.indexes_to_coinbase.vecs(), self.indexes_to_emptyoutput_count.vecs(), self.indexes_to_fee.vecs(), - self.indexes_to_feerate.vecs(), + self.indexes_to_fee_rate.vecs(), self.indexes_to_input_count.vecs(), self.indexes_to_opreturn_count.vecs(), self.indexes_to_output_count.vecs(), @@ -1111,6 +1703,7 @@ impl Vecs { self.indexes_to_p2ms_count.vecs(), self.indexes_to_p2pk33_count.vecs(), self.indexes_to_p2pk65_count.vecs(), + self.indexes_to_difficulty_as_hash.vecs(), self.indexes_to_p2pkh_count.vecs(), self.indexes_to_p2sh_count.vecs(), self.indexes_to_p2tr_count.vecs(), @@ -1126,6 +1719,12 @@ impl Vecs { self.indexes_to_unknownoutput_count.vecs(), self.indexes_to_exact_utxo_count.vecs(), self.indexes_to_unclaimed_rewards.vecs(), + self.indexes_to_subsidy_usd_1y_sma + .as_ref() + .map_or(vec![], |v| v.vecs()), + self.indexes_to_puell_multiple + .as_ref() + .map_or(vec![], |v| v.vecs()), ] .into_iter() .flatten() diff --git a/crates/brk_computer/src/cointime.rs b/crates/brk_computer/src/cointime.rs index bd4da6c7e..35ee20283 100644 --- a/crates/brk_computer/src/cointime.rs +++ b/crates/brk_computer/src/cointime.rs @@ -6,12 +6,12 @@ use brk_structs::{Bitcoin, CheckedSub, Dollars, StoredF64, Version}; use vecdb::{AnyCollectableVec, Database, Exit, PAGE_SIZE, VecIterator}; use super::{ - Indexes, + Indexes, chain, grouped::{ ComputedRatioVecsFromDateIndex, ComputedValueVecsFromHeight, ComputedVecsFromHeight, Source, VecBuilderOptions, }, - indexes, price, stateful, transactions, + indexes, price, stateful, }; const VERSION: Version = Version::ZERO; @@ -257,7 +257,7 @@ impl Vecs { indexes: &indexes::Vecs, starting_indexes: &Indexes, price: Option<&price::Vecs>, - transactions: &transactions::Vecs, + chain: &chain::Vecs, stateful: &stateful::Vecs, exit: &Exit, ) -> Result<()> { @@ -266,7 +266,7 @@ impl Vecs { indexes, starting_indexes, price, - transactions, + chain, stateful, exit, )?; @@ -281,7 +281,7 @@ impl Vecs { indexes: &indexes::Vecs, starting_indexes: &Indexes, price: Option<&price::Vecs>, - transactions: &transactions::Vecs, + chain: &chain::Vecs, stateful: &stateful::Vecs, exit: &Exit, ) -> Result<()> { @@ -446,7 +446,7 @@ impl Vecs { |vec, _, _, starting_indexes, exit| { vec.compute_transform( starting_indexes.height, - transactions + chain .indexes_to_subsidy .dollars .as_ref() diff --git a/crates/brk_computer/src/grouped/builder_eager.rs b/crates/brk_computer/src/grouped/builder_eager.rs index 0e483cdb3..ee5022062 100644 --- a/crates/brk_computer/src/grouped/builder_eager.rs +++ b/crates/brk_computer/src/grouped/builder_eager.rs @@ -19,11 +19,11 @@ where pub average: Option>>, pub sum: Option>>, pub max: Option>>, - pub _90p: Option>>, - pub _75p: Option>>, + pub p90: Option>>, + pub p75: Option>>, pub median: Option>>, - pub _25p: Option>>, - pub _10p: Option>>, + pub p25: Option>>, + pub p10: Option>>, pub min: Option>>, pub last: Option>>, pub cumulative: Option>>, @@ -118,7 +118,7 @@ where Box::new( EagerVec::forced_import( db, - &maybe_suffix("average"), + &maybe_suffix("avg"), version + VERSION + Version::ZERO, format, ) @@ -144,51 +144,51 @@ where Box::new( EagerVec::forced_import( db, - &suffix("cumulative"), + &suffix("cum"), version + VERSION + Version::ZERO, format, ) .unwrap(), ) }), - _90p: options._90p.then(|| { + p90: options.p90.then(|| { Box::new( EagerVec::forced_import( db, - &maybe_suffix("90p"), + &maybe_suffix("p90"), version + VERSION + Version::ZERO, format, ) .unwrap(), ) }), - _75p: options._75p.then(|| { + p75: options.p75.then(|| { Box::new( EagerVec::forced_import( db, - &maybe_suffix("75p"), + &maybe_suffix("p75"), version + VERSION + Version::ZERO, format, ) .unwrap(), ) }), - _25p: options._25p.then(|| { + p25: options.p25.then(|| { Box::new( EagerVec::forced_import( db, - &maybe_suffix("25p"), + &maybe_suffix("p25"), version + VERSION + Version::ZERO, format, ) .unwrap(), ) }), - _10p: options._10p.then(|| { + p10: options.p10.then(|| { Box::new( EagerVec::forced_import( db, - &maybe_suffix("10p"), + &maybe_suffix("p10"), version + VERSION + Version::ZERO, format, ) @@ -292,11 +292,11 @@ where let needs_average_sum_or_cumulative = needs_sum_or_cumulative || self.average.is_some(); let needs_sorted = self.max.is_some() - || self._90p.is_some() - || self._75p.is_some() + || self.p90.is_some() + || self.p75.is_some() || self.median.is_some() - || self._25p.is_some() - || self._10p.is_some() + || self.p25.is_some() + || self.p10.is_some() || self.min.is_some(); let needs_values = needs_sorted || needs_average_sum_or_cumulative; @@ -333,24 +333,24 @@ where )?; } - if let Some(_90p) = self._90p.as_mut() { - _90p.forced_push_at(index, get_percentile(&values, 0.90), exit)?; + if let Some(p90) = self.p90.as_mut() { + p90.forced_push_at(index, get_percentile(&values, 0.90), exit)?; } - if let Some(_75p) = self._75p.as_mut() { - _75p.forced_push_at(index, get_percentile(&values, 0.75), exit)?; + if let Some(p75) = self.p75.as_mut() { + p75.forced_push_at(index, get_percentile(&values, 0.75), exit)?; } if let Some(median) = self.median.as_mut() { median.forced_push_at(index, get_percentile(&values, 0.50), exit)?; } - if let Some(_25p) = self._25p.as_mut() { - _25p.forced_push_at(index, get_percentile(&values, 0.25), exit)?; + if let Some(p25) = self.p25.as_mut() { + p25.forced_push_at(index, get_percentile(&values, 0.25), exit)?; } - if let Some(_10p) = self._10p.as_mut() { - _10p.forced_push_at(index, get_percentile(&values, 0.10), exit)?; + if let Some(p10) = self.p10.as_mut() { + p10.forced_push_at(index, get_percentile(&values, 0.10), exit)?; } if let Some(min) = self.min.as_mut() { @@ -401,11 +401,11 @@ where where I2: StoredIndex + StoredRaw + CheckedSub, { - if self._90p.is_some() - || self._75p.is_some() + if self.p90.is_some() + || self.p75.is_some() || self.median.is_some() - || self._25p.is_some() - || self._10p.is_some() + || self.p25.is_some() + || self.p10.is_some() { panic!("unsupported"); } @@ -558,24 +558,24 @@ where self.max.as_ref().unwrap() } #[allow(unused)] - pub fn unwrap_90p(&self) -> &EagerVec { - self._90p.as_ref().unwrap() + pub fn unwrap_p90(&self) -> &EagerVec { + self.p90.as_ref().unwrap() } #[allow(unused)] - pub fn unwrap_75p(&self) -> &EagerVec { - self._75p.as_ref().unwrap() + pub fn unwrap_p75(&self) -> &EagerVec { + self.p75.as_ref().unwrap() } #[allow(unused)] pub fn unwrap_median(&self) -> &EagerVec { self.median.as_ref().unwrap() } #[allow(unused)] - pub fn unwrap_25p(&self) -> &EagerVec { - self._25p.as_ref().unwrap() + pub fn unwrap_p25(&self) -> &EagerVec { + self.p25.as_ref().unwrap() } #[allow(unused)] - pub fn unwrap_10p(&self) -> &EagerVec { - self._10p.as_ref().unwrap() + pub fn unwrap_p10(&self) -> &EagerVec { + self.p10.as_ref().unwrap() } pub fn unwrap_min(&self) -> &EagerVec { self.min.as_ref().unwrap() @@ -615,17 +615,17 @@ where if let Some(cumulative) = self.cumulative.as_ref() { v.push(cumulative.as_ref()); } - if let Some(_90p) = self._90p.as_ref() { - v.push(_90p.as_ref()); + if let Some(p90) = self.p90.as_ref() { + v.push(p90.as_ref()); } - if let Some(_75p) = self._75p.as_ref() { - v.push(_75p.as_ref()); + if let Some(p75) = self.p75.as_ref() { + v.push(p75.as_ref()); } - if let Some(_25p) = self._25p.as_ref() { - v.push(_25p.as_ref()); + if let Some(p25) = self.p25.as_ref() { + v.push(p25.as_ref()); } - if let Some(_10p) = self._10p.as_ref() { - v.push(_10p.as_ref()); + if let Some(p10) = self.p10.as_ref() { + v.push(p10.as_ref()); } v @@ -656,17 +656,17 @@ where if let Some(cumulative) = self.cumulative.as_mut() { cumulative.safe_flush(exit)?; } - if let Some(_90p) = self._90p.as_mut() { - _90p.safe_flush(exit)?; + if let Some(p90) = self.p90.as_mut() { + p90.safe_flush(exit)?; } - if let Some(_75p) = self._75p.as_mut() { - _75p.safe_flush(exit)?; + if let Some(p75) = self.p75.as_mut() { + p75.safe_flush(exit)?; } - if let Some(_25p) = self._25p.as_mut() { - _25p.safe_flush(exit)?; + if let Some(p25) = self.p25.as_mut() { + p25.safe_flush(exit)?; } - if let Some(_10p) = self._10p.as_mut() { - _10p.safe_flush(exit)?; + if let Some(p10) = self.p10.as_mut() { + p10.safe_flush(exit)?; } Ok(()) @@ -697,17 +697,17 @@ where if let Some(cumulative) = self.cumulative.as_mut() { cumulative.validate_computed_version_or_reset(Version::ZERO + version)?; } - if let Some(_90p) = self._90p.as_mut() { - _90p.validate_computed_version_or_reset(Version::ZERO + version)?; + if let Some(p90) = self.p90.as_mut() { + p90.validate_computed_version_or_reset(Version::ZERO + version)?; } - if let Some(_75p) = self._75p.as_mut() { - _75p.validate_computed_version_or_reset(Version::ZERO + version)?; + if let Some(p75) = self.p75.as_mut() { + p75.validate_computed_version_or_reset(Version::ZERO + version)?; } - if let Some(_25p) = self._25p.as_mut() { - _25p.validate_computed_version_or_reset(Version::ZERO + version)?; + if let Some(p25) = self.p25.as_mut() { + p25.validate_computed_version_or_reset(Version::ZERO + version)?; } - if let Some(_10p) = self._10p.as_mut() { - _10p.validate_computed_version_or_reset(Version::ZERO + version)?; + if let Some(p10) = self.p10.as_mut() { + p10.validate_computed_version_or_reset(Version::ZERO + version)?; } Ok(()) @@ -719,11 +719,11 @@ pub struct VecBuilderOptions { average: bool, sum: bool, max: bool, - _90p: bool, - _75p: bool, + p90: bool, + p75: bool, median: bool, - _25p: bool, - _10p: bool, + p25: bool, + p10: bool, min: bool, first: bool, last: bool, @@ -743,24 +743,24 @@ impl VecBuilderOptions { self.max } - pub fn _90p(&self) -> bool { - self._90p + pub fn p90(&self) -> bool { + self.p90 } - pub fn _75p(&self) -> bool { - self._75p + pub fn p75(&self) -> bool { + self.p75 } pub fn median(&self) -> bool { self.median } - pub fn _25p(&self) -> bool { - self._25p + pub fn p25(&self) -> bool { + self.p25 } - pub fn _10p(&self) -> bool { - self._10p + pub fn p10(&self) -> bool { + self.p10 } pub fn min(&self) -> bool { @@ -816,26 +816,26 @@ impl VecBuilderOptions { } #[allow(unused)] - pub fn add_90p(mut self) -> Self { - self._90p = true; + pub fn add_p90(mut self) -> Self { + self.p90 = true; self } #[allow(unused)] - pub fn add_75p(mut self) -> Self { - self._75p = true; + pub fn add_p75(mut self) -> Self { + self.p75 = true; self } #[allow(unused)] - pub fn add_25p(mut self) -> Self { - self._25p = true; + pub fn add_p25(mut self) -> Self { + self.p25 = true; self } #[allow(unused)] - pub fn add_10p(mut self) -> Self { - self._10p = true; + pub fn add_p10(mut self) -> Self { + self.p10 = true; self } @@ -875,26 +875,26 @@ impl VecBuilderOptions { } #[allow(unused)] - pub fn rm_90p(mut self) -> Self { - self._90p = false; + pub fn rm_p90(mut self) -> Self { + self.p90 = false; self } #[allow(unused)] - pub fn rm_75p(mut self) -> Self { - self._75p = false; + pub fn rm_p75(mut self) -> Self { + self.p75 = false; self } #[allow(unused)] - pub fn rm_25p(mut self) -> Self { - self._25p = false; + pub fn rm_p25(mut self) -> Self { + self.p25 = false; self } #[allow(unused)] - pub fn rm_10p(mut self) -> Self { - self._10p = false; + pub fn rm_p10(mut self) -> Self { + self.p10 = false; self } @@ -911,20 +911,20 @@ impl VecBuilderOptions { } pub fn add_percentiles(mut self) -> Self { - self._90p = true; - self._75p = true; + self.p90 = true; + self.p75 = true; self.median = true; - self._25p = true; - self._10p = true; + self.p25 = true; + self.p10 = true; self } pub fn remove_percentiles(mut self) -> Self { - self._90p = false; - self._75p = false; + self.p90 = false; + self.p75 = false; self.median = false; - self._25p = false; - self._10p = false; + self.p25 = false; + self.p10 = false; self } @@ -933,11 +933,11 @@ impl VecBuilderOptions { self.average, self.sum, self.max, - self._90p, - self._75p, + self.p90, + self.p75, self.median, - self._25p, - self._10p, + self.p25, + self.p10, self.min, self.first, self.last, diff --git a/crates/brk_computer/src/grouped/builder_lazy.rs b/crates/brk_computer/src/grouped/builder_lazy.rs index d167ca9e3..59b9a09c9 100644 --- a/crates/brk_computer/src/grouped/builder_lazy.rs +++ b/crates/brk_computer/src/grouped/builder_lazy.rs @@ -142,7 +142,7 @@ where }), average: options.average.then(|| { Box::new(LazyVecFrom2::init( - &maybe_suffix("average"), + &maybe_suffix("avg"), version + VERSION + Version::ZERO, source_extra .average @@ -197,7 +197,7 @@ where }), cumulative: options.cumulative.then(|| { Box::new(LazyVecFrom2::init( - &suffix("cumulative"), + &suffix("cum"), version + VERSION + Version::ZERO, source_extra.cumulative.as_ref().unwrap().boxed_clone(), len_source.clone(), diff --git a/crates/brk_computer/src/grouped/from_txindex.rs b/crates/brk_computer/src/grouped/from_txindex.rs index 9e5c6d75d..89a693378 100644 --- a/crates/brk_computer/src/grouped/from_txindex.rs +++ b/crates/brk_computer/src/grouped/from_txindex.rs @@ -319,24 +319,24 @@ impl ComputedVecsFromTxindex { exit, )?; } - if let Some(_90p) = self.height._90p.as_mut() { + if let Some(_90p) = self.height.p90.as_mut() { _90p.forced_push_at( height, Bitcoin::from( sats.height - .unwrap_90p() + .unwrap_p90() .into_iter() .unwrap_get_inner(height), ), exit, )?; } - if let Some(_75p) = self.height._75p.as_mut() { + if let Some(_75p) = self.height.p75.as_mut() { _75p.forced_push_at( height, Bitcoin::from( sats.height - .unwrap_75p() + .unwrap_p75() .into_iter() .unwrap_get_inner(height), ), @@ -355,24 +355,24 @@ impl ComputedVecsFromTxindex { exit, )?; } - if let Some(_25p) = self.height._25p.as_mut() { + if let Some(_25p) = self.height.p25.as_mut() { _25p.forced_push_at( height, Bitcoin::from( sats.height - .unwrap_25p() + .unwrap_p25() .into_iter() .unwrap_get_inner(height), ), exit, )?; } - if let Some(_10p) = self.height._10p.as_mut() { + if let Some(_10p) = self.height.p10.as_mut() { _10p.forced_push_at( height, Bitcoin::from( sats.height - .unwrap_10p() + .unwrap_p10() .into_iter() .unwrap_get_inner(height), ), @@ -502,25 +502,25 @@ impl ComputedVecsFromTxindex { exit, )?; } - if let Some(_90p) = self.height._90p.as_mut() { + if let Some(_90p) = self.height.p90.as_mut() { _90p.forced_push_at( height, price * bitcoin .height - .unwrap_90p() + .unwrap_p90() .into_iter() .unwrap_get_inner(height), exit, )?; } - if let Some(_75p) = self.height._75p.as_mut() { + if let Some(_75p) = self.height.p75.as_mut() { _75p.forced_push_at( height, price * bitcoin .height - .unwrap_75p() + .unwrap_p75() .into_iter() .unwrap_get_inner(height), exit, @@ -538,25 +538,25 @@ impl ComputedVecsFromTxindex { exit, )?; } - if let Some(_25p) = self.height._25p.as_mut() { + if let Some(_25p) = self.height.p25.as_mut() { _25p.forced_push_at( height, price * bitcoin .height - .unwrap_25p() + .unwrap_p25() .into_iter() .unwrap_get_inner(height), exit, )?; } - if let Some(_10p) = self.height._10p.as_mut() { + if let Some(_10p) = self.height.p10.as_mut() { _10p.forced_push_at( height, price * bitcoin .height - .unwrap_10p() + .unwrap_p10() .into_iter() .unwrap_get_inner(height), exit, diff --git a/crates/brk_computer/src/lib.rs b/crates/brk_computer/src/lib.rs index 1a4da8476..5fc37ad63 100644 --- a/crates/brk_computer/src/lib.rs +++ b/crates/brk_computer/src/lib.rs @@ -1,6 +1,6 @@ #![doc = include_str!("../README.md")] -use std::path::Path; +use std::{path::Path, thread}; use brk_error::Result; use brk_fetcher::Fetcher; @@ -9,19 +9,17 @@ use brk_structs::Version; use log::info; use vecdb::{AnyCollectableVec, Exit, Format}; -mod blocks; +mod chain; mod cointime; mod constants; mod fetched; mod grouped; mod indexes; mod market; -mod mining; mod price; mod stateful; mod states; mod traits; -mod transactions; mod utils; use indexes::Indexes; @@ -33,11 +31,9 @@ use states::*; pub struct Computer { pub indexes: indexes::Vecs, pub constants: constants::Vecs, - pub blocks: blocks::Vecs, - pub mining: mining::Vecs, pub market: market::Vecs, pub price: Option, - pub transactions: transactions::Vecs, + pub chain: chain::Vecs, pub stateful: stateful::Vecs, pub fetched: Option, pub cointime: cointime::Vecs, @@ -68,8 +64,6 @@ impl Computer { }); Ok(Self { - blocks: blocks::Vecs::forced_import(&computed_path, VERSION + Version::ZERO, &indexes)?, - mining: mining::Vecs::forced_import(&computed_path, VERSION + Version::ZERO, &indexes)?, constants: constants::Vecs::forced_import( &computed_path, VERSION + Version::ZERO, @@ -83,7 +77,7 @@ impl Computer { &indexes, price.as_ref(), )?, - transactions: transactions::Vecs::forced_import( + chain: chain::Vecs::forced_import( &computed_path, VERSION + Version::ZERO, indexer, @@ -115,14 +109,6 @@ impl Computer { self.constants .compute(indexer, &self.indexes, &starting_indexes, exit)?; - info!("Computing blocks..."); - self.blocks - .compute(indexer, &self.indexes, &starting_indexes, exit)?; - - info!("Computing mining..."); - self.mining - .compute(indexer, &self.indexes, &starting_indexes, exit)?; - if let Some(fetched) = self.fetched.as_mut() { info!("Computing fetched..."); fetched.compute(indexer, &self.indexes, &starting_indexes, exit)?; @@ -137,44 +123,49 @@ impl Computer { )?; } - info!("Computing transactions..."); - self.transactions.compute( - indexer, - &self.indexes, - &starting_indexes, - self.price.as_ref(), - exit, - )?; + thread::scope(|scope| -> Result<()> { + let chain = scope.spawn(|| { + info!("Computing chain..."); + self.chain.compute( + indexer, + &self.indexes, + &starting_indexes, + self.price.as_ref(), + exit, + ) + }); - if let Some(price) = self.price.as_ref() { - info!("Computing market..."); - self.market.compute( - indexer, - &self.indexes, - price, - &mut self.transactions, - &starting_indexes, - exit, - )?; - } + let market = scope.spawn(|| -> Result<()> { + if let Some(price) = self.price.as_ref() { + info!("Computing market..."); + self.market + .compute(indexer, &self.indexes, price, &starting_indexes, exit)?; + } + Ok(()) + }); + + chain.join().unwrap()?; + market.join().unwrap()?; + Ok(()) + })?; info!("Computing stateful..."); self.stateful.compute( indexer, &self.indexes, - &self.transactions, + &self.chain, self.price.as_ref(), - &self.market, &mut starting_indexes, exit, )?; + info!("Computing cointime..."); self.cointime.compute( indexer, &self.indexes, &starting_indexes, self.price.as_ref(), - &self.transactions, + &self.chain, &self.stateful, exit, )?; @@ -186,10 +177,8 @@ impl Computer { [ self.constants.vecs(), self.indexes.vecs(), - self.blocks.vecs(), - self.mining.vecs(), self.market.vecs(), - self.transactions.vecs(), + self.chain.vecs(), self.stateful.vecs(), self.cointime.vecs(), self.fetched.as_ref().map_or(vec![], |v| v.vecs()), diff --git a/crates/brk_computer/src/market.rs b/crates/brk_computer/src/market.rs index 946cb8983..c1f3738f2 100644 --- a/crates/brk_computer/src/market.rs +++ b/crates/brk_computer/src/market.rs @@ -14,7 +14,7 @@ use crate::{ use super::{ Indexes, grouped::{ComputedRatioVecsFromDateIndex, ComputedVecsFromDateIndex, VecBuilderOptions}, - indexes, transactions, + indexes, }; const VERSION: Version = Version::ZERO; @@ -23,10 +23,8 @@ const VERSION: Version = Version::ZERO; pub struct Vecs { db: Database, - pub height_to_marketcap: EagerVec, pub height_to_ath: EagerVec, pub height_to_drawdown: EagerVec, - pub indexes_to_marketcap: ComputedVecsFromDateIndex, pub indexes_to_ath: ComputedVecsFromDateIndex, pub indexes_to_drawdown: ComputedVecsFromDateIndex, pub indexes_to_days_since_ath: ComputedVecsFromDateIndex, @@ -188,11 +186,6 @@ impl Vecs { db.set_min_len(PAGE_SIZE * 1_000_000)?; Ok(Self { - height_to_marketcap: EagerVec::forced_import_compressed( - &db, - "marketcap", - version + VERSION + Version::ZERO, - )?, height_to_ath: EagerVec::forced_import_compressed( &db, "ath", @@ -203,14 +196,6 @@ impl Vecs { "drawdown", version + VERSION + Version::ZERO, )?, - indexes_to_marketcap: ComputedVecsFromDateIndex::forced_import( - &db, - "marketcap", - Source::Compute, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default().add_last(), - )?, indexes_to_ath: ComputedVecsFromDateIndex::forced_import( &db, "ath", @@ -1381,18 +1366,10 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, price: &price::Vecs, - transactions: &mut transactions::Vecs, starting_indexes: &Indexes, exit: &Exit, ) -> Result<()> { - self.compute_( - indexer, - indexes, - price, - transactions, - starting_indexes, - exit, - )?; + self.compute_(indexer, indexes, price, starting_indexes, exit)?; self.db.flush_then_punch()?; Ok(()) } @@ -1402,20 +1379,9 @@ impl Vecs { indexer: &Indexer, indexes: &indexes::Vecs, price: &price::Vecs, - transactions: &mut transactions::Vecs, starting_indexes: &Indexes, exit: &Exit, ) -> Result<()> { - self.height_to_marketcap.compute_multiply( - starting_indexes.height, - &price.chainindexes_to_close.height, - transactions - .indexes_to_subsidy - .bitcoin - .height_extra - .unwrap_cumulative(), - exit, - )?; self.height_to_ath.compute_max( starting_indexes.height, &price.chainindexes_to_high.height, @@ -1428,26 +1394,6 @@ impl Vecs { exit, )?; - self.indexes_to_marketcap.compute_all( - indexer, - indexes, - starting_indexes, - exit, - |v, _, _, starting_indexes, exit| { - v.compute_multiply( - starting_indexes.dateindex, - price.timeindexes_to_close.dateindex.as_ref().unwrap(), - transactions - .indexes_to_subsidy - .bitcoin - .dateindex - .unwrap_cumulative(), - exit, - )?; - Ok(()) - }, - )?; - self.indexes_to_ath.compute_all( indexer, indexes, @@ -2104,7 +2050,6 @@ impl Vecs { pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> { [ - self.indexes_to_marketcap.vecs(), self.indexes_to_ath.vecs(), self.indexes_to_drawdown.vecs(), self.indexes_to_days_since_ath.vecs(), @@ -2249,11 +2194,7 @@ impl Vecs { self.dca_class_2017_returns.vecs(), self.dca_class_2016_returns.vecs(), self.dca_class_2015_returns.vecs(), - vec![ - &self.height_to_marketcap, - &self.height_to_ath, - &self.height_to_drawdown, - ], + vec![&self.height_to_ath, &self.height_to_drawdown], ] .into_iter() .flatten() diff --git a/crates/brk_computer/src/mining.rs b/crates/brk_computer/src/mining.rs deleted file mode 100644 index b02024af9..000000000 --- a/crates/brk_computer/src/mining.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::path::Path; - -use brk_error::Result; -use brk_indexer::Indexer; -use brk_structs::{DifficultyEpoch, HalvingEpoch, StoredF64, Version}; -use vecdb::{AnyCollectableVec, Database, Exit, PAGE_SIZE, VecIterator}; - -use crate::grouped::Source; - -use super::{ - Indexes, - grouped::{ComputedVecsFromDateIndex, ComputedVecsFromHeight, VecBuilderOptions}, - indexes, -}; - -const VERSION: Version = Version::ZERO; - -#[derive(Clone)] -pub struct Vecs { - db: Database, - - pub indexes_to_difficulty: ComputedVecsFromHeight, - pub indexes_to_difficultyepoch: ComputedVecsFromDateIndex, - pub indexes_to_halvingepoch: ComputedVecsFromDateIndex, -} - -impl Vecs { - pub fn forced_import(parent: &Path, version: Version, indexes: &indexes::Vecs) -> Result { - let db = Database::open(&parent.join("mining"))?; - db.set_min_len(PAGE_SIZE * 1_000_000)?; - - Ok(Self { - indexes_to_difficulty: ComputedVecsFromHeight::forced_import( - &db, - "difficulty", - Source::None, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default().add_last(), - )?, - indexes_to_difficultyepoch: ComputedVecsFromDateIndex::forced_import( - &db, - "difficultyepoch", - Source::Compute, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default().add_last(), - )?, - indexes_to_halvingepoch: ComputedVecsFromDateIndex::forced_import( - &db, - "halvingepoch", - Source::Compute, - version + VERSION + Version::ZERO, - indexes, - VecBuilderOptions::default().add_last(), - )?, - - db, - }) - } - - pub fn compute( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &Indexes, - exit: &Exit, - ) -> Result<()> { - self.compute_(indexer, indexes, starting_indexes, exit)?; - self.db.flush_then_punch()?; - Ok(()) - } - - fn compute_( - &mut self, - indexer: &Indexer, - indexes: &indexes::Vecs, - starting_indexes: &Indexes, - exit: &Exit, - ) -> Result<()> { - let mut height_to_difficultyepoch_iter = indexes.height_to_difficultyepoch.into_iter(); - self.indexes_to_difficultyepoch.compute_all( - indexer, - indexes, - starting_indexes, - exit, - |vec, _, indexes, starting_indexes, exit| { - let mut height_count_iter = indexes.dateindex_to_height_count.into_iter(); - vec.compute_transform( - starting_indexes.dateindex, - &indexes.dateindex_to_first_height, - |(di, height, ..)| { - ( - di, - height_to_difficultyepoch_iter.unwrap_get_inner( - height + (*height_count_iter.unwrap_get_inner(di) - 1), - ), - ) - }, - exit, - )?; - Ok(()) - }, - )?; - - let mut height_to_halvingepoch_iter = indexes.height_to_halvingepoch.into_iter(); - self.indexes_to_halvingepoch.compute_all( - indexer, - indexes, - starting_indexes, - exit, - |vec, _, indexes, starting_indexes, exit| { - let mut height_count_iter = indexes.dateindex_to_height_count.into_iter(); - vec.compute_transform( - starting_indexes.dateindex, - &indexes.dateindex_to_first_height, - |(di, height, ..)| { - ( - di, - height_to_halvingepoch_iter.unwrap_get_inner( - height + (*height_count_iter.unwrap_get_inner(di) - 1), - ), - ) - }, - exit, - )?; - Ok(()) - }, - )?; - - self.indexes_to_difficulty.compute_rest( - indexes, - starting_indexes, - exit, - Some(&indexer.vecs.height_to_difficulty), - )?; - - Ok(()) - } - - pub fn vecs(&self) -> Vec<&dyn AnyCollectableVec> { - [ - self.indexes_to_difficulty.vecs(), - self.indexes_to_difficultyepoch.vecs(), - self.indexes_to_halvingepoch.vecs(), - ] - .into_iter() - .flatten() - .collect::>() - } -} diff --git a/crates/brk_computer/src/stateful/address_cohort.rs b/crates/brk_computer/src/stateful/address_cohort.rs index b35d74a24..26a85a107 100644 --- a/crates/brk_computer/src/stateful/address_cohort.rs +++ b/crates/brk_computer/src/stateful/address_cohort.rs @@ -11,7 +11,7 @@ use vecdb::{ use crate::{ Indexes, grouped::{ComputedVecsFromHeight, Source, VecBuilderOptions}, - indexes, market, price, + indexes, price, stateful::{ common, r#trait::{CohortVecs, DynCohortVecs}, @@ -228,9 +228,10 @@ impl CohortVecs for Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, starting_indexes: &Indexes, - market: &market::Vecs, height_to_supply: &impl AnyIterableVec, dateindex_to_supply: &impl AnyIterableVec, + height_to_market_cap: Option<&impl AnyIterableVec>, + dateindex_to_market_cap: Option<&impl AnyIterableVec>, height_to_realized_cap: Option<&impl AnyIterableVec>, dateindex_to_realized_cap: Option<&impl AnyIterableVec>, exit: &Exit, @@ -240,9 +241,10 @@ impl CohortVecs for Vecs { indexes, price, starting_indexes, - market, height_to_supply, dateindex_to_supply, + height_to_market_cap, + dateindex_to_market_cap, height_to_realized_cap, dateindex_to_realized_cap, exit, diff --git a/crates/brk_computer/src/stateful/address_cohorts.rs b/crates/brk_computer/src/stateful/address_cohorts.rs index 9f6c8b646..cc81e511d 100644 --- a/crates/brk_computer/src/stateful/address_cohorts.rs +++ b/crates/brk_computer/src/stateful/address_cohorts.rs @@ -10,7 +10,7 @@ use derive_deref::{Deref, DerefMut}; use vecdb::{AnyIterableVec, Database, Exit, Format}; use crate::{ - Indexes, indexes, market, price, + Indexes, indexes, price, stateful::{ address_cohort, r#trait::{CohortVecs, DynCohortVecs}, @@ -520,9 +520,10 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, starting_indexes: &Indexes, - market: &market::Vecs, height_to_supply: &impl AnyIterableVec, dateindex_to_supply: &impl AnyIterableVec, + height_to_market_cap: Option<&impl AnyIterableVec>, + dateindex_to_market_cap: Option<&impl AnyIterableVec>, height_to_realized_cap: Option<&impl AnyIterableVec>, dateindex_to_realized_cap: Option<&impl AnyIterableVec>, exit: &Exit, @@ -534,9 +535,10 @@ impl Vecs { indexes, price, starting_indexes, - market, height_to_supply, dateindex_to_supply, + height_to_market_cap, + dateindex_to_market_cap, height_to_realized_cap, dateindex_to_realized_cap, exit, diff --git a/crates/brk_computer/src/stateful/common.rs b/crates/brk_computer/src/stateful/common.rs index 43b1d2f8f..e365fbe82 100644 --- a/crates/brk_computer/src/stateful/common.rs +++ b/crates/brk_computer/src/stateful/common.rs @@ -14,7 +14,7 @@ use crate::{ ComputedHeightValueVecs, ComputedRatioVecsFromDateIndex, ComputedValueVecsFromDateIndex, ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, VecBuilderOptions, }, - indexes, market, price, + indexes, price, states::CohortState, }; @@ -2353,9 +2353,10 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, starting_indexes: &Indexes, - market: &market::Vecs, height_to_supply: &impl AnyIterableVec, dateindex_to_supply: &impl AnyIterableVec, + height_to_market_cap: Option<&impl AnyIterableVec>, + dateindex_to_market_cap: Option<&impl AnyIterableVec>, height_to_realized_cap: Option<&impl AnyIterableVec>, dateindex_to_realized_cap: Option<&impl AnyIterableVec>, exit: &Exit, @@ -2382,6 +2383,9 @@ impl Vecs { } if let Some(indexes_to_realized_cap) = self.indexes_to_realized_cap.as_mut() { + let height_to_market_cap = height_to_market_cap.unwrap(); + let dateindex_to_market_cap = dateindex_to_market_cap.unwrap(); + indexes_to_realized_cap.compute_rest( indexes, starting_indexes, @@ -2780,7 +2784,7 @@ impl Vecs { .compute_percentage( starting_indexes.height, self.height_to_unrealized_profit.as_ref().unwrap(), - &market.height_to_marketcap, + height_to_market_cap, exit, )?; self.height_to_unrealized_loss_relative_to_market_cap @@ -2789,7 +2793,7 @@ impl Vecs { .compute_percentage( starting_indexes.height, self.height_to_unrealized_loss.as_ref().unwrap(), - &market.height_to_marketcap, + height_to_market_cap, exit, )?; self.height_to_negative_unrealized_loss_relative_to_market_cap @@ -2798,7 +2802,7 @@ impl Vecs { .compute_percentage( starting_indexes.height, self.height_to_negative_unrealized_loss.as_ref().unwrap(), - &market.height_to_marketcap, + height_to_market_cap, exit, )?; self.height_to_net_unrealized_profit_and_loss_relative_to_market_cap @@ -2809,7 +2813,7 @@ impl Vecs { self.height_to_net_unrealized_profit_and_loss .as_ref() .unwrap(), - &market.height_to_marketcap, + height_to_market_cap, exit, )?; self.indexes_to_unrealized_profit_relative_to_market_cap @@ -2824,7 +2828,7 @@ impl Vecs { vec.compute_percentage( starting_indexes.dateindex, self.dateindex_to_unrealized_profit.as_ref().unwrap(), - market.indexes_to_marketcap.dateindex.as_ref().unwrap(), + dateindex_to_market_cap, exit, )?; Ok(()) @@ -2842,7 +2846,7 @@ impl Vecs { vec.compute_percentage( starting_indexes.dateindex, self.dateindex_to_unrealized_loss.as_ref().unwrap(), - market.indexes_to_marketcap.dateindex.as_ref().unwrap(), + dateindex_to_market_cap, exit, )?; Ok(()) @@ -2865,7 +2869,7 @@ impl Vecs { .dateindex .as_ref() .unwrap(), - market.indexes_to_marketcap.dateindex.as_ref().unwrap(), + dateindex_to_market_cap, exit, )?; Ok(()) @@ -2888,7 +2892,7 @@ impl Vecs { .dateindex .as_ref() .unwrap(), - market.indexes_to_marketcap.dateindex.as_ref().unwrap(), + dateindex_to_market_cap, exit, )?; Ok(()) @@ -3442,7 +3446,7 @@ impl Vecs { v.compute_percentage( starting_indexes.dateindex, self.indexes_to_net_realized_profit_and_loss_cumulative_30d_change.as_ref().unwrap().dateindex.as_ref().unwrap(), - market.indexes_to_marketcap.dateindex.as_ref().unwrap(), + dateindex_to_market_cap, exit, )?; Ok(()) diff --git a/crates/brk_computer/src/stateful/mod.rs b/crates/brk_computer/src/stateful/mod.rs index 59900a3b5..9fe417b77 100644 --- a/crates/brk_computer/src/stateful/mod.rs +++ b/crates/brk_computer/src/stateful/mod.rs @@ -18,15 +18,18 @@ use brk_structs::{ use log::info; use rayon::prelude::*; use vecdb::{ - AnyCollectableVec, AnyStoredVec, AnyVec, CollectableVec, Database, EagerVec, Exit, Format, - GenericStoredVec, ImportOptions, PAGE_SIZE, RawVec, Reader, Stamp, StoredIndex, VecIterator, + AnyCloneableIterableVec, AnyCollectableVec, AnyStoredVec, AnyVec, CollectableVec, Database, + EagerVec, Exit, Format, GenericStoredVec, ImportOptions, LazyVecFrom1, PAGE_SIZE, RawVec, + Reader, Stamp, StoredIndex, VecIterator, }; use crate::{ - BlockState, Indexes, SupplyState, Transacted, - grouped::{ComputedValueVecsFromHeight, VecBuilderOptions}, - grouped::{ComputedVecsFromHeight, Source}, - indexes, market, price, transactions, + BlockState, Indexes, SupplyState, Transacted, chain, + grouped::{ + ComputedValueVecsFromHeight, ComputedVecsFromDateIndex, ComputedVecsFromHeight, Source, + VecBuilderOptions, + }, + indexes, price, }; mod address_cohort; @@ -82,6 +85,8 @@ pub struct Vecs { pub indexes_to_opreturn_supply: ComputedValueVecsFromHeight, pub indexes_to_address_count: ComputedVecsFromHeight, pub indexes_to_empty_address_count: ComputedVecsFromHeight, + pub height_to_market_cap: Option>, + pub indexes_to_market_cap: Option>, } const SAVED_STAMPED_CHANGES: u16 = 10; @@ -103,6 +108,9 @@ impl Vecs { let compute_dollars = price.is_some(); + let utxo_cohorts = + utxo_cohorts::Vecs::forced_import(&db, version, format, indexes, price, &states_path)?; + Ok(Self { chain_state: RawVec::forced_import_with( ImportOptions::new(&db, "chain", version + VERSION + Version::ZERO) @@ -153,6 +161,37 @@ impl Vecs { indexes, VecBuilderOptions::default().add_last(), )?, + height_to_market_cap: compute_dollars.then(|| { + LazyVecFrom1::init( + "market_cap", + version + VERSION + Version::ONE, + utxo_cohorts + .all + .1 + .height_to_supply_value + .dollars + .as_ref() + .unwrap() + .boxed_clone(), + |height: Height, iter| { + iter.next_at(height.unwrap_to_usize()).map(|(_, value)| { + let d: Dollars = value.into_owned(); + d + }) + }, + ) + }), + indexes_to_market_cap: compute_dollars.then(|| { + ComputedVecsFromDateIndex::forced_import( + &db, + "market_cap", + Source::Compute, + version + VERSION + Version::TWO, + indexes, + VecBuilderOptions::default().add_last(), + ) + .unwrap() + }), addresstype_to_height_to_address_count: AddressTypeToHeightToAddressCount::from( ByAddressType { p2pk65: EagerVec::forced_import_compressed( @@ -377,14 +416,7 @@ impl Vecs { )?, }, ), - utxo_cohorts: utxo_cohorts::Vecs::forced_import( - &db, - version, - format, - indexes, - price, - &states_path, - )?, + utxo_cohorts, address_cohorts: address_cohorts::Vecs::forced_import( &db, version, @@ -445,22 +477,13 @@ impl Vecs { &mut self, indexer: &Indexer, indexes: &indexes::Vecs, - transactions: &transactions::Vecs, + chain: &chain::Vecs, price: Option<&price::Vecs>, - market: &market::Vecs, // Must take ownership as its indexes will be updated for this specific function starting_indexes: &mut Indexes, exit: &Exit, ) -> Result<()> { - self.compute_( - indexer, - indexes, - transactions, - price, - market, - starting_indexes, - exit, - )?; + self.compute_(indexer, indexes, chain, price, starting_indexes, exit)?; self.db.flush_then_punch()?; Ok(()) } @@ -470,9 +493,8 @@ impl Vecs { &mut self, indexer: &Indexer, indexes: &indexes::Vecs, - transactions: &transactions::Vecs, + chain: &chain::Vecs, price: Option<&price::Vecs>, - market: &market::Vecs, // Must take ownership as its indexes will be updated for this specific function starting_indexes: &mut Indexes, exit: &Exit, @@ -487,8 +509,8 @@ impl Vecs { let height_to_first_p2traddressindex = &indexer.vecs.height_to_first_p2traddressindex; let height_to_first_p2wpkhaddressindex = &indexer.vecs.height_to_first_p2wpkhaddressindex; let height_to_first_p2wshaddressindex = &indexer.vecs.height_to_first_p2wshaddressindex; - let height_to_output_count = transactions.indexes_to_output_count.height.unwrap_sum(); - let height_to_input_count = transactions.indexes_to_input_count.height.unwrap_sum(); + let height_to_output_count = chain.indexes_to_output_count.height.unwrap_sum(); + let height_to_input_count = chain.indexes_to_input_count.height.unwrap_sum(); let inputindex_to_outputindex = &indexer.vecs.inputindex_to_outputindex; let outputindex_to_value = &indexer.vecs.outputindex_to_value; let txindex_to_height = &indexes.txindex_to_height; @@ -496,7 +518,7 @@ impl Vecs { let outputindex_to_txindex = &indexes.outputindex_to_txindex; let outputindex_to_outputtype = &indexer.vecs.outputindex_to_outputtype; let outputindex_to_typeindex = &indexer.vecs.outputindex_to_typeindex; - let height_to_unclaimed_rewards = transactions + let height_to_unclaimed_rewards = chain .indexes_to_unclaimed_rewards .sats .height @@ -1331,6 +1353,33 @@ impl Vecs { self.address_cohorts .compute_rest_part1(indexer, indexes, price, starting_indexes, exit)?; + if let Some(indexes_to_market_cap) = self.indexes_to_market_cap.as_mut() { + indexes_to_market_cap.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |v, _, _, starting_indexes, exit| { + v.compute_transform( + starting_indexes.dateindex, + self.utxo_cohorts + .all + .1 + .indexes_to_supply + .dollars + .as_ref() + .unwrap() + .dateindex + .as_ref() + .unwrap(), + |(i, v, ..)| (i, v), + exit, + )?; + Ok(()) + }, + )?; + } + info!("Computing rest part 2..."); let height_to_supply = &self @@ -1348,6 +1397,11 @@ impl Vecs { .bitcoin .dateindex .clone(); + let height_to_market_cap = self.height_to_market_cap.clone(); + let dateindex_to_market_cap = self + .indexes_to_market_cap + .as_ref() + .map(|v| v.dateindex.as_ref().unwrap().clone()); let height_to_realized_cap = self.utxo_cohorts.all.1.height_to_realized_cap.clone(); let dateindex_to_realized_cap = self .utxo_cohorts @@ -1357,6 +1411,8 @@ impl Vecs { .as_ref() .map(|v| v.dateindex.unwrap_last().clone()); let dateindex_to_supply_ref = dateindex_to_supply.as_ref().unwrap(); + let height_to_market_cap_ref = height_to_market_cap.as_ref(); + let dateindex_to_market_cap_ref = dateindex_to_market_cap.as_ref(); let height_to_realized_cap_ref = height_to_realized_cap.as_ref(); let dateindex_to_realized_cap_ref = dateindex_to_realized_cap.as_ref(); @@ -1365,9 +1421,10 @@ impl Vecs { indexes, price, starting_indexes, - market, height_to_supply, dateindex_to_supply_ref, + height_to_market_cap_ref, + dateindex_to_market_cap_ref, height_to_realized_cap_ref, dateindex_to_realized_cap_ref, exit, @@ -1378,9 +1435,10 @@ impl Vecs { indexes, price, starting_indexes, - market, height_to_supply, dateindex_to_supply_ref, + height_to_market_cap_ref, + dateindex_to_market_cap_ref, height_to_realized_cap_ref, dateindex_to_realized_cap_ref, exit, @@ -1790,6 +1848,9 @@ impl Vecs { self.indexes_to_address_count.vecs(), self.indexes_to_empty_address_count.vecs(), self.addresstype_to_indexes_to_address_count.vecs(), + self.indexes_to_market_cap + .as_ref() + .map_or(vec![], |v| v.vecs()), self.addresstype_to_indexes_to_empty_address_count.vecs(), self.addresstype_to_height_to_address_count .as_typed_vec() @@ -1801,6 +1862,9 @@ impl Vecs { .into_iter() .map(|(_, v)| v as &dyn AnyCollectableVec) .collect::>(), + self.height_to_market_cap + .as_ref() + .map_or(vec![], |v| vec![v]), vec![ &self.height_to_unspendable_supply, &self.height_to_opreturn_supply, diff --git a/crates/brk_computer/src/stateful/trait.rs b/crates/brk_computer/src/stateful/trait.rs index f5bf37835..53404da15 100644 --- a/crates/brk_computer/src/stateful/trait.rs +++ b/crates/brk_computer/src/stateful/trait.rs @@ -3,7 +3,7 @@ use brk_indexer::Indexer; use brk_structs::{Bitcoin, DateIndex, Dollars, Height, Version}; use vecdb::{AnyCollectableVec, AnyIterableVec, Exit}; -use crate::{Indexes, indexes, market, price}; +use crate::{Indexes, indexes, price}; pub trait DynCohortVecs: Send + Sync { fn min_height_vecs_len(&self) -> usize; @@ -54,9 +54,10 @@ pub trait CohortVecs: DynCohortVecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, starting_indexes: &Indexes, - market: &market::Vecs, height_to_supply: &impl AnyIterableVec, dateindex_to_supply: &impl AnyIterableVec, + height_to_market_cap: Option<&impl AnyIterableVec>, + dateindex_to_market_cap: Option<&impl AnyIterableVec>, height_to_realized_cap: Option<&impl AnyIterableVec>, dateindex_to_realized_cap: Option<&impl AnyIterableVec>, exit: &Exit, diff --git a/crates/brk_computer/src/stateful/utxo_cohort.rs b/crates/brk_computer/src/stateful/utxo_cohort.rs index 9d02a38a1..ba91852a7 100644 --- a/crates/brk_computer/src/stateful/utxo_cohort.rs +++ b/crates/brk_computer/src/stateful/utxo_cohort.rs @@ -6,7 +6,7 @@ use brk_structs::{Bitcoin, DateIndex, Dollars, Height, Version}; use vecdb::{AnyCollectableVec, AnyIterableVec, Database, Exit, Format}; use crate::{ - Indexes, UTXOCohortState, indexes, market, price, + Indexes, UTXOCohortState, indexes, price, stateful::{ common, r#trait::{CohortVecs, DynCohortVecs}, @@ -158,9 +158,10 @@ impl CohortVecs for Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, starting_indexes: &Indexes, - market: &market::Vecs, height_to_supply: &impl AnyIterableVec, dateindex_to_supply: &impl AnyIterableVec, + height_to_market_cap: Option<&impl AnyIterableVec>, + dateindex_to_market_cap: Option<&impl AnyIterableVec>, height_to_realized_cap: Option<&impl AnyIterableVec>, dateindex_to_realized_cap: Option<&impl AnyIterableVec>, exit: &Exit, @@ -170,9 +171,10 @@ impl CohortVecs for Vecs { indexes, price, starting_indexes, - market, height_to_supply, dateindex_to_supply, + height_to_market_cap, + dateindex_to_market_cap, height_to_realized_cap, dateindex_to_realized_cap, exit, diff --git a/crates/brk_computer/src/stateful/utxo_cohorts.rs b/crates/brk_computer/src/stateful/utxo_cohorts.rs index 41485485a..a40760b0a 100644 --- a/crates/brk_computer/src/stateful/utxo_cohorts.rs +++ b/crates/brk_computer/src/stateful/utxo_cohorts.rs @@ -11,7 +11,7 @@ use derive_deref::{Deref, DerefMut}; use vecdb::{AnyIterableVec, Database, Exit, Format, StoredIndex}; use crate::{ - Indexes, indexes, market, price, + Indexes, indexes, price, stateful::r#trait::DynCohortVecs, states::{BlockState, Transacted}, }; @@ -1754,9 +1754,10 @@ impl Vecs { indexes: &indexes::Vecs, price: Option<&price::Vecs>, starting_indexes: &Indexes, - market: &market::Vecs, height_to_supply: &impl AnyIterableVec, dateindex_to_supply: &impl AnyIterableVec, + height_to_market_cap: Option<&impl AnyIterableVec>, + dateindex_to_market_cap: Option<&impl AnyIterableVec>, height_to_realized_cap: Option<&impl AnyIterableVec>, dateindex_to_realized_cap: Option<&impl AnyIterableVec>, exit: &Exit, @@ -1768,9 +1769,10 @@ impl Vecs { indexes, price, starting_indexes, - market, height_to_supply, dateindex_to_supply, + height_to_market_cap, + dateindex_to_market_cap, height_to_realized_cap, dateindex_to_realized_cap, exit, diff --git a/crates/brk_mcp/README.md b/crates/brk_mcp/README.md index 1cc1cda5a..b674aada4 100644 --- a/crates/brk_mcp/README.md +++ b/crates/brk_mcp/README.md @@ -4,6 +4,8 @@ `brk_mcp` provides a Model Context Protocol server that enables Large Language Models (LLMs) to access Bitcoin blockchain data through BRK's interface layer. It implements the MCP specification to expose BRK's analytics capabilities as tools that LLMs can call. +Try it out: [https://bitview.space/mcp](https://bitview.space/mcp) + ## What it provides - **MCP Server Implementation**: Standards-compliant Model Context Protocol server diff --git a/crates/brk_server/README.md b/crates/brk_server/README.md index 34dbc8719..eb0b7a58a 100644 --- a/crates/brk_server/README.md +++ b/crates/brk_server/README.md @@ -145,7 +145,7 @@ curl "/api/vecs/month-to-supply" **CSV Format**: ```csv -index,close,supply,feerate +index,close,supply,fee_rate 0,42.5,1500,0.05 1,43.1,1520,0.052 2,44.2,1480,0.048 diff --git a/crates/brk_structs/src/structs/date.rs b/crates/brk_structs/src/structs/date.rs index 2fb3fca47..7fbda2dcd 100644 --- a/crates/brk_structs/src/structs/date.rs +++ b/crates/brk_structs/src/structs/date.rs @@ -47,6 +47,10 @@ impl Date { pub fn into_jiff(self) -> Date_ { self.into() } + + pub fn today() -> Self { + Self::from(Timestamp::now()) + } } impl Default for Date { diff --git a/crates/brk_structs/src/structs/feerate.rs b/crates/brk_structs/src/structs/feerate.rs index 53906bd36..5e1705462 100644 --- a/crates/brk_structs/src/structs/feerate.rs +++ b/crates/brk_structs/src/structs/feerate.rs @@ -12,9 +12,9 @@ use super::{Sats, StoredU64}; #[derive( Debug, Clone, Copy, Serialize, FromBytes, Immutable, IntoBytes, KnownLayout, StoredCompressed, )] -pub struct Feerate(f64); +pub struct FeeRate(f64); -impl From<(Sats, StoredU64)> for Feerate { +impl From<(Sats, StoredU64)> for FeeRate { fn from((sats, vsize): (Sats, StoredU64)) -> Self { let sats = u64::from(sats); let vsize = u64::from(vsize); @@ -22,44 +22,44 @@ impl From<(Sats, StoredU64)> for Feerate { } } -impl From for Feerate { +impl From for FeeRate { fn from(value: f64) -> Self { Self(value) } } -impl From for f64 { - fn from(value: Feerate) -> Self { +impl From for f64 { + fn from(value: FeeRate) -> Self { value.0 } } -impl Add for Feerate { +impl Add for FeeRate { type Output = Self; fn add(self, rhs: Self) -> Self::Output { Self(self.0 + rhs.0) } } -impl AddAssign for Feerate { +impl AddAssign for FeeRate { fn add_assign(&mut self, rhs: Self) { *self = *self + rhs } } -impl Div for Feerate { +impl Div for FeeRate { type Output = Self; fn div(self, rhs: usize) -> Self::Output { Self(self.0 / rhs as f64) } } -impl From for Feerate { +impl From for FeeRate { fn from(value: usize) -> Self { Self(value as f64) } } -impl PartialEq for Feerate { +impl PartialEq for FeeRate { fn eq(&self, other: &Self) -> bool { match (self.0.is_nan(), other.0.is_nan()) { (true, true) => true, @@ -70,17 +70,17 @@ impl PartialEq for Feerate { } } -impl Eq for Feerate {} +impl Eq for FeeRate {} #[allow(clippy::derive_ord_xor_partial_ord)] -impl PartialOrd for Feerate { +impl PartialOrd for FeeRate { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } #[allow(clippy::derive_ord_xor_partial_ord)] -impl Ord for Feerate { +impl Ord for FeeRate { fn cmp(&self, other: &Self) -> Ordering { match (self.0.is_nan(), other.0.is_nan()) { (true, true) => Ordering::Equal, diff --git a/crates/brk_structs/src/structs/stored_f64.rs b/crates/brk_structs/src/structs/stored_f64.rs index 23bb4be09..1c6d98825 100644 --- a/crates/brk_structs/src/structs/stored_f64.rs +++ b/crates/brk_structs/src/structs/stored_f64.rs @@ -36,6 +36,12 @@ impl From for StoredF64 { } } +impl From for StoredF64 { + fn from(value: f32) -> Self { + Self(value as f64) + } +} + impl From for StoredF64 { fn from(value: usize) -> Self { Self(value as f64) @@ -88,6 +94,12 @@ impl From for f64 { } } +impl From for f32 { + fn from(value: StoredF64) -> Self { + value.0 as f32 + } +} + impl From for StoredF64 { fn from(value: Dollars) -> Self { Self(f64::from(value)) diff --git a/crates/brk_structs/src/structs/timestamp.rs b/crates/brk_structs/src/structs/timestamp.rs index d0a436f44..b10ffe765 100644 --- a/crates/brk_structs/src/structs/timestamp.rs +++ b/crates/brk_structs/src/structs/timestamp.rs @@ -69,6 +69,18 @@ impl Timestamp { pub fn is_more_than_hour(&self) -> bool { self.0 >= ONE_HOUR_IN_SEC } + + pub fn now() -> Self { + Self::from(jiff::Timestamp::now()) + } + + pub fn day_completion(&self) -> f64 { + let rounded = jiff::Timestamp::from(Self::from(Date::from(*self))); + ONE_DAY_IN_SEC_F64 + / jiff::Timestamp::from(*self) + .duration_since(rounded) + .as_secs_f64() + } } impl From for Timestamp { diff --git a/websites/bitview/packages/lightweight-charts/wrapper.js b/websites/bitview/packages/lightweight-charts/wrapper.js index 1187c9fd7..985f8efc6 100644 --- a/websites/bitview/packages/lightweight-charts/wrapper.js +++ b/websites/bitview/packages/lightweight-charts/wrapper.js @@ -997,13 +997,13 @@ function numberToShortUSFormat(value, digits) { return numberToUSFormat(value, Math.min(1, digits || 10)); } else if (absoluteValue < 1_000_000) { return numberToUSFormat(value, 0); - } else if (absoluteValue >= 900_000_000_000_000_000) { + } else if (absoluteValue >= 900_000_000_000_000_000_000_000) { return "Inf."; } const log = Math.floor(Math.log10(absoluteValue) - 6); - const suffices = ["M", "B", "T", "P", "E"]; + const suffices = ["M", "B", "T", "P", "E", "Z"]; const letterIndex = Math.floor(log / 3); const letter = suffices[letterIndex]; diff --git a/websites/bitview/scripts/main.js b/websites/bitview/scripts/main.js index 040bde8ec..7f4b7e067 100644 --- a/websites/bitview/scripts/main.js +++ b/websites/bitview/scripts/main.js @@ -44,6 +44,7 @@ * "%self" | * "%all" | * "Years" | + * "H/s" | * "Locktime" | * "sat/vB" | * "%pnl" | @@ -732,13 +733,15 @@ function createUtils() { id.endsWith("stack") || (id.endsWith("value") && !id.includes("realized")) || ((id.includes("coinbase") || - (id.includes("fee") && !id.includes("feerate")) || + id.includes("fee") || id.includes("subsidy") || id.includes("rewards")) && !( id.startsWith("is_") || - id.includes("in_btc") || - id.includes("in_usd") + id.includes("_btc") || + id.includes("_usd") || + id.includes("fee_rate") || + id.endsWith("dominance") ))) ) { if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`); @@ -755,8 +758,8 @@ function createUtils() { id === "low" || id === "close" || id === "open" || - id === "marketcap" || - id.includes("in_usd") || + id === "market_cap" || + id.includes("_usd") || id.includes("cointime_value") || id.startsWith("price") || id.endsWith("price_paid") || @@ -768,7 +771,8 @@ function createUtils() { !id.includes("ratio") && !id.includes("relative_to")) || ((id.endsWith("sma") || id.includes("sma_x") || id.endsWith("ema")) && - !id.includes("ratio")) || + !id.includes("ratio") && + !id.includes("hash_rate")) || id === "ath") ) { if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`); @@ -796,14 +800,17 @@ function createUtils() { id.endsWith("p98") || id.endsWith("p99"))) || id.includes("liveliness") || - id.includes("vaultedness") + id.includes("vaultedness") || + id == "puell_multiple" ) { if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`); unit = "Ratio"; } if ( (!unit || thoroughUnitCheck) && - (id === "drawdown" || id.endsWith("oscillator")) + (id === "drawdown" || + id.endsWith("oscillator") || + id.endsWith("dominance")) ) { if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`); unit = "percentage"; @@ -818,7 +825,14 @@ function createUtils() { if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`); unit = "Count"; } - if ((!unit || thoroughUnitCheck) && id.includes("feerate")) { + if ( + (!unit || thoroughUnitCheck) && + (id.startsWith("hash_rate") || id.endsWith("as_hash")) + ) { + if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`); + unit = "H/s"; + } + if ((!unit || thoroughUnitCheck) && id.includes("fee_rate")) { if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`); unit = "sat/vB"; } diff --git a/websites/bitview/scripts/options.js b/websites/bitview/scripts/options.js index 5a970ab99..2483f732f 100644 --- a/websites/bitview/scripts/options.js +++ b/websites/bitview/scripts/options.js @@ -157,24 +157,24 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { * @typedef {"_30d_change"} _30DChageSubString * @typedef {StartsWith} CumulativeVecId * @typedef {ExcludeSubstring, _30DChageSubString>} CumulativeVecIdBase - * @typedef {"_average"} AverageSuffix + * @typedef {"_avg"} AverageSuffix * @typedef {EndsWith} VecIdAverage * @typedef {WithoutSuffix} VecIdAverageBase * @typedef {"_median"} MedianSuffix * @typedef {EndsWith} VecIdMedian * @typedef {WithoutSuffix} VecIdMedianBase - * @typedef {"_90p"} _90pSuffix - * @typedef {EndsWith<_90pSuffix>} VecId90p - * @typedef {WithoutSuffix} VecId90pBase - * @typedef {"_75p"} _75pSuffix - * @typedef {EndsWith<_75pSuffix>} VecId75p - * @typedef {WithoutSuffix} VecId75pBase - * @typedef {"_25p"} _25pSuffix - * @typedef {EndsWith<_25pSuffix>} VecId25p - * @typedef {WithoutSuffix} VecId25pBase - * @typedef {"_10p"} _10pSuffix - * @typedef {EndsWith<_10pSuffix>} VecId10p - * @typedef {WithoutSuffix} VecId10pBase + * @typedef {"_p90"} _p90Suffix + * @typedef {EndsWith<_p90Suffix>} VecIdp90 + * @typedef {WithoutSuffix} VecIdp90Base + * @typedef {"_p75"} _p75Suffix + * @typedef {EndsWith<_p75Suffix>} VecIdp75 + * @typedef {WithoutSuffix} VecIdp75Base + * @typedef {"_p25"} _p25Suffix + * @typedef {EndsWith<_p25Suffix>} VecIdp25 + * @typedef {WithoutSuffix} VecIdp25Base + * @typedef {"_p10"} _p10Suffix + * @typedef {EndsWith<_p10Suffix>} VecIdp10 + * @typedef {WithoutSuffix} VecIdp10Base * @typedef {"_max"} MaxSuffix * @typedef {EndsWith} VecIdMax * @typedef {WithoutSuffix} VecIdMaxBase @@ -1152,7 +1152,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { */ function createAverageSeries({ concat, title = "" }) { return /** @satisfies {AnyFetchedSeriesBlueprint} */ ({ - key: `${concat}_average`, + key: `${concat}_avg`, title: `Average ${title}`, }); } @@ -1191,10 +1191,11 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { * @param {Color} [args.color] */ function createSumSeries({ key, title = "", color }) { + const sumKey = `${key}_sum`; return /** @satisfies {AnyFetchedSeriesBlueprint} */ ({ - key: key in vecIdToIndexes ? key : `${key}_sum`, + key: `${key}_sum` in vecIdToIndexes ? sumKey : key, title: `Sum ${title}`, - color: color ?? colors.orange, + color: color ?? colors.red, }); } @@ -1206,16 +1207,16 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { */ function createCumulativeSeries({ concat, title = "", color }) { return /** @satisfies {AnyFetchedSeriesBlueprint} */ ({ - key: `${concat}_cumulative`, + key: `${concat}_cum`, title: `Cumulative ${title}`, - color: color ?? colors.red, + color: color ?? colors.cyan, defaultActive: false, }); } /** * @param {Object} args - * @param {VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} args.concat + * @param {VecIdMinBase & VecIdMaxBase & VecIdp90Base & VecIdp75Base & VecIdMedianBase & VecIdp25Base & VecIdp10Base} args.concat * @param {string} [args.title] */ function createMinMaxPercentilesSeries({ concat, title = "" }) { @@ -1239,26 +1240,26 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { defaultActive: false, }, { - key: `${concat}_75p`, - title: `75p ${title}`, + key: `${concat}_p75`, + title: `p75 ${title}`, color: colors.red, defaultActive: false, }, { - key: `${concat}_25p`, - title: `25p ${title}`, + key: `${concat}_p25`, + title: `p25 ${title}`, color: colors.yellow, defaultActive: false, }, { - key: `${concat}_90p`, - title: `90p ${title}`, + key: `${concat}_p90`, + title: `p90 ${title}`, color: colors.rose, defaultActive: false, }, { - key: `${concat}_10p`, - title: `10p ${title}`, + key: `${concat}_p10`, + title: `p10 ${title}`, color: colors.lime, defaultActive: false, }, @@ -1266,7 +1267,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { } /** - * @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key + * @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecIdp90Base & VecIdp75Base & VecIdMedianBase & VecIdp25Base & VecIdp10Base} key */ function createSumCumulativeMinMaxPercentilesSeries(key) { return [ @@ -1276,7 +1277,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { } /** - * @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key + * @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecIdp90Base & VecIdp75Base & VecIdMedianBase & VecIdp25Base & VecIdp10Base} key */ function createAverageSumCumulativeMinMaxPercentilesSeries(key) { return [ @@ -1287,7 +1288,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { /** * @param {Object} args - * @param {VecId & VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} args.key + * @param {VecId & VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecIdp90Base & VecIdp75Base & VecIdMedianBase & VecIdp25Base & VecIdp10Base} args.key * @param {string} args.name */ function createBaseAverageSumCumulativeMinMaxPercentilesSeries({ @@ -2177,7 +2178,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color: colors.green, }), createBaseSeries({ - key: `${fixKey(args.key)}realized_profit_cumulative`, + key: `${fixKey(args.key)}realized_profit_cum`, name: "Cumulative Profit", color: colors.green, defaultActive: false, @@ -2189,7 +2190,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { defaultActive: false, }), createBaseSeries({ - key: `${fixKey(args.key)}realized_loss_cumulative`, + key: `${fixKey(args.key)}realized_loss_cum`, name: "Cumulative Loss", color: colors.red, defaultActive: false, @@ -2200,9 +2201,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color: colors.red, }), createBaseSeries({ - key: `${fixKey( - args.key, - )}negative_realized_loss_cumulative`, + key: `${fixKey(args.key)}negative_realized_loss_cum`, name: "Cumulative Negative Loss", color: colors.red, defaultActive: false, @@ -2243,9 +2242,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { }), /** @satisfies {FetchedBaselineSeriesBlueprint} */ ({ type: "Baseline", - key: `${fixKey( - key, - )}net_realized_profit_and_loss_cumulative`, + key: `${fixKey(key)}net_realized_profit_and_loss_cum`, title: "Cumulative", defaultActive: false, }), @@ -2476,7 +2473,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { const key = fixKey(_key); return /** @type {const} */ ([ createBaseSeries({ - key: `${key}realized_profit_cumulative`, + key: `${key}realized_profit_cum`, name, color, }), @@ -2490,7 +2487,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { const key = fixKey(_key); return /** @type {const} */ ([ createBaseSeries({ - key: `${key}realized_loss_cumulative`, + key: `${key}realized_loss_cum`, name, color, }), @@ -2506,7 +2503,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { type: "Baseline", key: `${fixKey( key, - )}net_realized_profit_and_loss_cumulative`, + )}net_realized_profit_and_loss_cum`, title: name, color, defaultActive: false, @@ -2946,7 +2943,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color, }), createBaseSeries({ - key: `${key}coinblocks_destroyed_cumulative`, + key: `${key}coinblocks_destroyed_cum`, name: useGroupName ? name : "cumulative", color, defaultActive: false, @@ -2957,7 +2954,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color, }), createBaseSeries({ - key: `${key}coindays_destroyed_cumulative`, + key: `${key}coindays_destroyed_cum`, name: useGroupName ? name : "cumulative", color, defaultActive: false, @@ -2994,7 +2991,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { title: "Market Capitalization", bottom: [ createBaseSeries({ - key: "marketcap", + key: "market_cap", name: "Capitalization", }), ], @@ -3296,7 +3293,15 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { title: "Circulating Supply", bottom: [ createBaseSeries({ - key: "subsidy_in_btc_cumulative", + key: "supply", + name: "Mined", + }), + createBaseSeries({ + key: "supply_in_btc", + name: "Mined", + }), + createBaseSeries({ + key: "supply_in_usd", name: "Mined", }), ], @@ -3327,6 +3332,10 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { key: "subsidy", name: "Subsidy", }), + createBaseSeries({ + key: "subsidy_usd_1y_sma", + name: "1y sma", + }), ...createBaseAverageSumCumulativeMinMaxPercentilesSeries({ key: "subsidy_in_btc", name: "Subsidy", @@ -3350,6 +3359,22 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { ), ], }, + { + name: "Dominance", + title: "Reward Dominance", + bottom: [ + createBaseSeries({ + key: "fee_dominance", + name: "Fee", + color: colors.amber, + }), + createBaseSeries({ + key: "subsidy_dominance", + name: "Subsidy", + color: colors.red, + }), + ], + }, { name: "Unclaimed Rewards", title: "Unclaimed Rewards", @@ -3369,9 +3394,19 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { name: "Feerate", title: "Transaction Fee Rate", bottom: [ - createAverageSeries({ concat: "feerate" }), + createAverageSeries({ concat: "fee_rate" }), ...createMinMaxPercentilesSeries({ - concat: "feerate", + concat: "fee_rate", + }), + ], + }, + { + name: "Puell multiple", + title: "Puell multiple", + bottom: [ + createBaseSeries({ + key: "puell_multiple", + name: "Multiple", }), ], }, @@ -3385,6 +3420,50 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { }), ], }, + { + name: "hash", + tree: [ + { + name: "Rate", + title: "Hash Rate", + bottom: [ + createBaseSeries({ + key: "hash_rate", + name: "Raw", + }), + createBaseSeries({ + key: "hash_rate_1w_sma", + name: "1w sma", + color: colors.red, + defaultActive: false, + }), + createBaseSeries({ + key: "hash_rate_1m_sma", + name: "1m sma", + color: colors.pink, + defaultActive: false, + }), + createBaseSeries({ + key: "hash_rate_2m_sma", + name: "2m sma", + color: colors.purple, + defaultActive: false, + }), + createBaseSeries({ + key: "hash_rate_1y_sma", + name: "1y sma", + color: colors.indigo, + defaultActive: false, + }), + createBaseSeries({ + key: "difficulty_as_hash", + name: "difficulty", + color: colors.default, + }), + ], + }, + ], + }, { name: "Difficulty Epoch", title: "Difficulty Epoch", @@ -3750,7 +3829,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { name: "sum", }), createBaseSeries({ - key: "opreturn_count_cumulative", + key: "opreturn_count_cum", name: "cumulative", color: colors.red, }), @@ -3815,7 +3894,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { title: "Compare Cointime Capitalizations", bottom: [ createBaseSeries({ - key: `marketcap`, + key: `market_cap`, name: "Market", color: colors.default, }), @@ -3844,7 +3923,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color, }), createBaseSeries({ - key: `marketcap`, + key: `market_cap`, name: "Market", color: colors.default, }), @@ -3924,7 +4003,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color: colors.red, }), createBaseSeries({ - key: "coinblocks_destroyed_cumulative", + key: "coinblocks_destroyed_cum", name: "Cumulative Destroyed", color: colors.red, defaultActive: false, @@ -3935,7 +4014,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color: colors.orange, }), createBaseSeries({ - key: "coinblocks_created_cumulative", + key: "coinblocks_created_cum", name: "Cumulative created", color: colors.orange, defaultActive: false, @@ -3946,7 +4025,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) { color: colors.green, }), createBaseSeries({ - key: "coinblocks_stored_cumulative", + key: "coinblocks_stored_cum", name: "Cumulative stored", color: colors.green, defaultActive: false,