Skip to content

Commit 96fa953

Browse files
committed
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.
1 parent b978701 commit 96fa953

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

src/main.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ struct CNodeState {
276276
CBlockIndex *pindexLastCommonBlock;
277277
//! The best header we have sent our peer.
278278
CBlockIndex *pindexBestHeaderSent;
279+
//! Length of current-streak of unconnecting headers announcements
280+
int nUnconnectingHeaders;
279281
//! Whether we've started headers synchronization with this peer.
280282
bool fSyncStarted;
281283
//! Since when we're stalling block download progress (in microseconds), or 0.
@@ -304,6 +306,7 @@ struct CNodeState {
304306
hashLastUnknownBlock.SetNull();
305307
pindexLastCommonBlock = NULL;
306308
pindexBestHeaderSent = NULL;
309+
nUnconnectingHeaders = 0;
307310
fSyncStarted = false;
308311
nStallingSince = 0;
309312
nDownloadingSince = 0;
@@ -5773,6 +5776,35 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
57735776
return true;
57745777
}
57755778

5779+
CNodeState *nodestate = State(pfrom->GetId());
5780+
5781+
// If this looks like it could be a block announcement (nCount <
5782+
// MAX_BLOCKS_TO_ANNOUNCE), use special logic for handling headers that
5783+
// don't connect:
5784+
// - Send a getheaders message in response to try to connect the chain.
5785+
// - The peer can send up to MAX_UNCONNECTING_HEADERS in a row that
5786+
// don't connect before giving DoS points
5787+
// - Once a headers message is received that is valid and does connect,
5788+
// nUnconnectingHeaders gets reset back to 0.
5789+
if (mapBlockIndex.find(headers[0].hashPrevBlock) == mapBlockIndex.end() && nCount < MAX_BLOCKS_TO_ANNOUNCE) {
5790+
nodestate->nUnconnectingHeaders++;
5791+
pfrom->PushMessage(NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), uint256());
5792+
LogPrint("net", "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
5793+
headers[0].GetHash().ToString(),
5794+
headers[0].hashPrevBlock.ToString(),
5795+
pindexBestHeader->nHeight,
5796+
pfrom->id, nodestate->nUnconnectingHeaders);
5797+
// Set hashLastUnknownBlock for this peer, so that if we
5798+
// eventually get the headers - even from a different peer -
5799+
// we can use this peer to download.
5800+
UpdateBlockAvailability(pfrom->GetId(), headers.back().GetHash());
5801+
5802+
if (nodestate->nUnconnectingHeaders % MAX_UNCONNECTING_HEADERS == 0) {
5803+
Misbehaving(pfrom->GetId(), 20);
5804+
}
5805+
return true;
5806+
}
5807+
57765808
CBlockIndex *pindexLast = NULL;
57775809
BOOST_FOREACH(const CBlockHeader& header, headers) {
57785810
CValidationState state;
@@ -5790,6 +5822,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
57905822
}
57915823
}
57925824

5825+
if (nodestate->nUnconnectingHeaders > 0) {
5826+
LogPrint("net", "peer=%d: resetting nUnconnectingHeaders (%d -> 0)\n", pfrom->id, nodestate->nUnconnectingHeaders);
5827+
}
5828+
nodestate->nUnconnectingHeaders = 0;
5829+
57935830
assert(pindexLast);
57945831
UpdateBlockAvailability(pfrom->GetId(), pindexLast->GetBlockHash());
57955832

@@ -5802,7 +5839,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
58025839
}
58035840

58045841
bool fCanDirectFetch = CanDirectFetch(chainparams.GetConsensus());
5805-
CNodeState *nodestate = State(pfrom->GetId());
58065842
// If this set of headers is valid and ends in a block with at least as
58075843
// much work as our tip, download as much as possible.
58085844
if (fCanDirectFetch && pindexLast->IsValid(BLOCK_VALID_TREE) && chainActive.Tip()->nChainWork <= pindexLast->nChainWork) {

src/main.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ static const bool DEFAULT_FEEFILTER = true;
138138
/** Maximum number of headers to announce when relaying blocks with headers message.*/
139139
static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
140140

141+
/** Maximum number of unconnecting headers announcements before DoS score */
142+
static const int MAX_UNCONNECTING_HEADERS = 10;
143+
141144
static const bool DEFAULT_PEERBLOOMFILTERS = true;
142145

143146
struct BlockHasher

0 commit comments

Comments
 (0)