Merge pull request #2417 from patricklodder/1.14-serialize-getheaders
Reduce getheaders spam by serializing getheader requests per peer
This commit is contained in:
commit
3a5a31c113
|
@ -2704,6 +2704,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn
|
|||
fPauseRecv = false;
|
||||
fPauseSend = false;
|
||||
nProcessQueueSize = 0;
|
||||
nPendingHeaderRequests = 0;
|
||||
|
||||
BOOST_FOREACH(const std::string &msg, getAllNetMessageTypes())
|
||||
mapRecvBytesPerMsgCmd[msg] = 0;
|
||||
|
|
|
@ -681,6 +681,9 @@ public:
|
|||
CAmount lastSentFeeFilter;
|
||||
int64_t nextSendTimeFeeFilter;
|
||||
|
||||
// Counts getheaders requests sent to this peer
|
||||
std::atomic<int64_t> nPendingHeaderRequests;
|
||||
|
||||
// Alert relay
|
||||
std::vector<CAlert> vAlertToSend;
|
||||
|
||||
|
|
|
@ -731,6 +731,25 @@ void Misbehaving(NodeId pnode, int howmuch)
|
|||
}
|
||||
|
||||
|
||||
// Dogecoin - 1.14 specific fix: do not request headers from a peer we are
|
||||
// already requesting headers from, unless forced.
|
||||
void RequestHeadersFrom(CNode* pto, CConnman& connman, const CBlockIndex* pindex, uint256 untilHash, bool fforceQuery)
|
||||
{
|
||||
if (pto->nPendingHeaderRequests > 0) {
|
||||
if (fforceQuery) {
|
||||
LogPrint("net", "forcing getheaders request (%d) to peer=%d (%d open)\n",
|
||||
pindex->nHeight, pto->id, pto->nPendingHeaderRequests);
|
||||
} else {
|
||||
LogPrint("net", "dropped getheaders request (%d) to peer=%d\n", pindex->nHeight, pto->id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const CNetMsgMaker msgMaker(pto->GetSendVersion());
|
||||
connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindex), untilHash));
|
||||
pto->nPendingHeaderRequests += 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1560,7 +1579,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
// fell back to inv we probably have a reorg which we should get the headers for first,
|
||||
// we now only provide a getheaders response here. When we receive the headers, we will
|
||||
// then ask for the blocks we need.
|
||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash));
|
||||
// Dogecoin: We force this check, in case we're only connected to nodes that send invs
|
||||
RequestHeadersFrom(pfrom, connman, pindexBestHeader, inv.hash, true);
|
||||
LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
|
||||
}
|
||||
}
|
||||
|
@ -1968,7 +1988,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
if (mapBlockIndex.find(cmpctblock.header.hashPrevBlock) == mapBlockIndex.end()) {
|
||||
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
|
||||
if (!IsInitialBlockDownload())
|
||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
|
||||
RequestHeadersFrom(pfrom, connman, pindexBestHeader, uint256(), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -2225,6 +2245,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
{
|
||||
std::vector<CBlockHeader> headers;
|
||||
|
||||
if (pfrom->nPendingHeaderRequests > 0)
|
||||
pfrom->nPendingHeaderRequests -= 1;
|
||||
|
||||
// Bypass the normal CBlock deserialization, as we don't want to risk deserializing 2000 full blocks.
|
||||
unsigned int nCount = ReadCompactSize(vRecv);
|
||||
if (nCount > MAX_HEADERS_RESULTS) {
|
||||
|
@ -2258,7 +2281,8 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
// nUnconnectingHeaders gets reset back to 0.
|
||||
if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
|
||||
nodestate->nUnconnectingHeaders++;
|
||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256()));
|
||||
// Dogecoin: allow a single getheaders query before triggering DoS
|
||||
RequestHeadersFrom(pfrom, connman, pindexBestHeader, uint256(), true);
|
||||
LogPrint("net", "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
|
||||
headers[0].GetHash().ToString(),
|
||||
headers[0].hashPrevBlock.ToString(),
|
||||
|
@ -2312,8 +2336,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
// Headers message had its maximum size; the peer may have more headers.
|
||||
// TODO: optimize: if pindexLast is an ancestor of chainActive.Tip or pindexBestHeader, continue
|
||||
// from there instead.
|
||||
//
|
||||
// Dogecoin: do not allow multiple getheader queries in parallel at
|
||||
// this point - makes sure that any parallel queries will end here,
|
||||
// preventing "getheaders" spam.
|
||||
LogPrint("net", "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom->id, pfrom->nStartingHeight);
|
||||
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexLast), uint256()));
|
||||
RequestHeadersFrom(pfrom, connman, pindexLast, uint256(), false);
|
||||
}
|
||||
|
||||
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus(0));
|
||||
|
@ -2539,7 +2567,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
|
|||
// Relay
|
||||
pfrom->setKnown.insert(alertHash);
|
||||
{
|
||||
|
||||
|
||||
connman.ForEachNode([&alert](CNode* pnode)
|
||||
{
|
||||
pnode->PushAlert(alert);
|
||||
|
@ -2912,10 +2940,13 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
|
|||
the peer's known best block. This wouldn't be possible
|
||||
if we requested starting at pindexBestHeader and
|
||||
got back an empty response. */
|
||||
// Dogecoin: make sure that if we are already processing an inv
|
||||
// or header message from this peer caused by a new block being
|
||||
// mined at chaintip, we do not send another getheaders request
|
||||
if (pindexStart->pprev)
|
||||
pindexStart = pindexStart->pprev;
|
||||
LogPrint("net", "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->id, pto->nStartingHeight);
|
||||
connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexStart), uint256()));
|
||||
RequestHeadersFrom(pto, connman, pindexStart, uint256(), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue