LCOV - code coverage report
Current view: top level - src - cluster_linearize.h (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 99.2 % 481 477
Test Date: 2025-12-25 04:41:25 Functions: 100.0 % 163 163
Branches: 73.8 % 790 583

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #ifndef BITCOIN_CLUSTER_LINEARIZE_H
       6                 :             : #define BITCOIN_CLUSTER_LINEARIZE_H
       7                 :             : 
       8                 :             : #include <algorithm>
       9                 :             : #include <cstdint>
      10                 :             : #include <numeric>
      11                 :             : #include <optional>
      12                 :             : #include <utility>
      13                 :             : #include <vector>
      14                 :             : 
      15                 :             : #include <memusage.h>
      16                 :             : #include <random.h>
      17                 :             : #include <span.h>
      18                 :             : #include <util/feefrac.h>
      19                 :             : #include <util/vecdeque.h>
      20                 :             : 
      21                 :             : namespace cluster_linearize {
      22                 :             : 
      23                 :             : /** Data type to represent transaction indices in DepGraphs and the clusters they represent. */
      24                 :             : using DepGraphIndex = uint32_t;
      25                 :             : 
      26                 :             : /** Data structure that holds a transaction graph's preprocessed data (fee, size, ancestors,
      27                 :             :  *  descendants). */
      28                 :             : template<typename SetType>
      29   [ +  +  +  -  :        5653 : class DepGraph
           +  - ][ +  -  
          +  -  +  -  +  
                -  +  - ]
      30                 :             : {
      31                 :             :     /** Information about a single transaction. */
      32                 :             :     struct Entry
      33                 :             :     {
      34                 :             :         /** Fee and size of transaction itself. */
      35                 :       50090 :         FeeFrac feerate;
      36                 :             :         /** All ancestors of the transaction (including itself). */
      37                 :       50090 :         SetType ancestors;
      38                 :             :         /** All descendants of the transaction (including itself). */
      39                 :       50090 :         SetType descendants;
      40                 :             : 
      41                 :             :         /** Equality operator (primarily for for testing purposes). */
      42   [ +  -  +  -  :      100180 :         friend bool operator==(const Entry&, const Entry&) noexcept = default;
                   -  + ]
      43                 :             : 
      44                 :             :         /** Construct an empty entry. */
      45                 :       75582 :         Entry() noexcept = default;
      46                 :             :         /** Construct an entry with a given feerate, ancestor set, descendant set. */
      47                 :       77239 :         Entry(const FeeFrac& f, const SetType& a, const SetType& d) noexcept : feerate(f), ancestors(a), descendants(d) {}
      48                 :             :     };
      49                 :             : 
      50                 :             :     /** Data for each transaction. */
      51                 :             :     std::vector<Entry> entries;
      52                 :             : 
      53                 :             :     /** Which positions are used. */
      54                 :             :     SetType m_used;
      55                 :             : 
      56                 :             : public:
      57                 :             :     /** Equality operator (primarily for testing purposes). */
      58                 :        1883 :     friend bool operator==(const DepGraph& a, const DepGraph& b) noexcept
      59                 :             :     {
      60         [ +  - ]:        1883 :         if (a.m_used != b.m_used) return false;
      61                 :             :         // Only compare the used positions within the entries vector.
      62   [ +  +  +  + ]:       52695 :         for (auto idx : a.m_used) {
      63         [ +  - ]:       50090 :             if (a.entries[idx] != b.entries[idx]) return false;
      64                 :             :         }
      65                 :             :         return true;
      66                 :             :     }
      67                 :             : 
      68                 :             :     // Default constructors.
      69                 :         184 :     DepGraph() noexcept = default;
      70                 :             :     DepGraph(const DepGraph&) noexcept = default;
      71                 :             :     DepGraph(DepGraph&&) noexcept = default;
      72                 :          13 :     DepGraph& operator=(const DepGraph&) noexcept = default;
      73                 :        3777 :     DepGraph& operator=(DepGraph&&) noexcept = default;
      74                 :             : 
      75                 :             :     /** Construct a DepGraph object given another DepGraph and a mapping from old to new.
      76                 :             :      *
      77                 :             :      * @param depgraph   The original DepGraph that is being remapped.
      78                 :             :      *
      79                 :             :      * @param mapping    A span such that mapping[i] gives the position in the new DepGraph
      80                 :             :      *                   for position i in the old depgraph. Its size must be equal to
      81                 :             :      *                   depgraph.PositionRange(). The value of mapping[i] is ignored if
      82                 :             :      *                   position i is a hole in depgraph (i.e., if !depgraph.Positions()[i]).
      83                 :             :      *
      84                 :             :      * @param pos_range  The PositionRange() for the new DepGraph. It must equal the largest
      85                 :             :      *                   value in mapping for any used position in depgraph plus 1, or 0 if
      86                 :             :      *                   depgraph.TxCount() == 0.
      87                 :             :      *
      88                 :             :      * Complexity: O(N^2) where N=depgraph.TxCount().
      89                 :             :      */
      90         [ -  + ]:        2814 :     DepGraph(const DepGraph<SetType>& depgraph, std::span<const DepGraphIndex> mapping, DepGraphIndex pos_range) noexcept : entries(pos_range)
      91                 :             :     {
      92         [ -  + ]:        2814 :         Assume(mapping.size() == depgraph.PositionRange());
      93                 :        2814 :         Assume((pos_range == 0) == (depgraph.TxCount() == 0));
      94         [ +  + ]:       77919 :         for (DepGraphIndex i : depgraph.Positions()) {
      95                 :       75105 :             auto new_idx = mapping[i];
      96                 :       75105 :             Assume(new_idx < pos_range);
      97                 :             :             // Add transaction.
      98                 :       75105 :             entries[new_idx].ancestors = SetType::Singleton(new_idx);
      99                 :       75105 :             entries[new_idx].descendants = SetType::Singleton(new_idx);
     100                 :       75105 :             m_used.Set(new_idx);
     101                 :             :             // Fill in fee and size.
     102                 :       75105 :             entries[new_idx].feerate = depgraph.entries[i].feerate;
     103                 :             :         }
     104         [ +  + ]:       77919 :         for (DepGraphIndex i : depgraph.Positions()) {
     105                 :             :             // Fill in dependencies by mapping direct parents.
     106                 :       75105 :             SetType parents;
     107   [ +  +  +  + ]:      321075 :             for (auto j : depgraph.GetReducedParents(i)) parents.Set(mapping[j]);
     108                 :       75105 :             AddDependencies(parents, mapping[i]);
     109                 :             :         }
     110                 :             :         // Verify that the provided pos_range was correct (no unused positions at the end).
     111         [ +  - ]:        4551 :         Assume(m_used.None() ? (pos_range == 0) : (pos_range == m_used.Last() + 1));
     112                 :        2814 :     }
     113                 :             : 
     114                 :             :     /** Get the set of transactions positions in use. Complexity: O(1). */
     115   [ +  +  +  +  :       33484 :     const SetType& Positions() const noexcept { return m_used; }
          +  -  +  -  +  
          +  +  +  +  +  
          +  -  +  +  +  
          +  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
     116                 :             :     /** Get the range of positions in this DepGraph. All entries in Positions() are in [0, PositionRange() - 1]. */
     117   [ -  +  -  +  :        5668 :     DepGraphIndex PositionRange() const noexcept { return entries.size(); }
          -  +  -  +  -  
           + ][ -  +  -  
          +  +  +  -  +  
          -  +  -  +  +  
          -  -  +  -  +  
          -  +  +  -  -  
          +  +  -  -  +  
          -  +  -  +  +  
          -  -  +  +  -  
          -  +  -  +  -  
          +  +  -  -  +  
          +  -  -  +  -  
          +  -  +  +  -  
          -  +  +  -  -  
          +  -  +  -  +  
          +  -  -  +  +  
          -  -  +  -  +  
          -  +  -  +  -  
                      + ]
     118                 :             :     /** Get the number of transactions in the graph. Complexity: O(1). */
     119   [ -  +  -  + ]:      452210 :     auto TxCount() const noexcept { return m_used.Count(); }
           [ +  -  +  -  
          +  +  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     120                 :             :     /** Get the feerate of a given transaction i. Complexity: O(1). */
     121   [ +  -  +  +  :       76119 :     const FeeFrac& FeeRate(DepGraphIndex i) const noexcept { return entries[i].feerate; }
          +  -  +  +  +  
          -  +  +  +  -  
          +  +  +  -  +  
                      + ]
     122                 :             :     /** Get the mutable feerate of a given transaction i. Complexity: O(1). */
     123   [ +  -  +  - ]:         121 :     FeeFrac& FeeRate(DepGraphIndex i) noexcept { return entries[i].feerate; }
     124                 :             :     /** Get the ancestors of a given transaction i. Complexity: O(1). */
     125   [ -  -  -  -  :    28855127 :     const SetType& Ancestors(DepGraphIndex i) const noexcept { return entries[i].ancestors; }
           -  + ][ +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  +  +  +  +  
          +  -  +  -  +  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          -  +  +  -  +  
          -  -  +  +  -  
          -  +  -  +  -  
          +  +  -  +  -  
          -  +  -  +  +  
          -  +  -  -  +  
          -  +  +  -  +  
          -  -  +  +  -  
          -  +  -  +  -  
                +  +  - ]
     126                 :             :     /** Get the descendants of a given transaction i. Complexity: O(1). */
     127 [ -  - ][ +  +  :     1845590 :     const SetType& Descendants(DepGraphIndex i) const noexcept { return entries[i].descendants; }
          +  +  +  -  +  
          -  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  -  
                      + ]
     128                 :             : 
     129                 :             :     /** Add a new unconnected transaction to this transaction graph (in the first available
     130                 :             :      *  position), and return its DepGraphIndex.
     131                 :             :      *
     132                 :             :      * Complexity: O(1) (amortized, due to resizing of backing vector).
     133                 :             :      */
     134                 :       77239 :     DepGraphIndex AddTransaction(const FeeFrac& feefrac) noexcept
     135                 :             :     {
     136                 :             :         static constexpr auto ALL_POSITIONS = SetType::Fill(SetType::Size());
     137         [ +  - ]:       77239 :         auto available = ALL_POSITIONS - m_used;
     138         [ +  - ]:      125164 :         Assume(available.Any());
     139                 :       77239 :         DepGraphIndex new_idx = available.First();
     140   [ -  +  +  - ]:       77239 :         if (new_idx == entries.size()) {
     141                 :       77239 :             entries.emplace_back(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));
     142                 :             :         } else {
     143                 :           0 :             entries[new_idx] = Entry(feefrac, SetType::Singleton(new_idx), SetType::Singleton(new_idx));
     144                 :             :         }
     145                 :       77239 :         m_used.Set(new_idx);
     146                 :       77239 :         return new_idx;
     147                 :             :     }
     148                 :             : 
     149                 :             :     /** Remove the specified positions from this DepGraph.
     150                 :             :      *
     151                 :             :      * The specified positions will no longer be part of Positions(), and dependencies with them are
     152                 :             :      * removed. Note that due to DepGraph only tracking ancestors/descendants (and not direct
     153                 :             :      * dependencies), if a parent is removed while a grandparent remains, the grandparent will
     154                 :             :      * remain an ancestor.
     155                 :             :      *
     156                 :             :      * Complexity: O(N) where N=TxCount().
     157                 :             :      */
     158                 :          28 :     void RemoveTransactions(const SetType& del) noexcept
     159                 :             :     {
     160                 :          28 :         m_used -= del;
     161                 :             :         // Remove now-unused trailing entries.
     162   [ +  +  -  +  :          67 :         while (!entries.empty() && !m_used[entries.size() - 1]) {
                   +  + ]
     163                 :          39 :             entries.pop_back();
     164                 :             :         }
     165                 :             :         // Remove the deleted transactions from ancestors/descendants of other transactions. Note
     166                 :             :         // that the deleted positions will retain old feerate and dependency information. This does
     167                 :             :         // not matter as they will be overwritten by AddTransaction if they get used again.
     168         [ +  + ]:         175 :         for (auto& entry : entries) {
     169                 :         147 :             entry.ancestors &= m_used;
     170                 :         147 :             entry.descendants &= m_used;
     171                 :             :         }
     172                 :          28 :     }
     173                 :             : 
     174                 :             :     /** Modify this transaction graph, adding multiple parents to a specified child.
     175                 :             :      *
     176                 :             :      * Complexity: O(N) where N=TxCount().
     177                 :             :      */
     178                 :      154233 :     void AddDependencies(const SetType& parents, DepGraphIndex child) noexcept
     179                 :             :     {
     180         [ +  + ]:      154233 :         Assume(m_used[child]);
     181                 :      250083 :         Assume(parents.IsSubsetOf(m_used));
     182                 :             :         // Compute the ancestors of parents that are not already ancestors of child.
     183         [ +  + ]:      154233 :         SetType par_anc;
     184   [ +  +  +  + ]:      834475 :         for (auto par : parents - Ancestors(child)) {
     185                 :     1045631 :             par_anc |= Ancestors(par);
     186                 :             :         }
     187         [ +  + ]:      154233 :         par_anc -= Ancestors(child);
     188                 :             :         // Bail out if there are no such ancestors.
     189         [ +  + ]:      154233 :         if (par_anc.None()) return;
     190                 :             :         // To each such ancestor, add as descendants the descendants of the child.
     191                 :      120257 :         const auto& chl_des = entries[child].descendants;
     192         [ +  + ]:      958600 :         for (auto anc_of_par : par_anc) {
     193                 :     1367525 :             entries[anc_of_par].descendants |= chl_des;
     194                 :             :         }
     195                 :             :         // To each descendant of the child, add those ancestors.
     196   [ +  +  +  + ]:      285189 :         for (auto dec_of_chl : Descendants(child)) {
     197                 :      195839 :             entries[dec_of_chl].ancestors |= par_anc;
     198                 :             :         }
     199                 :             :     }
     200                 :             : 
     201                 :             :     /** Compute the (reduced) set of parents of node i in this graph.
     202                 :             :      *
     203                 :             :      * This returns the minimal subset of the parents of i whose ancestors together equal all of
     204                 :             :      * i's ancestors (unless i is part of a cycle of dependencies). Note that DepGraph does not
     205                 :             :      * store the set of parents; this information is inferred from the ancestor sets.
     206                 :             :      *
     207                 :             :      * Complexity: O(N) where N=Ancestors(i).Count() (which is bounded by TxCount()).
     208                 :             :      */
     209         [ +  + ]:     5156757 :     SetType GetReducedParents(DepGraphIndex i) const noexcept
     210                 :             :     {
     211         [ +  + ]:     5156757 :         SetType parents = Ancestors(i);
     212                 :     5156757 :         parents.Reset(i);
     213   [ +  +  +  +  :    32339291 :         for (auto parent : parents) {
                   +  + ]
     214         [ +  + ]:    25697423 :             if (parents[parent]) {
     215                 :    21634185 :                 parents -= Ancestors(parent);
     216                 :    21634185 :                 parents.Set(parent);
     217                 :             :             }
     218                 :             :         }
     219                 :     5156757 :         return parents;
     220                 :             :     }
     221                 :             : 
     222                 :             :     /** Compute the (reduced) set of children of node i in this graph.
     223                 :             :      *
     224                 :             :      * This returns the minimal subset of the children of i whose descendants together equal all of
     225                 :             :      * i's descendants (unless i is part of a cycle of dependencies). Note that DepGraph does not
     226                 :             :      * store the set of children; this information is inferred from the descendant sets.
     227                 :             :      *
     228                 :             :      * Complexity: O(N) where N=Descendants(i).Count() (which is bounded by TxCount()).
     229                 :             :      */
     230         [ +  + ]:       50070 :     SetType GetReducedChildren(DepGraphIndex i) const noexcept
     231                 :             :     {
     232         [ +  + ]:       50070 :         SetType children = Descendants(i);
     233                 :       50070 :         children.Reset(i);
     234   [ +  +  +  +  :      293106 :         for (auto child : children) {
                   +  + ]
     235         [ +  + ]:      233772 :             if (children[child]) {
     236                 :      167192 :                 children -= Descendants(child);
     237                 :      167192 :                 children.Set(child);
     238                 :             :             }
     239                 :             :         }
     240                 :       50070 :         return children;
     241                 :             :     }
     242                 :             : 
     243                 :             :     /** Compute the aggregate feerate of a set of nodes in this graph.
     244                 :             :      *
     245                 :             :      * Complexity: O(N) where N=elems.Count().
     246                 :             :      **/
     247                 :             :     FeeFrac FeeRate(const SetType& elems) const noexcept
     248                 :             :     {
     249                 :             :         FeeFrac ret;
     250                 :             :         for (auto pos : elems) ret += entries[pos].feerate;
     251                 :             :         return ret;
     252                 :             :     }
     253                 :             : 
     254                 :             :     /** Get the connected component within the subset "todo" that contains tx (which must be in
     255                 :             :      *  todo).
     256                 :             :      *
     257                 :             :      * Two transactions are considered connected if they are both in `todo`, and one is an ancestor
     258                 :             :      * of the other in the entire graph (so not just within `todo`), or transitively there is a
     259                 :             :      * path of transactions connecting them. This does mean that if `todo` contains a transaction
     260                 :             :      * and a grandparent, but misses the parent, they will still be part of the same component.
     261                 :             :      *
     262                 :             :      * Complexity: O(ret.Count()).
     263                 :             :      */
     264                 :         119 :     SetType GetConnectedComponent(const SetType& todo, DepGraphIndex tx) const noexcept
     265                 :             :     {
     266                 :         119 :         Assume(todo[tx]);
     267                 :         119 :         Assume(todo.IsSubsetOf(m_used));
     268                 :         119 :         auto to_add = SetType::Singleton(tx);
     269                 :         119 :         SetType ret;
     270                 :             :         do {
     271                 :         238 :             SetType old = ret;
     272   [ +  -  +  + ]:         740 :             for (auto add : to_add) {
     273                 :         264 :                 ret |= Descendants(add);
     274                 :         264 :                 ret |= Ancestors(add);
     275                 :             :             }
     276         [ +  + ]:         238 :             ret &= todo;
     277                 :         238 :             to_add = ret - old;
     278         [ +  + ]:         238 :         } while (to_add.Any());
     279                 :         119 :         return ret;
     280                 :             :     }
     281                 :             : 
     282                 :             :     /** Find some connected component within the subset "todo" of this graph.
     283                 :             :      *
     284                 :             :      * Specifically, this finds the connected component which contains the first transaction of
     285                 :             :      * todo (if any).
     286                 :             :      *
     287                 :             :      * Complexity: O(ret.Count()).
     288                 :             :      */
     289         [ -  + ]:         119 :     SetType FindConnectedComponent(const SetType& todo) const noexcept
     290                 :             :     {
     291         [ -  + ]:         119 :         if (todo.None()) return todo;
     292                 :         119 :         return GetConnectedComponent(todo, todo.First());
     293                 :             :     }
     294                 :             : 
     295                 :             :     /** Determine if a subset is connected.
     296                 :             :      *
     297                 :             :      * Complexity: O(subset.Count()).
     298                 :             :      */
     299                 :          11 :     bool IsConnected(const SetType& subset) const noexcept
     300                 :             :     {
     301         [ -  + ]:          11 :         return FindConnectedComponent(subset) == subset;
     302                 :             :     }
     303                 :             : 
     304                 :             :     /** Determine if this entire graph is connected.
     305                 :             :      *
     306                 :             :      * Complexity: O(TxCount()).
     307                 :             :      */
     308                 :             :     bool IsConnected() const noexcept { return IsConnected(m_used); }
     309                 :             : 
     310                 :             :     /** Append the entries of select to list in a topologically valid order.
     311                 :             :      *
     312                 :             :      * Complexity: O(select.Count() * log(select.Count())).
     313                 :             :      */
     314                 :             :     void AppendTopo(std::vector<DepGraphIndex>& list, const SetType& select) const noexcept
     315                 :             :     {
     316                 :             :         DepGraphIndex old_len = list.size();
     317                 :             :         for (auto i : select) list.push_back(i);
     318                 :             :         std::sort(list.begin() + old_len, list.end(), [&](DepGraphIndex a, DepGraphIndex b) noexcept {
     319                 :             :             const auto a_anc_count = entries[a].ancestors.Count();
     320                 :             :             const auto b_anc_count = entries[b].ancestors.Count();
     321                 :             :             if (a_anc_count != b_anc_count) return a_anc_count < b_anc_count;
     322                 :             :             return a < b;
     323                 :             :         });
     324                 :             :     }
     325                 :             : 
     326                 :             :     /** Check if this graph is acyclic. */
     327                 :         942 :     bool IsAcyclic() const noexcept
     328                 :             :     {
     329   [ +  +  +  -  :       26350 :         for (auto i : Positions()) {
                   +  + ]
     330         [ +  - ]:       25046 :             if ((Ancestors(i) & Descendants(i)) != SetType::Singleton(i)) {
     331                 :             :                 return false;
     332                 :             :             }
     333                 :             :         }
     334                 :             :         return true;
     335                 :             :     }
     336                 :             : 
     337                 :             :     unsigned CountDependencies() const noexcept
     338                 :             :     {
     339                 :             :         unsigned ret = 0;
     340                 :             :         for (auto i : Positions()) {
     341                 :             :             ret += GetReducedParents(i).Count();
     342                 :             :         }
     343                 :             :         return ret;
     344                 :             :     }
     345                 :             : 
     346                 :             :     /** Reduce memory usage if possible. No observable effect. */
     347                 :        1911 :     void Compact() noexcept
     348                 :             :     {
     349                 :        1911 :         entries.shrink_to_fit();
     350                 :             :     }
     351                 :             : 
     352                 :        3699 :     size_t DynamicMemoryUsage() const noexcept
     353                 :             :     {
     354         [ -  + ]:        3699 :         return memusage::DynamicUsage(entries);
     355                 :             :     }
     356                 :             : };
     357                 :             : 
     358                 :             : /** A set of transactions together with their aggregate feerate. */
     359                 :             : template<typename SetType>
     360                 :             : struct SetInfo
     361                 :             : {
     362                 :             :     /** The transactions in the set. */
     363                 :             :     SetType transactions;
     364                 :             :     /** Their combined fee and size. */
     365                 :             :     FeeFrac feerate;
     366                 :             : 
     367                 :             :     /** Construct a SetInfo for the empty set. */
     368                 :     1848267 :     SetInfo() noexcept = default;
     369                 :             : 
     370                 :             :     /** Construct a SetInfo for a specified set and feerate. */
     371                 :     1034734 :     SetInfo(const SetType& txn, const FeeFrac& fr) noexcept : transactions(txn), feerate(fr) {}
     372                 :             : 
     373                 :             :     /** Construct a SetInfo for a given transaction in a depgraph. */
     374                 :       28471 :     explicit SetInfo(const DepGraph<SetType>& depgraph, DepGraphIndex pos) noexcept :
     375                 :       28471 :         transactions(SetType::Singleton(pos)), feerate(depgraph.FeeRate(pos)) {}
     376                 :             : 
     377                 :             :     /** Construct a SetInfo for a set of transactions in a depgraph. */
     378                 :             :     explicit SetInfo(const DepGraph<SetType>& depgraph, const SetType& txn) noexcept :
     379                 :             :         transactions(txn), feerate(depgraph.FeeRate(txn)) {}
     380                 :             : 
     381                 :             :     /** Add a transaction to this SetInfo (which must not yet be in it). */
     382                 :             :     void Set(const DepGraph<SetType>& depgraph, DepGraphIndex pos) noexcept
     383                 :             :     {
     384                 :             :         Assume(!transactions[pos]);
     385                 :             :         transactions.Set(pos);
     386                 :             :         feerate += depgraph.FeeRate(pos);
     387                 :             :     }
     388                 :             : 
     389                 :             :     /** Add the transactions of other to this SetInfo (no overlap allowed). */
     390                 :    34064869 :     SetInfo& operator|=(const SetInfo& other) noexcept
     391                 :             :     {
     392                 :    56059375 :         Assume(!transactions.Overlaps(other.transactions));
     393                 :    34064869 :         transactions |= other.transactions;
     394                 :    34064869 :         feerate += other.feerate;
     395                 :    34064869 :         return *this;
     396                 :             :     }
     397                 :             : 
     398                 :             :     /** Remove the transactions of other from this SetInfo (which must be a subset). */
     399                 :    12169945 :     SetInfo& operator-=(const SetInfo& other) noexcept
     400                 :             :     {
     401                 :    20144613 :         Assume(other.transactions.IsSubsetOf(transactions));
     402                 :    12169945 :         transactions -= other.transactions;
     403                 :    12169945 :         feerate -= other.feerate;
     404                 :    12169945 :         return *this;
     405                 :             :     }
     406                 :             : 
     407                 :             :     /** Compute the difference between this and other SetInfo (which must be a subset). */
     408                 :     1034734 :     SetInfo operator-(const SetInfo& other) const noexcept
     409                 :             :     {
     410                 :     1034734 :         Assume(other.transactions.IsSubsetOf(transactions));
     411                 :     1034734 :         return {transactions - other.transactions, feerate - other.feerate};
     412                 :             :     }
     413                 :             : 
     414                 :             :     /** Swap two SetInfo objects. */
     415                 :             :     friend void swap(SetInfo& a, SetInfo& b) noexcept
     416                 :             :     {
     417                 :             :         swap(a.transactions, b.transactions);
     418                 :             :         swap(a.feerate, b.feerate);
     419                 :             :     }
     420                 :             : 
     421                 :             :     /** Permit equality testing. */
     422                 :             :     friend bool operator==(const SetInfo&, const SetInfo&) noexcept = default;
     423                 :             : };
     424                 :             : 
     425                 :             : /** Compute the chunks of linearization as SetInfos. */
     426                 :             : template<typename SetType>
     427                 :        1900 : std::vector<SetInfo<SetType>> ChunkLinearizationInfo(const DepGraph<SetType>& depgraph, std::span<const DepGraphIndex> linearization) noexcept
     428                 :             : {
     429                 :        1900 :     std::vector<SetInfo<SetType>> ret;
     430         [ +  + ]:       30371 :     for (DepGraphIndex i : linearization) {
     431                 :             :         /** The new chunk to be added, initially a singleton. */
     432                 :       28471 :         SetInfo<SetType> new_chunk(depgraph, i);
     433                 :             :         // As long as the new chunk has a higher feerate than the last chunk so far, absorb it.
     434   [ +  +  +  + ]:       32456 :         while (!ret.empty() && new_chunk.feerate >> ret.back().feerate) {
     435                 :        3985 :             new_chunk |= ret.back();
     436                 :        3985 :             ret.pop_back();
     437                 :             :         }
     438                 :             :         // Actually move that new chunk into the chunking.
     439                 :       28471 :         ret.emplace_back(std::move(new_chunk));
     440                 :             :     }
     441                 :        1900 :     return ret;
     442                 :             : }
     443                 :             : 
     444                 :             : /** Compute the feerates of the chunks of linearization. Identical to ChunkLinearizationInfo, but
     445                 :             :  *  only returns the chunk feerates, not the corresponding transaction sets. */
     446                 :             : template<typename SetType>
     447                 :      186221 : std::vector<FeeFrac> ChunkLinearization(const DepGraph<SetType>& depgraph, std::span<const DepGraphIndex> linearization) noexcept
     448                 :             : {
     449                 :      186221 :     std::vector<FeeFrac> ret;
     450         [ +  + ]:     5189264 :     for (DepGraphIndex i : linearization) {
     451                 :             :         /** The new chunk to be added, initially a singleton. */
     452                 :     5003043 :         auto new_chunk = depgraph.FeeRate(i);
     453                 :             :         // As long as the new chunk has a higher feerate than the last chunk so far, absorb it.
     454   [ +  +  +  + ]:     8275662 :         while (!ret.empty() && new_chunk >> ret.back()) {
     455                 :     3272619 :             new_chunk += ret.back();
     456                 :     3272619 :             ret.pop_back();
     457                 :             :         }
     458                 :             :         // Actually move that new chunk into the chunking.
     459                 :     5003043 :         ret.push_back(std::move(new_chunk));
     460                 :             :     }
     461                 :      186221 :     return ret;
     462                 :             : }
     463                 :             : 
     464                 :             : /** Class to represent the internal state of the spanning-forest linearization (SFL) algorithm.
     465                 :             :  *
     466                 :             :  * At all times, each dependency is marked as either "active" or "inactive". The subset of active
     467                 :             :  * dependencies is the state of the SFL algorithm. The implementation maintains several other
     468                 :             :  * values to speed up operations, but everything is ultimately a function of what that subset of
     469                 :             :  * active dependencies is.
     470                 :             :  *
     471                 :             :  * Given such a subset, define a chunk as the set of transactions that are connected through active
     472                 :             :  * dependencies (ignoring their parent/child direction). Thus, every state implies a particular
     473                 :             :  * partitioning of the graph into chunks (including potential singletons). In the extreme, each
     474                 :             :  * transaction may be in its own chunk, or in the other extreme all transactions may form a single
     475                 :             :  * chunk. A chunk's feerate is its total fee divided by its total size.
     476                 :             :  *
     477                 :             :  * The algorithm consists of switching dependencies between active and inactive. The final
     478                 :             :  * linearization that is produced at the end consists of these chunks, sorted from high to low
     479                 :             :  * feerate, each individually sorted in an arbitrary but topological (= no child before parent)
     480                 :             :  * way.
     481                 :             :  *
     482                 :             :  * We define three quality properties the state can have, each being stronger than the previous:
     483                 :             :  *
     484                 :             :  * - acyclic: The state is acyclic whenever no cycle of active dependencies exists within the
     485                 :             :  *            graph, ignoring the parent/child direction. This is equivalent to saying that within
     486                 :             :  *            each chunk the set of active dependencies form a tree, and thus the overall set of
     487                 :             :  *            active dependencies in the graph form a spanning forest, giving the algorithm its
     488                 :             :  *            name. Being acyclic is also equivalent to every chunk of N transactions having
     489                 :             :  *            exactly N-1 active dependencies.
     490                 :             :  *
     491                 :             :  *            For example in a diamond graph, D->{B,C}->A, the 4 dependencies cannot be
     492                 :             :  *            simultaneously active. If at least one is inactive, the state is acyclic.
     493                 :             :  *
     494                 :             :  *            The algorithm maintains an acyclic state at *all* times as an invariant. This implies
     495                 :             :  *            that activating a dependency always corresponds to merging two chunks, and that
     496                 :             :  *            deactivating one always corresponds to splitting two chunks.
     497                 :             :  *
     498                 :             :  * - topological: We say the state is topological whenever it is acyclic and no inactive dependency
     499                 :             :  *                exists between two distinct chunks such that the child chunk has higher or equal
     500                 :             :  *                feerate than the parent chunk.
     501                 :             :  *
     502                 :             :  *                The relevance is that whenever the state is topological, the produced output
     503                 :             :  *                linearization will be topological too (i.e., not have children before parents).
     504                 :             :  *                Note that the "or equal" part of the definition matters: if not, one can end up
     505                 :             :  *                in a situation with mutually-dependent equal-feerate chunks that cannot be
     506                 :             :  *                linearized. For example C->{A,B} and D->{A,B}, with C->A and D->B active. The AC
     507                 :             :  *                chunk depends on DB through C->B, and the BD chunk depends on AC through D->A.
     508                 :             :  *                Merging them into a single ABCD chunk fixes this.
     509                 :             :  *
     510                 :             :  *                The algorithm attempts to keep the state topological as much as possible, so it
     511                 :             :  *                can be interrupted to produce an output whenever, but will sometimes need to
     512                 :             :  *                temporarily deviate from it when improving the state.
     513                 :             :  *
     514                 :             :  * - optimal: For every active dependency, define its top and bottom set as the set of transactions
     515                 :             :  *            in the chunks that would result if the dependency were deactivated; the top being the
     516                 :             :  *            one with the dependency's parent, and the bottom being the one with the child. Note
     517                 :             :  *            that due to acyclicity, every deactivation splits a chunk exactly in two.
     518                 :             :  *
     519                 :             :  *            We say the state is optimal whenever it is topological and it has no active
     520                 :             :  *            dependency whose top feerate is strictly higher than its bottom feerate. The
     521                 :             :  *            relevance is that it can be proven that whenever the state is optimal, the produced
     522                 :             :  *            linearization will also be optimal (in the convexified feerate diagram sense). It can
     523                 :             :  *            also be proven that for every graph at least one optimal state exists.
     524                 :             :  *
     525                 :             :  *            Note that it is possible for the SFL state to not be optimal, but the produced
     526                 :             :  *            linearization to still be optimal. This happens when the chunks of a state are
     527                 :             :  *            identical to those of an optimal state, but the exact set of active dependencies
     528                 :             :  *            within a chunk differ in such a way that the state optimality condition is not
     529                 :             :  *            satisfied. Thus, the state being optimal is more a "the eventual output is *known*
     530                 :             :  *            to be optimal".
     531                 :             :  *
     532                 :             :  *            The algorithm terminates whenever an optimal state is reached.
     533                 :             :  *
     534                 :             :  *
     535                 :             :  * This leads to the following high-level algorithm:
     536                 :             :  * - Start with all dependencies inactive, and thus all transactions in their own chunk. This is
     537                 :             :  *   definitely acyclic.
     538                 :             :  * - Activate dependencies (merging chunks) until the state is topological.
     539                 :             :  * - Loop until optimal (no dependencies with higher-feerate top than bottom), or time runs out:
     540                 :             :  *   - Deactivate a violating dependency, potentially making the state non-topological.
     541                 :             :  *   - Activate other dependencies to make the state topological again.
     542                 :             :  * - Output the chunks from high to low feerate, each internally sorted topologically.
     543                 :             :  *
     544                 :             :  * When merging, we always either:
     545                 :             :  * - Merge upwards: merge a chunk with the lowest-feerate other chunk it depends on, among those
     546                 :             :  *                  with lower or equal feerate than itself.
     547                 :             :  * - Merge downwards: merge a chunk with the highest-feerate other chunk that depends on it, among
     548                 :             :  *                    those with higher or equal feerate than itself.
     549                 :             :  *
     550                 :             :  * Using these strategies in the improvement loop above guarantees that the output linearization
     551                 :             :  * after a deactivate + merge step is never worse or incomparable (in the convexified feerate
     552                 :             :  * diagram sense) than the output linearization that would be produced before the step. With that,
     553                 :             :  * we can refine the high-level algorithm to:
     554                 :             :  * - Start with all dependencies inactive.
     555                 :             :  * - Perform merges as described until none are possible anymore, making the state topological.
     556                 :             :  * - Loop until optimal or time runs out:
     557                 :             :  *   - Pick a dependency D to deactivate among those with higher feerate top than bottom.
     558                 :             :  *   - Deactivate D, causing the chunk it is in to split into top T and bottom B.
     559                 :             :  *   - Do an upwards merge of T, if possible. If so, repeat the same with the merged result.
     560                 :             :  *   - Do a downwards merge of B, if possible. If so, repeat the same with the merged result.
     561                 :             :  * - Output the chunks from high to low feerate, each internally sorted topologically.
     562                 :             :  *
     563                 :             :  * Instead of performing merges arbitrarily to make the initial state topological, it is possible
     564                 :             :  * to do so guided by an existing linearization. This has the advantage that the state's would-be
     565                 :             :  * output linearization is immediately as good as the existing linearization it was based on:
     566                 :             :  * - Start with all dependencies inactive.
     567                 :             :  * - For each transaction t in the existing linearization:
     568                 :             :  *   - Find the chunk C that transaction is in (which will be singleton).
     569                 :             :  *   - Do an upwards merge of C, if possible. If so, repeat the same with the merged result.
     570                 :             :  * No downwards merges are needed in this case.
     571                 :             :  *
     572                 :             :  * What remains to be specified are a number of heuristics:
     573                 :             :  *
     574                 :             :  * - How to decide which chunks to merge:
     575                 :             :  *   - The merge upwards and downward rules specify that the lowest-feerate respectively
     576                 :             :  *     highest-feerate candidate chunk is merged with, but if there are multiple equal-feerate
     577                 :             :  *     candidates, a uniformly random one among them is picked.
     578                 :             :  *
     579                 :             :  * - How to decide what dependency to activate (when merging chunks):
     580                 :             :  *   - After picking two chunks to be merged (see above), a uniformly random dependency between the
     581                 :             :  *     two chunks is activated.
     582                 :             :  *
     583                 :             :  * - How to decide which chunk to find a dependency to split in:
     584                 :             :  *   - A round-robin queue of chunks to improve is maintained. The initial ordering of this queue
     585                 :             :  *     is uniformly randomly permuted.
     586                 :             :  *
     587                 :             :  * - How to decide what dependency to deactivate (when splitting chunks):
     588                 :             :  *   - Inside the selected chunk (see above), among the dependencies whose top feerate is strictly
     589                 :             :  *     higher than its bottom feerate in the selected chunk, if any, a uniformly random dependency
     590                 :             :  *     is deactivated.
     591                 :             :  *
     592                 :             :  * - How to decide the exact output linearization:
     593                 :             :  *   - When there are multiple equal-feerate chunks with no dependencies between them, output a
     594                 :             :  *     uniformly random one among the ones with no missing dependent chunks first.
     595                 :             :  *   - Within chunks, repeatedly pick a uniformly random transaction among those with no missing
     596                 :             :  *     dependencies.
     597                 :             :  */
     598                 :             : template<typename SetType>
     599                 :             : class SpanningForestState
     600                 :             : {
     601                 :             : private:
     602                 :             :     /** Internal RNG. */
     603                 :             :     InsecureRandomContext m_rng;
     604                 :             : 
     605                 :             :     /** Data type to represent indexing into m_tx_data. */
     606                 :             :     using TxIdx = uint32_t;
     607                 :             :     /** Data type to represent indexing into m_dep_data. */
     608                 :             :     using DepIdx = uint32_t;
     609                 :             : 
     610                 :             :     /** Structure with information about a single transaction. For transactions that are the
     611                 :             :      *  representative for the chunk they are in, this also stores chunk information. */
     612                 :     6909734 :     struct TxData {
     613                 :             :         /** The dependencies to children of this transaction. Immutable after construction. */
     614                 :             :         std::vector<DepIdx> child_deps;
     615                 :             :         /** The set of parent transactions of this transaction. Immutable after construction. */
     616                 :             :         SetType parents;
     617                 :             :         /** The set of child transactions of this transaction. Immutable after construction. */
     618                 :             :         SetType children;
     619                 :             :         /** Which transaction holds the chunk_setinfo for the chunk this transaction is in
     620                 :             :          *  (the representative for the chunk). */
     621                 :             :         TxIdx chunk_rep;
     622                 :             :         /** (Only if this transaction is the representative for the chunk it is in) the total
     623                 :             :          *  chunk set and feerate. */
     624                 :             :         SetInfo<SetType> chunk_setinfo;
     625                 :             :     };
     626                 :             : 
     627                 :             :     /** Structure with information about a single dependency. */
     628                 :    14996170 :     struct DepData {
     629                 :             :         /** Whether this dependency is active. */
     630                 :             :         bool active;
     631                 :             :         /** What the parent and child transactions are. Immutable after construction. */
     632                 :             :         TxIdx parent, child;
     633                 :             :         /** (Only if this dependency is active) the would-be top chunk and its feerate that would
     634                 :             :          *  be formed if this dependency were to be deactivated. */
     635                 :             :         SetInfo<SetType> top_setinfo;
     636                 :             :     };
     637                 :             : 
     638                 :             :     /** The set of all TxIdx's of transactions in the cluster indexing into m_tx_data. */
     639                 :             :     SetType m_transaction_idxs;
     640                 :             :     /** Information about each transaction (and chunks). Keeps the "holes" from DepGraph during
     641                 :             :      *  construction. Indexed by TxIdx. */
     642                 :             :     std::vector<TxData> m_tx_data;
     643                 :             :     /** Information about each dependency. Indexed by DepIdx. */
     644                 :             :     std::vector<DepData> m_dep_data;
     645                 :             :     /** A FIFO of chunk representatives of chunks that may be improved still. */
     646                 :             :     VecDeque<TxIdx> m_suboptimal_chunks;
     647                 :             : 
     648                 :             :     /** The number of updated transactions in activations/deactivations. */
     649                 :             :     uint64_t m_cost{0};
     650                 :             : 
     651                 :             :     /** Update a chunk:
     652                 :             :      *  - All transactions have their chunk representative set to `chunk_rep`.
     653                 :             :      *  - All dependencies which have `query` in their top_setinfo get `dep_change` added to it
     654                 :             :      *    (if `!Subtract`) or removed from it (if `Subtract`).
     655                 :             :      */
     656                 :             :     template<bool Subtract>
     657                 :    11202206 :     void UpdateChunk(const SetType& chunk, TxIdx query, TxIdx chunk_rep, const SetInfo<SetType>& dep_change) noexcept
     658                 :             :     {
     659                 :             :         // Iterate over all the chunk's transactions.
     660   [ +  +  +  + ]:    96773394 :         for (auto tx_idx : chunk) {
     661         [ -  + ]:    81507702 :             auto& tx_data = m_tx_data[tx_idx];
     662                 :             :             // Update the chunk representative.
     663                 :    81507702 :             tx_data.chunk_rep = chunk_rep;
     664                 :             :             // Iterate over all active dependencies with tx_idx as parent. Combined with the outer
     665                 :             :             // loop this iterates over all internal active dependencies of the chunk.
     666         [ -  + ]:    81507702 :             auto child_deps = std::span{tx_data.child_deps};
     667         [ +  + ]:   565874180 :             for (auto dep_idx : child_deps) {
     668         [ +  + ]:   484366478 :                 auto& dep_entry = m_dep_data[dep_idx];
     669         [ +  + ]:   484366478 :                 Assume(dep_entry.parent == tx_idx);
     670                 :             :                 // Skip inactive dependencies.
     671         [ +  + ]:   484366478 :                 if (!dep_entry.active) continue;
     672                 :             :                 // If this dependency's top_setinfo contains query, update it to add/remove
     673                 :             :                 // dep_change.
     674         [ +  + ]:    70305496 :                 if (dep_entry.top_setinfo.transactions[query]) {
     675                 :             :                     if constexpr (Subtract) {
     676                 :    12169945 :                         dep_entry.top_setinfo -= dep_change;
     677                 :             :                     } else {
     678                 :    29494515 :                         dep_entry.top_setinfo |= dep_change;
     679                 :             :                     }
     680                 :             :                 }
     681                 :             :             }
     682                 :             :         }
     683                 :    11202206 :     }
     684                 :             : 
     685                 :             :     /** Make a specified inactive dependency active. Returns the merged chunk representative. */
     686                 :     4566369 :     TxIdx Activate(DepIdx dep_idx) noexcept
     687                 :             :     {
     688                 :     4566369 :         auto& dep_data = m_dep_data[dep_idx];
     689                 :     4566369 :         Assume(!dep_data.active);
     690                 :     4566369 :         auto& child_tx_data = m_tx_data[dep_data.child];
     691                 :     4566369 :         auto& parent_tx_data = m_tx_data[dep_data.parent];
     692                 :             : 
     693                 :             :         // Gather information about the parent and child chunks.
     694                 :     4566369 :         Assume(parent_tx_data.chunk_rep != child_tx_data.chunk_rep);
     695                 :     4566369 :         auto& par_chunk_data = m_tx_data[parent_tx_data.chunk_rep];
     696                 :     4566369 :         auto& chl_chunk_data = m_tx_data[child_tx_data.chunk_rep];
     697                 :     4566369 :         TxIdx top_rep = parent_tx_data.chunk_rep;
     698                 :     4566369 :         auto top_part = par_chunk_data.chunk_setinfo;
     699                 :     4566369 :         auto bottom_part = chl_chunk_data.chunk_setinfo;
     700                 :             :         // Update the parent chunk to also contain the child.
     701                 :     4566369 :         par_chunk_data.chunk_setinfo |= bottom_part;
     702                 :     4566369 :         m_cost += par_chunk_data.chunk_setinfo.transactions.Count();
     703                 :             : 
     704                 :             :         // Consider the following example:
     705                 :             :         //
     706                 :             :         //    A           A     There are two chunks, ABC and DEF, and the inactive E->C dependency
     707                 :             :         //   / \         / \    is activated, resulting in a single chunk ABCDEF.
     708                 :             :         //  B   C       B   C
     709                 :             :         //      :  ==>      |   Dependency | top set before | top set after | change
     710                 :             :         //  D   E       D   E   B->A       | AC             | ACDEF         | +DEF
     711                 :             :         //   \ /         \ /    C->A       | AB             | AB            |
     712                 :             :         //    F           F     F->D       | D              | D             |
     713                 :             :         //                      F->E       | E              | ABCE          | +ABC
     714                 :             :         //
     715                 :             :         // The common pattern here is that any dependency which has the parent or child of the
     716                 :             :         // dependency being activated (E->C here) in its top set, will have the opposite part added
     717                 :             :         // to it. This is true for B->A and F->E, but not for C->A and F->D.
     718                 :             :         //
     719                 :             :         // Let UpdateChunk traverse the old parent chunk top_part (ABC in example), and add
     720                 :             :         // bottom_part (DEF) to every dependency's top_set which has the parent (C) in it. The
     721                 :             :         // representative of each of these transactions was already top_rep, so that is not being
     722                 :             :         // changed here.
     723                 :     4566369 :         UpdateChunk<false>(/*chunk=*/top_part.transactions, /*query=*/dep_data.parent,
     724                 :             :                            /*chunk_rep=*/top_rep, /*dep_change=*/bottom_part);
     725                 :             :         // Let UpdateChunk traverse the old child chunk bottom_part (DEF in example), and add
     726                 :             :         // top_part (ABC) to every dependency's top_set which has the child (E) in it. At the same
     727                 :             :         // time, change the representative of each of these transactions to be top_rep, which
     728                 :             :         // becomes the representative for the merged chunk.
     729                 :     4566369 :         UpdateChunk<false>(/*chunk=*/bottom_part.transactions, /*query=*/dep_data.child,
     730                 :             :                            /*chunk_rep=*/top_rep, /*dep_change=*/top_part);
     731                 :             :         // Make active.
     732                 :     4566369 :         dep_data.active = true;
     733                 :     4566369 :         dep_data.top_setinfo = top_part;
     734                 :     4566369 :         return top_rep;
     735                 :             :     }
     736                 :             : 
     737                 :             :     /** Make a specified active dependency inactive. */
     738                 :     1034734 :     void Deactivate(DepIdx dep_idx) noexcept
     739                 :             :     {
     740                 :     1034734 :         auto& dep_data = m_dep_data[dep_idx];
     741                 :     1034734 :         Assume(dep_data.active);
     742                 :     1034734 :         auto& parent_tx_data = m_tx_data[dep_data.parent];
     743                 :             :         // Make inactive.
     744                 :     1034734 :         dep_data.active = false;
     745                 :             :         // Update representatives.
     746                 :     1034734 :         auto& chunk_data = m_tx_data[parent_tx_data.chunk_rep];
     747                 :     1034734 :         m_cost += chunk_data.chunk_setinfo.transactions.Count();
     748                 :     1034734 :         auto top_part = dep_data.top_setinfo;
     749                 :     1034734 :         auto bottom_part = chunk_data.chunk_setinfo - top_part;
     750                 :     1034734 :         TxIdx bottom_rep = dep_data.child;
     751                 :     1034734 :         auto& bottom_chunk_data = m_tx_data[bottom_rep];
     752                 :     1034734 :         bottom_chunk_data.chunk_setinfo = bottom_part;
     753                 :     1034734 :         TxIdx top_rep = dep_data.parent;
     754                 :     1034734 :         auto& top_chunk_data = m_tx_data[top_rep];
     755                 :     1034734 :         top_chunk_data.chunk_setinfo = top_part;
     756                 :             : 
     757                 :             :         // See the comment above in Activate(). We perform the opposite operations here,
     758                 :             :         // removing instead of adding.
     759                 :             :         //
     760                 :             :         // Let UpdateChunk traverse the old parent chunk top_part, and remove bottom_part from
     761                 :             :         // every dependency's top_set which has the parent in it. At the same time, change the
     762                 :             :         // representative of each of these transactions to be top_rep.
     763                 :     1034734 :         UpdateChunk<true>(/*chunk=*/top_part.transactions, /*query=*/dep_data.parent,
     764                 :             :                           /*chunk_rep=*/top_rep, /*dep_change=*/bottom_part);
     765                 :             :         // Let UpdateChunk traverse the old child chunk bottom_part, and remove top_part from every
     766                 :             :         // dependency's top_set which has the child in it. At the same time, change the
     767                 :             :         // representative of each of these transactions to be bottom_rep.
     768                 :     1034734 :         UpdateChunk<true>(/*chunk=*/bottom_part.transactions, /*query=*/dep_data.child,
     769                 :             :                           /*chunk_rep=*/bottom_rep, /*dep_change=*/top_part);
     770                 :     1034734 :     }
     771                 :             : 
     772                 :             :     /** Activate a dependency from the chunk represented by bottom_rep to the chunk represented by
     773                 :             :      *  top_rep, which must exist. Return the representative of the merged chunk. */
     774                 :     4566369 :     TxIdx MergeChunks(TxIdx top_rep, TxIdx bottom_rep) noexcept
     775                 :             :     {
     776         [ +  - ]:     4566369 :         auto& top_chunk = m_tx_data[top_rep];
     777         [ +  - ]:     4566369 :         Assume(top_chunk.chunk_rep == top_rep);
     778                 :     4566369 :         auto& bottom_chunk = m_tx_data[bottom_rep];
     779                 :     4566369 :         Assume(bottom_chunk.chunk_rep == bottom_rep);
     780                 :             :         // Count the number of dependencies between bottom_chunk and top_chunk.
     781                 :     4566369 :         TxIdx num_deps{0};
     782   [ +  +  +  + ]:    43389606 :         for (auto tx : top_chunk.chunk_setinfo.transactions) {
     783                 :    37158648 :             auto& tx_data = m_tx_data[tx];
     784                 :    37158648 :             num_deps += (tx_data.children & bottom_chunk.chunk_setinfo.transactions).Count();
     785                 :             :         }
     786                 :     4566369 :         Assume(num_deps > 0);
     787                 :             :         // Uniformly randomly pick one of them and activate it.
     788                 :     4566369 :         TxIdx pick = m_rng.randrange(num_deps);
     789   [ +  -  +  - ]:    16960778 :         for (auto tx : top_chunk.chunk_setinfo.transactions) {
     790         [ +  + ]:    15296189 :             auto& tx_data = m_tx_data[tx];
     791         [ +  + ]:    15296189 :             auto intersect = tx_data.children & bottom_chunk.chunk_setinfo.transactions;
     792                 :    15296189 :             auto count = intersect.Count();
     793         [ +  + ]:    15296189 :             if (pick < count) {
     794         [ +  - ]:    30554337 :                 for (auto dep : tx_data.child_deps) {
     795         [ +  + ]:    30554337 :                     auto& dep_data = m_dep_data[dep];
     796         [ +  + ]:    30554337 :                     if (bottom_chunk.chunk_setinfo.transactions[dep_data.child]) {
     797         [ +  + ]:     5990514 :                         if (pick == 0) return Activate(dep);
     798                 :     1424145 :                         --pick;
     799                 :             :                     }
     800                 :             :                 }
     801                 :             :                 break;
     802                 :             :             }
     803                 :    10729820 :             pick -= count;
     804                 :             :         }
     805                 :           0 :         Assume(false);
     806                 :           0 :         return TxIdx(-1);
     807                 :             :     }
     808                 :             : 
     809                 :             :     /** Perform an upward or downward merge step, on the specified chunk representative. Returns
     810                 :             :      *  the representative of the merged chunk, or TxIdx(-1) if no merge took place. */
     811                 :             :     template<bool DownWard>
     812                 :    12199923 :     TxIdx MergeStep(TxIdx chunk_rep) noexcept
     813                 :             :     {
     814                 :             :         /** Information about the chunk that tx_idx is currently in. */
     815         [ +  - ]:    12199923 :         auto& chunk_data = m_tx_data[chunk_rep];
     816                 :    12199923 :         SetType chunk_txn = chunk_data.chunk_setinfo.transactions;
     817                 :             :         // Iterate over all transactions in the chunk, figuring out which other chunk each
     818                 :             :         // depends on, but only testing each other chunk once. For those depended-on chunks,
     819                 :             :         // remember the highest-feerate (if DownWard) or lowest-feerate (if !DownWard) one.
     820                 :             :         // If multiple equal-feerate candidate chunks to merge with exist, pick a random one
     821                 :             :         // among them.
     822                 :             : 
     823                 :             :         /** Which transactions have been reached from this chunk already. Initialize with the
     824                 :             :          *  chunk itself, so internal dependencies within the chunk are ignored. */
     825                 :    12199923 :         SetType explored = chunk_txn;
     826                 :             :         /** The minimum feerate (if downward) or maximum feerate (if upward) to consider when
     827                 :             :          *  looking for candidate chunks to merge with. Initially, this is the original chunk's
     828                 :             :          *  feerate, but is updated to be the current best candidate whenever one is found. */
     829                 :    12199923 :         FeeFrac best_other_chunk_feerate = chunk_data.chunk_setinfo.feerate;
     830                 :             :         /** The representative for the best candidate chunk to merge with. -1 if none. */
     831                 :    12199923 :         TxIdx best_other_chunk_rep = TxIdx(-1);
     832                 :             :         /** We generate random tiebreak values to pick between equal-feerate candidate chunks.
     833                 :             :          *  This variable stores the tiebreak of the current best candidate. */
     834                 :    12199923 :         uint64_t best_other_chunk_tiebreak{0};
     835   [ +  +  +  + ]:   130069842 :         for (auto tx : chunk_txn) {
     836                 :   113442626 :             auto& tx_data = m_tx_data[tx];
     837                 :             :             /** The transactions reached by following dependencies from tx that have not been
     838                 :             :              *  explored before. */
     839                 :   113442626 :             auto newly_reached = (DownWard ? tx_data.children : tx_data.parents) - explored;
     840                 :   140345382 :             explored |= newly_reached;
     841         [ +  + ]:   254882191 :             while (newly_reached.Any()) {
     842                 :             :                 // Find a chunk inside newly_reached, and remove it from newly_reached.
     843         [ +  + ]:    41156802 :                 auto reached_chunk_rep = m_tx_data[newly_reached.First()].chunk_rep;
     844                 :    41156802 :                 auto& reached_chunk = m_tx_data[reached_chunk_rep].chunk_setinfo;
     845         [ +  + ]:    41156802 :                 newly_reached -= reached_chunk.transactions;
     846                 :             :                 // See if it has an acceptable feerate.
     847         [ +  + ]:    10745711 :                 auto cmp = DownWard ? FeeRateCompare(best_other_chunk_feerate, reached_chunk.feerate)
     848         [ +  + ]:    30411091 :                                     : FeeRateCompare(reached_chunk.feerate, best_other_chunk_feerate);
     849         [ +  + ]:    41156802 :                 if (cmp > 0) continue;
     850         [ +  + ]:     7114142 :                 uint64_t tiebreak = m_rng.rand64();
     851   [ +  +  +  + ]:     7114142 :                 if (cmp < 0 || tiebreak >= best_other_chunk_tiebreak) {
     852                 :     6195361 :                     best_other_chunk_feerate = reached_chunk.feerate;
     853                 :     6195361 :                     best_other_chunk_rep = reached_chunk_rep;
     854                 :     6195361 :                     best_other_chunk_tiebreak = tiebreak;
     855                 :             :                 }
     856                 :             :             }
     857                 :             :         }
     858                 :             :         // Stop if there are no candidate chunks to merge with.
     859         [ +  + ]:    12199923 :         if (best_other_chunk_rep == TxIdx(-1)) return TxIdx(-1);
     860                 :             :         if constexpr (DownWard) {
     861                 :      554539 :             chunk_rep = MergeChunks(chunk_rep, best_other_chunk_rep);
     862                 :             :         } else {
     863                 :     4011830 :             chunk_rep = MergeChunks(best_other_chunk_rep, chunk_rep);
     864                 :             :         }
     865                 :     4566369 :         Assume(chunk_rep != TxIdx(-1));
     866                 :     4566369 :         return chunk_rep;
     867                 :             :     }
     868                 :             : 
     869                 :             : 
     870                 :             :     /** Perform an upward or downward merge sequence on the specified transaction. */
     871                 :             :     template<bool DownWard>
     872                 :     2069468 :     void MergeSequence(TxIdx tx_idx) noexcept
     873                 :             :     {
     874                 :     2069468 :         auto chunk_rep = m_tx_data[tx_idx].chunk_rep;
     875                 :      845899 :         while (true) {
     876                 :     2915367 :             auto merged_rep = MergeStep<DownWard>(chunk_rep);
     877         [ +  + ]:     2915367 :             if (merged_rep == TxIdx(-1)) break;
     878                 :      845899 :             chunk_rep = merged_rep;
     879                 :             :         }
     880                 :             :         // Add the chunk to the queue of improvable chunks.
     881                 :     2069468 :         m_suboptimal_chunks.push_back(chunk_rep);
     882                 :     2069468 :     }
     883                 :             : 
     884                 :             :     /** Split a chunk, and then merge the resulting two chunks to make the graph topological
     885                 :             :      *  again. */
     886                 :     1034734 :     void Improve(DepIdx dep_idx) noexcept
     887                 :             :     {
     888                 :     1034734 :         auto& dep_data = m_dep_data[dep_idx];
     889                 :     1034734 :         Assume(dep_data.active);
     890                 :             :         // Deactivate the specified dependency, splitting it into two new chunks: a top containing
     891                 :             :         // the parent, and a bottom containing the child. The top should have a higher feerate.
     892                 :     1034734 :         Deactivate(dep_idx);
     893                 :             : 
     894                 :             :         // At this point we have exactly two chunks which may violate topology constraints (the
     895                 :             :         // parent chunk and child chunk that were produced by deactivating dep_idx). We can fix
     896                 :             :         // these using just merge sequences, one upwards and one downwards, avoiding the need for a
     897                 :             :         // full MakeTopological.
     898                 :             : 
     899                 :             :         // Merge the top chunk with lower-feerate chunks it depends on (which may be the bottom it
     900                 :             :         // was just split from, or other pre-existing chunks).
     901                 :     1034734 :         MergeSequence<false>(dep_data.parent);
     902                 :             :         // Merge the bottom chunk with higher-feerate chunks that depend on it.
     903                 :     1034734 :         MergeSequence<true>(dep_data.child);
     904                 :     1034734 :     }
     905                 :             : 
     906                 :             : public:
     907                 :             :     /** Construct a spanning forest for the given DepGraph, with every transaction in its own chunk
     908                 :             :      *  (not topological). */
     909         [ -  + ]:      188100 :     explicit SpanningForestState(const DepGraph<SetType>& depgraph, uint64_t rng_seed) noexcept : m_rng(rng_seed)
     910                 :             :     {
     911                 :      188100 :         m_transaction_idxs = depgraph.Positions();
     912         [ -  + ]:      188100 :         auto num_transactions = m_transaction_idxs.Count();
     913         [ -  + ]:      188100 :         m_tx_data.resize(depgraph.PositionRange());
     914                 :             :         // Reserve the maximum number of (reserved) dependencies the cluster can have, so
     915                 :             :         // m_dep_data won't need any reallocations during construction. For a cluster with N
     916                 :             :         // transactions, the worst case consists of two sets of transactions, the parents and the
     917                 :             :         // children, where each child depends on each parent and nothing else. For even N, both
     918                 :             :         // sets can be sized N/2, which means N^2/4 dependencies. For odd N, one can be (N + 1)/2
     919                 :             :         // and the other can be (N - 1)/2, meaning (N^2 - 1)/4 dependencies. Because N^2 is odd in
     920                 :             :         // this case, N^2/4 (with rounding-down division) is the correct value in both cases.
     921                 :      188100 :         m_dep_data.reserve((num_transactions * num_transactions) / 4);
     922   [ +  +  +  + ]:     5291867 :         for (auto tx : m_transaction_idxs) {
     923                 :             :             // Fill in transaction data.
     924                 :     5031467 :             auto& tx_data = m_tx_data[tx];
     925                 :     5031467 :             tx_data.chunk_rep = tx;
     926                 :     5031467 :             tx_data.chunk_setinfo.transactions = SetType::Singleton(tx);
     927                 :     5031467 :             tx_data.chunk_setinfo.feerate = depgraph.FeeRate(tx);
     928                 :             :             // Add its dependencies.
     929                 :     5031467 :             SetType parents = depgraph.GetReducedParents(tx);
     930   [ +  +  +  + ]:    21477101 :             for (auto par : parents) {
     931         [ -  + ]:    14996170 :                 auto& par_tx_data = m_tx_data[par];
     932         [ -  + ]:    14996170 :                 auto dep_idx = m_dep_data.size();
     933                 :             :                 // Construct new dependency.
     934                 :    14996170 :                 auto& dep = m_dep_data.emplace_back();
     935                 :    14996170 :                 dep.active = false;
     936                 :    14996170 :                 dep.parent = par;
     937                 :    14996170 :                 dep.child = tx;
     938                 :             :                 // Add it as parent of the child.
     939                 :    14996170 :                 tx_data.parents.Set(par);
     940                 :             :                 // Add it as child of the parent.
     941                 :    14996170 :                 par_tx_data.child_deps.push_back(dep_idx);
     942                 :    14996170 :                 par_tx_data.children.Set(tx);
     943                 :             :             }
     944                 :             :         }
     945                 :      188100 :     }
     946                 :             : 
     947                 :             :     /** Load an existing linearization. Must be called immediately after constructor. The result is
     948                 :             :      *  topological if the linearization is valid. Otherwise, MakeTopological still needs to be
     949                 :             :      *  called. */
     950                 :      125570 :     void LoadLinearization(std::span<const DepGraphIndex> old_linearization) noexcept
     951                 :             :     {
     952                 :             :         // Add transactions one by one, in order of existing linearization.
     953         [ +  + ]:     3477034 :         for (DepGraphIndex tx : old_linearization) {
     954                 :     3351464 :             auto chunk_rep = m_tx_data[tx].chunk_rep;
     955                 :             :             // Merge the chunk upwards, as long as merging succeeds.
     956                 :             :             while (true) {
     957                 :     5779287 :                 chunk_rep = MergeStep<false>(chunk_rep);
     958         [ +  + ]:     5779287 :                 if (chunk_rep == TxIdx(-1)) break;
     959                 :             :             }
     960                 :             :         }
     961                 :      125570 :     }
     962                 :             : 
     963                 :             :     /** Make state topological. Can be called after constructing, or after LoadLinearization. */
     964                 :       62530 :     void MakeTopological() noexcept
     965                 :             :     {
     966   [ +  +  +  + ]:     1766122 :         for (auto tx : m_transaction_idxs) {
     967         [ +  - ]:     1680003 :             auto& tx_data = m_tx_data[tx];
     968         [ +  - ]:     1680003 :             if (tx_data.chunk_rep == tx) {
     969                 :     1680003 :                 m_suboptimal_chunks.emplace_back(tx);
     970                 :             :                 // Randomize the initial order of suboptimal chunks in the queue.
     971                 :     1680003 :                 TxIdx j = m_rng.randrange<TxIdx>(m_suboptimal_chunks.size());
     972         [ +  + ]:     1680003 :                 if (j != m_suboptimal_chunks.size() - 1) {
     973                 :     1450952 :                     std::swap(m_suboptimal_chunks.back(), m_suboptimal_chunks[j]);
     974                 :             :                 }
     975                 :             :             }
     976                 :             :         }
     977         [ +  + ]:     3035180 :         while (!m_suboptimal_chunks.empty()) {
     978                 :             :             // Pop an entry from the potentially-suboptimal chunk queue.
     979                 :     2972650 :             TxIdx chunk = m_suboptimal_chunks.front();
     980                 :     2972650 :             m_suboptimal_chunks.pop_front();
     981         [ +  + ]:     2972650 :             auto& chunk_data = m_tx_data[chunk];
     982                 :             :             // If what was popped is not currently a chunk representative, continue. This may
     983                 :             :             // happen when it was merged with something else since being added.
     984         [ +  + ]:     2972650 :             if (chunk_data.chunk_rep != chunk) continue;
     985                 :     2135412 :             int flip = m_rng.randbool();
     986         [ +  + ]:     4348034 :             for (int i = 0; i < 2; ++i) {
     987         [ +  + ]:     3505269 :                 if (i ^ flip) {
     988                 :             :                     // Attempt to merge the chunk upwards.
     989                 :     1810798 :                     auto result_up = MergeStep<false>(chunk);
     990         [ +  + ]:     1810798 :                     if (result_up != TxIdx(-1)) {
     991                 :      763225 :                         m_suboptimal_chunks.push_back(result_up);
     992                 :             :                         break;
     993                 :             :                     }
     994                 :             :                 } else {
     995                 :             :                     // Attempt to merge the chunk downwards.
     996                 :     1694471 :                     auto result_down = MergeStep<true>(chunk);
     997         [ +  + ]:     1694471 :                     if (result_down != TxIdx(-1)) {
     998                 :      529422 :                         m_suboptimal_chunks.push_back(result_down);
     999                 :             :                         break;
    1000                 :             :                     }
    1001                 :             :                 }
    1002                 :             :             }
    1003                 :             :         }
    1004                 :       62530 :     }
    1005                 :             : 
    1006                 :             :     /** Initialize the data structure for optimization. It must be topological already. */
    1007                 :      188094 :     void StartOptimizing() noexcept
    1008                 :             :     {
    1009                 :             :         // Mark chunks suboptimal.
    1010   [ +  +  +  + ]:     5291492 :         for (auto tx : m_transaction_idxs) {
    1011         [ +  + ]:     5031104 :             auto& tx_data = m_tx_data[tx];
    1012         [ +  + ]:     5031104 :             if (tx_data.chunk_rep == tx) {
    1013                 :     1310991 :                 m_suboptimal_chunks.push_back(tx);
    1014                 :             :                 // Randomize the initial order of suboptimal chunks in the queue.
    1015                 :     1310991 :                 TxIdx j = m_rng.randrange<TxIdx>(m_suboptimal_chunks.size());
    1016         [ +  + ]:     1310991 :                 if (j != m_suboptimal_chunks.size() - 1) {
    1017                 :      930861 :                     std::swap(m_suboptimal_chunks.back(), m_suboptimal_chunks[j]);
    1018                 :             :                 }
    1019                 :             :             }
    1020                 :             :         }
    1021                 :      188094 :     }
    1022                 :             : 
    1023                 :             :     /** Try to improve the forest. Returns false if it is optimal, true otherwise. */
    1024                 :     2670561 :     bool OptimizeStep() noexcept
    1025                 :             :     {
    1026         [ +  - ]:     3380459 :         while (!m_suboptimal_chunks.empty()) {
    1027                 :             :             // Pop an entry from the potentially-suboptimal chunk queue.
    1028                 :     3380459 :             TxIdx chunk = m_suboptimal_chunks.front();
    1029                 :     3380459 :             m_suboptimal_chunks.pop_front();
    1030         [ +  + ]:     3380459 :             auto& chunk_data = m_tx_data[chunk];
    1031                 :             :             // If what was popped is not currently a chunk representative, continue. This may
    1032                 :             :             // happen when a split chunk merges in Improve() with one or more existing chunks that
    1033                 :             :             // are themselves on the suboptimal queue already.
    1034         [ +  + ]:     3380459 :             if (chunk_data.chunk_rep != chunk) continue;
    1035                 :             :             // Remember the best dependency seen so far.
    1036                 :     2670561 :             DepIdx candidate_dep = DepIdx(-1);
    1037                 :     2670561 :             uint64_t candidate_tiebreak = 0;
    1038                 :             :             // Iterate over all transactions.
    1039   [ +  +  +  + ]:    35546543 :             for (auto tx : chunk_data.chunk_setinfo.transactions) {
    1040         [ -  + ]:    31919175 :                 const auto& tx_data = m_tx_data[tx];
    1041                 :             :                 // Iterate over all active child dependencies of the transaction.
    1042         [ -  + ]:    31919175 :                 const auto children = std::span{tx_data.child_deps};
    1043         [ +  + ]:   246905127 :                 for (DepIdx dep_idx : children) {
    1044         [ +  + ]:   214985952 :                     const auto& dep_data = m_dep_data[dep_idx];
    1045         [ +  + ]:   214985952 :                     if (!dep_data.active) continue;
    1046                 :             :                     // Skip if this dependency is ineligible (the top chunk that would be created
    1047                 :             :                     // does not have higher feerate than the chunk it is currently part of).
    1048         [ +  + ]:    29248614 :                     auto cmp = FeeRateCompare(dep_data.top_setinfo.feerate, chunk_data.chunk_setinfo.feerate);
    1049         [ +  + ]:    29248614 :                     if (cmp <= 0) continue;
    1050                 :             :                     // Generate a random tiebreak for this dependency, and reject it if its tiebreak
    1051                 :             :                     // is worse than the best so far. This means that among all eligible
    1052                 :             :                     // dependencies, a uniformly random one will be chosen.
    1053                 :     4647898 :                     uint64_t tiebreak = m_rng.rand64();
    1054         [ +  + ]:     4647898 :                     if (tiebreak < candidate_tiebreak) continue;
    1055                 :             :                     // Remember this as our (new) candidate dependency.
    1056                 :             :                     candidate_dep = dep_idx;
    1057                 :             :                     candidate_tiebreak = tiebreak;
    1058                 :             :                 }
    1059                 :             :             }
    1060                 :             :             // If a candidate with positive gain was found, deactivate it and then make the state
    1061                 :             :             // topological again with a sequence of merges.
    1062         [ +  + ]:     2670561 :             if (candidate_dep != DepIdx(-1)) Improve(candidate_dep);
    1063                 :             :             // Stop processing for now, even if nothing was activated, as the loop above may have
    1064                 :             :             // had a nontrivial cost.
    1065                 :     2670561 :             return !m_suboptimal_chunks.empty();
    1066                 :             :         }
    1067                 :             :         // No improvable chunk was found, we are done.
    1068                 :             :         return false;
    1069                 :             :     }
    1070                 :             : 
    1071                 :             :     /** Construct a topologically-valid linearization from the current forest state. Must be
    1072                 :             :      *  topological. */
    1073                 :      188100 :     std::vector<DepGraphIndex> GetLinearization() noexcept
    1074                 :             :     {
    1075                 :             :         /** The output linearization. */
    1076                 :      188100 :         std::vector<DepGraphIndex> ret;
    1077                 :      188100 :         ret.reserve(m_transaction_idxs.Count());
    1078                 :             :         /** A heap with all chunks (by representative) that can currently be included, sorted by
    1079                 :             :          *  chunk feerate and a random tie-breaker. */
    1080                 :      188100 :         std::vector<std::pair<TxIdx, uint64_t>> ready_chunks;
    1081                 :             :         /** Information about chunks:
    1082                 :             :          *  - The first value is only used for chunk representatives, and counts the number of
    1083                 :             :          *    unmet dependencies this chunk has on other chunks (not including dependencies within
    1084                 :             :          *    the chunk itself).
    1085                 :             :          *  - The second value is the number of unmet dependencies overall.
    1086                 :             :          */
    1087   [ -  +  +  - ]:      188100 :         std::vector<std::pair<TxIdx, TxIdx>> chunk_deps(m_tx_data.size(), {0, 0});
    1088                 :             :         /** The set of all chunk representatives. */
    1089                 :      188100 :         SetType chunk_reps;
    1090                 :             :         /** A list with all transactions within the current chunk that can be included. */
    1091                 :      188100 :         std::vector<TxIdx> ready_tx;
    1092                 :             :         // Populate chunk_deps[c] with the number of {out-of-chunk dependencies, dependencies} the
    1093                 :             :         // child has.
    1094   [ +  +  +  + ]:     5291867 :         for (TxIdx chl_idx : m_transaction_idxs) {
    1095         [ +  + ]:     5031467 :             const auto& chl_data = m_tx_data[chl_idx];
    1096         [ +  + ]:     5031467 :             chunk_deps[chl_idx].second = chl_data.parents.Count();
    1097         [ +  + ]:     5031467 :             auto chl_chunk_rep = chl_data.chunk_rep;
    1098                 :     5031467 :             chunk_reps.Set(chl_chunk_rep);
    1099   [ +  +  +  + ]:    21477101 :             for (auto par_idx : chl_data.parents) {
    1100                 :    14996170 :                 auto par_chunk_rep = m_tx_data[par_idx].chunk_rep;
    1101                 :    14996170 :                 chunk_deps[chl_chunk_rep].first += (par_chunk_rep != chl_chunk_rep);
    1102                 :             :             }
    1103                 :             :         }
    1104                 :             :         // Construct a heap with all chunks that have no out-of-chunk dependencies.
    1105                 :             :         /** Comparison function for the heap. */
    1106                 :     4868409 :         auto chunk_cmp_fn = [&](const std::pair<TxIdx, uint64_t>& a, const std::pair<TxIdx, uint64_t>& b) noexcept {
    1107 [ #  # ][ +  +  :     4680309 :             auto& chunk_a = m_tx_data[a.first];
          +  +  +  +  +  
                +  +  + ]
    1108                 :     4680309 :             auto& chunk_b = m_tx_data[b.first];
    1109 [ #  # ][ +  +  :     4680309 :             Assume(chunk_a.chunk_rep == a.first);
          +  +  +  +  +  
                +  +  + ]
    1110                 :     4680309 :             Assume(chunk_b.chunk_rep == b.first);
    1111                 :             :             // First sort by chunk feerate.
    1112 [ #  # ][ +  +  :     4680309 :             if (chunk_a.chunk_setinfo.feerate != chunk_b.chunk_setinfo.feerate) {
          +  +  +  +  +  
                +  +  + ]
    1113                 :     3392073 :                 return chunk_a.chunk_setinfo.feerate < chunk_b.chunk_setinfo.feerate;
    1114                 :             :             }
    1115                 :             :             // Tie-break randomly.
    1116 [ #  # ][ +  -  :     1288236 :             if (a.second != b.second) return a.second < b.second;
          +  -  +  -  +  
                -  +  - ]
    1117                 :             :             // Lastly, tie-break by chunk representative.
    1118                 :           0 :             return a.first < b.first;
    1119                 :             :         };
    1120   [ +  +  +  + ]:     1760232 :         for (TxIdx chunk_rep : chunk_reps) {
    1121         [ +  + ]:     1499832 :             if (chunk_deps[chunk_rep].first == 0) ready_chunks.emplace_back(chunk_rep, m_rng.rand64());
    1122                 :             :         }
    1123                 :      188100 :         std::make_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
    1124                 :             :         // Pop chunks off the heap, highest-feerate ones first.
    1125         [ +  + ]:     1687932 :         while (!ready_chunks.empty()) {
    1126                 :     1499832 :             auto [chunk_rep, _rnd] = ready_chunks.front();
    1127         [ +  - ]:     1499832 :             std::pop_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
    1128                 :     1499832 :             ready_chunks.pop_back();
    1129         [ +  - ]:     1499832 :             Assume(m_tx_data[chunk_rep].chunk_rep == chunk_rep);
    1130                 :     1499832 :             Assume(chunk_deps[chunk_rep].first == 0);
    1131         [ +  - ]:     1499832 :             const auto& chunk_txn = m_tx_data[chunk_rep].chunk_setinfo.transactions;
    1132                 :             :             // Build heap of all includable transactions in chunk.
    1133   [ +  +  +  + ]:     7070331 :             for (TxIdx tx_idx : chunk_txn) {
    1134         [ +  + ]:     5031467 :                 if (chunk_deps[tx_idx].second == 0) {
    1135                 :     2113838 :                     ready_tx.push_back(tx_idx);
    1136                 :             :                 }
    1137                 :             :             }
    1138                 :     1499832 :             Assume(!ready_tx.empty());
    1139                 :             :             // Pick transactions from the ready queue, append them to linearization, and decrement
    1140                 :             :             // dependency counts.
    1141         [ +  + ]:     6531299 :             while (!ready_tx.empty()) {
    1142                 :             :                 // Move a random queue element to the back.
    1143   [ -  +  -  + ]:     5031467 :                 auto pos = m_rng.randrange(ready_tx.size());
    1144         [ +  + ]:     5031467 :                 if (pos != ready_tx.size() - 1) std::swap(ready_tx.back(), ready_tx[pos]);
    1145                 :             :                 // Pop from the back.
    1146                 :     5031467 :                 auto tx_idx = ready_tx.back();
    1147                 :     5031467 :                 Assume(chunk_txn[tx_idx]);
    1148                 :     5031467 :                 ready_tx.pop_back();
    1149                 :             :                 // Append to linearization.
    1150                 :     5031467 :                 ret.push_back(tx_idx);
    1151                 :             :                 // Decrement dependency counts.
    1152         [ +  + ]:     5031467 :                 auto& tx_data = m_tx_data[tx_idx];
    1153   [ +  +  +  + ]:    20972925 :                 for (TxIdx chl_idx : tx_data.children) {
    1154         [ +  + ]:    14996170 :                     auto& chl_data = m_tx_data[chl_idx];
    1155                 :             :                     // Decrement tx dependency count.
    1156                 :    14996170 :                     Assume(chunk_deps[chl_idx].second > 0);
    1157   [ +  +  +  + ]:    14996170 :                     if (--chunk_deps[chl_idx].second == 0 && chunk_txn[chl_idx]) {
    1158                 :             :                         // Child tx has no dependencies left, and is in this chunk. Add it to the tx queue.
    1159                 :     2917629 :                         ready_tx.push_back(chl_idx);
    1160                 :             :                     }
    1161                 :             :                     // Decrement chunk dependency count if this is out-of-chunk dependency.
    1162         [ +  + ]:    14996170 :                     if (chl_data.chunk_rep != chunk_rep) {
    1163         [ +  + ]:     7859535 :                         Assume(chunk_deps[chl_data.chunk_rep].first > 0);
    1164         [ +  + ]:     7859535 :                         if (--chunk_deps[chl_data.chunk_rep].first == 0) {
    1165                 :             :                             // Child chunk has no dependencies left. Add it to the chunk heap.
    1166                 :     1043834 :                             ready_chunks.emplace_back(chl_data.chunk_rep, m_rng.rand64());
    1167                 :     1043834 :                             std::push_heap(ready_chunks.begin(), ready_chunks.end(), chunk_cmp_fn);
    1168                 :             :                         }
    1169                 :             :                     }
    1170                 :             :                 }
    1171                 :             :             }
    1172                 :             :         }
    1173         [ -  + ]:      188100 :         Assume(ret.size() == m_transaction_idxs.Count());
    1174                 :      188100 :         return ret;
    1175                 :      188100 :     }
    1176                 :             : 
    1177                 :             :     /** Get the diagram for the current state, which must be topological. Test-only.
    1178                 :             :      *
    1179                 :             :      * The linearization produced by GetLinearization() is always at least as good (in the
    1180                 :             :      * CompareChunks() sense) as this diagram, but may be better.
    1181                 :             :      *
    1182                 :             :      * After an OptimizeStep(), the diagram will always be at least as good as before. Once
    1183                 :             :      * OptimizeStep() returns false, the diagram will be equivalent to that produced by
    1184                 :             :      * GetLinearization(), and optimal.
    1185                 :             :      */
    1186                 :             :     std::vector<FeeFrac> GetDiagram() const noexcept
    1187                 :             :     {
    1188                 :             :         std::vector<FeeFrac> ret;
    1189                 :             :         for (auto tx : m_transaction_idxs) {
    1190                 :             :             if (m_tx_data[tx].chunk_rep == tx) {
    1191                 :             :                 ret.push_back(m_tx_data[tx].chunk_setinfo.feerate);
    1192                 :             :             }
    1193                 :             :         }
    1194                 :             :         std::sort(ret.begin(), ret.end(), std::greater{});
    1195                 :             :         return ret;
    1196                 :             :     }
    1197                 :             : 
    1198                 :             :     /** Determine how much work was performed so far. */
    1199                 :     2858667 :     uint64_t GetCost() const noexcept { return m_cost; }
    1200                 :             : 
    1201                 :             :     /** Verify internal consistency of the data structure. */
    1202                 :             :     void SanityCheck(const DepGraph<SetType>& depgraph) const
    1203                 :             :     {
    1204                 :             :         //
    1205                 :             :         // Verify dependency parent/child information, and build list of (active) dependencies.
    1206                 :             :         //
    1207                 :             :         std::vector<std::pair<TxIdx, TxIdx>> expected_dependencies;
    1208                 :             :         std::vector<std::tuple<TxIdx, TxIdx, DepIdx>> all_dependencies;
    1209                 :             :         std::vector<std::tuple<TxIdx, TxIdx, DepIdx>> active_dependencies;
    1210                 :             :         for (auto parent_idx : depgraph.Positions()) {
    1211                 :             :             for (auto child_idx : depgraph.GetReducedChildren(parent_idx)) {
    1212                 :             :                 expected_dependencies.emplace_back(parent_idx, child_idx);
    1213                 :             :             }
    1214                 :             :         }
    1215                 :             :         for (DepIdx dep_idx = 0; dep_idx < m_dep_data.size(); ++dep_idx) {
    1216                 :             :             const auto& dep_data = m_dep_data[dep_idx];
    1217                 :             :             all_dependencies.emplace_back(dep_data.parent, dep_data.child, dep_idx);
    1218                 :             :             // Also add to active_dependencies if it is active.
    1219                 :             :             if (m_dep_data[dep_idx].active) {
    1220                 :             :                 active_dependencies.emplace_back(dep_data.parent, dep_data.child, dep_idx);
    1221                 :             :             }
    1222                 :             :         }
    1223                 :             :         std::sort(expected_dependencies.begin(), expected_dependencies.end());
    1224                 :             :         std::sort(all_dependencies.begin(), all_dependencies.end());
    1225                 :             :         assert(expected_dependencies.size() == all_dependencies.size());
    1226                 :             :         for (size_t i = 0; i < expected_dependencies.size(); ++i) {
    1227                 :             :             assert(expected_dependencies[i] ==
    1228                 :             :                    std::make_pair(std::get<0>(all_dependencies[i]),
    1229                 :             :                                   std::get<1>(all_dependencies[i])));
    1230                 :             :         }
    1231                 :             : 
    1232                 :             :         //
    1233                 :             :         // Verify the chunks against the list of active dependencies
    1234                 :             :         //
    1235                 :             :         for (auto tx_idx: depgraph.Positions()) {
    1236                 :             :             // Only process chunks for now.
    1237                 :             :             if (m_tx_data[tx_idx].chunk_rep == tx_idx) {
    1238                 :             :                 const auto& chunk_data = m_tx_data[tx_idx];
    1239                 :             :                 // Verify that transactions in the chunk point back to it. This guarantees
    1240                 :             :                 // that chunks are non-overlapping.
    1241                 :             :                 for (auto chunk_tx : chunk_data.chunk_setinfo.transactions) {
    1242                 :             :                     assert(m_tx_data[chunk_tx].chunk_rep == tx_idx);
    1243                 :             :                 }
    1244                 :             :                 // Verify the chunk's transaction set: it must contain the representative, and for
    1245                 :             :                 // every active dependency, if it contains the parent or child, it must contain
    1246                 :             :                 // both. It must have exactly N-1 active dependencies in it, guaranteeing it is
    1247                 :             :                 // acyclic.
    1248                 :             :                 SetType expected_chunk = SetType::Singleton(tx_idx);
    1249                 :             :                 while (true) {
    1250                 :             :                     auto old = expected_chunk;
    1251                 :             :                     size_t active_dep_count{0};
    1252                 :             :                     for (const auto& [par, chl, _dep] : active_dependencies) {
    1253                 :             :                         if (expected_chunk[par] || expected_chunk[chl]) {
    1254                 :             :                             expected_chunk.Set(par);
    1255                 :             :                             expected_chunk.Set(chl);
    1256                 :             :                             ++active_dep_count;
    1257                 :             :                         }
    1258                 :             :                     }
    1259                 :             :                     if (old == expected_chunk) {
    1260                 :             :                         assert(expected_chunk.Count() == active_dep_count + 1);
    1261                 :             :                         break;
    1262                 :             :                     }
    1263                 :             :                 }
    1264                 :             :                 assert(chunk_data.chunk_setinfo.transactions == expected_chunk);
    1265                 :             :                 // Verify the chunk's feerate.
    1266                 :             :                 assert(chunk_data.chunk_setinfo.feerate ==
    1267                 :             :                        depgraph.FeeRate(chunk_data.chunk_setinfo.transactions));
    1268                 :             :             }
    1269                 :             :         }
    1270                 :             : 
    1271                 :             :         //
    1272                 :             :         // Verify other transaction data.
    1273                 :             :         //
    1274                 :             :         assert(m_transaction_idxs == depgraph.Positions());
    1275                 :             :         for (auto tx_idx : m_transaction_idxs) {
    1276                 :             :             const auto& tx_data = m_tx_data[tx_idx];
    1277                 :             :             // Verify it has a valid chunk representative, and that chunk includes this
    1278                 :             :             // transaction.
    1279                 :             :             assert(m_tx_data[tx_data.chunk_rep].chunk_rep == tx_data.chunk_rep);
    1280                 :             :             assert(m_tx_data[tx_data.chunk_rep].chunk_setinfo.transactions[tx_idx]);
    1281                 :             :             // Verify parents/children.
    1282                 :             :             assert(tx_data.parents == depgraph.GetReducedParents(tx_idx));
    1283                 :             :             assert(tx_data.children == depgraph.GetReducedChildren(tx_idx));
    1284                 :             :             // Verify list of child dependencies.
    1285                 :             :             std::vector<DepIdx> expected_child_deps;
    1286                 :             :             for (const auto& [par_idx, chl_idx, dep_idx] : all_dependencies) {
    1287                 :             :                 if (tx_idx == par_idx) {
    1288                 :             :                     assert(tx_data.children[chl_idx]);
    1289                 :             :                     expected_child_deps.push_back(dep_idx);
    1290                 :             :                 }
    1291                 :             :             }
    1292                 :             :             std::sort(expected_child_deps.begin(), expected_child_deps.end());
    1293                 :             :             auto child_deps_copy = tx_data.child_deps;
    1294                 :             :             std::sort(child_deps_copy.begin(), child_deps_copy.end());
    1295                 :             :             assert(expected_child_deps == child_deps_copy);
    1296                 :             :         }
    1297                 :             : 
    1298                 :             :         //
    1299                 :             :         // Verify active dependencies' top_setinfo.
    1300                 :             :         //
    1301                 :             :         for (const auto& [par_idx, chl_idx, dep_idx] : active_dependencies) {
    1302                 :             :             const auto& dep_data = m_dep_data[dep_idx];
    1303                 :             :             // Verify the top_info's transactions: it must contain the parent, and for every
    1304                 :             :             // active dependency, except dep_idx itself, if it contains the parent or child, it
    1305                 :             :             // must contain both.
    1306                 :             :             SetType expected_top = SetType::Singleton(par_idx);
    1307                 :             :             while (true) {
    1308                 :             :                 auto old = expected_top;
    1309                 :             :                 for (const auto& [par2_idx, chl2_idx, dep2_idx] : active_dependencies) {
    1310                 :             :                     if (dep2_idx != dep_idx && (expected_top[par2_idx] || expected_top[chl2_idx])) {
    1311                 :             :                         expected_top.Set(par2_idx);
    1312                 :             :                         expected_top.Set(chl2_idx);
    1313                 :             :                     }
    1314                 :             :                 }
    1315                 :             :                 if (old == expected_top) break;
    1316                 :             :             }
    1317                 :             :             assert(!expected_top[chl_idx]);
    1318                 :             :             assert(dep_data.top_setinfo.transactions == expected_top);
    1319                 :             :             // Verify the top_info's feerate.
    1320                 :             :             assert(dep_data.top_setinfo.feerate ==
    1321                 :             :                    depgraph.FeeRate(dep_data.top_setinfo.transactions));
    1322                 :             :         }
    1323                 :             : 
    1324                 :             :         //
    1325                 :             :         // Verify m_suboptimal_chunks.
    1326                 :             :         //
    1327                 :             :         for (size_t i = 0; i < m_suboptimal_chunks.size(); ++i) {
    1328                 :             :             auto tx_idx = m_suboptimal_chunks[i];
    1329                 :             :             assert(m_transaction_idxs[tx_idx]);
    1330                 :             :         }
    1331                 :             :     }
    1332                 :             : };
    1333                 :             : 
    1334                 :             : /** Find or improve a linearization for a cluster.
    1335                 :             :  *
    1336                 :             :  * @param[in] depgraph            Dependency graph of the cluster to be linearized.
    1337                 :             :  * @param[in] max_iterations      Upper bound on the amount of work that will be done.
    1338                 :             :  * @param[in] rng_seed            A random number seed to control search order. This prevents peers
    1339                 :             :  *                                from predicting exactly which clusters would be hard for us to
    1340                 :             :  *                                linearize.
    1341                 :             :  * @param[in] old_linearization   An existing linearization for the cluster (which must be
    1342                 :             :  *                                topologically valid), or empty.
    1343                 :             :  * @return                        A tuple of:
    1344                 :             :  *                                - The resulting linearization. It is guaranteed to be at least as
    1345                 :             :  *                                  good (in the feerate diagram sense) as old_linearization.
    1346                 :             :  *                                - A boolean indicating whether the result is guaranteed to be
    1347                 :             :  *                                  optimal.
    1348                 :             :  *                                - How many optimization steps were actually performed.
    1349                 :             :  */
    1350                 :             : template<typename SetType>
    1351                 :      188100 : std::tuple<std::vector<DepGraphIndex>, bool, uint64_t> Linearize(const DepGraph<SetType>& depgraph, uint64_t max_iterations, uint64_t rng_seed, std::span<const DepGraphIndex> old_linearization = {}) noexcept
    1352                 :             : {
    1353                 :             :     /** Initialize a spanning forest data structure for this cluster. */
    1354         [ +  + ]:      188100 :     SpanningForestState forest(depgraph, rng_seed);
    1355         [ +  + ]:      188100 :     if (!old_linearization.empty()) {
    1356                 :      125570 :         forest.LoadLinearization(old_linearization);
    1357                 :             :     } else {
    1358                 :       62530 :         forest.MakeTopological();
    1359                 :             :     }
    1360                 :             :     // Make improvement steps to it until we hit the max_iterations limit, or an optimal result
    1361                 :             :     // is found.
    1362                 :      188100 :     bool optimal = false;
    1363         [ +  + ]:      188100 :     if (forest.GetCost() < max_iterations) {
    1364                 :      188094 :         forest.StartOptimizing();
    1365                 :             :         do {
    1366         [ +  + ]:     2670561 :             if (!forest.OptimizeStep()) {
    1367                 :             :                 optimal = true;
    1368                 :             :                 break;
    1369                 :             :             }
    1370         [ +  - ]:     2482467 :         } while (forest.GetCost() < max_iterations);
    1371                 :             :     }
    1372                 :      188100 :     return {forest.GetLinearization(), optimal, forest.GetCost()};
    1373                 :      188100 : }
    1374                 :             : 
    1375                 :             : /** Improve a given linearization.
    1376                 :             :  *
    1377                 :             :  * @param[in]     depgraph       Dependency graph of the cluster being linearized.
    1378                 :             :  * @param[in,out] linearization  On input, an existing linearization for depgraph. On output, a
    1379                 :             :  *                               potentially better linearization for the same graph.
    1380                 :             :  *
    1381                 :             :  * Postlinearization guarantees:
    1382                 :             :  * - The resulting chunks are connected.
    1383                 :             :  * - If the input has a tree shape (either all transactions have at most one child, or all
    1384                 :             :  *   transactions have at most one parent), the result is optimal.
    1385                 :             :  * - Given a linearization L1 and a leaf transaction T in it. Let L2 be L1 with T moved to the end,
    1386                 :             :  *   optionally with its fee increased. Let L3 be the postlinearization of L2. L3 will be at least
    1387                 :             :  *   as good as L1. This means that replacing transactions with same-size higher-fee transactions
    1388                 :             :  *   will not worsen linearizations through a "drop conflicts, append new transactions,
    1389                 :             :  *   postlinearize" process.
    1390                 :             :  */
    1391                 :             : template<typename SetType>
    1392         [ -  + ]:        5695 : void PostLinearize(const DepGraph<SetType>& depgraph, std::span<DepGraphIndex> linearization)
    1393                 :             : {
    1394                 :             :     // This algorithm performs a number of passes (currently 2); the even ones operate from back to
    1395                 :             :     // front, the odd ones from front to back. Each results in an equal-or-better linearization
    1396                 :             :     // than the one started from.
    1397                 :             :     // - One pass in either direction guarantees that the resulting chunks are connected.
    1398                 :             :     // - Each direction corresponds to one shape of tree being linearized optimally (forward passes
    1399                 :             :     //   guarantee this for graphs where each transaction has at most one child; backward passes
    1400                 :             :     //   guarantee this for graphs where each transaction has at most one parent).
    1401                 :             :     // - Starting with a backward pass guarantees the moved-tree property.
    1402                 :             :     //
    1403                 :             :     // During an odd (forward) pass, the high-level operation is:
    1404                 :             :     // - Start with an empty list of groups L=[].
    1405                 :             :     // - For every transaction i in the old linearization, from front to back:
    1406                 :             :     //   - Append a new group C=[i], containing just i, to the back of L.
    1407                 :             :     //   - While L has at least one group before C, and the group immediately before C has feerate
    1408                 :             :     //     lower than C:
    1409                 :             :     //     - If C depends on P:
    1410                 :             :     //       - Merge P into C, making C the concatenation of P+C, continuing with the combined C.
    1411                 :             :     //     - Otherwise:
    1412                 :             :     //       - Swap P with C, continuing with the now-moved C.
    1413                 :             :     // - The output linearization is the concatenation of the groups in L.
    1414                 :             :     //
    1415                 :             :     // During even (backward) passes, i iterates from the back to the front of the existing
    1416                 :             :     // linearization, and new groups are prepended instead of appended to the list L. To enable
    1417                 :             :     // more code reuse, both passes append groups, but during even passes the meanings of
    1418                 :             :     // parent/child, and of high/low feerate are reversed, and the final concatenation is reversed
    1419                 :             :     // on output.
    1420                 :             :     //
    1421                 :             :     // In the implementation below, the groups are represented by singly-linked lists (pointing
    1422                 :             :     // from the back to the front), which are themselves organized in a singly-linked circular
    1423                 :             :     // list (each group pointing to its predecessor, with a special sentinel group at the front
    1424                 :             :     // that points back to the last group).
    1425                 :             :     //
    1426                 :             :     // Information about transaction t is stored in entries[t + 1], while the sentinel is in
    1427                 :             :     // entries[0].
    1428                 :             : 
    1429                 :             :     /** Index of the sentinel in the entries array below. */
    1430                 :             :     static constexpr DepGraphIndex SENTINEL{0};
    1431                 :             :     /** Indicator that a group has no previous transaction. */
    1432                 :             :     static constexpr DepGraphIndex NO_PREV_TX{0};
    1433                 :             : 
    1434                 :             : 
    1435                 :             :     /** Data structure per transaction entry. */
    1436                 :       90357 :     struct TxEntry
    1437                 :             :     {
    1438                 :             :         /** The index of the previous transaction in this group; NO_PREV_TX if this is the first
    1439                 :             :          *  entry of a group. */
    1440                 :             :         DepGraphIndex prev_tx;
    1441                 :             : 
    1442                 :             :         // The fields below are only used for transactions that are the last one in a group
    1443                 :             :         // (referred to as tail transactions below).
    1444                 :             : 
    1445                 :             :         /** Index of the first transaction in this group, possibly itself. */
    1446                 :             :         DepGraphIndex first_tx;
    1447                 :             :         /** Index of the last transaction in the previous group. The first group (the sentinel)
    1448                 :             :          *  points back to the last group here, making it a singly-linked circular list. */
    1449                 :             :         DepGraphIndex prev_group;
    1450                 :             :         /** All transactions in the group. Empty for the sentinel. */
    1451                 :             :         SetType group;
    1452                 :             :         /** All dependencies of the group (descendants in even passes; ancestors in odd ones). */
    1453                 :             :         SetType deps;
    1454                 :             :         /** The combined fee/size of transactions in the group. Fee is negated in even passes. */
    1455                 :             :         FeeFrac feerate;
    1456                 :             :     };
    1457                 :             : 
    1458                 :             :     // As an example, consider the state corresponding to the linearization [1,0,3,2], with
    1459                 :             :     // groups [1,0,3] and [2], in an odd pass. The linked lists would be:
    1460                 :             :     //
    1461                 :             :     //                                        +-----+
    1462                 :             :     //                                 0<-P-- | 0 S | ---\     Legend:
    1463                 :             :     //                                        +-----+    |
    1464                 :             :     //                                           ^       |     - digit in box: entries index
    1465                 :             :     //             /--------------F---------+    G       |       (note: one more than tx value)
    1466                 :             :     //             v                         \   |       |     - S: sentinel group
    1467                 :             :     //          +-----+        +-----+        +-----+    |          (empty feerate)
    1468                 :             :     //   0<-P-- | 2   | <--P-- | 1   | <--P-- | 4 T |    |     - T: tail transaction, contains
    1469                 :             :     //          +-----+        +-----+        +-----+    |          fields beyond prev_tv.
    1470                 :             :     //                                           ^       |     - P: prev_tx reference
    1471                 :             :     //                                           G       G     - F: first_tx reference
    1472                 :             :     //                                           |       |     - G: prev_group reference
    1473                 :             :     //                                        +-----+    |
    1474                 :             :     //                                 0<-P-- | 3 T | <--/
    1475                 :             :     //                                        +-----+
    1476                 :             :     //                                         ^   |
    1477                 :             :     //                                         \-F-/
    1478                 :             :     //
    1479                 :             :     // During an even pass, the diagram above would correspond to linearization [2,3,0,1], with
    1480                 :             :     // groups [2] and [3,0,1].
    1481                 :             : 
    1482                 :        5695 :     std::vector<TxEntry> entries(depgraph.PositionRange() + 1);
    1483                 :             : 
    1484                 :             :     // Perform two passes over the linearization.
    1485         [ +  + ]:       17085 :     for (int pass = 0; pass < 2; ++pass) {
    1486                 :       11390 :         int rev = !(pass & 1);
    1487                 :             :         // Construct a sentinel group, identifying the start of the list.
    1488                 :       11390 :         entries[SENTINEL].prev_group = SENTINEL;
    1489                 :       11390 :         Assume(entries[SENTINEL].feerate.IsEmpty());
    1490                 :             : 
    1491                 :             :         // Iterate over all elements in the existing linearization.
    1492         [ +  + ]:      180714 :         for (DepGraphIndex i = 0; i < linearization.size(); ++i) {
    1493                 :             :             // Even passes are from back to front; odd passes from front to back.
    1494         [ +  + ]:      169324 :             DepGraphIndex idx = linearization[rev ? linearization.size() - 1 - i : i];
    1495                 :             :             // Construct a new group containing just idx. In even passes, the meaning of
    1496                 :             :             // parent/child and high/low feerate are swapped.
    1497         [ +  + ]:      169324 :             DepGraphIndex cur_group = idx + 1;
    1498         [ +  + ]:      169324 :             entries[cur_group].group = SetType::Singleton(idx);
    1499   [ +  +  +  + ]:      169324 :             entries[cur_group].deps = rev ? depgraph.Descendants(idx): depgraph.Ancestors(idx);
    1500                 :      169324 :             entries[cur_group].feerate = depgraph.FeeRate(idx);
    1501         [ +  + ]:      169324 :             if (rev) entries[cur_group].feerate.fee = -entries[cur_group].feerate.fee;
    1502                 :      169324 :             entries[cur_group].prev_tx = NO_PREV_TX; // No previous transaction in group.
    1503                 :      169324 :             entries[cur_group].first_tx = cur_group; // Transaction itself is first of group.
    1504                 :             :             // Insert the new group at the back of the groups linked list.
    1505                 :      169324 :             entries[cur_group].prev_group = entries[SENTINEL].prev_group;
    1506                 :      169324 :             entries[SENTINEL].prev_group = cur_group;
    1507                 :             : 
    1508                 :             :             // Start merge/swap cycle.
    1509                 :      169324 :             DepGraphIndex next_group = SENTINEL; // We inserted at the end, so next group is sentinel.
    1510                 :      169324 :             DepGraphIndex prev_group = entries[cur_group].prev_group;
    1511                 :             :             // Continue as long as the current group has higher feerate than the previous one.
    1512         [ +  + ]:      193487 :             while (entries[cur_group].feerate >> entries[prev_group].feerate) {
    1513                 :             :                 // prev_group/cur_group/next_group refer to (the last transactions of) 3
    1514                 :             :                 // consecutive entries in groups list.
    1515         [ +  + ]:       24163 :                 Assume(cur_group == entries[next_group].prev_group);
    1516                 :       24163 :                 Assume(prev_group == entries[cur_group].prev_group);
    1517                 :             :                 // The sentinel has empty feerate, which is neither higher or lower than other
    1518                 :             :                 // feerates. Thus, the while loop we are in here guarantees that cur_group and
    1519                 :             :                 // prev_group are not the sentinel.
    1520                 :       24163 :                 Assume(cur_group != SENTINEL);
    1521                 :       24163 :                 Assume(prev_group != SENTINEL);
    1522         [ +  + ]:       24163 :                 if (entries[cur_group].deps.Overlaps(entries[prev_group].group)) {
    1523                 :             :                     // There is a dependency between cur_group and prev_group; merge prev_group
    1524                 :             :                     // into cur_group. The group/deps/feerate fields of prev_group remain unchanged
    1525                 :             :                     // but become unused.
    1526                 :       23488 :                     entries[cur_group].group |= entries[prev_group].group;
    1527                 :       23488 :                     entries[cur_group].deps |= entries[prev_group].deps;
    1528                 :       23488 :                     entries[cur_group].feerate += entries[prev_group].feerate;
    1529                 :             :                     // Make the first of the current group point to the tail of the previous group.
    1530                 :       23488 :                     entries[entries[cur_group].first_tx].prev_tx = prev_group;
    1531                 :             :                     // The first of the previous group becomes the first of the newly-merged group.
    1532                 :       23488 :                     entries[cur_group].first_tx = entries[prev_group].first_tx;
    1533                 :             :                     // The previous group becomes whatever group was before the former one.
    1534                 :       23488 :                     prev_group = entries[prev_group].prev_group;
    1535                 :       23488 :                     entries[cur_group].prev_group = prev_group;
    1536                 :             :                 } else {
    1537                 :             :                     // There is no dependency between cur_group and prev_group; swap them.
    1538                 :         675 :                     DepGraphIndex preprev_group = entries[prev_group].prev_group;
    1539                 :             :                     // If PP, P, C, N were the old preprev, prev, cur, next groups, then the new
    1540                 :             :                     // layout becomes [PP, C, P, N]. Update prev_groups to reflect that order.
    1541                 :         675 :                     entries[next_group].prev_group = prev_group;
    1542                 :         675 :                     entries[prev_group].prev_group = cur_group;
    1543                 :         675 :                     entries[cur_group].prev_group = preprev_group;
    1544                 :             :                     // The current group remains the same, but the groups before/after it have
    1545                 :             :                     // changed.
    1546                 :         675 :                     next_group = prev_group;
    1547                 :         675 :                     prev_group = preprev_group;
    1548                 :             :                 }
    1549                 :             :             }
    1550                 :             :         }
    1551                 :             : 
    1552                 :             :         // Convert the entries back to linearization (overwriting the existing one).
    1553                 :       11390 :         DepGraphIndex cur_group = entries[0].prev_group;
    1554                 :       11390 :         DepGraphIndex done = 0;
    1555         [ +  + ]:      157226 :         while (cur_group != SENTINEL) {
    1556                 :      145836 :             DepGraphIndex cur_tx = cur_group;
    1557                 :             :             // Traverse the transactions of cur_group (from back to front), and write them in the
    1558                 :             :             // same order during odd passes, and reversed (front to back) in even passes.
    1559         [ +  + ]:      145836 :             if (rev) {
    1560                 :             :                 do {
    1561         [ +  + ]:       84662 :                     *(linearization.begin() + (done++)) = cur_tx - 1;
    1562         [ +  + ]:       84662 :                     cur_tx = entries[cur_tx].prev_tx;
    1563         [ +  + ]:       84662 :                 } while (cur_tx != NO_PREV_TX);
    1564                 :             :             } else {
    1565                 :             :                 do {
    1566         [ +  + ]:       84662 :                     *(linearization.end() - (++done)) = cur_tx - 1;
    1567         [ +  + ]:       84662 :                     cur_tx = entries[cur_tx].prev_tx;
    1568         [ +  + ]:       84662 :                 } while (cur_tx != NO_PREV_TX);
    1569                 :             :             }
    1570                 :      145836 :             cur_group = entries[cur_group].prev_group;
    1571                 :             :         }
    1572                 :       11390 :         Assume(done == linearization.size());
    1573                 :             :     }
    1574                 :        5695 : }
    1575                 :             : 
    1576                 :             : /** Make linearization topological, retaining its ordering where possible. */
    1577                 :             : template<typename SetType>
    1578                 :       64060 : void FixLinearization(const DepGraph<SetType>& depgraph, std::span<DepGraphIndex> linearization) noexcept
    1579                 :             : {
    1580                 :             :     // This algorithm can be summarized as moving every element in the linearization backwards
    1581                 :             :     // until it is placed after all its ancestors.
    1582                 :       64060 :     SetType done;
    1583                 :       64060 :     const auto len = linearization.size();
    1584                 :             :     // Iterate over the elements of linearization from back to front (i is distance from back).
    1585         [ +  + ]:     1754022 :     for (DepGraphIndex i = 0; i < len; ++i) {
    1586                 :             :         /** The element at that position. */
    1587                 :     1689962 :         DepGraphIndex elem = linearization[len - 1 - i];
    1588                 :             :         /** j represents how far from the back of the linearization elem should be placed. */
    1589                 :     1689962 :         DepGraphIndex j = i;
    1590                 :             :         // Figure out which elements need to be moved before elem.
    1591                 :     1689962 :         SetType place_before = done & depgraph.Ancestors(elem);
    1592                 :             :         // Find which position to place elem in (updating j), continuously moving the elements
    1593                 :             :         // in between forward.
    1594         [ +  + ]:    15512475 :         while (place_before.Any()) {
    1595                 :             :             // j cannot be 0 here; if it was, then there was necessarily nothing earlier which
    1596                 :             :             // elem needs to be placed before anymore, and place_before would be empty.
    1597                 :     7708602 :             Assume(j > 0);
    1598                 :     7708602 :             auto to_swap = linearization[len - 1 - (j - 1)];
    1599                 :     7708602 :             place_before.Reset(to_swap);
    1600                 :     7708602 :             linearization[len - 1 - (j--)] = to_swap;
    1601                 :             :         }
    1602                 :             :         // Put elem in its final position and mark it as done.
    1603                 :     1689962 :         linearization[len - 1 - j] = elem;
    1604                 :     1689962 :         done.Set(elem);
    1605                 :             :     }
    1606                 :       64060 : }
    1607                 :             : 
    1608                 :             : } // namespace cluster_linearize
    1609                 :             : 
    1610                 :             : #endif // BITCOIN_CLUSTER_LINEARIZE_H
        

Generated by: LCOV version 2.0-1