dash/src/masternode-sync.cpp

435 lines
16 KiB
C++
Raw Normal View History

// Copyright (c) 2014-2016 The Dash Core developers
2015-07-15 04:44:58 +02:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
2015-07-29 05:26:08 +02:00
#include "activemasternode.h"
2015-07-15 04:44:58 +02:00
#include "masternode-sync.h"
2015-07-19 01:20:48 +02:00
#include "masternode-payments.h"
#include "masternode-budget.h"
2015-07-15 04:44:58 +02:00
#include "masternode.h"
#include "masternodeman.h"
#include "spork.h"
2015-07-15 04:44:58 +02:00
#include "util.h"
#include "addrman.h"
class CMasternodeSync;
CMasternodeSync masternodeSync;
CMasternodeSync::CMasternodeSync()
{
2015-08-04 20:21:27 +02:00
Reset();
2015-07-15 04:44:58 +02:00
}
bool CMasternodeSync::IsSynced()
{
2015-07-23 03:53:17 +02:00
return RequestedMasternodeAssets == MASTERNODE_SYNC_FINISHED;
2015-07-15 04:44:58 +02:00
}
bool CMasternodeSync::IsBlockchainSynced()
{
static bool fBlockchainSynced = false;
2015-08-04 23:15:24 +02:00
static int64_t lastProcess = GetTime();
2015-08-11 23:54:42 +02:00
// if the last call to this function was more than 60 minutes ago (client was in sleep mode) reset the sync process
if(GetTime() - lastProcess > 60*60) {
2015-08-04 23:15:24 +02:00
Reset();
fBlockchainSynced = false;
}
lastProcess = GetTime();
if(fBlockchainSynced) return true;
2015-08-03 22:42:18 +02:00
if (fImporting || fReindex) return false;
TRY_LOCK(cs_main, lockMain);
if(!lockMain) return false;
CBlockIndex* pindex = chainActive.Tip();
if(pindex == NULL) return false;
if(pindex->nTime + 60*60 < GetTime())
2015-08-03 22:42:18 +02:00
return false;
fBlockchainSynced = true;
return true;
}
2015-08-04 20:21:27 +02:00
void CMasternodeSync::Reset()
{
lastMasternodeList = GetTime();
lastMasternodeWinner = GetTime();
lastBudgetItem = GetTime();
2015-08-05 04:10:47 +02:00
mapSeenSyncMNB.clear();
mapSeenSyncMNW.clear();
mapSeenSyncBudget.clear();
2015-08-04 20:21:27 +02:00
lastFailure = 0;
nCountFailures = 0;
sumMasternodeList = 0;
sumMasternodeWinner = 0;
sumBudgetItemProp = 0;
sumBudgetItemFin = 0;
countMasternodeList = 0;
countMasternodeWinner = 0;
countBudgetItemProp = 0;
countBudgetItemFin = 0;
RequestedMasternodeAssets = MASTERNODE_SYNC_INITIAL;
RequestedMasternodeAttempt = 0;
nAssetSyncStarted = GetTime();
2015-08-04 20:21:27 +02:00
}
void CMasternodeSync::AddedMasternodeList(uint256 hash)
2015-07-15 04:44:58 +02:00
{
if(mnodeman.mapSeenMasternodeBroadcast.count(hash)) {
lastMasternodeList = GetTime();
mapSeenSyncMNB[hash]++;
} else {
lastMasternodeList = GetTime();
mapSeenSyncMNB.insert(make_pair(hash, 1));
}
2015-07-15 04:44:58 +02:00
}
void CMasternodeSync::AddedMasternodeWinner(uint256 hash)
2015-07-15 04:44:58 +02:00
{
if(mnpayments.mapMasternodePayeeVotes.count(hash)) {
lastMasternodeWinner = GetTime();
mapSeenSyncMNW[hash]++;
} else {
lastMasternodeWinner = GetTime();
mapSeenSyncMNW.insert(make_pair(hash, 1));
}
2015-07-15 04:44:58 +02:00
}
void CMasternodeSync::AddedBudgetItem(uint256 hash)
2015-07-15 04:44:58 +02:00
{
if(budget.mapSeenMasternodeBudgetProposals.count(hash) || budget.mapSeenMasternodeBudgetVotes.count(hash) ||
budget.mapSeenFinalizedBudgets.count(hash) || budget.mapSeenFinalizedBudgetVotes.count(hash)) {
lastBudgetItem = GetTime();
mapSeenSyncBudget[hash]++;
} else {
lastBudgetItem = GetTime();
mapSeenSyncBudget.insert(make_pair(hash, 1));
}
2015-07-15 04:44:58 +02:00
}
2015-07-29 10:08:15 +02:00
bool CMasternodeSync::IsBudgetPropEmpty()
{
return sumBudgetItemProp==0 && countBudgetItemProp>0;
}
bool CMasternodeSync::IsBudgetFinEmpty()
{
return sumBudgetItemFin==0 && countBudgetItemFin>0;
}
2015-07-15 04:44:58 +02:00
void CMasternodeSync::GetNextAsset()
{
switch(RequestedMasternodeAssets)
{
case(MASTERNODE_SYNC_INITIAL):
2015-08-04 23:33:47 +02:00
case(MASTERNODE_SYNC_FAILED): // should never be used here actually, use Reset() instead
2015-07-30 10:51:48 +02:00
ClearFulfilledRequest();
//printf("MASTERNODE_SYNC_SPORKS\n");
2015-08-04 23:33:47 +02:00
RequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS;
break;
case(MASTERNODE_SYNC_SPORKS):
//printf("MASTERNODE_SYNC_LIST\n");
2015-07-15 04:44:58 +02:00
RequestedMasternodeAssets = MASTERNODE_SYNC_LIST;
break;
case(MASTERNODE_SYNC_LIST):
//printf("MASTERNODE_SYNC_MNW\n");
2015-07-15 04:44:58 +02:00
RequestedMasternodeAssets = MASTERNODE_SYNC_MNW;
break;
case(MASTERNODE_SYNC_MNW):
//printf("MASTERNODE_SYNC_BUDGET\n");
2015-07-15 04:44:58 +02:00
RequestedMasternodeAssets = MASTERNODE_SYNC_BUDGET;
break;
case(MASTERNODE_SYNC_BUDGET):
LogPrintf("CMasternodeSync::GetNextAsset - Sync has finished\n");
RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
2015-07-15 04:44:58 +02:00
break;
}
RequestedMasternodeAttempt = 0;
nAssetSyncStarted = GetTime();
2015-07-15 04:44:58 +02:00
}
std::string CMasternodeSync::GetSyncStatus()
{
switch (masternodeSync.RequestedMasternodeAssets) {
2015-09-02 10:20:18 +02:00
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 winners...");
case MASTERNODE_SYNC_BUDGET: return _("Synchronizing budgets...");
case MASTERNODE_SYNC_FAILED: return _("Synchronization failed");
case MASTERNODE_SYNC_FINISHED: return _("Synchronization finished");
}
return "";
}
2015-07-29 06:16:11 +02:00
void CMasternodeSync::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv)
{
if (strCommand == "ssc") { //Sync status count
int nItemID;
int nCount;
vRecv >> nItemID >> nCount;
if(RequestedMasternodeAssets >= MASTERNODE_SYNC_FINISHED) return;
//this means we will receive no further communication
switch(nItemID)
{
case(MASTERNODE_SYNC_LIST):
if(nItemID != RequestedMasternodeAssets) return;
sumMasternodeList += nCount;
countMasternodeList++;
break;
case(MASTERNODE_SYNC_MNW):
if(nItemID != RequestedMasternodeAssets) return;
sumMasternodeWinner += nCount;
countMasternodeWinner++;
break;
case(MASTERNODE_SYNC_BUDGET_PROP):
if(RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
sumBudgetItemProp += nCount;
countBudgetItemProp++;
break;
case(MASTERNODE_SYNC_BUDGET_FIN):
if(RequestedMasternodeAssets != MASTERNODE_SYNC_BUDGET) return;
sumBudgetItemFin += nCount;
countBudgetItemFin++;
break;
2015-07-29 06:16:11 +02:00
}
2015-07-30 10:51:48 +02:00
LogPrintf("CMasternodeSync:ProcessMessage - ssc - got inventory count %d %d\n", nItemID, nCount);
}
}
void CMasternodeSync::ClearFulfilledRequest()
{
2015-07-30 15:44:18 +02:00
TRY_LOCK(cs_vNodes, lockRecv);
if(!lockRecv) return;
2015-07-30 10:51:48 +02:00
BOOST_FOREACH(CNode* pnode, vNodes)
{
pnode->ClearFulfilledRequest("getspork");
pnode->ClearFulfilledRequest("mnsync");
pnode->ClearFulfilledRequest("mnwsync");
pnode->ClearFulfilledRequest("busync");
2015-07-29 06:16:11 +02:00
}
}
void CMasternodeSync::Process()
2015-07-15 04:44:58 +02:00
{
2015-07-19 10:19:54 +02:00
static int tick = 0;
if(tick++ % 6 != 0) return;
2015-07-19 10:19:54 +02:00
//the actual count of masternodes we have currently
int nMnCount = mnodeman.CountEnabled();
2015-07-19 10:19:54 +02:00
// RESET SYNCING INCASE OF FAILURE
{
if(IsSynced()) {
/*
Resync if we lose all masternodes from sleep/wake or failure to sync originally
*/
if(mnodeman.CountEnabled() == 0) {
Reset();
} else
return;
}
//try syncing again
if(RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED && lastFailure + (1*60) < GetTime()) {
2015-08-04 23:33:47 +02:00
Reset();
} else if (RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED) {
2015-07-19 10:19:54 +02:00
return;
}
if(fDebug) LogPrintf("CMasternodeSync::Process() - tick %d RequestedMasternodeAssets %d\n", tick, RequestedMasternodeAssets);
2015-07-18 01:49:41 +02:00
}
2015-07-15 04:44:58 +02:00
//printf("CMasternodeSync::Process() TICK - %d %d \n", tick, RequestedMasternodeAssets);
if(RequestedMasternodeAssets == MASTERNODE_SYNC_INITIAL) GetNextAsset();
2015-07-15 04:44:58 +02:00
2015-08-03 22:42:18 +02:00
// sporks synced but blockchain is not, wait until we're almost at a recent block to continue
if(Params().NetworkIDString() != CBaseChainParams::REGTEST &&
2015-08-03 22:42:18 +02:00
!IsBlockchainSynced() && RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS) return;
//printf("CMasternodeSync::Process() TICK2 - %d %d \n", tick, RequestedMasternodeAssets);
2015-07-30 15:44:18 +02:00
TRY_LOCK(cs_vNodes, lockRecv);
if(!lockRecv) return;
//printf("CMasternodeSync::Process() TICK3 - %d %d \n", tick, RequestedMasternodeAssets);
BOOST_FOREACH(CNode* pnode, vNodes)
{
/*
REGTEST QUICK MODE
*/
if(Params().NetworkIDString() == CBaseChainParams::REGTEST){
if(RequestedMasternodeAttempt <= 2) {
2015-07-23 01:51:51 +02:00
pnode->PushMessage("getsporks"); //get current network sporks
} else if(RequestedMasternodeAttempt < 4) {
mnodeman.DsegUpdate(pnode);
} else if(RequestedMasternodeAttempt < 6) {
2015-09-02 14:13:32 +02:00
int nMnCount = mnodeman.CountEnabled();
pnode->PushMessage("mnget", nMnCount); //sync payees
uint256 n = uint256();
pnode->PushMessage("mnvs", n); //sync masternode votes
} else {
RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED;
}
RequestedMasternodeAttempt++;
2015-07-19 01:25:52 +02:00
return;
}
/*
NORMAL NETWORK MODE - TESTNET/MAINNET
*/
2016-02-04 23:48:23 +01:00
// ALWAYS ASK FOR SPORKS AS WE SYNC (we skip this mode now)
{
2016-02-04 23:48:23 +01:00
if(!pnode->HasFulfilledRequest("getspork"))
{
pnode->FulfilledRequest("getspork");
pnode->PushMessage("getsporks"); //get current network sporks
}
//we always ask for sporks, so just skip this
if(RequestedMasternodeAssets == MASTERNODE_SYNC_SPORKS){
GetNextAsset();
return;
}
}
if (pnode->nVersion >= mnpayments.GetMinMasternodePaymentsProto()) {
2015-07-15 04:44:58 +02:00
// MODE : MASTERNODE_SYNC_LIST
2015-07-19 01:25:52 +02:00
if(RequestedMasternodeAssets == MASTERNODE_SYNC_LIST) {
//printf("MASTERNODE_SYNC_LIST Timeout at %d\n", lastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT);
2015-07-15 04:44:58 +02:00
// shall we move onto the next asset?
2015-07-15 04:44:58 +02:00
//printf("Masternode count %d est %d\n", nMnCount, mnodeman.GetEstimatedMasternodes(chainActive.Height())) ;
if(nMnCount > mnodeman.GetEstimatedMasternodes(chainActive.Height())*0.9)
{
GetNextAsset();
//printf("synced masternode list successfully\n");
2015-07-15 04:44:58 +02:00
return;
}
if(lastMasternodeList < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
GetNextAsset();
return;
}
2016-02-04 23:48:23 +01:00
// requesting is the last thing we do (incase we needed to move to the next asset and we've requested from each peer already)
if(pnode->HasFulfilledRequest("mnsync")) continue;
pnode->FulfilledRequest("mnsync");
2016-02-04 23:48:23 +01:00
//see if we've synced the masternode list
/* note: Is this activing up? It's probably related to int CMasternodeMan::GetEstimatedMasternodes(int nBlock) */
mnodeman.DsegUpdate(pnode);
RequestedMasternodeAttempt++;
2016-02-04 23:48:23 +01:00
return; //this will cause each peer to get one request each six seconds for the various assets we need
}
2015-07-15 04:44:58 +02:00
// MODE : MASTERNODE_SYNC_MNW
2015-07-19 01:25:52 +02:00
if(RequestedMasternodeAssets == MASTERNODE_SYNC_MNW) {
//printf("MASTERNODE_SYNC_MNW Timeout at %d\n", lastMasternodeWinner < GetTime() - MASTERNODE_SYNC_TIMEOUT);
2016-02-04 23:48:23 +01:00
// Shall we move onto the next asset?
// --
// This might take a lot longer than 2 minutes due to new blocks, but that's OK. It will eventually time out if needed
if(lastMasternodeWinner < GetTime() - MASTERNODE_SYNC_TIMEOUT){ //hasn't received a new item in the last five seconds, so we'll move to the
GetNextAsset();
2015-07-15 04:44:58 +02:00
return;
}
//printf("MASTERNODE_SYNC_MNW BlockCount %d, mnCount %d\n", mnpayments.GetBlockCount(), nMnCount);
// target blocks count
if(mnpayments.GetBlockCount() > nMnCount)
{
//printf("MASTERNODE_SYNC_MNW VoteCount %d, mnCount*6 %d\n", mnpayments.GetVoteCount(), nMnCount*6);
// target votes, max ten per item. 6 average should be fine
if(mnpayments.GetVoteCount() > nMnCount*6)
{
//printf("Successfully synced mnw blocks and votes %d %d\n", mnpayments.GetBlockCount(), mnpayments.GetVoteCount());
GetNextAsset();
return;
}
}
2016-02-04 23:48:23 +01:00
// requesting is the last thing we do (incase we needed to move to the next asset and we've requested from each peer already)
2016-02-04 23:48:23 +01:00
if(pnode->HasFulfilledRequest("mnwsync")) continue;
pnode->FulfilledRequest("mnwsync");
CBlockIndex* pindexPrev = chainActive.Tip();
if(pindexPrev == NULL) return;
2015-09-02 14:13:32 +02:00
int nMnCount = mnodeman.CountEnabled();
pnode->PushMessage("mnget", nMnCount); //sync payees
RequestedMasternodeAttempt++;
2015-07-19 01:25:52 +02:00
2016-02-04 23:48:23 +01:00
return; //this will cause each peer to get one request each six seconds for the various assets we need
}
2016-02-04 23:48:23 +01:00
// MODE : MASTERNODE_SYNC_BUDGET
if(RequestedMasternodeAssets == MASTERNODE_SYNC_BUDGET){
//printf("MASTERNODE_SYNC_BUDGET Timeout at %d\n", lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT);
2016-02-04 23:48:23 +01:00
// shall we move onto the next asset
if(countBudgetItemProp > 0 && countBudgetItemFin)
{
//printf("MASTERNODE_SYNC_BUDGET countBudgetItemProp %d - %d\n", (sumBudgetItemProp / countBudgetItemProp), budget.CountProposalInventoryItems());
//printf("MASTERNODE_SYNC_BUDGET countBudgetItemFin %d - %d\n", (sumBudgetItemFin / countBudgetItemFin), budget.CountFinalizedInventoryItems());
if(budget.CountProposalInventoryItems() >= (sumBudgetItemProp / countBudgetItemProp)*0.9)
{
//printf("HAVE BUDGETS\n");
if(budget.CountFinalizedInventoryItems() >= (sumBudgetItemFin / countBudgetItemFin)*0.9)
{
//printf("HAVE FINAL BUDGETS\n");
GetNextAsset();
return;
}
}
2015-07-15 04:44:58 +02:00
}
2016-02-04 23:48:23 +01:00
//we'll start rejecting votes if we accidentally get set as synced too soon, this allows plenty of time
if(lastBudgetItem < GetTime() - MASTERNODE_SYNC_TIMEOUT){
2015-08-14 05:56:58 +02:00
GetNextAsset();
//try to activate our masternode if possible
2015-08-14 05:56:58 +02:00
activeMasternode.ManageStatus();
return;
}
2016-02-04 23:48:23 +01:00
// requesting is the last thing we do, incase we needed to move to the next asset and we've requested from each peer already
if(pnode->HasFulfilledRequest("busync")) continue;
pnode->FulfilledRequest("busync");
uint256 n = uint256();
pnode->PushMessage("mnvs", n); //sync masternode votes
RequestedMasternodeAttempt++;
2016-02-04 23:48:23 +01:00
return; //this will cause each peer to get one request each six seconds for the various assets we need
2015-07-15 04:44:58 +02:00
}
2015-07-15 04:44:58 +02:00
}
}
}