mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-20 06:44:47 -07:00
global: adding support for safe lengths
This commit is contained in:
@@ -71,8 +71,7 @@ impl<I> Cluster<I> {
|
||||
/// strictly less than `i`.
|
||||
fn permute_to_topo_order(mut nodes: Vec<ClusterNode<I>>) -> Vec<ClusterNode<I>> {
|
||||
let n = nodes.len();
|
||||
let mut children: Vec<SmallVec<[LocalIdx; 2]>> =
|
||||
(0..n).map(|_| SmallVec::new()).collect();
|
||||
let mut children: Vec<SmallVec<[LocalIdx; 2]>> = (0..n).map(|_| SmallVec::new()).collect();
|
||||
let mut indegree: Vec<u32> = vec![0; n];
|
||||
for (i, node) in nodes.iter().enumerate() {
|
||||
indegree[i] = node.parents.len() as u32;
|
||||
@@ -118,10 +117,7 @@ impl<I> Cluster<I> {
|
||||
/// `trailing_zeros` visits each chunk's bits in ascending order, and
|
||||
/// nodes are stored in topo order (`LocalIdx == position`), so each
|
||||
/// pushed `LocalIdx` lands parents-first in `chunk.txs`.
|
||||
fn materialize_chunks(
|
||||
chunk_masks: &[sfl::ChunkMask],
|
||||
n: usize,
|
||||
) -> (Vec<Chunk>, Vec<ChunkId>) {
|
||||
fn materialize_chunks(chunk_masks: &[sfl::ChunkMask], n: usize) -> (Vec<Chunk>, Vec<ChunkId>) {
|
||||
let mut chunks: Vec<Chunk> = Vec::with_capacity(chunk_masks.len());
|
||||
let mut node_to_chunk = vec![ChunkId::ZERO; n];
|
||||
for (cid, cm) in chunk_masks.iter().enumerate() {
|
||||
|
||||
@@ -84,7 +84,10 @@ fn extract_chunks(t: &Tables) -> Vec<ChunkMask> {
|
||||
/// `0..n`; since the cluster is stored in topological order, that *is*
|
||||
/// a topological sweep.
|
||||
fn best_subset(t: &Tables, remaining: u128) -> (u128, Sats, VSize) {
|
||||
let ctx = Ctx { tables: t, remaining };
|
||||
let ctx = Ctx {
|
||||
tables: t,
|
||||
remaining,
|
||||
};
|
||||
let mut best = (0u128, Sats::ZERO, VSize::default());
|
||||
recurse(&ctx, 0, 0, Sats::ZERO, VSize::default(), &mut best);
|
||||
best
|
||||
@@ -99,8 +102,7 @@ fn recurse(
|
||||
best: &mut (u128, Sats, VSize),
|
||||
) {
|
||||
if idx == ctx.tables.n {
|
||||
if included != 0
|
||||
&& (best.0 == 0 || FeeRate::from((f, v)) > FeeRate::from((best.1, best.2)))
|
||||
if included != 0 && (best.0 == 0 || FeeRate::from((f, v)) > FeeRate::from((best.1, best.2)))
|
||||
{
|
||||
*best = (included, f, v);
|
||||
}
|
||||
@@ -110,8 +112,7 @@ fn recurse(
|
||||
|
||||
// Not in remaining, or a parent (within remaining) is excluded:
|
||||
// this node is forced-excluded, no branching.
|
||||
if (bit & ctx.remaining) == 0
|
||||
|| (ctx.tables.parents_mask[idx] & ctx.remaining & !included) != 0
|
||||
if (bit & ctx.remaining) == 0 || (ctx.tables.parents_mask[idx] & ctx.remaining & !included) != 0
|
||||
{
|
||||
recurse(ctx, idx + 1, included, f, v, best);
|
||||
return;
|
||||
|
||||
@@ -22,7 +22,6 @@ use brk_types::{
|
||||
VSize,
|
||||
};
|
||||
|
||||
|
||||
use crate::Mempool;
|
||||
use crate::cluster::{Cluster, ClusterRef, LocalIdx};
|
||||
|
||||
@@ -81,7 +80,11 @@ impl<I> Cluster<I> {
|
||||
let mut reachable = 1u128 << seed.inner();
|
||||
let mut out: Vec<CpfpEntry> = Vec::new();
|
||||
for (i, node) in self.nodes.iter().enumerate().skip(seed_pos + 1) {
|
||||
if node.parents.iter().any(|&p| reachable & (1u128 << p.inner()) != 0) {
|
||||
if node
|
||||
.parents
|
||||
.iter()
|
||||
.any(|&p| reachable & (1u128 << p.inner()) != 0)
|
||||
{
|
||||
reachable |= 1u128 << i;
|
||||
out.push(CpfpEntry::from(node));
|
||||
}
|
||||
@@ -108,7 +111,10 @@ impl Mempool {
|
||||
pub fn cpfp_info(&self, prefix: &TxidPrefix) -> Option<CpfpInfo> {
|
||||
let snapshot = self.snapshot();
|
||||
let seed_idx = self.entries().idx_of(prefix)?;
|
||||
let ClusterRef { cluster_id, local: seed_local } = snapshot.cluster_of(seed_idx)?;
|
||||
let ClusterRef {
|
||||
cluster_id,
|
||||
local: seed_local,
|
||||
} = snapshot.cluster_of(seed_idx)?;
|
||||
let cluster = &snapshot.clusters[cluster_id.as_usize()];
|
||||
let seed_txid = &cluster.nodes[seed_local.as_usize()].txid;
|
||||
|
||||
|
||||
@@ -43,7 +43,10 @@ impl Preparer {
|
||||
}
|
||||
|
||||
fn live_set(entries_info: &[MempoolEntryInfo]) -> FxHashSet<TxidPrefix> {
|
||||
entries_info.iter().map(|info| TxidPrefix::from(&info.txid)).collect()
|
||||
entries_info
|
||||
.iter()
|
||||
.map(|info| TxidPrefix::from(&info.txid))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn classify_additions(
|
||||
@@ -59,9 +62,7 @@ impl Preparer {
|
||||
|
||||
entries_info
|
||||
.iter()
|
||||
.filter_map(|info| {
|
||||
Self::classify(info, known, graveyard, &mut new_raws, &parent_raws)
|
||||
})
|
||||
.filter_map(|info| Self::classify(info, known, graveyard, &mut new_raws, &parent_raws))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,10 @@ fn flood_component(
|
||||
|
||||
while let Some(pos) = stack.pop() {
|
||||
members.push(pos);
|
||||
for &n in parents[pos as usize].iter().chain(children[pos as usize].iter()) {
|
||||
for &n in parents[pos as usize]
|
||||
.iter()
|
||||
.chain(children[pos as usize].iter())
|
||||
{
|
||||
if !seen[n as usize] {
|
||||
seen[n as usize] = true;
|
||||
stack.push(n);
|
||||
|
||||
@@ -11,11 +11,11 @@ use brk_types::FeeRate;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use tracing::warn;
|
||||
|
||||
use crate::stores::MempoolState;
|
||||
use clusters::build_clusters;
|
||||
use partition::Partitioner;
|
||||
#[cfg(debug_assertions)]
|
||||
use verify::Verifier;
|
||||
use crate::stores::MempoolState;
|
||||
|
||||
pub(crate) mod clusters;
|
||||
mod partition;
|
||||
|
||||
@@ -114,7 +114,9 @@ impl<'a> Partitioner<'a> {
|
||||
fn try_fill_with_smaller(&mut self, start: usize, remaining_space: VSize) -> bool {
|
||||
let end = (start + LOOK_AHEAD_COUNT).min(self.slots.len());
|
||||
for idx in (start + 1)..end {
|
||||
let Some(cand) = self.slots[idx] else { continue };
|
||||
let Some(cand) = self.slots[idx] else {
|
||||
continue;
|
||||
};
|
||||
if cand.vsize > remaining_space {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,10 @@ impl Snapshot {
|
||||
/// the full `CpfpInfo`.
|
||||
pub fn chunk_rate_of(&self, idx: TxIndex) -> Option<FeeRate> {
|
||||
let ClusterRef { cluster_id, local } = self.cluster_of(idx)?;
|
||||
Some(self.clusters[cluster_id.as_usize()].chunk_of(local).fee_rate())
|
||||
Some(
|
||||
self.clusters[cluster_id.as_usize()]
|
||||
.chunk_of(local)
|
||||
.fee_rate(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,11 @@ impl BlockStats {
|
||||
total_fee += entry.fee;
|
||||
total_vsize += entry.vsize;
|
||||
total_size += entry.size;
|
||||
fee_rates.push(clusters[cref.cluster_id.as_usize()].chunk_of(cref.local).fee_rate());
|
||||
fee_rates.push(
|
||||
clusters[cref.cluster_id.as_usize()]
|
||||
.chunk_of(cref.local)
|
||||
.fee_rate(),
|
||||
);
|
||||
}
|
||||
|
||||
let tx_count = fee_rates.len() as u32;
|
||||
|
||||
@@ -59,9 +59,7 @@ fn all_topo_orders(parents: &[Vec<u32>]) -> Vec<Vec<u32>> {
|
||||
out.push(current.clone());
|
||||
return;
|
||||
}
|
||||
let ready: Vec<u32> = (0..n as u32)
|
||||
.filter(|&i| indeg[i as usize] == 0)
|
||||
.collect();
|
||||
let ready: Vec<u32> = (0..n as u32).filter(|&i| indeg[i as usize] == 0).collect();
|
||||
for v in ready {
|
||||
indeg[v as usize] = u32::MAX;
|
||||
current.push(v);
|
||||
|
||||
@@ -72,16 +72,8 @@ fn check_invariants(fees_vsizes: &[(u64, u64)], edges: &[(u32, u32)], cluster: &
|
||||
}
|
||||
|
||||
for chunk in chunks {
|
||||
let fee: u64 = chunk
|
||||
.txs
|
||||
.iter()
|
||||
.map(|&l| fees_vsizes[input_of(l)].0)
|
||||
.sum();
|
||||
let vsize: u64 = chunk
|
||||
.txs
|
||||
.iter()
|
||||
.map(|&l| fees_vsizes[input_of(l)].1)
|
||||
.sum();
|
||||
let fee: u64 = chunk.txs.iter().map(|&l| fees_vsizes[input_of(l)].0).sum();
|
||||
let vsize: u64 = chunk.txs.iter().map(|&l| fees_vsizes[input_of(l)].1).sum();
|
||||
assert_eq!(chunk.fee, Sats::from(fee), "chunk fee mismatch");
|
||||
assert_eq!(chunk.vsize, VSize::from(vsize), "chunk vsize mismatch");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user