@@ -5569,18 +5569,11 @@ class CompareInvMempoolOrder
5569
5569
mp = mempool;
5570
5570
}
5571
5571
5572
- bool operator ()(const CInv & a, const CInv & b)
5572
+ bool operator ()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)
5573
5573
{
5574
- if (a.type != MSG_TX && b.type != MSG_TX) {
5575
- return false ;
5576
- } else {
5577
- if (a.type != MSG_TX) {
5578
- return true ;
5579
- } else if (b.type != MSG_TX) {
5580
- return false ;
5581
- }
5582
- return mp->CompareDepthAndScore (a.hash , b.hash );
5583
- }
5574
+ /* As std::make_heap produces a max-heap, we want the entries with the
5575
+ * fewest ancestors/highest fee to sort later. */
5576
+ return mp->CompareDepthAndScore (*b, *a);
5584
5577
}
5585
5578
};
5586
5579
@@ -5808,38 +5801,59 @@ bool SendMessages(CNode* pto)
5808
5801
// Message: inventory
5809
5802
//
5810
5803
vector<CInv> vInv;
5811
- vector<CInv> vInvWait;
5812
5804
{
5805
+ LOCK (pto->cs_inventory );
5806
+ vInv.reserve (std::max<size_t >(pto->vInventoryBlockToSend .size (), INVENTORY_BROADCAST_MAX));
5807
+
5808
+ // Add blocks
5809
+ BOOST_FOREACH (const uint256& hash, pto->vInventoryBlockToSend ) {
5810
+ vInv.push_back (CInv (MSG_BLOCK, hash));
5811
+ if (vInv.size () == MAX_INV_SZ) {
5812
+ pto->PushMessage (NetMsgType::INV, vInv);
5813
+ vInv.clear ();
5814
+ }
5815
+ }
5816
+ pto->vInventoryBlockToSend .clear ();
5817
+
5818
+ // Determine transactions to relay
5813
5819
bool fSendTrickle = pto->fWhitelisted ;
5814
5820
if (pto->nNextInvSend < nNow) {
5815
5821
fSendTrickle = true ;
5816
- // Use half the delay for outbound peers, as their is less privacy concern for them.
5822
+ // Use half the delay for outbound peers, as there is less privacy concern for them.
5817
5823
pto->nNextInvSend = PoissonNextSend (nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound );
5818
5824
}
5819
- LOCK (pto->cs_inventory );
5820
- if (fSendTrickle && pto->vInventoryToSend .size () > 1 ) {
5825
+ if (fSendTrickle ) {
5826
+ // Produce a vector with all candidates for sending
5827
+ vector<std::set<uint256>::iterator> vInvTx;
5828
+ vInvTx.reserve (pto->setInventoryTxToSend .size ());
5829
+ for (std::set<uint256>::iterator it = pto->setInventoryTxToSend .begin (); it != pto->setInventoryTxToSend .end (); it++) {
5830
+ vInvTx.push_back (it);
5831
+ }
5821
5832
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
5833
+ // A heap is used so that not all items need sorting if only a few are being sent.
5822
5834
CompareInvMempoolOrder compareInvMempoolOrder (&mempool);
5823
- std::stable_sort (pto->vInventoryToSend .begin (), pto->vInventoryToSend .end (), compareInvMempoolOrder);
5824
- }
5825
- vInv.reserve (std::min<size_t >(INVENTORY_BROADCAST_MAX, pto->vInventoryToSend .size ()));
5826
- vInvWait.reserve (pto->vInventoryToSend .size ());
5827
- BOOST_FOREACH (const CInv& inv, pto->vInventoryToSend )
5828
- {
5829
- if (inv.type == MSG_TX && pto->filterInventoryKnown .contains (inv.hash ))
5830
- continue ;
5835
+ std::make_heap (vInvTx.begin (), vInvTx.end (), compareInvMempoolOrder);
5831
5836
// No reason to drain out at many times the network's capacity,
5832
5837
// especially since we have many peers and some will draw much shorter delays.
5833
- if (vInv.size () >= INVENTORY_BROADCAST_MAX || (inv.type == MSG_TX && !fSendTrickle )) {
5834
- vInvWait.push_back (inv);
5835
- continue ;
5838
+ unsigned int nRelayedTransactions = 0 ;
5839
+ while (!vInvTx.empty () && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
5840
+ // Fetch the top element from the heap
5841
+ std::pop_heap (vInvTx.begin (), vInvTx.end (), compareInvMempoolOrder);
5842
+ std::set<uint256>::iterator it = vInvTx.back ();
5843
+ vInvTx.pop_back ();
5844
+ uint256 hash = *it;
5845
+ // Remove it from the to-be-sent set
5846
+ pto->setInventoryTxToSend .erase (it);
5847
+ // Check if not in the filter already
5848
+ if (pto->filterInventoryKnown .contains (hash)) {
5849
+ continue ;
5850
+ }
5851
+ // Send
5852
+ vInv.push_back (CInv (MSG_TX, hash));
5853
+ nRelayedTransactions++;
5854
+ pto->filterInventoryKnown .insert (hash);
5836
5855
}
5837
-
5838
- pto->filterInventoryKnown .insert (inv.hash );
5839
-
5840
- vInv.push_back (inv);
5841
5856
}
5842
- pto->vInventoryToSend = vInvWait;
5843
5857
}
5844
5858
if (!vInv.empty ())
5845
5859
pto->PushMessage (NetMsgType::INV, vInv);
0 commit comments