@@ -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 ) {
0 commit comments