@@ -154,8 +154,8 @@ namespace {
154
154
uint256 hash;
155
155
CBlockIndex *pindex; // ! Optional.
156
156
int64_t nTime; // ! Time of "getdata" request in microseconds.
157
- int nValidatedQueuedBefore; // ! Number of blocks queued with validated headers (globally) at the time this one is requested.
158
157
bool fValidatedHeaders ; // ! Whether this block has validated headers at the time of request.
158
+ int64_t nTimeDisconnect; // ! The timeout for this block request (for disconnecting a slow peer)
159
159
};
160
160
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
161
161
@@ -216,6 +216,7 @@ struct CNodeState {
216
216
int64_t nStallingSince;
217
217
list<QueuedBlock> vBlocksInFlight;
218
218
int nBlocksInFlight;
219
+ int nBlocksInFlightValidHeaders;
219
220
// ! Whether we consider this a preferred download peer.
220
221
bool fPreferredDownload ;
221
222
@@ -229,6 +230,7 @@ struct CNodeState {
229
230
fSyncStarted = false ;
230
231
nStallingSince = 0 ;
231
232
nBlocksInFlight = 0 ;
233
+ nBlocksInFlightValidHeaders = 0 ;
232
234
fPreferredDownload = false ;
233
235
}
234
236
};
@@ -260,6 +262,12 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
260
262
nPreferredDownload += state->fPreferredDownload ;
261
263
}
262
264
265
+ // Returns time at which to timeout block request (nTime in microseconds)
266
+ int64_t GetBlockTimeout (int64_t nTime, int nValidatedQueuedBefore)
267
+ {
268
+ return nTime + 500000 * Params ().GetConsensus ().nPowTargetSpacing * (4 + nValidatedQueuedBefore);
269
+ }
270
+
263
271
void InitializeNode (NodeId nodeid, const CNode *pnode) {
264
272
LOCK (cs_main);
265
273
CNodeState &state = mapNodeState.insert (std::make_pair (nodeid, CNodeState ())).first ->second ;
@@ -292,6 +300,7 @@ void MarkBlockAsReceived(const uint256& hash) {
292
300
if (itInFlight != mapBlocksInFlight.end ()) {
293
301
CNodeState *state = State (itInFlight->second .first );
294
302
nQueuedValidatedHeaders -= itInFlight->second .second ->fValidatedHeaders ;
303
+ state->nBlocksInFlightValidHeaders -= itInFlight->second .second ->fValidatedHeaders ;
295
304
state->vBlocksInFlight .erase (itInFlight->second .second );
296
305
state->nBlocksInFlight --;
297
306
state->nStallingSince = 0 ;
@@ -307,10 +316,12 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex
307
316
// Make sure it's not listed somewhere already.
308
317
MarkBlockAsReceived (hash);
309
318
310
- QueuedBlock newentry = {hash, pindex, GetTimeMicros (), nQueuedValidatedHeaders, pindex != NULL };
319
+ int64_t nNow = GetTimeMicros ();
320
+ QueuedBlock newentry = {hash, pindex, nNow, pindex != NULL , GetBlockTimeout (nNow, nQueuedValidatedHeaders)};
311
321
nQueuedValidatedHeaders += newentry.fValidatedHeaders ;
312
322
list<QueuedBlock>::iterator it = state->vBlocksInFlight .insert (state->vBlocksInFlight .end (), newentry);
313
323
state->nBlocksInFlight ++;
324
+ state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders ;
314
325
mapBlocksInFlight[hash] = std::make_pair (nodeid, it);
315
326
}
316
327
@@ -5015,9 +5026,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
5015
5026
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
5016
5027
// being saturated. We only count validated in-flight blocks so peers can't advertise non-existing block hashes
5017
5028
// to unreasonably increase our timeout.
5018
- if (!pto->fDisconnect && state.vBlocksInFlight .size () > 0 && state.vBlocksInFlight .front ().nTime < nNow - 500000 * consensusParams.nPowTargetSpacing * (4 + state.vBlocksInFlight .front ().nValidatedQueuedBefore )) {
5019
- LogPrintf (" Timeout downloading block %s from peer=%d, disconnecting\n " , state.vBlocksInFlight .front ().hash .ToString (), pto->id );
5020
- pto->fDisconnect = true ;
5029
+ // We also compare the block download timeout originally calculated against the time at which we'd disconnect
5030
+ // if we assumed the block were being requested now (ignoring blocks we've requested from this peer, since we're
5031
+ // only looking at this peer's oldest request). This way a large queue in the past doesn't result in a
5032
+ // permanently large window for this block to be delivered (ie if the number of blocks in flight is decreasing
5033
+ // more quickly than once every 5 minutes, then we'll shorten the download window for this block).
5034
+ if (!pto->fDisconnect && state.vBlocksInFlight .size () > 0 ) {
5035
+ QueuedBlock &queuedBlock = state.vBlocksInFlight .front ();
5036
+ int64_t nTimeoutIfRequestedNow = GetBlockTimeout (nNow, nQueuedValidatedHeaders - state.nBlocksInFlightValidHeaders );
5037
+ if (queuedBlock.nTimeDisconnect > nTimeoutIfRequestedNow) {
5038
+ LogPrint (" net" , " Reducing block download timeout for peer=%d block=%s, orig=%d new=%d\n " , pto->id , queuedBlock.hash .ToString (), queuedBlock.nTimeDisconnect , nTimeoutIfRequestedNow);
5039
+ queuedBlock.nTimeDisconnect = nTimeoutIfRequestedNow;
5040
+ }
5041
+ if (queuedBlock.nTimeDisconnect < nNow) {
5042
+ LogPrintf (" Timeout downloading block %s from peer=%d, disconnecting\n " , queuedBlock.hash .ToString (), pto->id );
5043
+ pto->fDisconnect = true ;
5044
+ }
5021
5045
}
5022
5046
5023
5047
//
0 commit comments