Skip to content

Commit dc13dcd

Browse files
committed
Split up and optimize transaction and block inv queues
1 parent f2d3ba7 commit dc13dcd

File tree

2 files changed

+59
-37
lines changed

2 files changed

+59
-37
lines changed

src/main.cpp

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5569,18 +5569,11 @@ class CompareInvMempoolOrder
55695569
mp = mempool;
55705570
}
55715571

5572-
bool operator()(const CInv &a, const CInv &b)
5572+
bool operator()(std::set<uint256>::iterator a, std::set<uint256>::iterator b)
55735573
{
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);
55845577
}
55855578
};
55865579

@@ -5808,38 +5801,59 @@ bool SendMessages(CNode* pto)
58085801
// Message: inventory
58095802
//
58105803
vector<CInv> vInv;
5811-
vector<CInv> vInvWait;
58125804
{
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
58135819
bool fSendTrickle = pto->fWhitelisted;
58145820
if (pto->nNextInvSend < nNow) {
58155821
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.
58175823
pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);
58185824
}
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+
}
58215832
// 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.
58225834
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);
58315836
// No reason to drain out at many times the network's capacity,
58325837
// 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);
58365855
}
5837-
5838-
pto->filterInventoryKnown.insert(inv.hash);
5839-
5840-
vInv.push_back(inv);
58415856
}
5842-
pto->vInventoryToSend = vInvWait;
58435857
}
58445858
if (!vInv.empty())
58455859
pto->PushMessage(NetMsgType::INV, vInv);

src/net.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,13 @@ class CNode
397397

398398
// inventory based relay
399399
CRollingBloomFilter filterInventoryKnown;
400-
std::vector<CInv> vInventoryToSend;
400+
// Set of transaction ids we still have to announce.
401+
// They are sorted by the mempool before relay, so the order is not important.
402+
std::set<uint256> setInventoryTxToSend;
403+
// List of block ids we still have announce.
404+
// There is no final sorting before sending, as they are always sent immediately
405+
// and in the order requested.
406+
std::vector<uint256> vInventoryBlockToSend;
401407
CCriticalSection cs_inventory;
402408
std::set<uint256> setAskFor;
403409
std::multimap<int64_t, CInv> mapAskFor;
@@ -517,11 +523,13 @@ class CNode
517523

518524
void PushInventory(const CInv& inv)
519525
{
520-
{
521-
LOCK(cs_inventory);
522-
if (inv.type == MSG_TX && filterInventoryKnown.contains(inv.hash))
523-
return;
524-
vInventoryToSend.push_back(inv);
526+
LOCK(cs_inventory);
527+
if (inv.type == MSG_TX) {
528+
if (!filterInventoryKnown.contains(inv.hash)) {
529+
setInventoryTxToSend.insert(inv.hash);
530+
}
531+
} else if (inv.type == MSG_BLOCK) {
532+
vInventoryBlockToSend.push_back(inv.hash);
525533
}
526534
}
527535

0 commit comments

Comments
 (0)