@ -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 ) {