Skip to content

Commit

Permalink
Fix sync issues (#1599)
Browse files Browse the repository at this point in the history
- add `MASTERNODE_SYNC_WAITING` sync state/asset and initial timeout
- wait for block headers to be downloaded (new signal `AcceptedBlockHeader`)
- wait for blocks to reach best headers tip before switching to masternode list sync (new signal `NotifyHeaderTip`)
- switched sync from `UpdatedBlockTip` to a combination of `AcceptedBlockHeader` and `NotifyHeaderTip`
- all blockchain-related bumps should take place only while we are still syncing blockchain, should be no such bumps after that
  • Loading branch information
UdjinM6 authored Sep 3, 2017
1 parent b82b978 commit 4f0618a
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 15 deletions.
11 changes: 10 additions & 1 deletion src/dsnotificationinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ void CDSNotificationInterface::InitializeCurrentBlockTip()
UpdatedBlockTip(chainActive.Tip(), NULL, IsInitialBlockDownload());
}

void CDSNotificationInterface::AcceptedBlockHeader(const CBlockIndex *pindexNew)
{
masternodeSync.AcceptedBlockHeader(pindexNew);
}

void CDSNotificationInterface::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload)
{
masternodeSync.NotifyHeaderTip(pindexNew, fInitialDownload);
}

void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload)
{
if (fInitialDownload || pindexNew == pindexFork) // In IBD or blocks were disconnected without any new ones
Expand All @@ -26,7 +36,6 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con
instantsend.UpdatedBlockTip(pindexNew);
mnpayments.UpdatedBlockTip(pindexNew);
governance.UpdatedBlockTip(pindexNew);
masternodeSync.UpdatedBlockTip(pindexNew, fInitialDownload);
}

void CDSNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlock *pblock)
Expand Down
2 changes: 2 additions & 0 deletions src/dsnotificationinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class CDSNotificationInterface : public CValidationInterface

protected:
// CValidationInterface
void AcceptedBlockHeader(const CBlockIndex *pindexNew) override;
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) override;
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
void SyncTransaction(const CTransaction &tx, const CBlock *pblock) override;

Expand Down
90 changes: 78 additions & 12 deletions src/masternode-sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void CMasternodeSync::Reset()
nRequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
nRequestedMasternodeAttempt = 0;
nTimeAssetSyncStarted = GetTime();
nTimeLastBumped = 0;
nTimeLastBumped = GetTime();
nTimeLastFailure = 0;
}

Expand All @@ -44,6 +44,7 @@ std::string CMasternodeSync::GetAssetName()
switch(nRequestedMasternodeAssets)
{
case(MASTERNODE_SYNC_INITIAL): return "MASTERNODE_SYNC_INITIAL";
case(MASTERNODE_SYNC_WAITING): return "MASTERNODE_SYNC_WAITING";
case(MASTERNODE_SYNC_LIST): return "MASTERNODE_SYNC_LIST";
case(MASTERNODE_SYNC_MNW): return "MASTERNODE_SYNC_MNW";
case(MASTERNODE_SYNC_GOVERNANCE): return "MASTERNODE_SYNC_GOVERNANCE";
Expand All @@ -62,6 +63,12 @@ void CMasternodeSync::SwitchToNextAsset()
break;
case(MASTERNODE_SYNC_INITIAL):
ClearFulfilledRequests();
nRequestedMasternodeAssets = MASTERNODE_SYNC_WAITING;
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
break;
case(MASTERNODE_SYNC_WAITING):
ClearFulfilledRequests();
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Completed %s in %llds\n", GetAssetName(), GetTime() - nTimeAssetSyncStarted);
nRequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
break;
Expand Down Expand Up @@ -101,7 +108,8 @@ void CMasternodeSync::SwitchToNextAsset()
std::string CMasternodeSync::GetSyncStatus()
{
switch (masternodeSync.nRequestedMasternodeAssets) {
case MASTERNODE_SYNC_INITIAL: return _("Synchronization pending...");
case MASTERNODE_SYNC_INITIAL: return _("Synchroning blockchain...");
case MASTERNODE_SYNC_WAITING: return _("Synchronization pending...");
case MASTERNODE_SYNC_LIST: return _("Synchronizing masternodes...");
case MASTERNODE_SYNC_MNW: return _("Synchronizing masternode payments...");
case MASTERNODE_SYNC_GOVERNANCE: return _("Synchronizing governance objects...");
Expand Down Expand Up @@ -228,6 +236,22 @@ void CMasternodeSync::ProcessTick()
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- requesting sporks from peer %d\n", nTick, nRequestedMasternodeAssets, pnode->id);
}

// INITIAL TIMEOUT

if(nRequestedMasternodeAssets == MASTERNODE_SYNC_WAITING) {
if(GetTime() - nTimeLastBumped > MASTERNODE_SYNC_TIMEOUT_SECONDS) {
// At this point we know that:
// a) there are peers (because we are looping on at least one of them);
// b) we waited for at least MASTERNODE_SYNC_TIMEOUT_SECONDS since we reached
// the headers tip the last time (i.e. since we switched from
// MASTERNODE_SYNC_INITIAL to MASTERNODE_SYNC_WAITING and bumped time);
// c) there were no blocks (NotifyHeaderTip) or headers (AcceptedBlockHeader)
// for at least MASTERNODE_SYNC_TIMEOUT_SECONDS.
// We must be at the tip already, let's move to the next asset.
SwitchToNextAsset();
}
}

// MNLIST : SYNC MASTERNODE LIST FROM OTHER CONNECTED CLIENTS

if(nRequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
Expand Down Expand Up @@ -386,15 +410,57 @@ void CMasternodeSync::SendGovernanceSyncRequest(CNode* pnode)
}
}

void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload)
void CMasternodeSync::AcceptedBlockHeader(const CBlockIndex *pindexNew)
{
if (fDebug)
LogPrintf("CMasternodeSync::AcceptedBlockHeader -- pindexNew->nHeight: %d\n", pindexNew->nHeight);

if (!IsBlockchainSynced()) {
// Postpone timeout each time new block header arrives while we are still syncing blockchain
BumpAssetLastTime("CMasternodeSync::AcceptedBlockHeader");
}
}

void CMasternodeSync::NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload)
{
if(fDebug) LogPrintf("CMasternodeSync::UpdatedBlockTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload);
// nothing to do here if we failed to sync previousely,
// just wait till status reset after a cooldown (see ProcessTick)
if(IsFailed()) return;
// switch from MASTERNODE_SYNC_INITIAL to the next "asset"
// the first time we are out of IBD mode (and only the first time)
if(!fInitialDownload && !IsBlockchainSynced()) SwitchToNextAsset();
// postpone timeout each time new block arrives while we are syncing
if(!IsSynced()) BumpAssetLastTime("CMasternodeSync::UpdatedBlockTip");
if (fDebug)
LogPrintf("CMasternodeSync::NotifyHeaderTip -- pindexNew->nHeight: %d fInitialDownload=%d\n", pindexNew->nHeight, fInitialDownload);

if (IsFailed() || IsSynced() || !pindexBestHeader)
return;

if (!IsBlockchainSynced()) {
// Postpone timeout each time new block arrives while we are still syncing blockchain
BumpAssetLastTime("CMasternodeSync::NotifyHeaderTip");
}

if (fInitialDownload) {
// no need to check any further while still in IBD mode
return;
}

// Note: since we sync headers first, it should be ok to use this
static bool fReachedBestHeader = false;
bool fReachedBestHeaderNew = pindexNew->GetBlockHash() == pindexBestHeader->GetBlockHash();

if (fReachedBestHeader && !fReachedBestHeaderNew) {
// Switching from true to false means that we previousely stuck syncing headers for some reason,
// probably initial timeout was not enough,
// because there is no way we can update tip not having best header
Reset();
fReachedBestHeader = false;
return;
}

fReachedBestHeader = fReachedBestHeaderNew;

if (fDebug)
LogPrintf("CMasternodeSync::NotifyHeaderTip -- pindexNew->nHeight: %d pindexBestHeader->nHeight: %d fInitialDownload=%d fReachedBestHeader=%d\n",
pindexNew->nHeight, pindexBestHeader->nHeight, fInitialDownload, fReachedBestHeader);

if (!IsBlockchainSynced() && fReachedBestHeader) {
// Reached best header while being in initial mode.
// We must be at the tip already, let's move to the next asset.
SwitchToNextAsset();
}
}
6 changes: 4 additions & 2 deletions src/masternode-sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class CMasternodeSync;

static const int MASTERNODE_SYNC_FAILED = -1;
static const int MASTERNODE_SYNC_INITIAL = 0; // sync just started, was reset recently or still in IDB
static const int MASTERNODE_SYNC_WAITING = 1; // waiting after initial to see if we can get more headers/blocks
static const int MASTERNODE_SYNC_LIST = 2;
static const int MASTERNODE_SYNC_MNW = 3;
static const int MASTERNODE_SYNC_GOVERNANCE = 4;
Expand Down Expand Up @@ -56,7 +57,7 @@ class CMasternodeSync
void SendGovernanceSyncRequest(CNode* pnode);

bool IsFailed() { return nRequestedMasternodeAssets == MASTERNODE_SYNC_FAILED; }
bool IsBlockchainSynced() { return nRequestedMasternodeAssets > MASTERNODE_SYNC_INITIAL; }
bool IsBlockchainSynced() { return nRequestedMasternodeAssets > MASTERNODE_SYNC_WAITING; }
bool IsMasternodeListSynced() { return nRequestedMasternodeAssets > MASTERNODE_SYNC_LIST; }
bool IsWinnersListSynced() { return nRequestedMasternodeAssets > MASTERNODE_SYNC_MNW; }
bool IsSynced() { return nRequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED; }
Expand All @@ -74,7 +75,8 @@ class CMasternodeSync
void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
void ProcessTick();

void UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload);
void AcceptedBlockHeader(const CBlockIndex *pindexNew);
void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload);
};

#endif
4 changes: 4 additions & 0 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2762,6 +2762,7 @@ static void NotifyHeaderTip() {
// Send block tip changed notifications without cs_main
if (fNotify) {
uiInterface.NotifyHeaderTip(fInitialBlockDownload, pindexHeader);
GetMainSignals().NotifyHeaderTip(pindexHeader, fInitialBlockDownload);
}
}

Expand Down Expand Up @@ -3323,6 +3324,9 @@ static bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state

CheckBlockIndex(chainparams.GetConsensus());

// Notify external listeners about accepted block header
GetMainSignals().AcceptedBlockHeader(pindex);

return true;
}

Expand Down
6 changes: 6 additions & 0 deletions src/validationinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ CMainSignals& GetMainSignals()
}

void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.AcceptedBlockHeader.connect(boost::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, _1));
g_signals.NotifyHeaderTip.connect(boost::bind(&CValidationInterface::NotifyHeaderTip, pwalletIn, _1, _2));
g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
g_signals.NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1));
Expand All @@ -36,6 +38,8 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1));
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
g_signals.NotifyHeaderTip.disconnect(boost::bind(&CValidationInterface::NotifyHeaderTip, pwalletIn, _1, _2));
g_signals.AcceptedBlockHeader.disconnect(boost::bind(&CValidationInterface::AcceptedBlockHeader, pwalletIn, _1));
}

void UnregisterAllValidationInterfaces() {
Expand All @@ -49,4 +53,6 @@ void UnregisterAllValidationInterfaces() {
g_signals.NotifyTransactionLock.disconnect_all_slots();
g_signals.SyncTransaction.disconnect_all_slots();
g_signals.UpdatedBlockTip.disconnect_all_slots();
g_signals.NotifyHeaderTip.disconnect_all_slots();
g_signals.AcceptedBlockHeader.disconnect_all_slots();
}
6 changes: 6 additions & 0 deletions src/validationinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ void UnregisterAllValidationInterfaces();

class CValidationInterface {
protected:
virtual void AcceptedBlockHeader(const CBlockIndex *pindexNew) {}
virtual void NotifyHeaderTip(const CBlockIndex *pindexNew, bool fInitialDownload) {}
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {}
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}
virtual void NotifyTransactionLock(const CTransaction &tx) {}
Expand All @@ -46,6 +48,10 @@ class CValidationInterface {
};

struct CMainSignals {
/** Notifies listeners of accepted block header */
boost::signals2::signal<void (const CBlockIndex *)> AcceptedBlockHeader;
/** Notifies listeners of updated block header tip */
boost::signals2::signal<void (const CBlockIndex *, bool fInitialDownload)> NotifyHeaderTip;
/** Notifies listeners of updated block chain tip */
boost::signals2::signal<void (const CBlockIndex *, const CBlockIndex *, bool fInitialDownload)> UpdatedBlockTip;
/** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
Expand Down

0 comments on commit 4f0618a

Please sign in to comment.