Move bloom and feerate filtering to just prior to tx sending.

This will avoid sending more pointless INVs around updates, and
 prevents using filter updates to timetag transactions.

Also adds locking for fRelayTxes.
This commit is contained in:
Gregory Maxwell 2016-04-20 07:05:23 +00:00 committed by Pieter Wuille
parent 4578215e7f
commit b559914753
3 changed files with 38 additions and 21 deletions

View File

@ -4557,12 +4557,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH); vRecv >> LIMITED_STRING(pfrom->strSubVer, MAX_SUBVERSION_LENGTH);
pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer); pfrom->cleanSubVer = SanitizeString(pfrom->strSubVer);
} }
if (!vRecv.empty()) if (!vRecv.empty()) {
vRecv >> pfrom->nStartingHeight; vRecv >> pfrom->nStartingHeight;
if (!vRecv.empty()) }
vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message {
else LOCK(pfrom->cs_filter);
pfrom->fRelayTxes = true; if (!vRecv.empty())
vRecv >> pfrom->fRelayTxes; // set to true after we get the first filter* message
else
pfrom->fRelayTxes = true;
}
// Disconnect if we connected to ourself // Disconnect if we connected to ourself
if (nNonce == nLocalHostNonce && nNonce > 1) if (nNonce == nLocalHostNonce && nNonce > 1)
@ -5325,12 +5329,13 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
CBloomFilter filter; CBloomFilter filter;
vRecv >> filter; vRecv >> filter;
LOCK(pfrom->cs_filter);
if (!filter.IsWithinSizeConstraints()) if (!filter.IsWithinSizeConstraints())
// There is no excuse for sending a too-large filter // There is no excuse for sending a too-large filter
Misbehaving(pfrom->GetId(), 100); Misbehaving(pfrom->GetId(), 100);
else else
{ {
LOCK(pfrom->cs_filter);
delete pfrom->pfilter; delete pfrom->pfilter;
pfrom->pfilter = new CBloomFilter(filter); pfrom->pfilter = new CBloomFilter(filter);
pfrom->pfilter->UpdateEmptyFull(); pfrom->pfilter->UpdateEmptyFull();
@ -5798,6 +5803,12 @@ bool SendMessages(CNode* pto)
pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound); pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound);
} }
// Time to send but the peer has requested we not relay transactions.
if (fSendTrickle) {
LOCK(pto->cs_filter);
if (!pto->fRelayTxes) pto->setInventoryTxToSend.clear();
}
// Respond to BIP35 mempool requests // Respond to BIP35 mempool requests
if (fSendTrickle && pto->fSendMempool) { if (fSendTrickle && pto->fSendMempool) {
std::vector<uint256> vtxid; std::vector<uint256> vtxid;
@ -5843,6 +5854,11 @@ bool SendMessages(CNode* pto)
for (std::set<uint256>::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) { for (std::set<uint256>::iterator it = pto->setInventoryTxToSend.begin(); it != pto->setInventoryTxToSend.end(); it++) {
vInvTx.push_back(it); vInvTx.push_back(it);
} }
CAmount filterrate = 0;
{
LOCK(pto->cs_feeFilter);
filterrate = pto->minFeeFilter;
}
// Topologically and fee-rate sort the inventory we send for privacy and priority reasons. // 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. // A heap is used so that not all items need sorting if only a few are being sent.
CompareInvMempoolOrder compareInvMempoolOrder(&mempool); CompareInvMempoolOrder compareInvMempoolOrder(&mempool);
@ -5850,6 +5866,7 @@ bool SendMessages(CNode* pto)
// No reason to drain out at many times the network's capacity, // 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. // especially since we have many peers and some will draw much shorter delays.
unsigned int nRelayedTransactions = 0; unsigned int nRelayedTransactions = 0;
LOCK(pto->cs_filter);
while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) { while (!vInvTx.empty() && nRelayedTransactions < INVENTORY_BROADCAST_MAX) {
// Fetch the top element from the heap // Fetch the top element from the heap
std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder); std::pop_heap(vInvTx.begin(), vInvTx.end(), compareInvMempoolOrder);
@ -5862,6 +5879,19 @@ bool SendMessages(CNode* pto)
if (pto->filterInventoryKnown.contains(hash)) { if (pto->filterInventoryKnown.contains(hash)) {
continue; continue;
} }
// Not in the mempool anymore? don't bother sending it.
CFeeRate feeRate;
if (!mempool.lookupFeeRate(hash, feeRate)) {
continue;
}
if (filterrate && feeRate.GetFeePerK() < filterrate) {
continue;
}
if (pto->pfilter) {
CTransaction tx;
if (!mempool.lookup(hash, tx)) continue;
if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
}
// Send // Send
vInv.push_back(CInv(MSG_TX, hash)); vInv.push_back(CInv(MSG_TX, hash));
nRelayedTransactions++; nRelayedTransactions++;

View File

@ -2071,20 +2071,7 @@ void RelayTransaction(const CTransaction& tx, CFeeRate feerate)
LOCK(cs_vNodes); LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes) BOOST_FOREACH(CNode* pnode, vNodes)
{ {
if(!pnode->fRelayTxes) pnode->PushInventory(inv);
continue;
{
LOCK(pnode->cs_feeFilter);
if (feerate.GetFeePerK() < pnode->minFeeFilter)
continue;
}
LOCK(pnode->cs_filter);
if (pnode->pfilter)
{
if (pnode->pfilter->IsRelevantAndUpdate(tx))
pnode->PushInventory(inv);
} else
pnode->PushInventory(inv);
} }
} }

View File

@ -357,7 +357,7 @@ public:
// a) it allows us to not relay tx invs before receiving the peer's version message // a) it allows us to not relay tx invs before receiving the peer's version message
// b) the peer may tell us in its version message that we should not relay tx invs // b) the peer may tell us in its version message that we should not relay tx invs
// unless it loads a bloom filter. // unless it loads a bloom filter.
bool fRelayTxes; bool fRelayTxes; //protected by cs_filter
bool fSentAddr; bool fSentAddr;
CSemaphoreGrant grantOutbound; CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter; CCriticalSection cs_filter;