mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-14 20:48:12 -07:00
crates: snapshot
This commit is contained in:
@@ -32,11 +32,12 @@ use std::{
|
||||
};
|
||||
|
||||
use brk_error::Result;
|
||||
use brk_oracle::Histogram;
|
||||
use brk_rpc::Client;
|
||||
use brk_types::{
|
||||
AddrBytes, AddrMempoolStats, BlockTemplate, BlockTemplateDiff, FeeRate, MempoolBlock,
|
||||
MempoolInfo, MempoolRecentTx, NextBlockHash, OutpointPrefix, OutputType, Sats, Timestamp,
|
||||
Transaction, TxOut, Txid, TxidPrefix, Vin, Vout,
|
||||
MempoolInfo, MempoolRecentTx, NextBlockHash, OutpointPrefix, Timestamp, Transaction, TxOut,
|
||||
Txid, TxidPrefix, Vin, Vout,
|
||||
};
|
||||
use parking_lot::{RwLock, RwLockReadGuard};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
@@ -236,19 +237,20 @@ impl Mempool {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Apply `f` to an iterator over `(value, output_type)` for every output
|
||||
/// of every live mempool tx. The lock is held for the duration of the call.
|
||||
pub fn process_live_outputs<R>(
|
||||
&self,
|
||||
f: impl FnOnce(&mut dyn Iterator<Item = (Sats, OutputType)>) -> R,
|
||||
) -> R {
|
||||
/// Histogram of pre-bucketed oracle bins across all live mempool tx
|
||||
/// outputs. Bins are computed once on insert (see `OutputBins`), so this
|
||||
/// hot path is `O(eligible outputs)` of integer increments. Used by
|
||||
/// `live_price` to blend the mempool into the committed oracle without
|
||||
/// re-parsing scripts per request.
|
||||
pub fn live_histogram(&self) -> Histogram {
|
||||
let mut hist = Histogram::zeros();
|
||||
let state = self.read();
|
||||
let mut iter = state
|
||||
.txs
|
||||
.values()
|
||||
.flat_map(|tx| &tx.output)
|
||||
.map(|txout| (txout.value, txout.type_()));
|
||||
f(&mut iter)
|
||||
for (_, record) in state.txs.records() {
|
||||
for bin in record.output_bins.iter() {
|
||||
hist.increment(bin as usize);
|
||||
}
|
||||
}
|
||||
hist
|
||||
}
|
||||
|
||||
/// Effective fee rate for a live tx: snapshot's linearized chunk
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
|
||||
pub(crate) mod addr_tracker;
|
||||
pub(crate) mod outpoint_spends;
|
||||
pub(crate) mod output_bins;
|
||||
pub(crate) mod tx_graveyard;
|
||||
pub(crate) mod tx_store;
|
||||
|
||||
pub(crate) use addr_tracker::AddrTracker;
|
||||
pub(crate) use outpoint_spends::OutpointSpends;
|
||||
pub(crate) use output_bins::OutputBins;
|
||||
pub(crate) use tx_graveyard::{TxGraveyard, TxTombstone};
|
||||
pub(crate) use tx_store::TxStore;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
use brk_oracle::default_eligible_bin;
|
||||
use brk_types::Transaction;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
/// Pre-bucketed oracle bins for a tx's eligible outputs. Computed once on
|
||||
/// insert so `Mempool::live_histogram` can bin all live outputs without
|
||||
/// re-parsing scripts or recomputing eligibility per request.
|
||||
pub struct OutputBins(SmallVec<[u16; 4]>);
|
||||
|
||||
impl OutputBins {
|
||||
pub fn from_tx(tx: &Transaction) -> Self {
|
||||
Self(
|
||||
tx.output
|
||||
.iter()
|
||||
.filter_map(|o| default_eligible_bin(o.value, o.type_()))
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = u16> + '_ {
|
||||
self.0.iter().copied()
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,28 @@
|
||||
use brk_types::{MempoolRecentTx, Transaction, TxOut, Txid, TxidPrefix, Vin};
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use crate::TxEntry;
|
||||
use crate::{TxEntry, stores::OutputBins};
|
||||
|
||||
const RECENT_CAP: usize = 10;
|
||||
|
||||
/// Per-tx record: live tx body and its mempool entry, kept under one
|
||||
/// key so a single map probe returns both.
|
||||
/// Per-tx record: live tx body, its mempool entry, and the pre-bucketed
|
||||
/// oracle bins for its outputs. Kept under one key so a single map probe
|
||||
/// returns everything readers need.
|
||||
pub struct TxRecord {
|
||||
pub tx: Transaction,
|
||||
pub entry: TxEntry,
|
||||
pub output_bins: OutputBins,
|
||||
}
|
||||
|
||||
impl TxRecord {
|
||||
pub fn new(tx: Transaction, entry: TxEntry) -> Self {
|
||||
let output_bins = OutputBins::from_tx(&tx);
|
||||
Self {
|
||||
tx,
|
||||
entry,
|
||||
output_bins,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Live-pool index keyed by `TxidPrefix`. The full `Txid` lives in
|
||||
@@ -63,10 +76,6 @@ impl TxStore {
|
||||
self.records.values().map(|r| &r.entry.txid)
|
||||
}
|
||||
|
||||
pub fn values(&self) -> impl Iterator<Item = &Transaction> {
|
||||
self.records.values().map(|r| &r.tx)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, tx: Transaction, entry: TxEntry) {
|
||||
let prefix = entry.txid_prefix();
|
||||
debug_assert!(
|
||||
@@ -77,7 +86,7 @@ impl TxStore {
|
||||
if tx.input.iter().any(|i| i.prevout.is_none()) {
|
||||
self.unresolved.insert(prefix);
|
||||
}
|
||||
self.records.insert(prefix, TxRecord { tx, entry });
|
||||
self.records.insert(prefix, TxRecord::new(tx, entry));
|
||||
}
|
||||
|
||||
fn sample_recent(&mut self, txid: &Txid, tx: &Transaction) {
|
||||
|
||||
Reference in New Issue
Block a user