mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-07 17:18:13 -07:00
113 lines
4.7 KiB
Rust
113 lines
4.7 KiB
Rust
use std::sync::Arc;
|
|
|
|
use parking_lot::RwLock;
|
|
|
|
use crate::lengths::Lengths;
|
|
|
|
/// Pipeline-wide safe-read snapshot. All fields are lengths/counts
|
|
/// (next-to-write totals): `bound.f = N` means positions `0..N` are
|
|
/// fully written; readers reject `pos >= bound.f`. Covers vecs only:
|
|
/// reorg store rewrites can briefly tear in-flight reads.
|
|
#[derive(Clone, Default)]
|
|
pub struct SafeLengths(Arc<RwLock<Lengths>>);
|
|
|
|
impl SafeLengths {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn load(&self) -> Lengths {
|
|
self.0.read().clone()
|
|
}
|
|
|
|
pub fn reset(&self) {
|
|
*self.0.write() = Lengths::default();
|
|
}
|
|
|
|
pub fn advance(&self, next: Lengths) {
|
|
let mut g = self.0.write();
|
|
debug_assert!(
|
|
next.height >= g.height
|
|
&& next.tx_index >= g.tx_index
|
|
&& next.txin_index >= g.txin_index
|
|
&& next.txout_index >= g.txout_index
|
|
&& next.empty_output_index >= g.empty_output_index
|
|
&& next.op_return_index >= g.op_return_index
|
|
&& next.p2ms_output_index >= g.p2ms_output_index
|
|
&& next.p2pk33_addr_index >= g.p2pk33_addr_index
|
|
&& next.p2pk65_addr_index >= g.p2pk65_addr_index
|
|
&& next.p2pkh_addr_index >= g.p2pkh_addr_index
|
|
&& next.p2sh_addr_index >= g.p2sh_addr_index
|
|
&& next.p2tr_addr_index >= g.p2tr_addr_index
|
|
&& next.p2wpkh_addr_index >= g.p2wpkh_addr_index
|
|
&& next.p2wsh_addr_index >= g.p2wsh_addr_index
|
|
&& next.p2a_addr_index >= g.p2a_addr_index
|
|
&& next.unknown_output_index >= g.unknown_output_index,
|
|
"advance: per-field regression"
|
|
);
|
|
*g = next;
|
|
}
|
|
|
|
/// Drop each field to at most `starting`. Must be called BEFORE
|
|
/// any rewrite at positions `>= starting`.
|
|
pub fn lower_before(&self, starting: &Lengths) {
|
|
let mut g = self.0.write();
|
|
g.height = g.height.min(starting.height);
|
|
g.tx_index = g.tx_index.min(starting.tx_index);
|
|
g.txin_index = g.txin_index.min(starting.txin_index);
|
|
g.txout_index = g.txout_index.min(starting.txout_index);
|
|
g.empty_output_index = g.empty_output_index.min(starting.empty_output_index);
|
|
g.op_return_index = g.op_return_index.min(starting.op_return_index);
|
|
g.p2ms_output_index = g.p2ms_output_index.min(starting.p2ms_output_index);
|
|
g.p2pk33_addr_index = g.p2pk33_addr_index.min(starting.p2pk33_addr_index);
|
|
g.p2pk65_addr_index = g.p2pk65_addr_index.min(starting.p2pk65_addr_index);
|
|
g.p2pkh_addr_index = g.p2pkh_addr_index.min(starting.p2pkh_addr_index);
|
|
g.p2sh_addr_index = g.p2sh_addr_index.min(starting.p2sh_addr_index);
|
|
g.p2tr_addr_index = g.p2tr_addr_index.min(starting.p2tr_addr_index);
|
|
g.p2wpkh_addr_index = g.p2wpkh_addr_index.min(starting.p2wpkh_addr_index);
|
|
g.p2wsh_addr_index = g.p2wsh_addr_index.min(starting.p2wsh_addr_index);
|
|
g.p2a_addr_index = g.p2a_addr_index.min(starting.p2a_addr_index);
|
|
g.unknown_output_index = g.unknown_output_index.min(starting.unknown_output_index);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use brk_types::{
|
|
EmptyOutputIndex, Height, OpReturnIndex, P2AAddrIndex, P2MSOutputIndex, P2PK33AddrIndex,
|
|
P2PK65AddrIndex, P2PKHAddrIndex, P2SHAddrIndex, P2TRAddrIndex, P2WPKHAddrIndex,
|
|
P2WSHAddrIndex, TxInIndex, TxIndex, TxOutIndex, UnknownOutputIndex,
|
|
};
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn lower_before_clamps_every_field() {
|
|
let sentinel = u32::MAX as usize;
|
|
let max = Lengths {
|
|
empty_output_index: EmptyOutputIndex::from(sentinel),
|
|
height: Height::from(sentinel),
|
|
op_return_index: OpReturnIndex::from(sentinel),
|
|
p2ms_output_index: P2MSOutputIndex::from(sentinel),
|
|
p2pk33_addr_index: P2PK33AddrIndex::from(sentinel),
|
|
p2pk65_addr_index: P2PK65AddrIndex::from(sentinel),
|
|
p2pkh_addr_index: P2PKHAddrIndex::from(sentinel),
|
|
p2sh_addr_index: P2SHAddrIndex::from(sentinel),
|
|
p2tr_addr_index: P2TRAddrIndex::from(sentinel),
|
|
p2wpkh_addr_index: P2WPKHAddrIndex::from(sentinel),
|
|
p2wsh_addr_index: P2WSHAddrIndex::from(sentinel),
|
|
p2a_addr_index: P2AAddrIndex::from(sentinel),
|
|
tx_index: TxIndex::from(sentinel),
|
|
txin_index: TxInIndex::from(sentinel),
|
|
txout_index: TxOutIndex::from(sentinel),
|
|
unknown_output_index: UnknownOutputIndex::from(sentinel),
|
|
};
|
|
|
|
let safe = SafeLengths::new();
|
|
safe.advance(max);
|
|
safe.lower_before(&Lengths::default());
|
|
|
|
assert_eq!(safe.load(), Lengths::default());
|
|
}
|
|
}
|