Skip to content

Commit 8ba7f84

Browse files
committed
Reduce download timeouts as blocks arrive
Compare the block download timeout to what the timeout would be if calculated based on current time and current value of nQueuedValidatedHeaders, but ignoring other in-flight blocks from the same peer. If the calculation based on present conditions is shorter, then set that to be the time after which we disconnect the peer for not delivering this block.
1 parent ea2b425 commit 8ba7f84

File tree

1 file changed

+29
-5
lines changed

1 file changed

+29
-5
lines changed

src/main.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ namespace {
141141
uint256 hash;
142142
CBlockIndex *pindex; //! Optional.
143143
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.
145144
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)
146146
};
147147
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight;
148148

@@ -203,6 +203,7 @@ struct CNodeState {
203203
int64_t nStallingSince;
204204
list<QueuedBlock> vBlocksInFlight;
205205
int nBlocksInFlight;
206+
int nBlocksInFlightValidHeaders;
206207
//! Whether we consider this a preferred download peer.
207208
bool fPreferredDownload;
208209

@@ -216,6 +217,7 @@ struct CNodeState {
216217
fSyncStarted = false;
217218
nStallingSince = 0;
218219
nBlocksInFlight = 0;
220+
nBlocksInFlightValidHeaders = 0;
219221
fPreferredDownload = false;
220222
}
221223
};
@@ -247,6 +249,12 @@ void UpdatePreferredDownload(CNode* node, CNodeState* state)
247249
nPreferredDownload += state->fPreferredDownload;
248250
}
249251

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+
250258
void InitializeNode(NodeId nodeid, const CNode *pnode) {
251259
LOCK(cs_main);
252260
CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second;
@@ -279,6 +287,7 @@ void MarkBlockAsReceived(const uint256& hash) {
279287
if (itInFlight != mapBlocksInFlight.end()) {
280288
CNodeState *state = State(itInFlight->second.first);
281289
nQueuedValidatedHeaders -= itInFlight->second.second->fValidatedHeaders;
290+
state->nBlocksInFlightValidHeaders -= itInFlight->second.second->fValidatedHeaders;
282291
state->vBlocksInFlight.erase(itInFlight->second.second);
283292
state->nBlocksInFlight--;
284293
state->nStallingSince = 0;
@@ -294,10 +303,12 @@ void MarkBlockAsInFlight(NodeId nodeid, const uint256& hash, CBlockIndex *pindex
294303
// Make sure it's not listed somewhere already.
295304
MarkBlockAsReceived(hash);
296305

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)};
298308
nQueuedValidatedHeaders += newentry.fValidatedHeaders;
299309
list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(), newentry);
300310
state->nBlocksInFlight++;
311+
state->nBlocksInFlightValidHeaders += newentry.fValidatedHeaders;
301312
mapBlocksInFlight[hash] = std::make_pair(nodeid, it);
302313
}
303314

@@ -4693,9 +4704,22 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
46934704
// timeout. We compensate for in-flight blocks to prevent killing off peers due to our own downstream link
46944705
// being saturated. We only count validated in-flight blocks so peers can't advertize nonexisting block hashes
46954706
// 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+
}
46994723
}
47004724

47014725
//

0 commit comments

Comments
 (0)