mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-25 07:09:59 -07:00
global: snapshot
This commit is contained in:
@@ -12,11 +12,11 @@ use vecdb::{
|
||||
use crate::{indexes, internal::ComputedPerBlock};
|
||||
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct AddrCountVecs<M: StorageMode = Rw>(
|
||||
pub struct AddressCountVecs<M: StorageMode = Rw>(
|
||||
#[traversable(flatten)] pub ComputedPerBlock<StoredU64, M>,
|
||||
);
|
||||
|
||||
impl AddrCountVecs {
|
||||
impl AddressCountVecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
@@ -40,9 +40,9 @@ impl AddressTypeToAddressCount {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<(&AddressTypeToAddrCountVecs, Height)> for AddressTypeToAddressCount {
|
||||
impl From<(&AddressTypeToAddressCountVecs, Height)> for AddressTypeToAddressCount {
|
||||
#[inline]
|
||||
fn from((groups, starting_height): (&AddressTypeToAddrCountVecs, Height)) -> Self {
|
||||
fn from((groups, starting_height): (&AddressTypeToAddressCountVecs, Height)) -> Self {
|
||||
if let Some(prev_height) = starting_height.decremented() {
|
||||
Self(ByAddressType {
|
||||
p2pk65: groups
|
||||
@@ -102,25 +102,25 @@ impl From<(&AddressTypeToAddrCountVecs, Height)> for AddressTypeToAddressCount {
|
||||
|
||||
/// Address count per address type, with height + derived indexes.
|
||||
#[derive(Deref, DerefMut, Traversable)]
|
||||
pub struct AddressTypeToAddrCountVecs<M: StorageMode = Rw>(ByAddressType<AddrCountVecs<M>>);
|
||||
pub struct AddressTypeToAddressCountVecs<M: StorageMode = Rw>(ByAddressType<AddressCountVecs<M>>);
|
||||
|
||||
impl From<ByAddressType<AddrCountVecs>> for AddressTypeToAddrCountVecs {
|
||||
impl From<ByAddressType<AddressCountVecs>> for AddressTypeToAddressCountVecs {
|
||||
#[inline]
|
||||
fn from(value: ByAddressType<AddrCountVecs>) -> Self {
|
||||
fn from(value: ByAddressType<AddressCountVecs>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressTypeToAddrCountVecs {
|
||||
impl AddressTypeToAddressCountVecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self::from(ByAddressType::<AddrCountVecs>::new_with_name(
|
||||
Ok(Self::from(ByAddressType::<AddressCountVecs>::new_with_name(
|
||||
|type_name| {
|
||||
AddrCountVecs::forced_import(db, &format!("{type_name}_{name}"), version, indexes)
|
||||
AddressCountVecs::forced_import(db, &format!("{type_name}_{name}"), version, indexes)
|
||||
},
|
||||
)?))
|
||||
}
|
||||
@@ -140,9 +140,9 @@ impl AddressTypeToAddrCountVecs {
|
||||
pub(crate) fn truncate_push_height(
|
||||
&mut self,
|
||||
height: Height,
|
||||
addr_counts: &AddressTypeToAddressCount,
|
||||
address_counts: &AddressTypeToAddressCount,
|
||||
) -> Result<()> {
|
||||
for (vecs, &count) in self.0.values_mut().zip(addr_counts.values()) {
|
||||
for (vecs, &count) in self.0.values_mut().zip(address_counts.values()) {
|
||||
vecs.height.truncate_push(height, count.into())?;
|
||||
}
|
||||
Ok(())
|
||||
@@ -162,13 +162,13 @@ impl AddressTypeToAddrCountVecs {
|
||||
}
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct AddrCountsVecs<M: StorageMode = Rw> {
|
||||
pub all: AddrCountVecs<M>,
|
||||
pub struct AddressCountsVecs<M: StorageMode = Rw> {
|
||||
pub all: AddressCountVecs<M>,
|
||||
#[traversable(flatten)]
|
||||
pub by_addresstype: AddressTypeToAddrCountVecs<M>,
|
||||
pub by_addresstype: AddressTypeToAddressCountVecs<M>,
|
||||
}
|
||||
|
||||
impl AddrCountsVecs {
|
||||
impl AddressCountsVecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
name: &str,
|
||||
@@ -176,8 +176,8 @@ impl AddrCountsVecs {
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
all: AddrCountVecs::forced_import(db, name, version, indexes)?,
|
||||
by_addresstype: AddressTypeToAddrCountVecs::forced_import(db, name, version, indexes)?,
|
||||
all: AddressCountVecs::forced_import(db, name, version, indexes)?,
|
||||
by_addresstype: AddressTypeToAddressCountVecs::forced_import(db, name, version, indexes)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -202,11 +202,11 @@ impl AddrCountsVecs {
|
||||
&mut self,
|
||||
height: Height,
|
||||
total: u64,
|
||||
addr_counts: &AddressTypeToAddressCount,
|
||||
address_counts: &AddressTypeToAddressCount,
|
||||
) -> Result<()> {
|
||||
self.all.height.truncate_push(height, total.into())?;
|
||||
self.by_addresstype
|
||||
.truncate_push_height(height, addr_counts)?;
|
||||
.truncate_push_height(height, address_counts)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::{
|
||||
internal::{WindowStarts, RollingDelta},
|
||||
};
|
||||
|
||||
use super::AddrCountsVecs;
|
||||
use super::AddressCountsVecs;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct DeltaVecs<M: StorageMode = Rw> {
|
||||
@@ -26,10 +26,10 @@ impl DeltaVecs {
|
||||
) -> Result<Self> {
|
||||
let version = version + Version::TWO;
|
||||
|
||||
let all = RollingDelta::forced_import(db, "addr_count", version, indexes)?;
|
||||
let all = RollingDelta::forced_import(db, "address_count", version, indexes)?;
|
||||
|
||||
let by_addresstype = ByAddressType::new_with_name(|name| {
|
||||
RollingDelta::forced_import(db, &format!("{name}_addr_count"), version, indexes)
|
||||
RollingDelta::forced_import(db, &format!("{name}_address_count"), version, indexes)
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
@@ -42,16 +42,16 @@ impl DeltaVecs {
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
addr_count: &AddrCountsVecs,
|
||||
address_count: &AddressCountsVecs,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.all
|
||||
.compute(max_from, windows, &addr_count.all.height, exit)?;
|
||||
.compute(max_from, windows, &address_count.all.height, exit)?;
|
||||
|
||||
for ((_, growth), (_, addr)) in self
|
||||
.by_addresstype
|
||||
.iter_mut()
|
||||
.zip(addr_count.by_addresstype.iter())
|
||||
.zip(address_count.by_addresstype.iter())
|
||||
{
|
||||
growth.compute(max_from, windows, &addr.height, exit)?;
|
||||
}
|
||||
|
||||
@@ -3,15 +3,15 @@ mod address_count;
|
||||
mod data;
|
||||
mod delta;
|
||||
mod indexes;
|
||||
mod new_addr_count;
|
||||
mod total_addr_count;
|
||||
mod new_address_count;
|
||||
mod total_address_count;
|
||||
mod type_map;
|
||||
|
||||
pub use activity::{AddressActivityVecs, AddressTypeToActivityCounts};
|
||||
pub use address_count::{AddrCountsVecs, AddressTypeToAddressCount};
|
||||
pub use address_count::{AddressCountsVecs, AddressTypeToAddressCount};
|
||||
pub use data::AddressesDataVecs;
|
||||
pub use delta::DeltaVecs;
|
||||
pub use indexes::AnyAddressIndexesVecs;
|
||||
pub use new_addr_count::NewAddrCountVecs;
|
||||
pub use total_addr_count::TotalAddrCountVecs;
|
||||
pub use new_address_count::NewAddressCountVecs;
|
||||
pub use total_address_count::TotalAddressCountVecs;
|
||||
pub use type_map::{AddressTypeToTypeIndexMap, AddressTypeToVec, HeightToAddressTypeToVec};
|
||||
|
||||
@@ -9,29 +9,29 @@ use crate::{
|
||||
internal::{ComputedPerBlockSum, WindowStarts},
|
||||
};
|
||||
|
||||
use super::TotalAddrCountVecs;
|
||||
use super::TotalAddressCountVecs;
|
||||
|
||||
/// New address count per block (global + per-type)
|
||||
#[derive(Traversable)]
|
||||
pub struct NewAddrCountVecs<M: StorageMode = Rw> {
|
||||
pub struct NewAddressCountVecs<M: StorageMode = Rw> {
|
||||
pub all: ComputedPerBlockSum<StoredU64, M>,
|
||||
#[traversable(flatten)]
|
||||
pub by_addresstype: ByAddressType<ComputedPerBlockSum<StoredU64, M>>,
|
||||
}
|
||||
|
||||
impl NewAddrCountVecs {
|
||||
impl NewAddressCountVecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let all = ComputedPerBlockSum::forced_import(db, "new_addr_count", version, indexes)?;
|
||||
let all = ComputedPerBlockSum::forced_import(db, "new_address_count", version, indexes)?;
|
||||
|
||||
let by_addresstype: ByAddressType<ComputedPerBlockSum<StoredU64>> =
|
||||
ByAddressType::new_with_name(|name| {
|
||||
ComputedPerBlockSum::forced_import(
|
||||
db,
|
||||
&format!("{name}_new_addr_count"),
|
||||
&format!("{name}_new_address_count"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
@@ -47,17 +47,17 @@ impl NewAddrCountVecs {
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
windows: &WindowStarts<'_>,
|
||||
total_addr_count: &TotalAddrCountVecs,
|
||||
total_address_count: &TotalAddressCountVecs,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.all.compute(max_from, windows, exit, |height_vec| {
|
||||
Ok(height_vec.compute_change(max_from, &total_addr_count.all.height, 1, exit)?)
|
||||
Ok(height_vec.compute_change(max_from, &total_address_count.all.height, 1, exit)?)
|
||||
})?;
|
||||
|
||||
for ((_, new), (_, total)) in self
|
||||
.by_addresstype
|
||||
.iter_mut()
|
||||
.zip(total_addr_count.by_addresstype.iter())
|
||||
.zip(total_address_count.by_addresstype.iter())
|
||||
{
|
||||
new.compute(max_from, windows, exit, |height_vec| {
|
||||
Ok(height_vec.compute_change(max_from, &total.height, 1, exit)?)
|
||||
@@ -6,29 +6,29 @@ use vecdb::{Database, Exit, Rw, StorageMode};
|
||||
|
||||
use crate::{indexes, internal::ComputedPerBlock};
|
||||
|
||||
use super::AddrCountsVecs;
|
||||
use super::AddressCountsVecs;
|
||||
|
||||
/// Total address count (global + per-type) with all derived indexes
|
||||
#[derive(Traversable)]
|
||||
pub struct TotalAddrCountVecs<M: StorageMode = Rw> {
|
||||
pub struct TotalAddressCountVecs<M: StorageMode = Rw> {
|
||||
pub all: ComputedPerBlock<StoredU64, M>,
|
||||
#[traversable(flatten)]
|
||||
pub by_addresstype: ByAddressType<ComputedPerBlock<StoredU64, M>>,
|
||||
}
|
||||
|
||||
impl TotalAddrCountVecs {
|
||||
impl TotalAddressCountVecs {
|
||||
pub(crate) fn forced_import(
|
||||
db: &Database,
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Result<Self> {
|
||||
let all = ComputedPerBlock::forced_import(db, "total_addr_count", version, indexes)?;
|
||||
let all = ComputedPerBlock::forced_import(db, "total_address_count", version, indexes)?;
|
||||
|
||||
let by_addresstype: ByAddressType<ComputedPerBlock<StoredU64>> =
|
||||
ByAddressType::new_with_name(|name| {
|
||||
ComputedPerBlock::forced_import(
|
||||
db,
|
||||
&format!("{name}_total_addr_count"),
|
||||
&format!("{name}_total_address_count"),
|
||||
version,
|
||||
indexes,
|
||||
)
|
||||
@@ -40,26 +40,26 @@ impl TotalAddrCountVecs {
|
||||
})
|
||||
}
|
||||
|
||||
/// Eagerly compute total = addr_count + empty_addr_count.
|
||||
/// Eagerly compute total = address_count + empty_address_count.
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
addr_count: &AddrCountsVecs,
|
||||
empty_addr_count: &AddrCountsVecs,
|
||||
address_count: &AddressCountsVecs,
|
||||
empty_address_count: &AddressCountsVecs,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.all.height.compute_add(
|
||||
max_from,
|
||||
&addr_count.all.height,
|
||||
&empty_addr_count.all.height,
|
||||
&address_count.all.height,
|
||||
&empty_address_count.all.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
for ((_, total), ((_, addr), (_, empty))) in self.by_addresstype.iter_mut().zip(
|
||||
addr_count
|
||||
address_count
|
||||
.by_addresstype
|
||||
.iter()
|
||||
.zip(empty_addr_count.by_addresstype.iter()),
|
||||
.zip(empty_address_count.by_addresstype.iter()),
|
||||
) {
|
||||
total
|
||||
.height
|
||||
@@ -22,8 +22,8 @@ pub(crate) fn process_received(
|
||||
cohorts: &mut AddressCohorts,
|
||||
lookup: &mut AddressLookup<'_>,
|
||||
price: Cents,
|
||||
addr_count: &mut ByAddressType<u64>,
|
||||
empty_addr_count: &mut ByAddressType<u64>,
|
||||
address_count: &mut ByAddressType<u64>,
|
||||
empty_address_count: &mut ByAddressType<u64>,
|
||||
activity_counts: &mut AddressTypeToActivityCounts,
|
||||
) {
|
||||
let max_type_len = received_data.iter().map(|(_, v)| v.len()).max().unwrap_or(0);
|
||||
@@ -36,8 +36,8 @@ pub(crate) fn process_received(
|
||||
}
|
||||
|
||||
// Cache mutable refs for this address type
|
||||
let type_addr_count = addr_count.get_mut(output_type).unwrap();
|
||||
let type_empty_count = empty_addr_count.get_mut(output_type).unwrap();
|
||||
let type_address_count = address_count.get_mut(output_type).unwrap();
|
||||
let type_empty_count = empty_address_count.get_mut(output_type).unwrap();
|
||||
let type_activity = activity_counts.get_mut_unwrap(output_type);
|
||||
|
||||
// Aggregate receives by address - each address processed exactly once
|
||||
@@ -55,10 +55,10 @@ pub(crate) fn process_received(
|
||||
|
||||
match status {
|
||||
TrackingStatus::New => {
|
||||
*type_addr_count += 1;
|
||||
*type_address_count += 1;
|
||||
}
|
||||
TrackingStatus::WasEmpty => {
|
||||
*type_addr_count += 1;
|
||||
*type_address_count += 1;
|
||||
*type_empty_count -= 1;
|
||||
// Reactivated - was empty, now has funds
|
||||
type_activity.reactivated += 1;
|
||||
|
||||
@@ -32,8 +32,8 @@ pub(crate) fn process_sent(
|
||||
lookup: &mut AddressLookup<'_>,
|
||||
current_price: Cents,
|
||||
price_range_max: &PriceRangeMax,
|
||||
addr_count: &mut ByAddressType<u64>,
|
||||
empty_addr_count: &mut ByAddressType<u64>,
|
||||
address_count: &mut ByAddressType<u64>,
|
||||
empty_address_count: &mut ByAddressType<u64>,
|
||||
activity_counts: &mut AddressTypeToActivityCounts,
|
||||
received_addresses: &ByAddressType<FxHashSet<TypeIndex>>,
|
||||
height_to_price: &[Cents],
|
||||
@@ -55,8 +55,8 @@ pub(crate) fn process_sent(
|
||||
|
||||
for (output_type, vec) in by_type.unwrap().into_iter() {
|
||||
// Cache mutable refs for this address type
|
||||
let type_addr_count = addr_count.get_mut(output_type).unwrap();
|
||||
let type_empty_count = empty_addr_count.get_mut(output_type).unwrap();
|
||||
let type_address_count = address_count.get_mut(output_type).unwrap();
|
||||
let type_empty_count = empty_address_count.get_mut(output_type).unwrap();
|
||||
let type_activity = activity_counts.get_mut_unwrap(output_type);
|
||||
let type_received = received_addresses.get(output_type);
|
||||
let type_seen = seen_senders.get_mut_unwrap(output_type);
|
||||
@@ -126,7 +126,7 @@ pub(crate) fn process_sent(
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
*type_addr_count -= 1;
|
||||
*type_address_count -= 1;
|
||||
*type_empty_count += 1;
|
||||
|
||||
// Move from funded to empty
|
||||
|
||||
@@ -96,10 +96,10 @@ impl AddressCohorts {
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.par_iter_mut().try_for_each(|v| {
|
||||
v.addr_count_delta.compute(
|
||||
v.address_count_delta.compute(
|
||||
starting_indexes.height,
|
||||
&blocks.lookback._1m,
|
||||
&v.addr_count.height,
|
||||
&v.address_count.height,
|
||||
exit,
|
||||
)
|
||||
})?;
|
||||
|
||||
@@ -28,9 +28,9 @@ pub struct AddressCohortVecs<M: StorageMode = Rw> {
|
||||
#[traversable(flatten)]
|
||||
pub metrics: MinimalCohortMetrics<M>,
|
||||
|
||||
pub addr_count: ComputedPerBlock<StoredU64, M>,
|
||||
#[traversable(wrap = "addr_count", rename = "delta")]
|
||||
pub addr_count_delta: RollingDelta1m<StoredU64, StoredI64, M>,
|
||||
pub address_count: ComputedPerBlock<StoredU64, M>,
|
||||
#[traversable(wrap = "address_count", rename = "delta")]
|
||||
pub address_count_delta: RollingDelta1m<StoredU64, StoredI64, M>,
|
||||
}
|
||||
|
||||
impl AddressCohortVecs {
|
||||
@@ -59,15 +59,15 @@ impl AddressCohortVecs {
|
||||
|
||||
metrics: MinimalCohortMetrics::forced_import(&cfg)?,
|
||||
|
||||
addr_count: ComputedPerBlock::forced_import(
|
||||
address_count: ComputedPerBlock::forced_import(
|
||||
db,
|
||||
&cfg.name("addr_count"),
|
||||
&cfg.name("address_count"),
|
||||
version,
|
||||
indexes,
|
||||
)?,
|
||||
addr_count_delta: RollingDelta1m::forced_import(
|
||||
address_count_delta: RollingDelta1m::forced_import(
|
||||
db,
|
||||
&cfg.name("addr_count_delta"),
|
||||
&cfg.name("address_count_delta"),
|
||||
version + Version::ONE,
|
||||
indexes,
|
||||
)?,
|
||||
@@ -82,7 +82,7 @@ impl AddressCohortVecs {
|
||||
&mut self,
|
||||
) -> impl ParallelIterator<Item = &mut dyn AnyStoredVec> {
|
||||
let mut vecs: Vec<&mut dyn AnyStoredVec> = Vec::new();
|
||||
vecs.push(&mut self.addr_count.height as &mut dyn AnyStoredVec);
|
||||
vecs.push(&mut self.address_count.height as &mut dyn AnyStoredVec);
|
||||
vecs.extend(self.metrics.collect_all_vecs_mut());
|
||||
vecs.into_par_iter()
|
||||
}
|
||||
@@ -103,7 +103,7 @@ impl Filtered for AddressCohortVecs {
|
||||
|
||||
impl DynCohortVecs for AddressCohortVecs {
|
||||
fn min_stateful_len(&self) -> usize {
|
||||
self.addr_count
|
||||
self.address_count
|
||||
.height
|
||||
.len()
|
||||
.min(self.metrics.min_stateful_len())
|
||||
@@ -136,7 +136,7 @@ impl DynCohortVecs for AddressCohortVecs {
|
||||
.height
|
||||
.collect_one(prev_height)
|
||||
.unwrap();
|
||||
state.addr_count = *self.addr_count.height.collect_one(prev_height).unwrap();
|
||||
state.address_count = *self.address_count.height.collect_one(prev_height).unwrap();
|
||||
|
||||
state.inner.restore_realized_cap();
|
||||
|
||||
@@ -155,7 +155,7 @@ impl DynCohortVecs for AddressCohortVecs {
|
||||
|
||||
fn validate_computed_versions(&mut self, base_version: Version) -> Result<()> {
|
||||
use vecdb::WritableVec;
|
||||
self.addr_count
|
||||
self.address_count
|
||||
.height
|
||||
.validate_computed_version_or_reset(base_version)?;
|
||||
Ok(())
|
||||
@@ -167,9 +167,9 @@ impl DynCohortVecs for AddressCohortVecs {
|
||||
}
|
||||
|
||||
if let Some(state) = self.state.as_ref() {
|
||||
self.addr_count
|
||||
self.address_count
|
||||
.height
|
||||
.truncate_push(height, state.addr_count.into())?;
|
||||
.truncate_push(height, state.address_count.into())?;
|
||||
self.metrics.supply.truncate_push(height, &state.inner)?;
|
||||
self.metrics.outputs.truncate_push(height, &state.inner)?;
|
||||
self.metrics.realized.truncate_push(height, &state.inner)?;
|
||||
@@ -226,11 +226,11 @@ impl CohortVecs for AddressCohortVecs {
|
||||
others: &[&Self],
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.addr_count.height.compute_sum_of_others(
|
||||
self.address_count.height.compute_sum_of_others(
|
||||
starting_indexes.height,
|
||||
others
|
||||
.iter()
|
||||
.map(|v| &v.addr_count.height)
|
||||
.map(|v| &v.address_count.height)
|
||||
.collect::<Vec<_>>()
|
||||
.as_slice(),
|
||||
exit,
|
||||
|
||||
@@ -520,10 +520,10 @@ impl UTXOCohorts<Rw> {
|
||||
where
|
||||
HM: ReadableVec<Height, Dollars> + Sync,
|
||||
{
|
||||
// Get up_to_1h value sources for adjusted computation (cloned to avoid borrow conflicts).
|
||||
let up_to_1h_value_created = self
|
||||
// Get under_1h value sources for adjusted computation (cloned to avoid borrow conflicts).
|
||||
let under_1h_value_created = self
|
||||
.age_range
|
||||
.up_to_1h
|
||||
.under_1h
|
||||
.metrics
|
||||
.realized
|
||||
.minimal
|
||||
@@ -532,9 +532,9 @@ impl UTXOCohorts<Rw> {
|
||||
.raw
|
||||
.height
|
||||
.read_only_clone();
|
||||
let up_to_1h_value_destroyed = self
|
||||
let under_1h_value_destroyed = self
|
||||
.age_range
|
||||
.up_to_1h
|
||||
.under_1h
|
||||
.metrics
|
||||
.realized
|
||||
.minimal
|
||||
@@ -550,8 +550,8 @@ impl UTXOCohorts<Rw> {
|
||||
prices,
|
||||
starting_indexes,
|
||||
height_to_market_cap,
|
||||
&up_to_1h_value_created,
|
||||
&up_to_1h_value_destroyed,
|
||||
&under_1h_value_created,
|
||||
&under_1h_value_destroyed,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -576,8 +576,8 @@ impl UTXOCohorts<Rw> {
|
||||
|
||||
// All remaining groups run in parallel. Each closure owns an exclusive &mut
|
||||
// to its field and shares read-only references to common data.
|
||||
let vc = &up_to_1h_value_created;
|
||||
let vd = &up_to_1h_value_destroyed;
|
||||
let vc = &under_1h_value_created;
|
||||
let vd = &under_1h_value_destroyed;
|
||||
let ss = &all_supply_sats;
|
||||
|
||||
let tasks: Vec<Box<dyn FnOnce() -> Result<()> + Send + '_>> = vec![
|
||||
|
||||
@@ -9,7 +9,7 @@ impl UTXOCohorts<Rw> {
|
||||
/// Process received outputs for this block.
|
||||
///
|
||||
/// New UTXOs are added to:
|
||||
/// - The "up_to_1h" age cohort (all new UTXOs start at 0 hours old)
|
||||
/// - The "under_1h" age cohort (all new UTXOs start at 0 hours old)
|
||||
/// - The appropriate epoch cohort based on block height
|
||||
/// - The appropriate class cohort based on block timestamp
|
||||
/// - The appropriate output type cohort (P2PKH, P2SH, etc.)
|
||||
@@ -26,9 +26,9 @@ impl UTXOCohorts<Rw> {
|
||||
// Pre-compute snapshot once for the 3 cohorts sharing the same supply_state
|
||||
let snapshot = CostBasisSnapshot::from_utxo(price, &supply_state);
|
||||
|
||||
// New UTXOs go into up_to_1h, current epoch, and current class
|
||||
// New UTXOs go into under_1h, current epoch, and current class
|
||||
self.age_range
|
||||
.up_to_1h
|
||||
.under_1h
|
||||
.state
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
|
||||
@@ -17,7 +17,7 @@ impl UTXOCohorts<Rw> {
|
||||
/// Complexity: O(k * c) where k = 20 boundaries, c = ~1 (forward scan steps).
|
||||
///
|
||||
/// Returns how many sats matured INTO each cohort from the younger adjacent one.
|
||||
/// `up_to_1h` is always zero since nothing ages into the youngest cohort.
|
||||
/// `under_1h` is always zero since nothing ages into the youngest cohort.
|
||||
pub(crate) fn tick_tock_next_block(
|
||||
&mut self,
|
||||
chain_state: &[BlockState],
|
||||
|
||||
@@ -183,22 +183,22 @@ pub(crate) fn process_blocks(
|
||||
.collect_range_at(start_usize, end_usize);
|
||||
|
||||
// Track running totals - recover from previous height if resuming
|
||||
debug!("recovering addr_counts from height {}", starting_height);
|
||||
let (mut addr_counts, mut empty_addr_counts) = if starting_height > Height::ZERO {
|
||||
let addr_counts =
|
||||
debug!("recovering address_counts from height {}", starting_height);
|
||||
let (mut address_counts, mut empty_address_counts) = if starting_height > Height::ZERO {
|
||||
let address_counts =
|
||||
AddressTypeToAddressCount::from((&vecs.addresses.funded.by_addresstype, starting_height));
|
||||
let empty_addr_counts = AddressTypeToAddressCount::from((
|
||||
let empty_address_counts = AddressTypeToAddressCount::from((
|
||||
&vecs.addresses.empty.by_addresstype,
|
||||
starting_height,
|
||||
));
|
||||
(addr_counts, empty_addr_counts)
|
||||
(address_counts, empty_address_counts)
|
||||
} else {
|
||||
(
|
||||
AddressTypeToAddressCount::default(),
|
||||
AddressTypeToAddressCount::default(),
|
||||
)
|
||||
};
|
||||
debug!("addr_counts recovered");
|
||||
debug!("address_counts recovered");
|
||||
|
||||
// Track activity counts - reset each block
|
||||
let mut activity_counts = AddressTypeToActivityCounts::default();
|
||||
@@ -406,8 +406,8 @@ pub(crate) fn process_blocks(
|
||||
&mut vecs.address_cohorts,
|
||||
&mut lookup,
|
||||
block_price,
|
||||
&mut addr_counts,
|
||||
&mut empty_addr_counts,
|
||||
&mut address_counts,
|
||||
&mut empty_address_counts,
|
||||
&mut activity_counts,
|
||||
);
|
||||
|
||||
@@ -418,8 +418,8 @@ pub(crate) fn process_blocks(
|
||||
&mut lookup,
|
||||
block_price,
|
||||
ctx.price_range_max,
|
||||
&mut addr_counts,
|
||||
&mut empty_addr_counts,
|
||||
&mut address_counts,
|
||||
&mut empty_address_counts,
|
||||
&mut activity_counts,
|
||||
&received_addresses,
|
||||
height_to_price_vec,
|
||||
@@ -437,11 +437,11 @@ pub(crate) fn process_blocks(
|
||||
|
||||
// Push to height-indexed vectors
|
||||
vecs.addresses.funded
|
||||
.truncate_push_height(height, addr_counts.sum(), &addr_counts)?;
|
||||
.truncate_push_height(height, address_counts.sum(), &address_counts)?;
|
||||
vecs.addresses.empty.truncate_push_height(
|
||||
height,
|
||||
empty_addr_counts.sum(),
|
||||
&empty_addr_counts,
|
||||
empty_address_counts.sum(),
|
||||
&empty_address_counts,
|
||||
)?;
|
||||
vecs.addresses.activity
|
||||
.truncate_push_height(height, &activity_counts)?;
|
||||
|
||||
@@ -114,8 +114,8 @@ impl AllCohortMetrics {
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.realized.compute_rest_part2(
|
||||
@@ -132,8 +132,8 @@ impl AllCohortMetrics {
|
||||
starting_indexes,
|
||||
&self.realized.minimal.sopr.value_created.raw.height,
|
||||
&self.realized.minimal.sopr.value_destroyed.raw.height,
|
||||
up_to_1h_value_created,
|
||||
up_to_1h_value_destroyed,
|
||||
under_1h_value_created,
|
||||
under_1h_value_destroyed,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -63,8 +63,8 @@ impl ExtendedAdjustedCohortMetrics {
|
||||
prices: &prices::Vecs,
|
||||
starting_indexes: &Indexes,
|
||||
height_to_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
all_supply_sats: &impl ReadableVec<Height, Sats>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
@@ -82,8 +82,8 @@ impl ExtendedAdjustedCohortMetrics {
|
||||
starting_indexes,
|
||||
&self.inner.realized.minimal.sopr.value_created.raw.height,
|
||||
&self.inner.realized.minimal.sopr.value_destroyed.raw.height,
|
||||
up_to_1h_value_created,
|
||||
up_to_1h_value_destroyed,
|
||||
under_1h_value_created,
|
||||
under_1h_value_destroyed,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ pub struct AdjustedSopr<M: StorageMode = Rw> {
|
||||
impl AdjustedSopr {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
value_created: cfg.import("adjusted_value_created", Version::ZERO)?,
|
||||
value_destroyed: cfg.import("adjusted_value_destroyed", Version::ZERO)?,
|
||||
value_created_sum: cfg.import("adjusted_value_created", Version::ONE)?,
|
||||
value_destroyed_sum: cfg.import("adjusted_value_destroyed", Version::ONE)?,
|
||||
ratio: cfg.import("adjusted_sopr", Version::ONE)?,
|
||||
value_created: cfg.import("adj_value_created", Version::ZERO)?,
|
||||
value_destroyed: cfg.import("adj_value_destroyed", Version::ZERO)?,
|
||||
value_created_sum: cfg.import("adj_value_created", Version::ONE)?,
|
||||
value_destroyed_sum: cfg.import("adj_value_destroyed", Version::ONE)?,
|
||||
ratio: cfg.import("asopr", Version::ONE)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -39,21 +39,21 @@ impl AdjustedSopr {
|
||||
starting_indexes: &Indexes,
|
||||
base_value_created: &impl ReadableVec<Height, Cents>,
|
||||
base_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
up_to_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_created: &impl ReadableVec<Height, Cents>,
|
||||
under_1h_value_destroyed: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
// Compute value_created = base.value_created - up_to_1h.value_created
|
||||
// Compute value_created = base.value_created - under_1h.value_created
|
||||
self.value_created.height.compute_subtract(
|
||||
starting_indexes.height,
|
||||
base_value_created,
|
||||
up_to_1h_value_created,
|
||||
under_1h_value_created,
|
||||
exit,
|
||||
)?;
|
||||
self.value_destroyed.height.compute_subtract(
|
||||
starting_indexes.height,
|
||||
base_value_destroyed,
|
||||
up_to_1h_value_destroyed,
|
||||
under_1h_value_destroyed,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ impl RealizedFull {
|
||||
&profit_value_destroyed,
|
||||
);
|
||||
let profit = RealizedProfit {
|
||||
rel_to_rcap: cfg.import("realized_profit_rel_to_realized_cap", Version::new(2))?,
|
||||
rel_to_rcap: cfg.import("realized_profit_rel_to_rcap", Version::new(2))?,
|
||||
value_created: cfg.import("profit_value_created", v0)?,
|
||||
value_destroyed: profit_value_destroyed,
|
||||
value_created_sum: cfg.import("profit_value_created", v1)?,
|
||||
@@ -173,7 +173,7 @@ impl RealizedFull {
|
||||
&loss_value_destroyed,
|
||||
);
|
||||
let loss = RealizedLoss {
|
||||
rel_to_rcap: cfg.import("realized_loss_rel_to_realized_cap", Version::new(2))?,
|
||||
rel_to_rcap: cfg.import("realized_loss_rel_to_rcap", Version::new(2))?,
|
||||
value_created: cfg.import("loss_value_created", v0)?,
|
||||
value_destroyed: loss_value_destroyed,
|
||||
value_created_sum: cfg.import("loss_value_created", v1)?,
|
||||
@@ -192,15 +192,15 @@ impl RealizedFull {
|
||||
// Net PnL
|
||||
let net_pnl = RealizedNetPnl {
|
||||
rel_to_rcap: cfg
|
||||
.import("net_realized_pnl_rel_to_realized_cap", Version::new(2))?,
|
||||
.import("net_realized_pnl_rel_to_rcap", Version::new(2))?,
|
||||
cumulative: cfg.import("net_realized_pnl_cumulative", v1)?,
|
||||
sum_extended: cfg.import("net_realized_pnl", v1)?,
|
||||
delta: cfg.import("net_pnl_delta", Version::new(5))?,
|
||||
delta_extended: cfg.import("net_pnl_delta", Version::new(5))?,
|
||||
change_1m_rel_to_rcap: cfg
|
||||
.import("net_pnl_change_1m_rel_to_realized_cap", Version::new(4))?,
|
||||
.import("net_pnl_change_1m_rel_to_rcap", Version::new(4))?,
|
||||
change_1m_rel_to_mcap: cfg
|
||||
.import("net_pnl_change_1m_rel_to_market_cap", Version::new(4))?,
|
||||
.import("net_pnl_change_1m_rel_to_mcap", Version::new(4))?,
|
||||
};
|
||||
|
||||
// SOPR
|
||||
@@ -214,7 +214,7 @@ impl RealizedFull {
|
||||
let peak_regret = RealizedPeakRegret {
|
||||
value: cfg.import("realized_peak_regret", Version::new(2))?,
|
||||
rel_to_rcap: cfg
|
||||
.import("realized_peak_regret_rel_to_realized_cap", Version::new(2))?,
|
||||
.import("realized_peak_regret_rel_to_rcap", Version::new(2))?,
|
||||
};
|
||||
|
||||
// Investor
|
||||
@@ -241,7 +241,7 @@ impl RealizedFull {
|
||||
profit_to_loss_ratio: cfg.import("realized_profit_to_loss_ratio", v1)?,
|
||||
cap_delta_extended: cfg.import("realized_cap_delta", Version::new(5))?,
|
||||
cap_raw: cfg.import("cap_raw", v0)?,
|
||||
cap_rel_to_own_mcap: cfg.import("realized_cap_rel_to_own_market_cap", v1)?,
|
||||
cap_rel_to_own_mcap: cfg.import("realized_cap_rel_to_own_mcap", v1)?,
|
||||
price_ratio_percentiles: RatioPerBlockPercentiles::forced_import(
|
||||
cfg.db,
|
||||
&realized_price_name,
|
||||
|
||||
@@ -10,12 +10,12 @@ use crate::distribution::metrics::{ImportConfig, UnrealizedCore};
|
||||
/// Extended relative metrics for own market cap (extended && rel_to_all).
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeExtendedOwnMarketCap<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "unrealized/profit", rename = "rel_to_own_market_cap")]
|
||||
pub unrealized_profit_rel_to_own_market_cap: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "unrealized/loss", rename = "rel_to_own_market_cap")]
|
||||
pub unrealized_loss_rel_to_own_market_cap: PercentPerBlock<BasisPoints32, M>,
|
||||
#[traversable(wrap = "unrealized/net_pnl", rename = "rel_to_own_market_cap")]
|
||||
pub net_unrealized_pnl_rel_to_own_market_cap: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
#[traversable(wrap = "unrealized/profit", rename = "rel_to_own_mcap")]
|
||||
pub unrealized_profit_rel_to_own_mcap: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "unrealized/loss", rename = "rel_to_own_mcap")]
|
||||
pub unrealized_loss_rel_to_own_mcap: PercentPerBlock<BasisPoints32, M>,
|
||||
#[traversable(wrap = "unrealized/net_pnl", rename = "rel_to_own_mcap")]
|
||||
pub net_unrealized_pnl_rel_to_own_mcap: PercentPerBlock<BasisPointsSigned32, M>,
|
||||
}
|
||||
|
||||
impl RelativeExtendedOwnMarketCap {
|
||||
@@ -23,12 +23,12 @@ impl RelativeExtendedOwnMarketCap {
|
||||
let v2 = Version::new(2);
|
||||
|
||||
Ok(Self {
|
||||
unrealized_profit_rel_to_own_market_cap: cfg
|
||||
.import("unrealized_profit_rel_to_own_market_cap", v2)?,
|
||||
unrealized_loss_rel_to_own_market_cap: cfg
|
||||
.import("unrealized_loss_rel_to_own_market_cap", Version::new(3))?,
|
||||
net_unrealized_pnl_rel_to_own_market_cap: cfg
|
||||
.import("net_unrealized_pnl_rel_to_own_market_cap", Version::new(3))?,
|
||||
unrealized_profit_rel_to_own_mcap: cfg
|
||||
.import("unrealized_profit_rel_to_own_mcap", v2)?,
|
||||
unrealized_loss_rel_to_own_mcap: cfg
|
||||
.import("unrealized_loss_rel_to_own_mcap", Version::new(3))?,
|
||||
net_unrealized_pnl_rel_to_own_mcap: cfg
|
||||
.import("net_unrealized_pnl_rel_to_own_mcap", Version::new(3))?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -39,21 +39,21 @@ impl RelativeExtendedOwnMarketCap {
|
||||
own_market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.unrealized_profit_rel_to_own_market_cap
|
||||
self.unrealized_profit_rel_to_own_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from,
|
||||
&unrealized.profit.raw.usd.height,
|
||||
own_market_cap,
|
||||
exit,
|
||||
)?;
|
||||
self.unrealized_loss_rel_to_own_market_cap
|
||||
self.unrealized_loss_rel_to_own_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp32>(
|
||||
max_from,
|
||||
&unrealized.loss.raw.usd.height,
|
||||
own_market_cap,
|
||||
exit,
|
||||
)?;
|
||||
self.net_unrealized_pnl_rel_to_own_market_cap
|
||||
self.net_unrealized_pnl_rel_to_own_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBps32>(
|
||||
max_from,
|
||||
&unrealized.net_pnl.usd.height,
|
||||
|
||||
@@ -11,15 +11,15 @@ use crate::{
|
||||
/// Full relative metrics (sth/lth/all tier).
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeFull<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "supply/in_profit", rename = "rel_to_own_supply")]
|
||||
pub supply_in_profit_rel_to_own_supply: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "supply/in_loss", rename = "rel_to_own_supply")]
|
||||
pub supply_in_loss_rel_to_own_supply: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "supply/in_profit", rename = "rel_to_own")]
|
||||
pub supply_in_profit_rel_to_own: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "supply/in_loss", rename = "rel_to_own")]
|
||||
pub supply_in_loss_rel_to_own: PercentPerBlock<BasisPoints16, M>,
|
||||
|
||||
#[traversable(wrap = "unrealized/profit", rename = "rel_to_market_cap")]
|
||||
pub unrealized_profit_rel_to_market_cap: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "unrealized/loss", rename = "rel_to_market_cap")]
|
||||
pub unrealized_loss_rel_to_market_cap: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "unrealized/profit", rename = "rel_to_mcap")]
|
||||
pub unrealized_profit_rel_to_mcap: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "unrealized/loss", rename = "rel_to_mcap")]
|
||||
pub unrealized_loss_rel_to_mcap: PercentPerBlock<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
impl RelativeFull {
|
||||
@@ -28,13 +28,13 @@ impl RelativeFull {
|
||||
let v2 = Version::new(2);
|
||||
|
||||
Ok(Self {
|
||||
supply_in_profit_rel_to_own_supply: cfg
|
||||
.import("supply_in_profit_rel_to_own_supply", v1)?,
|
||||
supply_in_loss_rel_to_own_supply: cfg.import("supply_in_loss_rel_to_own_supply", v1)?,
|
||||
unrealized_profit_rel_to_market_cap: cfg
|
||||
.import("unrealized_profit_rel_to_market_cap", v2)?,
|
||||
unrealized_loss_rel_to_market_cap: cfg
|
||||
.import("unrealized_loss_rel_to_market_cap", v2)?,
|
||||
supply_in_profit_rel_to_own: cfg
|
||||
.import("supply_in_profit_rel_to_own", v1)?,
|
||||
supply_in_loss_rel_to_own: cfg.import("supply_in_loss_rel_to_own", v1)?,
|
||||
unrealized_profit_rel_to_mcap: cfg
|
||||
.import("unrealized_profit_rel_to_mcap", v2)?,
|
||||
unrealized_loss_rel_to_mcap: cfg
|
||||
.import("unrealized_loss_rel_to_mcap", v2)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,14 +46,14 @@ impl RelativeFull {
|
||||
market_cap: &impl ReadableVec<Height, Dollars>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply_in_profit_rel_to_own_supply
|
||||
self.supply_in_profit_rel_to_own
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from,
|
||||
&supply.in_profit.sats.height,
|
||||
&supply.total.sats.height,
|
||||
exit,
|
||||
)?;
|
||||
self.supply_in_loss_rel_to_own_supply
|
||||
self.supply_in_loss_rel_to_own
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from,
|
||||
&supply.in_loss.sats.height,
|
||||
@@ -61,14 +61,14 @@ impl RelativeFull {
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.unrealized_profit_rel_to_market_cap
|
||||
self.unrealized_profit_rel_to_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from,
|
||||
&unrealized.profit.raw.usd.height,
|
||||
market_cap,
|
||||
exit,
|
||||
)?;
|
||||
self.unrealized_loss_rel_to_market_cap
|
||||
self.unrealized_loss_rel_to_mcap
|
||||
.compute_binary::<Dollars, Dollars, RatioDollarsBp16>(
|
||||
max_from,
|
||||
&unrealized.loss.raw.usd.height,
|
||||
|
||||
@@ -11,22 +11,22 @@ use crate::distribution::metrics::{ImportConfig, SupplyCore};
|
||||
#[derive(Traversable)]
|
||||
pub struct RelativeToAll<M: StorageMode = Rw> {
|
||||
#[traversable(wrap = "supply", rename = "rel_to_circulating")]
|
||||
pub supply_rel_to_circulating_supply: PercentPerBlock<BasisPoints16, M>,
|
||||
pub supply_rel_to_circulating: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "supply/in_profit", rename = "rel_to_circulating")]
|
||||
pub supply_in_profit_rel_to_circulating_supply: PercentPerBlock<BasisPoints16, M>,
|
||||
pub supply_in_profit_rel_to_circulating: PercentPerBlock<BasisPoints16, M>,
|
||||
#[traversable(wrap = "supply/in_loss", rename = "rel_to_circulating")]
|
||||
pub supply_in_loss_rel_to_circulating_supply: PercentPerBlock<BasisPoints16, M>,
|
||||
pub supply_in_loss_rel_to_circulating: PercentPerBlock<BasisPoints16, M>,
|
||||
}
|
||||
|
||||
impl RelativeToAll {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
supply_rel_to_circulating_supply: cfg
|
||||
.import("supply_rel_to_circulating_supply", Version::ONE)?,
|
||||
supply_in_profit_rel_to_circulating_supply: cfg
|
||||
.import("supply_in_profit_rel_to_circulating_supply", Version::ONE)?,
|
||||
supply_in_loss_rel_to_circulating_supply: cfg
|
||||
.import("supply_in_loss_rel_to_circulating_supply", Version::ONE)?,
|
||||
supply_rel_to_circulating: cfg
|
||||
.import("supply_rel_to_circulating", Version::ONE)?,
|
||||
supply_in_profit_rel_to_circulating: cfg
|
||||
.import("supply_in_profit_rel_to_circulating", Version::ONE)?,
|
||||
supply_in_loss_rel_to_circulating: cfg
|
||||
.import("supply_in_loss_rel_to_circulating", Version::ONE)?,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -37,21 +37,21 @@ impl RelativeToAll {
|
||||
all_supply_sats: &impl ReadableVec<Height, Sats>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.supply_rel_to_circulating_supply
|
||||
self.supply_rel_to_circulating
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from,
|
||||
&supply.total.sats.height,
|
||||
all_supply_sats,
|
||||
exit,
|
||||
)?;
|
||||
self.supply_in_profit_rel_to_circulating_supply
|
||||
self.supply_in_profit_rel_to_circulating
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from,
|
||||
&supply.in_profit.sats.height,
|
||||
all_supply_sats,
|
||||
exit,
|
||||
)?;
|
||||
self.supply_in_loss_rel_to_circulating_supply
|
||||
self.supply_in_loss_rel_to_circulating
|
||||
.compute_binary::<Sats, Sats, RatioSatsBp16>(
|
||||
max_from,
|
||||
&supply.in_loss.sats.height,
|
||||
|
||||
@@ -16,23 +16,23 @@ use crate::distribution::metrics::ImportConfig;
|
||||
#[derive(Traversable)]
|
||||
pub struct SupplyBase<M: StorageMode = Rw> {
|
||||
pub total: AmountPerBlock<M>,
|
||||
pub halved: LazyAmountPerBlock,
|
||||
pub half: LazyAmountPerBlock,
|
||||
}
|
||||
|
||||
impl SupplyBase {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
let supply = cfg.import("supply", Version::ZERO)?;
|
||||
|
||||
let supply_halved = LazyAmountPerBlock::from_block_source::<
|
||||
let supply_half = LazyAmountPerBlock::from_block_source::<
|
||||
HalveSats,
|
||||
HalveSatsToBitcoin,
|
||||
HalveCents,
|
||||
HalveDollars,
|
||||
>(&cfg.name("supply_halved"), &supply, cfg.version);
|
||||
>(&cfg.name("supply_half"), &supply, cfg.version);
|
||||
|
||||
Ok(Self {
|
||||
total: supply,
|
||||
halved: supply_halved,
|
||||
half: supply_half,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
use brk_error::Result;
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{BasisPointsSigned32, Cents, Height, Version};
|
||||
use vecdb::{Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::internal::RatioPerBlock;
|
||||
|
||||
use crate::distribution::metrics::ImportConfig;
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct UnrealizedMinimal<M: StorageMode = Rw> {
|
||||
pub nupl: RatioPerBlock<BasisPointsSigned32, M>,
|
||||
}
|
||||
|
||||
impl UnrealizedMinimal {
|
||||
pub(crate) fn forced_import(cfg: &ImportConfig) -> Result<Self> {
|
||||
Ok(Self {
|
||||
nupl: cfg.import("nupl", Version::ONE)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compute(
|
||||
&mut self,
|
||||
max_from: Height,
|
||||
spot_price: &impl ReadableVec<Height, Cents>,
|
||||
realized_price: &impl ReadableVec<Height, Cents>,
|
||||
exit: &Exit,
|
||||
) -> Result<()> {
|
||||
self.nupl.bps.height.compute_transform2(
|
||||
max_from,
|
||||
spot_price,
|
||||
realized_price,
|
||||
|(i, price, realized_price, ..)| {
|
||||
let p = price.as_u128();
|
||||
if p == 0 {
|
||||
(i, BasisPointsSigned32::ZERO)
|
||||
} else {
|
||||
let rp = realized_price.as_u128();
|
||||
let nupl_bps = ((p as i128 - rp as i128) * 10000) / p as i128;
|
||||
(i, BasisPointsSigned32::from(nupl_bps as i32))
|
||||
}
|
||||
},
|
||||
exit,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -11,21 +11,21 @@ use super::base::CohortState;
|
||||
const COST_BASIS_PRICE_DIGITS: i32 = 4;
|
||||
|
||||
pub struct AddressCohortState<R: RealizedOps> {
|
||||
pub addr_count: u64,
|
||||
pub address_count: u64,
|
||||
pub inner: CohortState<R, CostBasisRaw>,
|
||||
}
|
||||
|
||||
impl<R: RealizedOps> AddressCohortState<R> {
|
||||
pub(crate) fn new(path: &Path, name: &str) -> Self {
|
||||
Self {
|
||||
addr_count: 0,
|
||||
address_count: 0,
|
||||
inner: CohortState::new(path, name).with_price_rounding(COST_BASIS_PRICE_DIGITS),
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset state for fresh start.
|
||||
pub(crate) fn reset(&mut self) {
|
||||
self.addr_count = 0;
|
||||
self.address_count = 0;
|
||||
self.inner.supply = SupplyState::default();
|
||||
self.inner.sent = Sats::ZERO;
|
||||
self.inner.satdays_destroyed = Sats::ZERO;
|
||||
@@ -84,7 +84,7 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
||||
}
|
||||
|
||||
pub(crate) fn add(&mut self, addressdata: &FundedAddressData) {
|
||||
self.addr_count += 1;
|
||||
self.address_count += 1;
|
||||
self.inner
|
||||
.increment_snapshot(&addressdata.cost_basis_snapshot());
|
||||
}
|
||||
@@ -96,12 +96,12 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
||||
if unlikely(self.inner.supply.utxo_count < snapshot.supply_state.utxo_count) {
|
||||
panic!(
|
||||
"AddressCohortState::subtract underflow!\n\
|
||||
Cohort state: addr_count={}, supply={}\n\
|
||||
Cohort state: address_count={}, supply={}\n\
|
||||
Address being subtracted: {}\n\
|
||||
Address supply: {}\n\
|
||||
Realized price: {}\n\
|
||||
This means the address is not properly tracked in this cohort.",
|
||||
self.addr_count,
|
||||
self.address_count,
|
||||
self.inner.supply,
|
||||
addressdata,
|
||||
snapshot.supply_state,
|
||||
@@ -111,12 +111,12 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
||||
if unlikely(self.inner.supply.value < snapshot.supply_state.value) {
|
||||
panic!(
|
||||
"AddressCohortState::subtract value underflow!\n\
|
||||
Cohort state: addr_count={}, supply={}\n\
|
||||
Cohort state: address_count={}, supply={}\n\
|
||||
Address being subtracted: {}\n\
|
||||
Address supply: {}\n\
|
||||
Realized price: {}\n\
|
||||
This means the address is not properly tracked in this cohort.",
|
||||
self.addr_count,
|
||||
self.address_count,
|
||||
self.inner.supply,
|
||||
addressdata,
|
||||
snapshot.supply_state,
|
||||
@@ -124,9 +124,9 @@ impl<R: RealizedOps> AddressCohortState<R> {
|
||||
);
|
||||
}
|
||||
|
||||
self.addr_count = self.addr_count.checked_sub(1).unwrap_or_else(|| {
|
||||
self.address_count = self.address_count.checked_sub(1).unwrap_or_else(|| {
|
||||
panic!(
|
||||
"AddressCohortState::subtract addr_count underflow! addr_count=0\n\
|
||||
"AddressCohortState::subtract address_count underflow! address_count=0\n\
|
||||
Address being subtracted: {}\n\
|
||||
Realized price: {}",
|
||||
addressdata, snapshot.realized_price
|
||||
|
||||
@@ -30,7 +30,7 @@ use crate::{
|
||||
use super::{
|
||||
AddressCohorts, AddressesDataVecs, AnyAddressIndexesVecs, RangeMap, UTXOCohorts,
|
||||
address::{
|
||||
AddrCountsVecs, AddressActivityVecs, DeltaVecs, NewAddrCountVecs, TotalAddrCountVecs,
|
||||
AddressCountsVecs, AddressActivityVecs, DeltaVecs, NewAddressCountVecs, TotalAddressCountVecs,
|
||||
},
|
||||
compute::aggregates,
|
||||
};
|
||||
@@ -39,11 +39,11 @@ const VERSION: Version = Version::new(22);
|
||||
|
||||
#[derive(Traversable)]
|
||||
pub struct AddressMetricsVecs<M: StorageMode = Rw> {
|
||||
pub funded: AddrCountsVecs<M>,
|
||||
pub empty: AddrCountsVecs<M>,
|
||||
pub funded: AddressCountsVecs<M>,
|
||||
pub empty: AddressCountsVecs<M>,
|
||||
pub activity: AddressActivityVecs<M>,
|
||||
pub total: TotalAddrCountVecs<M>,
|
||||
pub new: NewAddrCountVecs<M>,
|
||||
pub total: TotalAddressCountVecs<M>,
|
||||
pub new: NewAddressCountVecs<M>,
|
||||
pub delta: DeltaVecs<M>,
|
||||
#[traversable(wrap = "indexes", rename = "funded")]
|
||||
pub funded_index:
|
||||
@@ -135,19 +135,19 @@ impl Vecs {
|
||||
|index, _| index,
|
||||
);
|
||||
|
||||
let addr_count = AddrCountsVecs::forced_import(&db, "addr_count", version, indexes)?;
|
||||
let empty_addr_count =
|
||||
AddrCountsVecs::forced_import(&db, "empty_addr_count", version, indexes)?;
|
||||
let address_count = AddressCountsVecs::forced_import(&db, "address_count", version, indexes)?;
|
||||
let empty_address_count =
|
||||
AddressCountsVecs::forced_import(&db, "empty_address_count", version, indexes)?;
|
||||
let address_activity =
|
||||
AddressActivityVecs::forced_import(&db, "address_activity", version, indexes)?;
|
||||
|
||||
// Stored total = addr_count + empty_addr_count (global + per-type, with all derived indexes)
|
||||
let total_addr_count = TotalAddrCountVecs::forced_import(&db, version, indexes)?;
|
||||
// Stored total = address_count + empty_address_count (global + per-type, with all derived indexes)
|
||||
let total_address_count = TotalAddressCountVecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
// Per-block delta of total (global + per-type)
|
||||
let new_addr_count = NewAddrCountVecs::forced_import(&db, version, indexes)?;
|
||||
let new_address_count = NewAddressCountVecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
// Growth rate: new / addr_count (global + per-type)
|
||||
// Growth rate: new / address_count (global + per-type)
|
||||
let delta = DeltaVecs::forced_import(&db, version, indexes)?;
|
||||
|
||||
let this = Self {
|
||||
@@ -157,11 +157,11 @@ impl Vecs {
|
||||
)?,
|
||||
|
||||
addresses: AddressMetricsVecs {
|
||||
funded: addr_count,
|
||||
empty: empty_addr_count,
|
||||
funded: address_count,
|
||||
empty: empty_address_count,
|
||||
activity: address_activity,
|
||||
total: total_addr_count,
|
||||
new: new_addr_count,
|
||||
total: total_address_count,
|
||||
new: new_address_count,
|
||||
delta,
|
||||
funded_index: funded_address_index,
|
||||
empty_index: empty_address_index,
|
||||
@@ -423,7 +423,7 @@ impl Vecs {
|
||||
self.addresses.funded.compute_rest(starting_indexes, exit)?;
|
||||
self.addresses.empty.compute_rest(starting_indexes, exit)?;
|
||||
|
||||
// 6c. Compute total_addr_count = addr_count + empty_addr_count
|
||||
// 6c. Compute total_address_count = address_count + empty_address_count
|
||||
self.addresses.total.compute(
|
||||
starting_indexes.height,
|
||||
&self.addresses.funded,
|
||||
|
||||
48
crates/brk_computer/src/indexes/cached_mappings.rs
Normal file
48
crates/brk_computer/src/indexes/cached_mappings.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
use brk_types::{
|
||||
Day1, Day3, Epoch, Halving, Height, Hour1, Hour4, Hour12, Minute10, Minute30, Month1, Month3,
|
||||
Month6, Week1, Year1, Year10,
|
||||
};
|
||||
use vecdb::CachedVec;
|
||||
|
||||
use super::Vecs;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CachedMappings {
|
||||
pub minute10_first_height: CachedVec<Minute10, Height>,
|
||||
pub minute30_first_height: CachedVec<Minute30, Height>,
|
||||
pub hour1_first_height: CachedVec<Hour1, Height>,
|
||||
pub hour4_first_height: CachedVec<Hour4, Height>,
|
||||
pub hour12_first_height: CachedVec<Hour12, Height>,
|
||||
pub day1_first_height: CachedVec<Day1, Height>,
|
||||
pub day3_first_height: CachedVec<Day3, Height>,
|
||||
pub week1_first_height: CachedVec<Week1, Height>,
|
||||
pub month1_first_height: CachedVec<Month1, Height>,
|
||||
pub month3_first_height: CachedVec<Month3, Height>,
|
||||
pub month6_first_height: CachedVec<Month6, Height>,
|
||||
pub year1_first_height: CachedVec<Year1, Height>,
|
||||
pub year10_first_height: CachedVec<Year10, Height>,
|
||||
pub halving_identity: CachedVec<Halving, Halving>,
|
||||
pub epoch_identity: CachedVec<Epoch, Epoch>,
|
||||
}
|
||||
|
||||
impl CachedMappings {
|
||||
pub fn new(vecs: &Vecs) -> Self {
|
||||
Self {
|
||||
minute10_first_height: CachedVec::new(&vecs.minute10.first_height),
|
||||
minute30_first_height: CachedVec::new(&vecs.minute30.first_height),
|
||||
hour1_first_height: CachedVec::new(&vecs.hour1.first_height),
|
||||
hour4_first_height: CachedVec::new(&vecs.hour4.first_height),
|
||||
hour12_first_height: CachedVec::new(&vecs.hour12.first_height),
|
||||
day1_first_height: CachedVec::new(&vecs.day1.first_height),
|
||||
day3_first_height: CachedVec::new(&vecs.day3.first_height),
|
||||
week1_first_height: CachedVec::new(&vecs.week1.first_height),
|
||||
month1_first_height: CachedVec::new(&vecs.month1.first_height),
|
||||
month3_first_height: CachedVec::new(&vecs.month3.first_height),
|
||||
month6_first_height: CachedVec::new(&vecs.month6.first_height),
|
||||
year1_first_height: CachedVec::new(&vecs.year1.first_height),
|
||||
year10_first_height: CachedVec::new(&vecs.year10.first_height),
|
||||
halving_identity: CachedVec::new(&vecs.halving.identity),
|
||||
epoch_identity: CachedVec::new(&vecs.epoch.identity),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
mod address;
|
||||
mod cached_mappings;
|
||||
mod day1;
|
||||
mod day3;
|
||||
mod epoch;
|
||||
@@ -28,13 +29,14 @@ use brk_types::{
|
||||
Date, Day1, Day3, Height, Hour1, Hour4, Hour12, Indexes, Minute10, Minute30, Month1, Month3,
|
||||
Month6, Version, Week1, Year1, Year10,
|
||||
};
|
||||
use vecdb::{Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
use vecdb::{CachedVec, Database, Exit, ReadableVec, Rw, StorageMode};
|
||||
|
||||
use crate::{
|
||||
blocks,
|
||||
internal::{finalize_db, open_db},
|
||||
};
|
||||
|
||||
pub use cached_mappings::CachedMappings;
|
||||
pub use address::Vecs as AddressVecs;
|
||||
pub use day1::Vecs as Day1Vecs;
|
||||
pub use day3::Vecs as Day3Vecs;
|
||||
@@ -61,6 +63,8 @@ pub const DB_NAME: &str = "indexes";
|
||||
#[derive(Traversable)]
|
||||
pub struct Vecs<M: StorageMode = Rw> {
|
||||
db: Database,
|
||||
#[traversable(skip)]
|
||||
pub cached_mappings: CachedMappings,
|
||||
pub address: AddressVecs,
|
||||
pub height: HeightVecs<M>,
|
||||
pub epoch: EpochVecs<M>,
|
||||
@@ -93,27 +97,67 @@ impl Vecs {
|
||||
|
||||
let version = parent_version;
|
||||
|
||||
let address = AddressVecs::forced_import(version, indexer);
|
||||
let height = HeightVecs::forced_import(&db, version)?;
|
||||
let epoch = EpochVecs::forced_import(&db, version)?;
|
||||
let halving = HalvingVecs::forced_import(&db, version)?;
|
||||
let minute10 = Minute10Vecs::forced_import(&db, version)?;
|
||||
let minute30 = Minute30Vecs::forced_import(&db, version)?;
|
||||
let hour1 = Hour1Vecs::forced_import(&db, version)?;
|
||||
let hour4 = Hour4Vecs::forced_import(&db, version)?;
|
||||
let hour12 = Hour12Vecs::forced_import(&db, version)?;
|
||||
let day1 = Day1Vecs::forced_import(&db, version)?;
|
||||
let day3 = Day3Vecs::forced_import(&db, version)?;
|
||||
let week1 = Week1Vecs::forced_import(&db, version)?;
|
||||
let month1 = Month1Vecs::forced_import(&db, version)?;
|
||||
let month3 = Month3Vecs::forced_import(&db, version)?;
|
||||
let month6 = Month6Vecs::forced_import(&db, version)?;
|
||||
let year1 = Year1Vecs::forced_import(&db, version)?;
|
||||
let year10 = Year10Vecs::forced_import(&db, version)?;
|
||||
let txindex = TxIndexVecs::forced_import(&db, version, indexer)?;
|
||||
let txinindex = TxInIndexVecs::forced_import(version, indexer);
|
||||
let txoutindex = TxOutIndexVecs::forced_import(version, indexer);
|
||||
|
||||
let cached_mappings = CachedMappings {
|
||||
minute10_first_height: CachedVec::new(&minute10.first_height),
|
||||
minute30_first_height: CachedVec::new(&minute30.first_height),
|
||||
hour1_first_height: CachedVec::new(&hour1.first_height),
|
||||
hour4_first_height: CachedVec::new(&hour4.first_height),
|
||||
hour12_first_height: CachedVec::new(&hour12.first_height),
|
||||
day1_first_height: CachedVec::new(&day1.first_height),
|
||||
day3_first_height: CachedVec::new(&day3.first_height),
|
||||
week1_first_height: CachedVec::new(&week1.first_height),
|
||||
month1_first_height: CachedVec::new(&month1.first_height),
|
||||
month3_first_height: CachedVec::new(&month3.first_height),
|
||||
month6_first_height: CachedVec::new(&month6.first_height),
|
||||
year1_first_height: CachedVec::new(&year1.first_height),
|
||||
year10_first_height: CachedVec::new(&year10.first_height),
|
||||
halving_identity: CachedVec::new(&halving.identity),
|
||||
epoch_identity: CachedVec::new(&epoch.identity),
|
||||
};
|
||||
|
||||
let this = Self {
|
||||
address: AddressVecs::forced_import(version, indexer),
|
||||
height: HeightVecs::forced_import(&db, version)?,
|
||||
epoch: EpochVecs::forced_import(&db, version)?,
|
||||
halving: HalvingVecs::forced_import(&db, version)?,
|
||||
minute10: Minute10Vecs::forced_import(&db, version)?,
|
||||
minute30: Minute30Vecs::forced_import(&db, version)?,
|
||||
hour1: Hour1Vecs::forced_import(&db, version)?,
|
||||
hour4: Hour4Vecs::forced_import(&db, version)?,
|
||||
hour12: Hour12Vecs::forced_import(&db, version)?,
|
||||
day1: Day1Vecs::forced_import(&db, version)?,
|
||||
day3: Day3Vecs::forced_import(&db, version)?,
|
||||
week1: Week1Vecs::forced_import(&db, version)?,
|
||||
month1: Month1Vecs::forced_import(&db, version)?,
|
||||
month3: Month3Vecs::forced_import(&db, version)?,
|
||||
month6: Month6Vecs::forced_import(&db, version)?,
|
||||
year1: Year1Vecs::forced_import(&db, version)?,
|
||||
year10: Year10Vecs::forced_import(&db, version)?,
|
||||
txindex: TxIndexVecs::forced_import(&db, version, indexer)?,
|
||||
txinindex: TxInIndexVecs::forced_import(version, indexer),
|
||||
txoutindex: TxOutIndexVecs::forced_import(version, indexer),
|
||||
cached_mappings,
|
||||
address,
|
||||
height,
|
||||
epoch,
|
||||
halving,
|
||||
minute10,
|
||||
minute30,
|
||||
hour1,
|
||||
hour4,
|
||||
hour12,
|
||||
day1,
|
||||
day3,
|
||||
week1,
|
||||
month1,
|
||||
month3,
|
||||
month6,
|
||||
year1,
|
||||
year10,
|
||||
txindex,
|
||||
txinindex,
|
||||
txoutindex,
|
||||
db,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use brk_traversable::Traversable;
|
||||
use brk_types::{
|
||||
Day1, Day3, Epoch, FromCoarserIndex, Halving, Height, Hour1, Hour4, Hour12, Minute10, Minute30,
|
||||
@@ -6,7 +8,7 @@ use brk_types::{
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use vecdb::{
|
||||
Cursor, LazyAggVec, ReadOnlyClone, ReadableBoxedVec, ReadableCloneableVec, VecIndex, VecValue,
|
||||
AggFold, Cursor, LazyAggVec, ReadOnlyClone, ReadableBoxedVec, ReadableVec, VecIndex, VecValue,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -14,6 +16,53 @@ use crate::{
|
||||
internal::{ComputedVecValue, NumericValue, PerResolution},
|
||||
};
|
||||
|
||||
/// Aggregation strategy for epoch-based indices (Halving, Epoch).
|
||||
///
|
||||
/// Uses `FromCoarserIndex::max_from` to compute the target height for each
|
||||
/// coarse index, rather than reading from the mapping. The mapping is only
|
||||
/// used for its length.
|
||||
pub struct CoarserIndex<I>(PhantomData<I>);
|
||||
|
||||
impl<I, O, S1I, S2T> AggFold<O, S1I, S2T, O> for CoarserIndex<I>
|
||||
where
|
||||
I: VecIndex,
|
||||
O: VecValue,
|
||||
S1I: VecIndex + FromCoarserIndex<I>,
|
||||
S2T: VecValue,
|
||||
{
|
||||
#[inline]
|
||||
fn try_fold<S: ReadableVec<S1I, O> + ?Sized, B, E, F: FnMut(B, O) -> Result<B, E>>(
|
||||
source: &S,
|
||||
mapping: &[S2T],
|
||||
from: usize,
|
||||
to: usize,
|
||||
init: B,
|
||||
mut f: F,
|
||||
) -> Result<B, E> {
|
||||
let mapping_len = mapping.len();
|
||||
let source_len = source.len();
|
||||
let mut cursor = Cursor::new(source);
|
||||
let mut acc = init;
|
||||
for i in from..to.min(mapping_len) {
|
||||
let target = S1I::max_from(I::from(i), source_len);
|
||||
if let Some(v) = cursor.get(target) {
|
||||
acc = f(acc, v)?;
|
||||
}
|
||||
}
|
||||
Ok(acc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn collect_one<S: ReadableVec<S1I, O> + ?Sized>(
|
||||
source: &S,
|
||||
_mapping: &[S2T],
|
||||
index: usize,
|
||||
) -> Option<O> {
|
||||
let target = S1I::max_from(I::from(index), source.len());
|
||||
source.collect_one_at(target)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Deref, DerefMut, Traversable)]
|
||||
#[traversable(transparent)]
|
||||
pub struct Resolutions<T>(
|
||||
@@ -32,8 +81,8 @@ pub struct Resolutions<T>(
|
||||
LazyAggVec<Month6, Option<T>, Height, Height, T>,
|
||||
LazyAggVec<Year1, Option<T>, Height, Height, T>,
|
||||
LazyAggVec<Year10, Option<T>, Height, Height, T>,
|
||||
LazyAggVec<Halving, T, Height, Halving>,
|
||||
LazyAggVec<Epoch, T, Height, Epoch>,
|
||||
LazyAggVec<Halving, T, Height, Halving, T, CoarserIndex<Halving>>,
|
||||
LazyAggVec<Epoch, T, Height, Epoch, T, CoarserIndex<Epoch>>,
|
||||
>,
|
||||
)
|
||||
where
|
||||
@@ -59,71 +108,38 @@ where
|
||||
version: Version,
|
||||
indexes: &indexes::Vecs,
|
||||
) -> Self {
|
||||
macro_rules! period {
|
||||
($idx:ident) => {
|
||||
LazyAggVec::sparse_from_first_index(
|
||||
name,
|
||||
version,
|
||||
height_source.clone(),
|
||||
indexes.$idx.first_height.read_only_boxed_clone(),
|
||||
)
|
||||
};
|
||||
}
|
||||
let cm = &indexes.cached_mappings;
|
||||
|
||||
fn for_each_range<
|
||||
I: VecIndex,
|
||||
O: VecValue,
|
||||
S1I: VecIndex + FromCoarserIndex<I>,
|
||||
S2T: VecValue,
|
||||
>(
|
||||
from: usize,
|
||||
to: usize,
|
||||
source: &ReadableBoxedVec<S1I, O>,
|
||||
mapping: &ReadableBoxedVec<I, S2T>,
|
||||
f: &mut dyn FnMut(O),
|
||||
) {
|
||||
let mapping_len = mapping.len();
|
||||
let source_len = source.len();
|
||||
let mut cursor = Cursor::new(&**source);
|
||||
for i in from..to {
|
||||
if i >= mapping_len {
|
||||
break;
|
||||
}
|
||||
let target = S1I::max_from(I::from(i), source_len);
|
||||
if let Some(v) = cursor.get(target) {
|
||||
f(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! epoch {
|
||||
($idx:ident) => {
|
||||
macro_rules! res {
|
||||
($cached:expr) => {{
|
||||
let cached = $cached.clone();
|
||||
let mapping_version = cached.version();
|
||||
LazyAggVec::new(
|
||||
name,
|
||||
version,
|
||||
mapping_version,
|
||||
height_source.clone(),
|
||||
indexes.$idx.identity.read_only_boxed_clone(),
|
||||
for_each_range,
|
||||
move || cached.get(),
|
||||
)
|
||||
};
|
||||
}};
|
||||
}
|
||||
|
||||
Self(PerResolution {
|
||||
minute10: period!(minute10),
|
||||
minute30: period!(minute30),
|
||||
hour1: period!(hour1),
|
||||
hour4: period!(hour4),
|
||||
hour12: period!(hour12),
|
||||
day1: period!(day1),
|
||||
day3: period!(day3),
|
||||
week1: period!(week1),
|
||||
month1: period!(month1),
|
||||
month3: period!(month3),
|
||||
month6: period!(month6),
|
||||
year1: period!(year1),
|
||||
year10: period!(year10),
|
||||
halving: epoch!(halving),
|
||||
epoch: epoch!(epoch),
|
||||
minute10: res!(cm.minute10_first_height),
|
||||
minute30: res!(cm.minute30_first_height),
|
||||
hour1: res!(cm.hour1_first_height),
|
||||
hour4: res!(cm.hour4_first_height),
|
||||
hour12: res!(cm.hour12_first_height),
|
||||
day1: res!(cm.day1_first_height),
|
||||
day3: res!(cm.day3_first_height),
|
||||
week1: res!(cm.week1_first_height),
|
||||
month1: res!(cm.month1_first_height),
|
||||
month3: res!(cm.month3_first_height),
|
||||
month6: res!(cm.month6_first_height),
|
||||
year1: res!(cm.year1_first_height),
|
||||
year10: res!(cm.year10_first_height),
|
||||
halving: res!(cm.halving_identity),
|
||||
epoch: res!(cm.epoch_identity),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ impl Price<ComputedPerBlock<Cents>> {
|
||||
let cents =
|
||||
ComputedPerBlock::forced_import(db, &format!("{name}_cents"), version, indexes)?;
|
||||
let usd = LazyPerBlock::from_computed::<CentsUnsignedToDollars>(
|
||||
&format!("{name}_usd"),
|
||||
name,
|
||||
version,
|
||||
cents.height.read_only_boxed_clone(),
|
||||
¢s,
|
||||
|
||||
@@ -62,21 +62,21 @@ impl RatioPerBlockPercentiles {
|
||||
}
|
||||
|
||||
macro_rules! import_band {
|
||||
($suffix:expr) => {
|
||||
($pct:expr) => {
|
||||
RatioBand {
|
||||
ratio: import_ratio!($suffix),
|
||||
price: import_price!($suffix),
|
||||
ratio: import_ratio!(concat!("ratio_", $pct)),
|
||||
price: import_price!($pct),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
pct99: import_band!("ratio_pct99"),
|
||||
pct98: import_band!("ratio_pct98"),
|
||||
pct95: import_band!("ratio_pct95"),
|
||||
pct5: import_band!("ratio_pct5"),
|
||||
pct2: import_band!("ratio_pct2"),
|
||||
pct1: import_band!("ratio_pct1"),
|
||||
pct99: import_band!("pct99"),
|
||||
pct98: import_band!("pct98"),
|
||||
pct95: import_band!("pct95"),
|
||||
pct5: import_band!("pct5"),
|
||||
pct2: import_band!("pct2"),
|
||||
pct1: import_band!("pct1"),
|
||||
expanding_pct: ExpandingPercentiles::default(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ impl StdDevPerBlockExtended {
|
||||
macro_rules! import_band {
|
||||
($suffix:expr) => {
|
||||
StdDevBand {
|
||||
value: import!($suffix),
|
||||
value: import!(concat!("ratio_", $suffix)),
|
||||
price: import_price!($suffix),
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user