global: snapshot

This commit is contained in:
nym21
2026-01-17 02:34:08 +01:00
parent 6bb1a2a311
commit 7b3e172948
25 changed files with 1070 additions and 1173 deletions
+24 -14
View File
@@ -1456,9 +1456,9 @@ impl Vecs {
let price_cents = if histogram.total_count() >= 10 {
// Downsample 200 bins to 100 bins
let mut bins100 = [0u32; 100];
for i in 0..100 {
(0..100).for_each(|i| {
bins100[i] = histogram.bins[i * 2] as u32 + histogram.bins[i * 2 + 1] as u32;
}
});
// Find peak bin, skipping bin 0 (round BTC amounts cluster there)
let peak_bin = bins100
@@ -1553,10 +1553,10 @@ impl Vecs {
Ok(())
}
/// Compute Phase Oracle V3 - Step 1: Per-block histograms with uniqueVal filtering
/// Compute Phase Oracle V3 - Step 1: Per-block histograms with uniqueVal + noP2TR filtering
///
/// Filters: >= 1000 sats, only outputs with unique values within their transaction.
/// This reduces spurious peaks from exchange batched payouts and inscription spam.
/// Filters: >= 1000 sats, no P2TR outputs, only outputs with unique values within their tx.
/// This reduces spurious peaks from inscription spam and exchange batched payouts.
fn compute_phase_v3_histograms(
&mut self,
indexer: &Indexer,
@@ -1564,7 +1564,8 @@ impl Vecs {
starting_indexes: &ComputeIndexes,
exit: &Exit,
) -> Result<()> {
let source_version = indexer.vecs.outputs.value.version();
let source_version =
indexer.vecs.outputs.value.version() + indexer.vecs.outputs.outputtype.version();
self.phase_v3_histogram
.validate_computed_version_or_reset(source_version)?;
@@ -1592,12 +1593,13 @@ impl Vecs {
indexer.vecs.transactions.first_txoutindex.into_iter();
let mut txindex_to_output_count_iter = indexes.txindex.output_count.iter();
let mut txoutindex_to_value_iter = indexer.vecs.outputs.value.into_iter();
let mut txoutindex_to_outputtype_iter = indexer.vecs.outputs.outputtype.into_iter();
let total_txs = indexer.vecs.transactions.height.len();
let mut last_progress = (start_height * 100 / total_heights.max(1)) as u8;
// Reusable buffer for collecting output values per transaction
let mut tx_values: Vec<Sats> = Vec::with_capacity(16);
// Reusable buffer for collecting output values per transaction (sats, is_p2tr)
let mut tx_outputs: Vec<(Sats, bool)> = Vec::with_capacity(16);
for height in start_height..total_heights {
// Get transaction range for this block
@@ -1606,7 +1608,7 @@ impl Vecs {
.get_at(height + 1)
.unwrap_or(TxIndex::from(total_txs));
// Build phase histogram with uniqueVal filtering
// Build phase histogram with uniqueVal + noP2TR filtering
let mut histogram = OracleBinsV2::ZERO;
// Skip coinbase (first tx in block)
@@ -1616,17 +1618,25 @@ impl Vecs {
let output_count: StoredU64 =
txindex_to_output_count_iter.get_unwrap(TxIndex::from(txindex));
// Collect all output values for this transaction
tx_values.clear();
// Collect all output values and types for this transaction
tx_outputs.clear();
for i in 0..*output_count as usize {
let txoutindex = first_txoutindex.to_usize() + i;
let sats: Sats = txoutindex_to_value_iter.get_at_unwrap(txoutindex);
tx_values.push(sats);
let outputtype: OutputType =
txoutindex_to_outputtype_iter.get_at_unwrap(txoutindex);
let is_p2tr = outputtype == OutputType::P2TR;
tx_outputs.push((sats, is_p2tr));
}
// Count occurrences of each value to determine uniqueness
// For small output counts, simple nested loop is faster than HashMap
for (i, &sats) in tx_values.iter().enumerate() {
for (i, &(sats, is_p2tr)) in tx_outputs.iter().enumerate() {
// Skip P2TR outputs (inscription spam)
if is_p2tr {
continue;
}
// Skip if below minimum (BASE filter: >= 1000 sats)
if sats < Sats::_1K {
continue;
@@ -1634,7 +1644,7 @@ impl Vecs {
// Check if this value is unique within the transaction
let mut is_unique = true;
for (j, &other_sats) in tx_values.iter().enumerate() {
for (j, &(other_sats, _)) in tx_outputs.iter().enumerate() {
if i != j && sats == other_sats {
is_unique = false;
break;
@@ -72,9 +72,9 @@ impl Vecs {
&phase_v2_peak_daily_cents,
);
// Phase Oracle V3 (BASE + uniqueVal filter)
// v4: Peak prices use 100 bins (downsampled from 200)
let phase_v3_version = version + Version::new(4);
// Phase Oracle V3 (BASE + noP2TR + uniqueVal filter)
// v5: Added noP2TR filter to reduce inscription spam
let phase_v3_version = version + Version::new(5);
let phase_v3_histogram =
BytesVec::forced_import(db, "phase_v3_histogram", phase_v3_version)?;
let phase_v3_price_cents =
@@ -67,6 +67,7 @@ impl Default for PhaseHistogramV2 {
}
}
#[allow(unused)]
impl PhaseHistogramV2 {
pub fn new() -> Self {
Self {
@@ -153,9 +154,7 @@ pub fn find_best_phase(
(min_bin..=max_bin).collect()
} else {
// Wraps around
(min_bin..PHASE_BINS_V2)
.chain(0..=max_bin)
.collect()
(min_bin..PHASE_BINS_V2).chain(0..=max_bin).collect()
}
} else {
(0..PHASE_BINS_V2).collect()