Repository: bitcoin/bitcoin
File: src/net_processing.cpp (C++)

Code before:
                        CInv inv{
                            peer->m_wtxid_relay ? MSG_WTX : MSG_TX,
                            peer->m_wtxid_relay ?
                                txinfo.tx->GetWitnessHash().ToUint256() :
                                txinfo.tx->GetHash().ToUint256(),
                        };
                        tx_relay->m_tx_inventory_to_send.erase(ToGenTxid(inv));

                        // Don't send transactions that peers will not put into their mempool
                        if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
                            continue;
                        }
                        if (tx_relay->m_bloom_filter) {
                            if (!tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
                        }
                        tx_relay->m_tx_inventory_known_filter.insert(inv.hash);
                        vInv.push_back(inv);
                        if (vInv.size() == MAX_INV_SZ) {
                            MakeAndPushMessage(*pto, NetMsgType::INV, vInv);
                            vInv.clear();
                        }
                    }
                }

                // Determine transactions to relay
                if (fSendTrickle) {
                    // Produce a vector with all candidates for sending
                    std::vector<std::set<GenTxid>::iterator> vInvTx;
                    vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
                    for (std::set<GenTxid>::iterator it = tx_relay->m_tx_inventory_to_send.begin(); it != tx_relay->m_tx_inventory_to_send.end(); it++) {
                        vInvTx.push_back(it);
                    }
                    const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
                    // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
                    // A heap is used so that not all items need sorting if only a few are being sent.
                    CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
                    std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
                    // No reason to drain out at many times the network's capacity,
                    // especially since we have many peers and some will draw much shorter delays.
                    unsigned int nRelayedTransactions = 0;
                    LOCK(tx_relay->m_bloom_filter_mutex);
                    size_t broadcast_max{INVENTORY_BROADCAST_TARGET + (tx_relay->m_tx_inventory_to_send.size()/1000)*5};
                    broadcast_max = std::min<size_t>(INVENTORY_BROADCAST_MAX, broadcast_max);
                    while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) {
                        // Fetch the top element from the heap
                        std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
                        std::set<GenTxid>::iterator it = vInvTx.back();
                        vInvTx.pop_back();
                        GenTxid hash = *it;
                        Assume(peer->m_wtxid_relay == hash.IsWtxid());
                        CInv inv(peer->m_wtxid_relay ? MSG_WTX : MSG_TX, hash.ToUint256());

Review comment (suggestion):
nit: this is touching a lot more code than you are, but modernizing this bit of code would make it more readable:

<details>
<summary>git diff on 94b39ce738</summary>

```diff
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 165f6e822f..a9dafb7160 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -5780,28 +5780,23 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
 
                 // Determine transactions to relay
                 if (fSendTrickle) {
-                    // Produce a vector with all candidates for sending
-                    std::vector<std::set<Wtxid>::iterator> vInvTx;
-                    vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
-                    for (std::set<Wtxid>::iterator it = tx_relay->m_tx_inventory_to_send.begin(); it != tx_relay->m_tx_inventory_to_send.end(); it++) {
-                        vInvTx.push_back(it);
-                    }
                     const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
                     // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
-                    // A heap is used so that not all items need sorting if only a few are being sent.
                     CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
-                    std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
+                    auto tx_inv_iters{std::views::iota(tx_relay->m_tx_inventory_to_send.begin(),
+                                                       tx_relay->m_tx_inventory_to_send.end())};
+                    // A priority queue is used so that not all items need sorting if only a few are being sent.
+                    std::priority_queue tx_inv_to_send{tx_inv_iters.begin(), tx_inv_iters.end(),
+                                                       compareInvMempoolOrder};
                     // No reason to drain out at many times the network's capacity,
                     // especially since we have many peers and some will draw much shorter delays.
                     unsigned int nRelayedTransactions = 0;
                     LOCK(tx_relay->m_bloom_filter_mutex);
                     size_t broadcast_max{INVENTORY_BROADCAST_TARGET + (tx_relay->m_tx_inventory_to_send.size()/1000)*5};
                     broadcast_max = std::min<size_t>(INVENTORY_BROADCAST_MAX, broadcast_max);
-                    while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) {
-                        // Fetch the top element from the heap
-                        std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
-                        std::set<Wtxid>::iterator it = vInvTx.back();
-                        vInvTx.pop_back();
+                    while (!tx_inv_to_send.empty() && nRelayedTransactions < broadcast_max) {
+                        std::set<Wtxid>::iterator it = tx_inv_to_send.top();
+                        tx_inv_to_send.pop();
                         auto wtxid = *it;
                         // Remove it from the to-be-sent set
                         tx_relay->m_tx_inventory_to_send.erase(it);

```
</details>


Code after:
                        const Wtxid& wtxid{txinfo.tx->GetWitnessHash()};
                        const auto inv = peer->m_wtxid_relay ?
                                             CInv{MSG_WTX, wtxid.ToUint256()} :
                                             CInv{MSG_TX, txid.ToUint256()};
                        tx_relay->m_tx_inventory_to_send.erase(wtxid);

                        // Don't send transactions that peers will not put into their mempool
                        if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
                            continue;
                        }
                        if (tx_relay->m_bloom_filter) {
                            if (!tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
                        }
                        tx_relay->m_tx_inventory_known_filter.insert(inv.hash);
                        vInv.push_back(inv);
                        if (vInv.size() == MAX_INV_SZ) {
                            MakeAndPushMessage(*pto, NetMsgType::INV, vInv);
                            vInv.clear();
                        }
                    }
                }

                // Determine transactions to relay
                if (fSendTrickle) {
                    // Produce a vector with all candidates for sending
                    std::vector<std::set<Wtxid>::iterator> vInvTx;
                    vInvTx.reserve(tx_relay->m_tx_inventory_to_send.size());
                    for (std::set<Wtxid>::iterator it = tx_relay->m_tx_inventory_to_send.begin(); it != tx_relay->m_tx_inventory_to_send.end(); it++) {
                        vInvTx.push_back(it);
                    }
                    const CFeeRate filterrate{tx_relay->m_fee_filter_received.load()};
                    // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
                    // A heap is used so that not all items need sorting if only a few are being sent.
                    CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool);
                    std::make_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
                    // No reason to drain out at many times the network's capacity,
                    // especially since we have many peers and some will draw much shorter delays.
                    unsigned int nRelayedTransactions = 0;
                    LOCK(tx_relay->m_bloom_filter_mutex);
                    size_t broadcast_max{INVENTORY_BROADCAST_TARGET + (tx_relay->m_tx_inventory_to_send.size()/1000)*5};
                    broadcast_max = std::min<size_t>(INVENTORY_BROADCAST_MAX, broadcast_max);
                    while (!vInvTx.empty() && nRelayedTransactions < broadcast_max) {
                        // Fetch the top element from the heap
                        std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
                        std::set<Wtxid>::iterator it = vInvTx.back();
                        vInvTx.pop_back();
                        auto wtxid = *it;
                        // Remove it from the to-be-sent set
                        tx_relay->m_tx_inventory_to_send.erase(it);
                        // Not in the mempool anymore? don't bother sending it.
                        auto txinfo = m_mempool.info(wtxid);