global: MASSIVE snapshot

This commit is contained in:
nym21
2026-02-23 17:22:12 +01:00
parent be0d749f9c
commit 3b7aa8242a
703 changed files with 29130 additions and 30779 deletions

View File

@@ -1,9 +1,9 @@
// TODO: INCOMPLETE - indexes_to_fee_rate.dateindex doesn't have percentile fields
// because from_txindex.rs calls remove_percentiles() before creating dateindex.
// TODO: INCOMPLETE - indexes_to_fee_rate.day1 doesn't have percentile fields
// because from_txindex.rs calls remove_percentiles() before creating day1.
// Need to either:
// 1. Use .height instead and convert height to dateindex for iteration
// 2. Fix from_txindex.rs to preserve percentiles for dateindex
// 3. Create a separate dateindex computation path with percentiles
// 1. Use .height instead and convert height to day1 for iteration
// 2. Fix from_txindex.rs to preserve percentiles for day1
// 3. Create a separate day1 computation path with percentiles
#![allow(dead_code)]
@@ -15,12 +15,11 @@ use brk_types::{
};
// use vecdb::{IterableVec, VecIndex};
// use super::dateindex_iter::DateIndexIter;
use crate::Query;
impl Query {
pub fn block_fee_rates(&self, _time_period: TimePeriod) -> Result<Vec<BlockFeeRatesEntry>> {
// Disabled until percentile data is available at dateindex level
// Disabled until percentile data is available at day1 level
Ok(Vec::new())
// Original implementation:
@@ -30,9 +29,9 @@ impl Query {
// .to_usize()
// .saturating_sub(time_period.block_count());
//
// let iter = DateIndexIter::new(computer, start, current_height.to_usize());
// let iter = Day1Iter::new(computer, start, current_height.to_usize());
//
// let vecs = &computer.transactions.transaction.indexes_to_fee_rate.dateindex;
// let vecs = &computer.transactions.transaction.indexes_to_fee_rate.day1;
// let mut min = vecs.unwrap_min().iter();
// let mut pct10 = vecs.unwrap_pct10().iter();
// let mut pct25 = vecs.unwrap_pct25().iter();

View File

@@ -1,8 +1,8 @@
use brk_error::Result;
use brk_types::{BlockFeesEntry, TimePeriod};
use vecdb::{IterableVec, VecIndex};
use vecdb::{ReadableVec, VecIndex};
use super::dateindex_iter::DateIndexIter;
use super::day1_iter::Day1Iter;
use crate::Query;
impl Query {
@@ -13,19 +13,18 @@ impl Query {
.to_usize()
.saturating_sub(time_period.block_count());
let iter = DateIndexIter::new(computer, start, current_height.to_usize());
let iter = Day1Iter::new(computer, start, current_height.to_usize());
let mut fees = computer
let fees_vec = &computer
.transactions
.fees
.fee
.sats
.dateindex
.average()
.iter();
.day1
.average;
Ok(iter.collect(|di, ts, h| {
fees.get(di).map(|fee| BlockFeesEntry {
fees_vec.collect_one(di).map(|fee| BlockFeesEntry {
avg_height: h,
timestamp: ts,
avg_fees: fee,

View File

@@ -1,8 +1,8 @@
use brk_error::Result;
use brk_types::{BlockRewardsEntry, TimePeriod};
use vecdb::{IterableVec, VecIndex};
use vecdb::{ReadableVec, VecIndex};
use super::dateindex_iter::DateIndexIter;
use super::day1_iter::Day1Iter;
use crate::Query;
impl Query {
@@ -13,20 +13,18 @@ impl Query {
.to_usize()
.saturating_sub(time_period.block_count());
let iter = DateIndexIter::new(computer, start, current_height.to_usize());
let iter = Day1Iter::new(computer, start, current_height.to_usize());
let mut rewards = computer
.blocks
let rewards_vec = &computer
.mining
.rewards
.coinbase
.sats
.dateindex
.distribution
.average()
.iter();
.day1
.average;
Ok(iter.collect(|di, ts, h| {
rewards.get(di).map(|reward| BlockRewardsEntry {
rewards_vec.collect_one(di).map(|reward| BlockRewardsEntry {
avg_height: h.into(),
timestamp: *ts,
avg_rewards: *reward,

View File

@@ -1,8 +1,8 @@
use brk_error::Result;
use brk_types::{BlockSizeEntry, BlockSizesWeights, BlockWeightEntry, TimePeriod};
use vecdb::{IterableVec, VecIndex};
use vecdb::{ReadableVec, VecIndex};
use super::dateindex_iter::DateIndexIter;
use super::day1_iter::Day1Iter;
use crate::Query;
impl Query {
@@ -13,34 +13,30 @@ impl Query {
.to_usize()
.saturating_sub(time_period.block_count());
let iter = DateIndexIter::new(computer, start, current_height.to_usize());
let iter = Day1Iter::new(computer, start, current_height.to_usize());
let mut sizes_vec = computer
let sizes_vec = &computer
.blocks
.size
.size
.dateindex
.distribution
.average()
.iter();
let mut weights_vec = computer
.day1
.average;
let weights_vec = &computer
.blocks
.weight
.weight
.dateindex
.distribution
.average()
.iter();
.day1
.average;
let entries: Vec<_> = iter.collect(|di, ts, h| {
let size = sizes_vec.get(di).map(|s| *s);
let weight = weights_vec.get(di).map(|w| *w);
let size = sizes_vec.collect_one(di).map(|s| *s);
let weight = weights_vec.collect_one(di).map(|w| *w);
Some((h.into(), (*ts), size, weight))
});
let sizes = entries
.iter()
.filter_map(|(h, ts, size, _)| {
.filter_map(|(h, ts, size, _): &(u32, _, _, _)| {
size.map(|s| BlockSizeEntry {
avg_height: *h,
timestamp: *ts,
@@ -51,7 +47,7 @@ impl Query {
let weights = entries
.iter()
.filter_map(|(h, ts, _, weight)| {
.filter_map(|(h, ts, _, weight): &(u32, _, _, _)| {
weight.map(|w| BlockWeightEntry {
avg_height: *h,
timestamp: *ts,

View File

@@ -1,28 +1,28 @@
use brk_computer::Computer;
use brk_types::{DateIndex, Height, Timestamp};
use vecdb::{GenericStoredVec, IterableVec, VecIndex};
use brk_types::{Day1, Height, Timestamp};
use vecdb::{ReadableVec, Ro, VecIndex};
/// Helper for iterating over dateindex ranges with sampling.
pub struct DateIndexIter<'a> {
computer: &'a Computer,
start_di: DateIndex,
end_di: DateIndex,
/// Helper for iterating over day1 ranges with sampling.
pub struct Day1Iter<'a> {
computer: &'a Computer<Ro>,
start_di: Day1,
end_di: Day1,
step: usize,
}
impl<'a> DateIndexIter<'a> {
pub fn new(computer: &'a Computer, start_height: usize, end_height: usize) -> Self {
impl<'a> Day1Iter<'a> {
pub fn new(computer: &'a Computer<Ro>, start_height: usize, end_height: usize) -> Self {
let start_di = computer
.indexes
.height
.dateindex
.read_once(Height::from(start_height))
.day1
.collect_one(Height::from(start_height))
.unwrap_or_default();
let end_di = computer
.indexes
.height
.dateindex
.read_once(Height::from(end_height))
.day1
.collect_one(Height::from(end_height))
.unwrap_or_default();
let total = end_di.to_usize().saturating_sub(start_di.to_usize()) + 1;
@@ -39,22 +39,22 @@ impl<'a> DateIndexIter<'a> {
/// Iterate and collect entries using the provided transform function.
pub fn collect<T, F>(&self, mut transform: F) -> Vec<T>
where
F: FnMut(DateIndex, Timestamp, Height) -> Option<T>,
F: FnMut(Day1, Timestamp, Height) -> Option<T>,
{
let total = self
.end_di
.to_usize()
.saturating_sub(self.start_di.to_usize())
+ 1;
let mut timestamps = self.computer.blocks.time.timestamp.dateindex.iter();
let mut heights = self.computer.indexes.dateindex.first_height.iter();
let timestamps = &self.computer.blocks.time.timestamp.day1;
let heights = &self.computer.indexes.day1.first_height;
let mut entries = Vec::with_capacity(total / self.step + 1);
let mut i = self.start_di.to_usize();
while i <= self.end_di.to_usize() {
let di = DateIndex::from(i);
if let (Some(ts), Some(h)) = (timestamps.get(di), heights.get(di))
let di = Day1::from(i);
if let (Some(ts), Some(h)) = (timestamps.collect_one(di), heights.collect_one(di))
&& let Some(entry) = transform(di, ts, h)
{
entries.push(entry);

View File

@@ -2,7 +2,7 @@ use std::time::{SystemTime, UNIX_EPOCH};
use brk_error::Result;
use brk_types::{DifficultyAdjustment, DifficultyEpoch, Height};
use vecdb::GenericStoredVec;
use vecdb::ReadableVec;
use crate::Query;
@@ -24,7 +24,8 @@ impl Query {
.indexes
.height
.difficultyepoch
.read_once(current_height)?;
.collect_one(current_height)
.unwrap();
let current_epoch_usize: usize = current_epoch.into();
// Get epoch start height
@@ -32,7 +33,8 @@ impl Query {
.indexes
.difficultyepoch
.first_height
.read_once(current_epoch)?;
.collect_one(current_epoch)
.unwrap();
let epoch_start_u32: u32 = epoch_start_height.into();
// Calculate epoch progress
@@ -47,12 +49,14 @@ impl Query {
.time
.timestamp
.difficultyepoch
.read_once(current_epoch)?;
.collect_one(current_epoch)
.unwrap();
let current_timestamp = indexer
.vecs
.blocks
.timestamp
.read_once(current_height)?;
.collect_one(current_height)
.unwrap();
// Calculate average block time in current epoch
let elapsed_time = (*current_timestamp - *epoch_start_timestamp) as u64;
@@ -88,18 +92,21 @@ impl Query {
.indexes
.difficultyepoch
.first_height
.read_once(prev_epoch)?;
.collect_one(prev_epoch)
.unwrap();
let prev_difficulty = indexer
.vecs
.blocks
.difficulty
.read_once(prev_epoch_start)?;
.collect_one(prev_epoch_start)
.unwrap();
let curr_difficulty = indexer
.vecs
.blocks
.difficulty
.read_once(epoch_start_height)?;
.collect_one(epoch_start_height)
.unwrap();
if *prev_difficulty > 0.0 {
((*curr_difficulty / *prev_difficulty) - 1.0) * 100.0

View File

@@ -1,10 +1,10 @@
use brk_computer::Computer;
use brk_types::{DifficultyAdjustmentEntry, DifficultyEpoch, Height};
use vecdb::{GenericStoredVec, IterableVec, VecIndex};
use vecdb::{ReadableVec, Ro, VecIndex};
/// Iterate over difficulty epochs within a height range.
pub fn iter_difficulty_epochs(
computer: &Computer,
computer: &Computer<Ro>,
start_height: usize,
end_height: usize,
) -> Vec<DifficultyAdjustmentEntry> {
@@ -12,38 +12,34 @@ pub fn iter_difficulty_epochs(
.indexes
.height
.difficultyepoch
.read_once(Height::from(start_height))
.collect_one(Height::from(start_height))
.unwrap_or_default();
let end_epoch = computer
.indexes
.height
.difficultyepoch
.read_once(Height::from(end_height))
.collect_one(Height::from(end_height))
.unwrap_or_default();
let mut epoch_to_height_iter = computer
.indexes
.difficultyepoch
.first_height
.iter();
let mut epoch_to_timestamp_iter = computer.blocks.time.timestamp.difficultyepoch.iter();
let mut epoch_to_difficulty_iter = computer.blocks.difficulty.raw.difficultyepoch.iter();
let epoch_to_height = &computer.indexes.difficultyepoch.first_height;
let epoch_to_timestamp = &computer.blocks.time.timestamp.difficultyepoch;
let epoch_to_difficulty = &computer.blocks.difficulty.raw.difficultyepoch;
let mut results = Vec::with_capacity(end_epoch.to_usize() - start_epoch.to_usize() + 1);
let mut prev_difficulty: Option<f64> = None;
for epoch_usize in start_epoch.to_usize()..=end_epoch.to_usize() {
let epoch = DifficultyEpoch::from(epoch_usize);
let epoch_height = epoch_to_height_iter.get(epoch).unwrap_or_default();
let epoch_height = epoch_to_height.collect_one(epoch).unwrap_or_default();
// Skip epochs before our start height but track difficulty
if epoch_height.to_usize() < start_height {
prev_difficulty = epoch_to_difficulty_iter.get(epoch).map(|d| *d);
prev_difficulty = epoch_to_difficulty.collect_one(epoch).map(|d| *d);
continue;
}
let epoch_timestamp = epoch_to_timestamp_iter.get(epoch).unwrap_or_default();
let epoch_difficulty = *epoch_to_difficulty_iter.get(epoch).unwrap_or_default();
let epoch_timestamp = epoch_to_timestamp.collect_one(epoch).unwrap_or_default();
let epoch_difficulty = *epoch_to_difficulty.collect_one(epoch).unwrap_or_default();
let change_percent = match prev_difficulty {
Some(prev) if prev > 0.0 => ((epoch_difficulty / prev) - 1.0) * 100.0,

View File

@@ -1,6 +1,6 @@
use brk_error::Result;
use brk_types::{DateIndex, DifficultyEntry, HashrateEntry, HashrateSummary, Height, TimePeriod};
use vecdb::{GenericStoredVec, IterableVec, VecIndex};
use brk_types::{Day1, DifficultyEntry, HashrateEntry, HashrateSummary, Height, TimePeriod};
use vecdb::{ReadableVec, VecIndex};
use super::epochs::iter_difficulty_epochs;
use crate::Query;
@@ -12,21 +12,23 @@ impl Query {
let current_height = self.height();
// Get current difficulty
let current_difficulty = *indexer.vecs.blocks.difficulty.read_once(current_height)?;
let current_difficulty = *indexer.vecs.blocks.difficulty.collect_one(current_height).unwrap();
// Get current hashrate
let current_dateindex = computer
let current_day1 = computer
.indexes
.height
.dateindex
.read_once(current_height)?;
.day1
.collect_one(current_height)
.unwrap();
let current_hashrate = *computer
.blocks
.mining
.hashrate
.hash_rate
.dateindex
.read_once(current_dateindex)? as u128;
.day1
.collect_one(current_day1)
.unwrap() as u128;
// Calculate start height based on time period
let end = current_height.to_usize();
@@ -36,31 +38,30 @@ impl Query {
};
// Get hashrate entries using iterators for efficiency
let start_dateindex = computer
let start_day1 = computer
.indexes
.height
.dateindex
.read_once(Height::from(start))?;
let end_dateindex = current_dateindex;
.day1
.collect_one(Height::from(start))
.unwrap();
let end_day1 = current_day1;
// Sample at regular intervals to avoid too many data points
let total_days = end_dateindex
let total_days = end_day1
.to_usize()
.saturating_sub(start_dateindex.to_usize())
.saturating_sub(start_day1.to_usize())
+ 1;
let step = (total_days / 200).max(1); // Max ~200 data points
// Create iterators for the loop
let mut hashrate_iter = computer.blocks.mining.hash_rate.dateindex.iter();
let mut timestamp_iter = computer.blocks.time.timestamp.dateindex.iter();
let hashrate_vec = &computer.mining.hashrate.hash_rate.day1;
let timestamp_vec = &computer.blocks.time.timestamp.day1;
let mut hashrates = Vec::with_capacity(total_days / step + 1);
let mut di = start_dateindex.to_usize();
while di <= end_dateindex.to_usize() {
let dateindex = DateIndex::from(di);
let mut di = start_day1.to_usize();
while di <= end_day1.to_usize() {
let day1 = Day1::from(di);
if let (Some(hr), Some(timestamp)) =
(hashrate_iter.get(dateindex), timestamp_iter.get(dateindex))
(hashrate_vec.collect_one(day1), timestamp_vec.collect_one(day1))
{
hashrates.push(HashrateEntry {
timestamp,

View File

@@ -2,7 +2,7 @@ mod block_fee_rates;
mod block_fees;
mod block_rewards;
mod block_sizes;
mod dateindex_iter;
mod day1_iter;
mod difficulty;
mod difficulty_adjustments;
mod epochs;

View File

@@ -3,7 +3,7 @@ use brk_types::{
Height, PoolBlockCounts, PoolBlockShares, PoolDetail, PoolDetailInfo, PoolInfo, PoolSlug,
PoolStats, PoolsSummary, TimePeriod, pools,
};
use vecdb::{AnyVec, IterableVec, VecIndex};
use vecdb::{AnyVec, ReadableVec, VecIndex};
use crate::Query;
@@ -30,18 +30,16 @@ impl Query {
// For each pool, get cumulative count at end and start, subtract to get range count
for (pool_id, pool_vecs) in &computer.pools.vecs {
let mut cumulative = pool_vecs
let cumulative = &pool_vecs
.blocks_mined
.height_cumulative
.inner()
.iter();
.height_cumulative;
let count_at_end: u32 = *cumulative.get(current_height).unwrap_or_default();
let count_at_end: u32 = *cumulative.collect_one(current_height).unwrap_or_default();
let count_at_start: u32 = if start == 0 {
0
} else {
*cumulative.get(Height::from(start - 1)).unwrap_or_default()
*cumulative.collect_one(Height::from(start - 1)).unwrap_or_default()
};
let block_count = count_at_end.saturating_sub(count_at_start);
@@ -100,14 +98,12 @@ impl Query {
.get(&slug)
.ok_or_else(|| Error::NotFound("Pool data not found".into()))?;
let mut cumulative = pool_vecs
let cumulative = &pool_vecs
.blocks_mined
.height_cumulative
.inner()
.iter();
.height_cumulative;
// Get total blocks (all time)
let total_all: u32 = *cumulative.get(current_height).unwrap_or_default();
let total_all: u32 = *cumulative.collect_one(current_height).unwrap_or_default();
// Get blocks for 24h (144 blocks)
let start_24h = end.saturating_sub(144);
@@ -115,7 +111,7 @@ impl Query {
0
} else {
*cumulative
.get(Height::from(start_24h - 1))
.collect_one(Height::from(start_24h - 1))
.unwrap_or_default()
};
let total_24h = total_all.saturating_sub(count_before_24h);
@@ -126,7 +122,7 @@ impl Query {
0
} else {
*cumulative
.get(Height::from(start_1w - 1))
.collect_one(Height::from(start_1w - 1))
.unwrap_or_default()
};
let total_1w = total_all.saturating_sub(count_before_1w);

View File

@@ -1,6 +1,6 @@
use brk_error::Result;
use brk_types::{Height, RewardStats, Sats};
use vecdb::{IterableVec, VecIndex};
use vecdb::{ReadableVec, VecIndex};
use crate::Query;
@@ -12,39 +12,16 @@ impl Query {
let end_block = current_height;
let start_block = Height::from(current_height.to_usize().saturating_sub(block_count - 1));
let mut coinbase_iter = computer.blocks.rewards.coinbase.sats.height.iter();
let coinbase_vec = &computer.mining.rewards.coinbase.sats.height;
let fee_vec = &computer.transactions.fees.fee.sats.height.sum_cum.sum.0;
let tx_count_vec = &computer.transactions.count.tx_count.height;
let mut fee_iter = computer
.transactions
.fees
.fee
.sats
.height
.sum_cum
.sum
.0
.iter();
let mut tx_count_iter = computer.transactions.count.tx_count.height.iter();
let start = start_block.to_usize();
let end = end_block.to_usize() + 1;
let mut total_reward = Sats::ZERO;
let mut total_fee = Sats::ZERO;
let mut total_tx: u64 = 0;
for height in start_block.to_usize()..=end_block.to_usize() {
let h = Height::from(height);
if let Some(coinbase) = coinbase_iter.get(h) {
total_reward += coinbase;
}
if let Some(fee) = fee_iter.get(h) {
total_fee += fee;
}
if let Some(tx_count) = tx_count_iter.get(h) {
total_tx += *tx_count;
}
}
let total_reward = coinbase_vec.fold_range_at(start, end, Sats::ZERO, |acc, v| acc + v);
let total_fee = fee_vec.fold_range_at(start, end, Sats::ZERO, |acc, v| acc + v);
let total_tx = tx_count_vec.fold_range_at(start, end, 0u64, |acc, v| acc + *v);
Ok(RewardStats {
start_block,