global: adding support for safe lengths

This commit is contained in:
nym21
2026-05-06 15:33:07 +02:00
parent da7671744f
commit 086bfd9938
177 changed files with 2445 additions and 2049 deletions

View File

@@ -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() {

View File

@@ -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;

View File

@@ -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;

View File

@@ -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()
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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(),
)
}
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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");
}