global: big snapshot part 2

This commit is contained in:
nym21
2026-04-13 22:47:08 +02:00
parent 765261648d
commit 283baca848
93 changed files with 3242 additions and 3067 deletions
@@ -4,10 +4,10 @@ use derive_more::{Deref, DerefMut};
use crate::{
indexes,
internal::{LazyRollingDeltasFromHeight, WindowStartVec, Windows},
internal::{LazyRollingDeltasFromHeight, WindowStartVec, Windows, WithAddrTypes},
};
use super::{AddrCountsVecs, WithAddrTypes};
use super::AddrCountsVecs;
type AddrDelta = LazyRollingDeltasFromHeight<StoredU64, StoredI64, BasisPointsSigned32>;
@@ -5,9 +5,8 @@ use derive_more::{Deref, DerefMut};
use vecdb::{Database, Rw, StorageMode};
use crate::{
distribution::addr::WithAddrTypes,
indexes,
internal::PerBlock,
internal::{PerBlock, WithAddrTypes},
};
/// Exposed address count (`all` + per-type) for a single variant (funded or total).
@@ -45,7 +45,7 @@ use brk_types::{Indexes, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Database, Exit, Rw, StorageMode};
use crate::indexes;
use crate::{indexes, prices};
/// Top-level container for all exposed address tracking: counts (funded +
/// total) plus the funded supply.
@@ -87,9 +87,15 @@ impl ExposedAddrVecs {
Ok(())
}
pub(crate) fn compute_rest(&mut self, starting_indexes: &Indexes, exit: &Exit) -> Result<()> {
pub(crate) fn compute_rest(
&mut self,
starting_indexes: &Indexes,
prices: &prices::Vecs,
exit: &Exit,
) -> Result<()> {
self.count.compute_rest(starting_indexes, exit)?;
self.supply.compute_rest(starting_indexes, exit)?;
self.supply
.compute_rest(starting_indexes.height, prices, exit)?;
Ok(())
}
}
@@ -1,9 +1,9 @@
use brk_cohort::ByAddrType;
use brk_types::{Height, Sats};
use brk_types::Height;
use derive_more::{Deref, DerefMut};
use vecdb::ReadableVec;
use crate::internal::PerBlock;
use crate::internal::AmountPerBlock;
use super::vecs::ExposedAddrSupplyVecs;
@@ -23,8 +23,8 @@ impl From<(&ExposedAddrSupplyVecs, Height)> for AddrTypeToExposedAddrSupply {
#[inline]
fn from((vecs, starting_height): (&ExposedAddrSupplyVecs, Height)) -> Self {
if let Some(prev_height) = starting_height.decremented() {
let read = |v: &PerBlock<Sats>| -> u64 {
u64::from(v.height.collect_one(prev_height).unwrap())
let read = |v: &AmountPerBlock| -> u64 {
u64::from(v.sats.height.collect_one(prev_height).unwrap())
};
Self(ByAddrType {
p2pk65: read(&vecs.by_addr_type.p2pk65),
@@ -1,20 +1,21 @@
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Sats, Version};
use brk_types::Version;
use derive_more::{Deref, DerefMut};
use vecdb::{Database, Rw, StorageMode};
use crate::{
distribution::addr::WithAddrTypes,
indexes,
internal::PerBlock,
internal::{AmountPerBlock, WithAddrTypes},
};
/// Exposed address supply (sats) — `all` + per-address-type. Tracks the total
/// balance held by addresses currently in the funded exposed set.
/// Exposed address supply (sats/btc/cents/usd) — `all` + per-address-type.
/// Tracks the total balance held by addresses currently in the funded
/// exposed set. Sats are pushed stateful per block; cents/usd are derived
/// post-hoc from sats × spot price.
#[derive(Deref, DerefMut, Traversable)]
pub struct ExposedAddrSupplyVecs<M: StorageMode = Rw>(
#[traversable(flatten)] pub WithAddrTypes<PerBlock<Sats, M>>,
#[traversable(flatten)] pub WithAddrTypes<AmountPerBlock<M>>,
);
impl ExposedAddrSupplyVecs {
@@ -23,7 +24,7 @@ impl ExposedAddrSupplyVecs {
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
Ok(Self(WithAddrTypes::<PerBlock<Sats>>::forced_import(
Ok(Self(WithAddrTypes::<AmountPerBlock>::forced_import(
db,
"exposed_addr_supply",
version,
@@ -8,7 +8,6 @@ mod new_addr_count;
mod reused;
mod total_addr_count;
mod type_map;
mod with_addr_types;
pub use activity::{AddrActivityVecs, AddrTypeToActivityCounts};
pub use addr_count::{AddrCountsVecs, AddrTypeToAddrCount};
@@ -24,4 +23,3 @@ pub use reused::{
};
pub use total_addr_count::TotalAddrCountVecs;
pub use type_map::{AddrTypeToTypeIndexMap, AddrTypeToVec, HeightToAddrTypeToVec};
pub use with_addr_types::WithAddrTypes;
@@ -6,10 +6,10 @@ use vecdb::{Database, Exit, Rw, StorageMode};
use crate::{
indexes,
internal::{PerBlockCumulativeRolling, WindowStartVec, Windows},
internal::{PerBlockCumulativeRolling, WindowStartVec, Windows, WithAddrTypes},
};
use super::{TotalAddrCountVecs, WithAddrTypes};
use super::TotalAddrCountVecs;
/// New address count per block (global + per-type).
#[derive(Deref, DerefMut, Traversable)]
@@ -5,9 +5,8 @@ use derive_more::{Deref, DerefMut};
use vecdb::{Database, Rw, StorageMode};
use crate::{
distribution::addr::WithAddrTypes,
indexes,
internal::PerBlock,
internal::{PerBlock, WithAddrTypes},
};
/// Reused address count (`all` + per-type) for a single variant (funded or total).
@@ -10,7 +10,7 @@
//! an aggregated `all`.
//! - [`uses`] — per-block count of outputs going to addresses that were
//! already reused, plus the derived percent over total address-output
//! count (denominator from `scripts::count`).
//! count (denominator from `outputs::by_type`).
mod count;
mod uses;
@@ -27,7 +27,7 @@ use vecdb::{AnyStoredVec, Database, Exit, Rw, StorageMode};
use crate::{
indexes,
internal::{WindowStartVec, Windows},
scripts,
outputs,
};
/// Top-level container for all reused address tracking: counts (funded +
@@ -74,12 +74,12 @@ impl ReusedAddrVecs {
pub(crate) fn compute_rest(
&mut self,
starting_indexes: &Indexes,
scripts_count: &scripts::CountVecs,
outputs_by_type: &outputs::ByTypeVecs,
exit: &Exit,
) -> Result<()> {
self.count.compute_rest(starting_indexes, exit)?;
self.uses
.compute_rest(starting_indexes, scripts_count, exit)?;
.compute_rest(starting_indexes, outputs_by_type, exit)?;
Ok(())
}
}
@@ -1,17 +1,17 @@
use brk_cohort::ByAddrType;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{BasisPoints16, Height, Indexes, OutputType, StoredU64, Version};
use brk_types::{BasisPoints16, Indexes, OutputType, StoredU64, Version};
use rayon::prelude::*;
use vecdb::{AnyStoredVec, Database, Exit, Rw, StorageMode};
use crate::{
distribution::addr::WithAddrTypes,
indexes,
internal::{
PerBlockCumulativeRolling, PercentCumulativeRolling, RatioU64Bp16, WindowStartVec, Windows,
PerBlockCumulativeRolling, PercentCumulativeRolling, WindowStartVec, Windows,
WithAddrTypes,
},
scripts,
outputs,
};
use super::state::AddrTypeToReusedAddrUseCount;
@@ -22,8 +22,9 @@ use super::state::AddrTypeToReusedAddrUseCount;
/// that were *already* reused at the moment of the use, so the use that
/// makes an address reused is not itself counted.
///
/// The denominator for the percent (total address-output count) lives in
/// `scripts::count` and is reused here rather than duplicated.
/// The denominator for the percent (per-type and aggregate address-output
/// counts) is read from `outputs::ByTypeVecs::output_count` rather than
/// duplicated here.
#[derive(Traversable)]
pub struct ReusedAddrUsesVecs<M: StorageMode = Rw> {
pub reused_addr_use_count:
@@ -87,66 +88,29 @@ impl ReusedAddrUsesVecs {
pub(crate) fn compute_rest(
&mut self,
starting_indexes: &Indexes,
scripts_count: &scripts::CountVecs,
outputs_by_type: &outputs::ByTypeVecs,
exit: &Exit,
) -> Result<()> {
self.reused_addr_use_count
.compute_rest(starting_indexes.height, exit)?;
compute_one_percent(
&mut self.reused_addr_use_percent.all,
self.reused_addr_use_percent.all.compute_count_ratio(
&self.reused_addr_use_count.all,
&scripts_count.addr_output_count,
&outputs_by_type.output_count.all,
starting_indexes.height,
exit,
)?;
for otype in OutputType::ADDR_TYPES {
compute_one_percent(
self.reused_addr_use_percent
.by_addr_type
.get_mut_unwrap(otype),
self.reused_addr_use_count.by_addr_type.get_unwrap(otype),
denom_for_type(scripts_count, otype),
starting_indexes.height,
exit,
)?;
self.reused_addr_use_percent
.by_addr_type
.get_mut_unwrap(otype)
.compute_count_ratio(
self.reused_addr_use_count.by_addr_type.get_unwrap(otype),
outputs_by_type.output_count.by_type.get(otype),
starting_indexes.height,
exit,
)?;
}
Ok(())
}
}
#[inline]
fn compute_one_percent(
percent: &mut PercentCumulativeRolling<BasisPoints16>,
reused: &PerBlockCumulativeRolling<StoredU64, StoredU64>,
denom: &PerBlockCumulativeRolling<StoredU64, StoredU64>,
starting_height: Height,
exit: &Exit,
) -> Result<()> {
percent.compute_binary::<StoredU64, StoredU64, RatioU64Bp16, _, _, _, _>(
starting_height,
&reused.cumulative.height,
&denom.cumulative.height,
reused.sum.as_array().map(|w| &w.height),
denom.sum.as_array().map(|w| &w.height),
exit,
)
}
#[inline]
fn denom_for_type(
scripts_count: &scripts::CountVecs,
otype: OutputType,
) -> &PerBlockCumulativeRolling<StoredU64, StoredU64> {
match otype {
OutputType::P2PK33 => &scripts_count.p2pk33,
OutputType::P2PK65 => &scripts_count.p2pk65,
OutputType::P2PKH => &scripts_count.p2pkh,
OutputType::P2SH => &scripts_count.p2sh,
OutputType::P2WPKH => &scripts_count.p2wpkh,
OutputType::P2WSH => &scripts_count.p2wsh,
OutputType::P2TR => &scripts_count.p2tr,
OutputType::P2A => &scripts_count.p2a,
_ => unreachable!("OutputType::ADDR_TYPES contains only address types"),
}
}
@@ -4,9 +4,12 @@ use brk_types::{Height, StoredU64, Version};
use derive_more::{Deref, DerefMut};
use vecdb::{Database, Exit, Rw, StorageMode};
use crate::{indexes, internal::PerBlock};
use crate::{
indexes,
internal::{PerBlock, WithAddrTypes},
};
use super::{AddrCountsVecs, WithAddrTypes};
use super::AddrCountsVecs;
/// Total address count (global + per-type) with all derived indexes.
#[derive(Deref, DerefMut, Traversable)]
@@ -1,173 +0,0 @@
//! Generic `all` + per-`AddrType` container, mirrors the `WithSth` pattern
//! along the address-type axis. Used by every metric that tracks one
//! aggregate value alongside a per-address-type breakdown.
use brk_cohort::ByAddrType;
use brk_error::Result;
use brk_traversable::Traversable;
use brk_types::{Height, Indexes, Version};
use rayon::prelude::*;
use schemars::JsonSchema;
use vecdb::{AnyStoredVec, AnyVec, Database, EagerVec, Exit, PcoVec, WritableVec};
use crate::{
indexes,
internal::{NumericValue, PerBlock, PerBlockCumulativeRolling, WindowStartVec, Windows},
};
/// `all` aggregate plus per-`AddrType` breakdown.
#[derive(Clone, Traversable)]
pub struct WithAddrTypes<T> {
pub all: T,
#[traversable(flatten)]
pub by_addr_type: ByAddrType<T>,
}
impl<T> WithAddrTypes<PerBlock<T>>
where
T: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
) -> Result<Self> {
let all = PerBlock::forced_import(db, name, version, indexes)?;
let by_addr_type = ByAddrType::new_with_name(|type_name| {
PerBlock::forced_import(db, &format!("{type_name}_{name}"), version, indexes)
})?;
Ok(Self { all, by_addr_type })
}
pub(crate) fn min_stateful_len(&self) -> usize {
self.by_addr_type
.values()
.map(|v| v.height.len())
.min()
.unwrap()
.min(self.all.height.len())
}
pub(crate) fn par_iter_height_mut(
&mut self,
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
rayon::iter::once(&mut self.all.height as &mut dyn AnyStoredVec).chain(
self.by_addr_type
.par_values_mut()
.map(|v| &mut v.height as &mut dyn AnyStoredVec),
)
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.all.height.reset()?;
for v in self.by_addr_type.values_mut() {
v.height.reset()?;
}
Ok(())
}
#[inline(always)]
pub(crate) fn push_height<U>(&mut self, total: U, per_type: impl IntoIterator<Item = U>)
where
U: Into<T>,
{
self.all.height.push(total.into());
for (v, value) in self.by_addr_type.values_mut().zip(per_type) {
v.height.push(value.into());
}
}
/// Compute `all.height` as the per-block sum of the per-type vecs.
pub(crate) fn compute_rest(
&mut self,
starting_indexes: &Indexes,
exit: &Exit,
) -> Result<()> {
let sources: Vec<&EagerVec<PcoVec<Height, T>>> =
self.by_addr_type.values().map(|v| &v.height).collect();
self.all
.height
.compute_sum_of_others(starting_indexes.height, &sources, exit)?;
Ok(())
}
}
impl<T, C> WithAddrTypes<PerBlockCumulativeRolling<T, C>>
where
T: NumericValue + JsonSchema + Into<C>,
C: NumericValue + JsonSchema,
{
pub(crate) fn forced_import(
db: &Database,
name: &str,
version: Version,
indexes: &indexes::Vecs,
cached_starts: &Windows<&WindowStartVec>,
) -> Result<Self> {
let all = PerBlockCumulativeRolling::forced_import(
db,
name,
version,
indexes,
cached_starts,
)?;
let by_addr_type = ByAddrType::new_with_name(|type_name| {
PerBlockCumulativeRolling::forced_import(
db,
&format!("{type_name}_{name}"),
version,
indexes,
cached_starts,
)
})?;
Ok(Self { all, by_addr_type })
}
pub(crate) fn min_stateful_len(&self) -> usize {
self.by_addr_type
.values()
.map(|v| v.block.len())
.min()
.unwrap()
.min(self.all.block.len())
}
pub(crate) fn par_iter_height_mut(
&mut self,
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
rayon::iter::once(&mut self.all.block as &mut dyn AnyStoredVec).chain(
self.by_addr_type
.par_values_mut()
.map(|v| &mut v.block as &mut dyn AnyStoredVec),
)
}
pub(crate) fn reset_height(&mut self) -> Result<()> {
self.all.block.reset()?;
for v in self.by_addr_type.values_mut() {
v.block.reset()?;
}
Ok(())
}
#[inline(always)]
pub(crate) fn push_height<U>(&mut self, total: U, per_type: impl IntoIterator<Item = U>)
where
U: Into<T>,
{
self.all.block.push(total.into());
for (v, value) in self.by_addr_type.values_mut().zip(per_type) {
v.block.push(value.into());
}
}
/// Finalize `cumulative` / `sum` / `average` for `all` and every per-type vec.
pub(crate) fn compute_rest(&mut self, max_from: Height, exit: &Exit) -> Result<()> {
self.all.compute_rest(max_from, exit)?;
for v in self.by_addr_type.values_mut() {
v.compute_rest(max_from, exit)?;
}
Ok(())
}
}
+5 -4
View File
@@ -27,7 +27,7 @@ use crate::{
PerBlockCumulativeRolling, WindowStartVec, Windows,
db_utils::{finalize_db, open_db},
},
outputs, prices, scripts, transactions,
outputs, prices, transactions,
};
use super::{
@@ -235,7 +235,6 @@ impl Vecs {
indexes: &indexes::Vecs,
inputs: &inputs::Vecs,
outputs: &outputs::Vecs,
scripts: &scripts::Vecs,
transactions: &transactions::Vecs,
blocks: &blocks::Vecs,
prices: &prices::Vecs,
@@ -473,8 +472,10 @@ impl Vecs {
self.addrs.empty.compute_rest(starting_indexes, exit)?;
self.addrs
.reused
.compute_rest(starting_indexes, &scripts.count, exit)?;
self.addrs.exposed.compute_rest(starting_indexes, exit)?;
.compute_rest(starting_indexes, &outputs.by_type, exit)?;
self.addrs
.exposed
.compute_rest(starting_indexes, prices, exit)?;
// 6c. Compute total_addr_count = addr_count + empty_addr_count
self.addrs.total.compute(