@@ -276,6 +276,8 @@ struct CNodeState {
276
276
CBlockIndex *pindexLastCommonBlock;
277
277
// ! The best header we have sent our peer.
278
278
CBlockIndex *pindexBestHeaderSent;
279
+ // ! Length of current-streak of unconnecting headers announcements
280
+ int nUnconnectingHeaders;
279
281
// ! Whether we've started headers synchronization with this peer.
280
282
bool fSyncStarted ;
281
283
// ! Since when we're stalling block download progress (in microseconds), or 0.
@@ -304,6 +306,7 @@ struct CNodeState {
304
306
hashLastUnknownBlock.SetNull ();
305
307
pindexLastCommonBlock = NULL ;
306
308
pindexBestHeaderSent = NULL ;
309
+ nUnconnectingHeaders = 0 ;
307
310
fSyncStarted = false ;
308
311
nStallingSince = 0 ;
309
312
nDownloadingSince = 0 ;
@@ -5773,6 +5776,35 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5773
5776
return true ;
5774
5777
}
5775
5778
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
+
5776
5808
CBlockIndex *pindexLast = NULL ;
5777
5809
BOOST_FOREACH (const CBlockHeader& header, headers) {
5778
5810
CValidationState state;
@@ -5790,6 +5822,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5790
5822
}
5791
5823
}
5792
5824
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
+
5793
5830
assert (pindexLast);
5794
5831
UpdateBlockAvailability (pfrom->GetId (), pindexLast->GetBlockHash ());
5795
5832
@@ -5802,7 +5839,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5802
5839
}
5803
5840
5804
5841
bool fCanDirectFetch = CanDirectFetch (chainparams.GetConsensus ());
5805
- CNodeState *nodestate = State (pfrom->GetId ());
5806
5842
// If this set of headers is valid and ends in a block with at least as
5807
5843
// much work as our tip, download as much as possible.
5808
5844
if (fCanDirectFetch && pindexLast->IsValid (BLOCK_VALID_TREE) && chainActive.Tip ()->nChainWork <= pindexLast->nChainWork ) {
0 commit comments