use std::path::Path;
use brk_error::Result;
use brk_types::{Bitcoin, Cents, PartsPerMillion64, Sats, StoredF32, Version};
use super::Vecs;
use crate::{
distribution::{self, AllChainCache},
indexes,
internal::{
Identity, LazyPerBlock, LazyRatioPerBlock, PerBlock, PercentPerBlock, RatioPerBlock,
db_utils::{finalize_db, open_db},
},
mining, transactions,
};
const VERSION: Version = Version::new(1);
impl Vecs {
pub(crate) fn forced_import(
parent_path: &Path,
parent_version: Version,
indexes: &indexes::Vecs,
all_chain: &AllChainCache,
mining: &mining::Vecs,
distribution: &distribution::Vecs,
transactions: &transactions::Vecs,
) -> Result<Self> {
let db = open_db(parent_path, super::DB_NAME, 100_000)?;
let v = parent_version + VERSION;
let puell_multiple = RatioPerBlock::forced_import_ppm(&db, "puell_multiple", v, indexes)?;
let nvt_source = all_chain.with_market_cap(
"nvt_ppm_source",
v,
&transactions.volume.transfer_volume.sum._24h.cents.height,
|_, volume, market_cap| Self::market_ratio(market_cap, volume),
);
let nvt = LazyRatioPerBlock::from_uncached_height_source("nvt", v, nvt_source, indexes);
let gini = PercentPerBlock::forced_import(&db, "gini", v, indexes)?;
let rhodl_ratio = RatioPerBlock::forced_import_ppm(&db, "rhodl_ratio", v, indexes)?;
let thermo_source = all_chain.with_market_cap(
"thermo_cap_multiple_ppm_source",
v,
&mining.rewards.subsidy.cumulative.cents.height,
|_, thermo_cap, market_cap| Self::market_ratio(market_cap, thermo_cap),
);
let thermo_cap_multiple = LazyRatioPerBlock::from_uncached_height_source(
"thermo_cap_multiple",
v,
thermo_source,
indexes,
);
let all_activity = &distribution.utxo_cohorts.all.metrics.activity;
let cdd_source = all_chain.with_supply(
"coindays_destroyed_supply_adj_source",
v,
&all_activity.coindays_destroyed.sum._24h.height,
|_, cdd, supply| Self::supply_adjusted(f64::from(cdd), supply),
);
let coindays_destroyed_supply_adj =
LazyPerBlock::from_uncached_height_source::<Identity<StoredF32>, _>(
"coindays_destroyed_supply_adj",
v,
cdd_source,
indexes,
);
let cyd_source = all_chain.with_supply(
"coinyears_destroyed_supply_adj_source",
v,
&all_activity.coinyears_destroyed.height,
|_, cyd, supply| Self::supply_adjusted(f64::from(cyd), supply),
);
let coinyears_destroyed_supply_adj =
LazyPerBlock::from_uncached_height_source::<Identity<StoredF32>, _>(
"coinyears_destroyed_supply_adj",
v,
cyd_source,
indexes,
);
let dormancy_24h = &all_activity.dormancy._24h.height;
let dormancy_supply_source = all_chain.with_supply(
"dormancy_supply_adj_source",
v,
dormancy_24h,
|_, dormancy, supply| Self::supply_adjusted(f64::from(dormancy), supply),
);
let dormancy_flow_source = all_chain.with_supply(
"dormancy_flow_source",
v,
dormancy_24h,
|_, dormancy, supply| Self::dormancy_flow(dormancy, supply),
);
let dormancy = super::vecs::DormancyVecs {
supply_adj: LazyPerBlock::from_uncached_height_source::<Identity<StoredF32>, _>(
"dormancy_supply_adj",
v,
dormancy_supply_source,
indexes,
),
flow: LazyPerBlock::from_uncached_height_source::<Identity<StoredF32>, _>(
"dormancy_flow",
v,
dormancy_flow_source,
indexes,
),
};
let stock_source = all_chain.with_supply(
"stock_to_flow_source",
v,
&mining.rewards.subsidy.block.sats,
|_, subsidy, supply| Self::stock_to_flow(supply, subsidy),
);
let stock_to_flow = LazyPerBlock::from_uncached_height_source::<Identity<StoredF32>, _>(
"stock_to_flow",
v,
stock_source,
indexes,
);
let seller_exhaustion = PerBlock::forced_import(&db, "seller_exhaustion", v, indexes)?;
let this = Self {
db,
puell_multiple,
nvt,
gini,
rhodl_ratio,
thermo_cap_multiple,
coindays_destroyed_supply_adj,
coinyears_destroyed_supply_adj,
dormancy,
stock_to_flow,
seller_exhaustion,
};
finalize_db(&this.db, &this)?;
Ok(this)
}
fn market_ratio(numerator: Cents, denominator: Cents) -> PartsPerMillion64 {
let ratio = f64::from(numerator) / f64::from(denominator);
if ratio.is_finite() {
PartsPerMillion64::from(ratio)
} else {
PartsPerMillion64::default()
}
}
fn supply_adjusted(value: f64, supply: Sats) -> StoredF32 {
let supply = f64::from(Bitcoin::from(supply));
if supply == 0.0 {
StoredF32::from(0.0f32)
} else {
StoredF32::from((value / supply) as f32)
}
}
fn stock_to_flow(supply: Sats, subsidy: Sats) -> StoredF32 {
let annual_flow = subsidy.as_u128() as f64 * 52_560.0;
if annual_flow == 0.0 {
StoredF32::from(0.0f32)
} else {
StoredF32::from((supply.as_u128() as f64 / annual_flow) as f32)
}
}
fn dormancy_flow(dormancy: StoredF32, supply: Sats) -> StoredF32 {
let dormancy = f64::from(dormancy);
if dormancy == 0.0 {
StoredF32::from(0.0f32)
} else {
StoredF32::from((f64::from(Bitcoin::from(supply)) / dormancy) as f32)
}
}
}