From f4b1b24a3bcd0199a6d2e828ad46033e1368336e Mon Sep 17 00:00:00 2001 From: glozow Date: Fri, 14 Jul 2023 11:28:00 +0100 Subject: [PATCH] [MiniMiner] track inclusion order and add Linearize() function Sometimes we are just interested in the order in which transactions would be included in a block (we want to "linearize" the transactions). Track and store this information. This doesn't change any of the bump fee calculations. --- src/node/mini_miner.cpp | 16 ++++++++++++++++ src/node/mini_miner.h | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/node/mini_miner.cpp b/src/node/mini_miner.cpp index ea702ab7343..3d24a3f58eb 100644 --- a/src/node/mini_miner.cpp +++ b/src/node/mini_miner.cpp @@ -170,6 +170,7 @@ MiniMiner::MiniMiner(const std::vector& manual_entries, Assume(m_to_be_replaced.empty()); Assume(m_requested_outpoints_by_txid.empty()); Assume(m_bump_fees.empty()); + Assume(m_inclusion_order.empty()); SanityCheck(); } @@ -255,6 +256,7 @@ void MiniMiner::SanityCheck() const void MiniMiner::BuildMockTemplate(std::optional target_feerate) { const auto num_txns{m_entries_by_txid.size()}; + uint32_t sequence_num{0}; while (!m_entries_by_txid.empty()) { // Sort again, since transaction removal may change some m_entries' ancestor feerates. std::sort(m_entries.begin(), m_entries.end(), AncestorFeerateComparator()); @@ -290,18 +292,32 @@ void MiniMiner::BuildMockTemplate(std::optional target_feerate) to_process.erase(iter); } } + // Track the order in which transactions were selected. + for (const auto& ancestor : ancestors) { + m_inclusion_order.emplace(Txid::FromUint256(ancestor->first), sequence_num); + } DeleteAncestorPackage(ancestors); SanityCheck(); + ++sequence_num; } if (!target_feerate.has_value()) { Assume(m_in_block.size() == num_txns); } else { Assume(m_in_block.empty() || m_total_fees >= target_feerate->GetFee(m_total_vsize)); } + Assume(m_in_block.empty() || sequence_num > 0); + Assume(m_in_block.size() == m_inclusion_order.size()); // Do not try to continue building the block template with a different feerate. m_ready_to_calculate = false; } + +std::map MiniMiner::Linearize() +{ + BuildMockTemplate(std::nullopt); + return m_inclusion_order; +} + std::map MiniMiner::CalculateBumpFees(const CFeeRate& target_feerate) { if (!m_ready_to_calculate) return {}; diff --git a/src/node/mini_miner.h b/src/node/mini_miner.h index e0051f33640..8f86709ae4e 100644 --- a/src/node/mini_miner.h +++ b/src/node/mini_miner.h @@ -67,8 +67,14 @@ struct IteratorComparator } }; -/** A minimal version of BlockAssembler. Allows us to run the mining algorithm on a subset of - * mempool transactions, ignoring consensus rules, to calculate mining scores. */ +/** A minimal version of BlockAssembler, using the same ancestor set scoring algorithm. Allows us to + * run this algorithm on a limited set of transactions (e.g. subset of mempool or transactions that + * are not yet in mempool) instead of the entire mempool, ignoring consensus rules. + * Callers may use this to: + * - Calculate the "bump fee" needed to spend an unconfirmed UTXO at a given feerate + * - "Linearize" a list of transactions to see the order in which they would be selected for + * inclusion in a block + */ class MiniMiner { // When true, a caller may use CalculateBumpFees(). Becomes false if we failed to retrieve @@ -84,6 +90,10 @@ class MiniMiner // the same tx will have the same bumpfee. Excludes non-mempool transactions. std::map> m_requested_outpoints_by_txid; + // Txid to a number representing the order in which this transaction was included (smaller + // number = included earlier). Transactions included in an ancestor set together have the same + // sequence number. + std::map m_inclusion_order; // What we're trying to calculate. Outpoint to the fee needed to bring the transaction to the target feerate. std::map m_bump_fees; @@ -151,6 +161,11 @@ public: * if it cannot be calculated. */ std::optional CalculateTotalBumpFees(const CFeeRate& target_feerate); + /** Construct a new block template with all of the transactions and calculate the order in which + * they are selected. Returns the sequence number (lower = selected earlier) with which each + * transaction was selected, indexed by txid, or an empty map if it cannot be calculated. + */ + std::map Linearize(); }; } // namespace node