@@ -1945,23 +1945,16 @@ class CompareInvMempoolOrder
19451945{
19461946 CTxMemPool *mp;
19471947public:
1948- CompareInvMempoolOrder (CTxMemPool *mempool )
1948+ CompareInvMempoolOrder (CTxMemPool *_mempool )
19491949 {
1950- mp = mempool ;
1950+ mp = _mempool ;
19511951 }
19521952
1953- bool operator ()(const CInv & a, const CInv & b)
1953+ bool operator ()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)
19541954 {
1955- if (a.type != MSG_TX && b.type != MSG_TX) {
1956- return false ;
1957- } else {
1958- if (a.type != MSG_TX) {
1959- return true ;
1960- } else if (b.type != MSG_TX) {
1961- return false ;
1962- }
1963- return mp->CompareDepthAndScore (a.hash , b.hash );
1964- }
1955+ /* As std::make_heap produces a max-heap, we want the entries with the
1956+ * fewest ancestors/highest fee to sort later. */
1957+ return mp->CompareDepthAndScore (*b, *a);
19651958 }
19661959};
19671960
@@ -2088,36 +2081,68 @@ bool SendMessages(CNode* pto, CConnman& connman, std::atomic<bool>& interruptMsg
20882081 std::vector<CInv> vInv;
20892082 std::vector<CInv> vInvWait;
20902083 {
2084+ LOCK (pto->cs_inventory );
2085+ vInv.reserve (std::max<size_t >(pto->vInventoryBlockToSend .size (), INVENTORY_BROADCAST_MAX));
2086+
2087+ // Add blocks
2088+ for (const uint256& hash : pto->vInventoryBlockToSend ) {
2089+ vInv.emplace_back (CInv (MSG_BLOCK, hash));
2090+ if (vInv.size () == MAX_INV_SZ) {
2091+ connman.PushMessage (pto, msgMaker.Make (NetMsgType::INV, vInv));
2092+ vInv.clear ();
2093+ }
2094+ }
2095+ pto->vInventoryBlockToSend .clear ();
2096+
2097+ // Add tier two INVs
2098+ for (const CInv& tInv : pto->vInventoryTierTwoToSend ) {
2099+ vInv.emplace_back (tInv);
2100+ if (vInv.size () == MAX_INV_SZ) {
2101+ connman.PushMessage (pto, msgMaker.Make (NetMsgType::INV, vInv));
2102+ vInv.clear ();
2103+ }
2104+ }
2105+ pto->vInventoryTierTwoToSend .clear ();
2106+
2107+ // Determine transactions to relay
20912108 bool fSendTrickle = pto->fWhitelisted ;
20922109 if (pto->nNextInvSend < nNow) {
20932110 fSendTrickle = true ;
2094- // Use half the delay for outbound peers, as their is less privacy concern for them.
2111+ // Use half the delay for outbound peers, as there is less privacy concern for them.
20952112 pto->nNextInvSend = PoissonNextSend (nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound );
20962113 }
2097- LOCK (pto->cs_inventory );
2098- if (fSendTrickle && pto->vInventoryToSend .size () > 1 ) {
2114+ if (fSendTrickle ) {
2115+ // Produce a vector with all candidates for sending
2116+ std::vector<std::set<uint256>::iterator> vInvTx;
2117+ vInvTx.reserve (pto->setInventoryTxToSend .size ());
2118+ for (std::set<uint256>::iterator it = pto->setInventoryTxToSend .begin (); it != pto->setInventoryTxToSend .end (); it++) {
2119+ vInvTx.push_back (it);
2120+ }
20992121 // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
2122+ // A heap is used so that not all items need sorting if only a few are being sent.
21002123 CompareInvMempoolOrder compareInvMempoolOrder (&mempool);
2101- std::stable_sort (pto->vInventoryToSend .begin (), pto->vInventoryToSend .end (), compareInvMempoolOrder);
2102- }
2103- vInv.reserve (std::min<size_t >(INVENTORY_BROADCAST_MAX, pto->vInventoryToSend .size ()));
2104- vInvWait.reserve (pto->vInventoryToSend .size ());
2105- for (const CInv& inv : pto->vInventoryToSend ) {
2106- if (inv.type == MSG_TX && pto->filterInventoryKnown .contains (inv.hash ))
2107- continue ;
2108-
2124+ std::make_heap (vInvTx.begin (), vInvTx.end (), compareInvMempoolOrder);
21092125 // No reason to drain out at many times the network's capacity,
21102126 // especially since we have many peers and some will draw much shorter delays.
2111- if (vInv.size () >= INVENTORY_BROADCAST_MAX || (inv.type == MSG_TX && !fSendTrickle )) {
2112- vInvWait.push_back (inv);
2113- continue ;
2127+ unsigned int nRelayedTransactions = 0 ;
2128+ while (!vInvTx.empty () && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
2129+ // Fetch the top element from the heap
2130+ std::pop_heap (vInvTx.begin (), vInvTx.end (), compareInvMempoolOrder);
2131+ std::set<uint256>::iterator it = vInvTx.back ();
2132+ vInvTx.pop_back ();
2133+ uint256 hash = *it;
2134+ // Remove it from the to-be-sent set
2135+ pto->setInventoryTxToSend .erase (it);
2136+ // Check if not in the filter already
2137+ if (pto->filterInventoryKnown .contains (hash)) {
2138+ continue ;
2139+ }
2140+ // Send
2141+ vInv.emplace_back (CInv (MSG_TX, hash));
2142+ nRelayedTransactions++;
2143+ pto->filterInventoryKnown .insert (hash);
21142144 }
2115-
2116- pto->filterInventoryKnown .insert (inv.hash );
2117-
2118- vInv.push_back (inv);
21192145 }
2120- pto->vInventoryToSend = vInvWait;
21212146 }
21222147 if (!vInv.empty ())
21232148 connman.PushMessage (pto, msgMaker.Make (NetMsgType::INV, vInv));
0 commit comments