diff --git a/crates/brk_computer/src/chain.rs b/crates/brk_computer/src/chain.rs index e03275936..cd94b4f70 100644 --- a/crates/brk_computer/src/chain.rs +++ b/crates/brk_computer/src/chain.rs @@ -31,6 +31,7 @@ const TARGET_BLOCKS_PER_QUARTER: u64 = 3 * TARGET_BLOCKS_PER_MONTH; const TARGET_BLOCKS_PER_SEMESTER: u64 = 2 * TARGET_BLOCKS_PER_QUARTER; const TARGET_BLOCKS_PER_YEAR: u64 = 2 * TARGET_BLOCKS_PER_SEMESTER; const TARGET_BLOCKS_PER_DECADE: u64 = 10 * TARGET_BLOCKS_PER_YEAR; +const ONE_TERA_HASH: f64 = 1_000_000_000_000.0; #[derive(Clone, Allocative)] pub struct Vecs { @@ -112,10 +113,22 @@ pub struct Vecs { 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_hash_price_ths: ComputedVecsFromDateIndex, + pub indexes_to_hash_price_ths_min: ComputedVecsFromDateIndex, + pub indexes_to_hash_price_phs: ComputedVecsFromDateIndex, + pub indexes_to_hash_price_phs_min: ComputedVecsFromDateIndex, + pub indexes_to_hash_price_rebound: ComputedVecsFromDateIndex, + pub indexes_to_hash_value_ths: ComputedVecsFromDateIndex, + pub indexes_to_hash_value_ths_min: ComputedVecsFromDateIndex, + pub indexes_to_hash_value_phs: ComputedVecsFromDateIndex, + pub indexes_to_hash_value_phs_min: ComputedVecsFromDateIndex, + pub indexes_to_hash_value_rebound: ComputedVecsFromDateIndex, pub indexes_to_difficulty_as_hash: ComputedVecsFromDateIndex, pub indexes_to_difficulty_adjustment: ComputedVecsFromHeight, pub indexes_to_blocks_before_next_difficulty_adjustment: ComputedVecsFromHeight, pub indexes_to_days_before_next_difficulty_adjustment: ComputedVecsFromHeight, + pub indexes_to_blocks_before_next_halving: ComputedVecsFromHeight, + pub indexes_to_days_before_next_halving: ComputedVecsFromHeight, } impl Vecs { @@ -917,6 +930,102 @@ impl Vecs { indexes, VecBuilderOptions::default().add_last(), )?, + indexes_to_blocks_before_next_halving: ComputedVecsFromHeight::forced_import( + &db, + "blocks_before_next_halving", + Source::Compute, + version + VERSION + Version::TWO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_days_before_next_halving: ComputedVecsFromHeight::forced_import( + &db, + "days_before_next_halving", + Source::Compute, + version + VERSION + Version::TWO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_price_ths: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_price_ths", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_price_phs: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_price_phs", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_value_ths: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_value_ths", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_value_phs: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_value_phs", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_price_ths_min: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_price_ths_min", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_price_phs_min: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_price_phs_min", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_price_rebound: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_price_rebound", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_value_ths_min: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_value_ths_min", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_value_phs_min: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_value_phs_min", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, + indexes_to_hash_value_rebound: ComputedVecsFromDateIndex::forced_import( + &db, + "hash_value_rebound", + Source::Compute, + version + VERSION + Version::ZERO, + indexes, + VecBuilderOptions::default().add_last(), + )?, txindex_to_is_coinbase, inputindex_to_value, @@ -1713,6 +1822,169 @@ impl Vecs { Ok(()) })?; + self.indexes_to_blocks_before_next_halving.compute_all( + indexes, + starting_indexes, + exit, + |v| { + v.compute_transform( + starting_indexes.height, + &indexes.height_to_height, + |(h, ..)| (h, StoredU32::from(h.left_before_next_halving())), + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_days_before_next_halving.compute_all( + indexes, + starting_indexes, + exit, + |v| { + v.compute_transform( + starting_indexes.height, + self.indexes_to_blocks_before_next_halving + .height + .as_ref() + .unwrap(), + |(h, blocks, ..)| (h, (*blocks as f32 / TARGET_BLOCKS_PER_DAY_F32).into()), + exit, + )?; + Ok(()) + }, + )?; + + self.indexes_to_hash_price_ths + .compute_all(starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.dateindex, + self.indexes_to_coinbase + .dollars + .as_ref() + .unwrap() + .dateindex + .unwrap_sum(), + self.indexes_to_hash_rate.dateindex.as_ref().unwrap(), + |(i, coinbase_sum, hashrate, ..)| { + (i, (*coinbase_sum / (*hashrate / ONE_TERA_HASH)).into()) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_phs + .compute_all(starting_indexes, exit, |v| { + v.compute_transform( + starting_indexes.dateindex, + self.indexes_to_hash_price_ths.dateindex.as_ref().unwrap(), + |(i, price, ..)| (i, (*price * 1000.0).into()), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_ths + .compute_all(starting_indexes, exit, |v| { + v.compute_transform2( + starting_indexes.dateindex, + self.indexes_to_coinbase.sats.dateindex.unwrap_sum(), + self.indexes_to_hash_rate.dateindex.as_ref().unwrap(), + |(i, coinbase_sum, hashrate, ..)| { + ( + i, + (*coinbase_sum as f64 / (*hashrate / ONE_TERA_HASH)).into(), + ) + }, + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_phs + .compute_all(starting_indexes, exit, |v| { + v.compute_transform( + starting_indexes.dateindex, + self.indexes_to_hash_value_ths.dateindex.as_ref().unwrap(), + |(i, value, ..)| (i, (*value * 1000.0).into()), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_ths_min + .compute_all(starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.dateindex, + self.indexes_to_hash_price_ths.dateindex.as_ref().unwrap(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_phs_min + .compute_all(starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.dateindex, + self.indexes_to_hash_price_phs.dateindex.as_ref().unwrap(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_ths_min + .compute_all(starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.dateindex, + self.indexes_to_hash_value_ths.dateindex.as_ref().unwrap(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_phs_min + .compute_all(starting_indexes, exit, |v| { + v.compute_all_time_low_( + starting_indexes.dateindex, + self.indexes_to_hash_value_phs.dateindex.as_ref().unwrap(), + exit, + true, + )?; + Ok(()) + })?; + + self.indexes_to_hash_price_rebound + .compute_all(starting_indexes, exit, |v| { + v.compute_percentage_difference( + starting_indexes.dateindex, + self.indexes_to_hash_price_phs.dateindex.as_ref().unwrap(), + self.indexes_to_hash_price_phs_min + .dateindex + .as_ref() + .unwrap(), + exit, + )?; + Ok(()) + })?; + + self.indexes_to_hash_value_rebound + .compute_all(starting_indexes, exit, |v| { + v.compute_percentage_difference( + starting_indexes.dateindex, + self.indexes_to_hash_value_phs.dateindex.as_ref().unwrap(), + self.indexes_to_hash_value_phs_min + .dateindex + .as_ref() + .unwrap(), + exit, + )?; + Ok(()) + })?; + Ok(()) } @@ -1777,6 +2049,28 @@ impl Vecs { .iter_any_collectable(), ), ); + iter = Box::new( + iter.chain( + self.indexes_to_blocks_before_next_halving + .iter_any_collectable(), + ), + ); + iter = Box::new( + iter.chain( + self.indexes_to_days_before_next_halving + .iter_any_collectable(), + ), + ); + iter = Box::new(iter.chain(self.indexes_to_hash_price_ths.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_price_phs.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_value_ths.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_value_phs.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_price_ths_min.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_price_phs_min.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_value_ths_min.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_value_phs_min.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_price_rebound.iter_any_collectable())); + iter = Box::new(iter.chain(self.indexes_to_hash_value_rebound.iter_any_collectable())); iter = Box::new(iter.chain(self.indexes_to_coinbase.iter_any_collectable())); iter = Box::new(iter.chain(self.indexes_to_fee.iter_any_collectable())); diff --git a/crates/brk_structs/src/structs/halvingepoch.rs b/crates/brk_structs/src/structs/halvingepoch.rs index 8ef0a7623..1fd16c2a3 100644 --- a/crates/brk_structs/src/structs/halvingepoch.rs +++ b/crates/brk_structs/src/structs/halvingepoch.rs @@ -10,6 +10,8 @@ use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; use super::Height; +pub const BLOCKS_PER_HALVING: u32 = 210_000; + #[derive( Debug, Clone, @@ -78,7 +80,7 @@ impl Add for HalvingEpoch { impl From for HalvingEpoch { fn from(value: Height) -> Self { - Self((u32::from(value) / 210_000) as u16) + Self((u32::from(value) / BLOCKS_PER_HALVING) as u16) } } diff --git a/crates/brk_structs/src/structs/height.rs b/crates/brk_structs/src/structs/height.rs index 3c2ce2a2a..987530893 100644 --- a/crates/brk_structs/src/structs/height.rs +++ b/crates/brk_structs/src/structs/height.rs @@ -12,7 +12,7 @@ use vecdb::{CheckedSub, Printable, Stamp, StoredCompressed}; use zerocopy::{FromBytes, IntoBytes}; use zerocopy_derive::{FromBytes, Immutable, IntoBytes, KnownLayout}; -use crate::{BLOCKS_PER_DIFF_EPOCHS, copy_first_4bytes}; +use crate::{BLOCKS_PER_DIFF_EPOCHS, BLOCKS_PER_HALVING, copy_first_4bytes}; use super::StoredU64; @@ -74,7 +74,11 @@ impl Height { } pub fn left_before_next_diff_adj(self) -> u32 { - BLOCKS_PER_DIFF_EPOCHS - (*self % 2016) + BLOCKS_PER_DIFF_EPOCHS - (*self % BLOCKS_PER_DIFF_EPOCHS) + } + + pub fn left_before_next_halving(self) -> u32 { + BLOCKS_PER_HALVING - (*self % BLOCKS_PER_HALVING) } } diff --git a/websites/bitview/scripts/main.js b/websites/bitview/scripts/main.js index c01e54d3b..0cd257e6a 100644 --- a/websites/bitview/scripts/main.js +++ b/websites/bitview/scripts/main.js @@ -32,7 +32,10 @@ * "Timestamp" | * "tx" | * "Type" | - * "USD / (PetaHash / Second)" | + * "USD/(TH/s)/day" | + * "USD/(PH/s)/day" | + * "Sats/(TH/s)/day" | + * "Sats/(PH/s)/day" | * "USD" | * "Version" | * "WU" | @@ -839,11 +842,12 @@ function createUtils() { (!unit || thoroughUnitCheck) && (id === "price_drawdown" || id === "difficulty_adjustment" || - id.endsWith("oscillator") || - id.endsWith("dominance") || - id.endsWith("returns") || - id.endsWith("volatility") || - id.endsWith("cagr")) + id.endsWith("_oscillator") || + id.endsWith("_dominance") || + id.endsWith("_returns") || + id.endsWith("_rebound") || + id.endsWith("_volatility") || + id.endsWith("_cagr")) ) { setUnit("percentage"); } @@ -980,6 +984,19 @@ function createUtils() { if ((!unit || thoroughUnitCheck) && id === "blockhash") { setUnit("Hash"); } + if ((!unit || thoroughUnitCheck) && id.startsWith("hash_price_phs")) { + setUnit("USD/(PH/s)/day"); + } + if ((!unit || thoroughUnitCheck) && id.startsWith("hash_price_ths")) { + setUnit("USD/(TH/s)/day"); + } + if ((!unit || thoroughUnitCheck) && id.startsWith("hash_value_phs")) { + setUnit("Sats/(PH/s)/day"); + } + if ((!unit || thoroughUnitCheck) && id.startsWith("hash_value_ths")) { + setUnit("Sats/(TH/s)/day"); + } + if ( (!unit || thoroughUnitCheck) && (id.includes("days_between") || diff --git a/websites/bitview/scripts/options.js b/websites/bitview/scripts/options.js index 44864b3d2..8c43b42cd 100644 --- a/websites/bitview/scripts/options.js +++ b/websites/bitview/scripts/options.js @@ -3752,6 +3752,24 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) { }), ], }, + { + name: "Halving", + title: "Halving Epoch", + bottom: [ + createBaseSeries({ + key: "halvingepoch", + name: "Halving", + }), + createBaseSeries({ + key: "blocks_before_next_halving", + name: "Before next", + }), + createBaseSeries({ + key: "days_before_next_halving", + name: "Before next", + }), + ], + }, { name: "Difficulty", title: "Difficulty", @@ -3762,13 +3780,8 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) { }), createBaseSeries({ key: "difficultyepoch", - name: "Epoch", + name: "Difficulty", }), - { - key: "difficulty_adjustment", - title: "Adjustment", - type: "Baseline", - }, createBaseSeries({ key: "blocks_before_next_difficulty_adjustment", name: "Before next", @@ -3779,6 +3792,17 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) { }), ], }, + { + name: "adjustment", + title: "Difficulty adjustment", + bottom: [ + { + key: "difficulty_adjustment", + title: "difficulty change", + type: "Baseline", + }, + ], + }, { name: "hash", tree: [ @@ -3824,16 +3848,80 @@ function createPartialOptions({ env, colors, vecIdToIndexes, pools }) { }), ], }, - ], - }, - { - name: "Halving Epoch", - title: "Halving Epoch", - bottom: [ - createBaseSeries({ - key: "halvingepoch", - name: "Epoch", - }), + { + name: "Price", + title: "Hash Price", + bottom: [ + createBaseSeries({ + key: "hash_price_ths", + name: "Dollars", + color: colors.emerald, + }), + createBaseSeries({ + key: "hash_price_phs", + name: "Dollars", + color: colors.emerald, + }), + createBaseSeries({ + key: "hash_price_rebound", + name: "Rebound", + color: colors.yellow, + }), + createBaseSeries({ + key: "hash_price_ths_min", + name: "Min", + color: colors.red, + options: { + lineStyle: 1, + }, + }), + createBaseSeries({ + key: "hash_price_phs_min", + name: "Min", + color: colors.red, + options: { + lineStyle: 1, + }, + }), + ], + }, + { + name: "Value", + title: "Hash Value", + bottom: [ + createBaseSeries({ + key: "hash_value_ths", + name: "Sats", + color: colors.orange, + }), + createBaseSeries({ + key: "hash_value_phs", + name: "Sats", + color: colors.orange, + }), + createBaseSeries({ + key: "hash_value_rebound", + name: "Rebound", + color: colors.yellow, + }), + createBaseSeries({ + key: "hash_value_ths_min", + name: "Min", + color: colors.red, + options: { + lineStyle: 1, + }, + }), + createBaseSeries({ + key: "hash_value_phs_min", + name: "Min", + color: colors.red, + options: { + lineStyle: 1, + }, + }), + ], + }, ], }, {