txgraph: use fallback order when linearizing (feature)

Add glue to make TxGraph use the fallback order provided to it, in the
fallback comparator it provides to the cluster linearization code.

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-txid (chunk with lowest maximum-txid first)

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. Txid (low to high txid)

This makes optimal cluster linearization, both the order of chunks
within a chunk, and the order of transactions within those chunks,
completely deterministic.
This commit is contained in:
Pieter Wuille 2026-01-10 23:28:00 -05:00
parent fba004a3df
commit 0a3351947e

View File

@ -2140,11 +2140,14 @@ 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, 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).
const auto fallback_order = [&](DepGraphIndex a, DepGraphIndex b) noexcept {
const auto ref_a = graph.m_entries[m_mapping[a]].m_ref;
const auto ref_b = graph.m_entries[m_mapping[b]].m_ref;
return graph.m_fallback_order(*ref_a, *ref_b);
};
auto [linearization, optimal, cost] = Linearize(m_depgraph, max_iters, rng_seed, fallback_order, m_linearization, /*is_topological=*/IsTopological());
// Postlinearize to improve the linearization (if optimal, only the sub-chunk order).
// This also guarantees that all chunks are connected (even when non-optimal).
PostLinearize(m_depgraph, linearization);
// Update the linearization.
m_linearization = std::move(linearization);