clusterlin: make optimal linearizations deterministic (feature)

This allows passing in a fallback order comparator to Linearize(), which
is used as final tiebreak when deciding the order of chunks and
transactions within a chunk, rather than a random tiebreak.

The order of transactions within a chunk becomes:
1. Topology (parents before children)
2. Individual transaction feerate (high to low)
3. Weight (small to large)
4. Fallback (low to high fallback order)

The order of chunks within a cluster becomes:
1. Topology (chunks after their dependencies)
2. Feerate (high to low)
3. Weight (small to large)
4. Max-fallback (chunk with lowest maximum-fallback-tx first)

For now, txgraph passes a naive comparator to Linearize(), which makes
the cluster order deterministic when treating the input transactions as
identified by the DepGraphIndex. However, since DepGraphIndexes are the
result of possibly-randomized operations inside txgraph, this doesn't
actually make txgraph's per-cluster ordering deterministic. That will be
changed in a later commit, by using a txid-based fallback instead.
This commit is contained in:
Pieter Wuille
2026-01-07 15:02:02 -05:00
parent 8bfbba3207
commit 39d0052cbf
6 changed files with 361 additions and 275 deletions

View File

@@ -2132,9 +2132,11 @@ std::pair<uint64_t, bool> GenericClusterImpl::Relinearize(TxGraphImpl& graph, in
if (IsOptimal()) return {0, false};
// Invoke the actual linearization algorithm (passing in the existing one).
uint64_t rng_seed = graph.m_rng.rand64();
auto [linearization, optimal, cost] = Linearize(m_depgraph, max_iters, rng_seed, m_linearization, /*is_topological=*/IsTopological());
// Postlinearize to undo some of the non-determinism caused by randomizing the linearization.
// This also guarantees that all chunks are connected (even when non-optimal).
auto [linearization, optimal, cost] = Linearize(m_depgraph, max_iters, rng_seed, IndexTxOrder{}, m_linearization, /*is_topological=*/IsTopological());
// Postlinearize to improve the linearization (if optimal, only the sub-chunk order), and
// reduce the amount of information the IndexTxOrder-based fallback order leaks about
// DepGraphIndexes in the cluster. This also guarantees that all chunks are connected (even
// when non-optimal).
PostLinearize(m_depgraph, linearization);
// Update the linearization.
m_linearization = std::move(linearization);