2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash Core developers
2015-02-24 15:02:22 +01:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2015-02-23 21:01:21 +01:00
# include "activemasternode.h"
2016-12-20 14:27:59 +01:00
# include "addrman.h"
2015-02-23 21:01:21 +01:00
# include "darksend.h"
2016-11-13 18:52:34 +01:00
# include "governance.h"
2016-01-24 20:05:31 +01:00
# include "masternode-payments.h"
# include "masternode-sync.h"
2016-12-20 14:27:59 +01:00
# include "masternodeman.h"
2016-10-20 23:11:30 +02:00
# include "netfulfilledman.h"
2015-02-23 21:01:21 +01:00
# include "util.h"
/** Masternode manager */
CMasternodeMan mnodeman ;
2017-01-01 18:48:53 +01:00
const std : : string CMasternodeMan : : SERIALIZATION_VERSION_STRING = " CMasternodeMan-Version-4 " ;
2016-10-20 23:11:30 +02:00
2016-09-11 22:22:37 +02:00
struct CompareLastPaidBlock
2015-02-23 21:01:21 +01:00
{
2016-09-20 00:27:36 +02:00
bool operator ( ) ( const std : : pair < int , CMasternode * > & t1 ,
const std : : pair < int , CMasternode * > & t2 ) const
2015-02-23 21:01:21 +01:00
{
2016-09-20 00:27:36 +02:00
return ( t1 . first ! = t2 . first ) ? ( t1 . first < t2 . first ) : ( t1 . second - > vin < t2 . second - > vin ) ;
2015-07-30 18:00:28 +02:00
}
} ;
struct CompareScoreMN
2015-03-14 19:34:51 +01:00
{
2016-09-20 00:27:36 +02:00
bool operator ( ) ( const std : : pair < int64_t , CMasternode * > & t1 ,
const std : : pair < int64_t , CMasternode * > & t2 ) const
2015-03-14 19:34:51 +01:00
{
2016-09-20 00:27:36 +02:00
return ( t1 . first ! = t2 . first ) ? ( t1 . first < t2 . first ) : ( t1 . second - > vin < t2 . second - > vin ) ;
2015-03-14 19:34:51 +01:00
}
} ;
2015-02-23 21:01:21 +01:00
2016-11-13 18:52:34 +01:00
CMasternodeIndex : : CMasternodeIndex ( )
: nSize ( 0 ) ,
mapIndex ( ) ,
mapReverseIndex ( )
{ }
bool CMasternodeIndex : : Get ( int nIndex , CTxIn & vinMasternode ) const
{
rindex_m_cit it = mapReverseIndex . find ( nIndex ) ;
if ( it = = mapReverseIndex . end ( ) ) {
return false ;
}
vinMasternode = it - > second ;
return true ;
}
int CMasternodeIndex : : GetMasternodeIndex ( const CTxIn & vinMasternode ) const
{
index_m_cit it = mapIndex . find ( vinMasternode ) ;
if ( it = = mapIndex . end ( ) ) {
return - 1 ;
}
return it - > second ;
}
void CMasternodeIndex : : AddMasternodeVIN ( const CTxIn & vinMasternode )
{
index_m_it it = mapIndex . find ( vinMasternode ) ;
if ( it ! = mapIndex . end ( ) ) {
return ;
}
int nNextIndex = nSize ;
mapIndex [ vinMasternode ] = nNextIndex ;
mapReverseIndex [ nNextIndex ] = vinMasternode ;
+ + nSize ;
}
void CMasternodeIndex : : Clear ( )
{
mapIndex . clear ( ) ;
mapReverseIndex . clear ( ) ;
nSize = 0 ;
}
2016-10-20 23:11:30 +02:00
struct CompareByAddr
2016-11-13 18:52:34 +01:00
2016-10-20 23:11:30 +02:00
{
bool operator ( ) ( const CMasternode * t1 ,
const CMasternode * t2 ) const
{
return t1 - > addr < t2 - > addr ;
}
} ;
2015-02-23 21:01:21 +01:00
2016-11-13 18:52:34 +01:00
void CMasternodeIndex : : RebuildIndex ( )
{
nSize = mapIndex . size ( ) ;
for ( index_m_it it = mapIndex . begin ( ) ; it ! = mapIndex . end ( ) ; + + it ) {
mapReverseIndex [ it - > second ] = it - > first ;
}
}
CMasternodeMan : : CMasternodeMan ( )
: cs ( ) ,
vMasternodes ( ) ,
mAskedUsForMasternodeList ( ) ,
mWeAskedForMasternodeList ( ) ,
mWeAskedForMasternodeListEntry ( ) ,
nLastIndexRebuildTime ( 0 ) ,
indexMasternodes ( ) ,
indexMasternodesOld ( ) ,
fIndexRebuilt ( false ) ,
fMasternodesAdded ( false ) ,
fMasternodesRemoved ( false ) ,
vecDirtyGovernanceObjectHashes ( ) ,
nLastWatchdogVoteTime ( 0 ) ,
mapSeenMasternodeBroadcast ( ) ,
mapSeenMasternodePing ( ) ,
nDsqCount ( 0 )
{ }
2015-02-23 21:01:21 +01:00
bool CMasternodeMan : : Add ( CMasternode & mn )
{
LOCK ( cs ) ;
CMasternode * pmn = Find ( mn . vin ) ;
2016-10-22 18:52:14 +02:00
if ( pmn = = NULL ) {
LogPrint ( " masternode " , " CMasternodeMan::Add -- Adding new Masternode: addr=%s, %i now \n " , mn . addr . ToString ( ) , size ( ) + 1 ) ;
2015-02-23 21:01:21 +01:00
vMasternodes . push_back ( mn ) ;
2016-11-13 18:52:34 +01:00
indexMasternodes . AddMasternodeVIN ( mn . vin ) ;
fMasternodesAdded = true ;
2015-02-23 21:01:21 +01:00
return true ;
}
return false ;
}
2016-11-13 18:52:34 +01:00
void CMasternodeMan : : AskForMN ( CNode * pnode , const CTxIn & vin )
2015-08-07 05:07:40 +02:00
{
2016-10-22 18:52:14 +02:00
if ( ! pnode ) return ;
2016-12-21 00:55:55 +01:00
LOCK ( cs ) ;
2015-08-07 05:07:40 +02:00
2016-12-21 00:55:55 +01:00
std : : map < COutPoint , std : : map < CNetAddr , int64_t > > : : iterator it1 = mWeAskedForMasternodeListEntry . find ( vin . prevout ) ;
if ( it1 ! = mWeAskedForMasternodeListEntry . end ( ) ) {
std : : map < CNetAddr , int64_t > : : iterator it2 = it1 - > second . find ( pnode - > addr ) ;
if ( it2 ! = it1 - > second . end ( ) ) {
if ( GetTime ( ) < it2 - > second ) {
// we've asked recently, should not repeat too often or we could get banned
return ;
}
// we asked this node for this outpoint but it's ok to ask again already
LogPrintf ( " CMasternodeMan::AskForMN -- Asking same peer %s for missing masternode entry again: %s \n " , pnode - > addr . ToString ( ) , vin . prevout . ToStringShort ( ) ) ;
} else {
// we already asked for this outpoint but not this node
LogPrintf ( " CMasternodeMan::AskForMN -- Asking new peer %s for missing masternode entry: %s \n " , pnode - > addr . ToString ( ) , vin . prevout . ToStringShort ( ) ) ;
}
} else {
// we never asked any node for this outpoint
LogPrintf ( " CMasternodeMan::AskForMN -- Asking peer %s for missing masternode entry for the first time: %s \n " , pnode - > addr . ToString ( ) , vin . prevout . ToStringShort ( ) ) ;
}
mWeAskedForMasternodeListEntry [ vin . prevout ] [ pnode - > addr ] = GetTime ( ) + DSEG_UPDATE_SECONDS ;
2015-08-07 05:07:40 +02:00
2016-02-17 23:18:57 +01:00
pnode - > PushMessage ( NetMsgType : : DSEG , vin ) ;
2015-08-07 05:07:40 +02:00
}
2015-02-23 21:01:21 +01:00
void CMasternodeMan : : Check ( )
{
LOCK ( cs ) ;
2016-12-24 03:49:13 +01:00
LogPrint ( " masternode " , " CMasternodeMan::Check -- nLastWatchdogVoteTime=%d, IsWatchdogActive()=%d \n " , nLastWatchdogVoteTime , IsWatchdogActive ( ) ) ;
2016-10-17 20:54:28 +02:00
2015-06-24 18:41:03 +02:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2015-02-23 21:01:21 +01:00
mn . Check ( ) ;
2015-06-24 18:41:03 +02:00
}
2015-02-23 21:01:21 +01:00
}
2016-11-16 03:09:37 +01:00
void CMasternodeMan : : CheckAndRemove ( )
2015-02-23 21:01:21 +01:00
{
2017-01-14 23:29:08 +01:00
if ( ! masternodeSync . IsMasternodeListSynced ( ) ) return ;
2016-05-30 08:22:30 +02:00
2017-01-14 23:29:08 +01:00
LogPrintf ( " CMasternodeMan::CheckAndRemove \n " ) ;
2015-02-23 21:01:21 +01:00
2016-11-13 18:52:34 +01:00
{
2017-01-01 18:48:53 +01:00
// Need LOCK2 here to ensure consistent locking order because code below locks cs_main
// through GetHeight() signal in ConnectNode and in CheckMnbAndUpdateMasternodeList()
LOCK2 ( cs_main , cs ) ;
Check ( ) ;
2015-07-30 15:44:18 +02:00
2017-01-01 18:48:53 +01:00
// Remove spent masternodes, prepare structures and make requests to reasure the state of inactive ones
2016-11-13 18:52:34 +01:00
std : : vector < CMasternode > : : iterator it = vMasternodes . begin ( ) ;
2017-01-01 18:48:53 +01:00
std : : vector < std : : pair < int , CMasternode > > vecMasternodeRanks ;
bool fAskedForMnbRecovery = false ; // ask for one mn at a time
2016-11-13 18:52:34 +01:00
while ( it ! = vMasternodes . end ( ) ) {
2017-01-01 18:48:53 +01:00
CMasternodeBroadcast mnb = CMasternodeBroadcast ( * it ) ;
uint256 hash = mnb . GetHash ( ) ;
2016-12-24 03:49:13 +01:00
// If collateral was spent ...
if ( ( * it ) . IsOutpointSpent ( ) ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- Removing Masternode: %s addr=%s %i now \n " , ( * it ) . GetStateString ( ) , ( * it ) . addr . ToString ( ) , size ( ) - 1 ) ;
2016-11-13 18:52:34 +01:00
// erase all of the broadcasts we've seen from this txin, ...
2017-01-01 18:48:53 +01:00
mapSeenMasternodeBroadcast . erase ( hash ) ;
2016-11-13 18:52:34 +01:00
mWeAskedForMasternodeListEntry . erase ( ( * it ) . vin . prevout ) ;
// and finally remove it from the list
2017-01-18 16:24:19 +01:00
it - > FlagGovernanceItemsAsDirty ( ) ;
2016-11-13 18:52:34 +01:00
it = vMasternodes . erase ( it ) ;
fMasternodesRemoved = true ;
} else {
2017-01-14 23:29:08 +01:00
bool fAsk = pCurrentBlockIndex & &
! fAskedForMnbRecovery & &
masternodeSync . IsSynced ( ) & &
it - > IsNewStartRequired ( ) & &
! IsMnbRecoveryRequested ( hash ) ;
if ( fAsk ) {
2017-01-01 18:48:53 +01:00
// this mn is in a non-recoverable state and we haven't asked other nodes yet
std : : set < CNetAddr > setRequested ;
// calulate only once and only when it's needed
if ( vecMasternodeRanks . empty ( ) ) {
int nRandomBlockHeight = GetRandInt ( pCurrentBlockIndex - > nHeight ) ;
vecMasternodeRanks = GetMasternodeRanks ( nRandomBlockHeight ) ;
}
// ask first MNB_RECOVERY_QUORUM_TOTAL mns we can connect to and we haven't asked recently
for ( int i = 0 ; setRequested . size ( ) < MNB_RECOVERY_QUORUM_TOTAL & & i < ( int ) vecMasternodeRanks . size ( ) ; i + + ) {
// avoid banning
if ( mWeAskedForMasternodeListEntry . count ( it - > vin . prevout ) & & mWeAskedForMasternodeListEntry [ it - > vin . prevout ] . count ( vecMasternodeRanks [ i ] . second . addr ) ) continue ;
// didn't ask recently, ok to ask now
CService addr = vecMasternodeRanks [ i ] . second . addr ;
CNode * pnode = ConnectNode ( CAddress ( addr ) , NULL , true ) ;
if ( pnode ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- asking for mnb of %s, addr=%s \n " , it - > vin . prevout . ToStringShort ( ) , addr . ToString ( ) ) ;
setRequested . insert ( addr ) ;
// can't use AskForMN here, inv system is way too smart, request data directly instead
std : : vector < CInv > vToFetch ;
vToFetch . push_back ( CInv ( MSG_MASTERNODE_ANNOUNCE , hash ) ) ;
pnode - > PushMessage ( NetMsgType : : GETDATA , vToFetch ) ;
fAskedForMnbRecovery = true ;
} else {
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- can't connect to node to ask for mnb, addr=%s \n " , addr . ToString ( ) ) ;
}
}
// wait for mnb recovery replies for MNB_RECOVERY_WAIT_SECONDS seconds
mMnbRecoveryRequests [ hash ] = std : : make_pair ( GetTime ( ) + MNB_RECOVERY_WAIT_SECONDS , setRequested ) ;
}
2016-11-13 18:52:34 +01:00
+ + it ;
}
2015-02-23 21:01:21 +01:00
}
2015-02-26 00:21:28 +01:00
2017-01-01 18:48:53 +01:00
// proces replies for MASTERNODE_NEW_START_REQUIRED masternodes
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- mMnbRecoveryGoodReplies size=%d \n " , ( int ) mMnbRecoveryGoodReplies . size ( ) ) ;
std : : map < uint256 , std : : vector < CMasternodeBroadcast > > : : iterator itMnbReplies = mMnbRecoveryGoodReplies . begin ( ) ;
while ( itMnbReplies ! = mMnbRecoveryGoodReplies . end ( ) ) {
if ( mMnbRecoveryRequests [ itMnbReplies - > first ] . first < GetTime ( ) ) {
// all nodes we asked should have replied now
if ( itMnbReplies - > second . size ( ) > = MNB_RECOVERY_QUORUM_REQUIRED ) {
// majority of nodes we asked agrees that this mn doesn't require new mnb, reprocess one of new mnbs
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- reprocessing mnb, masternode=%s \n " , itMnbReplies - > second [ 0 ] . vin . prevout . ToStringShort ( ) ) ;
// mapSeenMasternodeBroadcast.erase(itMnbReplies->first);
int nDos ;
itMnbReplies - > second [ 0 ] . fRecovery = true ;
CheckMnbAndUpdateMasternodeList ( NULL , itMnbReplies - > second [ 0 ] , nDos ) ;
}
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- removing mnb recovery reply, masternode=%s, size=%d \n " , itMnbReplies - > second [ 0 ] . vin . prevout . ToStringShort ( ) , ( int ) itMnbReplies - > second . size ( ) ) ;
mMnbRecoveryGoodReplies . erase ( itMnbReplies + + ) ;
} else {
+ + itMnbReplies ;
}
}
}
{
// no need for cm_main below
LOCK ( cs ) ;
std : : map < uint256 , std : : pair < int64_t , std : : set < CNetAddr > > > : : iterator itMnbRequest = mMnbRecoveryRequests . begin ( ) ;
while ( itMnbRequest ! = mMnbRecoveryRequests . end ( ) ) {
// Allow this mnb to be re-verified again after MNB_RECOVERY_RETRY_SECONDS seconds
// if mn is still in MASTERNODE_NEW_START_REQUIRED state.
if ( GetTime ( ) - itMnbRequest - > second . first > MNB_RECOVERY_RETRY_SECONDS ) {
mMnbRecoveryRequests . erase ( itMnbRequest + + ) ;
} else {
+ + itMnbRequest ;
}
}
2016-11-13 18:52:34 +01:00
// check who's asked for the Masternode list
std : : map < CNetAddr , int64_t > : : iterator it1 = mAskedUsForMasternodeList . begin ( ) ;
while ( it1 ! = mAskedUsForMasternodeList . end ( ) ) {
if ( ( * it1 ) . second < GetTime ( ) ) {
mAskedUsForMasternodeList . erase ( it1 + + ) ;
} else {
+ + it1 ;
}
2015-02-26 15:02:39 +01:00
}
2015-02-26 00:21:28 +01:00
2016-11-13 18:52:34 +01:00
// check who we asked for the Masternode list
it1 = mWeAskedForMasternodeList . begin ( ) ;
while ( it1 ! = mWeAskedForMasternodeList . end ( ) ) {
if ( ( * it1 ) . second < GetTime ( ) ) {
mWeAskedForMasternodeList . erase ( it1 + + ) ;
} else {
+ + it1 ;
}
2015-02-26 15:02:39 +01:00
}
2015-02-26 00:21:28 +01:00
2016-11-13 18:52:34 +01:00
// check which Masternodes we've asked for
2016-12-21 00:55:55 +01:00
std : : map < COutPoint , std : : map < CNetAddr , int64_t > > : : iterator it2 = mWeAskedForMasternodeListEntry . begin ( ) ;
2016-11-13 18:52:34 +01:00
while ( it2 ! = mWeAskedForMasternodeListEntry . end ( ) ) {
2016-12-21 00:55:55 +01:00
std : : map < CNetAddr , int64_t > : : iterator it3 = it2 - > second . begin ( ) ;
while ( it3 ! = it2 - > second . end ( ) ) {
if ( it3 - > second < GetTime ( ) ) {
it2 - > second . erase ( it3 + + ) ;
} else {
+ + it3 ;
}
}
if ( it2 - > second . empty ( ) ) {
2016-11-13 18:52:34 +01:00
mWeAskedForMasternodeListEntry . erase ( it2 + + ) ;
} else {
+ + it2 ;
}
2015-02-26 15:02:39 +01:00
}
2015-08-29 05:25:55 +02:00
2016-12-24 03:49:13 +01:00
std : : map < CNetAddr , CMasternodeVerification > : : iterator it3 = mWeAskedForVerification . begin ( ) ;
while ( it3 ! = mWeAskedForVerification . end ( ) ) {
if ( it3 - > second . nBlockHeight < pCurrentBlockIndex - > nHeight - MAX_POSE_BLOCKS ) {
mWeAskedForVerification . erase ( it3 + + ) ;
2016-11-13 18:52:34 +01:00
} else {
+ + it3 ;
}
2016-03-14 13:17:23 +01:00
}
2016-12-24 03:49:13 +01:00
// NOTE: do not expire mapSeenMasternodeBroadcast entries here, clean them on mnb updates!
2016-11-13 18:52:34 +01:00
// remove expired mapSeenMasternodePing
std : : map < uint256 , CMasternodePing > : : iterator it4 = mapSeenMasternodePing . begin ( ) ;
while ( it4 ! = mapSeenMasternodePing . end ( ) ) {
2016-12-24 03:49:13 +01:00
if ( ( * it4 ) . second . IsExpired ( ) ) {
2016-11-13 18:52:34 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- Removing expired Masternode ping: hash=%s \n " , ( * it4 ) . second . GetHash ( ) . ToString ( ) ) ;
mapSeenMasternodePing . erase ( it4 + + ) ;
} else {
+ + it4 ;
}
2015-08-25 04:24:30 +02:00
}
2016-11-13 18:52:34 +01:00
// remove expired mapSeenMasternodeVerification
std : : map < uint256 , CMasternodeVerification > : : iterator itv2 = mapSeenMasternodeVerification . begin ( ) ;
while ( itv2 ! = mapSeenMasternodeVerification . end ( ) ) {
if ( ( * itv2 ) . second . nBlockHeight < pCurrentBlockIndex - > nHeight - MAX_POSE_BLOCKS ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- Removing expired Masternode verification: hash=%s \n " , ( * itv2 ) . first . ToString ( ) ) ;
mapSeenMasternodeVerification . erase ( itv2 + + ) ;
} else {
+ + itv2 ;
}
}
LogPrintf ( " CMasternodeMan::CheckAndRemove -- %s \n " , ToString ( ) ) ;
if ( fMasternodesRemoved ) {
CheckAndRebuildMasternodeIndex ( ) ;
2016-10-20 23:11:30 +02:00
}
}
2016-10-22 18:52:14 +02:00
2016-11-13 18:52:34 +01:00
if ( fMasternodesRemoved ) {
NotifyMasternodeUpdates ( ) ;
}
2015-02-23 21:01:21 +01:00
}
2015-03-01 01:04:17 +01:00
void CMasternodeMan : : Clear ( )
{
LOCK ( cs ) ;
vMasternodes . clear ( ) ;
mAskedUsForMasternodeList . clear ( ) ;
mWeAskedForMasternodeList . clear ( ) ;
mWeAskedForMasternodeListEntry . clear ( ) ;
2015-09-30 03:24:29 +02:00
mapSeenMasternodeBroadcast . clear ( ) ;
mapSeenMasternodePing . clear ( ) ;
2015-03-06 18:25:48 +01:00
nDsqCount = 0 ;
2016-10-17 20:54:28 +02:00
nLastWatchdogVoteTime = 0 ;
2016-11-16 03:31:14 +01:00
indexMasternodes . Clear ( ) ;
indexMasternodesOld . Clear ( ) ;
2016-10-17 20:54:28 +02:00
}
2016-10-22 18:52:14 +02:00
int CMasternodeMan : : CountMasternodes ( int nProtocolVersion )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2016-10-22 18:52:14 +02:00
int nCount = 0 ;
nProtocolVersion = nProtocolVersion = = - 1 ? mnpayments . GetMinMasternodePaymentsProto ( ) : nProtocolVersion ;
2016-10-17 20:54:28 +02:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2016-10-22 18:52:14 +02:00
if ( mn . nProtocolVersion < nProtocolVersion ) continue ;
nCount + + ;
2016-10-17 20:54:28 +02:00
}
2016-10-22 18:52:14 +02:00
return nCount ;
2015-03-01 01:04:17 +01:00
}
2016-10-22 18:52:14 +02:00
int CMasternodeMan : : CountEnabled ( int nProtocolVersion )
2015-02-23 21:01:21 +01:00
{
2016-10-17 20:54:28 +02:00
LOCK ( cs ) ;
2016-10-22 18:52:14 +02:00
int nCount = 0 ;
nProtocolVersion = nProtocolVersion = = - 1 ? mnpayments . GetMinMasternodePaymentsProto ( ) : nProtocolVersion ;
2015-02-23 21:01:21 +01:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2016-10-22 18:52:14 +02:00
if ( mn . nProtocolVersion < nProtocolVersion | | ! mn . IsEnabled ( ) ) continue ;
nCount + + ;
2015-02-23 21:01:21 +01:00
}
2016-10-22 18:52:14 +02:00
return nCount ;
2016-08-06 22:52:01 +02:00
}
2016-10-22 18:52:14 +02:00
/* Only IPv4 masternodes are allowed in 12.1, saving this for later
2016-08-12 07:58:55 +02:00
int CMasternodeMan : : CountByIP ( int nNetworkType )
2016-08-06 22:52:01 +02:00
{
2016-10-17 20:54:28 +02:00
LOCK ( cs ) ;
2016-08-12 07:58:55 +02:00
int nNodeCount = 0 ;
2016-08-06 22:52:01 +02:00
2016-08-12 07:58:55 +02:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes )
2016-10-22 18:52:14 +02:00
if ( ( nNetworkType = = NET_IPV4 & & mn . addr . IsIPv4 ( ) ) | |
2016-08-12 07:58:55 +02:00
( nNetworkType = = NET_TOR & & mn . addr . IsTor ( ) ) | |
( nNetworkType = = NET_IPV6 & & mn . addr . IsIPv6 ( ) ) ) {
nNodeCount + + ;
2016-08-06 22:52:01 +02:00
}
2016-08-12 07:58:55 +02:00
return nNodeCount ;
2015-02-23 21:01:21 +01:00
}
2016-10-22 18:52:14 +02:00
*/
2015-02-23 21:01:21 +01:00
2015-02-26 00:21:28 +01:00
void CMasternodeMan : : DsegUpdate ( CNode * pnode )
{
2015-02-27 00:12:43 +01:00
LOCK ( cs ) ;
2016-02-02 16:28:56 +01:00
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN ) {
2016-10-22 18:52:14 +02:00
if ( ! ( pnode - > addr . IsRFC1918 ( ) | | pnode - > addr . IsLocal ( ) ) ) {
2015-07-29 10:06:30 +02:00
std : : map < CNetAddr , int64_t > : : iterator it = mWeAskedForMasternodeList . find ( pnode - > addr ) ;
2016-10-22 18:52:14 +02:00
if ( it ! = mWeAskedForMasternodeList . end ( ) & & GetTime ( ) < ( * it ) . second ) {
LogPrintf ( " CMasternodeMan::DsegUpdate -- we already asked %s for the list; skipping... \n " , pnode - > addr . ToString ( ) ) ;
return ;
2015-07-02 17:07:30 +02:00
}
2015-02-26 00:21:28 +01:00
}
}
2015-07-29 10:06:30 +02:00
2016-02-17 23:18:57 +01:00
pnode - > PushMessage ( NetMsgType : : DSEG , CTxIn ( ) ) ;
2016-10-20 23:11:30 +02:00
int64_t askAgain = GetTime ( ) + DSEG_UPDATE_SECONDS ;
2015-02-26 00:21:28 +01:00
mWeAskedForMasternodeList [ pnode - > addr ] = askAgain ;
2016-10-22 18:52:14 +02:00
LogPrint ( " masternode " , " CMasternodeMan::DsegUpdate -- asked %s for the list \n " , pnode - > addr . ToString ( ) ) ;
2015-02-26 00:21:28 +01:00
}
2016-10-22 18:52:14 +02:00
CMasternode * CMasternodeMan : : Find ( const CScript & payee )
2015-05-28 19:45:31 +02:00
{
LOCK ( cs ) ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes )
{
2016-09-16 00:00:06 +02:00
if ( GetScriptForDestination ( mn . pubKeyCollateralAddress . GetID ( ) ) = = payee )
2015-05-28 19:45:31 +02:00
return & mn ;
}
return NULL ;
}
2016-10-22 18:52:14 +02:00
CMasternode * CMasternodeMan : : Find ( const CTxIn & vin )
2015-02-26 00:21:28 +01:00
{
LOCK ( cs ) ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes )
{
2015-04-09 21:17:32 +02:00
if ( mn . vin . prevout = = vin . prevout )
2015-02-26 00:21:28 +01:00
return & mn ;
}
return NULL ;
}
2016-09-16 00:00:06 +02:00
CMasternode * CMasternodeMan : : Find ( const CPubKey & pubKeyMasternode )
2015-04-07 21:59:30 +02:00
{
LOCK ( cs ) ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes )
{
2016-09-16 00:00:06 +02:00
if ( mn . pubKeyMasternode = = pubKeyMasternode )
2015-04-07 21:59:30 +02:00
return & mn ;
}
return NULL ;
}
2016-09-05 01:44:10 +02:00
bool CMasternodeMan : : Get ( const CPubKey & pubKeyMasternode , CMasternode & masternode )
{
// Theses mutexes are recursive so double locking by the same thread is safe.
LOCK ( cs ) ;
CMasternode * pMN = Find ( pubKeyMasternode ) ;
if ( ! pMN ) {
return false ;
}
masternode = * pMN ;
return true ;
}
2016-09-15 08:49:24 +02:00
bool CMasternodeMan : : Get ( const CTxIn & vin , CMasternode & masternode )
{
// Theses mutexes are recursive so double locking by the same thread is safe.
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
return false ;
}
masternode = * pMN ;
return true ;
}
2016-10-17 20:54:28 +02:00
masternode_info_t CMasternodeMan : : GetMasternodeInfo ( const CTxIn & vin )
{
masternode_info_t info ;
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
return info ;
}
info = pMN - > GetInfo ( ) ;
return info ;
}
masternode_info_t CMasternodeMan : : GetMasternodeInfo ( const CPubKey & pubKeyMasternode )
{
masternode_info_t info ;
LOCK ( cs ) ;
CMasternode * pMN = Find ( pubKeyMasternode ) ;
if ( ! pMN ) {
return info ;
}
info = pMN - > GetInfo ( ) ;
return info ;
}
bool CMasternodeMan : : Has ( const CTxIn & vin )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
return ( pMN ! = NULL ) ;
}
2016-10-22 18:52:14 +02:00
//
2015-07-22 05:07:23 +02:00
// Deterministically select the oldest/best masternode to pay on the network
//
2016-11-28 15:21:50 +01:00
CMasternode * CMasternodeMan : : GetNextMasternodeInQueueForPayment ( bool fFilterSigTime , int & nCount )
{
if ( ! pCurrentBlockIndex ) {
nCount = 0 ;
return NULL ;
}
return GetNextMasternodeInQueueForPayment ( pCurrentBlockIndex - > nHeight , fFilterSigTime , nCount ) ;
}
2015-08-20 17:36:44 +02:00
CMasternode * CMasternodeMan : : GetNextMasternodeInQueueForPayment ( int nBlockHeight , bool fFilterSigTime , int & nCount )
2015-02-26 00:21:28 +01:00
{
2016-10-27 17:58:12 +02:00
// Need LOCK2 here to ensure consistent locking order because the GetBlockHash call below locks cs_main
LOCK2 ( cs_main , cs ) ;
2015-02-26 00:21:28 +01:00
2015-07-22 05:07:23 +02:00
CMasternode * pBestMasternode = NULL ;
2016-09-20 00:27:36 +02:00
std : : vector < std : : pair < int , CMasternode * > > vecMasternodeLastPaid ;
2015-07-22 05:07:23 +02:00
/*
Make a vector with all of the last paid times
*/
2015-03-01 16:38:53 +01:00
2015-07-23 16:16:55 +02:00
int nMnCount = CountEnabled ( ) ;
2015-02-26 00:21:28 +01:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes )
{
2016-11-23 16:30:36 +01:00
if ( ! mn . IsValidForPayment ( ) ) continue ;
2015-02-26 00:21:28 +01:00
2015-06-25 21:59:11 +02:00
// //check protocol version
2016-09-16 00:00:06 +02:00
if ( mn . nProtocolVersion < mnpayments . GetMinMasternodePaymentsProto ( ) ) continue ;
2015-06-25 21:59:11 +02:00
2015-07-23 15:45:43 +02:00
//it's in the list (up to 8 entries ahead of current block to allow propagation) -- so let's skip it
2016-02-04 20:29:09 +01:00
if ( mnpayments . IsScheduled ( mn , nBlockHeight ) ) continue ;
2015-05-27 21:47:01 +02:00
2015-07-23 16:16:55 +02:00
//it's too new, wait for a cycle
2015-07-25 01:10:44 +02:00
if ( fFilterSigTime & & mn . sigTime + ( nMnCount * 2.6 * 60 ) > GetAdjustedTime ( ) ) continue ;
2015-07-23 16:16:55 +02:00
2016-10-22 18:52:14 +02:00
//make sure it has at least as many confirmations as there are masternodes
2016-09-11 22:22:37 +02:00
if ( mn . GetCollateralAge ( ) < nMnCount ) continue ;
2015-05-30 19:27:51 +02:00
2016-09-20 00:27:36 +02:00
vecMasternodeLastPaid . push_back ( std : : make_pair ( mn . GetLastPaidBlock ( ) , & mn ) ) ;
2015-02-26 00:21:28 +01:00
}
2015-08-20 18:27:34 +02:00
nCount = ( int ) vecMasternodeLastPaid . size ( ) ;
2015-08-20 17:36:44 +02:00
//when the network is in the process of upgrading, don't penalize nodes that recently restarted
if ( fFilterSigTime & & nCount < nMnCount / 3 ) return GetNextMasternodeInQueueForPayment ( nBlockHeight , false , nCount ) ;
2016-09-11 22:22:37 +02:00
// Sort them low to high
sort ( vecMasternodeLastPaid . begin ( ) , vecMasternodeLastPaid . end ( ) , CompareLastPaidBlock ( ) ) ;
2015-07-22 05:07:23 +02:00
2016-10-13 11:45:18 +02:00
uint256 blockHash ;
if ( ! GetBlockHash ( blockHash , nBlockHeight - 101 ) ) {
LogPrintf ( " CMasternode::GetNextMasternodeInQueueForPayment -- ERROR: GetBlockHash() failed at nBlockHeight %d \n " , nBlockHeight - 101 ) ;
return NULL ;
}
2015-07-22 05:07:23 +02:00
// Look at 1/10 of the oldest nodes (by last payment), calculate their scores and pay the best one
2015-07-23 15:45:43 +02:00
// -- This doesn't look at who is being paid in the +8-10 blocks, allowing for double payments very rarely
2015-07-30 18:00:28 +02:00
// -- 1/100 payments should be a double payment on mainnet - (1/(3000/10))*2
// -- (chance per block * chances before IsScheduled will fire)
2016-12-24 03:49:13 +01:00
int nTenthNetwork = nMnCount / 10 ;
2016-09-11 22:22:37 +02:00
int nCountTenth = 0 ;
2016-10-13 11:45:18 +02:00
arith_uint256 nHighest = 0 ;
2016-09-20 00:27:36 +02:00
BOOST_FOREACH ( PAIRTYPE ( int , CMasternode * ) & s , vecMasternodeLastPaid ) {
2016-10-13 11:45:18 +02:00
arith_uint256 nScore = s . second - > CalculateScore ( blockHash ) ;
if ( nScore > nHighest ) {
nHighest = nScore ;
2016-09-20 00:27:36 +02:00
pBestMasternode = s . second ;
2015-07-22 05:07:23 +02:00
}
2015-08-20 17:36:44 +02:00
nCountTenth + + ;
2015-08-20 17:50:29 +02:00
if ( nCountTenth > = nTenthNetwork ) break ;
2015-07-22 05:07:23 +02:00
}
return pBestMasternode ;
2015-02-26 00:21:28 +01:00
}
2016-10-22 18:52:14 +02:00
CMasternode * CMasternodeMan : : FindRandomNotInVec ( const std : : vector < CTxIn > & vecToExclude , int nProtocolVersion )
2015-02-26 00:21:28 +01:00
{
LOCK ( cs ) ;
2016-07-29 07:29:41 +02:00
nProtocolVersion = nProtocolVersion = = - 1 ? mnpayments . GetMinMasternodePaymentsProto ( ) : nProtocolVersion ;
2015-07-29 17:11:43 +02:00
2016-07-29 07:29:41 +02:00
int nCountEnabled = CountEnabled ( nProtocolVersion ) ;
int nCountNotExcluded = nCountEnabled - vecToExclude . size ( ) ;
2015-07-29 17:11:43 +02:00
2016-10-22 18:52:14 +02:00
LogPrintf ( " CMasternodeMan::FindRandomNotInVec -- %d enabled masternodes, %d masternodes to choose from \n " , nCountEnabled , nCountNotExcluded ) ;
2016-07-29 07:29:41 +02:00
if ( nCountNotExcluded < 1 ) return NULL ;
2015-02-26 00:21:28 +01:00
2016-09-20 00:27:36 +02:00
// fill a vector of pointers
std : : vector < CMasternode * > vpMasternodesShuffled ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
vpMasternodesShuffled . push_back ( & mn ) ;
}
2016-11-20 07:52:45 +01:00
InsecureRand insecureRand ;
2016-09-20 00:27:36 +02:00
// shuffle pointers
2016-11-20 07:52:45 +01:00
std : : random_shuffle ( vpMasternodesShuffled . begin ( ) , vpMasternodesShuffled . end ( ) , insecureRand ) ;
2016-07-29 07:29:41 +02:00
bool fExclude ;
2016-09-20 00:27:36 +02:00
// loop through
BOOST_FOREACH ( CMasternode * pmn , vpMasternodesShuffled ) {
if ( pmn - > nProtocolVersion < nProtocolVersion | | ! pmn - > IsEnabled ( ) ) continue ;
2016-07-29 07:29:41 +02:00
fExclude = false ;
2016-10-22 18:52:14 +02:00
BOOST_FOREACH ( const CTxIn & txinToExclude , vecToExclude ) {
2016-09-20 00:27:36 +02:00
if ( pmn - > vin . prevout = = txinToExclude . prevout ) {
2016-07-29 07:29:41 +02:00
fExclude = true ;
2015-07-29 17:11:43 +02:00
break ;
}
}
2016-07-29 07:29:41 +02:00
if ( fExclude ) continue ;
// found the one not in vecToExclude
2016-09-20 00:27:36 +02:00
LogPrint ( " masternode " , " CMasternodeMan::FindRandomNotInVec -- found, masternode=%s \n " , pmn - > vin . prevout . ToStringShort ( ) ) ;
return pmn ;
2015-07-29 17:11:43 +02:00
}
2016-09-20 00:27:36 +02:00
LogPrint ( " masternode " , " CMasternodeMan::FindRandomNotInVec -- failed \n " ) ;
2015-07-29 17:11:43 +02:00
return NULL ;
2015-02-26 00:21:28 +01:00
}
2016-10-22 18:52:14 +02:00
int CMasternodeMan : : GetMasternodeRank ( const CTxIn & vin , int nBlockHeight , int nMinProtocol , bool fOnlyActive )
2015-02-23 21:01:21 +01:00
{
2016-09-20 00:27:36 +02:00
std : : vector < std : : pair < int64_t , CMasternode * > > vecMasternodeScores ;
2015-02-23 21:01:21 +01:00
2015-03-23 13:59:22 +01:00
//make sure we know about this block
2016-10-13 11:45:18 +02:00
uint256 blockHash = uint256 ( ) ;
if ( ! GetBlockHash ( blockHash , nBlockHeight ) ) return - 1 ;
2015-03-23 13:59:22 +01:00
2016-09-20 00:27:36 +02:00
LOCK ( cs ) ;
2015-02-23 21:01:21 +01:00
// scan for winner
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2016-10-22 18:52:14 +02:00
if ( mn . nProtocolVersion < nMinProtocol ) continue ;
2015-03-24 03:02:22 +01:00
if ( fOnlyActive ) {
if ( ! mn . IsEnabled ( ) ) continue ;
2015-02-23 21:01:21 +01:00
}
2016-11-23 16:30:36 +01:00
else {
if ( ! mn . IsValidForPayment ( ) ) continue ;
}
2016-10-13 11:45:18 +02:00
int64_t nScore = mn . CalculateScore ( blockHash ) . GetCompact ( false ) ;
2015-02-23 21:01:21 +01:00
2016-10-13 11:45:18 +02:00
vecMasternodeScores . push_back ( std : : make_pair ( nScore , & mn ) ) ;
2015-02-23 21:01:21 +01:00
}
2016-09-20 00:27:36 +02:00
sort ( vecMasternodeScores . rbegin ( ) , vecMasternodeScores . rend ( ) , CompareScoreMN ( ) ) ;
2015-02-23 21:01:21 +01:00
2016-09-20 00:27:36 +02:00
int nRank = 0 ;
BOOST_FOREACH ( PAIRTYPE ( int64_t , CMasternode * ) & scorePair , vecMasternodeScores ) {
nRank + + ;
if ( scorePair . second - > vin . prevout = = vin . prevout ) return nRank ;
2015-02-23 21:01:21 +01:00
}
return - 1 ;
}
2016-10-22 18:52:14 +02:00
std : : vector < std : : pair < int , CMasternode > > CMasternodeMan : : GetMasternodeRanks ( int nBlockHeight , int nMinProtocol )
2015-03-14 19:34:51 +01:00
{
2016-09-20 00:27:36 +02:00
std : : vector < std : : pair < int64_t , CMasternode * > > vecMasternodeScores ;
std : : vector < std : : pair < int , CMasternode > > vecMasternodeRanks ;
2015-03-14 19:34:51 +01:00
2015-03-23 13:59:22 +01:00
//make sure we know about this block
2016-10-13 11:45:18 +02:00
uint256 blockHash = uint256 ( ) ;
if ( ! GetBlockHash ( blockHash , nBlockHeight ) ) return vecMasternodeRanks ;
2015-03-23 13:59:22 +01:00
2016-09-20 00:27:36 +02:00
LOCK ( cs ) ;
2015-03-14 19:34:51 +01:00
// scan for winner
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2016-10-22 18:52:14 +02:00
if ( mn . nProtocolVersion < nMinProtocol | | ! mn . IsEnabled ( ) ) continue ;
2015-03-14 19:34:51 +01:00
2016-10-13 11:45:18 +02:00
int64_t nScore = mn . CalculateScore ( blockHash ) . GetCompact ( false ) ;
2015-03-14 19:34:51 +01:00
2016-10-13 11:45:18 +02:00
vecMasternodeScores . push_back ( std : : make_pair ( nScore , & mn ) ) ;
2015-03-14 19:34:51 +01:00
}
2015-07-30 18:00:28 +02:00
sort ( vecMasternodeScores . rbegin ( ) , vecMasternodeScores . rend ( ) , CompareScoreMN ( ) ) ;
2015-03-14 19:34:51 +01:00
2016-09-20 00:27:36 +02:00
int nRank = 0 ;
BOOST_FOREACH ( PAIRTYPE ( int64_t , CMasternode * ) & s , vecMasternodeScores ) {
nRank + + ;
vecMasternodeRanks . push_back ( std : : make_pair ( nRank , * s . second ) ) ;
2015-03-14 19:34:51 +01:00
}
return vecMasternodeRanks ;
}
2016-10-22 18:52:14 +02:00
CMasternode * CMasternodeMan : : GetMasternodeByRank ( int nRank , int nBlockHeight , int nMinProtocol , bool fOnlyActive )
2015-03-02 00:09:33 +01:00
{
2016-09-20 00:27:36 +02:00
std : : vector < std : : pair < int64_t , CMasternode * > > vecMasternodeScores ;
2015-03-02 00:09:33 +01:00
2016-09-20 00:27:36 +02:00
LOCK ( cs ) ;
2016-10-13 11:45:18 +02:00
uint256 blockHash ;
if ( ! GetBlockHash ( blockHash , nBlockHeight ) ) {
LogPrintf ( " CMasternode::GetMasternodeByRank -- ERROR: GetBlockHash() failed at nBlockHeight %d \n " , nBlockHeight ) ;
return NULL ;
}
2016-09-20 00:27:36 +02:00
// Fill scores
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2016-10-22 18:52:14 +02:00
if ( mn . nProtocolVersion < nMinProtocol ) continue ;
2016-11-28 15:21:50 +01:00
if ( fOnlyActive & & ! mn . IsEnabled ( ) ) continue ;
2015-03-02 00:09:33 +01:00
2016-10-13 11:45:18 +02:00
int64_t nScore = mn . CalculateScore ( blockHash ) . GetCompact ( false ) ;
2015-03-02 00:09:33 +01:00
2016-10-13 11:45:18 +02:00
vecMasternodeScores . push_back ( std : : make_pair ( nScore , & mn ) ) ;
2015-03-02 00:09:33 +01:00
}
2016-09-20 00:27:36 +02:00
sort ( vecMasternodeScores . rbegin ( ) , vecMasternodeScores . rend ( ) , CompareScoreMN ( ) ) ;
2015-03-02 00:09:33 +01:00
int rank = 0 ;
2016-09-20 00:27:36 +02:00
BOOST_FOREACH ( PAIRTYPE ( int64_t , CMasternode * ) & s , vecMasternodeScores ) {
2015-03-02 00:09:33 +01:00
rank + + ;
if ( rank = = nRank ) {
2016-09-20 00:27:36 +02:00
return s . second ;
2015-03-02 00:09:33 +01:00
}
}
return NULL ;
}
void CMasternodeMan : : ProcessMasternodeConnections ( )
{
2015-03-24 03:03:34 +01:00
//we don't care about this for regtest
2016-02-02 16:28:56 +01:00
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : REGTEST ) return ;
2015-03-06 23:17:51 +01:00
2015-08-11 08:00:46 +02:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes ) {
2016-07-30 13:05:41 +02:00
if ( pnode - > fMasternode ) {
2015-08-11 08:00:46 +02:00
if ( darkSendPool . pSubmittedToMasternode ! = NULL & & pnode - > addr = = darkSendPool . pSubmittedToMasternode - > addr ) continue ;
2016-10-22 18:52:14 +02:00
LogPrintf ( " Closing Masternode connection: peer=%d, addr=%s \n " , pnode - > id , pnode - > addr . ToString ( ) ) ;
2016-07-30 13:05:41 +02:00
pnode - > fDisconnect = true ;
2015-03-02 00:09:33 +01:00
}
}
}
2015-02-23 21:01:21 +01:00
void CMasternodeMan : : ProcessMessage ( CNode * pfrom , std : : string & strCommand , CDataStream & vRecv )
{
2016-10-22 18:52:14 +02:00
if ( fLiteMode ) return ; // disable all Dash specific functionality
2015-08-07 06:48:55 +02:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) return ;
2015-02-23 21:01:21 +01:00
2016-02-17 23:18:57 +01:00
if ( strCommand = = NetMsgType : : MNANNOUNCE ) { //Masternode Broadcast
2016-10-22 18:52:14 +02:00
2016-11-28 15:21:50 +01:00
CMasternodeBroadcast mnb ;
vRecv > > mnb ;
2015-02-23 21:01:21 +01:00
2017-01-17 21:02:59 +01:00
pfrom - > setAskFor . erase ( mnb . GetHash ( ) ) ;
2016-12-24 03:49:13 +01:00
LogPrint ( " masternode " , " MNANNOUNCE -- Masternode announce, masternode=%s \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
2016-12-20 00:09:38 +01:00
// backward compatibility patch
if ( pfrom - > nVersion < 70204 ) {
int64_t nLastDsqDummy ;
vRecv > > nLastDsqDummy ;
}
2016-11-28 15:21:50 +01:00
int nDos = 0 ;
2015-02-23 21:01:21 +01:00
2017-01-01 18:48:53 +01:00
if ( CheckMnbAndUpdateMasternodeList ( pfrom , mnb , nDos ) ) {
2016-11-28 15:21:50 +01:00
// use announced Masternode as a peer
addrman . Add ( CAddress ( mnb . addr ) , pfrom - > addr , 2 * 60 * 60 ) ;
} else if ( nDos > 0 ) {
Misbehaving ( pfrom - > GetId ( ) , nDos ) ;
2016-11-13 18:52:34 +01:00
}
2016-11-28 15:21:50 +01:00
2016-11-13 18:52:34 +01:00
if ( fMasternodesAdded ) {
NotifyMasternodeUpdates ( ) ;
}
2016-08-29 21:11:34 +02:00
} else if ( strCommand = = NetMsgType : : MNPING ) { //Masternode Ping
2015-04-17 17:10:38 +02:00
CMasternodePing mnp ;
vRecv > > mnp ;
2015-02-23 21:01:21 +01:00
2017-01-17 21:02:59 +01:00
uint256 nHash = mnp . GetHash ( ) ;
pfrom - > setAskFor . erase ( nHash ) ;
2016-10-22 18:52:14 +02:00
LogPrint ( " masternode " , " MNPING -- Masternode ping, masternode=%s \n " , mnp . vin . prevout . ToStringShort ( ) ) ;
2015-07-14 07:25:07 +02:00
2016-11-28 15:21:50 +01:00
// Need LOCK2 here to ensure consistent locking order because the CheckAndUpdate call below locks cs_main
LOCK2 ( cs_main , cs ) ;
2016-10-30 20:40:30 +01:00
2017-01-17 21:02:59 +01:00
if ( mapSeenMasternodePing . count ( nHash ) ) return ; //seen
mapSeenMasternodePing . insert ( std : : make_pair ( nHash , mnp ) ) ;
2015-02-23 21:01:21 +01:00
2016-10-22 18:52:14 +02:00
LogPrint ( " masternode " , " MNPING -- Masternode ping, masternode=%s new \n " , mnp . vin . prevout . ToStringShort ( ) ) ;
2016-02-17 19:53:55 +01:00
2016-12-24 03:49:13 +01:00
// see if we have this Masternode
CMasternode * pmn = mnodeman . Find ( mnp . vin ) ;
// too late, new MNANNOUNCE is required
if ( pmn & & pmn - > IsNewStartRequired ( ) ) return ;
2016-03-15 00:16:29 +01:00
int nDos = 0 ;
2016-12-26 07:44:48 +01:00
if ( mnp . CheckAndUpdate ( pmn , false , nDos ) ) return ;
2015-07-14 07:25:07 +02:00
2016-03-15 00:16:29 +01:00
if ( nDos > 0 ) {
2015-08-07 05:07:40 +02:00
// if anything significant failed, mark that node
2016-03-15 00:16:29 +01:00
Misbehaving ( pfrom - > GetId ( ) , nDos ) ;
2016-12-24 03:49:13 +01:00
} else if ( pmn ! = NULL ) {
// nothing significant failed, mn is a known one too
return ;
2015-02-23 21:01:21 +01:00
}
2015-08-07 05:07:40 +02:00
// something significant is broken or mn is unknown,
// we might have to ask for a masternode entry once
AskForMN ( pfrom , mnp . vin ) ;
2015-02-23 21:01:21 +01:00
2016-02-17 23:18:57 +01:00
} else if ( strCommand = = NetMsgType : : DSEG ) { //Get Masternode list or specific entry
2016-08-29 21:11:34 +02:00
// 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.
2016-08-05 18:25:03 +02:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2015-02-23 21:01:21 +01:00
CTxIn vin ;
vRecv > > vin ;
2016-10-22 18:52:14 +02:00
LogPrint ( " masternode " , " DSEG -- Masternode list, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
2016-02-17 19:53:55 +01:00
2016-10-30 20:40:30 +01:00
LOCK ( cs ) ;
2015-02-23 21:01:21 +01:00
if ( vin = = CTxIn ( ) ) { //only should ask for this once
//local network
2015-07-02 17:07:30 +02:00
bool isLocal = ( pfrom - > addr . IsRFC1918 ( ) | | pfrom - > addr . IsLocal ( ) ) ;
2016-02-02 16:28:56 +01:00
if ( ! isLocal & & Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN ) {
2015-02-26 00:21:28 +01:00
std : : map < CNetAddr , int64_t > : : iterator i = mAskedUsForMasternodeList . find ( pfrom - > addr ) ;
2015-04-03 00:51:08 +02:00
if ( i ! = mAskedUsForMasternodeList . end ( ) ) {
2015-02-23 21:01:21 +01:00
int64_t t = ( * i ) . second ;
if ( GetTime ( ) < t ) {
Misbehaving ( pfrom - > GetId ( ) , 34 ) ;
2016-10-22 18:52:14 +02:00
LogPrintf ( " DSEG -- peer already asked me for the list, peer=%d \n " , pfrom - > id ) ;
2015-02-23 21:01:21 +01:00
return ;
}
}
2016-10-20 23:11:30 +02:00
int64_t askAgain = GetTime ( ) + DSEG_UPDATE_SECONDS ;
2015-02-26 00:21:28 +01:00
mAskedUsForMasternodeList [ pfrom - > addr ] = askAgain ;
2015-02-23 21:01:21 +01:00
}
} //else, asking for a specific node which is ok
2015-08-31 06:05:10 +02:00
int nInvCount = 0 ;
2015-02-23 21:01:21 +01:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2016-09-15 15:30:51 +02:00
if ( vin ! = CTxIn ( ) & & vin ! = mn . vin ) continue ; // asked for specific vin but we are not there yet
if ( mn . addr . IsRFC1918 ( ) | | mn . addr . IsLocal ( ) ) continue ; // do not send local network masternode
2016-10-22 18:52:14 +02:00
LogPrint ( " masternode " , " DSEG -- Sending Masternode entry: masternode=%s addr=%s \n " , mn . vin . prevout . ToStringShort ( ) , mn . addr . ToString ( ) ) ;
2016-09-15 15:30:51 +02:00
CMasternodeBroadcast mnb = CMasternodeBroadcast ( mn ) ;
uint256 hash = mnb . GetHash ( ) ;
pfrom - > PushInventory ( CInv ( MSG_MASTERNODE_ANNOUNCE , hash ) ) ;
2016-12-24 03:49:13 +01:00
pfrom - > PushInventory ( CInv ( MSG_MASTERNODE_PING , mn . lastPing . GetHash ( ) ) ) ;
2016-09-15 15:30:51 +02:00
nInvCount + + ;
if ( ! mapSeenMasternodeBroadcast . count ( hash ) ) {
2016-12-26 07:44:36 +01:00
mapSeenMasternodeBroadcast . insert ( std : : make_pair ( hash , std : : make_pair ( GetTime ( ) , mnb ) ) ) ;
2016-09-15 15:30:51 +02:00
}
2015-08-26 02:18:01 +02:00
2016-09-15 15:30:51 +02:00
if ( vin = = mn . vin ) {
2016-10-22 18:52:14 +02:00
LogPrintf ( " DSEG -- Sent 1 Masternode inv to peer %d \n " , pfrom - > id ) ;
2016-09-15 15:30:51 +02:00
return ;
2015-02-23 21:01:21 +01:00
}
}
2015-07-29 06:16:11 +02:00
2015-08-31 06:05:10 +02:00
if ( vin = = CTxIn ( ) ) {
2016-02-17 23:18:57 +01:00
pfrom - > PushMessage ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_LIST , nInvCount ) ;
2016-10-22 18:52:14 +02:00
LogPrintf ( " DSEG -- Sent %d Masternode invs to peer %d \n " , nInvCount , pfrom - > id ) ;
2016-09-15 15:30:51 +02:00
return ;
2015-08-31 06:05:10 +02:00
}
2016-09-15 15:30:51 +02:00
// smth weird happen - someone asked us for vin we have no idea about?
2016-10-22 18:52:14 +02:00
LogPrint ( " masternode " , " DSEG -- No invs sent to peer %d \n " , pfrom - > id ) ;
2016-10-20 23:11:30 +02:00
} else if ( strCommand = = NetMsgType : : MNVERIFY ) { // Masternode Verify
2016-11-30 01:48:05 +01:00
// Need LOCK2 here to ensure consistent locking order because the all functions below call GetBlockHash which locks cs_main
LOCK2 ( cs_main , cs ) ;
2016-11-13 18:52:34 +01:00
2016-10-20 23:11:30 +02:00
CMasternodeVerification mnv ;
vRecv > > mnv ;
if ( mnv . vchSig1 . empty ( ) ) {
// CASE 1: someone asked me to verify myself /IP we are using/
SendVerifyReply ( pfrom , mnv ) ;
} else if ( mnv . vchSig2 . empty ( ) ) {
// CASE 2: we _probably_ got verification we requested from some masternode
ProcessVerifyReply ( pfrom , mnv ) ;
} else {
// CASE 3: we _probably_ got verification broadcast signed by some masternode which verified another one
ProcessVerifyBroadcast ( pfrom , mnv ) ;
}
}
}
2016-10-22 18:52:14 +02:00
// Verification of masternodes via unique direct requests.
2016-10-20 23:11:30 +02:00
void CMasternodeMan : : DoFullVerificationStep ( )
{
if ( activeMasternode . vin = = CTxIn ( ) ) return ;
2017-01-14 23:29:08 +01:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2016-10-20 23:11:30 +02:00
std : : vector < std : : pair < int , CMasternode > > vecMasternodeRanks = GetMasternodeRanks ( pCurrentBlockIndex - > nHeight - 1 , MIN_POSE_PROTO_VERSION ) ;
2016-11-28 15:21:50 +01:00
// Need LOCK2 here to ensure consistent locking order because the SendVerifyRequest call below locks cs_main
// through GetHeight() signal in ConnectNode
LOCK2 ( cs_main , cs ) ;
2016-10-20 23:11:30 +02:00
int nCount = 0 ;
int nCountMax = std : : max ( 10 , ( int ) vMasternodes . size ( ) / 100 ) ; // verify at least 10 masternode at once but at most 1% of all known masternodes
int nMyRank = - 1 ;
int nRanksTotal = ( int ) vecMasternodeRanks . size ( ) ;
// send verify requests only if we are in top MAX_POSE_RANK
std : : vector < std : : pair < int , CMasternode > > : : iterator it = vecMasternodeRanks . begin ( ) ;
while ( it ! = vecMasternodeRanks . end ( ) ) {
if ( it - > first > MAX_POSE_RANK ) {
LogPrint ( " masternode " , " CMasternodeMan::DoFullVerificationStep -- Must be in top %d to send verify request \n " ,
( int ) MAX_POSE_RANK ) ;
return ;
}
if ( it - > second . vin = = activeMasternode . vin ) {
nMyRank = it - > first ;
LogPrint ( " masternode " , " CMasternodeMan::DoFullVerificationStep -- Found self at rank %d/%d, verifying up to %d masternodes \n " ,
nMyRank , nRanksTotal , nCountMax ) ;
break ;
}
+ + it ;
}
// edge case: list is too short and this masternode is not enabled
if ( nMyRank = = - 1 ) return ;
// send verify requests to up to nCountMax masternodes starting from
// (MAX_POSE_RANK + nCountMax * (nMyRank - 1) + 1)
int nOffset = MAX_POSE_RANK + nCountMax * ( nMyRank - 1 ) ;
if ( nOffset > = ( int ) vecMasternodeRanks . size ( ) ) return ;
std : : vector < CMasternode * > vSortedByAddr ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
vSortedByAddr . push_back ( & mn ) ;
}
sort ( vSortedByAddr . begin ( ) , vSortedByAddr . end ( ) , CompareByAddr ( ) ) ;
it = vecMasternodeRanks . begin ( ) + nOffset ;
while ( it ! = vecMasternodeRanks . end ( ) ) {
if ( it - > second . IsPoSeVerified ( ) | | it - > second . IsPoSeBanned ( ) ) {
LogPrint ( " masternode " , " CMasternodeMan::DoFullVerificationStep -- Already %s%s%s masternode %s address %s, skipping... \n " ,
it - > second . IsPoSeVerified ( ) ? " verified " : " " ,
it - > second . IsPoSeVerified ( ) & & it - > second . IsPoSeBanned ( ) ? " and " : " " ,
it - > second . IsPoSeBanned ( ) ? " banned " : " " ,
it - > second . vin . prevout . ToStringShort ( ) , it - > second . addr . ToString ( ) ) ;
+ + it ;
continue ;
}
LogPrint ( " masternode " , " CMasternodeMan::DoFullVerificationStep -- Verifying masternode %s rank %d/%d address %s \n " ,
it - > second . vin . prevout . ToStringShort ( ) , it - > first , nRanksTotal , it - > second . addr . ToString ( ) ) ;
if ( SendVerifyRequest ( ( CAddress ) it - > second . addr , vSortedByAddr ) ) {
nCount + + ;
if ( nCount > = nCountMax ) break ;
}
+ + it ;
}
LogPrint ( " masternode " , " CMasternodeMan::DoFullVerificationStep -- Sent verification requests to %d masternodes \n " , nCount ) ;
}
2016-10-22 18:52:14 +02:00
// This function tries to find masternodes with the same addr,
// find a verified one and ban all the other. If there are many nodes
// with the same addr but none of them is verified yet, then none of them are banned.
// It could take many times to run this before most of the duplicate nodes are banned.
2016-10-20 23:11:30 +02:00
void CMasternodeMan : : CheckSameAddr ( )
{
if ( ! masternodeSync . IsSynced ( ) | | vMasternodes . empty ( ) ) return ;
std : : vector < CMasternode * > vBan ;
std : : vector < CMasternode * > vSortedByAddr ;
{
LOCK ( cs ) ;
CMasternode * pprevMasternode = NULL ;
CMasternode * pverifiedMasternode = NULL ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
vSortedByAddr . push_back ( & mn ) ;
}
sort ( vSortedByAddr . begin ( ) , vSortedByAddr . end ( ) , CompareByAddr ( ) ) ;
BOOST_FOREACH ( CMasternode * pmn , vSortedByAddr ) {
// check only (pre)enabled masternodes
if ( ! pmn - > IsEnabled ( ) & & ! pmn - > IsPreEnabled ( ) ) continue ;
// initial step
if ( ! pprevMasternode ) {
pprevMasternode = pmn ;
pverifiedMasternode = pmn - > IsPoSeVerified ( ) ? pmn : NULL ;
continue ;
}
// second+ step
if ( pmn - > addr = = pprevMasternode - > addr ) {
if ( pverifiedMasternode ) {
// another masternode with the same ip is verified, ban this one
vBan . push_back ( pmn ) ;
} else if ( pmn - > IsPoSeVerified ( ) ) {
// this masternode with the same ip is verified, ban previous one
vBan . push_back ( pprevMasternode ) ;
// and keep a reference to be able to ban following masternodes with the same ip
pverifiedMasternode = pmn ;
}
} else {
pverifiedMasternode = pmn - > IsPoSeVerified ( ) ? pmn : NULL ;
}
pprevMasternode = pmn ;
}
}
// ban duplicates
BOOST_FOREACH ( CMasternode * pmn , vBan ) {
2016-10-30 21:56:47 +01:00
LogPrintf ( " CMasternodeMan::CheckSameAddr -- increasing PoSe ban score for masternode %s \n " , pmn - > vin . prevout . ToStringShort ( ) ) ;
pmn - > IncreasePoSeBanScore ( ) ;
2016-10-20 23:11:30 +02:00
}
}
bool CMasternodeMan : : SendVerifyRequest ( const CAddress & addr , const std : : vector < CMasternode * > & vSortedByAddr )
{
if ( netfulfilledman . HasFulfilledRequest ( addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -request " ) ) {
// we already asked for verification, not a good idea to do this too often, skip it
LogPrint ( " masternode " , " CMasternodeMan::SendVerifyRequest -- too many requests, skipping... addr=%s \n " , addr . ToString ( ) ) ;
return false ;
}
CNode * pnode = ConnectNode ( addr , NULL , true ) ;
2016-12-11 07:18:52 +01:00
if ( pnode = = NULL ) {
LogPrintf ( " CMasternodeMan::SendVerifyRequest -- can't connect to node to verify it, addr=%s \n " , addr . ToString ( ) ) ;
2016-10-20 23:11:30 +02:00
return false ;
}
2016-12-11 07:18:52 +01:00
netfulfilledman . AddFulfilledRequest ( addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -request " ) ;
// use random nonce, store it and require node to reply with correct one later
CMasternodeVerification mnv ( addr , GetRandInt ( 999999 ) , pCurrentBlockIndex - > nHeight - 1 ) ;
mWeAskedForVerification [ addr ] = mnv ;
LogPrintf ( " CMasternodeMan::SendVerifyRequest -- verifying node using nonce %d addr=%s \n " , mnv . nonce , addr . ToString ( ) ) ;
pnode - > PushMessage ( NetMsgType : : MNVERIFY , mnv ) ;
return true ;
2016-10-20 23:11:30 +02:00
}
void CMasternodeMan : : SendVerifyReply ( CNode * pnode , CMasternodeVerification & mnv )
{
// only masternodes can sign this, why would someone ask regular node?
if ( ! fMasterNode ) {
// do not ban, malicious node might be using my IP
// and trying to confuse the node which tries to verify it
return ;
}
if ( netfulfilledman . HasFulfilledRequest ( pnode - > addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -reply " ) ) {
// peer should not ask us that often
LogPrintf ( " MasternodeMan::SendVerifyReply -- ERROR: peer already asked me recently, peer=%d \n " , pnode - > id ) ;
Misbehaving ( pnode - > id , 20 ) ;
return ;
}
uint256 blockHash ;
if ( ! GetBlockHash ( blockHash , mnv . nBlockHeight ) ) {
LogPrintf ( " MasternodeMan::SendVerifyReply -- can't get block hash for unknown block height %d, peer=%d \n " , mnv . nBlockHeight , pnode - > id ) ;
return ;
}
std : : string strMessage = strprintf ( " %s%d%s " , activeMasternode . service . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ) ;
if ( ! darkSendSigner . SignMessage ( strMessage , mnv . vchSig1 , activeMasternode . keyMasternode ) ) {
LogPrintf ( " MasternodeMan::SendVerifyReply -- SignMessage() failed \n " ) ;
return ;
}
std : : string strError ;
if ( ! darkSendSigner . VerifyMessage ( activeMasternode . pubKeyMasternode , mnv . vchSig1 , strMessage , strError ) ) {
LogPrintf ( " MasternodeMan::SendVerifyReply -- VerifyMessage() failed, error: %s \n " , strError ) ;
return ;
}
pnode - > PushMessage ( NetMsgType : : MNVERIFY , mnv ) ;
netfulfilledman . AddFulfilledRequest ( pnode - > addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -reply " ) ;
}
void CMasternodeMan : : ProcessVerifyReply ( CNode * pnode , CMasternodeVerification & mnv )
{
std : : string strError ;
// did we even ask for it? if that's the case we should have matching fulfilled request
if ( ! netfulfilledman . HasFulfilledRequest ( pnode - > addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -request " ) ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyReply -- ERROR: we didn't ask for verification of %s, peer=%d \n " , pnode - > addr . ToString ( ) , pnode - > id ) ;
Misbehaving ( pnode - > id , 20 ) ;
return ;
}
// Received nonce for a known address must match the one we sent
if ( mWeAskedForVerification [ pnode - > addr ] . nonce ! = mnv . nonce ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyReply -- ERROR: wrong nounce: requested=%d, received=%d, peer=%d \n " ,
mWeAskedForVerification [ pnode - > addr ] . nonce , mnv . nonce , pnode - > id ) ;
Misbehaving ( pnode - > id , 20 ) ;
return ;
}
// Received nBlockHeight for a known address must match the one we sent
if ( mWeAskedForVerification [ pnode - > addr ] . nBlockHeight ! = mnv . nBlockHeight ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyReply -- ERROR: wrong nBlockHeight: requested=%d, received=%d, peer=%d \n " ,
mWeAskedForVerification [ pnode - > addr ] . nBlockHeight , mnv . nBlockHeight , pnode - > id ) ;
Misbehaving ( pnode - > id , 20 ) ;
return ;
}
uint256 blockHash ;
if ( ! GetBlockHash ( blockHash , mnv . nBlockHeight ) ) {
// this shouldn't happen...
LogPrintf ( " MasternodeMan::ProcessVerifyReply -- can't get block hash for unknown block height %d, peer=%d \n " , mnv . nBlockHeight , pnode - > id ) ;
return ;
}
// we already verified this address, why node is spamming?
if ( netfulfilledman . HasFulfilledRequest ( pnode - > addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -done " ) ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyReply -- ERROR: already verified %s recently \n " , pnode - > addr . ToString ( ) ) ;
Misbehaving ( pnode - > id , 20 ) ;
return ;
}
{
LOCK ( cs ) ;
CMasternode * prealMasternode = NULL ;
std : : vector < CMasternode * > vpMasternodesToBan ;
std : : vector < CMasternode > : : iterator it = vMasternodes . begin ( ) ;
std : : string strMessage1 = strprintf ( " %s%d%s " , pnode - > addr . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ) ;
while ( it ! = vMasternodes . end ( ) ) {
if ( ( CAddress ) it - > addr = = pnode - > addr ) {
if ( darkSendSigner . VerifyMessage ( it - > pubKeyMasternode , mnv . vchSig1 , strMessage1 , strError ) ) {
// found it!
prealMasternode = & ( * it ) ;
if ( ! it - > IsPoSeVerified ( ) ) {
2016-10-30 21:56:47 +01:00
it - > DecreasePoSeBanScore ( ) ;
2016-10-20 23:11:30 +02:00
}
netfulfilledman . AddFulfilledRequest ( pnode - > addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -done " ) ;
// we can only broadcast it if we are an activated masternode
if ( activeMasternode . vin = = CTxIn ( ) ) continue ;
// update ...
mnv . addr = it - > addr ;
mnv . vin1 = it - > vin ;
mnv . vin2 = activeMasternode . vin ;
std : : string strMessage2 = strprintf ( " %s%d%s%s%s " , mnv . addr . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ,
mnv . vin1 . prevout . ToStringShort ( ) , mnv . vin2 . prevout . ToStringShort ( ) ) ;
// ... and sign it
if ( ! darkSendSigner . SignMessage ( strMessage2 , mnv . vchSig2 , activeMasternode . keyMasternode ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyReply -- SignMessage() failed \n " ) ;
return ;
}
std : : string strError ;
if ( ! darkSendSigner . VerifyMessage ( activeMasternode . pubKeyMasternode , mnv . vchSig2 , strMessage2 , strError ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyReply -- VerifyMessage() failed, error: %s \n " , strError ) ;
return ;
}
mWeAskedForVerification [ pnode - > addr ] = mnv ;
mnv . Relay ( ) ;
} else {
vpMasternodesToBan . push_back ( & ( * it ) ) ;
}
}
+ + it ;
}
// no real masternode found?...
if ( ! prealMasternode ) {
// this should never be the case normally,
// only if someone is trying to game the system in some way or smth like that
LogPrintf ( " CMasternodeMan::ProcessVerifyReply -- ERROR: no real masternode found for addr %s \n " , pnode - > addr . ToString ( ) ) ;
Misbehaving ( pnode - > id , 20 ) ;
return ;
}
LogPrintf ( " CMasternodeMan::ProcessVerifyReply -- verified real masternode %s for addr %s \n " ,
prealMasternode - > vin . prevout . ToStringShort ( ) , pnode - > addr . ToString ( ) ) ;
// increase ban score for everyone else
BOOST_FOREACH ( CMasternode * pmn , vpMasternodesToBan ) {
2016-10-30 21:56:47 +01:00
pmn - > IncreasePoSeBanScore ( ) ;
2016-10-20 23:11:30 +02:00
LogPrint ( " masternode " , " CMasternodeMan::ProcessVerifyBroadcast -- increased PoSe ban score for %s addr %s, new score %d \n " ,
prealMasternode - > vin . prevout . ToStringShort ( ) , pnode - > addr . ToString ( ) , pmn - > nPoSeBanScore ) ;
}
2016-11-30 02:33:47 +01:00
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- PoSe score increased for %d fake masternodes, addr %s \n " ,
2016-10-20 23:11:30 +02:00
( int ) vpMasternodesToBan . size ( ) , pnode - > addr . ToString ( ) ) ;
}
}
void CMasternodeMan : : ProcessVerifyBroadcast ( CNode * pnode , const CMasternodeVerification & mnv )
{
std : : string strError ;
if ( mapSeenMasternodeVerification . find ( mnv . GetHash ( ) ) ! = mapSeenMasternodeVerification . end ( ) ) {
// we already have one
return ;
}
mapSeenMasternodeVerification [ mnv . GetHash ( ) ] = mnv ;
// we don't care about history
if ( mnv . nBlockHeight < pCurrentBlockIndex - > nHeight - MAX_POSE_BLOCKS ) {
LogPrint ( " masternode " , " MasternodeMan::ProcessVerifyBroadcast -- Outdated: current block %d, verification block %d, peer=%d \n " ,
pCurrentBlockIndex - > nHeight , mnv . nBlockHeight , pnode - > id ) ;
return ;
}
if ( mnv . vin1 . prevout = = mnv . vin2 . prevout ) {
LogPrint ( " masternode " , " MasternodeMan::ProcessVerifyBroadcast -- ERROR: same vins %s, peer=%d \n " ,
mnv . vin1 . prevout . ToStringShort ( ) , pnode - > id ) ;
// that was NOT a good idea to cheat and verify itself,
// ban the node we received such message from
Misbehaving ( pnode - > id , 100 ) ;
return ;
}
uint256 blockHash ;
if ( ! GetBlockHash ( blockHash , mnv . nBlockHeight ) ) {
// this shouldn't happen...
LogPrintf ( " MasternodeMan::ProcessVerifyBroadcast -- Can't get block hash for unknown block height %d, peer=%d \n " , mnv . nBlockHeight , pnode - > id ) ;
return ;
}
int nRank = GetMasternodeRank ( mnv . vin2 , mnv . nBlockHeight , MIN_POSE_PROTO_VERSION ) ;
if ( nRank < MAX_POSE_RANK ) {
LogPrint ( " masternode " , " MasternodeMan::ProcessVerifyBroadcast -- Mastrernode is not in top %d, current rank %d, peer=%d \n " ,
( int ) MAX_POSE_RANK , nRank , pnode - > id ) ;
return ;
}
{
LOCK ( cs ) ;
std : : string strMessage1 = strprintf ( " %s%d%s " , mnv . addr . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ) ;
std : : string strMessage2 = strprintf ( " %s%d%s%s%s " , mnv . addr . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ,
mnv . vin1 . prevout . ToStringShort ( ) , mnv . vin2 . prevout . ToStringShort ( ) ) ;
CMasternode * pmn1 = Find ( mnv . vin1 ) ;
if ( ! pmn1 ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode1 %s \n " , mnv . vin1 . prevout . ToStringShort ( ) ) ;
return ;
}
CMasternode * pmn2 = Find ( mnv . vin2 ) ;
if ( ! pmn2 ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode2 %s \n " , mnv . vin2 . prevout . ToStringShort ( ) ) ;
return ;
}
if ( pmn1 - > addr ! = mnv . addr ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- addr %s do not match %s \n " , mnv . addr . ToString ( ) , pnode - > addr . ToString ( ) ) ;
return ;
}
if ( darkSendSigner . VerifyMessage ( pmn1 - > pubKeyMasternode , mnv . vchSig1 , strMessage1 , strError ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode1 failed, error: %s \n " , strError ) ;
return ;
}
if ( darkSendSigner . VerifyMessage ( pmn2 - > pubKeyMasternode , mnv . vchSig2 , strMessage2 , strError ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode2 failed, error: %s \n " , strError ) ;
return ;
}
if ( ! pmn1 - > IsPoSeVerified ( ) ) {
2016-10-30 21:56:47 +01:00
pmn1 - > DecreasePoSeBanScore ( ) ;
2016-10-20 23:11:30 +02:00
}
mnv . Relay ( ) ;
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- verified masternode %s for addr %s \n " ,
pmn1 - > vin . prevout . ToStringShort ( ) , pnode - > addr . ToString ( ) ) ;
// increase ban score for everyone else with the same addr
int nCount = 0 ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
if ( mn . addr ! = mnv . addr | | mn . vin . prevout = = mnv . vin1 . prevout ) continue ;
2016-10-30 21:56:47 +01:00
mn . IncreasePoSeBanScore ( ) ;
2016-10-20 23:11:30 +02:00
nCount + + ;
LogPrint ( " masternode " , " CMasternodeMan::ProcessVerifyBroadcast -- increased PoSe ban score for %s addr %s, new score %d \n " ,
mn . vin . prevout . ToStringShort ( ) , mn . addr . ToString ( ) , mn . nPoSeBanScore ) ;
}
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- PoSe score incresed for %d fake masternodes, addr %s \n " ,
nCount , pnode - > addr . ToString ( ) ) ;
2015-08-09 15:06:54 +02:00
}
2015-02-23 21:01:21 +01:00
}
2015-03-01 00:56:52 +01:00
2015-03-05 00:46:50 +01:00
std : : string CMasternodeMan : : ToString ( ) const
2015-03-01 00:56:52 +01:00
{
std : : ostringstream info ;
2015-03-05 09:10:15 +01:00
info < < " Masternodes: " < < ( int ) vMasternodes . size ( ) < <
" , peers who asked us for Masternode list: " < < ( int ) mAskedUsForMasternodeList . size ( ) < <
" , peers we asked for Masternode list: " < < ( int ) mWeAskedForMasternodeList . size ( ) < <
2015-03-06 18:25:48 +01:00
" , entries in Masternode list we asked for: " < < ( int ) mWeAskedForMasternodeListEntry . size ( ) < <
" , nDsqCount: " < < ( int ) nDsqCount ;
2015-03-01 00:56:52 +01:00
return info . str ( ) ;
}
2016-02-04 20:29:09 +01:00
2016-10-22 18:52:14 +02:00
void CMasternodeMan : : UpdateMasternodeList ( CMasternodeBroadcast mnb )
{
2016-10-17 20:54:28 +02:00
LOCK ( cs ) ;
2016-10-22 18:52:14 +02:00
mapSeenMasternodePing . insert ( std : : make_pair ( mnb . lastPing . GetHash ( ) , mnb . lastPing ) ) ;
2016-12-26 07:44:36 +01:00
mapSeenMasternodeBroadcast . insert ( std : : make_pair ( mnb . GetHash ( ) , std : : make_pair ( GetTime ( ) , mnb ) ) ) ;
2016-03-16 16:30:22 +01:00
2016-10-22 18:52:14 +02:00
LogPrintf ( " CMasternodeMan::UpdateMasternodeList -- masternode=%s addr=%s \n " , mnb . vin . prevout . ToStringShort ( ) , mnb . addr . ToString ( ) ) ;
2016-03-16 16:30:22 +01:00
CMasternode * pmn = Find ( mnb . vin ) ;
2016-10-22 18:52:14 +02:00
if ( pmn = = NULL ) {
2016-03-16 16:30:22 +01:00
CMasternode mn ( mnb ) ;
2016-09-29 22:23:02 +02:00
if ( Add ( mn ) ) {
masternodeSync . AddedMasternodeList ( ) ;
}
2016-12-24 03:49:13 +01:00
} else {
2016-12-26 07:44:36 +01:00
CMasternodeBroadcast mnbOld = mapSeenMasternodeBroadcast [ CMasternodeBroadcast ( * pmn ) . GetHash ( ) ] . second ;
2016-12-24 03:49:13 +01:00
if ( pmn - > UpdateFromNewBroadcast ( mnb ) ) {
masternodeSync . AddedMasternodeList ( ) ;
mapSeenMasternodeBroadcast . erase ( mnbOld . GetHash ( ) ) ;
}
2016-03-16 16:30:22 +01:00
}
}
2016-03-18 00:37:48 +01:00
2017-01-01 18:48:53 +01:00
bool CMasternodeMan : : CheckMnbAndUpdateMasternodeList ( CNode * pfrom , CMasternodeBroadcast mnb , int & nDos )
2016-10-20 23:11:30 +02:00
{
2016-11-28 15:21:50 +01:00
// Need LOCK2 here to ensure consistent locking order because the SimpleCheck call below locks cs_main
LOCK2 ( cs_main , cs ) ;
2016-10-20 23:11:30 +02:00
2016-03-18 00:37:48 +01:00
nDos = 0 ;
2016-10-20 23:11:30 +02:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
2016-03-18 00:37:48 +01:00
2016-12-26 07:44:36 +01:00
uint256 hash = mnb . GetHash ( ) ;
2017-01-01 18:48:53 +01:00
if ( mapSeenMasternodeBroadcast . count ( hash ) & & ! mnb . fRecovery ) { //seen
2016-12-24 03:49:13 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
2016-12-26 07:44:36 +01:00
// less then 2 pings left before this MN goes into non-recoverable state, bump sync timeout
if ( GetTime ( ) - mapSeenMasternodeBroadcast [ hash ] . first > MASTERNODE_NEW_START_REQUIRED_SECONDS - MASTERNODE_MIN_MNP_SECONDS * 2 ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen update \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
mapSeenMasternodeBroadcast [ hash ] . first = GetTime ( ) ;
masternodeSync . AddedMasternodeList ( ) ;
}
2017-01-01 18:48:53 +01:00
// did we ask this node for it?
if ( pfrom & & IsMnbRecoveryRequested ( hash ) & & GetTime ( ) < mMnbRecoveryRequests [ hash ] . first ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request \n " , hash . ToString ( ) ) ;
if ( mMnbRecoveryRequests [ hash ] . second . count ( pfrom - > addr ) ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request, addr=%s \n " , hash . ToString ( ) , pfrom - > addr . ToString ( ) ) ;
// do not allow node to send same mnb multiple times in recovery mode
mMnbRecoveryRequests [ hash ] . second . erase ( pfrom - > addr ) ;
// does it have newer lastPing?
if ( mnb . lastPing . sigTime > mapSeenMasternodeBroadcast [ hash ] . second . lastPing . sigTime ) {
// simulate Check
CMasternode mnTemp = CMasternode ( mnb ) ;
mnTemp . Check ( ) ;
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- mnb=%s seen request, addr=%s, better lastPing: %d min ago, projected mn state: %s \n " , hash . ToString ( ) , pfrom - > addr . ToString ( ) , ( GetTime ( ) - mnb . lastPing . sigTime ) / 60 , mnTemp . GetStateString ( ) ) ;
if ( mnTemp . IsValidStateForAutoStart ( mnTemp . nActiveState ) ) {
// this node thinks it's a good one
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen good \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
mMnbRecoveryGoodReplies [ hash ] . push_back ( mnb ) ;
}
}
}
}
2016-03-18 00:37:48 +01:00
return true ;
}
2016-12-26 07:44:36 +01:00
mapSeenMasternodeBroadcast . insert ( std : : make_pair ( hash , std : : make_pair ( GetTime ( ) , mnb ) ) ) ;
2016-03-18 00:37:48 +01:00
2016-10-20 23:11:30 +02:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s new \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
2016-03-18 00:37:48 +01:00
2016-10-20 23:11:30 +02:00
if ( ! mnb . SimpleCheck ( nDos ) ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- SimpleCheck() failed, masternode=%s \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
2016-03-18 00:37:48 +01:00
return false ;
}
2016-10-20 23:11:30 +02:00
// search Masternode list
CMasternode * pmn = Find ( mnb . vin ) ;
if ( pmn ) {
2016-12-26 07:44:36 +01:00
CMasternodeBroadcast mnbOld = mapSeenMasternodeBroadcast [ CMasternodeBroadcast ( * pmn ) . GetHash ( ) ] . second ;
2016-10-20 23:11:30 +02:00
if ( ! mnb . Update ( pmn , nDos ) ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Update() failed, masternode=%s \n " , mnb . vin . prevout . ToStringShort ( ) ) ;
return false ;
}
2016-12-26 07:44:36 +01:00
if ( hash ! = mnbOld . GetHash ( ) ) {
2016-12-24 03:49:13 +01:00
mapSeenMasternodeBroadcast . erase ( mnbOld . GetHash ( ) ) ;
}
2016-03-18 00:37:48 +01:00
} else {
2016-10-20 23:11:30 +02:00
if ( mnb . CheckOutpoint ( nDos ) ) {
Add ( mnb ) ;
masternodeSync . AddedMasternodeList ( ) ;
// if it matches our Masternode privkey...
if ( fMasterNode & & mnb . pubKeyMasternode = = activeMasternode . pubKeyMasternode ) {
mnb . nPoSeBanScore = - MASTERNODE_POSE_BAN_MAX_SCORE ;
if ( mnb . nProtocolVersion = = PROTOCOL_VERSION ) {
// ... and PROTOCOL_VERSION, then we've been remotely activated ...
LogPrintf ( " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Got NEW Masternode entry: masternode=%s sigTime=%lld addr=%s \n " ,
mnb . vin . prevout . ToStringShort ( ) , mnb . sigTime , mnb . addr . ToString ( ) ) ;
activeMasternode . ManageState ( ) ;
} else {
// ... otherwise we need to reactivate our node, do not add it to the list and do not relay
// but also do not ban the node we get this message from
LogPrintf ( " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- wrong PROTOCOL_VERSION, re-activate your MN: message nProtocolVersion=%d PROTOCOL_VERSION=%d \n " , mnb . nProtocolVersion , PROTOCOL_VERSION ) ;
return false ;
}
}
mnb . Relay ( ) ;
} else {
LogPrintf ( " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Rejected Masternode entry: %s addr=%s \n " , mnb . vin . prevout . ToStringShort ( ) , mnb . addr . ToString ( ) ) ;
return false ;
}
2016-03-18 00:37:48 +01:00
}
return true ;
}
2016-09-11 22:22:37 +02:00
2016-11-28 15:21:50 +01:00
void CMasternodeMan : : UpdateLastPaid ( )
2016-10-20 23:11:30 +02:00
{
2016-10-17 20:54:28 +02:00
LOCK ( cs ) ;
2016-10-20 23:11:30 +02:00
2016-09-11 22:22:37 +02:00
if ( fLiteMode ) return ;
2016-11-28 15:21:50 +01:00
if ( ! pCurrentBlockIndex ) return ;
2016-09-11 22:22:37 +02:00
static bool IsFirstRun = true ;
// Do full scan on first run or if we are not a masternode
// (MNs should update this info on every block, so limited scan should be enough for them)
2016-10-20 23:11:30 +02:00
int nMaxBlocksToScanBack = ( IsFirstRun | | ! fMasterNode ) ? mnpayments . GetStorageLimit ( ) : LAST_PAID_SCAN_BLOCKS ;
2016-09-11 22:22:37 +02:00
// LogPrint("mnpayments", "CMasternodeMan::UpdateLastPaid -- nHeight=%d, nMaxBlocksToScanBack=%d, IsFirstRun=%s\n",
2016-11-28 15:21:50 +01:00
// pCurrentBlockIndex->nHeight, nMaxBlocksToScanBack, IsFirstRun ? "true" : "false");
2016-09-11 22:22:37 +02:00
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
2016-11-28 15:21:50 +01:00
mn . UpdateLastPaid ( pCurrentBlockIndex , nMaxBlocksToScanBack ) ;
2016-09-11 22:22:37 +02:00
}
// every time is like the first time if winners list is not synced
IsFirstRun = ! masternodeSync . IsWinnersListSynced ( ) ;
}
2016-10-17 20:54:28 +02:00
2016-11-13 18:52:34 +01:00
void CMasternodeMan : : CheckAndRebuildMasternodeIndex ( )
{
LOCK ( cs ) ;
if ( GetTime ( ) - nLastIndexRebuildTime < MIN_INDEX_REBUILD_TIME ) {
return ;
}
if ( indexMasternodes . GetSize ( ) < = MAX_EXPECTED_INDEX_SIZE ) {
return ;
}
if ( indexMasternodes . GetSize ( ) < = int ( vMasternodes . size ( ) ) ) {
return ;
}
indexMasternodesOld = indexMasternodes ;
indexMasternodes . Clear ( ) ;
for ( size_t i = 0 ; i < vMasternodes . size ( ) ; + + i ) {
indexMasternodes . AddMasternodeVIN ( vMasternodes [ i ] . vin ) ;
}
fIndexRebuilt = true ;
nLastIndexRebuildTime = GetTime ( ) ;
}
2016-10-17 20:54:28 +02:00
void CMasternodeMan : : UpdateWatchdogVoteTime ( const CTxIn & vin )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
return ;
}
pMN - > UpdateWatchdogVoteTime ( ) ;
nLastWatchdogVoteTime = GetTime ( ) ;
}
bool CMasternodeMan : : IsWatchdogActive ( )
{
LOCK ( cs ) ;
// Check if any masternodes have voted recently, otherwise return false
return ( GetTime ( ) - nLastWatchdogVoteTime ) < = MASTERNODE_WATCHDOG_MAX_SECONDS ;
}
void CMasternodeMan : : AddGovernanceVote ( const CTxIn & vin , uint256 nGovernanceObjectHash )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
return ;
}
pMN - > AddGovernanceVote ( nGovernanceObjectHash ) ;
}
void CMasternodeMan : : RemoveGovernanceObject ( uint256 nGovernanceObjectHash )
{
LOCK ( cs ) ;
BOOST_FOREACH ( CMasternode & mn , vMasternodes ) {
mn . RemoveGovernanceObject ( nGovernanceObjectHash ) ;
}
}
void CMasternodeMan : : CheckMasternode ( const CTxIn & vin , bool fForce )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
return ;
}
pMN - > Check ( fForce ) ;
}
void CMasternodeMan : : CheckMasternode ( const CPubKey & pubKeyMasternode , bool fForce )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( pubKeyMasternode ) ;
if ( ! pMN ) {
return ;
}
pMN - > Check ( fForce ) ;
}
int CMasternodeMan : : GetMasternodeState ( const CTxIn & vin )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
2016-12-24 03:49:13 +01:00
return CMasternode : : MASTERNODE_NEW_START_REQUIRED ;
2016-10-17 20:54:28 +02:00
}
return pMN - > nActiveState ;
}
int CMasternodeMan : : GetMasternodeState ( const CPubKey & pubKeyMasternode )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( pubKeyMasternode ) ;
if ( ! pMN ) {
2016-12-24 03:49:13 +01:00
return CMasternode : : MASTERNODE_NEW_START_REQUIRED ;
2016-10-17 20:54:28 +02:00
}
return pMN - > nActiveState ;
}
bool CMasternodeMan : : IsMasternodePingedWithin ( const CTxIn & vin , int nSeconds , int64_t nTimeToCheckAt )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
return false ;
}
return pMN - > IsPingedWithin ( nSeconds , nTimeToCheckAt ) ;
}
void CMasternodeMan : : SetMasternodeLastPing ( const CTxIn & vin , const CMasternodePing & mnp )
{
LOCK ( cs ) ;
CMasternode * pMN = Find ( vin ) ;
if ( ! pMN ) {
return ;
}
pMN - > lastPing = mnp ;
mapSeenMasternodePing . insert ( std : : make_pair ( mnp . GetHash ( ) , mnp ) ) ;
CMasternodeBroadcast mnb ( * pMN ) ;
uint256 hash = mnb . GetHash ( ) ;
if ( mapSeenMasternodeBroadcast . count ( hash ) ) {
2016-12-26 07:44:36 +01:00
mapSeenMasternodeBroadcast [ hash ] . second . lastPing = mnp ;
2016-10-17 20:54:28 +02:00
}
}
2016-10-20 23:11:30 +02:00
void CMasternodeMan : : UpdatedBlockTip ( const CBlockIndex * pindex )
{
pCurrentBlockIndex = pindex ;
LogPrint ( " masternode " , " CMasternodeMan::UpdatedBlockTip -- pCurrentBlockIndex->nHeight=%d \n " , pCurrentBlockIndex - > nHeight ) ;
CheckSameAddr ( ) ;
if ( fMasterNode ) {
DoFullVerificationStep ( ) ;
// normal wallet does not need to update this every block, doing update on rpc call should be enough
2016-11-28 15:21:50 +01:00
UpdateLastPaid ( ) ;
2016-10-20 23:11:30 +02:00
}
}
2016-11-13 18:52:34 +01:00
void CMasternodeMan : : NotifyMasternodeUpdates ( )
{
// Avoid double locking
bool fMasternodesAddedLocal = false ;
bool fMasternodesRemovedLocal = false ;
{
LOCK ( cs ) ;
fMasternodesAddedLocal = fMasternodesAdded ;
fMasternodesRemovedLocal = fMasternodesRemoved ;
}
if ( fMasternodesAddedLocal ) {
2016-11-12 02:51:45 +01:00
governance . CheckMasternodeOrphanObjects ( ) ;
2016-11-13 18:52:34 +01:00
governance . CheckMasternodeOrphanVotes ( ) ;
}
if ( fMasternodesRemovedLocal ) {
governance . UpdateCachesAndClean ( ) ;
}
LOCK ( cs ) ;
fMasternodesAdded = false ;
fMasternodesRemoved = false ;
}