Construct a topologically-valid linearization from the current forest state. Must be * topological. fallback_order is a comparator that defines a strong order for DepGraphIndexes * in this cluster, used to order equal-feerate transactions and chunks. * * Specifically, the resulting order consists of: * - The chunks of the current SFL state, sorted by (in decreasing order
| 1463 | * - the lowest transaction, by fallback_order, first |
| 1464 | */ |
| 1465 | std::vector<DepGraphIndex> GetLinearization(const StrongComparator<DepGraphIndex> auto& fallback_order) noexcept |
| 1466 | { |
| 1467 | m_cost.GetLinearizationBegin(); |
| 1468 | /** The output linearization. */ |
| 1469 | std::vector<DepGraphIndex> ret; |
| 1470 | ret.reserve(m_set_info.size()); |
| 1471 | /** A heap with all chunks (by set index) that can currently be included, sorted by |
| 1472 | * chunk feerate (high to low), chunk size (small to large), and by least maximum element |
| 1473 | * according to the fallback order (which is the second pair element). */ |
| 1474 | std::vector<std::pair<SetIdx, TxIdx>> ready_chunks; |
| 1475 | /** For every chunk, indexed by SetIdx, the number of unmet dependencies the chunk has on |
| 1476 | * other chunks (not including dependencies within the chunk itself). */ |
| 1477 | std::vector<TxIdx> chunk_deps(m_set_info.size(), 0); |
| 1478 | /** For every transaction, indexed by TxIdx, the number of unmet dependencies the |
| 1479 | * transaction has. */ |
| 1480 | std::vector<TxIdx> tx_deps(m_tx_data.size(), 0); |
| 1481 | /** A heap with all transactions within the current chunk that can be included, sorted by |
| 1482 | * tx feerate (high to low), tx size (small to large), and fallback order. */ |
| 1483 | std::vector<TxIdx> ready_tx; |
| 1484 | // Populate chunk_deps and tx_deps. |
| 1485 | unsigned num_deps{0}; |
| 1486 | for (TxIdx chl_idx : m_transaction_idxs) { |
| 1487 | const auto& chl_data = m_tx_data[chl_idx]; |
| 1488 | tx_deps[chl_idx] = chl_data.parents.Count(); |
| 1489 | num_deps += tx_deps[chl_idx]; |
| 1490 | auto chl_chunk_idx = chl_data.chunk_idx; |
| 1491 | auto& chl_chunk_info = m_set_info[chl_chunk_idx]; |
| 1492 | chunk_deps[chl_chunk_idx] += (chl_data.parents - chl_chunk_info.transactions).Count(); |
| 1493 | } |
| 1494 | /** Function to compute the highest element of a chunk, by fallback_order. */ |
| 1495 | auto max_fallback_fn = [&](SetIdx chunk_idx) noexcept { |
| 1496 | auto& chunk = m_set_info[chunk_idx].transactions; |
| 1497 | auto it = chunk.begin(); |
| 1498 | DepGraphIndex ret = *it; |
| 1499 | ++it; |
| 1500 | while (it != chunk.end()) { |
| 1501 | if (fallback_order(*it, ret) > 0) ret = *it; |
| 1502 | ++it; |
| 1503 | } |
| 1504 | return ret; |
| 1505 | }; |
| 1506 | /** Comparison function for the transaction heap. Note that it is a max-heap, so |
| 1507 | * tx_cmp_fn(a, b) == true means "a appears after b in the linearization". */ |
| 1508 | auto tx_cmp_fn = [&](const auto& a, const auto& b) noexcept { |
| 1509 | // Bail out for identical transactions. |
| 1510 | if (a == b) return false; |
| 1511 | // First sort by increasing transaction feerate. |
| 1512 | auto& a_feerate = m_depgraph.FeeRate(a); |
| 1513 | auto& b_feerate = m_depgraph.FeeRate(b); |
| 1514 | auto feerate_cmp = ByRatio{a_feerate} <=> ByRatio{b_feerate}; |
| 1515 | if (feerate_cmp != 0) return feerate_cmp < 0; |
| 1516 | // Then by decreasing transaction size. |
| 1517 | if (a_feerate.size != b_feerate.size) { |
| 1518 | return a_feerate.size > b_feerate.size; |
| 1519 | } |
| 1520 | // Tie-break by decreasing fallback_order. |
| 1521 | auto fallback_cmp = fallback_order(a, b); |
| 1522 | if (fallback_cmp != 0) return fallback_cmp > 0; |