mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-23 00:48:11 -07:00
computer: snapshot
This commit is contained in:
@@ -31,7 +31,7 @@ use super::{
|
||||
},
|
||||
BIP30_DUPLICATE_HEIGHT_1, BIP30_DUPLICATE_HEIGHT_2, BIP30_ORIGINAL_HEIGHT_1,
|
||||
BIP30_ORIGINAL_HEIGHT_2, ComputeContext, FLUSH_INTERVAL, TxInReaders, TxOutReaders,
|
||||
VecsReaders, build_txinindex_to_txindex, build_txoutindex_to_txindex,
|
||||
IndexToTxIndexBuf, VecsReaders,
|
||||
};
|
||||
|
||||
/// Process all blocks from starting_height to last_height.
|
||||
@@ -78,7 +78,7 @@ pub(crate) fn process_blocks(
|
||||
let txindex_to_input_count = &indexes.txindex.input_count;
|
||||
|
||||
// From price - use cents for computation:
|
||||
let height_to_price = &prices.cents.price;
|
||||
let height_to_price = &prices.price.cents;
|
||||
|
||||
// Access pre-computed vectors from context for thread-safe access
|
||||
let height_to_price_vec = &ctx.height_to_price;
|
||||
@@ -127,9 +127,11 @@ pub(crate) fn process_blocks(
|
||||
};
|
||||
debug!("txindex_to_height RangeMap built");
|
||||
|
||||
// Create reusable iterators for sequential txout/txin reads (16KB buffered)
|
||||
// Create reusable iterators and buffers for per-block reads
|
||||
let mut txout_iters = TxOutReaders::new(indexer);
|
||||
let mut txin_iters = TxInReaders::new(indexer, inputs, &mut txindex_to_height);
|
||||
let mut txout_to_txindex_buf = IndexToTxIndexBuf::new();
|
||||
let mut txin_to_txindex_buf = IndexToTxIndexBuf::new();
|
||||
|
||||
// Pre-collect first address indexes per type for the block range
|
||||
let first_p2a_vec = indexer
|
||||
@@ -230,11 +232,11 @@ pub(crate) fn process_blocks(
|
||||
debug_assert_eq!(ctx.timestamp_at(height), timestamp);
|
||||
debug_assert_eq!(ctx.price_at(height), block_price);
|
||||
|
||||
// Build txindex mappings for this block (pass ReadableVec refs directly)
|
||||
// Build txindex mappings for this block (reuses internal buffers)
|
||||
let txoutindex_to_txindex =
|
||||
build_txoutindex_to_txindex(first_txindex, tx_count, txindex_to_output_count);
|
||||
txout_to_txindex_buf.build(first_txindex, tx_count, txindex_to_output_count);
|
||||
let txinindex_to_txindex =
|
||||
build_txinindex_to_txindex(first_txindex, tx_count, txindex_to_input_count);
|
||||
txin_to_txindex_buf.build(first_txindex, tx_count, txindex_to_input_count);
|
||||
|
||||
// Get first address indexes for this height from pre-collected vecs
|
||||
let first_addressindexes = ByAddressType {
|
||||
|
||||
@@ -125,7 +125,7 @@ impl ComputeContext {
|
||||
blocks.time.timestamp_monotonic.collect();
|
||||
|
||||
let height_to_price: Vec<Cents> =
|
||||
prices.cents.price.collect();
|
||||
prices.price.cents.collect();
|
||||
|
||||
// Build sparse table for O(1) range max queries on prices
|
||||
// Used for computing peak price during UTXO holding periods (peak regret)
|
||||
|
||||
@@ -7,10 +7,7 @@ mod write;
|
||||
|
||||
pub(crate) use block_loop::process_blocks;
|
||||
pub(crate) use context::{ComputeContext, PriceRangeMax};
|
||||
pub(crate) use readers::{
|
||||
TxInReaders, TxOutData, TxOutReaders, VecsReaders, build_txinindex_to_txindex,
|
||||
build_txoutindex_to_txindex,
|
||||
};
|
||||
pub(crate) use readers::{IndexToTxIndexBuf, TxInReaders, TxOutData, TxOutReaders, VecsReaders};
|
||||
pub(crate) use recover::{StartMode, determine_start_mode, recover_state, reset_state};
|
||||
|
||||
/// Flush checkpoint interval (every N blocks).
|
||||
|
||||
@@ -153,42 +153,39 @@ impl VecsReaders {
|
||||
}
|
||||
}
|
||||
|
||||
/// Build txoutindex -> txindex mapping for a block.
|
||||
pub(crate) fn build_txoutindex_to_txindex(
|
||||
block_first_txindex: TxIndex,
|
||||
block_tx_count: u64,
|
||||
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
|
||||
) -> Vec<TxIndex> {
|
||||
build_index_to_txindex(block_first_txindex, block_tx_count, txindex_to_count)
|
||||
/// Reusable buffers for per-block txindex mapping construction.
|
||||
pub(crate) struct IndexToTxIndexBuf {
|
||||
counts: Vec<StoredU64>,
|
||||
result: Vec<TxIndex>,
|
||||
}
|
||||
|
||||
/// Build txinindex -> txindex mapping for a block.
|
||||
pub(crate) fn build_txinindex_to_txindex(
|
||||
block_first_txindex: TxIndex,
|
||||
block_tx_count: u64,
|
||||
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
|
||||
) -> Vec<TxIndex> {
|
||||
build_index_to_txindex(block_first_txindex, block_tx_count, txindex_to_count)
|
||||
}
|
||||
|
||||
/// Build index -> txindex mapping for a block (shared implementation).
|
||||
fn build_index_to_txindex(
|
||||
block_first_txindex: TxIndex,
|
||||
block_tx_count: u64,
|
||||
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
|
||||
) -> Vec<TxIndex> {
|
||||
let first = block_first_txindex.to_usize();
|
||||
|
||||
let counts: Vec<StoredU64> =
|
||||
txindex_to_count.collect_range_at(first, first + block_tx_count as usize);
|
||||
|
||||
let total: u64 = counts.iter().map(|c| u64::from(*c)).sum();
|
||||
let mut result = Vec::with_capacity(total as usize);
|
||||
|
||||
for (offset, count) in counts.iter().enumerate() {
|
||||
let txindex = TxIndex::from(first + offset);
|
||||
result.extend(std::iter::repeat_n(txindex, u64::from(*count) as usize));
|
||||
impl IndexToTxIndexBuf {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self {
|
||||
counts: Vec::new(),
|
||||
result: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
/// Build index -> txindex mapping for a block, reusing internal buffers.
|
||||
pub(crate) fn build(
|
||||
&mut self,
|
||||
block_first_txindex: TxIndex,
|
||||
block_tx_count: u64,
|
||||
txindex_to_count: &impl ReadableVec<TxIndex, StoredU64>,
|
||||
) -> &[TxIndex] {
|
||||
let first = block_first_txindex.to_usize();
|
||||
txindex_to_count.collect_range_into_at(first, first + block_tx_count as usize, &mut self.counts);
|
||||
|
||||
let total: u64 = self.counts.iter().map(|c| u64::from(*c)).sum();
|
||||
self.result.clear();
|
||||
self.result.reserve(total as usize);
|
||||
|
||||
for (offset, count) in self.counts.iter().enumerate() {
|
||||
let txindex = TxIndex::from(first + offset);
|
||||
self.result.extend(std::iter::repeat_n(txindex, u64::from(*count) as usize));
|
||||
}
|
||||
|
||||
&self.result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,15 +697,26 @@ impl RealizedBase {
|
||||
.min(self.investor_price_cents.height.len());
|
||||
let end = others.iter().map(|o| o.cap_raw.len()).min().unwrap_or(0);
|
||||
|
||||
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
|
||||
let cap_ranges: Vec<Vec<CentsSats>> = others
|
||||
.iter()
|
||||
.map(|o| o.cap_raw.collect_range_at(start, end))
|
||||
.collect();
|
||||
let investor_cap_ranges: Vec<Vec<CentsSquaredSats>> = others
|
||||
.iter()
|
||||
.map(|o| o.investor_cap_raw.collect_range_at(start, end))
|
||||
.collect();
|
||||
|
||||
for i in start..end {
|
||||
let height = Height::from(i);
|
||||
let local_i = i - start;
|
||||
|
||||
let mut sum_cap = CentsSats::ZERO;
|
||||
let mut sum_investor_cap = CentsSquaredSats::ZERO;
|
||||
|
||||
for o in others.iter() {
|
||||
sum_cap += o.cap_raw.collect_one_at(i).unwrap();
|
||||
sum_investor_cap += o.investor_cap_raw.collect_one_at(i).unwrap();
|
||||
for idx in 0..others.len() {
|
||||
sum_cap += cap_ranges[idx][local_i];
|
||||
sum_investor_cap += investor_cap_ranges[idx][local_i];
|
||||
}
|
||||
|
||||
self.cap_raw.truncate_push(height, sum_cap)?;
|
||||
@@ -842,14 +853,14 @@ impl RealizedBase {
|
||||
|
||||
self.realized_price_extra.compute_ratio(
|
||||
starting_indexes,
|
||||
&prices.usd.price,
|
||||
&prices.price.usd,
|
||||
&self.realized_price.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
self.investor_price_extra.compute_ratio(
|
||||
starting_indexes,
|
||||
&prices.usd.price,
|
||||
&prices.price.usd,
|
||||
&self.investor_price.usd.height,
|
||||
exit,
|
||||
)?;
|
||||
|
||||
@@ -331,31 +331,38 @@ impl UnrealizedBase {
|
||||
.min()
|
||||
.unwrap_or(0);
|
||||
|
||||
// Pre-collect all cohort data to avoid per-element BytesVec reads in nested loop
|
||||
let invested_profit_ranges: Vec<Vec<CentsSats>> = others
|
||||
.iter()
|
||||
.map(|o| o.invested_capital_in_profit_raw.collect_range_at(start, end))
|
||||
.collect();
|
||||
let invested_loss_ranges: Vec<Vec<CentsSats>> = others
|
||||
.iter()
|
||||
.map(|o| o.invested_capital_in_loss_raw.collect_range_at(start, end))
|
||||
.collect();
|
||||
let investor_profit_ranges: Vec<Vec<CentsSquaredSats>> = others
|
||||
.iter()
|
||||
.map(|o| o.investor_cap_in_profit_raw.collect_range_at(start, end))
|
||||
.collect();
|
||||
let investor_loss_ranges: Vec<Vec<CentsSquaredSats>> = others
|
||||
.iter()
|
||||
.map(|o| o.investor_cap_in_loss_raw.collect_range_at(start, end))
|
||||
.collect();
|
||||
|
||||
for i in start..end {
|
||||
let height = Height::from(i);
|
||||
let local_i = i - start;
|
||||
|
||||
let mut sum_invested_profit = CentsSats::ZERO;
|
||||
let mut sum_invested_loss = CentsSats::ZERO;
|
||||
let mut sum_investor_profit = CentsSquaredSats::ZERO;
|
||||
let mut sum_investor_loss = CentsSquaredSats::ZERO;
|
||||
|
||||
for o in others.iter() {
|
||||
sum_invested_profit += o
|
||||
.invested_capital_in_profit_raw
|
||||
.collect_one_at(i)
|
||||
.unwrap();
|
||||
sum_invested_loss += o
|
||||
.invested_capital_in_loss_raw
|
||||
.collect_one_at(i)
|
||||
.unwrap();
|
||||
sum_investor_profit += o
|
||||
.investor_cap_in_profit_raw
|
||||
.collect_one_at(i)
|
||||
.unwrap();
|
||||
sum_investor_loss += o
|
||||
.investor_cap_in_loss_raw
|
||||
.collect_one_at(i)
|
||||
.unwrap();
|
||||
for idx in 0..others.len() {
|
||||
sum_invested_profit += invested_profit_ranges[idx][local_i];
|
||||
sum_invested_loss += invested_loss_ranges[idx][local_i];
|
||||
sum_investor_profit += investor_profit_ranges[idx][local_i];
|
||||
sum_investor_loss += investor_loss_ranges[idx][local_i];
|
||||
}
|
||||
|
||||
self.invested_capital_in_profit_raw
|
||||
@@ -383,7 +390,7 @@ impl UnrealizedBase {
|
||||
starting_indexes.height,
|
||||
&self.investor_cap_in_loss_raw,
|
||||
&self.invested_capital_in_loss_raw,
|
||||
&prices.cents.price,
|
||||
&prices.price.cents,
|
||||
|(h, investor_cap, invested_cap, spot, ..)| {
|
||||
if invested_cap.inner() == 0 {
|
||||
return (h, Dollars::ZERO);
|
||||
@@ -403,7 +410,7 @@ impl UnrealizedBase {
|
||||
starting_indexes.height,
|
||||
&self.investor_cap_in_profit_raw,
|
||||
&self.invested_capital_in_profit_raw,
|
||||
&prices.cents.price,
|
||||
&prices.price.cents,
|
||||
|(h, investor_cap, invested_cap, spot, ..)| {
|
||||
if invested_cap.inner() == 0 {
|
||||
return (h, Dollars::ZERO);
|
||||
|
||||
@@ -249,7 +249,7 @@ impl Vecs {
|
||||
// Recover chain_state from stored values
|
||||
debug!("recovering chain_state from stored values");
|
||||
let height_to_timestamp = &blocks.time.timestamp_monotonic;
|
||||
let height_to_price = &prices.cents.price;
|
||||
let height_to_price = &prices.price.cents;
|
||||
|
||||
let end = usize::from(recovered_height);
|
||||
let timestamp_data: Vec<_> = height_to_timestamp.collect_range_at(0, end);
|
||||
|
||||
Reference in New Issue
Block a user