2015-07-15 04:44:58 +02:00
// Copyright (c) 2014-2015 The Dash developers
// 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"
2015-07-25 18:29:29 +02:00
# include "masternode-budget.h"
2015-07-15 04:44:58 +02:00
# include "masternode.h"
2015-07-17 11:17:15 +02:00
# include "masternodeman.h"
2015-08-15 15:27:26 +02:00
# 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
}
2015-07-26 22:04:17 +02:00
bool CMasternodeSync : : IsBlockchainSynced ( )
2015-07-26 21:37:01 +02:00
{
2015-08-04 01:23:36 +02:00
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 ( ) ;
2015-08-04 01:23:36 +02:00
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 ;
2015-08-13 17:04:25 +02:00
if ( pindex - > nTime + 60 * 60 < GetTime ( ) )
2015-08-03 22:42:18 +02:00
return false ;
fBlockchainSynced = true ;
2015-07-26 22:04:17 +02:00
return true ;
2015-07-26 21:37:01 +02:00
}
2015-08-04 20:21:27 +02:00
void CMasternodeSync : : Reset ( )
{
lastMasternodeList = 0 ;
lastMasternodeWinner = 0 ;
lastBudgetItem = 0 ;
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 ;
2015-08-15 15:27:26 +02:00
nAssetSyncStarted = GetTime ( ) ;
2015-08-04 20:21:27 +02:00
}
2015-08-05 02:54:02 +02:00
void CMasternodeSync : : AddedMasternodeList ( uint256 hash )
2015-07-15 04:44:58 +02:00
{
2015-08-05 02:54:02 +02:00
if ( mnodeman . mapSeenMasternodeBroadcast . count ( hash ) ) {
2015-08-11 21:43:05 +02:00
if ( mapSeenSyncMNB [ hash ] < MASTERNODE_SYNC_THRESHOLD ) {
2015-08-05 02:54:02 +02:00
lastMasternodeList = GetTime ( ) ;
mapSeenSyncMNB [ hash ] + + ;
}
} else {
lastMasternodeList = GetTime ( ) ;
mapSeenSyncMNB . insert ( make_pair ( hash , 1 ) ) ;
}
2015-07-15 04:44:58 +02:00
}
2015-08-05 02:54:02 +02:00
void CMasternodeSync : : AddedMasternodeWinner ( uint256 hash )
2015-07-15 04:44:58 +02:00
{
2015-08-05 02:54:02 +02:00
if ( masternodePayments . mapMasternodePayeeVotes . count ( hash ) ) {
2015-08-11 21:43:05 +02:00
if ( mapSeenSyncMNW [ hash ] < MASTERNODE_SYNC_THRESHOLD ) {
2015-08-05 02:54:02 +02:00
lastMasternodeWinner = GetTime ( ) ;
mapSeenSyncMNW [ hash ] + + ;
}
} else {
lastMasternodeWinner = GetTime ( ) ;
mapSeenSyncMNW . insert ( make_pair ( hash , 1 ) ) ;
}
2015-07-15 04:44:58 +02:00
}
2015-08-05 02:54:02 +02:00
void CMasternodeSync : : AddedBudgetItem ( uint256 hash )
2015-07-15 04:44:58 +02:00
{
2015-08-05 02:54:02 +02:00
if ( budget . mapSeenMasternodeBudgetProposals . count ( hash ) | | budget . mapSeenMasternodeBudgetVotes . count ( hash ) | |
budget . mapSeenFinalizedBudgets . count ( hash ) | | budget . mapSeenFinalizedBudgetVotes . count ( hash ) ) {
2015-08-11 21:43:05 +02:00
if ( mapSeenSyncBudget [ hash ] < MASTERNODE_SYNC_THRESHOLD ) {
2015-08-05 02:54:02 +02:00
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 ;
}
2015-07-29 10:06:30 +02:00
bool CMasternodeSync : : IsBudgetFinEmpty ( )
{
return sumBudgetItemFin = = 0 & & countBudgetItemFin > 0 ;
}
2015-07-15 04:44:58 +02:00
void CMasternodeSync : : GetNextAsset ( )
{
switch ( RequestedMasternodeAssets )
{
2015-07-17 12:26:24 +02:00
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 ( ) ;
2015-08-04 23:33:47 +02:00
RequestedMasternodeAssets = MASTERNODE_SYNC_SPORKS ;
2015-07-17 05:03:42 +02:00
break ;
2015-07-17 12:26:24 +02:00
case ( MASTERNODE_SYNC_SPORKS ) :
2015-07-15 04:44:58 +02:00
RequestedMasternodeAssets = MASTERNODE_SYNC_LIST ;
break ;
case ( MASTERNODE_SYNC_LIST ) :
RequestedMasternodeAssets = MASTERNODE_SYNC_MNW ;
break ;
case ( MASTERNODE_SYNC_MNW ) :
RequestedMasternodeAssets = MASTERNODE_SYNC_BUDGET ;
break ;
case ( MASTERNODE_SYNC_BUDGET ) :
2015-07-19 17:49:46 +02:00
LogPrintf ( " CMasternodeSync::GetNextAsset - Sync has finished \n " ) ;
2015-07-17 12:26:24 +02:00
RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED ;
2015-07-15 04:44:58 +02:00
break ;
}
2015-07-17 11:17:15 +02:00
RequestedMasternodeAttempt = 0 ;
2015-08-15 15:27:26 +02:00
nAssetSyncStarted = GetTime ( ) ;
2015-07-15 04:44:58 +02:00
}
2015-08-15 17:53:55 +02:00
std : : string CMasternodeSync : : GetSyncStatus ( )
{
switch ( masternodeSync . RequestedMasternodeAssets ) {
case MASTERNODE_SYNC_INITIAL : return _ ( " Synchronization doesn't yet started " ) ;
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 ;
2015-07-29 10:06:30 +02:00
//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
}
}
2015-07-17 11:17:15 +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 + + % MASTERNODE_SYNC_TIMEOUT ! = 0 ) return ;
2015-07-18 01:49:41 +02:00
if ( IsSynced ( ) ) {
/*
Resync if we lose all masternodes from sleep / wake or failure to sync originally
*/
if ( mnodeman . CountEnabled ( ) = = 0 ) {
2015-08-04 23:33:47 +02:00
Reset ( ) ;
2015-07-19 10:19:54 +02:00
} else
return ;
2015-07-18 01:49:41 +02:00
}
2015-07-15 04:44:58 +02:00
2015-08-25 16:50:47 +02:00
//try syncing again
if ( RequestedMasternodeAssets = = MASTERNODE_SYNC_FAILED & & lastFailure + ( 1 * 60 ) < GetTime ( ) ) {
2015-08-04 23:33:47 +02:00
Reset ( ) ;
2015-07-25 18:29:29 +02:00
} else if ( RequestedMasternodeAssets = = MASTERNODE_SYNC_FAILED ) {
return ;
}
2015-07-19 10:19:54 +02:00
if ( fDebug ) LogPrintf ( " CMasternodeSync::Process() - tick %d RequestedMasternodeAssets %d \n " , tick , RequestedMasternodeAssets ) ;
2015-07-17 11:17:15 +02:00
2015-07-17 12:26:24 +02:00
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 ( ) . NetworkID ( ) ! = CBaseChainParams : : REGTEST & &
! IsBlockchainSynced ( ) & & RequestedMasternodeAssets > MASTERNODE_SYNC_SPORKS ) return ;
2015-07-30 15:44:18 +02:00
TRY_LOCK ( cs_vNodes , lockRecv ) ;
if ( ! lockRecv ) return ;
2015-07-17 11:17:15 +02:00
BOOST_FOREACH ( CNode * pnode , vNodes )
{
2015-07-23 23:35:14 +02:00
if ( Params ( ) . NetworkID ( ) = = CBaseChainParams : : REGTEST ) {
if ( RequestedMasternodeAttempt < = 2 ) {
2015-07-23 01:51:51 +02:00
pnode - > PushMessage ( " getsporks " ) ; //get current network sporks
2015-07-23 23:35:14 +02:00
} else if ( RequestedMasternodeAttempt < 4 ) {
mnodeman . DsegUpdate ( pnode ) ;
} else if ( RequestedMasternodeAttempt < 6 ) {
int nMnCount = mnodeman . CountEnabled ( ) * 2 ;
pnode - > PushMessage ( " mnget " , nMnCount ) ; //sync payees
uint256 n = 0 ;
pnode - > PushMessage ( " mnvs " , n ) ; //sync masternode votes
} else {
RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED ;
2015-07-17 11:17:15 +02:00
}
2015-07-23 23:35:14 +02:00
RequestedMasternodeAttempt + + ;
2015-07-19 01:25:52 +02:00
return ;
}
2015-07-23 23:35:14 +02:00
//set to synced
if ( RequestedMasternodeAssets = = MASTERNODE_SYNC_SPORKS ) {
if ( pnode - > HasFulfilledRequest ( " getspork " ) ) continue ;
pnode - > FulfilledRequest ( " getspork " ) ;
pnode - > PushMessage ( " getsporks " ) ; //get current network sporks
if ( RequestedMasternodeAttempt > = 2 ) GetNextAsset ( ) ;
RequestedMasternodeAttempt + + ;
return ;
}
2015-07-20 20:56:02 +02:00
2015-07-20 07:03:36 +02:00
if ( pnode - > nVersion > = masternodePayments . GetMinMasternodePaymentsProto ( ) ) {
2015-07-15 04:44:58 +02:00
2015-07-19 01:25:52 +02:00
if ( RequestedMasternodeAssets = = MASTERNODE_SYNC_LIST ) {
if ( fDebug ) LogPrintf ( " CMasternodeSync::Process() - lastMasternodeList %lld (GetTime() - MASTERNODE_SYNC_TIMEOUT) %lld \n " , lastMasternodeList , GetTime ( ) - MASTERNODE_SYNC_TIMEOUT ) ;
2015-08-25 16:50:47 +02:00
if ( lastMasternodeList > 0 & & lastMasternodeList < GetTime ( ) - MASTERNODE_SYNC_TIMEOUT * 2 & & RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD ) { //hasn't received a new item in the last five seconds, so we'll move to the
2015-07-17 11:17:15 +02:00
GetNextAsset ( ) ;
2015-07-15 04:44:58 +02:00
return ;
}
2015-07-17 11:17:15 +02:00
if ( pnode - > HasFulfilledRequest ( " mnsync " ) ) continue ;
pnode - > FulfilledRequest ( " mnsync " ) ;
2015-07-15 04:44:58 +02:00
2015-08-15 15:27:26 +02:00
// timeout
if ( lastMasternodeList = = 0 & &
2015-08-25 16:50:47 +02:00
( RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD * 3 | | GetTime ( ) - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5 ) ) {
2015-08-15 15:27:26 +02:00
if ( IsSporkActive ( SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT ) ) {
LogPrintf ( " CMasternodeSync::Process - ERROR - Sync has failed, will retry later \n " ) ;
RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED ;
RequestedMasternodeAttempt = 0 ;
lastFailure = GetTime ( ) ;
nCountFailures + + ;
} else {
GetNextAsset ( ) ;
}
return ;
}
2015-08-25 16:50:47 +02:00
if ( RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD * 3 ) return ;
2015-07-27 05:41:25 +02:00
mnodeman . DsegUpdate ( pnode ) ;
RequestedMasternodeAttempt + + ;
2015-07-17 11:17:15 +02:00
return ;
}
2015-07-15 04:44:58 +02:00
2015-07-19 01:25:52 +02:00
if ( RequestedMasternodeAssets = = MASTERNODE_SYNC_MNW ) {
2015-08-25 16:50:47 +02:00
if ( lastMasternodeWinner > 0 & & lastMasternodeWinner < GetTime ( ) - MASTERNODE_SYNC_TIMEOUT * 2 & & RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD ) { //hasn't received a new item in the last five seconds, so we'll move to the
2015-07-17 11:17:15 +02:00
GetNextAsset ( ) ;
2015-07-15 04:44:58 +02:00
return ;
}
2015-07-17 11:17:15 +02:00
if ( pnode - > HasFulfilledRequest ( " mnwsync " ) ) continue ;
pnode - > FulfilledRequest ( " mnwsync " ) ;
2015-08-15 15:27:26 +02:00
// timeout
if ( lastMasternodeWinner = = 0 & &
2015-08-25 16:50:47 +02:00
( RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD * 3 | | GetTime ( ) - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5 ) ) {
2015-08-15 15:27:26 +02:00
if ( IsSporkActive ( SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT ) ) {
LogPrintf ( " CMasternodeSync::Process - ERROR - Sync has failed, will retry later \n " ) ;
RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED ;
RequestedMasternodeAttempt = 0 ;
lastFailure = GetTime ( ) ;
nCountFailures + + ;
} else {
GetNextAsset ( ) ;
}
return ;
}
2015-08-25 16:50:47 +02:00
if ( RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD * 3 ) return ;
2015-07-21 04:24:43 +02:00
2015-07-27 05:41:25 +02:00
CBlockIndex * pindexPrev = chainActive . Tip ( ) ;
if ( pindexPrev = = NULL ) return ;
int nMnCount = mnodeman . CountEnabled ( ) * 2 ;
pnode - > PushMessage ( " mnget " , nMnCount ) ; //sync payees
RequestedMasternodeAttempt + + ;
2015-07-21 04:24:43 +02:00
2015-07-17 11:17:15 +02:00
return ;
}
2015-07-19 01:25:52 +02:00
}
if ( pnode - > nVersion > = MIN_BUDGET_PEER_PROTO_VERSION ) {
2015-07-17 11:17:15 +02:00
if ( RequestedMasternodeAssets = = MASTERNODE_SYNC_BUDGET ) {
2015-07-26 16:01:49 +02:00
//we'll start rejecting votes if we accidentally get set as synced too soon
2015-08-25 16:50:47 +02:00
if ( lastBudgetItem > 0 & & lastBudgetItem < GetTime ( ) - MASTERNODE_SYNC_TIMEOUT * 2 & & RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD ) { //hasn't received a new item in the last five seconds, so we'll move to the
2015-07-30 15:18:31 +02:00
//LogPrintf("CMasternodeSync::Process - HasNextFinalizedBudget %d nCountFailures %d IsBudgetPropEmpty %d\n", budget.HasNextFinalizedBudget(), nCountFailures, IsBudgetPropEmpty());
//if(budget.HasNextFinalizedBudget() || nCountFailures >= 2 || IsBudgetPropEmpty()) {
2015-07-25 18:29:29 +02:00
GetNextAsset ( ) ;
2015-07-29 05:26:08 +02:00
//try to activate our masternode if possible
activeMasternode . ManageStatus ( ) ;
2015-07-30 15:18:31 +02:00
// } else { //we've failed to sync, this state will reject the next budget block
// LogPrintf("CMasternodeSync::Process - ERROR - Sync has failed, will retry later\n");
// RequestedMasternodeAssets = MASTERNODE_SYNC_FAILED;
// RequestedMasternodeAttempt = 0;
// lastFailure = GetTime();
// nCountFailures++;
// }
2015-07-15 04:44:58 +02:00
return ;
}
2015-08-14 05:56:58 +02:00
// timeout
2015-08-15 15:27:26 +02:00
if ( lastBudgetItem = = 0 & &
2015-08-25 16:50:47 +02:00
( RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD * 3 | | GetTime ( ) - nAssetSyncStarted > MASTERNODE_SYNC_TIMEOUT * 5 ) ) {
2015-08-15 15:27:26 +02:00
// maybe there is no budgets at all, so just finish syncing
2015-08-14 05:56:58 +02:00
GetNextAsset ( ) ;
activeMasternode . ManageStatus ( ) ;
return ;
}
2015-07-17 11:17:15 +02:00
if ( pnode - > HasFulfilledRequest ( " busync " ) ) continue ;
pnode - > FulfilledRequest ( " busync " ) ;
2015-08-25 16:50:47 +02:00
if ( RequestedMasternodeAttempt > = MASTERNODE_SYNC_THRESHOLD * 3 ) return ;
2015-07-27 05:41:25 +02:00
uint256 n = 0 ;
pnode - > PushMessage ( " mnvs " , n ) ; //sync masternode votes
RequestedMasternodeAttempt + + ;
2015-07-17 11:17:15 +02:00
return ;
2015-07-15 04:44:58 +02:00
}
2015-07-17 11:17:15 +02:00
2015-07-15 04:44:58 +02:00
}
}
2015-07-17 11:17:15 +02:00
}