From d4497738999873c8432d02fd71e14f1afc2065a8 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 31 Jan 2025 16:26:06 -0500 Subject: [PATCH] scripted-diff: (refactor) ClusterIndex -> DepGraphIndex Since cluster_linearize.h does not actually have a Cluster type anymore, it is more appropriate to rename the index type to DepGraphIndex. -BEGIN VERIFY SCRIPT- sed -i 's/Data type to represent transaction indices in clusters./Data type to represent transaction indices in DepGraphs and the clusters they represent./' $(git grep -l 'using ClusterIndex') sed -i 's|\|DepGraphIndex|g' $(git grep -l 'ClusterIndex') -END VERIFY SCRIPT- --- src/bench/cluster_linearize.cpp | 44 ++++----- src/cluster_linearize.h | 132 +++++++++++++-------------- src/test/cluster_linearize_tests.cpp | 4 +- src/test/fuzz/cluster_linearize.cpp | 70 +++++++------- src/test/util/cluster_linearize.h | 36 ++++---- 5 files changed, 143 insertions(+), 143 deletions(-) diff --git a/src/bench/cluster_linearize.cpp b/src/bench/cluster_linearize.cpp index 7d011975dd..cb06f3fc28 100644 --- a/src/bench/cluster_linearize.cpp +++ b/src/bench/cluster_linearize.cpp @@ -23,10 +23,10 @@ namespace { * remaining transaction, whose removal requires updating all remaining transactions' ancestor * set feerates. */ template -DepGraph MakeLinearGraph(ClusterIndex ntx) +DepGraph MakeLinearGraph(DepGraphIndex ntx) { DepGraph depgraph; - for (ClusterIndex i = 0; i < ntx; ++i) { + for (DepGraphIndex i = 0; i < ntx; ++i) { depgraph.AddTransaction({-int32_t(i), 1}); if (i > 0) depgraph.AddDependencies(SetType::Singleton(i - 1), i); } @@ -38,10 +38,10 @@ DepGraph MakeLinearGraph(ClusterIndex ntx) * rechunking is needed after every candidate (the last transaction gets picked every time). */ template -DepGraph MakeWideGraph(ClusterIndex ntx) +DepGraph MakeWideGraph(DepGraphIndex ntx) { DepGraph depgraph; - for (ClusterIndex i = 0; i < ntx; ++i) { + for (DepGraphIndex i = 0; i < ntx; ++i) { depgraph.AddTransaction({int32_t(i) + 1, 1}); if (i > 0) depgraph.AddDependencies(SetType::Singleton(0), i); } @@ -51,10 +51,10 @@ DepGraph MakeWideGraph(ClusterIndex ntx) // Construct a difficult graph. These need at least sqrt(2^(n-1)) iterations in the implemented // algorithm (purely empirically determined). template -DepGraph MakeHardGraph(ClusterIndex ntx) +DepGraph MakeHardGraph(DepGraphIndex ntx) { DepGraph depgraph; - for (ClusterIndex i = 0; i < ntx; ++i) { + for (DepGraphIndex i = 0; i < ntx; ++i) { if (ntx & 1) { // Odd cluster size. // @@ -121,7 +121,7 @@ DepGraph MakeHardGraph(ClusterIndex ntx) * iterations difference. */ template -void BenchLinearizeWorstCase(ClusterIndex ntx, benchmark::Bench& bench, uint64_t iter_limit) +void BenchLinearizeWorstCase(DepGraphIndex ntx, benchmark::Bench& bench, uint64_t iter_limit) { const auto depgraph = MakeHardGraph(ntx); uint64_t rng_seed = 0; @@ -147,12 +147,12 @@ void BenchLinearizeWorstCase(ClusterIndex ntx, benchmark::Bench& bench, uint64_t * cheap. */ template -void BenchLinearizeNoItersWorstCaseAnc(ClusterIndex ntx, benchmark::Bench& bench) +void BenchLinearizeNoItersWorstCaseAnc(DepGraphIndex ntx, benchmark::Bench& bench) { const auto depgraph = MakeLinearGraph(ntx); uint64_t rng_seed = 0; - std::vector old_lin(ntx); - for (ClusterIndex i = 0; i < ntx; ++i) old_lin[i] = i; + std::vector old_lin(ntx); + for (DepGraphIndex i = 0; i < ntx; ++i) old_lin[i] = i; bench.run([&] { Linearize(depgraph, /*max_iterations=*/0, rng_seed++, old_lin); }); @@ -167,41 +167,41 @@ void BenchLinearizeNoItersWorstCaseAnc(ClusterIndex ntx, benchmark::Bench& bench * AncestorCandidateFinder is cheap. */ template -void BenchLinearizeNoItersWorstCaseLIMO(ClusterIndex ntx, benchmark::Bench& bench) +void BenchLinearizeNoItersWorstCaseLIMO(DepGraphIndex ntx, benchmark::Bench& bench) { const auto depgraph = MakeWideGraph(ntx); uint64_t rng_seed = 0; - std::vector old_lin(ntx); - for (ClusterIndex i = 0; i < ntx; ++i) old_lin[i] = i; + std::vector old_lin(ntx); + for (DepGraphIndex i = 0; i < ntx; ++i) old_lin[i] = i; bench.run([&] { Linearize(depgraph, /*max_iterations=*/0, rng_seed++, old_lin); }); } template -void BenchPostLinearizeWorstCase(ClusterIndex ntx, benchmark::Bench& bench) +void BenchPostLinearizeWorstCase(DepGraphIndex ntx, benchmark::Bench& bench) { DepGraph depgraph = MakeWideGraph(ntx); - std::vector lin(ntx); + std::vector lin(ntx); bench.run([&] { - for (ClusterIndex i = 0; i < ntx; ++i) lin[i] = i; + for (DepGraphIndex i = 0; i < ntx; ++i) lin[i] = i; PostLinearize(depgraph, lin); }); } template -void BenchMergeLinearizationsWorstCase(ClusterIndex ntx, benchmark::Bench& bench) +void BenchMergeLinearizationsWorstCase(DepGraphIndex ntx, benchmark::Bench& bench) { DepGraph depgraph; - for (ClusterIndex i = 0; i < ntx; ++i) { + for (DepGraphIndex i = 0; i < ntx; ++i) { depgraph.AddTransaction({i, 1}); if (i) depgraph.AddDependencies(SetType::Singleton(0), i); } - std::vector lin1; - std::vector lin2; + std::vector lin1; + std::vector lin2; lin1.push_back(0); lin2.push_back(0); - for (ClusterIndex i = 1; i < ntx; ++i) { + for (DepGraphIndex i = 1; i < ntx; ++i) { lin1.push_back(i); lin2.push_back(ntx - i); } @@ -214,7 +214,7 @@ template void BenchLinearizeOptimally(benchmark::Bench& bench, const std::array& serialized) { // Determine how many transactions the serialized cluster has. - ClusterIndex num_tx{0}; + DepGraphIndex num_tx{0}; { SpanReader reader{serialized}; DepGraph> depgraph; diff --git a/src/cluster_linearize.h b/src/cluster_linearize.h index 28dde840ef..b01daedf4b 100644 --- a/src/cluster_linearize.h +++ b/src/cluster_linearize.h @@ -19,8 +19,8 @@ namespace cluster_linearize { -/** Data type to represent transaction indices in clusters. */ -using ClusterIndex = uint32_t; +/** Data type to represent transaction indices in DepGraphs and the clusters they represent. */ +using DepGraphIndex = uint32_t; /** Data structure that holds a transaction graph's preprocessed data (fee, size, ancestors, * descendants). */ @@ -86,11 +86,11 @@ public: * * Complexity: O(N^2) where N=depgraph.TxCount(). */ - DepGraph(const DepGraph& depgraph, std::span mapping, ClusterIndex pos_range) noexcept : entries(pos_range) + DepGraph(const DepGraph& depgraph, std::span mapping, DepGraphIndex pos_range) noexcept : entries(pos_range) { Assume(mapping.size() == depgraph.PositionRange()); Assume((pos_range == 0) == (depgraph.TxCount() == 0)); - for (ClusterIndex i : depgraph.Positions()) { + for (DepGraphIndex i : depgraph.Positions()) { auto new_idx = mapping[i]; Assume(new_idx < pos_range); // Add transaction. @@ -100,7 +100,7 @@ public: // Fill in fee and size. entries[new_idx].feerate = depgraph.entries[i].feerate; } - for (ClusterIndex i : depgraph.Positions()) { + for (DepGraphIndex i : depgraph.Positions()) { // Fill in dependencies by mapping direct parents. SetType parents; for (auto j : depgraph.GetReducedParents(i)) parents.Set(mapping[j]); @@ -113,29 +113,29 @@ public: /** Get the set of transactions positions in use. Complexity: O(1). */ const SetType& Positions() const noexcept { return m_used; } /** Get the range of positions in this DepGraph. All entries in Positions() are in [0, PositionRange() - 1]. */ - ClusterIndex PositionRange() const noexcept { return entries.size(); } + DepGraphIndex PositionRange() const noexcept { return entries.size(); } /** Get the number of transactions in the graph. Complexity: O(1). */ auto TxCount() const noexcept { return m_used.Count(); } /** Get the feerate of a given transaction i. Complexity: O(1). */ - const FeeFrac& FeeRate(ClusterIndex i) const noexcept { return entries[i].feerate; } + const FeeFrac& FeeRate(DepGraphIndex i) const noexcept { return entries[i].feerate; } /** Get the mutable feerate of a given transaction i. Complexity: O(1). */ - FeeFrac& FeeRate(ClusterIndex i) noexcept { return entries[i].feerate; } + FeeFrac& FeeRate(DepGraphIndex i) noexcept { return entries[i].feerate; } /** Get the ancestors of a given transaction i. Complexity: O(1). */ - const SetType& Ancestors(ClusterIndex i) const noexcept { return entries[i].ancestors; } + const SetType& Ancestors(DepGraphIndex i) const noexcept { return entries[i].ancestors; } /** Get the descendants of a given transaction i. Complexity: O(1). */ - const SetType& Descendants(ClusterIndex i) const noexcept { return entries[i].descendants; } + const SetType& Descendants(DepGraphIndex i) const noexcept { return entries[i].descendants; } /** Add a new unconnected transaction to this transaction graph (in the first available - * position), and return its ClusterIndex. + * position), and return its DepGraphIndex. * * Complexity: O(1) (amortized, due to resizing of backing vector). */ - ClusterIndex AddTransaction(const FeeFrac& feefrac) noexcept + DepGraphIndex AddTransaction(const FeeFrac& feefrac) noexcept { static constexpr auto ALL_POSITIONS = SetType::Fill(SetType::Size()); auto available = ALL_POSITIONS - m_used; Assume(available.Any()); - ClusterIndex new_idx = available.First(); + DepGraphIndex new_idx = available.First(); if (new_idx == entries.size()) { entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx)); } else { @@ -174,7 +174,7 @@ public: * * Complexity: O(N) where N=TxCount(). */ - void AddDependencies(const SetType& parents, ClusterIndex child) noexcept + void AddDependencies(const SetType& parents, DepGraphIndex child) noexcept { Assume(m_used[child]); Assume(parents.IsSubsetOf(m_used)); @@ -205,7 +205,7 @@ public: * * Complexity: O(N) where N=Ancestors(i).Count() (which is bounded by TxCount()). */ - SetType GetReducedParents(ClusterIndex i) const noexcept + SetType GetReducedParents(DepGraphIndex i) const noexcept { SetType parents = Ancestors(i); parents.Reset(i); @@ -226,7 +226,7 @@ public: * * Complexity: O(N) where N=Descendants(i).Count() (which is bounded by TxCount()). */ - SetType GetReducedChildren(ClusterIndex i) const noexcept + SetType GetReducedChildren(DepGraphIndex i) const noexcept { SetType children = Descendants(i); children.Reset(i); @@ -298,11 +298,11 @@ public: * * Complexity: O(select.Count() * log(select.Count())). */ - void AppendTopo(std::vector& list, const SetType& select) const noexcept + void AppendTopo(std::vector& list, const SetType& select) const noexcept { - ClusterIndex old_len = list.size(); + DepGraphIndex old_len = list.size(); for (auto i : select) list.push_back(i); - std::sort(list.begin() + old_len, list.end(), [&](ClusterIndex a, ClusterIndex b) noexcept { + std::sort(list.begin() + old_len, list.end(), [&](DepGraphIndex a, DepGraphIndex b) noexcept { const auto a_anc_count = entries[a].ancestors.Count(); const auto b_anc_count = entries[b].ancestors.Count(); if (a_anc_count != b_anc_count) return a_anc_count < b_anc_count; @@ -338,7 +338,7 @@ struct SetInfo SetInfo(const SetType& txn, const FeeFrac& fr) noexcept : transactions(txn), feerate(fr) {} /** Construct a SetInfo for a given transaction in a depgraph. */ - explicit SetInfo(const DepGraph& depgraph, ClusterIndex pos) noexcept : + explicit SetInfo(const DepGraph& depgraph, DepGraphIndex pos) noexcept : transactions(SetType::Singleton(pos)), feerate(depgraph.FeeRate(pos)) {} /** Construct a SetInfo for a set of transactions in a depgraph. */ @@ -346,7 +346,7 @@ struct SetInfo transactions(txn), feerate(depgraph.FeeRate(txn)) {} /** Add a transaction to this SetInfo (which must not yet be in it). */ - void Set(const DepGraph& depgraph, ClusterIndex pos) noexcept + void Set(const DepGraph& depgraph, DepGraphIndex pos) noexcept { Assume(!transactions[pos]); transactions.Set(pos); @@ -382,10 +382,10 @@ struct SetInfo /** Compute the feerates of the chunks of linearization. */ template -std::vector ChunkLinearization(const DepGraph& depgraph, std::span linearization) noexcept +std::vector ChunkLinearization(const DepGraph& depgraph, std::span linearization) noexcept { std::vector ret; - for (ClusterIndex i : linearization) { + for (DepGraphIndex i : linearization) { /** The new chunk to be added, initially a singleton. */ auto new_chunk = depgraph.FeeRate(i); // As long as the new chunk has a higher feerate than the last chunk so far, absorb it. @@ -407,13 +407,13 @@ class LinearizationChunking const DepGraph& m_depgraph; /** The linearization we started from, possibly with removed prefix stripped. */ - std::span m_linearization; + std::span m_linearization; /** Chunk sets and their feerates, of what remains of the linearization. */ std::vector> m_chunks; /** How large a prefix of m_chunks corresponds to removed transactions. */ - ClusterIndex m_chunks_skip{0}; + DepGraphIndex m_chunks_skip{0}; /** Which transactions remain in the linearization. */ SetType m_todo; @@ -448,7 +448,7 @@ class LinearizationChunking public: /** Initialize a LinearizationSubset object for a given length of linearization. */ - explicit LinearizationChunking(const DepGraph& depgraph LIFETIMEBOUND, std::span lin LIFETIMEBOUND) noexcept : + explicit LinearizationChunking(const DepGraph& depgraph LIFETIMEBOUND, std::span lin LIFETIMEBOUND) noexcept : m_depgraph(depgraph), m_linearization(lin) { // Mark everything in lin as todo still. @@ -459,10 +459,10 @@ public: } /** Determine how many chunks remain in the linearization. */ - ClusterIndex NumChunksLeft() const noexcept { return m_chunks.size() - m_chunks_skip; } + DepGraphIndex NumChunksLeft() const noexcept { return m_chunks.size() - m_chunks_skip; } /** Access a chunk. Chunk 0 is the highest-feerate prefix of what remains. */ - const SetInfo& GetChunk(ClusterIndex n) const noexcept + const SetInfo& GetChunk(DepGraphIndex n) const noexcept { Assume(n + m_chunks_skip < m_chunks.size()); return m_chunks[n + m_chunks_skip]; @@ -505,7 +505,7 @@ public: Assume(subset.transactions.IsSubsetOf(m_todo)); SetInfo accumulator; // Iterate over all chunks of the remaining linearization. - for (ClusterIndex i = 0; i < NumChunksLeft(); ++i) { + for (DepGraphIndex i = 0; i < NumChunksLeft(); ++i) { // Find what (if any) intersection the chunk has with subset. const SetType to_add = GetChunk(i).transactions & subset.transactions; if (to_add.Any()) { @@ -557,13 +557,13 @@ public: m_ancestor_set_feerates(depgraph.PositionRange()) { // Precompute ancestor-set feerates. - for (ClusterIndex i : m_depgraph.Positions()) { + for (DepGraphIndex i : m_depgraph.Positions()) { /** The remaining ancestors for transaction i. */ SetType anc_to_add = m_depgraph.Ancestors(i); FeeFrac anc_feerate; // Reuse accumulated feerate from first ancestor, if usable. Assume(anc_to_add.Any()); - ClusterIndex first = anc_to_add.First(); + DepGraphIndex first = anc_to_add.First(); if (first < i) { anc_feerate = m_ancestor_set_feerates[first]; Assume(!anc_feerate.IsEmpty()); @@ -603,7 +603,7 @@ public: } /** Count the number of remaining unlinearized transactions. */ - ClusterIndex NumRemaining() const noexcept + DepGraphIndex NumRemaining() const noexcept { return m_todo.Count(); } @@ -616,7 +616,7 @@ public: SetInfo FindCandidateSet() const noexcept { Assume(!AllDone()); - std::optional best; + std::optional best; for (auto i : m_todo) { if (best.has_value()) { Assume(!m_ancestor_set_feerates[i].IsEmpty()); @@ -644,9 +644,9 @@ class SearchCandidateFinder /** Internal RNG. */ InsecureRandomContext m_rng; /** m_sorted_to_original[i] is the original position that sorted transaction position i had. */ - std::vector m_sorted_to_original; + std::vector m_sorted_to_original; /** m_original_to_sorted[i] is the sorted position original transaction position i has. */ - std::vector m_original_to_sorted; + std::vector m_original_to_sorted; /** Internal dependency graph for the cluster (with transactions in decreasing individual * feerate order). */ DepGraph m_sorted_depgraph; @@ -684,7 +684,7 @@ public: { // Determine reordering mapping, by sorting by decreasing feerate. Unused positions are // not included, as they will never be looked up anyway. - ClusterIndex sorted_pos{0}; + DepGraphIndex sorted_pos{0}; for (auto i : depgraph.Positions()) { m_sorted_to_original[sorted_pos++] = i; } @@ -694,7 +694,7 @@ public: return feerate_cmp > 0; }); // Compute reverse mapping. - for (ClusterIndex i = 0; i < m_sorted_to_original.size(); ++i) { + for (DepGraphIndex i = 0; i < m_sorted_to_original.size(); ++i) { m_original_to_sorted[m_sorted_to_original[i]] = i; } // Compute reordered dependency graph. @@ -793,7 +793,7 @@ public: /** The set of transactions in m_todo which have feerate > best's. */ SetType imp = m_todo; while (imp.Any()) { - ClusterIndex check = imp.Last(); + DepGraphIndex check = imp.Last(); if (m_sorted_depgraph.FeeRate(check) >> best.feerate) break; imp.Reset(check); } @@ -850,7 +850,7 @@ public: best = inc; // See if we can remove any entries from imp now. while (imp.Any()) { - ClusterIndex check = imp.Last(); + DepGraphIndex check = imp.Last(); if (m_sorted_depgraph.FeeRate(check) >> best.feerate) break; imp.Reset(check); } @@ -891,7 +891,7 @@ public: // If pot is empty, then so is inc. Assume(elem.inc.feerate.IsEmpty() == elem.pot_feerate.IsEmpty()); - const ClusterIndex first = elem.und.First(); + const DepGraphIndex first = elem.und.First(); if (!elem.inc.feerate.IsEmpty()) { // If no undecided transactions remain with feerate higher than best, this entry // cannot be improved beyond best. @@ -917,17 +917,17 @@ public: // most. Let I(t) be the size of the undecided set after including t, and E(t) the size // of the undecided set after excluding t. Then choose the split transaction t such // that 2^I(t) + 2^E(t) is minimal, tie-breaking by highest individual feerate for t. - ClusterIndex split = 0; + DepGraphIndex split = 0; const auto select = elem.und & m_sorted_depgraph.Ancestors(first); Assume(select.Any()); - std::optional> split_counts; + std::optional> split_counts; for (auto t : select) { // Call max = max(I(t), E(t)) and min = min(I(t), E(t)). Let counts = {max,min}. // Sorting by the tuple counts is equivalent to sorting by 2^I(t) + 2^E(t). This // expression is equal to 2^max + 2^min = 2^max * (1 + 1/2^(max - min)). The second // factor (1 + 1/2^(max - min)) there is in (1,2]. Thus increasing max will always // increase it, even when min decreases. Because of this, we can first sort by max. - std::pair counts{ + std::pair counts{ (elem.und - m_sorted_depgraph.Ancestors(t)).Count(), (elem.und - m_sorted_depgraph.Descendants(t)).Count()}; if (counts.first < counts.second) std::swap(counts.first, counts.second); @@ -1027,13 +1027,13 @@ public: * Complexity: possibly O(N * min(max_iterations + N, sqrt(2^N))) where N=depgraph.TxCount(). */ template -std::pair, bool> Linearize(const DepGraph& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span old_linearization = {}) noexcept +std::pair, bool> Linearize(const DepGraph& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span old_linearization = {}) noexcept { Assume(old_linearization.empty() || old_linearization.size() == depgraph.TxCount()); if (depgraph.TxCount() == 0) return {{}, true}; uint64_t iterations_left = max_iterations; - std::vector linearization; + std::vector linearization; AncestorCandidateFinder anc_finder(depgraph); std::optional> src_finder; @@ -1121,7 +1121,7 @@ std::pair, bool> Linearize(const DepGraph& de * postlinearize" process. */ template -void PostLinearize(const DepGraph& depgraph, std::span linearization) +void PostLinearize(const DepGraph& depgraph, std::span linearization) { // This algorithm performs a number of passes (currently 2); the even ones operate from back to // front, the odd ones from front to back. Each results in an equal-or-better linearization @@ -1159,9 +1159,9 @@ void PostLinearize(const DepGraph& depgraph, std::span li // entries[0]. /** Index of the sentinel in the entries array below. */ - static constexpr ClusterIndex SENTINEL{0}; + static constexpr DepGraphIndex SENTINEL{0}; /** Indicator that a group has no previous transaction. */ - static constexpr ClusterIndex NO_PREV_TX{0}; + static constexpr DepGraphIndex NO_PREV_TX{0}; /** Data structure per transaction entry. */ @@ -1169,16 +1169,16 @@ void PostLinearize(const DepGraph& depgraph, std::span li { /** The index of the previous transaction in this group; NO_PREV_TX if this is the first * entry of a group. */ - ClusterIndex prev_tx; + DepGraphIndex prev_tx; // The fields below are only used for transactions that are the last one in a group // (referred to as tail transactions below). /** Index of the first transaction in this group, possibly itself. */ - ClusterIndex first_tx; + DepGraphIndex first_tx; /** Index of the last transaction in the previous group. The first group (the sentinel) * points back to the last group here, making it a singly-linked circular list. */ - ClusterIndex prev_group; + DepGraphIndex prev_group; /** All transactions in the group. Empty for the sentinel. */ SetType group; /** All dependencies of the group (descendants in even passes; ancestors in odd ones). */ @@ -1221,12 +1221,12 @@ void PostLinearize(const DepGraph& depgraph, std::span li Assume(entries[SENTINEL].feerate.IsEmpty()); // Iterate over all elements in the existing linearization. - for (ClusterIndex i = 0; i < linearization.size(); ++i) { + for (DepGraphIndex i = 0; i < linearization.size(); ++i) { // Even passes are from back to front; odd passes from front to back. - ClusterIndex idx = linearization[rev ? linearization.size() - 1 - i : i]; + DepGraphIndex idx = linearization[rev ? linearization.size() - 1 - i : i]; // Construct a new group containing just idx. In even passes, the meaning of // parent/child and high/low feerate are swapped. - ClusterIndex cur_group = idx + 1; + DepGraphIndex cur_group = idx + 1; entries[cur_group].group = SetType::Singleton(idx); entries[cur_group].deps = rev ? depgraph.Descendants(idx): depgraph.Ancestors(idx); entries[cur_group].feerate = depgraph.FeeRate(idx); @@ -1238,8 +1238,8 @@ void PostLinearize(const DepGraph& depgraph, std::span li entries[SENTINEL].prev_group = cur_group; // Start merge/swap cycle. - ClusterIndex next_group = SENTINEL; // We inserted at the end, so next group is sentinel. - ClusterIndex prev_group = entries[cur_group].prev_group; + DepGraphIndex next_group = SENTINEL; // We inserted at the end, so next group is sentinel. + DepGraphIndex prev_group = entries[cur_group].prev_group; // Continue as long as the current group has higher feerate than the previous one. while (entries[cur_group].feerate >> entries[prev_group].feerate) { // prev_group/cur_group/next_group refer to (the last transactions of) 3 @@ -1267,7 +1267,7 @@ void PostLinearize(const DepGraph& depgraph, std::span li entries[cur_group].prev_group = prev_group; } else { // There is no dependency between cur_group and prev_group; swap them. - ClusterIndex preprev_group = entries[prev_group].prev_group; + DepGraphIndex preprev_group = entries[prev_group].prev_group; // If PP, P, C, N were the old preprev, prev, cur, next groups, then the new // layout becomes [PP, C, P, N]. Update prev_groups to reflect that order. entries[next_group].prev_group = prev_group; @@ -1282,10 +1282,10 @@ void PostLinearize(const DepGraph& depgraph, std::span li } // Convert the entries back to linearization (overwriting the existing one). - ClusterIndex cur_group = entries[0].prev_group; - ClusterIndex done = 0; + DepGraphIndex cur_group = entries[0].prev_group; + DepGraphIndex done = 0; while (cur_group != SENTINEL) { - ClusterIndex cur_tx = cur_group; + DepGraphIndex cur_tx = cur_group; // Traverse the transactions of cur_group (from back to front), and write them in the // same order during odd passes, and reversed (front to back) in even passes. if (rev) { @@ -1310,7 +1310,7 @@ void PostLinearize(const DepGraph& depgraph, std::span li * Complexity: O(N^2) where N=depgraph.TxCount(); O(N) if both inputs are identical. */ template -std::vector MergeLinearizations(const DepGraph& depgraph, std::span lin1, std::span lin2) +std::vector MergeLinearizations(const DepGraph& depgraph, std::span lin1, std::span lin2) { Assume(lin1.size() == depgraph.TxCount()); Assume(lin2.size() == depgraph.TxCount()); @@ -1318,7 +1318,7 @@ std::vector MergeLinearizations(const DepGraph& depgraph, /** Chunkings of what remains of both input linearizations. */ LinearizationChunking chunking1(depgraph, lin1), chunking2(depgraph, lin2); /** Output linearization. */ - std::vector ret; + std::vector ret; if (depgraph.TxCount() == 0) return ret; ret.reserve(depgraph.TxCount()); @@ -1349,18 +1349,18 @@ std::vector MergeLinearizations(const DepGraph& depgraph, /** Make linearization topological, retaining its ordering where possible. */ template -void FixLinearization(const DepGraph& depgraph, std::span linearization) noexcept +void FixLinearization(const DepGraph& depgraph, std::span linearization) noexcept { // This algorithm can be summarized as moving every element in the linearization backwards // until it is placed after all its ancestors. SetType done; const auto len = linearization.size(); // Iterate over the elements of linearization from back to front (i is distance from back). - for (ClusterIndex i = 0; i < len; ++i) { + for (DepGraphIndex i = 0; i < len; ++i) { /** The element at that position. */ - ClusterIndex elem = linearization[len - 1 - i]; + DepGraphIndex elem = linearization[len - 1 - i]; /** j represents how far from the back of the linearization elem should be placed. */ - ClusterIndex j = i; + DepGraphIndex j = i; // Figure out which elements need to be moved before elem. SetType place_before = done & depgraph.Ancestors(elem); // Find which position to place elem in (updating j), continuously moving the elements diff --git a/src/test/cluster_linearize_tests.cpp b/src/test/cluster_linearize_tests.cpp index 265ccdc805..3413af4a21 100644 --- a/src/test/cluster_linearize_tests.cpp +++ b/src/test/cluster_linearize_tests.cpp @@ -28,11 +28,11 @@ void TestDepGraphSerialization(const std::vector>& c // Construct DepGraph from cluster argument. DepGraph depgraph; SetType holes; - for (ClusterIndex i = 0; i < cluster.size(); ++i) { + for (DepGraphIndex i = 0; i < cluster.size(); ++i) { depgraph.AddTransaction(cluster[i].first); if (cluster[i] == HOLE) holes.Set(i); } - for (ClusterIndex i = 0; i < cluster.size(); ++i) { + for (DepGraphIndex i = 0; i < cluster.size(); ++i) { depgraph.AddDependencies(cluster[i].second, i); } depgraph.RemoveTransactions(holes); diff --git a/src/test/fuzz/cluster_linearize.cpp b/src/test/fuzz/cluster_linearize.cpp index f5c0c897c9..c7e40a833d 100644 --- a/src/test/fuzz/cluster_linearize.cpp +++ b/src/test/fuzz/cluster_linearize.cpp @@ -149,9 +149,9 @@ public: * than AncestorCandidateFinder and SearchCandidateFinder. */ template -std::pair, bool> SimpleLinearize(const DepGraph& depgraph, uint64_t max_iterations) +std::pair, bool> SimpleLinearize(const DepGraph& depgraph, uint64_t max_iterations) { - std::vector linearization; + std::vector linearization; SimpleCandidateFinder finder(depgraph); SetType todo = depgraph.Positions(); bool optimal = true; @@ -203,9 +203,9 @@ SetType ReadTopologicalSet(const DepGraph& depgraph, const SetType& tod /** Given a dependency graph, construct any valid linearization for it, reading from a SpanReader. */ template -std::vector ReadLinearization(const DepGraph& depgraph, SpanReader& reader) +std::vector ReadLinearization(const DepGraph& depgraph, SpanReader& reader) { - std::vector linearization; + std::vector linearization; TestBitSet todo = depgraph.Positions(); // In every iteration one topologically-valid transaction is appended to linearization. while (todo.Any()) { @@ -253,18 +253,18 @@ FUZZ_TARGET(clusterlin_depgraph_sim) * sim[i]->first is its individual feerate, and sim[i]->second is its set of ancestors. */ std::array>, TestBitSet::Size()> sim; /** The number of non-nullopt position in sim. */ - ClusterIndex num_tx_sim{0}; + DepGraphIndex num_tx_sim{0}; /** Read a valid index of a transaction from the provider. */ auto idx_fn = [&]() { - auto offset = provider.ConsumeIntegralInRange(0, num_tx_sim - 1); - for (ClusterIndex i = 0; i < sim.size(); ++i) { + auto offset = provider.ConsumeIntegralInRange(0, num_tx_sim - 1); + for (DepGraphIndex i = 0; i < sim.size(); ++i) { if (!sim[i].has_value()) continue; if (offset == 0) return i; --offset; } assert(false); - return ClusterIndex(-1); + return DepGraphIndex(-1); }; /** Read a valid subset of the transactions from the provider. */ @@ -273,7 +273,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) const auto mask = provider.ConsumeIntegralInRange(0, range); auto mask_shifted = mask; TestBitSet subset; - for (ClusterIndex i = 0; i < sim.size(); ++i) { + for (DepGraphIndex i = 0; i < sim.size(); ++i) { if (!sim[i].has_value()) continue; if (mask_shifted & 1) { subset.Set(i); @@ -289,7 +289,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) auto range = (uint64_t{1} << sim.size()) - 1; const auto mask = provider.ConsumeIntegralInRange(0, range); TestBitSet set; - for (ClusterIndex i = 0; i < sim.size(); ++i) { + for (DepGraphIndex i = 0; i < sim.size(); ++i) { if ((mask >> i) & 1) { set.Set(i); } @@ -301,7 +301,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) auto anc_update_fn = [&]() { while (true) { bool updates{false}; - for (ClusterIndex chl = 0; chl < sim.size(); ++chl) { + for (DepGraphIndex chl = 0; chl < sim.size(); ++chl) { if (!sim[chl].has_value()) continue; for (auto par : sim[chl]->second) { if (!sim[chl]->second.IsSupersetOf(sim[par]->second)) { @@ -315,7 +315,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) }; /** Compare the state of transaction i in the simulation with the real one. */ - auto check_fn = [&](ClusterIndex i) { + auto check_fn = [&](DepGraphIndex i) { // Compare used positions. assert(real.Positions()[i] == sim[i].has_value()); if (sim[i].has_value()) { @@ -338,7 +338,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) auto idx = real.AddTransaction(feerate); // Verify that the returned index is correct. assert(!sim[idx].has_value()); - for (ClusterIndex i = 0; i < TestBitSet::Size(); ++i) { + for (DepGraphIndex i = 0; i < TestBitSet::Size(); ++i) { if (!sim[i].has_value()) { assert(idx == i); break; @@ -351,7 +351,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) } if ((command % 3) <= 1 && num_tx_sim > 0) { // AddDependencies. - ClusterIndex child = idx_fn(); + DepGraphIndex child = idx_fn(); auto parents = subset_fn(); // Apply to DepGraph. real.AddDependencies(parents, child); @@ -370,7 +370,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) // Apply to DepGraph. real.RemoveTransactions(del); // Apply to sim. - for (ClusterIndex i = 0; i < sim.size(); ++i) { + for (DepGraphIndex i = 0; i < sim.size(); ++i) { if (sim[i].has_value()) { if (del[i]) { --num_tx_sim; @@ -388,7 +388,7 @@ FUZZ_TARGET(clusterlin_depgraph_sim) // Compare the real obtained depgraph against the simulation. anc_update_fn(); - for (ClusterIndex i = 0; i < sim.size(); ++i) check_fn(i); + for (DepGraphIndex i = 0; i < sim.size(); ++i) check_fn(i); assert(real.TxCount() == num_tx_sim); // Sanity check the result (which includes round-tripping serialization, if applicable). SanityCheck(real); @@ -401,7 +401,7 @@ FUZZ_TARGET(clusterlin_depgraph_serialization) // Construct a graph by deserializing. SpanReader reader(buffer); DepGraph depgraph; - ClusterIndex par_code{0}, chl_code{0}; + DepGraphIndex par_code{0}, chl_code{0}; try { reader >> Using(depgraph) >> VARINT(par_code) >> VARINT(chl_code); } catch (const std::ios_base::failure&) {} @@ -412,7 +412,7 @@ FUZZ_TARGET(clusterlin_depgraph_serialization) // Introduce a cycle, and then test that IsAcyclic returns false. if (depgraph.TxCount() < 2) return; - ClusterIndex par(0), chl(0); + DepGraphIndex par(0), chl(0); // Pick any transaction of depgraph as parent. par_code %= depgraph.TxCount(); for (auto i : depgraph.Positions()) { @@ -498,7 +498,7 @@ FUZZ_TARGET(clusterlin_components) reader >> VARINT(subset_bits); } catch (const std::ios_base::failure&) {} TestBitSet subset; - for (ClusterIndex i : depgraph.Positions()) { + for (DepGraphIndex i : depgraph.Positions()) { if (todo[i]) { if (subset_bits & 1) subset.Set(i); subset_bits >>= 1; @@ -555,7 +555,7 @@ FUZZ_TARGET(clusterlin_chunking) for (const auto& chunk_feerate : chunking) { assert(todo.Any()); SetInfo accumulator, best; - for (ClusterIndex idx : linearization) { + for (DepGraphIndex idx : linearization) { if (todo[idx]) { accumulator.Set(depgraph, idx); if (best.feerate.IsEmpty() || accumulator.feerate >> best.feerate) { @@ -766,7 +766,7 @@ FUZZ_TARGET(clusterlin_linearization_chunking) assert(chunking.NumChunksLeft() > 0); // Construct linearization with just todo. - std::vector linearization_left; + std::vector linearization_left; for (auto i : linearization) { if (todo[i]) linearization_left.push_back(i); } @@ -776,13 +776,13 @@ FUZZ_TARGET(clusterlin_linearization_chunking) // Verify that it matches the feerates of the chunks of chunking. assert(chunking.NumChunksLeft() == chunking_left.size()); - for (ClusterIndex i = 0; i < chunking.NumChunksLeft(); ++i) { + for (DepGraphIndex i = 0; i < chunking.NumChunksLeft(); ++i) { assert(chunking.GetChunk(i).feerate == chunking_left[i]); } // Check consistency of chunking. TestBitSet combined; - for (ClusterIndex i = 0; i < chunking.NumChunksLeft(); ++i) { + for (DepGraphIndex i = 0; i < chunking.NumChunksLeft(); ++i) { const auto& chunk_info = chunking.GetChunk(i); // Chunks must be non-empty. assert(chunk_info.transactions.Any()); @@ -833,7 +833,7 @@ FUZZ_TARGET(clusterlin_linearization_chunking) // - No non-empty intersection between the intersection and a prefix of the chunks of the // remainder of the linearization may be better than the intersection. TestBitSet prefix; - for (ClusterIndex i = 0; i < chunking.NumChunksLeft(); ++i) { + for (DepGraphIndex i = 0; i < chunking.NumChunksLeft(); ++i) { prefix |= chunking.GetChunk(i).transactions; auto reintersect = SetInfo(depgraph, prefix & intersect.transactions); if (!reintersect.feerate.IsEmpty()) { @@ -875,7 +875,7 @@ FUZZ_TARGET(clusterlin_linearize) if (make_connected) MakeConnected(depgraph); // Optionally construct an old linearization for it. - std::vector old_linearization; + std::vector old_linearization; { uint8_t have_old_linearization{0}; try { @@ -934,8 +934,8 @@ FUZZ_TARGET(clusterlin_linearize) // Only for very small clusters, test every topologically-valid permutation. if (depgraph.TxCount() <= 7) { - std::vector perm_linearization; - for (ClusterIndex i : depgraph.Positions()) perm_linearization.push_back(i); + std::vector perm_linearization; + for (DepGraphIndex i : depgraph.Positions()) perm_linearization.push_back(i); // Iterate over all valid permutations. do { // Determine whether perm_linearization is topological. @@ -971,7 +971,7 @@ FUZZ_TARGET(clusterlin_postlinearize) } catch (const std::ios_base::failure&) {} // Retrieve a linearization from the fuzz input. - std::vector linearization; + std::vector linearization; linearization = ReadLinearization(depgraph, reader); SanityCheck(depgraph, linearization); @@ -1019,7 +1019,7 @@ FUZZ_TARGET(clusterlin_postlinearize_tree) // Now construct a new graph, copying the nodes, but leaving only the first parent (even // direction) or the first child (odd direction). DepGraph depgraph_tree; - for (ClusterIndex i = 0; i < depgraph_gen.PositionRange(); ++i) { + for (DepGraphIndex i = 0; i < depgraph_gen.PositionRange(); ++i) { if (depgraph_gen.Positions()[i]) { depgraph_tree.AddTransaction(depgraph_gen.FeeRate(i)); } else { @@ -1031,14 +1031,14 @@ FUZZ_TARGET(clusterlin_postlinearize_tree) depgraph_tree.RemoveTransactions(TestBitSet::Fill(depgraph_gen.PositionRange()) - depgraph_gen.Positions()); if (direction & 1) { - for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) { + for (DepGraphIndex i = 0; i < depgraph_gen.TxCount(); ++i) { auto children = depgraph_gen.GetReducedChildren(i); if (children.Any()) { depgraph_tree.AddDependencies(TestBitSet::Singleton(i), children.First()); } } } else { - for (ClusterIndex i = 0; i < depgraph_gen.TxCount(); ++i) { + for (DepGraphIndex i = 0; i < depgraph_gen.TxCount(); ++i) { auto parents = depgraph_gen.GetReducedParents(i); if (parents.Any()) { depgraph_tree.AddDependencies(TestBitSet::Singleton(parents.First()), i); @@ -1047,7 +1047,7 @@ FUZZ_TARGET(clusterlin_postlinearize_tree) } // Retrieve a linearization from the fuzz input. - std::vector linearization; + std::vector linearization; linearization = ReadLinearization(depgraph_tree, reader); SanityCheck(depgraph_tree, linearization); @@ -1104,7 +1104,7 @@ FUZZ_TARGET(clusterlin_postlinearize_moved_leaf) // Construct a linearization identical to lin, but with the tail end of lin_leaf moved to the // back. - std::vector lin_moved; + std::vector lin_moved; for (auto i : lin) { if (i != lin_leaf.back()) lin_moved.push_back(i); } @@ -1160,7 +1160,7 @@ FUZZ_TARGET(clusterlin_fix_linearization) } catch (const std::ios_base::failure&) {} // Construct an arbitrary linearization (not necessarily topological for depgraph). - std::vector linearization; + std::vector linearization; /** Which transactions of depgraph are yet to be included in linearization. */ TestBitSet todo = depgraph.Positions(); while (todo.Any()) { @@ -1188,7 +1188,7 @@ FUZZ_TARGET(clusterlin_fix_linearization) size_t topo_prefix = 0; todo = depgraph.Positions(); while (topo_prefix < linearization.size()) { - ClusterIndex idx = linearization[topo_prefix]; + DepGraphIndex idx = linearization[topo_prefix]; todo.Reset(idx); if (todo.Overlaps(depgraph.Ancestors(idx))) break; ++topo_prefix; diff --git a/src/test/util/cluster_linearize.h b/src/test/util/cluster_linearize.h index 3db51a6b80..fa7945aac6 100644 --- a/src/test/util/cluster_linearize.h +++ b/src/test/util/cluster_linearize.h @@ -122,10 +122,10 @@ struct DepGraphFormatter static void Ser(Stream& s, const DepGraph& depgraph) { /** Construct a topological order to serialize the transactions in. */ - std::vector topo_order; + std::vector topo_order; topo_order.reserve(depgraph.TxCount()); for (auto i : depgraph.Positions()) topo_order.push_back(i); - std::sort(topo_order.begin(), topo_order.end(), [&](ClusterIndex a, ClusterIndex b) { + std::sort(topo_order.begin(), topo_order.end(), [&](DepGraphIndex a, DepGraphIndex b) { auto anc_a = depgraph.Ancestors(a).Count(), anc_b = depgraph.Ancestors(b).Count(); if (anc_a != anc_b) return anc_a < anc_b; return a < b; @@ -136,9 +136,9 @@ struct DepGraphFormatter SetType done; // Loop over the transactions in topological order. - for (ClusterIndex topo_idx = 0; topo_idx < topo_order.size(); ++topo_idx) { + for (DepGraphIndex topo_idx = 0; topo_idx < topo_order.size(); ++topo_idx) { /** Which depgraph index we are currently writing. */ - ClusterIndex idx = topo_order[topo_idx]; + DepGraphIndex idx = topo_order[topo_idx]; // Write size, which must be larger than 0. s << VARINT_MODE(depgraph.FeeRate(idx).size, VarIntMode::NONNEGATIVE_SIGNED); // Write fee, encoded as an unsigned varint (odd=negative, even=non-negative). @@ -146,9 +146,9 @@ struct DepGraphFormatter // Write dependency information. SetType written_parents; uint64_t diff = 0; //!< How many potential parent/child relations we have skipped over. - for (ClusterIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) { + for (DepGraphIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) { /** Which depgraph index we are currently considering as parent of idx. */ - ClusterIndex dep_idx = topo_order[topo_idx - 1 - dep_dist]; + DepGraphIndex dep_idx = topo_order[topo_idx - 1 - dep_dist]; // Ignore transactions which are already known to be ancestors. if (depgraph.Descendants(dep_idx).Overlaps(written_parents)) continue; if (depgraph.Ancestors(idx)[dep_idx]) { @@ -191,9 +191,9 @@ struct DepGraphFormatter DepGraph topo_depgraph; /** Mapping from serialization order to cluster order, used later to reconstruct the * cluster order. */ - std::vector reordering; + std::vector reordering; /** How big the entries vector in the reconstructed depgraph will be (including holes). */ - ClusterIndex total_size{0}; + DepGraphIndex total_size{0}; // Read transactions in topological order. while (true) { @@ -217,9 +217,9 @@ struct DepGraphFormatter // Read dependency information. auto topo_idx = reordering.size(); s >> VARINT(diff); - for (ClusterIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) { + for (DepGraphIndex dep_dist = 0; dep_dist < topo_idx; ++dep_dist) { /** Which topo_depgraph index we are currently considering as parent of topo_idx. */ - ClusterIndex dep_topo_idx = topo_idx - 1 - dep_dist; + DepGraphIndex dep_topo_idx = topo_idx - 1 - dep_dist; // Ignore transactions which are already known ancestors of topo_idx. if (new_ancestors[dep_topo_idx]) continue; if (diff == 0) { @@ -286,9 +286,9 @@ template void SanityCheck(const DepGraph& depgraph) { // Verify Positions and PositionRange consistency. - ClusterIndex num_positions{0}; - ClusterIndex position_range{0}; - for (ClusterIndex i : depgraph.Positions()) { + DepGraphIndex num_positions{0}; + DepGraphIndex position_range{0}; + for (DepGraphIndex i : depgraph.Positions()) { ++num_positions; position_range = i + 1; } @@ -297,7 +297,7 @@ void SanityCheck(const DepGraph& depgraph) assert(position_range >= num_positions); assert(position_range <= SetType::Size()); // Consistency check between ancestors internally. - for (ClusterIndex i : depgraph.Positions()) { + for (DepGraphIndex i : depgraph.Positions()) { // Transactions include themselves as ancestors. assert(depgraph.Ancestors(i)[i]); // If a is an ancestor of b, then b's ancestors must include all of a's ancestors. @@ -306,8 +306,8 @@ void SanityCheck(const DepGraph& depgraph) } } // Consistency check between ancestors and descendants. - for (ClusterIndex i : depgraph.Positions()) { - for (ClusterIndex j : depgraph.Positions()) { + for (DepGraphIndex i : depgraph.Positions()) { + for (DepGraphIndex j : depgraph.Positions()) { assert(depgraph.Ancestors(i)[j] == depgraph.Descendants(j)[i]); } // No transaction is a parent or child of itself. @@ -348,7 +348,7 @@ void SanityCheck(const DepGraph& depgraph) // In acyclic graphs, the union of parents with parents of parents etc. yields the // full ancestor set (and similar for children and descendants). std::vector parents(depgraph.PositionRange()), children(depgraph.PositionRange()); - for (ClusterIndex i : depgraph.Positions()) { + for (DepGraphIndex i : depgraph.Positions()) { parents[i] = depgraph.GetReducedParents(i); children[i] = depgraph.GetReducedChildren(i); } @@ -380,7 +380,7 @@ void SanityCheck(const DepGraph& depgraph) /** Perform a sanity check on a linearization. */ template -void SanityCheck(const DepGraph& depgraph, std::span linearization) +void SanityCheck(const DepGraph& depgraph, std::span linearization) { // Check completeness. assert(linearization.size() == depgraph.TxCount());