Improve handling of unconnecting headers
When processing a headers message that looks like a block announcement, send peer a getheaders if the headers message won't connect. Apply DoS points after too many consecutive unconnecting headers messages.
This commit is contained in:
parent
b978701ba1
commit
96fa95361f
2 changed files with 40 additions and 1 deletions
38
src/main.cpp
38
src/main.cpp
|
@ -276,6 +276,8 @@ struct CNodeState {
|
|||
CBlockIndex *pindexLastCommonBlock;
|
||||
//! The best header we have sent our peer.
|
||||
CBlockIndex *pindexBestHeaderSent;
|
||||
//! Length of current-streak of unconnecting headers announcements
|
||||
int nUnconnectingHeaders;
|
||||
//! Whether we've started headers synchronization with this peer.
|
||||
bool fSyncStarted;
|
||||
//! Since when we're stalling block download progress (in microseconds), or 0.
|
||||
|
@ -304,6 +306,7 @@ struct CNodeState {
|
|||
hashLastUnknownBlock.SetNull();
|
||||
pindexLastCommonBlock = NULL;
|
||||
pindexBestHeaderSent = NULL;
|
||||
nUnconnectingHeaders = 0;
|
||||
fSyncStarted = false;
|
||||
nStallingSince = 0;
|
||||
nDownloadingSince = 0;
|
||||
|
@ -5773,6 +5776,35 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
return true;
|
||||
}
|
||||
|
||||
CNodeState *nodestate = State(pfrom->GetId());
|
||||
|
||||
// If this looks like it could be a block announcement (nCount <
|
||||
// MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
|
||||
// don't connect:
|
||||
// - Send a getheaders message in response to try to connect the chain.
|
||||
// - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
|
||||
// don't connect before giving DoS points
|
||||
// - Once a headers message is received that is valid and does connect,
|
||||
// nUnconnectingHeaders gets reset back to 0.
|
||||
if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
|
||||
nodestate->nUnconnectingHeaders++;
|
||||
pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
|
||||
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(),
|
||||
pindexBestHeader->nHeight,
|
||||
pfrom->id, nodestate->nUnconnectingHeaders);
|
||||
// Set hashLastUnknownBlock for this peer, so that if we
|
||||
// eventually get the headers - even from a different peer -
|
||||
// we can use this peer to download.
|
||||
UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
|
||||
|
||||
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
|
||||
Misbehaving(pfrom->GetId(), 20);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
CBlockIndex *pindexLast = NULL;
|
||||
BOOST_FOREACH(const CBlockHeader& header, headers) {
|
||||
CValidationState state;
|
||||
|
@ -5790,6 +5822,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
}
|
||||
}
|
||||
|
||||
if (nodestate->nUnconnectingHeaders > 0) {
|
||||
LogPrint("net", "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->id, nodestate->nUnconnectingHeaders);
|
||||
}
|
||||
nodestate->nUnconnectingHeaders = 0;
|
||||
|
||||
assert(pindexLast);
|
||||
UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
|
||||
|
||||
|
@ -5802,7 +5839,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
|||
}
|
||||
|
||||
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
|
||||
CNodeState *nodestate = State(pfrom->GetId());
|
||||
// If this set of headers is valid and ends in a block with at least as
|
||||
// much work as our tip, download as much as possible.
|
||||
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {
|
||||
|
|
|
@ -138,6 +138,9 @@ static const bool DEFAULT_FEEFILTER = true;
|
|||
/** Maximum number of headers to announce when relaying blocks with headers message.*/
|
||||
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
|
||||
|
||||
/** Maximum number of unconnecting headers announcements before DoS score */
|
||||
static const int MAX_UNCONNECTING_HEADERS = 10;
|
||||
|
||||
static const bool DEFAULT_PEERBLOOMFILTERS = true;
|
||||
|
||||
struct BlockHasher
|
||||
|
|
Loading…
Reference in a new issue