| 22 | namespace node { |
| 23 | |
| 24 | MiniMiner::MiniMiner(const CTxMemPool& mempool, const std::vector<COutPoint>& outpoints) |
| 25 | { |
| 26 | LOCK(mempool.cs); |
| 27 | // Find which outpoints to calculate bump fees for. |
| 28 | // Anything that's spent by the mempool is to-be-replaced |
| 29 | // Anything otherwise unavailable just has a bump fee of 0 |
| 30 | for (const auto& outpoint : outpoints) { |
| 31 | if (!mempool.exists(outpoint.hash)) { |
| 32 | // This UTXO is either confirmed or not yet submitted to mempool. |
| 33 | // If it's confirmed, no bump fee is required. |
| 34 | // If it's not yet submitted, we have no information, so return 0. |
| 35 | m_bump_fees.emplace(outpoint, 0); |
| 36 | continue; |
| 37 | } |
| 38 | |
| 39 | // UXTO is created by transaction in mempool, add to map. |
| 40 | // Note: This will either create a missing entry or add the outpoint to an existing entry |
| 41 | m_requested_outpoints_by_txid[outpoint.hash].push_back(outpoint); |
| 42 | |
| 43 | if (const auto ptx{mempool.GetConflictTx(outpoint)}) { |
| 44 | // This outpoint is already being spent by another transaction in the mempool. We |
| 45 | // assume that the caller wants to replace this transaction and its descendants. It |
| 46 | // would be unusual for the transaction to have descendants as the wallet won’t normally |
| 47 | // attempt to replace transactions with descendants. If the outpoint is from a mempool |
| 48 | // transaction, we still need to calculate its ancestors bump fees (added to |
| 49 | // m_requested_outpoints_by_txid below), but after removing the to-be-replaced entries. |
| 50 | // |
| 51 | // Note that the descendants of a transaction include the transaction itself. Also note, |
| 52 | // that this is only calculating bump fees. RBF fee rules should be handled separately. |
| 53 | CTxMemPool::setEntries descendants; |
| 54 | mempool.CalculateDescendants(mempool.GetIter(ptx->GetHash()).value(), descendants); |
| 55 | for (const auto& desc_txiter : descendants) { |
| 56 | m_to_be_replaced.insert(desc_txiter->GetTx().GetHash()); |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // No unconfirmed UTXOs, so nothing mempool-related needs to be calculated. |
| 62 | if (m_requested_outpoints_by_txid.empty()) return; |
| 63 | |
| 64 | // Calculate the cluster and construct the entry map. |
| 65 | auto txids_needed{m_requested_outpoints_by_txid | std::views::keys}; |
| 66 | const auto cluster = mempool.GatherClusters({txids_needed.begin(), txids_needed.end()}); |
| 67 | if (cluster.empty()) { |
| 68 | // An empty cluster means that at least one of the transactions is missing from the mempool |
| 69 | // (should not be possible given processing above) or DoS limit was hit. |
| 70 | m_ready_to_calculate = false; |
| 71 | return; |
| 72 | } |
| 73 | |
| 74 | // Add every entry to m_entries_by_txid and m_entries, except the ones that will be replaced. |
| 75 | for (const auto& txiter : cluster) { |
| 76 | if (!m_to_be_replaced.contains(txiter->GetTx().GetHash())) { |
| 77 | auto [ancestor_count, ancestor_size, ancestor_fee] = mempool.CalculateAncestorData(*txiter); |
| 78 | auto [mapiter, success] = m_entries_by_txid.emplace(txiter->GetTx().GetHash(), |
| 79 | MiniMinerMempoolEntry{/*tx_in=*/txiter->GetSharedTx(), |
| 80 | /*vsize_self=*/txiter->GetTxSize(), |
| 81 | /*vsize_ancestor=*/int64_t(ancestor_size), |
nothing calls this directly
no test coverage detected