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

Code before:
                    // 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());
                        // Remove it from the to-be-sent set
                        tx_relay->m_tx_inventory_to_send.erase(it);
                        // Check if not in the filter already
                        if (tx_relay->m_tx_inventory_known_filter.contains(hash.ToUint256())) {
                            continue;
                        }
                        // Not in the mempool anymore? don't bother sending it.
                        auto txinfo{std::visit([&](const auto& id) { return m_mempool.info(id); }, hash)};
                        if (!txinfo.tx) {
                            continue;
                        }
                        // Peer told you to not send transactions at that feerate? Don't bother sending it.
                        if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
                            continue;
                        }
                        if (tx_relay->m_bloom_filter && !tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
                        // Send
                        vInv.push_back(inv);
                        nRelayedTransactions++;
                        if (vInv.size() == MAX_INV_SZ) {
                            MakeAndPushMessage(*pto, NetMsgType::INV, vInv);
                            vInv.clear();
                        }
                        tx_relay->m_tx_inventory_known_filter.insert(hash.ToUint256());
                    }

                    // Ensure we'll respond to GETDATA requests for anything we've just announced
                    LOCK(m_mempool.cs);
                    tx_relay->m_last_inv_sequence = m_mempool.GetSequence();
                }
        }
        if (!vInv.empty())
            MakeAndPushMessage(*pto, NetMsgType::INV, vInv);


Review comment (suggestion):
Might be worth a comment because non-obvious: `m_tx_inventory_known_filter` hashes are based on the wtxidrelay-ness of the peer, so it's important that we compare the hash from `inv` and not the wtxid that was in `m_tx_inventory_to_send`.

Code after:
                    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);
                        if (!txinfo.tx) {
                            continue;
                        }
                        // `TxRelay::m_tx_inventory_known_filter` contains either txids or wtxids
                        // depending on whether our peer supports wtxid-relay. Therefore, first
                        // construct the inv and then use its hash for the filter check.
                        const auto inv = peer->m_wtxid_relay ?
                                             CInv{MSG_WTX, wtxid.ToUint256()} :
                                             CInv{MSG_TX, txinfo.tx->GetHash().ToUint256()};
                        // Check if not in the filter already
                        if (tx_relay->m_tx_inventory_known_filter.contains(inv.hash)) {
                            continue;
                        }
                        // Peer told you to not send transactions at that feerate? Don't bother sending it.
                        if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
                            continue;
                        }
                        if (tx_relay->m_bloom_filter && !tx_relay->m_bloom_filter->IsRelevantAndUpdate(*txinfo.tx)) continue;
                        // Send
                        vInv.push_back(inv);
                        nRelayedTransactions++;
                        if (vInv.size() == MAX_INV_SZ) {
                            MakeAndPushMessage(*pto, NetMsgType::INV, vInv);
                            vInv.clear();
                        }
                        tx_relay->m_tx_inventory_known_filter.insert(inv.hash);
                    }

                    // Ensure we'll respond to GETDATA requests for anything we've just announced
                    LOCK(m_mempool.cs);
                    tx_relay->m_last_inv_sequence = m_mempool.GetSequence();
                }
        }
        if (!vInv.empty())