521 lines
24 KiB
C++
521 lines
24 KiB
C++
// Copyright (c) 2014-2017 The Dash Core developers
|
|
// Copyright (c) 2021-2024 The NeoBytes Core developers
|
|
// Distributed under the MIT/X11 software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include "activemasternode.h"
|
|
#include "checkpoints.h"
|
|
#include "governance.h"
|
|
#include "main.h"
|
|
#include "masternode.h"
|
|
#include "masternode-payments.h"
|
|
#include "masternode-sync.h"
|
|
#include "masternodeman.h"
|
|
#include "netfulfilledman.h"
|
|
#include "spork.h"
|
|
#include "util.h"
|
|
|
|
class CMasternodeSync;
|
|
CMasternodeSync masternodeSync;
|
|
|
|
bool CMasternodeSync::CheckNodeHeight(CNode* pnode, bool fDisconnectStuckNodes)
|
|
{
|
|
CNodeStateStats stats;
|
|
if(!GetNodeStateStats(pnode->id, stats) || stats.nCommonHeight == -1 || stats.nSyncHeight == -1) return false; // not enough info about this peer
|
|
|
|
// Check blocks and headers, allow a small error margin of 1 block
|
|
if(pCurrentBlockIndex->nHeight - 1 > stats.nCommonHeight) {
|
|
// This peer probably stuck, don't sync any additional data from it
|
|
if(fDisconnectStuckNodes) {
|
|
// Disconnect to free this connection slot for another peer.
|
|
pnode->fDisconnect = true;
|
|
LogPrintf("CMasternodeSync::CheckNodeHeight -- disconnecting from stuck peer, nHeight=%d, nCommonHeight=%d, peer=%d\n",
|
|
pCurrentBlockIndex->nHeight, stats.nCommonHeight, pnode->id);
|
|
} else {
|
|
LogPrintf("CMasternodeSync::CheckNodeHeight -- skipping stuck peer, nHeight=%d, nCommonHeight=%d, peer=%d\n",
|
|
pCurrentBlockIndex->nHeight, stats.nCommonHeight, pnode->id);
|
|
}
|
|
return false;
|
|
}
|
|
else if(pCurrentBlockIndex->nHeight < stats.nSyncHeight - 1) {
|
|
// This peer announced more headers than we have blocks currently
|
|
LogPrintf("CMasternodeSync::CheckNodeHeight -- skipping peer, who announced more headers than we have blocks currently, nHeight=%d, nSyncHeight=%d, peer=%d\n",
|
|
pCurrentBlockIndex->nHeight, stats.nSyncHeight, pnode->id);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CMasternodeSync::IsBlockchainSynced(bool fBlockAccepted)
|
|
{
|
|
static bool fBlockchainSynced = false;
|
|
static int64_t nTimeLastProcess = GetTime();
|
|
static int nSkipped = 0;
|
|
static bool fFirstBlockAccepted = false;
|
|
|
|
// if the last call to this function was more than 60 minutes ago (client was in sleep mode) reset the sync process
|
|
if(GetTime() - nTimeLastProcess > 60*60) {
|
|
Reset();
|
|
fBlockchainSynced = false;
|
|
}
|
|
|
|
if(!pCurrentBlockIndex || !pindexBestHeader || fImporting || fReindex) return false;
|
|
|
|
if(fBlockAccepted) {
|
|
// this should be only triggered while we are still syncing
|
|
if(!IsSynced()) {
|
|
// we are trying to download smth, reset blockchain sync status
|
|
if(fDebug) LogPrintf("CMasternodeSync::IsBlockchainSynced -- reset\n");
|
|
fFirstBlockAccepted = true;
|
|
fBlockchainSynced = false;
|
|
nTimeLastProcess = GetTime();
|
|
return false;
|
|
}
|
|
} else {
|
|
// skip if we already checked less than 1 tick ago
|
|
if(GetTime() - nTimeLastProcess < MASTERNODE_SYNC_TICK_SECONDS) {
|
|
nSkipped++;
|
|
return fBlockchainSynced;
|
|
}
|
|
}
|
|
|
|
if(fDebug) LogPrintf("CMasternodeSync::IsBlockchainSynced -- state before check: %ssynced, skipped %d times\n", fBlockchainSynced ? "" : "not ", nSkipped);
|
|
|
|
nTimeLastProcess = GetTime();
|
|
nSkipped = 0;
|
|
|
|
if(fBlockchainSynced) return true;
|
|
|
|
if(fCheckpointsEnabled && pCurrentBlockIndex->nHeight < Checkpoints::GetTotalBlocksEstimate(Params().Checkpoints()))
|
|
return false;
|
|
|
|
std::vector<CNode*> vNodesCopy = CopyNodeVector();
|
|
|
|
// We have enough peers and assume most of them are synced
|
|
if(vNodesCopy.size() >= MASTERNODE_SYNC_ENOUGH_PEERS) {
|
|
// Check to see how many of our peers are (almost) at the same height as we are
|
|
int nNodesAtSameHeight = 0;
|
|
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
|
{
|
|
// Make sure this peer is presumably at the same height
|
|
if(!CheckNodeHeight(pnode)) continue;
|
|
nNodesAtSameHeight++;
|
|
// if we have decent number of such peers, most likely we are synced now
|
|
if(nNodesAtSameHeight >= MASTERNODE_SYNC_ENOUGH_PEERS) {
|
|
LogPrintf("CMasternodeSync::IsBlockchainSynced -- found enough peers on the same height as we are, done\n");
|
|
fBlockchainSynced = true;
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
ReleaseNodeVector(vNodesCopy);
|
|
|
|
// wait for at least one new block to be accepted
|
|
if(!fFirstBlockAccepted) return false;
|
|
|
|
// same as !IsInitialBlockDownload() but no cs_main needed here
|
|
int64_t nMaxBlockTime = std::max(pCurrentBlockIndex->GetBlockTime(), pindexBestHeader->GetBlockTime());
|
|
fBlockchainSynced = pindexBestHeader->nHeight - pCurrentBlockIndex->nHeight < 24 * 6 &&
|
|
GetTime() - nMaxBlockTime < Params().MaxTipAge();
|
|
|
|
return fBlockchainSynced;
|
|
}
|
|
|
|
void CMasternodeSync::Fail()
|
|
{
|
|
nTimeLastFailure = GetTime();
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
|
|
}
|
|
|
|
void CMasternodeSync::Reset()
|
|
{
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
|
|
nRequestedMasternodeAttempt = 0;
|
|
nTimeAssetSyncStarted = GetTime();
|
|
nTimeLastMasternodeList = GetTime();
|
|
nTimeLastPaymentVote = GetTime();
|
|
nTimeLastGovernanceItem = GetTime();
|
|
nTimeLastFailure = 0;
|
|
nCountFailures = 0;
|
|
}
|
|
|
|
std::string CMasternodeSync::GetAssetName()
|
|
{
|
|
switch(nRequestedMasternodeAssets)
|
|
{
|
|
case(MASTERNODE_SYNC_INITIAL): return "MASTERNODE_SYNC_INITIAL";
|
|
case(MASTERNODE_SYNC_SPORKS): return "MASTERNODE_SYNC_SPORKS";
|
|
case(MASTERNODE_SYNC_LIST): return "MASTERNODE_SYNC_LIST";
|
|
case(MASTERNODE_SYNC_MNW): return "MASTERNODE_SYNC_MNW";
|
|
case(MASTERNODE_SYNC_GOVERNANCE): return "MASTERNODE_SYNC_GOVERNANCE";
|
|
case(MASTERNODE_SYNC_FAILED): return "MASTERNODE_SYNC_FAILED";
|
|
case MASTERNODE_SYNC_FINISHED: return "MASTERNODE_SYNC_FINISHED";
|
|
default: return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
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):
|
|
ClearFulfilledRequests();
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS;
|
|
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
|
|
break;
|
|
case(MASTERNODE_SYNC_SPORKS):
|
|
nTimeLastMasternodeList = GetTime();
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
|
|
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
|
|
break;
|
|
case(MASTERNODE_SYNC_LIST):
|
|
nTimeLastPaymentVote = GetTime();
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_MNW;
|
|
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
|
|
break;
|
|
case(MASTERNODE_SYNC_MNW):
|
|
nTimeLastGovernanceItem = GetTime();
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_GOVERNANCE;
|
|
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Starting %s\n", GetAssetName());
|
|
break;
|
|
case(MASTERNODE_SYNC_GOVERNANCE):
|
|
LogPrintf("CMasternodeSync::SwitchToNextAsset -- Sync has finished\n");
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
|
|
uiInterface.NotifyAdditionalDataSyncProgressChanged(1);
|
|
//try to activate our masternode if possible
|
|
activeMasternode.ManageState();
|
|
|
|
TRY_LOCK(cs_vNodes, lockRecv);
|
|
if(!lockRecv) return;
|
|
|
|
BOOST_FOREACH(CNode* pnode, vNodes) {
|
|
netfulfilledman.AddFulfilledRequest(pnode->addr, "full-sync");
|
|
}
|
|
|
|
break;
|
|
}
|
|
nRequestedMasternodeAttempt = 0;
|
|
nTimeAssetSyncStarted = GetTime();
|
|
}
|
|
|
|
std::string CMasternodeSync::GetSyncStatus()
|
|
{
|
|
switch (masternodeSync.nRequestedMasternodeAssets) {
|
|
case MASTERNODE_SYNC_INITIAL: return _("Synchronization pending...");
|
|
case MASTERNODE_SYNC_SPORKS: return _("Synchronizing sporks...");
|
|
case MASTERNODE_SYNC_LIST: return _("Synchronizing masternodes...");
|
|
case MASTERNODE_SYNC_MNW: return _("Synchronizing masternode payments...");
|
|
case MASTERNODE_SYNC_GOVERNANCE: return _("Synchronizing governance objects...");
|
|
case MASTERNODE_SYNC_FAILED: return _("Synchronization failed");
|
|
case MASTERNODE_SYNC_FINISHED: return _("Synchronization finished");
|
|
default: return "";
|
|
}
|
|
}
|
|
|
|
void CMasternodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
|
|
{
|
|
if (strCommand == NetMsgType::SYNCSTATUSCOUNT) { //Sync status count
|
|
|
|
//do not care about stats if sync process finished or failed
|
|
if(IsSynced() || IsFailed()) return;
|
|
|
|
int nItemID;
|
|
int nCount;
|
|
vRecv >> nItemID >> nCount;
|
|
|
|
LogPrintf("SYNCSTATUSCOUNT -- got inventory count: nItemID=%d nCount=%d peer=%d\n", nItemID, nCount, pfrom->id);
|
|
}
|
|
}
|
|
|
|
void CMasternodeSync::ClearFulfilledRequests()
|
|
{
|
|
TRY_LOCK(cs_vNodes, lockRecv);
|
|
if(!lockRecv) return;
|
|
|
|
BOOST_FOREACH(CNode* pnode, vNodes)
|
|
{
|
|
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "spork-sync");
|
|
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "masternode-list-sync");
|
|
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "masternode-payment-sync");
|
|
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "governance-sync");
|
|
netfulfilledman.RemoveFulfilledRequest(pnode->addr, "full-sync");
|
|
}
|
|
}
|
|
|
|
void CMasternodeSync::ProcessTick()
|
|
{
|
|
static int nTick = 0;
|
|
if(nTick++ % MASTERNODE_SYNC_TICK_SECONDS != 0) return;
|
|
if(!pCurrentBlockIndex) return;
|
|
|
|
//the actual count of masternodes we have currently
|
|
int nMnCount = mnodeman.CountMasternodes();
|
|
|
|
if(fDebug) LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nMnCount %d\n", nTick, nMnCount);
|
|
|
|
// RESET SYNCING INCASE OF FAILURE
|
|
{
|
|
if(IsSynced()) {
|
|
/*
|
|
Resync if we lost all masternodes from sleep/wake or failed to sync originally
|
|
*/
|
|
if(nMnCount == 0) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- WARNING: not enough data, restarting sync\n");
|
|
Reset();
|
|
} else {
|
|
std::vector<CNode*> vNodesCopy = CopyNodeVector();
|
|
governance.RequestGovernanceObjectVotes(vNodesCopy);
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
}
|
|
|
|
//try syncing again
|
|
if(IsFailed()) {
|
|
if(nTimeLastFailure + (1*60) < GetTime()) { // 1 minute cooldown after failed sync
|
|
Reset();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// INITIAL SYNC SETUP / LOG REPORTING
|
|
double nSyncProgress = double(nRequestedMasternodeAttempt + (nRequestedMasternodeAssets - 1) * 8) / (8*4);
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nRequestedMasternodeAttempt %d nSyncProgress %f\n", nTick, nRequestedMasternodeAssets, nRequestedMasternodeAttempt, nSyncProgress);
|
|
uiInterface.NotifyAdditionalDataSyncProgressChanged(nSyncProgress);
|
|
|
|
// sporks synced but blockchain is not, wait until we're almost at a recent block to continue
|
|
if(Params().NetworkIDString() != CBaseChainParams::REGTEST &&
|
|
!IsBlockchainSynced() && nRequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS)
|
|
{
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nRequestedMasternodeAttempt %d -- blockchain is not synced yet\n", nTick, nRequestedMasternodeAssets, nRequestedMasternodeAttempt);
|
|
nTimeLastMasternodeList = GetTime();
|
|
nTimeLastPaymentVote = GetTime();
|
|
nTimeLastGovernanceItem = GetTime();
|
|
return;
|
|
}
|
|
|
|
if(nRequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL ||
|
|
(nRequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS && IsBlockchainSynced()))
|
|
{
|
|
SwitchToNextAsset();
|
|
}
|
|
|
|
std::vector<CNode*> vNodesCopy = CopyNodeVector();
|
|
|
|
BOOST_FOREACH(CNode* pnode, vNodesCopy)
|
|
{
|
|
// Don't try to sync any data from outbound "masternode" connections -
|
|
// they are temporary and should be considered unreliable for a sync process.
|
|
// Inbound connection this early is most likely a "masternode" connection
|
|
// initialted from another node, so skip it too.
|
|
if(pnode->fMasternode || (fMasterNode && pnode->fInbound)) continue;
|
|
|
|
// QUICK MODE (REGTEST ONLY!)
|
|
if(Params().NetworkIDString() == CBaseChainParams::REGTEST)
|
|
{
|
|
if(nRequestedMasternodeAttempt <= 2) {
|
|
pnode->PushMessage(NetMsgType::GETSPORKS); //get current network sporks
|
|
} else if(nRequestedMasternodeAttempt < 4) {
|
|
mnodeman.DsegUpdate(pnode);
|
|
} else if(nRequestedMasternodeAttempt < 6) {
|
|
int nMnCount = mnodeman.CountMasternodes();
|
|
pnode->PushMessage(NetMsgType::MASTERNODEPAYMENTSYNC, nMnCount); //sync payment votes
|
|
SendGovernanceSyncRequest(pnode);
|
|
} else {
|
|
nRequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
|
|
}
|
|
nRequestedMasternodeAttempt++;
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
|
|
// NORMAL NETWORK MODE - TESTNET/MAINNET
|
|
{
|
|
if(netfulfilledman.HasFulfilledRequest(pnode->addr, "full-sync")) {
|
|
// We already fully synced from this node recently,
|
|
// disconnect to free this connection slot for another peer.
|
|
pnode->fDisconnect = true;
|
|
LogPrintf("CMasternodeSync::ProcessTick -- disconnecting from recently synced peer %d\n", pnode->id);
|
|
continue;
|
|
}
|
|
|
|
// SPORK : ALWAYS ASK FOR SPORKS AS WE SYNC (we skip this mode now)
|
|
|
|
if(!netfulfilledman.HasFulfilledRequest(pnode->addr, "spork-sync")) {
|
|
// only request once from each peer
|
|
netfulfilledman.AddFulfilledRequest(pnode->addr, "spork-sync");
|
|
// get current network sporks
|
|
pnode->PushMessage(NetMsgType::GETSPORKS);
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- requesting sporks from peer %d\n", nTick, nRequestedMasternodeAssets, pnode->id);
|
|
continue; // always get sporks first, switch to the next node without waiting for the next tick
|
|
}
|
|
|
|
// MNLIST : SYNC MASTERNODE LIST FROM OTHER CONNECTED CLIENTS
|
|
|
|
if(nRequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
|
|
LogPrint("masternode", "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastMasternodeList %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastMasternodeList, GetTime(), GetTime() - nTimeLastMasternodeList);
|
|
// check for timeout first
|
|
if(nTimeLastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT_SECONDS) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets);
|
|
if (nRequestedMasternodeAttempt == 0) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName());
|
|
// there is no way we can continue without masternode list, fail here and try later
|
|
Fail();
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
SwitchToNextAsset();
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
|
|
// only request once from each peer
|
|
if(netfulfilledman.HasFulfilledRequest(pnode->addr, "masternode-list-sync")) continue;
|
|
netfulfilledman.AddFulfilledRequest(pnode->addr, "masternode-list-sync");
|
|
|
|
if (pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue;
|
|
nRequestedMasternodeAttempt++;
|
|
|
|
mnodeman.DsegUpdate(pnode);
|
|
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return; //this will cause each peer to get one request each six seconds for the various assets we need
|
|
}
|
|
|
|
// MNW : SYNC MASTERNODE PAYMENT VOTES FROM OTHER CONNECTED CLIENTS
|
|
|
|
if(nRequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
|
|
LogPrint("mnpayments", "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastPaymentVote %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastPaymentVote, GetTime(), GetTime() - nTimeLastPaymentVote);
|
|
// check for timeout first
|
|
// This might take a lot longer than MASTERNODE_SYNC_TIMEOUT_SECONDS minutes due to new blocks,
|
|
// but that should be OK and it should timeout eventually.
|
|
if(nTimeLastPaymentVote < GetTime() - MASTERNODE_SYNC_TIMEOUT_SECONDS) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets);
|
|
if (nRequestedMasternodeAttempt == 0) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- ERROR: failed to sync %s\n", GetAssetName());
|
|
// probably not a good idea to proceed without winner list
|
|
Fail();
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
SwitchToNextAsset();
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
|
|
// check for data
|
|
// if mnpayments already has enough blocks and votes, switch to the next asset
|
|
// try to fetch data from at least two peers though
|
|
if(nRequestedMasternodeAttempt > 1 && mnpayments.IsEnoughData()) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- found enough data\n", nTick, nRequestedMasternodeAssets);
|
|
SwitchToNextAsset();
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
|
|
// only request once from each peer
|
|
if(netfulfilledman.HasFulfilledRequest(pnode->addr, "masternode-payment-sync")) continue;
|
|
netfulfilledman.AddFulfilledRequest(pnode->addr, "masternode-payment-sync");
|
|
|
|
if(pnode->nVersion < mnpayments.GetMinMasternodePaymentsProto()) continue;
|
|
nRequestedMasternodeAttempt++;
|
|
|
|
// ask node for all payment votes it has (new nodes will only return votes for future payments)
|
|
pnode->PushMessage(NetMsgType::MASTERNODEPAYMENTSYNC, mnpayments.GetStorageLimit());
|
|
// ask node for missing pieces only (old nodes will not be asked)
|
|
mnpayments.RequestLowDataPaymentBlocks(pnode);
|
|
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return; //this will cause each peer to get one request each six seconds for the various assets we need
|
|
}
|
|
|
|
// GOVOBJ : SYNC GOVERNANCE ITEMS FROM OUR PEERS
|
|
|
|
if(nRequestedMasternodeAssets == MASTERNODE_SYNC_GOVERNANCE) {
|
|
LogPrint("gobject", "CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d nTimeLastGovernanceItem %lld GetTime() %lld diff %lld\n", nTick, nRequestedMasternodeAssets, nTimeLastGovernanceItem, GetTime(), GetTime() - nTimeLastGovernanceItem);
|
|
|
|
// check for timeout first
|
|
if(GetTime() - nTimeLastGovernanceItem > MASTERNODE_SYNC_TIMEOUT_SECONDS) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- timeout\n", nTick, nRequestedMasternodeAssets);
|
|
if(nRequestedMasternodeAttempt == 0) {
|
|
LogPrintf("CMasternodeSync::ProcessTick -- WARNING: failed to sync %s\n", GetAssetName());
|
|
// it's kind of ok to skip this for now, hopefully we'll catch up later?
|
|
}
|
|
SwitchToNextAsset();
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
|
|
// only request obj sync once from each peer, then request votes on per-obj basis
|
|
if(netfulfilledman.HasFulfilledRequest(pnode->addr, "governance-sync")) {
|
|
int nObjsLeftToAsk = governance.RequestGovernanceObjectVotes(pnode);
|
|
static int64_t nTimeNoObjectsLeft = 0;
|
|
// check for data
|
|
if(nObjsLeftToAsk == 0) {
|
|
static int nLastTick = 0;
|
|
static int nLastVotes = 0;
|
|
if(nTimeNoObjectsLeft == 0) {
|
|
// asked all objects for votes for the first time
|
|
nTimeNoObjectsLeft = GetTime();
|
|
}
|
|
// make sure the condition below is checked only once per tick
|
|
if(nLastTick == nTick) continue;
|
|
if(GetTime() - nTimeNoObjectsLeft > MASTERNODE_SYNC_TIMEOUT_SECONDS &&
|
|
governance.GetVoteCount() - nLastVotes < std::max(int(0.0001 * nLastVotes), MASTERNODE_SYNC_TICK_SECONDS)
|
|
) {
|
|
// We already asked for all objects, waited for MASTERNODE_SYNC_TIMEOUT_SECONDS
|
|
// after that and less then 0.01% or MASTERNODE_SYNC_TICK_SECONDS
|
|
// (i.e. 1 per second) votes were recieved during the last tick.
|
|
// We can be pretty sure that we are done syncing.
|
|
LogPrintf("CMasternodeSync::ProcessTick -- nTick %d nRequestedMasternodeAssets %d -- asked for all objects, nothing to do\n", nTick, nRequestedMasternodeAssets);
|
|
// reset nTimeNoObjectsLeft to be able to use the same condition on resync
|
|
nTimeNoObjectsLeft = 0;
|
|
SwitchToNextAsset();
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return;
|
|
}
|
|
nLastTick = nTick;
|
|
nLastVotes = governance.GetVoteCount();
|
|
}
|
|
continue;
|
|
}
|
|
netfulfilledman.AddFulfilledRequest(pnode->addr, "governance-sync");
|
|
|
|
if (pnode->nVersion < MIN_GOVERNANCE_PEER_PROTO_VERSION) continue;
|
|
nRequestedMasternodeAttempt++;
|
|
|
|
SendGovernanceSyncRequest(pnode);
|
|
|
|
ReleaseNodeVector(vNodesCopy);
|
|
return; //this will cause each peer to get one request each six seconds for the various assets we need
|
|
}
|
|
}
|
|
}
|
|
// looped through all nodes, release them
|
|
ReleaseNodeVector(vNodesCopy);
|
|
}
|
|
|
|
void CMasternodeSync::SendGovernanceSyncRequest(CNode* pnode)
|
|
{
|
|
if(pnode->nVersion >= GOVERNANCE_FILTER_PROTO_VERSION) {
|
|
CBloomFilter filter;
|
|
filter.clear();
|
|
|
|
pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, uint256(), filter);
|
|
}
|
|
else {
|
|
pnode->PushMessage(NetMsgType::MNGOVERNANCESYNC, uint256());
|
|
}
|
|
}
|
|
|
|
void CMasternodeSync::UpdatedBlockTip(const CBlockIndex *pindex)
|
|
{
|
|
pCurrentBlockIndex = pindex;
|
|
}
|