@@ -141,8 +141,8 @@ namespace {
141
141
uint256 hash;
142
142
CBlockIndex *pindex; // ! Optional.
143
143
int64_t nTime; // ! Time of "getdata" request in microseconds.
144
- int nValidatedQueuedBefore; // ! Number of blocks queued with validated headers (globally) at the time this one is requested.
145
144
bool fValidatedHeaders ; // ! Whether this block has validated headers at the time of request.
145
+ int64_t nTimeDisconnect; // ! The timeout for this block request (for disconnecting a slow peer)
146
146
};
147
147
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
148
148
@@ -203,6 +203,7 @@ struct CNodeState {
203
203
int64_t nStallingSince;
204
204
list<QueuedBlock> vBlocksInFlight;
205
205
int nBlocksInFlight;
206
+ int nBlocksInFlightValidHeaders;
206
207
// ! Whether we consider this a preferred download peer.
207
208
bool fPreferredDownload ;
208
209
@@ -216,6 +217,7 @@ struct CNodeState {
216
217
fSyncStarted = false ;
217
218
nStallingSince = 0 ;
218
219
nBlocksInFlight = 0 ;
220
+ nBlocksInFlightValidHeaders = 0 ;
219
221
fPreferredDownload = false ;
220
222
}
221
223
};
@@ -247,6 +249,12 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
247
249
nPreferredDownload += state->fPreferredDownload ;
248
250
}
249
251
252
+ // Returns time at which to timeout block request (nTime in microseconds)
253
+ int64_t GetBlockTimeout (int64_t nTime, int nValidatedQueuedBefore)
254
+ {
255
+ return nTime + 500000 * Params ().GetConsensus ().nPowTargetSpacing * (4 + nValidatedQueuedBefore);
256
+ }
257
+
250
258
void InitializeNode (NodeId nodeid, const CNode *pnode) {
251
259
LOCK (cs_main);
252
260
CNodeState &state = mapNodeState.insert (std::make_pair (nodeid, CNodeState ())).first ->second ;
@@ -279,6 +287,7 @@ void MarkBlockAsReceived(const uint256& hash) {
279
287
if (itInFlight != mapBlocksInFlight.end ()) {
280
288
CNodeState *state = State (itInFlight->second .first );
281
289
nQueuedValidatedHeaders -= itInFlight->second .second ->fValidatedHeaders ;
290
+ state->nBlocksInFlightValidHeaders -= itInFlight->second .second ->fValidatedHeaders ;
282
291
state->vBlocksInFlight .erase (itInFlight->second .second );
283
292
state->nBlocksInFlight --;
284
293
state->nStallingSince = 0 ;
@@ -294,10 +303,12 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex
294
303
// Make sure it's not listed somewhere already.
295
304
MarkBlockAsReceived (hash);
296
305
297
- QueuedBlock newentry = {hash, pindex, GetTimeMicros (), nQueuedValidatedHeaders, pindex != NULL };
306
+ int64_t nNow = GetTimeMicros ();
307
+ QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL , GetBlockTimeout (nNow, nQueuedValidatedHeaders)};
298
308
nQueuedValidatedHeaders += newentry.fValidatedHeaders ;
299
309
list<QueuedBlock>::iterator it = state->vBlocksInFlight .insert (state->vBlocksInFlight .end (), newentry);
300
310
state->nBlocksInFlight ++;
311
+ state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders ;
301
312
mapBlocksInFlight[hash] = std::make_pair (nodeid, it);
302
313
}
303
314
@@ -4693,9 +4704,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
4693
4704
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
4694
4705
// being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
4695
4706
// to unreasonably increase our timeout.
4696
- if (!pto->fDisconnect && state.vBlocksInFlight .size () > 0 && state.vBlocksInFlight .front ().nTime < nNow - 500000 * consensusParams.nPowTargetSpacing * (4 + state.vBlocksInFlight .front ().nValidatedQueuedBefore )) {
4697
- LogPrintf (" Timeout downloading block %s from peer=%d, disconnecting\n " , state.vBlocksInFlight .front ().hash .ToString (), pto->id );
4698
- pto->fDisconnect = true ;
4707
+ // We also compare the block download timeout originally calculated against the time at which we'd disconnect
4708
+ // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're
4709
+ // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a
4710
+ // permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing
4711
+ // more quickly than once every 5 minutes, then we'll shorten the download window for this block).
4712
+ if (!pto->fDisconnect && state.vBlocksInFlight .size () > 0 ) {
4713
+ QueuedBlock &queuedBlock = state.vBlocksInFlight .front ();
4714
+ int64_t nTimeoutIfRequestedNow = GetBlockTimeout (nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders );
4715
+ if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) {
4716
+ LogPrint (" net" , " Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n " , pto->id , queuedBlock.hash .ToString (), queuedBlock.nTimeDisconnect , nTimeoutIfRequestedNow);
4717
+ queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow;
4718
+ }
4719
+ if (queuedBlock.nTimeDisconnect < nNow) {
4720
+ LogPrintf (" Timeout downloading block %s from peer=%d, disconnecting\n " , queuedBlock.hash .ToString (), pto->id );
4721
+ pto->fDisconnect = true ;
4722
+ }
4699
4723
}
4700
4724
4701
4725
//
0 commit comments