@ -141,8 +141,8 @@ namespace {
uint256 hash ;
uint256 hash ;
CBlockIndex * pindex ; //! Optional.
CBlockIndex * pindex ; //! Optional.
int64_t nTime ; //! Time of "getdata" request in microseconds.
int64_t nTime ; //! Time of "getdata" request in microseconds.
int nValidatedQueuedBefore ; //! Number of blocks queued with validated headers (globally) at the time this one is requested.
bool fValidatedHeaders ; //! Whether this block has validated headers at the time of request.
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 ;
map < uint256 , pair < NodeId , list < QueuedBlock > : : iterator > > mapBlocksInFlight ;
@ -203,6 +203,7 @@ struct CNodeState {
int64_t nStallingSince ;
int64_t nStallingSince ;
list < QueuedBlock > vBlocksInFlight ;
list < QueuedBlock > vBlocksInFlight ;
int nBlocksInFlight ;
int nBlocksInFlight ;
int nBlocksInFlightValidHeaders ;
//! Whether we consider this a preferred download peer.
//! Whether we consider this a preferred download peer.
bool fPreferredDownload ;
bool fPreferredDownload ;
@ -216,6 +217,7 @@ struct CNodeState {
fSyncStarted = false ;
fSyncStarted = false ;
nStallingSince = 0 ;
nStallingSince = 0 ;
nBlocksInFlight = 0 ;
nBlocksInFlight = 0 ;
nBlocksInFlightValidHeaders = 0 ;
fPreferredDownload = false ;
fPreferredDownload = false ;
}
}
} ;
} ;
@ -247,6 +249,12 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
nPreferredDownload + = state - > fPreferredDownload ;
nPreferredDownload + = state - > fPreferredDownload ;
}
}
// Returns time at which to timeout block request (nTime in microseconds)
int64_t GetBlockTimeout ( int64_t nTime , int nValidatedQueuedBefore )
{
return nTime + 500000 * Params ( ) . GetConsensus ( ) . nPowTargetSpacing * ( 4 + nValidatedQueuedBefore ) ;
}
void InitializeNode ( NodeId nodeid , const CNode * pnode ) {
void InitializeNode ( NodeId nodeid , const CNode * pnode ) {
LOCK ( cs_main ) ;
LOCK ( cs_main ) ;
CNodeState & state = mapNodeState . insert ( std : : make_pair ( nodeid , CNodeState ( ) ) ) . first - > second ;
CNodeState & state = mapNodeState . insert ( std : : make_pair ( nodeid , CNodeState ( ) ) ) . first - > second ;
@ -279,6 +287,7 @@ void MarkBlockAsReceived(const uint256& hash) {
if ( itInFlight ! = mapBlocksInFlight . end ( ) ) {
if ( itInFlight ! = mapBlocksInFlight . end ( ) ) {
CNodeState * state = State ( itInFlight - > second . first ) ;
CNodeState * state = State ( itInFlight - > second . first ) ;
nQueuedValidatedHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
nQueuedValidatedHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
state - > nBlocksInFlightValidHeaders - = itInFlight - > second . second - > fValidatedHeaders ;
state - > vBlocksInFlight . erase ( itInFlight - > second . second ) ;
state - > vBlocksInFlight . erase ( itInFlight - > second . second ) ;
state - > nBlocksInFlight - - ;
state - > nBlocksInFlight - - ;
state - > nStallingSince = 0 ;
state - > nStallingSince = 0 ;
@ -294,10 +303,12 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex
// Make sure it's not listed somewhere already.
// Make sure it's not listed somewhere already.
MarkBlockAsReceived ( hash ) ;
MarkBlockAsReceived ( hash ) ;
QueuedBlock newentry = { hash , pindex , GetTimeMicros ( ) , nQueuedValidatedHeaders , pindex ! = NULL } ;
int64_t nNow = GetTimeMicros ( ) ;
QueuedBlock newentry = { hash , pindex , nNow , pindex ! = NULL , GetBlockTimeout ( nNow , nQueuedValidatedHeaders ) } ;
nQueuedValidatedHeaders + = newentry . fValidatedHeaders ;
nQueuedValidatedHeaders + = newentry . fValidatedHeaders ;
list < QueuedBlock > : : iterator it = state - > vBlocksInFlight . insert ( state - > vBlocksInFlight . end ( ) , newentry ) ;
list < QueuedBlock > : : iterator it = state - > vBlocksInFlight . insert ( state - > vBlocksInFlight . end ( ) , newentry ) ;
state - > nBlocksInFlight + + ;
state - > nBlocksInFlight + + ;
state - > nBlocksInFlightValidHeaders + = newentry . fValidatedHeaders ;
mapBlocksInFlight [ hash ] = std : : make_pair ( nodeid , it ) ;
mapBlocksInFlight [ hash ] = std : : make_pair ( nodeid , it ) ;
}
}
@ -4693,10 +4704,23 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
// being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
// being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
// to unreasonably increase our timeout.
// to unreasonably increase our timeout.
if ( ! pto - > fDisconnect & & state . vBlocksInFlight . size ( ) > 0 & & state . vBlocksInFlight . front ( ) . nTime < nNow - 500000 * consensusParams . nPowTargetSpacing * ( 4 + state . vBlocksInFlight . front ( ) . nValidatedQueuedBefore ) ) {
// We also compare the block download timeout originally calculated against the time at which we'd disconnect
LogPrintf ( " Timeout downloading block %s from peer=%d, disconnecting \n " , state . vBlocksInFlight . front ( ) . hash . ToString ( ) , pto - > id ) ;
// 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 ) ;
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 ) {
LogPrintf ( " Timeout downloading block %s from peer=%d, disconnecting \n " , queuedBlock . hash . ToString ( ) , pto - > id ) ;
pto - > fDisconnect = true ;
pto - > fDisconnect = true ;
}
}
}
//
//
// Message: getdata (blocks)
// Message: getdata (blocks)