Skip to content

Commit 76f7481

Browse files
committed
Add timeout for headers sync
At startup, we choose one peer to serve us the headers chain, until our best header is close to caught up. Disconnect this peer if more than 15 minutes + 1ms/expected_header passes and our best header is still more than 1 day away from current time.
1 parent e265200 commit 76f7481

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

src/net_processing.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ struct CNodeState {
168168
int nUnconnectingHeaders;
169169
//! Whether we've started headers synchronization with this peer.
170170
bool fSyncStarted;
171+
//! When to potentially disconnect peer for stalling headers download
172+
int64_t nHeadersSyncTimeout;
171173
//! Since when we're stalling block download progress (in microseconds), or 0.
172174
int64_t nStallingSince;
173175
std::list<QueuedBlock> vBlocksInFlight;
@@ -207,6 +209,7 @@ struct CNodeState {
207209
pindexBestHeaderSent = NULL;
208210
nUnconnectingHeaders = 0;
209211
fSyncStarted = false;
212+
nHeadersSyncTimeout = 0;
210213
nStallingSince = 0;
211214
nDownloadingSince = 0;
212215
nBlocksInFlight = 0;
@@ -2883,6 +2886,7 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
28832886
// Only actively request headers from a single peer, unless we're close to today.
28842887
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
28852888
state.fSyncStarted = true;
2889+
state.nHeadersSyncTimeout = GetTimeMicros() + HEADERS_DOWNLOAD_TIMEOUT_BASE + HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER * (GetAdjustedTime() - pindexBestHeader->GetBlockTime())/(consensusParams.nPowTargetSpacing);
28862890
nSyncStarted++;
28872891
const CBlockIndex *pindexStart = pindexBestHeader;
28882892
/* If possible, start at the block preceding the currently
@@ -3206,6 +3210,39 @@ bool SendMessages(CNode* pto, CConnman& connman, const std::atomic<bool>& interr
32063210
return true;
32073211
}
32083212
}
3213+
// Check for headers sync timeouts
3214+
if (state.fSyncStarted && state.nHeadersSyncTimeout < std::numeric_limits<int64_t>::max()) {
3215+
// Detect whether this is a stalling initial-headers-sync peer
3216+
if (pindexBestHeader->GetBlockTime() <= GetAdjustedTime() - 24*60*60) {
3217+
if (nNow > state.nHeadersSyncTimeout && nSyncStarted == 1 && (nPreferredDownload - state.fPreferredDownload >= 1)) {
3218+
// Disconnect a (non-whitelisted) peer if it is our only sync peer,
3219+
// and we have others we could be using instead.
3220+
// Note: If all our peers are inbound, then we won't
3221+
// disconnect our sync peer for stalling; we have bigger
3222+
// problems if we can't get any outbound peers.
3223+
if (!pto->fWhitelisted) {
3224+
LogPrintf("Timeout downloading headers from peer=%d, disconnecting\n", pto->GetId());
3225+
pto->fDisconnect = true;
3226+
return true;
3227+
} else {
3228+
LogPrintf("Timeout downloading headers from whitelisted peer=%d, not disconnecting\n", pto->GetId());
3229+
// Reset the headers sync state so that we have a
3230+
// chance to try downloading from a different peer.
3231+
// Note: this will also result in at least one more
3232+
// getheaders message to be sent to
3233+
// this peer (eventually).
3234+
state.fSyncStarted = false;
3235+
nSyncStarted--;
3236+
state.nHeadersSyncTimeout = 0;
3237+
}
3238+
}
3239+
} else {
3240+
// After we've caught up once, reset the timeout so we can't trigger
3241+
// disconnect later.
3242+
state.nHeadersSyncTimeout = std::numeric_limits<int64_t>::max();
3243+
}
3244+
}
3245+
32093246

32103247
//
32113248
// Message: getdata (blocks)

src/net_processing.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ static const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60;
1717
static const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60;
1818
/** Default number of orphan+recently-replaced txn to keep around for block reconstruction */
1919
static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100;
20+
/** Headers download timeout expressed in microseconds
21+
* Timeout = base + per_header * (expected number of headers) */
22+
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes
23+
static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header
2024

2125
/** Register with a network node to receive its signals */
2226
void RegisterNodeSignals(CNodeSignals& nodeSignals);

0 commit comments

Comments
 (0)