From da406e3d23d4e86d2a27d4c9d3e5f818ef0df15f Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Sun, 28 Aug 2016 23:25:09 +0300 Subject: [PATCH] Masternode sync improvements: - add simple helpers for few more sync states (use them where appropriate instead of old code + rpc output) - use new helpers to avoid meaningless message processing - actually fail if sync shouldn't continue due to lack of info, make sure Reset is used to quit failed state --- src/darksend.cpp | 2 +- src/governance.cpp | 12 +++++++----- src/instantx.cpp | 4 +++- src/masternode-payments.cpp | 25 ++++++++++++++++--------- src/masternode-sync.cpp | 21 ++++++++++++++++----- src/masternode-sync.h | 6 ++++-- src/masternodeman.cpp | 11 ++++++++--- src/qt/masternodelist.cpp | 2 +- src/rpcmasternode.cpp | 5 ++--- src/rpcmisc.cpp | 2 ++ 10 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/darksend.cpp b/src/darksend.cpp index aa0c097b95..9da7ffd337 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -2313,7 +2313,7 @@ void CDarksendPool::UpdatedBlockTip(const CBlockIndex *pindex) pCurrentBlockIndex = pindex; LogPrint("privatesend", "CDarksendPool::UpdatedBlockTip -- pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight); - if(!fLiteMode && masternodeSync.GetAssetID() > MASTERNODE_SYNC_LIST) { + if(!fLiteMode && masternodeSync.IsMasternodeListSynced()) { NewBlock(); } } diff --git a/src/governance.cpp b/src/governance.cpp index 95a66e9c2c..c0941a90f4 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -281,6 +281,9 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, std::string& strCommand, C // A NEW GOVERNANCE OBJECT VOTE HAS ARRIVED else if (strCommand == NetMsgType::MNGOVERNANCEOBJECTVOTE) { + // Ignore such messages until masternode list is synced + if(!masternodeSync.IsMasternodeListSynced()) return; + CGovernanceVote vote; vRecv >> vote; vote.fValid = true; @@ -551,13 +554,12 @@ struct sortProposalsByVotes { void CGovernanceManager::NewBlock() { + // IF WE'RE NOT SYNCED, EXIT + if(!masternodeSync.IsSynced()) return; + TRY_LOCK(cs, fBudgetNewBlock); if(!fBudgetNewBlock || !pCurrentBlockIndex) return; - // IF WE'RE NOT SYNCED, EXIT - - if(!masternodeSync.IsSynced()) return; - // CHECK OBJECTS WE'VE ASKED FOR, REMOVE OLD ENTRIES std::map::iterator it = mapAskedForGovernanceObject.begin(); @@ -1065,7 +1067,7 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex *pindex) // TO REPROCESS OBJECTS WE SHOULD BE SYNCED - if(!fLiteMode && masternodeSync.GetAssetID() > MASTERNODE_SYNC_LIST) + if(!fLiteMode && masternodeSync.IsSynced()) NewBlock(); } diff --git a/src/instantx.cpp b/src/instantx.cpp index b3bd3970fe..a1f5647580 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -47,7 +47,9 @@ void ProcessMessageInstantSend(CNode* pfrom, std::string& strCommand, CDataStrea { if(fLiteMode) return; // disable all Dash specific functionality if(!sporkManager.IsSporkActive(SPORK_2_INSTANTX)) return; - if(!masternodeSync.IsBlockchainSynced()) return; + + // Ignore any InstantSend messages until masternode list is synced + if(!masternodeSync.IsMasternodeListSynced()) return; if (strCommand == NetMsgType::IX) { diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 011d83b394..651cda2f82 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -260,14 +260,16 @@ int CMasternodePayments::GetMinMasternodePaymentsProto() { void CMasternodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { - if(!masternodeSync.IsBlockchainSynced()) return; - - if(fLiteMode) return; //disable all Darksend/Masternode related functionality + // Ignore any payments messages until masternode list is synced + if(!masternodeSync.IsMasternodeListSynced()) return; + if(fLiteMode) return; // disable all Dash specific functionality if (strCommand == NetMsgType::MNWINNERSSYNC) { //Masternode Payments Request Sync - // ignore such request until we are fully synced + // Ignore such requests until we are fully synced. + // We could start processing this after masternode list is synced + // but this is a heavy one so it's better to finish sync first. if (!masternodeSync.IsSynced()) return; int nCountNeeded; @@ -294,9 +296,6 @@ void CMasternodePayments::ProcessMessage(CNode* pfrom, std::string& strCommand, if(!pCurrentBlockIndex) return; - // can't really verify it until masternode list is synced, reject it for now - if (masternodeSync.GetAssetID() < MASTERNODE_SYNC_MNW) return; - if(mapMasternodePayeeVotes.count(winner.GetHash())) { LogPrint("mnpayments", "MNWINNER -- Already seen: hash=%s, nHeight=%d\n", winner.GetHash().ToString(), pCurrentBlockIndex->nHeight); masternodeSync.AddedMasternodeWinner(winner.GetHash()); @@ -549,7 +548,10 @@ bool CMasternodePaymentWinner::IsValid(CNode* pnode, int nValidationHeight, std: if(!pmn) { strError = strprintf("Unknown Masternode: prevout=%s", vinMasternode.prevout.ToStringShort()); // Only ask if we are already synced and still have no idea about that Masternode - if (masternodeSync.IsSynced()) mnodeman.AskForMN(pnode, vinMasternode); + if(masternodeSync.IsSynced()) { + mnodeman.AskForMN(pnode, vinMasternode); + } + return false; } @@ -581,6 +583,11 @@ bool CMasternodePayments::ProcessBlock(int nBlockHeight) // DETERMINE IF WE SHOULD BE VOTING FOR THE NEXT PAYEE if(!fMasterNode) return false; + + // We have little chances to pick the right winner if we winners list is out of sync + // but we have no choice, so we'll try. However it doesn't make sense to even try to do so + // if we have not enough data about masternodes. + if(!masternodeSync.IsMasternodeListSynced()) return false; int n = mnodeman.GetMasternodeRank(activeMasternode.vin, nBlockHeight - 101, MIN_MNW_PEER_PROTO_VERSION); @@ -760,7 +767,7 @@ void CMasternodePayments::UpdatedBlockTip(const CBlockIndex *pindex) pCurrentBlockIndex = pindex; LogPrint("mnpayments", "pCurrentBlockIndex->nHeight: %d\n", pCurrentBlockIndex->nHeight); - if (!fLiteMode && masternodeSync.GetAssetID() > MASTERNODE_SYNC_LIST) { + if (!fLiteMode && masternodeSync.IsMasternodeListSynced()) { ProcessBlock(pindex->nHeight + 10); } } diff --git a/src/masternode-sync.cpp b/src/masternode-sync.cpp index b8fbad8b3f..ebcca7eb62 100644 --- a/src/masternode-sync.cpp +++ b/src/masternode-sync.cpp @@ -109,8 +109,10 @@ void CMasternodeSync::SwitchToNextAsset() { switch(nRequestedMasternodeAssets) { + case(MASTERNODE_SYNC_FAILED): + throw std::runtime_error("Can't switch to next asset from failed, should use Reset() first!"); + break; case(MASTERNODE_SYNC_INITIAL): - case(MASTERNODE_SYNC_FAILED): // should never be used here actually, use Reset() instead ClearFulfilledRequest(); nRequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS; break; @@ -159,9 +161,9 @@ void CMasternodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDat int nCount; vRecv >> nItemID >> nCount; - if(nRequestedMasternodeAssets >= MASTERNODE_SYNC_FINISHED) return; + //do not care about stats if sync process finished or failed + if(IsSynced() || IsFailed()) return; - //this means we will receive no further communication switch(nItemID) { case(MASTERNODE_SYNC_LIST): @@ -229,8 +231,9 @@ void CMasternodeSync::ProcessTick() //try syncing again if(IsFailed()) { - if(nTimeLastFailure + (1*60) < GetTime()) // 1 minute cooldown after failed sync + if(nTimeLastFailure + (1*60) < GetTime()) { // 1 minute cooldown after failed sync Reset(); + } return; } } @@ -247,7 +250,9 @@ void CMasternodeSync::ProcessTick() TRY_LOCK(cs_vNodes, lockRecv); if(!lockRecv) return; - if(nRequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) SwitchToNextAsset(); + if(nRequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) { + SwitchToNextAsset(); + } BOOST_FOREACH(CNode* pnode, vNodes) { @@ -295,6 +300,9 @@ void CMasternodeSync::ProcessTick() LogPrintf("CMasternodeSync::Process -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets); if (nRequestedMasternodeAttempt == 0) { LogPrintf("CMasternodeSync::Process -- WARNING: failed to sync %s\n", GetAssetName()); + // there is no way we can continue without masternode list, fail here and try later + Fail(); + return; } SwitchToNextAsset(); return; @@ -333,6 +341,9 @@ void CMasternodeSync::ProcessTick() LogPrintf("CMasternodeSync::Process -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets); if (nRequestedMasternodeAttempt == 0) { LogPrintf("CMasternodeSync::Process -- WARNING: failed to sync %s\n", GetAssetName()); + // probably not a good idea to proceed without winner list + Fail(); + return; } SwitchToNextAsset(); return; diff --git a/src/masternode-sync.h b/src/masternode-sync.h index 60b6de9a0b..bc8ffe63a7 100644 --- a/src/masternode-sync.h +++ b/src/masternode-sync.h @@ -11,6 +11,7 @@ class CMasternodeSync; +static const int MASTERNODE_SYNC_FAILED = -1; static const int MASTERNODE_SYNC_INITIAL = 0; static const int MASTERNODE_SYNC_SPORKS = 1; static const int MASTERNODE_SYNC_LIST = 2; @@ -18,7 +19,6 @@ static const int MASTERNODE_SYNC_MNW = 3; static const int MASTERNODE_SYNC_GOVERNANCE = 4; static const int MASTERNODE_SYNC_GOVOBJ = 10; static const int MASTERNODE_SYNC_GOVERNANCE_FIN = 11; -static const int MASTERNODE_SYNC_FAILED = 998; static const int MASTERNODE_SYNC_FINISHED = 999; static const int MASTERNODE_SYNC_TIMEOUT_SECONDS = 30; // our blocks are 2.5 minutes so 30 seconds should be fine @@ -80,8 +80,10 @@ public: void AddedBudgetItem(uint256 hash); bool IsFailed() { return nRequestedMasternodeAssets == MASTERNODE_SYNC_FAILED; } - bool IsSynced() { return nRequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED; } bool IsBlockchainSynced(); + bool IsMasternodeListSynced() { return nRequestedMasternodeAssets > MASTERNODE_SYNC_LIST; } + bool IsWinnersListSynced() { return nRequestedMasternodeAssets > MASTERNODE_SYNC_MNW; } + bool IsSynced() { return nRequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED; } int GetAssetID() { return nRequestedMasternodeAssets; } int GetAttempt() { return nRequestedMasternodeAttempt; } diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 3f3f58615b..f7b11266a8 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -568,9 +568,12 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } else { if(nDos > 0) Misbehaving(pfrom->GetId(), nDos); } - } - else if (strCommand == NetMsgType::MNPING) { //Masternode Ping + } else if (strCommand == NetMsgType::MNPING) { //Masternode Ping + + // ignore masternode pings until masternode list is synced + if (!masternodeSync.IsMasternodeListSynced()) return; + CMasternodePing mnp; vRecv >> mnp; @@ -600,7 +603,9 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } else if (strCommand == NetMsgType::DSEG) { //Get Masternode list or specific entry - // ignore such request until we are fully synced + // Ignore such requests until we are fully synced. + // We could start processing this after masternode list is synced + // but this is a heavy one so it's better to finish sync first. if (!masternodeSync.IsSynced()) return; CTxIn vin; diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index 51e3ea5ac3..f124430ec9 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -363,7 +363,7 @@ void MasternodeList::on_startAllButton_clicked() void MasternodeList::on_startMissingButton_clicked() { - if(masternodeSync.GetAssetID() <= MASTERNODE_SYNC_LIST || masternodeSync.IsFailed()) { + if(!masternodeSync.IsMasternodeListSynced()) { QMessageBox::critical(this, tr("Command is not available right now"), tr("You can't use this command until masternode list is synced")); return; diff --git a/src/rpcmasternode.cpp b/src/rpcmasternode.cpp index 8154f55591..836cee02a1 100644 --- a/src/rpcmasternode.cpp +++ b/src/rpcmasternode.cpp @@ -319,9 +319,8 @@ UniValue masternode(const UniValue& params, bool fHelp) } } - if((strCommand == "start-missing" || strCommand == "start-disabled") && - (masternodeSync.GetAssetID() <= MASTERNODE_SYNC_LIST || masternodeSync.IsFailed())) { - throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "You can't use this command until masternode list is synced"); + if((strCommand == "start-missing" || strCommand == "start-disabled") && !masternodeSync.IsMasternodeListSynced()) { + throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "You can't use this command until masternode list is synced"); } int successful = 0; diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp index e3837efa1c..d58e7b3d16 100644 --- a/src/rpcmisc.cpp +++ b/src/rpcmisc.cpp @@ -155,6 +155,8 @@ UniValue mnsync(const UniValue& params, bool fHelp) objStatus.push_back(Pair("AssetName", masternodeSync.GetAssetName())); objStatus.push_back(Pair("Attempt", masternodeSync.GetAttempt())); objStatus.push_back(Pair("IsBlockchainSynced", masternodeSync.IsBlockchainSynced())); + objStatus.push_back(Pair("IsMasternodeListSynced", masternodeSync.IsMasternodeListSynced())); + objStatus.push_back(Pair("IsWinnersListSynced", masternodeSync.IsWinnersListSynced())); objStatus.push_back(Pair("IsSynced", masternodeSync.IsSynced())); objStatus.push_back(Pair("IsFailed", masternodeSync.IsFailed())); return objStatus;