@ -195,15 +195,10 @@ namespace {
@@ -195,15 +195,10 @@ namespace {
struct QueuedBlock {
uint256 hash ;
CBlockIndex * pindex ; //!< Optional.
int64_t nTime ; //!< Time of "getdata" request in microseconds.
bool fValidatedHeaders ; //!< Whether this block has validated headers at the time of request.
int64_t nTimeDisconnect ; //!< The timeout for this block request (for disconnecting a slow peer)
} ;
map < uint256 , pair < NodeId , list < QueuedBlock > : : iterator > > mapBlocksInFlight ;
/** Number of blocks in flight with validated headers. */
int nQueuedValidatedHeaders = 0 ;
/** Number of preferable block download peers. */
int nPreferredDownload = 0 ;
@ -212,6 +207,9 @@ namespace {
@@ -212,6 +207,9 @@ namespace {
/** Dirty block file entries. */
set < int > setDirtyFileInfo ;
/** Number of peers from which we're downloading blocks. */
int nPeersWithValidatedDownloads = 0 ;
} // anon namespace
//////////////////////////////////////////////////////////////////////////////
@ -259,6 +257,8 @@ struct CNodeState {
@@ -259,6 +257,8 @@ struct CNodeState {
//! Since when we're stalling block download progress (in microseconds), or 0.
int64_t nStallingSince ;
list < QueuedBlock > vBlocksInFlight ;
//! When the first entry in vBlocksInFlight started downloading. Don't care when vBlocksInFlight is empty.
int64_t nDownloadingSince ;
int nBlocksInFlight ;
int nBlocksInFlightValidHeaders ;
//! Whether we consider this a preferred download peer.
@ -276,6 +276,7 @@ struct CNodeState {
@@ -276,6 +276,7 @@ struct CNodeState {
pindexBestHeaderSent = NULL ;
fSyncStarted = false ;
nStallingSince = 0 ;
nDownloadingSince = 0 ;
nBlocksInFlight = 0 ;
nBlocksInFlightValidHeaders = 0 ;
fPreferredDownload = false ;
@ -310,12 +311,6 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
@@ -310,12 +311,6 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload + = state - > fPreferredDownload ;
}
// Returns time at which to timeout block request (nTime in microseconds)
int64_t GetBlockTimeout ( int64_t nTime , int nValidatedQueuedBefore , const Consensus : : Params & consensusParams )
{
return nTime + 500000 * consensusParams . nPowTargetSpacing * ( 4 + nValidatedQueuedBefore ) ;
}
void InitializeNode ( NodeId nodeid , const CNode * pnode ) {
LOCK ( cs_main ) ;
CNodeState & state = mapNodeState . insert ( std : : make_pair ( nodeid , CNodeState ( ) ) ) . first - > second ;
@ -335,11 +330,12 @@ void FinalizeNode(NodeId nodeid) {
@@ -335,11 +330,12 @@ void FinalizeNode(NodeId nodeid) {
}
BOOST_FOREACH ( const QueuedBlock & entry , state - > vBlocksInFlight ) {
nQueuedValidatedHeaders - = entry . fValidatedHeaders ;
mapBlocksInFlight . erase ( entry . hash ) ;
}
EraseOrphansFor ( nodeid ) ;
nPreferredDownload - = state - > fPreferredDownload ;
nPeersWithValidatedDownloads - = ( state - > nBlocksInFlightValidHeaders ! = 0 ) ;
assert ( nPeersWithValidatedDownloads > = 0 ) ;
mapNodeState . erase ( nodeid ) ;
}
@ -350,8 +346,15 @@ bool MarkBlockAsReceived(const uint256& hash) {
@@ -350,8 +346,15 @@ bool MarkBlockAsReceived(const uint256& hash) {
map < uint256 , pair < NodeId , list < QueuedBlock > : : iterator > > : : iterator itInFlight = mapBlocksInFlight . find ( hash ) ;
if ( itInFlight ! = mapBlocksInFlight . end ( ) ) {
CNodeState * state = State ( itInFlight - > second . first ) ;
nQueuedValidatedHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
state - > nBlocksInFlightValidHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
if ( state - > nBlocksInFlightValidHeaders = = 0 & & itInFlight - > second . second - > fValidatedHeaders ) {
// Last validated block on the queue was received.
nPeersWithValidatedDownloads - - ;
}
if ( state - > vBlocksInFlight . begin ( ) = = itInFlight - > second . second ) {
// First block on the queue was received, update the start download time for the next one
state - > nDownloadingSince = std : : max ( state - > nDownloadingSince , GetTimeMicros ( ) ) ;
}
state - > vBlocksInFlight . erase ( itInFlight - > second . second ) ;
state - > nBlocksInFlight - - ;
state - > nStallingSince = 0 ;
@ -369,12 +372,17 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa
@@ -369,12 +372,17 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, const Consensus::Pa
// Make sure it's not listed somewhere already.
MarkBlockAsReceived ( hash ) ;
int64_t nNow = GetTimeMicros ( ) ;
QueuedBlock newentry = { hash , pindex , nNow , pindex ! = NULL , GetBlockTimeout ( nNow , nQueuedValidatedHeaders , consensusParams ) } ;
nQueuedValidatedHeaders + = newentry . fValidatedHeaders ;
QueuedBlock newentry = { hash , pindex , pindex ! = NULL } ;
list < QueuedBlock > : : iterator it = state - > vBlocksInFlight . insert ( state - > vBlocksInFlight . end ( ) , newentry ) ;
state - > nBlocksInFlight + + ;
state - > nBlocksInFlightValidHeaders + = newentry . fValidatedHeaders ;
if ( state - > nBlocksInFlight = = 1 ) {
// We're starting a block download (batch) from this peer.
state - > nDownloadingSince = GetTimeMicros ( ) ;
}
if ( state - > nBlocksInFlightValidHeaders = = 1 & & pindex ! = NULL ) {
nPeersWithValidatedDownloads + + ;
}
mapBlocksInFlight [ hash ] = std : : make_pair ( nodeid , it ) ;
}
@ -3894,7 +3902,6 @@ void UnloadBlockIndex()
@@ -3894,7 +3902,6 @@ void UnloadBlockIndex()
nBlockSequenceId = 1 ;
mapBlockSource . clear ( ) ;
mapBlocksInFlight . clear ( ) ;
nQueuedValidatedHeaders = 0 ;
nPreferredDownload = 0 ;
setDirtyBlockIndex . clear ( ) ;
setDirtyFileInfo . clear ( ) ;
@ -5811,24 +5818,15 @@ bool SendMessages(CNode* pto)
@@ -5811,24 +5818,15 @@ bool SendMessages(CNode* pto)
LogPrintf ( " Peer=%d is stalling block download, disconnecting \n " , pto - > id ) ;
pto - > fDisconnect = true ;
}
// In case there is a block that has been in flight from this peer for ( 2 + 0.5 * N) times the block interval
// (with N the number of validated blocks that were in flight at the time it was requested), disconnect due to
// timeout. We compensate for in-flight block s to prevent killing off peers due to our own downstream link
// In case there is a block that has been in flight from this peer for 2 + 0.5 * N times the block interval
// (with N the number of peers from which we're downloading validated blocks), disconnect due to timeout.
// We compensate for other peer s to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
// to unreasonably increase our timeout.
// We also compare the block download timeout originally calculated against the time at which we'd disconnect
// if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're
// only looking at this peer's oldest request). This way a large queue in the past doesn't result in a
// permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing
// more quickly than once every 5 minutes, then we'll shorten the download window for this block).
if ( ! pto - > fDisconnect & & state . vBlocksInFlight . size ( ) > 0 ) {
QueuedBlock & queuedBlock = state . vBlocksInFlight . front ( ) ;
int64_t nTimeoutIfRequestedNow = GetBlockTimeout ( nNow , nQueuedValidatedHeaders - state . nBlocksInFlightValidHeaders , consensusParams ) ;
if ( queuedBlock . nTimeDisconnect > nTimeoutIfRequestedNow ) {
LogPrint ( " net " , " Reducing block download timeout for peer=%d block=%s, orig=%d new=%d \n " , pto - > id , queuedBlock . hash . ToString ( ) , queuedBlock . nTimeDisconnect , nTimeoutIfRequestedNow ) ;
queuedBlock . nTimeDisconnect = nTimeoutIfRequestedNow ;
}
if ( queuedBlock . nTimeDisconnect < nNow ) {
int nOtherPeersWithValidatedDownloads = nPeersWithValidatedDownloads - ( state . nBlocksInFlightValidHeaders > 0 ) ;
if ( nNow > state . nDownloadingSince + consensusParams . nPowTargetSpacing * ( BLOCK_DOWNLOAD_TIMEOUT_BASE + BLOCK_DOWNLOAD_TIMEOUT_PER_PEER * nOtherPeersWithValidatedDownloads ) ) {
LogPrintf ( " Timeout downloading block %s from peer=%d, disconnecting \n " , queuedBlock . hash . ToString ( ) , pto - > id ) ;
pto - > fDisconnect = true ;
}