From 5801e0fb2b99f44ac24531779acf0d44ec35b98c Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 15 Nov 2024 13:31:23 -0500 Subject: [PATCH] txgraph: Delay chunking while sub-acceptable (optimization) Chunk-based information (primarily, chunk feerates) are never accessed without first bringing the relevant Clusters to an "acceptable" quality level. Thus, while operations are ongoing and Clusters are not acceptable, we can omit computing the chunkings and chunk feerates for Clusters. --- src/txgraph.cpp | 50 +++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/txgraph.cpp b/src/txgraph.cpp index 2ef2f7b2c3e..28a2790cc81 100644 --- a/src/txgraph.cpp +++ b/src/txgraph.cpp @@ -331,23 +331,27 @@ void Cluster::Updated(TxGraphImpl& graph) noexcept auto& entry = graph.m_entries[m_mapping[idx]]; entry.m_locator.SetPresent(this, idx); } - - // Compute its chunking and store its information in the Entry's m_chunk_feerate. - LinearizationChunking chunking(m_depgraph, m_linearization); - LinearizationIndex lin_idx{0}; - // Iterate over the chunks. - for (unsigned chunk_idx = 0; chunk_idx < chunking.NumChunksLeft(); ++chunk_idx) { - auto chunk = chunking.GetChunk(chunk_idx); - Assume(chunk.transactions.Any()); - // Iterate over the transactions in the linearization, which must match those in chunk. - do { - DepGraphIndex idx = m_linearization[lin_idx++]; - GraphIndex graph_idx = m_mapping[idx]; - auto& entry = graph.m_entries[graph_idx]; - entry.m_chunk_feerate = FeePerWeight::FromFeeFrac(chunk.feerate); - Assume(chunk.transactions[idx]); - chunk.transactions.Reset(idx); - } while(chunk.transactions.Any()); + // If the Cluster's quality is ACCEPTABLE or OPTIMAL, compute its chunking and store its + // information in the Entry's m_chunk_feerate. These fields are only accessed after making + // the entire graph ACCEPTABLE, so it is pointless to compute these if we haven't reached that + // quality level yet. + if (IsAcceptable()) { + LinearizationChunking chunking(m_depgraph, m_linearization); + LinearizationIndex lin_idx{0}; + // Iterate over the chunks. + for (unsigned chunk_idx = 0; chunk_idx < chunking.NumChunksLeft(); ++chunk_idx) { + auto chunk = chunking.GetChunk(chunk_idx); + Assume(chunk.transactions.Any()); + // Iterate over the transactions in the linearization, which must match those in chunk. + do { + DepGraphIndex idx = m_linearization[lin_idx++]; + GraphIndex graph_idx = m_mapping[idx]; + auto& entry = graph.m_entries[graph_idx]; + entry.m_chunk_feerate = FeePerWeight::FromFeeFrac(chunk.feerate); + Assume(chunk.transactions[idx]); + chunk.transactions.Reset(idx); + } while(chunk.transactions.Any()); + } } } @@ -409,8 +413,6 @@ bool Cluster::Split(TxGraphImpl& graph) noexcept // The existing Cluster is an entire component. Leave it be, but update its quality. Assume(todo == m_depgraph.Positions()); graph.SetClusterQuality(m_quality, m_setindex, QualityLevel::NEEDS_RELINEARIZE); - // We need to recompute and cache its chunking. - Updated(graph); return false; } first = false; @@ -1262,12 +1264,12 @@ void Cluster::SanityCheck(const TxGraphImpl& graph) const assert(entry.m_locator.cluster == this); assert(entry.m_locator.index == lin_pos); // Check linearization position and chunk feerate. - if (!linchunking.GetChunk(0).transactions[lin_pos]) { - linchunking.MarkDone(linchunking.GetChunk(0).transactions); - } - assert(entry.m_chunk_feerate == linchunking.GetChunk(0).feerate); - // If this Cluster has an acceptable quality level, its chunks must be connected. if (IsAcceptable()) { + if (!linchunking.GetChunk(0).transactions[lin_pos]) { + linchunking.MarkDone(linchunking.GetChunk(0).transactions); + } + assert(entry.m_chunk_feerate == linchunking.GetChunk(0).feerate); + // If this Cluster has an acceptable quality level, its chunks must be connected. assert(m_depgraph.IsConnected(linchunking.GetChunk(0).transactions)); } }