mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-29 20:39:26 -07:00
global: snapshot
This commit is contained in:
@@ -47,8 +47,7 @@ pub(crate) fn process_sent(
|
||||
for (receive_height, by_type) in sent_data.into_iter() {
|
||||
let prev_price = height_to_price[receive_height.to_usize()];
|
||||
let prev_timestamp = height_to_timestamp[receive_height.to_usize()];
|
||||
let blocks_old = current_height.to_usize() - receive_height.to_usize();
|
||||
let age = Age::new(current_timestamp, prev_timestamp, blocks_old);
|
||||
let age = Age::new(current_timestamp, prev_timestamp);
|
||||
|
||||
// Compute peak price during holding period for peak regret
|
||||
// This is the max HIGH price between receive and send heights
|
||||
|
||||
@@ -43,8 +43,7 @@ impl UTXOCohorts<Rw> {
|
||||
|
||||
let block_state = &chain_state[receive_height.to_usize()];
|
||||
let prev_price = block_state.price;
|
||||
let blocks_old = chain_len - 1 - receive_height.to_usize();
|
||||
let age = Age::new(last_timestamp, block_state.timestamp, blocks_old);
|
||||
let age = Age::new(last_timestamp, block_state.timestamp);
|
||||
|
||||
// Compute peak price during holding period for peak regret
|
||||
// This is the max price between receive and send heights
|
||||
|
||||
@@ -2,12 +2,12 @@ use brk_cohort::ByAddressType;
|
||||
use brk_error::Result;
|
||||
use brk_indexer::Indexer;
|
||||
use brk_types::{
|
||||
Cents, Date, Height, ONE_DAY_IN_SEC, OutputType, Sats, Timestamp, TxIndex, TypeIndex,
|
||||
Cents, Date, Height, ONE_DAY_IN_SEC, OutputType, Sats, StoredF64, Timestamp, TxIndex, TypeIndex,
|
||||
};
|
||||
use rayon::prelude::*;
|
||||
use rustc_hash::FxHashSet;
|
||||
use tracing::{debug, info};
|
||||
use vecdb::{AnyVec, Exit, ReadableVec, VecIndex};
|
||||
use vecdb::{AnyVec, Exit, ReadableVec, VecIndex, WritableVec};
|
||||
|
||||
use crate::{
|
||||
distribution::{
|
||||
@@ -66,7 +66,7 @@ pub(crate) fn process_blocks(
|
||||
let height_to_first_txindex = &indexer.vecs.transactions.first_txindex;
|
||||
let height_to_first_txoutindex = &indexer.vecs.outputs.first_txoutindex;
|
||||
let height_to_first_txinindex = &indexer.vecs.inputs.first_txinindex;
|
||||
let height_to_tx_count = &transactions.count.tx_count.height;
|
||||
let height_to_tx_count = &transactions.count.tx_count.raw.height;
|
||||
let height_to_output_count = &outputs.count.total_count.full.sum;
|
||||
let height_to_input_count = &inputs.count.full.sum;
|
||||
let txindex_to_output_count = &indexes.txindex.output_count;
|
||||
@@ -353,6 +353,23 @@ pub(crate) fn process_blocks(
|
||||
timestamp,
|
||||
});
|
||||
|
||||
// Compute total coinblocks destroyed (once globally, before send() consumes height_to_sent)
|
||||
{
|
||||
let h = height.to_usize();
|
||||
let total_satblocks: u128 = height_to_sent
|
||||
.iter()
|
||||
.filter(|(rh, _)| rh.to_usize() < h)
|
||||
.map(|(rh, sent)| {
|
||||
let blocks_old = h - rh.to_usize();
|
||||
blocks_old as u128 * u64::from(sent.spendable_supply.value) as u128
|
||||
})
|
||||
.sum();
|
||||
vecs.coinblocks_destroyed.raw.height.truncate_push(
|
||||
height,
|
||||
StoredF64::from(total_satblocks as f64 / Sats::ONE_BTC_U128 as f64),
|
||||
)?;
|
||||
}
|
||||
|
||||
// Record maturation (sats crossing age boundaries)
|
||||
vecs.utxo_cohorts.push_maturation(height, &matured)?;
|
||||
|
||||
|
||||
@@ -79,9 +79,13 @@ pub(crate) fn write(
|
||||
.chain(vecs.addr_count.par_iter_height_mut())
|
||||
.chain(vecs.empty_addr_count.par_iter_height_mut())
|
||||
.chain(vecs.address_activity.par_iter_height_mut())
|
||||
.chain(rayon::iter::once(
|
||||
&mut vecs.supply_state as &mut dyn AnyStoredVec,
|
||||
))
|
||||
.chain(
|
||||
[
|
||||
&mut vecs.supply_state as &mut dyn AnyStoredVec,
|
||||
&mut vecs.coinblocks_destroyed.raw.height,
|
||||
]
|
||||
.into_par_iter(),
|
||||
)
|
||||
.chain(vecs.utxo_cohorts.par_iter_vecs_mut())
|
||||
.chain(vecs.address_cohorts.par_iter_vecs_mut())
|
||||
.try_for_each(|v| v.any_stamped_write_maybe_with_changes(stamp, with_changes))?;
|
||||
|
||||
@@ -2,7 +2,7 @@ use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Bitcoin, Height, Indexes, Sats, StoredF32, StoredF64, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, ReadableVec, Rw, StorageMode, WritableVec};
|
||||
use vecdb::{AnyStoredVec, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::{ComputedPerBlock, RollingWindowsFrom1w};
|
||||
|
||||
@@ -10,12 +10,6 @@ use crate::{blocks, distribution::{metrics::ImportConfig, state::{CohortState, R
|
||||
|
||||
use super::ActivityCore;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct ActivityCoinblocks<M: StorageMode = Rw> {
|
||||
pub raw: ComputedPerBlock<StoredF64, M>,
|
||||
pub cumulative: ComputedPerBlock<StoredF64, M>,
|
||||
}
|
||||
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct ActivityFull<M: StorageMode = Rw> {
|
||||
#[deref]
|
||||
@@ -23,8 +17,6 @@ pub struct ActivityFull<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub inner: ActivityCore<M>,
|
||||
|
||||
pub coinblocks_destroyed: ActivityCoinblocks<M>,
|
||||
|
||||
#[traversable(wrap = "coindays_destroyed", rename = "cumulative")]
|
||||
pub coindays_destroyed_cumulative: ComputedPerBlock<StoredF64, M>,
|
||||
#[traversable(wrap = "coindays_destroyed", rename = "sum")]
|
||||
@@ -42,10 +34,6 @@ impl ActivityFull {
|
||||
let v1 = Version::ONE;
|
||||
Ok(Self {
|
||||
inner: ActivityCore::forced_import(cfg)?,
|
||||
coinblocks_destroyed: ActivityCoinblocks {
|
||||
raw: cfg.import("coinblocks_destroyed", v1)?,
|
||||
cumulative: cfg.import("coinblocks_destroyed_cumulative", v1)?,
|
||||
},
|
||||
coindays_destroyed_cumulative: cfg.import("coindays_destroyed_cumulative", v1)?,
|
||||
coindays_destroyed_sum: cfg.import("coindays_destroyed", v1)?,
|
||||
sent_sum_extended: cfg.import("sent", v1)?,
|
||||
@@ -55,9 +43,7 @@ impl ActivityFull {
|
||||
}
|
||||
|
||||
pub(crate) fn full_min_len(&self) -> usize {
|
||||
self.inner
|
||||
.min_len()
|
||||
.min(self.coinblocks_destroyed.raw.height.len())
|
||||
self.inner.min_len()
|
||||
}
|
||||
|
||||
pub(crate) fn full_truncate_push(
|
||||
@@ -65,17 +51,11 @@ impl ActivityFull {
|
||||
height: Height,
|
||||
state: &CohortState<impl RealizedOps>,
|
||||
) -> Result<()> {
|
||||
self.inner.truncate_push(height, state)?;
|
||||
self.coinblocks_destroyed.raw.height.truncate_push(
|
||||
height,
|
||||
StoredF64::from(Bitcoin::from(state.satblocks_destroyed)),
|
||||
)?;
|
||||
Ok(())
|
||||
self.inner.truncate_push(height, state)
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
let mut vecs = self.inner.collect_vecs_mut();
|
||||
vecs.push(&mut self.coinblocks_destroyed.raw.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.dormancy.height);
|
||||
vecs.push(&mut self.velocity.height);
|
||||
vecs
|
||||
@@ -100,15 +80,6 @@ impl ActivityFull {
|
||||
self.inner
|
||||
.compute_rest_part1(blocks, starting_indexes, exit)?;
|
||||
|
||||
self.coinblocks_destroyed
|
||||
.cumulative
|
||||
.height
|
||||
.compute_cumulative(
|
||||
starting_indexes.height,
|
||||
&self.coinblocks_destroyed.raw.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.coindays_destroyed_cumulative
|
||||
.height
|
||||
.compute_cumulative(
|
||||
|
||||
@@ -289,7 +289,7 @@ impl RealizedFull {
|
||||
.min(self.investor.price.cents.height.len())
|
||||
.min(self.cap_raw.len())
|
||||
.min(self.investor.cap_raw.len())
|
||||
.min(self.peak_regret.value.height.len())
|
||||
.min(self.peak_regret.value.raw.height.len())
|
||||
}
|
||||
|
||||
pub(crate) fn truncate_push(
|
||||
@@ -326,6 +326,7 @@ impl RealizedFull {
|
||||
.truncate_push(height, state.realized.investor_cap_raw())?;
|
||||
self.peak_regret
|
||||
.value
|
||||
.raw
|
||||
.height
|
||||
.truncate_push(height, state.realized.peak_regret())?;
|
||||
|
||||
@@ -341,7 +342,7 @@ impl RealizedFull {
|
||||
vecs.push(&mut self.investor.price.cents.height);
|
||||
vecs.push(&mut self.cap_raw as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.investor.cap_raw as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.peak_regret.value.height);
|
||||
vecs.push(&mut self.peak_regret.value.raw.height);
|
||||
vecs
|
||||
}
|
||||
|
||||
@@ -400,6 +401,7 @@ impl RealizedFull {
|
||||
|
||||
self.peak_regret
|
||||
.value
|
||||
.raw
|
||||
.height
|
||||
.truncate_push(height, accum.peak_regret)?;
|
||||
|
||||
@@ -609,7 +611,7 @@ impl RealizedFull {
|
||||
.rel_to_rcap
|
||||
.compute_binary::<Cents, Cents, RatioCentsBp32>(
|
||||
starting_indexes.height,
|
||||
&self.peak_regret.value.height,
|
||||
&self.peak_regret.value.raw.height,
|
||||
&self.core.minimal.cap.cents.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
96
crates/brk_computer/src/distribution/metrics/supply/core.rs
Normal file
96
crates/brk_computer/src/distribution/metrics/supply/core.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{Height, Indexes, Version};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use vecdb::{AnyStoredVec, AnyVec, Exit, Rw, StorageMode, WritableVec};
|
||||
|
||||
use crate::{distribution::state::UnrealizedState, prices};
|
||||
|
||||
use crate::internal::AmountPerBlock;
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
|
||||
use super::SupplyBase;
|
||||
|
||||
/// Core supply metrics: total + halved + in_profit/in_loss (4 stored vecs).
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct SupplyCore<M: StorageMode = Rw> {
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
#[traversable(flatten)]
|
||||
pub base: SupplyBase<M>,
|
||||
|
||||
pub in_profit: AmountPerBlock<M>,
|
||||
pub in_loss: AmountPerBlock<M>,
|
||||
}
|
||||
|
||||
impl SupplyCore {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let v0 = Version::ZERO;
|
||||
let base = SupplyBase::forced_import(cfg)?;
|
||||
|
||||
Ok(Self {
|
||||
base,
|
||||
in_profit: cfg.import("supply_in_profit", v0)?,
|
||||
in_loss: cfg.import("supply_in_loss", v0)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn min_len(&self) -> usize {
|
||||
self.base
|
||||
.min_len()
|
||||
.min(self.in_profit.sats.height.len())
|
||||
.min(self.in_loss.sats.height.len())
|
||||
}
|
||||
|
||||
pub(crate) fn truncate_push_profitability(
|
||||
&mut self,
|
||||
height: Height,
|
||||
state: &UnrealizedState,
|
||||
) -> Result<()> {
|
||||
self.in_profit
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.supply_in_profit)?;
|
||||
self.in_loss
|
||||
.sats
|
||||
.height
|
||||
.truncate_push(height, state.supply_in_loss)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn collect_vecs_mut(&mut self) -> Vec<&mut dyn AnyStoredVec> {
|
||||
let mut vecs = self.base.collect_vecs_mut();
|
||||
vecs.push(&mut self.in_profit.sats.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.in_profit.cents.height);
|
||||
vecs.push(&mut self.in_loss.sats.height);
|
||||
vecs.push(&mut self.in_loss.cents.height);
|
||||
vecs
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
prices: &prices::Vecs,
|
||||
max_from: Height,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.base.compute(prices, max_from, exit)?;
|
||||
self.in_profit.compute(prices, max_from, exit)?;
|
||||
self.in_loss.compute(prices, max_from, exit)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn compute_from_stateful(
|
||||
&mut self,
|
||||
starting_indexes: &Indexes,
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
let base_refs: Vec<&SupplyBase> = others.iter().map(|o| &o.base).collect();
|
||||
self.base
|
||||
.compute_from_stateful(starting_indexes, &base_refs, exit)?;
|
||||
sum_others!(self, starting_indexes, others, exit; in_profit.sats.height);
|
||||
sum_others!(self, starting_indexes, others, exit; in_loss.sats.height);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
mod base;
|
||||
mod core;
|
||||
mod full;
|
||||
|
||||
pub use base::SupplyBase;
|
||||
pub use self::core::SupplyCore;
|
||||
pub use full::SupplyFull;
|
||||
|
||||
@@ -28,7 +28,6 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
||||
self.addr_count = 0;
|
||||
self.inner.supply = SupplyState::default();
|
||||
self.inner.sent = Sats::ZERO;
|
||||
self.inner.satblocks_destroyed = Sats::ZERO;
|
||||
self.inner.satdays_destroyed = Sats::ZERO;
|
||||
self.inner.realized = R::default();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,6 @@ pub struct CohortState<R: RealizedOps> {
|
||||
pub supply: SupplyState,
|
||||
pub realized: R,
|
||||
pub sent: Sats,
|
||||
pub satblocks_destroyed: Sats,
|
||||
pub satdays_destroyed: Sats,
|
||||
cost_basis_data: CostBasisData,
|
||||
}
|
||||
@@ -64,7 +63,6 @@ impl<R: RealizedOps> CohortState<R> {
|
||||
supply: SupplyState::default(),
|
||||
realized: R::default(),
|
||||
sent: Sats::ZERO,
|
||||
satblocks_destroyed: Sats::ZERO,
|
||||
satdays_destroyed: Sats::ZERO,
|
||||
cost_basis_data: CostBasisData::create(path, name),
|
||||
}
|
||||
@@ -104,7 +102,6 @@ impl<R: RealizedOps> CohortState<R> {
|
||||
pub(crate) fn reset_single_iteration_values(&mut self) {
|
||||
self.sent = Sats::ZERO;
|
||||
self.satdays_destroyed = Sats::ZERO;
|
||||
self.satblocks_destroyed = Sats::ZERO;
|
||||
self.realized.reset_single_iteration_values();
|
||||
}
|
||||
|
||||
@@ -202,7 +199,6 @@ impl<R: RealizedOps> CohortState<R> {
|
||||
) {
|
||||
self.supply -= supply;
|
||||
self.sent += pre.sats;
|
||||
self.satblocks_destroyed += pre.age.satblocks_destroyed(pre.sats);
|
||||
self.satdays_destroyed += pre.age.satdays_destroyed(pre.sats);
|
||||
|
||||
self.realized
|
||||
@@ -246,7 +242,6 @@ impl<R: RealizedOps> CohortState<R> {
|
||||
|
||||
if supply.value > Sats::ZERO {
|
||||
self.sent += supply.value;
|
||||
self.satblocks_destroyed += age.satblocks_destroyed(supply.value);
|
||||
self.satdays_destroyed += age.satdays_destroyed(supply.value);
|
||||
|
||||
let sats = supply.value;
|
||||
|
||||
@@ -23,7 +23,6 @@ impl<R: RealizedOps> UTXOCohortState<R> {
|
||||
pub(crate) fn reset(&mut self) {
|
||||
self.0.supply = SupplyState::default();
|
||||
self.0.sent = Sats::ZERO;
|
||||
self.0.satblocks_destroyed = Sats::ZERO;
|
||||
self.0.satdays_destroyed = Sats::ZERO;
|
||||
self.0.realized = R::default();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use brk_indexer::Indexer;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Cents, EmptyAddressData, EmptyAddressIndex, FundedAddressData, FundedAddressIndex, Height,
|
||||
Indexes, SupplyState, Timestamp, TxIndex, Version,
|
||||
Indexes, StoredF64, SupplyState, Timestamp, TxIndex, Version,
|
||||
};
|
||||
use tracing::{debug, info};
|
||||
use vecdb::{
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
state::BlockState,
|
||||
},
|
||||
indexes, inputs,
|
||||
internal::{finalize_db, open_db},
|
||||
internal::{finalize_db, open_db, ComputedPerBlockCumulative},
|
||||
outputs, prices, transactions,
|
||||
};
|
||||
|
||||
@@ -49,6 +49,8 @@ pub struct Vecs<M: StorageMode = Rw> {
|
||||
pub utxo_cohorts: UTXOCohorts<M>,
|
||||
pub address_cohorts: AddressCohorts<M>,
|
||||
|
||||
pub coinblocks_destroyed: ComputedPerBlockCumulative<StoredF64, M>,
|
||||
|
||||
pub addr_count: AddrCountsVecs<M>,
|
||||
pub empty_addr_count: AddrCountsVecs<M>,
|
||||
pub address_activity: AddressActivityVecs<M>,
|
||||
@@ -159,6 +161,13 @@ impl Vecs {
|
||||
utxo_cohorts,
|
||||
address_cohorts,
|
||||
|
||||
coinblocks_destroyed: ComputedPerBlockCumulative::forced_import(
|
||||
&db,
|
||||
"coinblocks_destroyed",
|
||||
version + Version::TWO,
|
||||
indexes,
|
||||
)?,
|
||||
|
||||
any_address_indexes: AnyAddressIndexesVecs::forced_import(&db, version)?,
|
||||
addresses_data: AddressesDataVecs {
|
||||
funded: fundedaddressindex_to_fundedaddressdata,
|
||||
@@ -390,6 +399,10 @@ impl Vecs {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
// 5b. Compute coinblocks_destroyed cumulative from raw
|
||||
self.coinblocks_destroyed
|
||||
.compute_rest(starting_indexes.height, exit)?;
|
||||
|
||||
// 6. Compute rest part1 (day1 mappings)
|
||||
aggregates::compute_rest_part1(
|
||||
&mut self.utxo_cohorts,
|
||||
@@ -474,5 +487,6 @@ impl Vecs {
|
||||
.min(Height::from(self.addr_count.min_stateful_height()))
|
||||
.min(Height::from(self.empty_addr_count.min_stateful_height()))
|
||||
.min(Height::from(self.address_activity.min_stateful_height()))
|
||||
.min(Height::from(self.coinblocks_destroyed.raw.height.len()))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user