diff --git a/crates/brk_cli/README.md b/crates/brk_cli/README.md index 1004e5fc3..a3f4bbea8 100644 --- a/crates/brk_cli/README.md +++ b/crates/brk_cli/README.md @@ -59,16 +59,28 @@ To be determined - Unix based operating system (Mac OS or Linux) - Ubuntu users need to install `open-ssl` via `sudo apt install libssl-dev pkg-config` -## Install +## Download + +### Binaries + +You can find a pre-built binary for your operating system on the releases page ([link](https://github.com/bitcoinresearchkit/brk/releases/latest)). + +### Cargo ```bash +# Install cargo install brk # or `cargo install brk_cli`, the result is the same + +# Update +cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed ``` -## Update +### Source ```bash -cargo install brk # or `cargo install-update -a` if you have `cargo-update` installed +git clone https://github.com/bitcoinresearchkit/brk.git +cd brk/crates/brk +cargo run -r ``` ## Usage diff --git a/crates/brk_cli/src/run.rs b/crates/brk_cli/src/run.rs index ab10f1b99..00ce5463d 100644 --- a/crates/brk_cli/src/run.rs +++ b/crates/brk_cli/src/run.rs @@ -58,7 +58,25 @@ pub fn run(config: RunConfig) -> color_eyre::Result<()> { }; if config.process() { + let wait_for_synced_node = || -> color_eyre::Result<()> { + let is_synced = || -> color_eyre::Result { + let info = rpc.get_blockchain_info()?; + Ok(info.headers == info.blocks) + }; + + if !is_synced()? { + info!("Waiting for node to be synced..."); + while !is_synced()? { + sleep(Duration::from_secs(1)) + } + } + + Ok(()) + }; + loop { + wait_for_synced_node()?; + let block_count = rpc.get_block_count()?; info!("{} blocks found.", block_count + 1); diff --git a/crates/brk_computer/src/storage/vecs/blocks.rs b/crates/brk_computer/src/storage/vecs/blocks.rs index 864aefa4e..7a428a6b8 100644 --- a/crates/brk_computer/src/storage/vecs/blocks.rs +++ b/crates/brk_computer/src/storage/vecs/blocks.rs @@ -1,6 +1,6 @@ use std::{fs, path::Path}; -use brk_core::{CheckedSub, StoredU32, StoredU64, StoredUsize, Timestamp, Weight}; +use brk_core::{CheckedSub, Height, StoredU32, StoredU64, StoredUsize, Timestamp, Weight}; use brk_exit::Exit; use brk_indexer::Indexer; use brk_parser::bitcoin; @@ -8,15 +8,18 @@ use brk_vec::{Compressed, Version}; use super::{ Indexes, + base::ComputedVec, grouped::{ComputedVecsFromHeight, StorableVecGeneatorOptions}, indexes, }; #[derive(Clone)] pub struct Vecs { + pub height_to_interval: ComputedVec, pub indexes_to_block_interval: ComputedVecsFromHeight, pub indexes_to_block_count: ComputedVecsFromHeight, pub indexes_to_block_weight: ComputedVecsFromHeight, + pub height_to_vbytes: ComputedVec, pub indexes_to_block_vbytes: ComputedVecsFromHeight, pub indexes_to_block_size: ComputedVecsFromHeight, } @@ -26,10 +29,15 @@ impl Vecs { fs::create_dir_all(path)?; Ok(Self { + height_to_interval: ComputedVec::forced_import( + &path.join("height_to_interval"), + Version::ZERO, + compressed, + )?, indexes_to_block_interval: ComputedVecsFromHeight::forced_import( path, "block_interval", - true, + false, Version::ZERO, compressed, StorableVecGeneatorOptions::default() @@ -61,10 +69,15 @@ impl Vecs { compressed, StorableVecGeneatorOptions::default().add_sum().add_total(), )?, + height_to_vbytes: ComputedVec::forced_import( + &path.join("height_to_vbytes"), + Version::ZERO, + compressed, + )?, indexes_to_block_vbytes: ComputedVecsFromHeight::forced_import( path, "block_vbytes", - true, + false, Version::ZERO, compressed, StorableVecGeneatorOptions::default().add_sum().add_total(), @@ -79,30 +92,26 @@ impl Vecs { starting_indexes: &Indexes, exit: &Exit, ) -> color_eyre::Result<()> { - self.indexes_to_block_interval.compute_all( - indexer, + self.height_to_interval.compute_transform( + starting_indexes.height, + indexer.mut_vecs().height_to_timestamp.mut_vec(), + |(height, timestamp, _, height_to_timestamp)| { + let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| { + let prev_timestamp = *height_to_timestamp.cached_get(prev_h).unwrap().unwrap(); + timestamp + .checked_sub(prev_timestamp) + .unwrap_or(Timestamp::ZERO) + }); + (height, interval) + }, + exit, + )?; + + self.indexes_to_block_interval.compute_rest( indexes, starting_indexes, exit, - |v, indexer, _, starting_indexes, exit| { - let indexer_vecs = indexer.mut_vecs(); - - v.compute_transform( - starting_indexes.height, - indexer_vecs.height_to_timestamp.mut_vec(), - |(height, timestamp, _, height_to_timestamp)| { - let interval = height.decremented().map_or(Timestamp::ZERO, |prev_h| { - let prev_timestamp = - *height_to_timestamp.cached_get(prev_h).unwrap().unwrap(); - timestamp - .checked_sub(prev_timestamp) - .unwrap_or(Timestamp::ZERO) - }); - (height, interval) - }, - exit, - ) - }, + Some(self.height_to_interval.mut_vec()), )?; self.indexes_to_block_count.compute_all( @@ -113,7 +122,7 @@ impl Vecs { |v, indexer, _, starting_indexes, exit| { v.compute_transform( starting_indexes.height, - indexer.mut_vecs().height_to_block_weight.mut_vec(), + indexer.mut_vecs().height_to_weight.mut_vec(), |(h, ..)| (h, StoredU32::from(1_u32)), exit, ) @@ -124,34 +133,33 @@ impl Vecs { indexes, starting_indexes, exit, - Some(indexer.mut_vecs().height_to_block_weight.mut_vec()), + Some(indexer.mut_vecs().height_to_weight.mut_vec()), )?; self.indexes_to_block_size.compute_rest( indexes, starting_indexes, exit, - Some(indexer.mut_vecs().height_to_block_size.mut_vec()), + Some(indexer.mut_vecs().height_to_total_size.mut_vec()), )?; - self.indexes_to_block_vbytes.compute_all( - indexer, + self.height_to_vbytes.compute_transform( + starting_indexes.height, + indexer.mut_vecs().height_to_weight.mut_vec(), + |(h, w, ..)| { + ( + h, + StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()), + ) + }, + exit, + )?; + + self.indexes_to_block_vbytes.compute_rest( indexes, starting_indexes, exit, - |v, indexer, _, starting_indexes, exit| { - v.compute_transform( - starting_indexes.height, - indexer.mut_vecs().height_to_block_weight.mut_vec(), - |(h, w, ..)| { - ( - h, - StoredU64::from(bitcoin::Weight::from(w).to_vbytes_floor()), - ) - }, - exit, - ) - }, + Some(self.height_to_vbytes.mut_vec()), )?; Ok(()) @@ -159,6 +167,10 @@ impl Vecs { pub fn as_any_vecs(&self) -> Vec<&dyn brk_vec::AnyStoredVec> { [ + vec![ + self.height_to_interval.any_vec(), + self.height_to_vbytes.any_vec(), + ], self.indexes_to_block_interval.any_vecs(), self.indexes_to_block_count.any_vecs(), self.indexes_to_block_weight.any_vecs(), diff --git a/crates/brk_computer/src/storage/vecs/indexes.rs b/crates/brk_computer/src/storage/vecs/indexes.rs index b1ba2f3e3..1f420899b 100644 --- a/crates/brk_computer/src/storage/vecs/indexes.rs +++ b/crates/brk_computer/src/storage/vecs/indexes.rs @@ -12,8 +12,6 @@ use super::ComputedVec; #[derive(Clone)] pub struct Vecs { - // pub height_to_last_addressindex: StorableVec, - // pub height_to_last_txoutindex: StorableVec, pub dateindex_to_date: ComputedVec, pub dateindex_to_dateindex: ComputedVec, pub dateindex_to_first_height: ComputedVec, @@ -320,7 +318,7 @@ impl Vecs { ) -> color_eyre::Result { let indexer_vecs = indexer.mut_vecs(); - let height_count = indexer_vecs.height_to_block_size.len(); + let height_count = indexer_vecs.height_to_total_size.len(); let txindexes_count = indexer_vecs.txindex_to_txid.len(); let txinindexes_count = indexer_vecs.txinindex_to_txoutindex.len(); let txoutindexes_count = indexer_vecs.txoutindex_to_addressindex.len(); diff --git a/crates/brk_computer/src/storage/vecs/marketprice.rs b/crates/brk_computer/src/storage/vecs/marketprice.rs index 2f849aa7c..bfa85346f 100644 --- a/crates/brk_computer/src/storage/vecs/marketprice.rs +++ b/crates/brk_computer/src/storage/vecs/marketprice.rs @@ -19,7 +19,6 @@ use super::{ #[derive(Clone)] pub struct Vecs { - // pub dateindex_to_close: ComputedVec>, pub dateindex_to_close_in_cents: ComputedVec>, pub dateindex_to_high_in_cents: ComputedVec>, pub dateindex_to_low_in_cents: ComputedVec>, diff --git a/crates/brk_computer/src/storage/vecs/transactions.rs b/crates/brk_computer/src/storage/vecs/transactions.rs index fa7e61853..1150cb23e 100644 --- a/crates/brk_computer/src/storage/vecs/transactions.rs +++ b/crates/brk_computer/src/storage/vecs/transactions.rs @@ -7,7 +7,7 @@ use brk_core::{ use brk_exit::Exit; use brk_indexer::Indexer; use brk_parser::bitcoin; -use brk_vec::{Compressed, DynamicVec, Version}; +use brk_vec::{Compressed, DynamicVec, StoredIndex, Version}; use super::{ ComputedVec, Indexes, @@ -17,22 +17,19 @@ use super::{ #[derive(Clone)] pub struct Vecs { - // pub height_to_fee: ComputedVec, - // pub height_to_inputcount: ComputedVec, - // pub height_to_maxfeerate: ComputedVec, - // pub height_to_medianfeerate: ComputedVec, - // pub height_to_minfeerate: ComputedVec, - // pub height_to_outputcount: ComputedVec, - // pub height_to_subsidy: ComputedVec, - // pub height_to_totalfees: ComputedVec, - pub height_to_tx_count: ComputedVecsFromHeight, + pub indexes_to_tx_count: ComputedVecsFromHeight, pub indexes_to_fee: ComputedVecsFromTxindex, pub indexes_to_feerate: ComputedVecsFromTxindex, pub indexes_to_input_value: ComputedVecsFromTxindex, pub indexes_to_output_value: ComputedVecsFromTxindex, + // pub txindex_to_is_v1: ComputedVec, pub indexes_to_tx_v1: ComputedVecsFromHeight, + // pub txindex_to_is_v2: ComputedVec, pub indexes_to_tx_v2: ComputedVecsFromHeight, + // pub txindex_to_is_v3: ComputedVec, pub indexes_to_tx_v3: ComputedVecsFromHeight, + pub indexes_to_tx_vsize: ComputedVecsFromTxindex, + pub indexes_to_tx_weight: ComputedVecsFromTxindex, pub txindex_to_input_count: ComputedVecsFromTxindex, pub txindex_to_is_coinbase: ComputedVec, pub txindex_to_output_count: ComputedVecsFromTxindex, @@ -40,6 +37,8 @@ pub struct Vecs { pub txindex_to_weight: ComputedVec, /// Value == 0 when Coinbase pub txinindex_to_value: ComputedVec, + pub indexes_to_subsidy: ComputedVecsFromHeight, + pub indexes_to_coinbase: ComputedVecsFromHeight, } impl Vecs { @@ -47,42 +46,37 @@ impl Vecs { fs::create_dir_all(path)?; Ok(Self { - height_to_tx_count: ComputedVecsFromHeight::forced_import( + indexes_to_tx_count: ComputedVecsFromHeight::forced_import( path, "tx_count", true, Version::ZERO, compressed, - StorableVecGeneatorOptions::default().add_sum().add_total(), + StorableVecGeneatorOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + .add_sum() + .add_total(), )?, - // height_to_fee: StorableVec::forced_import(&path.join("height_to_fee"), Version::ZERO)?, - // height_to_input_count: StorableVec::forced_import( - // &path.join("height_to_input_count"), - // Version::ZERO, - // )?, - // height_to_maxfeerate: StorableVec::forced_import(&path.join("height_to_maxfeerate"), Version::ZERO)?, - // height_to_medianfeerate: StorableVec::forced_import(&path.join("height_to_medianfeerate"), Version::ZERO)?, - // height_to_minfeerate: StorableVec::forced_import(&path.join("height_to_minfeerate"), Version::ZERO)?, - // height_to_output_count: StorableVec::forced_import( - // &path.join("height_to_output_count"), - // Version::ZERO, - // )?, // height_to_subsidy: StorableVec::forced_import(&path.join("height_to_subsidy"), Version::ZERO)?, - // height_to_totalfees: StorableVec::forced_import(&path.join("height_to_totalfees"), Version::ZERO)?, - // height_to_txcount: StorableVec::forced_import(&path.join("height_to_txcount"), Version::ZERO)?, txindex_to_is_coinbase: ComputedVec::forced_import( &path.join("txindex_to_is_coinbase"), Version::ZERO, compressed, )?, - // txindex_to_feerate: StorableVec::forced_import(&path.join("txindex_to_feerate"), Version::ZERO)?, txindex_to_input_count: ComputedVecsFromTxindex::forced_import( path, "input_count", true, Version::ZERO, compressed, - StorableVecGeneatorOptions::default().add_sum().add_total(), + StorableVecGeneatorOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + .add_sum() + .add_total(), )?, txindex_to_output_count: ComputedVecsFromTxindex::forced_import( path, @@ -90,15 +84,13 @@ impl Vecs { true, Version::ZERO, compressed, - StorableVecGeneatorOptions::default().add_sum().add_total(), + StorableVecGeneatorOptions::default() + .add_average() + .add_minmax() + .add_percentiles() + .add_sum() + .add_total(), )?, - // txindex_to_output_value: ComputedVecsFromTxindex::forced_import( - // path, - // "output_value", - // Version::ZERO, - // compressed, - // StorableVecGeneatorOptions::default().add_sum().add_total(), - // )?, txinindex_to_value: ComputedVec::forced_import( &path.join("txinindex_to_value"), Version::ZERO, @@ -134,7 +126,10 @@ impl Vecs { true, Version::ZERO, compressed, - StorableVecGeneatorOptions::default().add_sum().add_total(), + StorableVecGeneatorOptions::default() + .add_average() + .add_sum() + .add_total(), )?, indexes_to_output_value: ComputedVecsFromTxindex::forced_import( path, @@ -142,7 +137,10 @@ impl Vecs { true, Version::ZERO, compressed, - StorableVecGeneatorOptions::default().add_sum().add_total(), + StorableVecGeneatorOptions::default() + .add_average() + .add_sum() + .add_total(), )?, indexes_to_fee: ComputedVecsFromTxindex::forced_import( path, @@ -150,7 +148,12 @@ impl Vecs { true, Version::ZERO, compressed, - StorableVecGeneatorOptions::default().add_sum().add_total(), + StorableVecGeneatorOptions::default() + .add_sum() + .add_total() + .add_percentiles() + .add_minmax() + .add_average(), )?, indexes_to_feerate: ComputedVecsFromTxindex::forced_import( path, @@ -173,6 +176,54 @@ impl Vecs { Version::ZERO, compressed, )?, + indexes_to_tx_vsize: ComputedVecsFromTxindex::forced_import( + path, + "tx_vsize", + false, + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default() + .add_percentiles() + .add_minmax() + .add_average(), + )?, + indexes_to_tx_weight: ComputedVecsFromTxindex::forced_import( + path, + "tx_weight", + false, + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default() + .add_percentiles() + .add_minmax() + .add_average(), + )?, + indexes_to_subsidy: ComputedVecsFromHeight::forced_import( + path, + "subsidy", + true, + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default() + .add_percentiles() + .add_sum() + .add_total() + .add_minmax() + .add_average(), + )?, + indexes_to_coinbase: ComputedVecsFromHeight::forced_import( + path, + "coinbase", + true, + Version::ZERO, + compressed, + StorableVecGeneatorOptions::default() + .add_sum() + .add_total() + .add_percentiles() + .add_minmax() + .add_average(), + )?, }) } @@ -183,7 +234,7 @@ impl Vecs { starting_indexes: &Indexes, exit: &Exit, ) -> color_eyre::Result<()> { - self.height_to_tx_count.compute_all( + self.indexes_to_tx_count.compute_all( indexer, indexes, starting_indexes, @@ -228,14 +279,6 @@ impl Vecs { }, )?; - // self.txindex_to_output_value.compute_rest( - // indexer, - // indexes, - // starting_indexes, - // exit, - // Some(indexer.mut_vecs().txoutindex_to_value.mut_vec()), - // )?; - let mut compute_indexes_to_tx_vany = |indexes_to_tx_vany: &mut ComputedVecsFromHeight, txversion| { indexes_to_tx_vany.compute_all( @@ -424,6 +467,94 @@ impl Vecs { }, )?; + self.indexes_to_tx_weight.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(self.txindex_to_weight.mut_vec()), + )?; + + self.indexes_to_tx_vsize.compute_rest( + indexer, + indexes, + starting_indexes, + exit, + Some(self.txindex_to_vsize.mut_vec()), + )?; + + self.indexes_to_subsidy.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |vec, indexer, indexes, starting_indexes, exit| { + let indexer_vecs = indexer.mut_vecs(); + vec.compute_transform( + starting_indexes.height, + indexer_vecs.height_to_first_txindex.mut_vec(), + |(height, txindex, ..)| { + let first_txoutindex = indexer_vecs + .txindex_to_first_txoutindex + .cached_get(txindex) + .unwrap() + .unwrap() + .into_inner() + .to_usize() + .unwrap(); + let last_txoutindex = indexes + .txindex_to_last_txoutindex + .mut_vec() + .cached_get(txindex) + .unwrap() + .unwrap() + .into_inner() + .to_usize() + .unwrap(); + let mut sats = Sats::ZERO; + (first_txoutindex..=last_txoutindex).for_each(|txoutindex| { + sats += indexer_vecs + .txoutindex_to_value + .cached_get_(txoutindex) + .unwrap() + .unwrap() + .into_inner(); + }); + (height, sats) + }, + exit, + ) + }, + )?; + + self.indexes_to_coinbase.compute_all( + indexer, + indexes, + starting_indexes, + exit, + |vec, _, _, starting_indexes, exit| { + vec.compute_transform( + starting_indexes.height, + self.indexes_to_subsidy.height.as_mut().unwrap().mut_vec(), + |(height, subsidy, ..)| { + let fees = self + .indexes_to_fee + .height + .sum + .as_mut() + .unwrap() + .mut_vec() + .cached_get(height) + .unwrap() + .unwrap() + .into_inner(); + (height, subsidy.checked_sub(fees).unwrap()) + }, + exit, + ) + }, + )?; + Ok(()) } @@ -435,14 +566,18 @@ impl Vecs { self.txindex_to_weight.any_vec(), self.txindex_to_vsize.any_vec(), ], - self.height_to_tx_count.any_vecs(), + self.indexes_to_tx_count.any_vecs(), + self.indexes_to_coinbase.any_vecs(), + self.indexes_to_fee.any_vecs(), + self.indexes_to_feerate.any_vecs(), self.indexes_to_input_value.any_vecs(), self.indexes_to_output_value.any_vecs(), + self.indexes_to_subsidy.any_vecs(), self.indexes_to_tx_v1.any_vecs(), self.indexes_to_tx_v2.any_vecs(), self.indexes_to_tx_v3.any_vecs(), - self.indexes_to_fee.any_vecs(), - self.indexes_to_feerate.any_vecs(), + self.indexes_to_tx_vsize.any_vecs(), + self.indexes_to_tx_weight.any_vecs(), self.txindex_to_input_count.any_vecs(), self.txindex_to_output_count.any_vecs(), ] diff --git a/crates/brk_indexer/README.md b/crates/brk_indexer/README.md index 894342b8b..a63653b86 100644 --- a/crates/brk_indexer/README.md +++ b/crates/brk_indexer/README.md @@ -58,13 +58,14 @@ Stores: `src/storage/stores/mod.rs` ## Benchmark -### Result 1 - 2025-04-10 +### Result 1 - 2025-04-12 -- version: `v0.0.20` +- version: `v0.0.21` - machine: `Macbook Pro M3 Pro (36GB RAM)` - mode: `raw` - from: `0` -- to: `891_810` -- time: `8 hours 27 min 3s` -- peak memory: `6.5GB` +- to: `892_098` +- time: `7 hours 10 min 22s` +- peak memory: `6.1GB` - disk usage: `270 GB` +- overhead: `36%` (`270 GB / 741 GB`) diff --git a/crates/brk_indexer/src/lib.rs b/crates/brk_indexer/src/lib.rs index aa354c355..8b8050e58 100644 --- a/crates/brk_indexer/src/lib.rs +++ b/crates/brk_indexer/src/lib.rs @@ -81,7 +81,7 @@ impl Indexer { self.stores.as_ref().unwrap(), rpc, )) - .unwrap_or_else(|_| { + .unwrap_or_else(|_report| { let indexes = Indexes::default(); indexes.push_if_needed(self.vecs.as_mut().unwrap()).unwrap(); indexes @@ -165,8 +165,8 @@ impl Indexer { .push_if_needed(height, block.header.difficulty_float())?; vecs.height_to_timestamp .push_if_needed(height, Timestamp::from(block.header.time))?; - vecs.height_to_block_size.push_if_needed(height, block.total_size().into())?; - vecs.height_to_block_weight.push_if_needed(height, block.weight().into())?; + vecs.height_to_total_size.push_if_needed(height, block.total_size().into())?; + vecs.height_to_weight.push_if_needed(height, block.weight().into())?; let inputs = block .txdata diff --git a/crates/brk_indexer/src/stores/base.rs b/crates/brk_indexer/src/stores/base.rs index 940beaeca..5f61d9087 100644 --- a/crates/brk_indexer/src/stores/base.rs +++ b/crates/brk_indexer/src/stores/base.rs @@ -98,10 +98,10 @@ where if !self.puts.is_empty() { unreachable!("Shouldn't reach this"); - // self.puts.remove(&key); } - // dbg!(&key); - if !self.dels.insert(key) { + + if !self.dels.insert(key.clone()) { + dbg!(key, &self.meta.path()); unreachable!(); } } diff --git a/crates/brk_indexer/src/stores/meta.rs b/crates/brk_indexer/src/stores/meta.rs index ccb3c3bbd..dc6b8b914 100644 --- a/crates/brk_indexer/src/stores/meta.rs +++ b/crates/brk_indexer/src/stores/meta.rs @@ -46,6 +46,10 @@ impl StoreMeta { self.len() == 0 } + pub fn version(&self) -> Version { + self.version + } + pub fn export(&mut self, len: usize, height: Height) -> io::Result<()> { self.len = len; self.write_length()?; @@ -61,6 +65,10 @@ impl StoreMeta { fs::create_dir(path) } + pub fn path(&self) -> &Path { + &self.pathbuf + } + fn path_version(&self) -> PathBuf { Self::path_version_(&self.pathbuf) } diff --git a/crates/brk_indexer/src/vecs/base.rs b/crates/brk_indexer/src/vecs/base.rs index 4c597fbbd..c2fb62e58 100644 --- a/crates/brk_indexer/src/vecs/base.rs +++ b/crates/brk_indexer/src/vecs/base.rs @@ -49,6 +49,10 @@ where pub fn cached_get(&mut self, index: I) -> Result>> { self.inner.cached_get(index) } + #[inline] + pub fn cached_get_(&mut self, index: usize) -> Result>> { + self.inner.cached_get_(index) + } pub fn iter_from(&mut self, index: I, f: F) -> Result<()> where diff --git a/crates/brk_indexer/src/vecs/mod.rs b/crates/brk_indexer/src/vecs/mod.rs index ab6754c61..a671bf0db 100644 --- a/crates/brk_indexer/src/vecs/mod.rs +++ b/crates/brk_indexer/src/vecs/mod.rs @@ -40,9 +40,9 @@ pub struct Vecs { pub height_to_first_txinindex: IndexedVec, pub height_to_first_txoutindex: IndexedVec, pub height_to_first_unknownindex: IndexedVec, - pub height_to_block_size: IndexedVec, + pub height_to_total_size: IndexedVec, pub height_to_timestamp: IndexedVec, - pub height_to_block_weight: IndexedVec, + pub height_to_weight: IndexedVec, pub multisigindex_to_height: IndexedVec, pub opreturnindex_to_height: IndexedVec, pub p2pk33index_to_height: IndexedVec, @@ -188,8 +188,8 @@ impl Vecs { Version::ZERO, compressed, )?, - height_to_block_size: IndexedVec::forced_import( - &path.join("height_to_block_size"), + height_to_total_size: IndexedVec::forced_import( + &path.join("height_to_total_size"), Version::ZERO, compressed, )?, @@ -198,8 +198,8 @@ impl Vecs { Version::ZERO, compressed, )?, - height_to_block_weight: IndexedVec::forced_import( - &path.join("height_to_block_weight"), + height_to_weight: IndexedVec::forced_import( + &path.join("height_to_weight"), Version::ZERO, compressed, )?, @@ -431,11 +431,11 @@ impl Vecs { .truncate_if_needed(height, saved_height)?; self.height_to_difficulty .truncate_if_needed(height, saved_height)?; - self.height_to_block_size + self.height_to_total_size .truncate_if_needed(height, saved_height)?; self.height_to_timestamp .truncate_if_needed(height, saved_height)?; - self.height_to_block_weight + self.height_to_weight .truncate_if_needed(height, saved_height)?; self.addressindex_to_addresstype @@ -631,9 +631,9 @@ impl Vecs { self.height_to_first_p2trindex.any_vec(), self.height_to_first_p2wpkhindex.any_vec(), self.height_to_first_p2wshindex.any_vec(), - self.height_to_block_size.any_vec(), + self.height_to_total_size.any_vec(), self.height_to_timestamp.any_vec(), - self.height_to_block_weight.any_vec(), + self.height_to_weight.any_vec(), self.p2pk33index_to_p2pk33addressbytes.any_vec(), self.p2pk65index_to_p2pk65addressbytes.any_vec(), self.p2pkhindex_to_p2pkhaddressbytes.any_vec(), @@ -693,9 +693,9 @@ impl Vecs { &mut self.height_to_first_p2trindex, &mut self.height_to_first_p2wpkhindex, &mut self.height_to_first_p2wshindex, - &mut self.height_to_block_size, + &mut self.height_to_total_size, &mut self.height_to_timestamp, - &mut self.height_to_block_weight, + &mut self.height_to_weight, &mut self.p2pk33index_to_p2pk33addressbytes, &mut self.p2pk65index_to_p2pk65addressbytes, &mut self.p2pkhindex_to_p2pkhaddressbytes, diff --git a/crates/brk_server/src/api/query/dts.rs b/crates/brk_server/src/api/query/dts.rs index 31dfac6fd..c3613ebf9 100644 --- a/crates/brk_server/src/api/query/dts.rs +++ b/crates/brk_server/src/api/query/dts.rs @@ -67,7 +67,7 @@ impl DTS for Query<'static> { .collect::>() .join("\n"); - contents += "\n\n return {\n"; + contents += "\n\n return /** @type {const} */ ({\n"; self.vec_trees .id_to_index_to_vec @@ -89,7 +89,7 @@ impl DTS for Query<'static> { ); }); - contents += " }\n"; + contents += " });\n"; contents.push('}'); contents += "\n/** @typedef {ReturnType} VecIdToIndexes */"; diff --git a/websites/kibo.money/packages/lightweight-charts/wrapper.js b/websites/kibo.money/packages/lightweight-charts/wrapper.js index 4a18d8454..e9e1b9df3 100644 --- a/websites/kibo.money/packages/lightweight-charts/wrapper.js +++ b/websites/kibo.money/packages/lightweight-charts/wrapper.js @@ -57,9 +57,6 @@ export default import("./v5.0.5-treeshaked/script.js").then((lc) => { vertLines: { visible: false }, horzLines: { visible: false }, }, - timeScale: { - minBarSpacing: 2.1, - }, localization: { priceFormatter: utils.locale.numberToShortUSFormat, locale: "en-us", @@ -942,7 +939,7 @@ function createPriceScaleSelectorIfNeeded({ /** @typedef {(typeof choices)[number]} Choices */ const serializedValue = signals.createSignal( /** @satisfies {Choices} */ ( - unit === "US Dollars" && seriesType !== "Baseline" ? "log" : "lin" + unit === "USD" && seriesType !== "Baseline" ? "log" : "lin" ), { save: { diff --git a/websites/kibo.money/scripts/chart.js b/websites/kibo.money/scripts/chart.js index 1af3f13b9..f421a2785 100644 --- a/websites/kibo.money/scripts/chart.js +++ b/websites/kibo.money/scripts/chart.js @@ -87,7 +87,7 @@ export function init({ const candles = chart.addCandlestickSeries({ vecId: "ohlc", name: "Price", - unit: "US Dollars", + unit: "USD", }); signals.createEffect(webSockets.kraken1dCandle.latest, (latest) => { if (!latest) return; @@ -103,7 +103,10 @@ export function init({ { blueprints: option.bottom, paneIndex: 1 }, ].forEach(({ blueprints, paneIndex }) => { blueprints?.forEach((blueprint) => { - if (vecIdToIndexes[blueprint.key].includes(index)) { + const indexes = /** @type {readonly number[]} */ ( + vecIdToIndexes[blueprint.key] + ); + if (indexes.includes(index)) { chart.addLineSeries({ vecId: blueprint.key, color: blueprint.color, @@ -178,7 +181,7 @@ function createIndexSelector({ elements, signals, utils }) { elements.charts.append(fieldset); const index = signals.createMemo( - /** @returns {Index} */ () => { + /** @returns {ChartableIndex} */ () => { switch (serializedIndex()) { case "timestamp": return /** @satisfies {Height} */ (0); diff --git a/websites/kibo.money/scripts/main.js b/websites/kibo.money/scripts/main.js index 80a2619e8..ed6e68744 100644 --- a/websites/kibo.money/scripts/main.js +++ b/websites/kibo.money/scripts/main.js @@ -1,7 +1,7 @@ // @ts-check /** - * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, Unit, AnySeriesBlueprint } from "./options" + * @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, Unit, AnySeriesBlueprint, ChartableIndex } from "./options" * @import {Valued, SingleValueData, CandlestickData, ChartData, OHLCTuple} from "../packages/lightweight-charts/wrapper" * @import * as _ from "../packages/ufuzzy/v1.0.14/types" * @import { createChart as CreateClassicChart, LineStyleOptions, DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, ISeriesApi, Time, LineData, LogicalRange, SeriesType, BaselineStyleOptions, SeriesOptionsCommon, BaselineData, CandlestickStyleOptions } from "../packages/lightweight-charts/v5.0.5-treeshaked/types" @@ -436,7 +436,7 @@ function createUtils() { createInputDollar({ id, title, signal, signals }) { return this.createInputNumberElement({ id, - placeholder: "US Dollars", + placeholder: "USD", min: 0, title, signal, @@ -1216,9 +1216,10 @@ function createUtils() { /** * @param {Index} index * @param {VecId} vecId + * @param {number} from */ - genUrl(index, vecId) { - return `/api${genPath(index, vecId)}`; + genUrl(index, vecId, from) { + return `/api${genPath(index, vecId, from)}`; }, /** * @template {number | OHLCTuple} [T=number] @@ -1284,8 +1285,10 @@ function createVecsResources(signals, utils) { let loading = false; let at = /** @type {Date | null} */ (null); + const from = -10_000; + return { - url: utils.api.genUrl(index, id), + url: utils.api.genUrl(index, id, from), fetched, async fetch() { if (loading) return fetched(); @@ -1302,7 +1305,7 @@ function createVecsResources(signals, utils) { }, index, id, - -10_000, + from, ) ); at = new Date(); diff --git a/websites/kibo.money/scripts/options.js b/websites/kibo.money/scripts/options.js index f9d7e00ca..78cdcc4c8 100644 --- a/websites/kibo.money/scripts/options.js +++ b/websites/kibo.money/scripts/options.js @@ -1,23 +1,34 @@ // @ts-check +/** + * @typedef {Height | Dateindex | Weekindex | Difficultyepoch | Monthindex | Quarterindex | Yearindex | Decadeindex | Halvingepoch} ChartableIndex + */ +/** + * @template {readonly unknown[]} T + * @typedef {Extract extends never ? false : true} IncludesChartableIndex + */ +/** + * @typedef {{[K in VecId]: IncludesChartableIndex extends true ? K : never}[VecId]} ChartableVecId + */ + /** * @typedef {"" | - * "Bitcoin" | + * "BTC" | * "Coinblocks" | * "Count" | * "Date" | - * "Dollars / (PetaHash / Second)" | + * "USD / (PetaHash / Second)" | * "ExaHash / Second" | * "Height" | * "Gigabytes" | * "Megabytes" | * "Percentage" | * "Ratio" | - * "Satoshis" | + * "Sats" | * "sat/vB" | * "Seconds" | * "Transactions" | - * "US Dollars" | + * "USD" | * "Version" | * "Virtual Bytes" | * "Weight Units" @@ -50,7 +61,7 @@ * * @typedef {BaselineSeriesBlueprint | CandlestickSeriesBlueprint | LineSeriesBlueprint} AnySeriesBlueprint * - * @typedef {AnySeriesBlueprint & {key: VecId}} AnyFetchedSeriesBlueprint + * @typedef {AnySeriesBlueprint & {key: ChartableVecId}} AnyFetchedSeriesBlueprint * * @typedef {Object} PartialOption * @property {string} name @@ -131,515 +142,515 @@ } */ -function initGroups() { - const xTermHolders = /** @type {const} */ ([ - { - id: "sth", - key: "sth", - name: "Short Term Holders", - legend: "Short Term Holders - STH", - }, - { - id: "lth", - key: "lth", - name: "Long Term Holders", - legend: "Long Term Holders - LTH", - }, - ]); +// function initGroups() { +// const xTermHolders = /** @type {const} */ ([ +// { +// id: "sth", +// key: "sth", +// name: "Short Term Holders", +// legend: "Short Term Holders - STH", +// }, +// { +// id: "lth", +// key: "lth", +// name: "Long Term Holders", +// legend: "Long Term Holders - LTH", +// }, +// ]); - const upTo = /** @type {const} */ ([ - { - id: "up-to-1d", - key: "up_to_1d", - name: "Up To 1 Day", - legend: "1D", - }, - { - id: "up-to-1w", - key: "up_to_1w", - name: "Up To 1 Week", - legend: "1W", - }, - { - id: "up-to-1m", - key: "up_to_1m", - name: "Up To 1 Month", - legend: "1M", - }, - { - id: "up-to-2m", - key: "up_to_2m", - name: "Up To 2 Months", - legend: "2M", - }, - { - id: "up-to-3m", - key: "up_to_3m", - name: "Up To 3 Months", - legend: "3M", - }, - { - id: "up-to-4m", - key: "up_to_4m", - name: "Up To 4 Months", - legend: "4M", - }, - { - id: "up-to-5m", - key: "up_to_5m", - name: "Up To 5 Months", - legend: "5M", - }, - { - id: "up-to-6m", - key: "up_to_6m", - name: "Up To 6 Months", - legend: "6M", - }, - { - id: "up-to-1y", - key: "up_to_1y", - name: "Up To 1 Year", - legend: "1Y", - }, - { - id: "up-to-2y", - key: "up_to_2y", - name: "Up To 2 Years", - legend: "2Y", - }, - { - id: "up-to-3y", - key: "up_to_3y", - name: "Up To 3 Years", - legend: "3Y", - }, - { - id: "up-to-5y", - key: "up_to_5y", - name: "Up To 5 Years", - legend: "5Y", - }, - { - id: "up-to-7y", - key: "up_to_7y", - name: "Up To 7 Years", - legend: "7Y", - }, - { - id: "up-to-10y", - key: "up_to_10y", - name: "Up To 10 Years", - legend: "10Y", - }, - { - id: "up-to-15y", - key: "up_to_15y", - name: "Up To 15 Years", - legend: "15Y", - }, - ]); +// const upTo = /** @type {const} */ ([ +// { +// id: "up-to-1d", +// key: "up_to_1d", +// name: "Up To 1 Day", +// legend: "1D", +// }, +// { +// id: "up-to-1w", +// key: "up_to_1w", +// name: "Up To 1 Week", +// legend: "1W", +// }, +// { +// id: "up-to-1m", +// key: "up_to_1m", +// name: "Up To 1 Month", +// legend: "1M", +// }, +// { +// id: "up-to-2m", +// key: "up_to_2m", +// name: "Up To 2 Months", +// legend: "2M", +// }, +// { +// id: "up-to-3m", +// key: "up_to_3m", +// name: "Up To 3 Months", +// legend: "3M", +// }, +// { +// id: "up-to-4m", +// key: "up_to_4m", +// name: "Up To 4 Months", +// legend: "4M", +// }, +// { +// id: "up-to-5m", +// key: "up_to_5m", +// name: "Up To 5 Months", +// legend: "5M", +// }, +// { +// id: "up-to-6m", +// key: "up_to_6m", +// name: "Up To 6 Months", +// legend: "6M", +// }, +// { +// id: "up-to-1y", +// key: "up_to_1y", +// name: "Up To 1 Year", +// legend: "1Y", +// }, +// { +// id: "up-to-2y", +// key: "up_to_2y", +// name: "Up To 2 Years", +// legend: "2Y", +// }, +// { +// id: "up-to-3y", +// key: "up_to_3y", +// name: "Up To 3 Years", +// legend: "3Y", +// }, +// { +// id: "up-to-5y", +// key: "up_to_5y", +// name: "Up To 5 Years", +// legend: "5Y", +// }, +// { +// id: "up-to-7y", +// key: "up_to_7y", +// name: "Up To 7 Years", +// legend: "7Y", +// }, +// { +// id: "up-to-10y", +// key: "up_to_10y", +// name: "Up To 10 Years", +// legend: "10Y", +// }, +// { +// id: "up-to-15y", +// key: "up_to_15y", +// name: "Up To 15 Years", +// legend: "15Y", +// }, +// ]); - const fromXToY = /** @type {const} */ ([ - { - id: "up-to-1d", - key: "up_to_1d", - name: "24h", - legend: "24h", - }, - { - id: "from-1d-to-1w", - key: "from_1d_to_1w", - name: "From 1 Day To 1 Week", - legend: "1D — 1W", - }, - { - id: "from-1w-to-1m", - key: "from_1w_to_1m", - name: "From 1 Week To 1 Month", - legend: "1W — 1M", - }, - { - id: "from-1m-to-3m", - key: "from_1m_to_3m", - name: "From 1 Month To 3 Months", - legend: "1M — 3M", - }, - { - id: "from-3m-to-6m", - key: "from_3m_to_6m", - name: "From 3 Months To 6 Months", - legend: "3M — 6M", - }, - { - id: "from-6m-to-1y", - key: "from_6m_to_1y", - name: "From 6 Months To 1 Year", - legend: "6M — 1Y", - }, - { - id: "from-1y-to-2y", - key: "from_1y_to_2y", - name: "From 1 Year To 2 Years", - legend: "1Y — 2Y", - }, - { - id: "from-2y-to-3y", - key: "from_2y_to_3y", - name: "From 2 Years To 3 Years", - legend: "2Y — 3Y", - }, - { - id: "from-3y-to-5y", - key: "from_3y_to_5y", - name: "From 3 Years To 5 Years", - legend: "3Y — 5Y", - }, - { - id: "from-5y-to-7y", - key: "from_5y_to_7y", - name: "From 5 Years To 7 Years", - legend: "5Y — 7Y", - }, - { - id: "from-7y-to-10y", - key: "from_7y_to_10y", - name: "From 7 Years To 10 Years", - legend: "7Y — 10Y", - }, - { - id: "from-10y-to-15y", - key: "from_10y_to_15y", - name: "From 10 Years To 15 Years", - legend: "10Y — 15Y", - }, - { - id: "from-15y", - key: "from_15y", - name: "From 15 Years To End", - legend: "15Y — End", - }, - ]); +// const fromXToY = /** @type {const} */ ([ +// { +// id: "up-to-1d", +// key: "up_to_1d", +// name: "24h", +// legend: "24h", +// }, +// { +// id: "from-1d-to-1w", +// key: "from_1d_to_1w", +// name: "From 1 Day To 1 Week", +// legend: "1D — 1W", +// }, +// { +// id: "from-1w-to-1m", +// key: "from_1w_to_1m", +// name: "From 1 Week To 1 Month", +// legend: "1W — 1M", +// }, +// { +// id: "from-1m-to-3m", +// key: "from_1m_to_3m", +// name: "From 1 Month To 3 Months", +// legend: "1M — 3M", +// }, +// { +// id: "from-3m-to-6m", +// key: "from_3m_to_6m", +// name: "From 3 Months To 6 Months", +// legend: "3M — 6M", +// }, +// { +// id: "from-6m-to-1y", +// key: "from_6m_to_1y", +// name: "From 6 Months To 1 Year", +// legend: "6M — 1Y", +// }, +// { +// id: "from-1y-to-2y", +// key: "from_1y_to_2y", +// name: "From 1 Year To 2 Years", +// legend: "1Y — 2Y", +// }, +// { +// id: "from-2y-to-3y", +// key: "from_2y_to_3y", +// name: "From 2 Years To 3 Years", +// legend: "2Y — 3Y", +// }, +// { +// id: "from-3y-to-5y", +// key: "from_3y_to_5y", +// name: "From 3 Years To 5 Years", +// legend: "3Y — 5Y", +// }, +// { +// id: "from-5y-to-7y", +// key: "from_5y_to_7y", +// name: "From 5 Years To 7 Years", +// legend: "5Y — 7Y", +// }, +// { +// id: "from-7y-to-10y", +// key: "from_7y_to_10y", +// name: "From 7 Years To 10 Years", +// legend: "7Y — 10Y", +// }, +// { +// id: "from-10y-to-15y", +// key: "from_10y_to_15y", +// name: "From 10 Years To 15 Years", +// legend: "10Y — 15Y", +// }, +// { +// id: "from-15y", +// key: "from_15y", +// name: "From 15 Years To End", +// legend: "15Y — End", +// }, +// ]); - const fromX = /** @type {const} */ ([ - { - id: "from-1y", - key: "from_1y", - name: "From 1 Year", - legend: "1Y+", - }, - { - id: "from-2y", - key: "from_2y", - name: "From 2 Years", - legend: "2Y+", - }, - { - id: "from-4y", - key: "from_4y", - name: "From 4 Years", - legend: "4Y+", - }, - { - id: "from-10y", - key: "from_10y", - name: "From 10 Years", - legend: "10Y+", - }, - { - id: "from-15y", - key: "from_15y", - name: "From 15 Years", - legend: "15Y+", - }, - ]); +// const fromX = /** @type {const} */ ([ +// { +// id: "from-1y", +// key: "from_1y", +// name: "From 1 Year", +// legend: "1Y+", +// }, +// { +// id: "from-2y", +// key: "from_2y", +// name: "From 2 Years", +// legend: "2Y+", +// }, +// { +// id: "from-4y", +// key: "from_4y", +// name: "From 4 Years", +// legend: "4Y+", +// }, +// { +// id: "from-10y", +// key: "from_10y", +// name: "From 10 Years", +// legend: "10Y+", +// }, +// { +// id: "from-15y", +// key: "from_15y", +// name: "From 15 Years", +// legend: "15Y+", +// }, +// ]); - const epochs = /** @type {const} */ ([ - { id: "epoch-1", key: "epoch_1", name: "Epoch 1" }, - { id: "epoch-2", key: "epoch_2", name: "Epoch 2" }, - { id: "epoch-3", key: "epoch_3", name: "Epoch 3" }, - { id: "epoch-4", key: "epoch_4", name: "Epoch 4" }, - { id: "epoch-5", key: "epoch_5", name: "Epoch 5" }, - ]); +// const epochs = /** @type {const} */ ([ +// { id: "epoch-1", key: "epoch_1", name: "Epoch 1" }, +// { id: "epoch-2", key: "epoch_2", name: "Epoch 2" }, +// { id: "epoch-3", key: "epoch_3", name: "Epoch 3" }, +// { id: "epoch-4", key: "epoch_4", name: "Epoch 4" }, +// { id: "epoch-5", key: "epoch_5", name: "Epoch 5" }, +// ]); - const age = /** @type {const} */ ([ - { - key: "", - id: "", - name: "", - }, - ...xTermHolders, - ...upTo, - ...fromXToY, - ...fromX, - ...epochs, - ]); +// const age = /** @type {const} */ ([ +// { +// key: "", +// id: "", +// name: "", +// }, +// ...xTermHolders, +// ...upTo, +// ...fromXToY, +// ...fromX, +// ...epochs, +// ]); - const size = /** @type {const} */ ([ - { - key: "plankton", - name: "Plankton", - size: "1 sat to 0.1 BTC", - }, - { - key: "shrimp", - name: "Shrimp", - size: "0.1 sat to 1 BTC", - }, - { key: "crab", name: "Crab", size: "1 BTC to 10 BTC" }, - { key: "fish", name: "Fish", size: "10 BTC to 100 BTC" }, - { key: "shark", name: "Shark", size: "100 BTC to 1000 BTC" }, - { key: "whale", name: "Whale", size: "1000 BTC to 10 000 BTC" }, - { - key: "humpback", - name: "Humpback", - size: "10 000 BTC to 100 000 BTC", - }, - { - key: "megalodon", - name: "Megalodon", - size: "More than 100 000 BTC", - }, - ]); +// const size = /** @type {const} */ ([ +// { +// key: "plankton", +// name: "Plankton", +// size: "1 sat to 0.1 BTC", +// }, +// { +// key: "shrimp", +// name: "Shrimp", +// size: "0.1 sat to 1 BTC", +// }, +// { key: "crab", name: "Crab", size: "1 BTC to 10 BTC" }, +// { key: "fish", name: "Fish", size: "10 BTC to 100 BTC" }, +// { key: "shark", name: "Shark", size: "100 BTC to 1000 BTC" }, +// { key: "whale", name: "Whale", size: "1000 BTC to 10 000 BTC" }, +// { +// key: "humpback", +// name: "Humpback", +// size: "10 000 BTC to 100 000 BTC", +// }, +// { +// key: "megalodon", +// name: "Megalodon", +// size: "More than 100 000 BTC", +// }, +// ]); - const type = /** @type {const} */ ([ - { key: "p2pk", name: "P2PK" }, - { key: "p2pkh", name: "P2PKH" }, - { key: "p2sh", name: "P2SH" }, - { key: "p2wpkh", name: "P2WPKH" }, - { key: "p2wsh", name: "P2WSH" }, - { key: "p2tr", name: "P2TR" }, - ]); +// const type = /** @type {const} */ ([ +// { key: "p2pk", name: "P2PK" }, +// { key: "p2pkh", name: "P2PKH" }, +// { key: "p2sh", name: "P2SH" }, +// { key: "p2wpkh", name: "P2WPKH" }, +// { key: "p2wsh", name: "P2WSH" }, +// { key: "p2tr", name: "P2TR" }, +// ]); - const address = /** @type {const} */ ([...size, ...type]); +// const address = /** @type {const} */ ([...size, ...type]); - const liquidities = /** @type {const} */ ([ - { - key: "illiquid", - id: "illiquid", - name: "Illiquid", - }, - { key: "liquid", id: "liquid", name: "Liquid" }, - { - key: "highly_liquid", - id: "highly-liquid", - name: "Highly Liquid", - }, - ]); +// const liquidities = /** @type {const} */ ([ +// { +// key: "illiquid", +// id: "illiquid", +// name: "Illiquid", +// }, +// { key: "liquid", id: "liquid", name: "Liquid" }, +// { +// key: "highly_liquid", +// id: "highly-liquid", +// name: "Highly Liquid", +// }, +// ]); - const averages = /** @type {const} */ ([ - { name: "1 Week", key: "1w", days: 7 }, - { name: "8 Days", key: "8d", days: 8 }, - { name: "13 Days", key: "13d", days: 13 }, - { name: "21 Days", key: "21d", days: 21 }, - { name: "1 Month", key: "1m", days: 30 }, - { name: "34 Days", key: "34d", days: 34 }, - { name: "55 Days", key: "55d", days: 55 }, - { name: "89 Days", key: "89d", days: 89 }, - { name: "144 Days", key: "144d", days: 144 }, - { name: "1 Year", key: "1y", days: 365 }, - { name: "2 Years", key: "2y", days: 2 * 365 }, - { name: "200 Weeks", key: "200w", days: 200 * 7 }, - { name: "4 Years", key: "4y", days: 4 * 365 }, - ]); +// const averages = /** @type {const} */ ([ +// { name: "1 Week", key: "1w", days: 7 }, +// { name: "8 Days", key: "8d", days: 8 }, +// { name: "13 Days", key: "13d", days: 13 }, +// { name: "21 Days", key: "21d", days: 21 }, +// { name: "1 Month", key: "1m", days: 30 }, +// { name: "34 Days", key: "34d", days: 34 }, +// { name: "55 Days", key: "55d", days: 55 }, +// { name: "89 Days", key: "89d", days: 89 }, +// { name: "144 Days", key: "144d", days: 144 }, +// { name: "1 Year", key: "1y", days: 365 }, +// { name: "2 Years", key: "2y", days: 2 * 365 }, +// { name: "200 Weeks", key: "200w", days: 200 * 7 }, +// { name: "4 Years", key: "4y", days: 4 * 365 }, +// ]); - const totalReturns = /** @type {const} */ ([ - { name: "1 Day", key: "1d" }, - { name: "1 Month", key: "1m" }, - { name: "6 Months", key: "6m" }, - { name: "1 Year", key: "1y" }, - { name: "2 Years", key: "2y" }, - { name: "3 Years", key: "3y" }, - { name: "4 Years", key: "4y" }, - { name: "6 Years", key: "6y" }, - { name: "8 Years", key: "8y" }, - { name: "10 Years", key: "10y" }, - ]); +// const totalReturns = /** @type {const} */ ([ +// { name: "1 Day", key: "1d" }, +// { name: "1 Month", key: "1m" }, +// { name: "6 Months", key: "6m" }, +// { name: "1 Year", key: "1y" }, +// { name: "2 Years", key: "2y" }, +// { name: "3 Years", key: "3y" }, +// { name: "4 Years", key: "4y" }, +// { name: "6 Years", key: "6y" }, +// { name: "8 Years", key: "8y" }, +// { name: "10 Years", key: "10y" }, +// ]); - const compoundReturns = /** @type {const} */ ([ - { name: "4 Years", key: "4y" }, - ]); +// const compoundReturns = /** @type {const} */ ([ +// { name: "4 Years", key: "4y" }, +// ]); - const percentiles = /** @type {const} */ ([ - { - key: "median_price_paid", - id: "median-price-paid", - name: "Median", - title: "Median Paid", - value: 50, - }, - { - key: "95p_price_paid", - id: "95p-price-paid", - name: `95%`, - title: `95th Percentile Paid`, - value: 95, - }, - { - key: "90p_price_paid", - id: "90p-price-paid", - name: `90%`, - title: `90th Percentile Paid`, - value: 90, - }, - { - key: "85p_price_paid", - id: "85p-price-paid", - name: `85%`, - title: `85th Percentile Paid`, - value: 85, - }, - { - key: "80p_price_paid", - id: "80p-price-paid", - name: `80%`, - title: `80th Percentile Paid`, - value: 80, - }, - { - key: "75p_price_paid", - id: "75p-price-paid", - name: `75%`, - title: `75th Percentile Paid`, - value: 75, - }, - { - key: "70p_price_paid", - id: "70p-price-paid", - name: `70%`, - title: `70th Percentile Paid`, - value: 70, - }, - { - key: "65p_price_paid", - id: "65p-price-paid", - name: `65%`, - title: `65th Percentile Paid`, - value: 65, - }, - { - key: "60p_price_paid", - id: "60p-price-paid", - name: `60%`, - title: `60th Percentile Paid`, - value: 60, - }, - { - key: "55p_price_paid", - id: "55p-price-paid", - name: `55%`, - title: `55th Percentile Paid`, - value: 55, - }, - { - key: "45p_price_paid", - id: "45p-price-paid", - name: `45%`, - title: `45th Percentile Paid`, - value: 45, - }, - { - key: "40p_price_paid", - id: "40p-price-paid", - name: `40%`, - title: `40th Percentile Paid`, - value: 40, - }, - { - key: "35p_price_paid", - id: "35p-price-paid", - name: `35%`, - title: `35th Percentile Paid`, - value: 35, - }, - { - key: "30p_price_paid", - id: "30p-price-paid", - name: `30%`, - title: `30th Percentile Paid`, - value: 30, - }, - { - key: "25p_price_paid", - id: "25p-price-paid", - name: `25%`, - title: `25th Percentile Paid`, - value: 25, - }, - { - key: "20p_price_paid", - id: "20p-price-paid", - name: `20%`, - title: `20th Percentile Paid`, - value: 20, - }, - { - key: "15p_price_paid", - id: "15p-price-paid", - name: `15%`, - title: `15th Percentile Paid`, - value: 15, - }, - { - key: "10p_price_paid", - id: "10p-price-paid", - name: `10%`, - title: `10th Percentile Paid`, - value: 10, - }, - { - key: "05p_price_paid", - id: "05p-price-paid", - name: `5%`, - title: `5th Percentile Paid`, - value: 5, - }, - ]); +// const percentiles = /** @type {const} */ ([ +// { +// key: "median_price_paid", +// id: "median-price-paid", +// name: "Median", +// title: "Median Paid", +// value: 50, +// }, +// { +// key: "95p_price_paid", +// id: "95p-price-paid", +// name: `95%`, +// title: `95th Percentile Paid`, +// value: 95, +// }, +// { +// key: "90p_price_paid", +// id: "90p-price-paid", +// name: `90%`, +// title: `90th Percentile Paid`, +// value: 90, +// }, +// { +// key: "85p_price_paid", +// id: "85p-price-paid", +// name: `85%`, +// title: `85th Percentile Paid`, +// value: 85, +// }, +// { +// key: "80p_price_paid", +// id: "80p-price-paid", +// name: `80%`, +// title: `80th Percentile Paid`, +// value: 80, +// }, +// { +// key: "75p_price_paid", +// id: "75p-price-paid", +// name: `75%`, +// title: `75th Percentile Paid`, +// value: 75, +// }, +// { +// key: "70p_price_paid", +// id: "70p-price-paid", +// name: `70%`, +// title: `70th Percentile Paid`, +// value: 70, +// }, +// { +// key: "65p_price_paid", +// id: "65p-price-paid", +// name: `65%`, +// title: `65th Percentile Paid`, +// value: 65, +// }, +// { +// key: "60p_price_paid", +// id: "60p-price-paid", +// name: `60%`, +// title: `60th Percentile Paid`, +// value: 60, +// }, +// { +// key: "55p_price_paid", +// id: "55p-price-paid", +// name: `55%`, +// title: `55th Percentile Paid`, +// value: 55, +// }, +// { +// key: "45p_price_paid", +// id: "45p-price-paid", +// name: `45%`, +// title: `45th Percentile Paid`, +// value: 45, +// }, +// { +// key: "40p_price_paid", +// id: "40p-price-paid", +// name: `40%`, +// title: `40th Percentile Paid`, +// value: 40, +// }, +// { +// key: "35p_price_paid", +// id: "35p-price-paid", +// name: `35%`, +// title: `35th Percentile Paid`, +// value: 35, +// }, +// { +// key: "30p_price_paid", +// id: "30p-price-paid", +// name: `30%`, +// title: `30th Percentile Paid`, +// value: 30, +// }, +// { +// key: "25p_price_paid", +// id: "25p-price-paid", +// name: `25%`, +// title: `25th Percentile Paid`, +// value: 25, +// }, +// { +// key: "20p_price_paid", +// id: "20p-price-paid", +// name: `20%`, +// title: `20th Percentile Paid`, +// value: 20, +// }, +// { +// key: "15p_price_paid", +// id: "15p-price-paid", +// name: `15%`, +// title: `15th Percentile Paid`, +// value: 15, +// }, +// { +// key: "10p_price_paid", +// id: "10p-price-paid", +// name: `10%`, +// title: `10th Percentile Paid`, +// value: 10, +// }, +// { +// key: "05p_price_paid", +// id: "05p-price-paid", +// name: `5%`, +// title: `5th Percentile Paid`, +// value: 5, +// }, +// ]); - return { - xTermHolders, - upTo, - fromX, - fromXToY, - epochs, - age, - type, - size, - address, - liquidities, - averages, - totalReturns, - compoundReturns, - percentiles, - }; -} -/** - * @typedef {ReturnType} Groups - * - * @typedef {Groups["age"][number]["id"]} AgeCohortId - * - * @typedef {Exclude} AgeCohortIdSub - * - * @typedef {Groups["address"][number]["key"]} AddressCohortId - * - * @typedef {Groups["liquidities"][number]["id"]} LiquidityId - * - * @typedef {AgeCohortId | AddressCohortId} AnyCohortId - * - * @typedef {AddressCohortId | LiquidityId} AnyAddressCohortId - * - * @typedef {AnyCohortId | LiquidityId} AnyPossibleCohortId - * - * @typedef {'' | `${AgeCohortIdSub | AddressCohortId | LiquidityId}-`} AnyDatasetPrefix - * - * @typedef {Groups["averages"][number]["key"]} AverageName - * - * @typedef {Groups["totalReturns"][number]["key"]} TotalReturnKey - * - * @typedef {Groups["compoundReturns"][number]["key"]} CompoundReturnKey - * - * @typedef {Groups["percentiles"][number]["id"]} PercentileId - */ +// return { +// xTermHolders, +// upTo, +// fromX, +// fromXToY, +// epochs, +// age, +// type, +// size, +// address, +// liquidities, +// averages, +// totalReturns, +// compoundReturns, +// percentiles, +// }; +// } +// /** +// * @typedef {ReturnType} Groups +// * +// * @typedef {Groups["age"][number]["id"]} AgeCohortId +// * +// * @typedef {Exclude} AgeCohortIdSub +// * +// * @typedef {Groups["address"][number]["key"]} AddressCohortId +// * +// * @typedef {Groups["liquidities"][number]["id"]} LiquidityId +// * +// * @typedef {AgeCohortId | AddressCohortId} AnyCohortId +// * +// * @typedef {AddressCohortId | LiquidityId} AnyAddressCohortId +// * +// * @typedef {AnyCohortId | LiquidityId} AnyPossibleCohortId +// * +// * @typedef {'' | `${AgeCohortIdSub | AddressCohortId | LiquidityId}-`} AnyDatasetPrefix +// * +// * @typedef {Groups["averages"][number]["key"]} AverageName +// * +// * @typedef {Groups["totalReturns"][number]["key"]} TotalReturnKey +// * +// * @typedef {Groups["compoundReturns"][number]["key"]} CompoundReturnKey +// * +// * @typedef {Groups["percentiles"][number]["id"]} PercentileId +// */ /** * @param {Colors} colors @@ -647,164 +658,152 @@ function initGroups() { */ function createPartialOptions(colors) { /** - * @typedef {"total-"} TotalPrefix - * @typedef {Extract} TotalVecId - * @typedef {"-sum"} SumSuffix - * @typedef {Extract} VecIdSum - * @typedef {"-average"} AverageSuffix - * @typedef {Extract} VecIdAverage - * @typedef {"-median"} MedianSuffix - * @typedef {Extract} VecIdMedian - * @typedef {"-90p"} _90pSuffix - * @typedef {Extract} VecId90p - * @typedef {"-75p"} _75pSuffix - * @typedef {Extract} VecId75p - * @typedef {"-25p"} _25pSuffix - * @typedef {Extract} VecId25p - * @typedef {"-10p"} _10pSuffix - * @typedef {Extract} VecId10p - * @typedef {"-max"} MaxSuffix - * @typedef {Extract} VecIdMax - * @typedef {"-min"} MinSuffix - * @typedef {Extract} VecIdMin - * @typedef {VecId extends infer X - ? X extends string - ? `${X}${SumSuffix}` extends VecIdSum - ? `${TotalPrefix}${X}` extends TotalVecId - ? X - : never - : never - : never - : never} BaseTotalSumVecId - * @typedef {VecId extends infer X - ? X extends string - ? `${X}${MinSuffix}` extends VecIdMin - ? `${X}${MaxSuffix}` extends VecIdMax - ? X - : never - : never - : never - : never} MinMaxVecId - * @typedef {VecId extends infer X - ? X extends string - ? `${X}${AverageSuffix}` extends VecIdAverage - ? X - : never - : never - : never} AverageVecId - * @typedef {VecId extends infer X - ? X extends string - ? `${X}${MedianSuffix}` extends VecIdMedian - ? X - : never - : never - : never} MedianVecId - * @typedef {VecId extends infer X - ? X extends string - ? `${X}${_90pSuffix}` extends VecId90p - ? `${X}${_75pSuffix}` extends VecId75p - ? `${X}${_25pSuffix}` extends VecId25p - ? `${X}${_10pSuffix}` extends VecId10p - ? X - : never - : never - : never - : never - : never - : never} PercentilesVecId - * @typedef {AverageVecId & MinMaxVecId & MedianVecId & PercentilesVecId} AverageMinMaxPercentilesVecId + * @template {string} S + * @typedef {Extract} StartsWith + */ + /** + * @template {string} S + * @typedef {Extract} EndsWith + */ + /** + * @template {string} K + * @template {string} S + * @typedef {K extends `${S}${infer Rest}` ? Rest : never} WithoutPrefix + */ + /** + * @template {string} K + * @template {string} S + * @typedef {K extends `${infer Rest}${S}` ? Rest : never} WithoutSuffix */ /** - * @template {BaseTotalSumVecId} T - * @param {Object} args - * @param {string} args.name - * @param {string} args.title - * @param {T} args.key + * @typedef {"total-"} TotalPrefix + * @typedef {StartsWith} TotalVecId + * @typedef {WithoutPrefix} TotalVecIdBase + * @typedef {"-sum"} SumSuffix + * @typedef {EndsWith} VecIdSum + * @typedef {WithoutSuffix} VecIdSumBase + * @typedef {"-average"} 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 {"-max"} MaxSuffix + * @typedef {EndsWith} VecIdMax + * @typedef {WithoutSuffix} VecIdMaxBase + * @typedef {"-min"} MinSuffix + * @typedef {EndsWith} VecIdMin + * @typedef {WithoutSuffix} VecIdMinBase */ - function createBaseSumTotal({ name, title, key }) { - return /** @satisfies {PartialChartOption} */ ({ - name, - title, - bottom: [ - { key, title: name, color: colors.bitcoin }, - { - key: `${key}-sum`, - title: "Sum", - color: colors.bitcoin, - }, - { - key: `total-${key}`, - title: "Total", - color: colors.offBitcoin, - defaultActive: false, - }, - ], + + /** + * + * @param {Object} args + * @param {ChartableVecId} args.key + * @param {string} args.name + * @returns + */ + function createBaseSeries({ key, name }) { + return { key, title: name, color: colors.bitcoin }; + } + + /** + * @template {VecIdAverageBase} T + * @param {Object} args + * @param {T} args.concat + */ + function createAverageSeries({ concat }) { + return /** @satisfies {AnyFetchedSeriesBlueprint} */ ({ + key: `${concat}-average`, + title: "Average", + color: colors.orange, }); } /** - * @template {AverageMinMaxPercentilesVecId} T + * @template {VecIdSumBase & TotalVecIdBase} T * @param {Object} args - * @param {string} args.name - * @param {string} args.title - * @param {T} args.key + * @param {T} args.concat */ - function createBaseAverageMinMaxPercentiles({ name, title, key }) { - return /** @satisfies {PartialChartOption} */ ({ - name, - title, - bottom: [ - { key, title: name, color: colors.bitcoin }, - { - key: `${key}-average`, - title: "Average", - color: colors.orange, - }, - { - key: `${key}-median`, - title: "Median", - color: colors.amber, - defaultActive: false, - }, - { - key: `${key}-75p`, - title: "75p", - color: colors.red, - defaultActive: false, - }, - { - key: `${key}-25p`, - title: "25p", - color: colors.yellow, - defaultActive: false, - }, - { - key: `${key}-90p`, - title: "90p", - color: colors.rose, - defaultActive: false, - }, - { - key: `${key}-10p`, - title: "10p", - color: colors.lime, - defaultActive: false, - }, - { - key: `${key}-max`, - title: "Max", - color: colors.pink, - defaultActive: false, - }, - { - key: `${key}-min`, - title: "Min", - color: colors.green, - defaultActive: false, - }, - ], - }); + function createSumTotalSeries({ concat }) { + return /** @satisfies {AnyFetchedSeriesBlueprint[]} */ ([ + { + key: `${concat}-sum`, + title: "Sum", + color: colors.bitcoin, + }, + { + key: `total-${concat}`, + title: "Total", + color: colors.offBitcoin, + defaultActive: false, + }, + ]); + } + + /** + * @template {VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} T + * @param {Object} args + * @param {T} args.concat + */ + function createMinMaxPercentilesSeries({ concat }) { + return /** @satisfies {AnyFetchedSeriesBlueprint[]} */ ([ + { + key: `${concat}-median`, + title: "Median", + color: colors.amber, + defaultActive: false, + }, + { + key: `${concat}-75p`, + title: "75p", + color: colors.red, + defaultActive: false, + }, + { + key: `${concat}-25p`, + title: "25p", + color: colors.yellow, + defaultActive: false, + }, + { + key: `${concat}-90p`, + title: "90p", + color: colors.rose, + defaultActive: false, + }, + { + key: `${concat}-10p`, + title: "10p", + color: colors.lime, + defaultActive: false, + }, + { + key: `${concat}-max`, + title: "Max", + color: colors.pink, + defaultActive: false, + }, + { + key: `${concat}-min`, + title: "Min", + color: colors.green, + defaultActive: false, + }, + ]); } return [ @@ -821,13 +820,11 @@ function createPartialOptions(colors) { { name: "usd/sats", title: "Satoshis Per US Dollar", - unit: "Satoshis", bottom: [ - { + createBaseSeries({ key: "sats-per-dollar", - title: "Satoshis", - color: colors.bitcoin, - }, + name: "Satoshis", + }), ], }, ], @@ -835,69 +832,185 @@ function createPartialOptions(colors) { { name: "Block", tree: [ - createBaseSumTotal({ + { name: "Count", title: "Block Count", - key: "block-count", - }), - createBaseAverageMinMaxPercentiles({ + bottom: [ + createBaseSeries({ + key: "block-count", + name: "Count", + }), + ...createSumTotalSeries({ concat: "block-count" }), + ], + }, + { name: "Interval", title: "Block Interval", - key: "block-interval", - }), - createBaseSumTotal({ + bottom: [ + createBaseSeries({ + key: "interval", + name: "Interval", + }), + createAverageSeries({ concat: "block-interval" }), + ...createMinMaxPercentilesSeries({ + concat: "block-interval", + }), + ], + }, + { name: "Size", title: "Block Size", - key: "block-size", - }), - createBaseSumTotal({ + bottom: [ + createBaseSeries({ + key: "total-size", + name: "Size", + }), + ...createSumTotalSeries({ concat: "block-size" }), + ], + }, + { name: "Weight", title: "Block Weight", - key: "block-weight", - }), - createBaseSumTotal({ + bottom: [ + createBaseSeries({ + key: "weight", + name: "Weight", + }), + ...createSumTotalSeries({ concat: "block-weight" }), + ], + }, + { name: "Vbytes", title: "Block Virtual Bytes", - key: "block-vbytes", - }), + bottom: [ + createBaseSeries({ + key: "vbytes", + name: "Vbytes", + }), + ...createSumTotalSeries({ concat: "block-vbytes" }), + ], + }, ], }, { name: "Transaction", tree: [ - createBaseSumTotal({ + { name: "Count", title: "Transaction Count", - key: "tx-count", - }), - createBaseSumTotal({ + bottom: [ + createBaseSeries({ + key: "tx-count", + name: "Count", + }), + createAverageSeries({ concat: "tx-count" }), + ...createSumTotalSeries({ concat: "tx-count" }), + ...createMinMaxPercentilesSeries({ + concat: "tx-count", + }), + ], + }, + { + name: "Subsidy", + title: "Subsidy", + bottom: [ + createBaseSeries({ + key: "subsidy", + name: "Subsidy", + }), + createAverageSeries({ concat: "subsidy" }), + ...createSumTotalSeries({ concat: "subsidy" }), + ...createMinMaxPercentilesSeries({ concat: "subsidy" }), + ], + }, + { + name: "Coinbase", + title: "Coinbase", + bottom: [ + createBaseSeries({ + key: "coinbase", + name: "Coinbase", + }), + createAverageSeries({ concat: "coinbase" }), + ...createSumTotalSeries({ concat: "coinbase" }), + ...createMinMaxPercentilesSeries({ concat: "coinbase" }), + ], + }, + { name: "Fee", title: "Transaction Fee", - key: "fee", - }), - createBaseAverageMinMaxPercentiles({ + bottom: [ + createAverageSeries({ concat: "fee" }), + ...createSumTotalSeries({ concat: "fee" }), + ...createMinMaxPercentilesSeries({ concat: "fee" }), + ], + }, + { name: "Feerate", title: "Transaction Fee Rate", - key: "feerate", - }), + bottom: [ + createAverageSeries({ concat: "feerate" }), + ...createMinMaxPercentilesSeries({ + concat: "feerate", + }), + ], + }, + { + name: "Weight", + title: "Transaction Weight", + bottom: [ + createAverageSeries({ concat: "tx-weight" }), + ...createMinMaxPercentilesSeries({ + concat: "tx-weight", + }), + ], + }, + { + name: "vsize", + title: "Transaction Virtual Size", + bottom: [ + createAverageSeries({ concat: "tx-vsize" }), + ...createMinMaxPercentilesSeries({ + concat: "tx-vsize", + }), + ], + }, { name: "Version", tree: [ - createBaseSumTotal({ + { name: "1", title: "Transaction V1 Count", - key: "tx-v1", - }), - createBaseSumTotal({ + bottom: [ + createBaseSeries({ + key: "tx-v1", + name: "Count", + }), + ...createSumTotalSeries({ concat: "tx-v1" }), + ], + }, + { name: "2", title: "Transaction V2 Count", - key: "tx-v2", - }), - createBaseSumTotal({ + bottom: [ + createBaseSeries({ + key: "tx-v2", + name: "Count", + }), + ...createSumTotalSeries({ concat: "tx-v2" }), + ], + }, + { name: "3", title: "Transaction V3 Count", - key: "tx-v3", - }), + bottom: [ + createBaseSeries({ + key: "tx-v3", + name: "Count", + }), + ...createSumTotalSeries({ concat: "tx-v3" }), + ], + }, ], }, ], @@ -905,31 +1018,49 @@ function createPartialOptions(colors) { { name: "Input", tree: [ - createBaseSumTotal({ + { name: "Count", title: "Transaction Input Count", - key: "input-count", - }), - createBaseSumTotal({ + bottom: [ + createAverageSeries({ concat: "input-count" }), + ...createSumTotalSeries({ concat: "input-count" }), + ...createMinMaxPercentilesSeries({ + concat: "input-count", + }), + ], + }, + { name: "Value", title: "Transaction Input Value", - key: "input-value", - }), + bottom: [ + createAverageSeries({ concat: "input-value" }), + ...createSumTotalSeries({ concat: "input-value" }), + ], + }, ], }, { name: "Output", tree: [ - createBaseSumTotal({ + { name: "Count", title: "Transaction Output Count", - key: "output-count", - }), - createBaseSumTotal({ + bottom: [ + createAverageSeries({ concat: "output-count" }), + ...createSumTotalSeries({ concat: "output-count" }), + ...createMinMaxPercentilesSeries({ + concat: "output-count", + }), + ], + }, + { name: "Value", title: "Transaction Output Value", - key: "output-value", - }), + bottom: [ + createAverageSeries({ concat: "output-value" }), + ...createSumTotalSeries({ concat: "output-value" }), + ], + }, ], }, ], @@ -1284,7 +1415,7 @@ export function initOptions({ id = `${kind}-${utils.stringToId(title)}`; const key = anyPartial.bottom?.at(0)?.key; if (key) { - if (key.includes("-interval")) { + if (key.includes("interval")) { anyPartial.unit = "Seconds"; } else if (key.includes("feerate")) { anyPartial.unit = "sat/vB"; @@ -1292,21 +1423,23 @@ export function initOptions({ key.startsWith("sats-") || key.includes("input-value") || key.includes("output-value") || - key.includes("fee") + key.includes("fee") || + key.startsWith("coinbase") || + key.startsWith("subsidy") ) { - anyPartial.unit = "Satoshis"; + anyPartial.unit = "Sats"; } else if (key.includes("count")) { anyPartial.unit = "Count"; } else if (key.includes("-size")) { anyPartial.unit = "Megabytes"; - } else if (key.includes("-weight")) { + } else if (key.includes("weight")) { anyPartial.unit = "Weight Units"; - } else if (key.includes("-vbytes")) { + } else if (key.includes("vbytes") || key.includes("vsize")) { anyPartial.unit = "Virtual Bytes"; - } else if (key.match(/v[0-9]/g)) { + } else if (key.match(/v[1-3]/g)) { anyPartial.unit = "Version"; } else { - console.log(anyPartial); + console.log([key, anyPartial]); throw Error("Unit not set"); } } @@ -1422,7 +1555,7 @@ export function initOptions({ // ); // switch (unit) { -// case "US Dollars": { +// case "USD": { // return `$${s}`; // } // case "Bitcoin": { diff --git a/websites/kibo.money/scripts/simulation.js b/websites/kibo.money/scripts/simulation.js index fdd075376..992ada163 100644 --- a/websites/kibo.money/scripts/simulation.js +++ b/websites/kibo.money/scripts/simulation.js @@ -557,7 +557,7 @@ export function init({ utils, config: [ { - unit: "US Dollars", + unit: "USD", blueprints: [ { title: "Bitcoin Value", @@ -600,7 +600,7 @@ export function init({ utils, config: [ { - unit: "Bitcoin", + unit: "BTC", blueprints: [ { title: "Bitcoin Stack", @@ -623,7 +623,7 @@ export function init({ utils, config: [ { - unit: "US Dollars", + unit: "USD", blueprints: [ { title: "Bitcoin Price", @@ -652,7 +652,7 @@ export function init({ utils, config: [ { - unit: "US Dollars", + unit: "USD", blueprints: [ { title: "Return Of Investment", diff --git a/websites/kibo.money/scripts/vecid-to-indexes.js b/websites/kibo.money/scripts/vecid-to-indexes.js index bb03c414c..10f75822c 100644 --- a/websites/kibo.money/scripts/vecid-to-indexes.js +++ b/websites/kibo.money/scripts/vecid-to-indexes.js @@ -57,14 +57,13 @@ export function createVecIdToIndexes() { const Pushonlyindex = /** @satisfies {Pushonlyindex} */ (23); const Unknownindex = /** @satisfies {Unknownindex} */ (24); - return { + return /** @type {const} */ ({ addressindex: [Txoutindex], addresstype: [Addressindex], addresstypeindex: [Addressindex], "base-size": [Txindex], "block-count": [Height], "block-count-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], - "block-interval": [Height], "block-interval-10p": [Dateindex], "block-interval-25p": [Dateindex], "block-interval-75p": [Dateindex], @@ -73,21 +72,36 @@ export function createVecIdToIndexes() { "block-interval-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "block-interval-median": [Dateindex], "block-interval-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], - "block-size": [Height], "block-size-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], - "block-vbytes": [Height], "block-vbytes-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], - "block-weight": [Height], "block-weight-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], blockhash: [Height], close: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "close-in-cents": [Dateindex, Height], + coinbase: [Height], + "coinbase-10p": [Dateindex], + "coinbase-25p": [Dateindex], + "coinbase-75p": [Dateindex], + "coinbase-90p": [Dateindex], + "coinbase-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "coinbase-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "coinbase-median": [Dateindex], + "coinbase-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "coinbase-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], date: [Dateindex], dateindex: [Dateindex, Height], decadeindex: [Yearindex, Decadeindex], difficulty: [Height], difficultyepoch: [Height, Difficultyepoch], fee: [Txindex], + "fee-10p": [Height], + "fee-25p": [Height], + "fee-75p": [Height], + "fee-90p": [Height], + "fee-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "fee-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "fee-median": [Height], + "fee-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "fee-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], feerate: [Txindex], "feerate-10p": [Height], @@ -125,9 +139,19 @@ export function createVecIdToIndexes() { high: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "high-in-cents": [Dateindex, Height], "input-count": [Txindex], + "input-count-10p": [Height], + "input-count-25p": [Height], + "input-count-75p": [Height], + "input-count-90p": [Height], + "input-count-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "input-count-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "input-count-median": [Height], + "input-count-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "input-count-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "input-value": [Txindex], + "input-value-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "input-value-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + interval: [Height], "is-coinbase": [Txindex], "is-explicitly-rbf": [Txindex], "last-dateindex": [Weekindex, Monthindex], @@ -146,8 +170,17 @@ export function createVecIdToIndexes() { open: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "open-in-cents": [Dateindex, Height], "output-count": [Txindex], + "output-count-10p": [Height], + "output-count-25p": [Height], + "output-count-75p": [Height], + "output-count-90p": [Height], + "output-count-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "output-count-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "output-count-median": [Height], + "output-count-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "output-count-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "output-value": [Txindex], + "output-value-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "output-value-sum": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], p2pk33addressbytes: [P2PK33index], p2pk65addressbytes: [P2PK65index], @@ -159,22 +192,42 @@ export function createVecIdToIndexes() { quarterindex: [Monthindex, Quarterindex], "real-date": [Height], "sats-per-dollar": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + subsidy: [Height], + "subsidy-10p": [Dateindex], + "subsidy-25p": [Dateindex], + "subsidy-75p": [Dateindex], + "subsidy-90p": [Dateindex], + "subsidy-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "subsidy-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "subsidy-median": [Dateindex], + "subsidy-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "subsidy-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], timestamp: [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch, Halvingepoch], "total-block-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-block-size": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-block-vbytes": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-block-weight": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "total-coinbase": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-fee": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-input-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-input-value": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-output-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-output-value": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], - "total-size": [Txindex], + "total-size": [Height, Txindex], + "total-subsidy": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-tx-count": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-tx-v1": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-tx-v2": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "total-tx-v3": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "tx-count": [Height], + "tx-count-10p": [Dateindex], + "tx-count-25p": [Dateindex], + "tx-count-75p": [Dateindex], + "tx-count-90p": [Dateindex], + "tx-count-average": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-count-max": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-count-median": [Dateindex], + "tx-count-min": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "tx-count-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "tx-v1": [Height], "tx-v1-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], @@ -182,15 +235,32 @@ export function createVecIdToIndexes() { "tx-v2-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], "tx-v3": [Height], "tx-v3-sum": [Dateindex, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-vsize-10p": [Height], + "tx-vsize-25p": [Height], + "tx-vsize-75p": [Height], + "tx-vsize-90p": [Height], + "tx-vsize-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-vsize-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-vsize-median": [Height], + "tx-vsize-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-weight-10p": [Height], + "tx-weight-25p": [Height], + "tx-weight-75p": [Height], + "tx-weight-90p": [Height], + "tx-weight-average": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-weight-max": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], + "tx-weight-median": [Height], + "tx-weight-min": [Dateindex, Height, Weekindex, Monthindex, Quarterindex, Yearindex, Decadeindex, Difficultyepoch], txid: [Txindex], txoutindex: [Txinindex], txversion: [Txindex], value: [Txinindex, Txoutindex], + vbytes: [Height], vsize: [Txindex], weekindex: [Dateindex, Weekindex], - weight: [Txindex], + weight: [Height, Txindex], yearindex: [Monthindex, Yearindex], - } + }); } /** @typedef {ReturnType} VecIdToIndexes */ /** @typedef {keyof VecIdToIndexes} VecId */