//! Verify the production restart property: an oracle restored via //! `from_checkpoint` (seeded from the previous block's stored cents price, //! replayed over the last `window_size` blocks) produces bit-exact `ref_bin` //! values matching a continuously-running oracle from the restart height //! onward. //! //! Mirrors the production transaction filter exactly, so it exercises the same code path //! `brk_computer::price::compute::feed_blocks` uses at runtime. //! //! Run with: cargo run -p brk_oracle --example determinism --release use std::path::PathBuf; use brk_indexer::Indexer; use brk_oracle::{ bin_to_cents, cents_to_bin, Config, HistogramRaw, Oracle, PaymentFilter, START_HEIGHT_FAST, START_HEIGHT_SLOW, }; use brk_types::{OutputType, Sats, TxIndex, TxOutIndex}; use vecdb::{AnyVec, ReadableVec, VecIndex}; struct Block { height: usize, values: Vec, output_types: Vec, tx_starts: Vec, out_start: usize, out_end: usize, } fn build_histogram(block: &Block) -> HistogramRaw { let tx_outputs = (0..block.tx_starts.len()).map(|tx| { let lo = block.tx_starts[tx] - block.out_start; let hi = block .tx_starts .get(tx + 1) .map(|s| s - block.out_start) .unwrap_or(block.out_end - block.out_start); block.values[lo..hi] .iter() .copied() .zip(block.output_types[lo..hi].iter().copied()) }); PaymentFilter::for_height(block.height).histogram(tx_outputs) } fn main() { let data_dir = std::env::var("BRK_DIR") .map(PathBuf::from) .unwrap_or_else(|_| { let home = std::env::var("HOME").unwrap(); PathBuf::from(home).join(".brk") }); let indexer = Indexer::forced_import(&data_dir).expect("Failed to load indexer"); let total_heights = indexer.vecs.blocks.timestamp.len(); let fast_config = Config::default(); let window_size = fast_config.window_size; let restart_offset = 1000; let end_offset = restart_offset + window_size * 4; let end_height = (START_HEIGHT_FAST + end_offset).min(total_heights); let restart_at = START_HEIGHT_FAST + restart_offset; let warmup_start = restart_at - window_size; let load_start = START_HEIGHT_SLOW; assert!( end_height > restart_at, "indexer has {total_heights} blocks; need at least {} to test restart at {restart_at}", restart_at + 1 ); println!( "Loading {} blocks ({load_start}..{end_height})...", end_height - load_start ); let total_txs = indexer.vecs.transactions.txid.len(); let total_outputs = indexer.vecs.outputs.value.len(); let first_tx_index: Vec = indexer.vecs.transactions.first_tx_index.collect(); let out_first: Vec = indexer.vecs.outputs.first_txout_index.collect(); let mut txout_cursor = indexer.vecs.transactions.first_txout_index.cursor(); let mut blocks: Vec = Vec::with_capacity(end_height - load_start); for h in load_start..end_height { let ft = first_tx_index[h]; let next_ft = first_tx_index .get(h + 1) .copied() .unwrap_or(TxIndex::from(total_txs)); let block_first_tx = ft.to_usize() + 1; let tx_count = next_ft.to_usize() - block_first_tx; let out_end = out_first .get(h + 1) .copied() .unwrap_or(TxOutIndex::from(total_outputs)) .to_usize(); txout_cursor.advance(block_first_tx - txout_cursor.position()); let mut tx_starts: Vec = Vec::with_capacity(tx_count); for _ in 0..tx_count { tx_starts.push(txout_cursor.next().unwrap().to_usize()); } let out_start = tx_starts.first().copied().unwrap_or(out_end); let values: Vec = indexer .vecs .outputs .value .collect_range_at(out_start, out_end); let output_types: Vec = indexer .vecs .outputs .output_type .collect_range_at(out_start, out_end); blocks.push(Block { height: h, values, output_types, tx_starts, out_start, out_end, }); } let mut continuous = Oracle::from_seed(); let continuous_bins: Vec = blocks .iter() .map(|b| { if b.height == START_HEIGHT_FAST { continuous.reconfigure(fast_config); } continuous.process_histogram(&build_histogram(b)) }) .collect(); println!( "Continuous oracle: {} blocks processed", continuous_bins.len() ); let prev_bin = continuous_bins[restart_at - load_start - 1]; let seed_bin = cents_to_bin(bin_to_cents(prev_bin) as f64); println!( "Restart at {restart_at}: prev_bin={prev_bin:.4} -> cents -> seed_bin={seed_bin:.4} (delta {:.6})", seed_bin - prev_bin ); let warmup_slice = &blocks[warmup_start - load_start..restart_at - load_start]; let mut restored = Oracle::from_checkpoint(seed_bin, fast_config, |o| { for b in warmup_slice { o.process_histogram(&build_histogram(b)); } }); let restored_bins: Vec = blocks[restart_at - load_start..] .iter() .map(|b| restored.process_histogram(&build_histogram(b))) .collect(); println!("Restored oracle: {} blocks processed", restored_bins.len()); let mut mismatches: Vec<(usize, f64, f64)> = Vec::new(); for (i, &r) in restored_bins.iter().enumerate() { let c = continuous_bins[restart_at - load_start + i]; if r != c { mismatches.push((restart_at + i, c, r)); } } println!(); if mismatches.is_empty() { println!( "All {} blocks from {restart_at} onward match exactly.", restored_bins.len() ); } else { println!( "{} of {} blocks differ (showing up to 5):", mismatches.len(), restored_bins.len() ); for (h, c, r) in mismatches.iter().take(5) { println!( " h={h}: continuous={c:.6}, restored={r:.6}, delta={:.6}", r - c ); } } assert_eq!( mismatches.len(), 0, "restored oracle diverged from continuous oracle" ); println!(); println!("Assertion passed: from_checkpoint restart is bit-exact."); }