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"
2018-03-15 10:21:12 +01:00
# include "alert.h"
2018-03-15 20:08:11 +01:00
# include "clientversion.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"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2016-10-20 23:11:30 +02:00
# include "netfulfilledman.h"
2016-11-25 20:01:56 +01:00
# include "netmessagemaker.h"
2017-12-01 19:53:34 +01:00
# ifdef ENABLE_WALLET
2017-05-05 13:26:27 +02:00
# include "privatesend-client.h"
2017-12-01 19:53:34 +01:00
# endif // ENABLE_WALLET
# include "script/standard.h"
2018-03-15 20:08:11 +01:00
# include "ui_interface.h"
2015-02-23 21:01:21 +01:00
# include "util.h"
2018-03-15 10:21:12 +01:00
# include "warnings.h"
2015-02-23 21:01:21 +01:00
/** Masternode manager */
CMasternodeMan mnodeman ;
2017-09-14 15:58:29 +02:00
const std : : string CMasternodeMan : : SERIALIZATION_VERSION_STRING = " CMasternodeMan-Version-7 " ;
2018-03-21 12:08:35 +01:00
const int CMasternodeMan : : LAST_PAID_SCAN_BLOCKS = 100 ;
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
{
2018-02-06 12:09:33 +01:00
bool operator ( ) ( const std : : pair < int , const CMasternode * > & t1 ,
const std : : pair < int , const CMasternode * > & t2 ) const
2015-02-23 21:01:21 +01:00
{
2018-02-15 08:29:44 +01:00
return ( t1 . first ! = t2 . first ) ? ( t1 . first < t2 . first ) : ( t1 . second - > outpoint < t2 . second - > outpoint ) ;
2015-07-30 18:00:28 +02:00
}
} ;
struct CompareScoreMN
2015-03-14 19:34:51 +01:00
{
2018-02-06 12:09:33 +01:00
bool operator ( ) ( const std : : pair < arith_uint256 , const CMasternode * > & t1 ,
const std : : pair < arith_uint256 , const CMasternode * > & t2 ) const
2015-03-14 19:34:51 +01:00
{
2018-02-15 08:29:44 +01:00
return ( t1 . first ! = t2 . first ) ? ( t1 . first < t2 . first ) : ( t1 . second - > outpoint < t2 . second - > outpoint ) ;
2015-03-14 19:34:51 +01:00
}
} ;
2015-02-23 21:01:21 +01:00
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
2018-02-21 17:32:08 +01:00
CMasternodeMan : : CMasternodeMan ( ) :
cs ( ) ,
mapMasternodes ( ) ,
mAskedUsForMasternodeList ( ) ,
mWeAskedForMasternodeList ( ) ,
mWeAskedForMasternodeListEntry ( ) ,
mWeAskedForVerification ( ) ,
mMnbRecoveryRequests ( ) ,
mMnbRecoveryGoodReplies ( ) ,
listScheduledMnbRequestConnections ( ) ,
fMasternodesAdded ( false ) ,
fMasternodesRemoved ( false ) ,
vecDirtyGovernanceObjectHashes ( ) ,
2018-02-25 06:33:27 +01:00
nLastSentinelPingTime ( 0 ) ,
2018-02-21 17:32:08 +01:00
mapSeenMasternodeBroadcast ( ) ,
mapSeenMasternodePing ( ) ,
nDsqCount ( 0 )
2016-11-13 18:52:34 +01:00
{ }
2015-02-23 21:01:21 +01:00
bool CMasternodeMan : : Add ( CMasternode & mn )
{
LOCK ( cs ) ;
2018-02-15 08:29:44 +01:00
if ( Has ( mn . outpoint ) ) return false ;
2015-02-23 21:01:21 +01:00
2017-08-25 14:57:19 +02:00
LogPrint ( " masternode " , " CMasternodeMan::Add -- Adding new Masternode: addr=%s, %i now \n " , mn . addr . ToString ( ) , size ( ) + 1 ) ;
2018-02-15 08:29:44 +01:00
mapMasternodes [ mn . outpoint ] = mn ;
2017-08-25 14:57:19 +02:00
fMasternodesAdded = true ;
return true ;
2015-02-23 21:01:21 +01:00
}
2017-09-19 16:51:38 +02:00
void CMasternodeMan : : AskForMN ( CNode * pnode , const COutPoint & outpoint , CConnman & connman )
2015-08-07 05:07:40 +02:00
{
2016-10-22 18:52:14 +02:00
if ( ! pnode ) return ;
2016-11-25 20:01:56 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
2016-12-21 00:55:55 +01:00
LOCK ( cs ) ;
2015-08-07 05:07:40 +02:00
2018-03-08 13:16:52 +01:00
CService addrSquashed = Params ( ) . AllowMultiplePorts ( ) ? ( CService ) pnode - > addr : CService ( pnode - > addr , 0 ) ;
auto it1 = mWeAskedForMasternodeListEntry . find ( outpoint ) ;
2016-12-21 00:55:55 +01:00
if ( it1 ! = mWeAskedForMasternodeListEntry . end ( ) ) {
2018-03-08 13:16:52 +01:00
auto it2 = it1 - > second . find ( addrSquashed ) ;
2016-12-21 00:55:55 +01:00
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
2018-03-08 13:16:52 +01:00
LogPrintf ( " CMasternodeMan::AskForMN -- Asking same peer %s for missing masternode entry again: %s \n " , addrSquashed . ToString ( ) , outpoint . ToStringShort ( ) ) ;
2016-12-21 00:55:55 +01:00
} else {
// we already asked for this outpoint but not this node
2018-03-08 13:16:52 +01:00
LogPrintf ( " CMasternodeMan::AskForMN -- Asking new peer %s for missing masternode entry: %s \n " , addrSquashed . ToString ( ) , outpoint . ToStringShort ( ) ) ;
2016-12-21 00:55:55 +01:00
}
} else {
// we never asked any node for this outpoint
2018-03-08 13:16:52 +01:00
LogPrintf ( " CMasternodeMan::AskForMN -- Asking peer %s for missing masternode entry for the first time: %s \n " , addrSquashed . ToString ( ) , outpoint . ToStringShort ( ) ) ;
2016-12-21 00:55:55 +01:00
}
2018-03-08 13:16:52 +01:00
mWeAskedForMasternodeListEntry [ outpoint ] [ addrSquashed ] = GetTime ( ) + DSEG_UPDATE_SECONDS ;
2015-08-07 05:07:40 +02:00
2018-02-15 08:29:44 +01:00
if ( pnode - > GetSendVersion ( ) = = 70208 ) {
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : DSEG , CTxIn ( outpoint ) ) ) ;
} else {
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : DSEG , outpoint ) ) ;
}
2017-09-11 16:13:48 +02:00
}
bool CMasternodeMan : : AllowMixing ( const COutPoint & outpoint )
{
LOCK ( cs ) ;
CMasternode * pmn = Find ( outpoint ) ;
if ( ! pmn ) {
return false ;
}
nDsqCount + + ;
pmn - > nLastDsq = nDsqCount ;
pmn - > fAllowMixingTx = true ;
return true ;
}
bool CMasternodeMan : : DisallowMixing ( const COutPoint & outpoint )
{
LOCK ( cs ) ;
CMasternode * pmn = Find ( outpoint ) ;
if ( ! pmn ) {
return false ;
}
pmn - > fAllowMixingTx = false ;
return true ;
2015-08-07 05:07:40 +02:00
}
2017-09-14 13:41:40 +02:00
bool CMasternodeMan : : PoSeBan ( const COutPoint & outpoint )
{
LOCK ( cs ) ;
CMasternode * pmn = Find ( outpoint ) ;
if ( ! pmn ) {
return false ;
}
pmn - > PoSeBan ( ) ;
return true ;
}
2015-02-23 21:01:21 +01:00
void CMasternodeMan : : Check ( )
{
2018-03-09 15:15:48 +01:00
LOCK2 ( cs_main , cs ) ;
2015-02-23 21:01:21 +01:00
2018-02-25 06:33:27 +01:00
LogPrint ( " masternode " , " CMasternodeMan::Check -- nLastSentinelPingTime=%d, IsSentinelPingActive()=%d \n " , nLastSentinelPingTime , IsSentinelPingActive ( ) ) ;
2016-10-17 20:54:28 +02:00
2017-09-11 16:13:48 +02:00
for ( auto & mnpair : mapMasternodes ) {
2018-02-21 17:32:08 +01:00
// NOTE: internally it checks only every MASTERNODE_CHECK_SECONDS seconds
// since the last time, so expect some MNs to skip this
2017-09-11 16:13:48 +02:00
mnpair . second . Check ( ) ;
2015-06-24 18:41:03 +02:00
}
2015-02-23 21:01:21 +01:00
}
2017-09-19 16:51:38 +02:00
void CMasternodeMan : : CheckAndRemove ( CConnman & connman )
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
2017-01-21 20:03:55 +01:00
// in CheckMnbAndUpdateMasternodeList()
2017-01-01 18:48:53 +01:00
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
2017-09-14 15:58:29 +02:00
rank_pair_vec_t vecMasternodeRanks ;
2017-01-31 16:29:27 +01:00
// ask for up to MNB_RECOVERY_MAX_ASK_ENTRIES masternode entries at a time
int nAskForMnbRecovery = MNB_RECOVERY_MAX_ASK_ENTRIES ;
2017-09-11 16:13:48 +02:00
std : : map < COutPoint , CMasternode > : : iterator it = mapMasternodes . begin ( ) ;
while ( it ! = mapMasternodes . end ( ) ) {
CMasternodeBroadcast mnb = CMasternodeBroadcast ( it - > second ) ;
2017-01-01 18:48:53 +01:00
uint256 hash = mnb . GetHash ( ) ;
2016-12-24 03:49:13 +01:00
// If collateral was spent ...
2017-09-11 16:13:48 +02:00
if ( it - > second . IsOutpointSpent ( ) ) {
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- Removing Masternode: %s addr=%s %i now \n " , it - > second . GetStateString ( ) , it - > second . 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 ) ;
2017-09-11 16:13:48 +02:00
mWeAskedForMasternodeListEntry . erase ( it - > first ) ;
2016-11-13 18:52:34 +01:00
// and finally remove it from the list
2017-09-11 16:13:48 +02:00
it - > second . FlagGovernanceItemsAsDirty ( ) ;
mapMasternodes . erase ( it + + ) ;
2016-11-13 18:52:34 +01:00
fMasternodesRemoved = true ;
} else {
2017-08-25 14:57:05 +02:00
bool fAsk = ( nAskForMnbRecovery > 0 ) & &
2017-01-14 23:29:08 +01:00
masternodeSync . IsSynced ( ) & &
2017-09-11 16:13:48 +02:00
it - > second . IsNewStartRequired ( ) & &
2018-03-19 14:08:32 +01:00
! IsMnbRecoveryRequested ( hash ) & &
! IsArgSet ( " -connect " ) ;
2017-01-14 23:29:08 +01:00
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
2018-03-08 13:16:52 +01:00
std : : set < CService > setRequested ;
2017-01-01 18:48:53 +01:00
// calulate only once and only when it's needed
if ( vecMasternodeRanks . empty ( ) ) {
2017-08-25 14:57:05 +02:00
int nRandomBlockHeight = GetRandInt ( nCachedBlockHeight ) ;
2017-09-14 15:58:29 +02:00
GetMasternodeRanks ( vecMasternodeRanks , nRandomBlockHeight ) ;
2017-01-01 18:48:53 +01:00
}
2017-01-31 16:29:27 +01:00
bool fAskedForMnbRecovery = false ;
// ask first MNB_RECOVERY_QUORUM_TOTAL masternodes we can connect to and we haven't asked recently
2017-01-01 18:48:53 +01:00
for ( int i = 0 ; setRequested . size ( ) < MNB_RECOVERY_QUORUM_TOTAL & & i < ( int ) vecMasternodeRanks . size ( ) ; i + + ) {
// avoid banning
2017-09-11 16:13:48 +02:00
if ( mWeAskedForMasternodeListEntry . count ( it - > first ) & & mWeAskedForMasternodeListEntry [ it - > first ] . count ( vecMasternodeRanks [ i ] . second . addr ) ) continue ;
2017-01-01 18:48:53 +01:00
// didn't ask recently, ok to ask now
CService addr = vecMasternodeRanks [ i ] . second . addr ;
2017-01-21 20:03:55 +01:00
setRequested . insert ( addr ) ;
listScheduledMnbRequestConnections . push_back ( std : : make_pair ( addr , hash ) ) ;
fAskedForMnbRecovery = true ;
2017-01-01 18:48:53 +01:00
}
2017-01-31 16:29:27 +01:00
if ( fAskedForMnbRecovery ) {
2017-09-11 16:13:48 +02:00
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- Recovery initiated, masternode=%s \n " , it - > first . ToStringShort ( ) ) ;
2017-01-31 16:29:27 +01:00
nAskForMnbRecovery - - ;
}
2017-01-01 18:48:53 +01:00
// 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
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- reprocessing mnb, masternode=%s \n " , itMnbReplies - > second [ 0 ] . outpoint . ToStringShort ( ) ) ;
2017-01-01 18:48:53 +01:00
// mapSeenMasternodeBroadcast.erase(itMnbReplies->first);
int nDos ;
itMnbReplies - > second [ 0 ] . fRecovery = true ;
2017-09-19 16:51:38 +02:00
CheckMnbAndUpdateMasternodeList ( NULL , itMnbReplies - > second [ 0 ] , nDos , connman ) ;
2017-01-01 18:48:53 +01:00
}
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckAndRemove -- removing mnb recovery reply, masternode=%s, size=%d \n " , itMnbReplies - > second [ 0 ] . outpoint . ToStringShort ( ) , ( int ) itMnbReplies - > second . size ( ) ) ;
2017-01-01 18:48:53 +01:00
mMnbRecoveryGoodReplies . erase ( itMnbReplies + + ) ;
} else {
+ + itMnbReplies ;
}
}
}
{
// no need for cm_main below
LOCK ( cs ) ;
2018-03-08 13:16:52 +01:00
auto itMnbRequest = mMnbRecoveryRequests . begin ( ) ;
2017-01-01 18:48:53 +01:00
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
2018-03-08 13:16:52 +01:00
auto it1 = mAskedUsForMasternodeList . begin ( ) ;
2016-11-13 18:52:34 +01:00
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
2018-03-08 13:16:52 +01:00
auto it2 = mWeAskedForMasternodeListEntry . begin ( ) ;
2016-11-13 18:52:34 +01:00
while ( it2 ! = mWeAskedForMasternodeListEntry . end ( ) ) {
2018-03-08 13:16:52 +01:00
auto it3 = it2 - > second . begin ( ) ;
2016-12-21 00:55:55 +01:00
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
2018-03-08 13:16:52 +01:00
auto it3 = mWeAskedForVerification . begin ( ) ;
2016-12-24 03:49:13 +01:00
while ( it3 ! = mWeAskedForVerification . end ( ) ) {
2017-08-25 14:57:05 +02:00
if ( it3 - > second . nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS ) {
2016-12-24 03:49:13 +01:00
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 ( ) ) {
2017-08-25 14:57:05 +02:00
if ( ( * itv2 ) . second . nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS ) {
2016-11-13 18:52:34 +01:00
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 ( ) ) ;
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 ) {
2017-09-19 16:51:38 +02:00
NotifyMasternodeUpdates ( connman ) ;
2016-11-13 18:52:34 +01:00
}
2015-02-23 21:01:21 +01:00
}
2015-03-01 01:04:17 +01:00
void CMasternodeMan : : Clear ( )
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
mapMasternodes . clear ( ) ;
2015-03-01 01:04:17 +01:00
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 ;
2018-02-25 06:33:27 +01:00
nLastSentinelPingTime = 0 ;
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
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes ) {
2017-09-11 16:13:48 +02:00
if ( mnpair . second . nProtocolVersion < nProtocolVersion ) continue ;
2016-10-22 18:52:14 +02:00
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
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes ) {
2017-09-11 16:13:48 +02:00
if ( mnpair . second . nProtocolVersion < nProtocolVersion | | ! mnpair . second . IsEnabled ( ) ) continue ;
2016-10-22 18:52:14 +02:00
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
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes )
2017-09-11 16:13:48 +02:00
if ( ( nNetworkType = = NET_IPV4 & & mnpair . second . addr . IsIPv4 ( ) ) | |
( nNetworkType = = NET_TOR & & mnpair . second . addr . IsTor ( ) ) | |
( nNetworkType = = NET_IPV6 & & mnpair . second . addr . IsIPv6 ( ) ) ) {
2016-08-12 07:58:55 +02:00
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
2017-09-19 16:51:38 +02:00
void CMasternodeMan : : DsegUpdate ( CNode * pnode , CConnman & connman )
2015-02-26 00:21:28 +01:00
{
2016-11-25 20:01:56 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
2015-02-27 00:12:43 +01:00
LOCK ( cs ) ;
2018-03-08 13:16:52 +01:00
CService addrSquashed = Params ( ) . AllowMultiplePorts ( ) ? ( CService ) pnode - > addr : CService ( pnode - > addr , 0 ) ;
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 ( ) ) ) {
2018-03-08 13:16:52 +01:00
auto it = mWeAskedForMasternodeList . find ( addrSquashed ) ;
2016-10-22 18:52:14 +02:00
if ( it ! = mWeAskedForMasternodeList . end ( ) & & GetTime ( ) < ( * it ) . second ) {
2018-03-08 13:16:52 +01:00
LogPrintf ( " CMasternodeMan::DsegUpdate -- we already asked %s for the list; skipping... \n " , addrSquashed . ToString ( ) ) ;
2016-10-22 18:52:14 +02:00
return ;
2015-07-02 17:07:30 +02:00
}
2015-02-26 00:21:28 +01:00
}
}
2017-07-21 17:21:09 +02:00
2018-02-15 08:29:44 +01:00
if ( pnode - > GetSendVersion ( ) = = 70208 ) {
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : DSEG , CTxIn ( ) ) ) ;
} else {
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : DSEG , COutPoint ( ) ) ) ;
}
2016-10-20 23:11:30 +02:00
int64_t askAgain = GetTime ( ) + DSEG_UPDATE_SECONDS ;
2018-03-08 13:16:52 +01:00
mWeAskedForMasternodeList [ addrSquashed ] = 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
}
2017-09-11 16:13:48 +02:00
CMasternode * CMasternodeMan : : Find ( const COutPoint & outpoint )
2015-05-28 19:45:31 +02:00
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
auto it = mapMasternodes . find ( outpoint ) ;
return it = = mapMasternodes . end ( ) ? NULL : & ( it - > second ) ;
2015-05-28 19:45:31 +02:00
}
2017-09-11 16:13:48 +02:00
bool CMasternodeMan : : Get ( const COutPoint & outpoint , CMasternode & masternodeRet )
2016-09-05 01:44:10 +02:00
{
// Theses mutexes are recursive so double locking by the same thread is safe.
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
auto it = mapMasternodes . find ( outpoint ) ;
if ( it = = mapMasternodes . end ( ) ) {
2016-09-05 01:44:10 +02:00
return false ;
}
2017-09-11 16:13:48 +02:00
masternodeRet = it - > second ;
2016-09-05 01:44:10 +02:00
return true ;
}
2017-09-11 16:13:48 +02:00
bool CMasternodeMan : : GetMasternodeInfo ( const COutPoint & outpoint , masternode_info_t & mnInfoRet )
2016-09-15 08:49:24 +02:00
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
auto it = mapMasternodes . find ( outpoint ) ;
if ( it = = mapMasternodes . end ( ) ) {
2016-09-15 08:49:24 +02:00
return false ;
}
2017-09-11 16:13:48 +02:00
mnInfoRet = it - > second . GetInfo ( ) ;
2016-09-15 08:49:24 +02:00
return true ;
}
2017-09-11 16:13:48 +02:00
bool CMasternodeMan : : GetMasternodeInfo ( const CPubKey & pubKeyMasternode , masternode_info_t & mnInfoRet )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes ) {
2017-09-11 16:13:48 +02:00
if ( mnpair . second . pubKeyMasternode = = pubKeyMasternode ) {
mnInfoRet = mnpair . second . GetInfo ( ) ;
return true ;
}
2016-10-17 20:54:28 +02:00
}
2017-09-11 16:13:48 +02:00
return false ;
2016-10-17 20:54:28 +02:00
}
2017-09-20 22:31:23 +02:00
bool CMasternodeMan : : GetMasternodeInfo ( const CScript & payee , masternode_info_t & mnInfoRet )
{
LOCK ( cs ) ;
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes ) {
2017-09-20 22:31:23 +02:00
CScript scriptCollateralAddress = GetScriptForDestination ( mnpair . second . pubKeyCollateralAddress . GetID ( ) ) ;
if ( scriptCollateralAddress = = payee ) {
mnInfoRet = mnpair . second . GetInfo ( ) ;
return true ;
}
}
return false ;
}
2017-09-11 16:13:48 +02:00
bool CMasternodeMan : : Has ( const COutPoint & outpoint )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
return mapMasternodes . find ( outpoint ) ! = mapMasternodes . end ( ) ;
2016-10-17 20:54:28 +02:00
}
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
//
2017-10-17 18:40:25 +02:00
bool CMasternodeMan : : GetNextMasternodeInQueueForPayment ( bool fFilterSigTime , int & nCountRet , masternode_info_t & mnInfoRet )
2016-11-28 15:21:50 +01:00
{
2017-10-17 18:40:25 +02:00
return GetNextMasternodeInQueueForPayment ( nCachedBlockHeight , fFilterSigTime , nCountRet , mnInfoRet ) ;
2016-11-28 15:21:50 +01:00
}
2017-10-17 18:40:25 +02:00
bool CMasternodeMan : : GetNextMasternodeInQueueForPayment ( int nBlockHeight , bool fFilterSigTime , int & nCountRet , masternode_info_t & mnInfoRet )
2015-02-26 00:21:28 +01:00
{
2017-09-11 16:13:48 +02:00
mnInfoRet = masternode_info_t ( ) ;
nCountRet = 0 ;
2017-08-25 14:57:05 +02:00
if ( ! masternodeSync . IsWinnersListSynced ( ) ) {
// without winner list we can't reliably find the next winner anyway
2017-09-11 16:13:48 +02:00
return false ;
2017-08-25 14:57:05 +02: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
2018-02-06 12:09:33 +01:00
std : : vector < std : : pair < int , const 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
2017-09-14 15:58:29 +02:00
int nMnCount = CountMasternodes ( ) ;
2017-09-11 16:13:48 +02:00
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes ) {
2017-09-11 16:13:48 +02:00
if ( ! mnpair . second . IsValidForPayment ( ) ) continue ;
2015-02-26 00:21:28 +01:00
2017-07-03 15:14:07 +02:00
//check protocol version
2017-09-11 16:13:48 +02:00
if ( mnpair . second . 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
2017-10-17 18:40:25 +02:00
if ( mnpayments . IsScheduled ( mnpair . second , 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
2017-09-11 16:13:48 +02:00
if ( fFilterSigTime & & mnpair . second . 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
2017-09-11 16:13:48 +02:00
if ( GetUTXOConfirmations ( mnpair . first ) < nMnCount ) continue ;
2015-05-30 19:27:51 +02:00
2017-09-11 16:13:48 +02:00
vecMasternodeLastPaid . push_back ( std : : make_pair ( mnpair . second . GetLastPaidBlock ( ) , & mnpair . second ) ) ;
2015-02-26 00:21:28 +01:00
}
2017-09-11 16:13:48 +02:00
nCountRet = ( int ) vecMasternodeLastPaid . size ( ) ;
2015-08-20 18:27:34 +02:00
2015-08-20 17:36:44 +02:00
//when the network is in the process of upgrading, don't penalize nodes that recently restarted
2017-09-11 16:13:48 +02:00
if ( fFilterSigTime & & nCountRet < nMnCount / 3 )
2017-10-17 18:40:25 +02:00
return GetNextMasternodeInQueueForPayment ( nBlockHeight , false , nCountRet , mnInfoRet ) ;
2015-08-20 17:36:44 +02:00
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 ) ;
2017-09-11 16:13:48 +02:00
return false ;
2016-10-13 11:45:18 +02:00
}
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 ;
2018-02-06 12:09:33 +01:00
const CMasternode * pBestMasternode = NULL ;
for ( const auto & 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
}
2017-09-11 16:13:48 +02:00
if ( pBestMasternode ) {
mnInfoRet = pBestMasternode - > GetInfo ( ) ;
}
return mnInfoRet . fInfoValid ;
2015-02-26 00:21:28 +01:00
}
2017-09-11 16:13:48 +02:00
masternode_info_t CMasternodeMan : : FindRandomNotInVec ( const std : : vector < COutPoint > & 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 ) ;
2017-05-05 13:26:27 +02:00
if ( nCountNotExcluded < 1 ) return masternode_info_t ( ) ;
2015-02-26 00:21:28 +01:00
2016-09-20 00:27:36 +02:00
// fill a vector of pointers
2018-02-06 12:09:33 +01:00
std : : vector < const CMasternode * > vpMasternodesShuffled ;
for ( const auto & mnpair : mapMasternodes ) {
2017-09-11 16:13:48 +02:00
vpMasternodesShuffled . push_back ( & mnpair . second ) ;
2016-09-20 00:27:36 +02:00
}
2018-01-12 16:37:39 +01:00
FastRandomContext insecure_rand ;
2016-09-20 00:27:36 +02:00
// shuffle pointers
2018-01-12 16:37:39 +01:00
std : : random_shuffle ( vpMasternodesShuffled . begin ( ) , vpMasternodesShuffled . end ( ) , insecure_rand ) ;
2016-07-29 07:29:41 +02:00
bool fExclude ;
2016-09-20 00:27:36 +02:00
// loop through
2018-02-06 12:09:33 +01:00
for ( const auto & pmn : vpMasternodesShuffled ) {
2016-09-20 00:27:36 +02:00
if ( pmn - > nProtocolVersion < nProtocolVersion | | ! pmn - > IsEnabled ( ) ) continue ;
2016-07-29 07:29:41 +02:00
fExclude = false ;
2018-02-06 12:09:33 +01:00
for ( const auto & outpointToExclude : vecToExclude ) {
2018-02-15 08:29:44 +01:00
if ( pmn - > outpoint = = outpointToExclude ) {
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
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::FindRandomNotInVec -- found, masternode=%s \n " , pmn - > outpoint . ToStringShort ( ) ) ;
2017-05-05 13:26:27 +02:00
return pmn - > GetInfo ( ) ;
2015-07-29 17:11:43 +02:00
}
2016-09-20 00:27:36 +02:00
LogPrint ( " masternode " , " CMasternodeMan::FindRandomNotInVec -- failed \n " ) ;
2017-05-05 13:26:27 +02:00
return masternode_info_t ( ) ;
2015-02-26 00:21:28 +01:00
}
2017-09-14 15:58:29 +02:00
bool CMasternodeMan : : GetMasternodeScores ( const uint256 & nBlockHash , CMasternodeMan : : score_pair_vec_t & vecMasternodeScoresRet , int nMinProtocol )
2015-02-23 21:01:21 +01:00
{
2017-09-14 15:58:29 +02:00
vecMasternodeScoresRet . clear ( ) ;
2015-02-23 21:01:21 +01:00
2017-09-14 15:58:29 +02:00
if ( ! masternodeSync . IsMasternodeListSynced ( ) )
return false ;
2015-03-23 13:59:22 +01:00
2017-09-14 15:58:29 +02:00
AssertLockHeld ( cs ) ;
if ( mapMasternodes . empty ( ) )
return false ;
2016-09-20 00:27:36 +02:00
2017-09-14 15:58:29 +02:00
// calculate scores
2018-02-06 12:09:33 +01:00
for ( const auto & mnpair : mapMasternodes ) {
2017-09-14 15:58:29 +02:00
if ( mnpair . second . nProtocolVersion > = nMinProtocol ) {
vecMasternodeScoresRet . push_back ( std : : make_pair ( mnpair . second . CalculateScore ( nBlockHash ) , & mnpair . second ) ) ;
2016-11-23 16:30:36 +01:00
}
2017-09-14 15:58:29 +02:00
}
sort ( vecMasternodeScoresRet . rbegin ( ) , vecMasternodeScoresRet . rend ( ) , CompareScoreMN ( ) ) ;
return ! vecMasternodeScoresRet . empty ( ) ;
}
bool CMasternodeMan : : GetMasternodeRank ( const COutPoint & outpoint , int & nRankRet , int nBlockHeight , int nMinProtocol )
{
nRankRet = - 1 ;
if ( ! masternodeSync . IsMasternodeListSynced ( ) )
return false ;
2015-02-23 21:01:21 +01:00
2017-09-14 15:58:29 +02:00
// make sure we know about this block
uint256 nBlockHash = uint256 ( ) ;
if ( ! GetBlockHash ( nBlockHash , nBlockHeight ) ) {
LogPrintf ( " CMasternodeMan::%s -- ERROR: GetBlockHash() failed at nBlockHeight %d \n " , __func__ , nBlockHeight ) ;
return false ;
2015-02-23 21:01:21 +01:00
}
2017-09-14 15:58:29 +02:00
LOCK ( cs ) ;
score_pair_vec_t vecMasternodeScores ;
if ( ! GetMasternodeScores ( nBlockHash , vecMasternodeScores , nMinProtocol ) )
return false ;
2015-02-23 21:01:21 +01:00
2016-09-20 00:27:36 +02:00
int nRank = 0 ;
2018-02-06 12:09:33 +01:00
for ( const auto & scorePair : vecMasternodeScores ) {
2016-09-20 00:27:36 +02:00
nRank + + ;
2018-02-15 08:29:44 +01:00
if ( scorePair . second - > outpoint = = outpoint ) {
2017-09-14 15:58:29 +02:00
nRankRet = nRank ;
return true ;
}
2015-02-23 21:01:21 +01:00
}
2017-09-14 15:58:29 +02:00
return false ;
2015-02-23 21:01:21 +01:00
}
2017-09-14 15:58:29 +02:00
bool CMasternodeMan : : GetMasternodeRanks ( CMasternodeMan : : rank_pair_vec_t & vecMasternodeRanksRet , int nBlockHeight , int nMinProtocol )
2015-03-14 19:34:51 +01:00
{
2017-09-14 15:58:29 +02:00
vecMasternodeRanksRet . clear ( ) ;
2016-09-20 00:27:36 +02:00
2017-09-14 15:58:29 +02:00
if ( ! masternodeSync . IsMasternodeListSynced ( ) )
return false ;
2015-03-14 19:34:51 +01:00
2017-09-14 15:58:29 +02:00
// make sure we know about this block
uint256 nBlockHash = uint256 ( ) ;
if ( ! GetBlockHash ( nBlockHash , nBlockHeight ) ) {
LogPrintf ( " CMasternodeMan::%s -- ERROR: GetBlockHash() failed at nBlockHeight %d \n " , __func__ , nBlockHeight ) ;
return false ;
2015-03-14 19:34:51 +01:00
}
2017-09-14 15:58:29 +02:00
LOCK ( cs ) ;
score_pair_vec_t vecMasternodeScores ;
if ( ! GetMasternodeScores ( nBlockHash , vecMasternodeScores , nMinProtocol ) )
return false ;
2015-03-14 19:34:51 +01:00
2016-09-20 00:27:36 +02:00
int nRank = 0 ;
2018-02-06 12:09:33 +01:00
for ( const auto & scorePair : vecMasternodeScores ) {
2016-09-20 00:27:36 +02:00
nRank + + ;
2017-09-14 15:58:29 +02:00
vecMasternodeRanksRet . push_back ( std : : make_pair ( nRank , * scorePair . second ) ) ;
2015-03-14 19:34:51 +01:00
}
2017-09-14 15:58:29 +02:00
return true ;
2015-03-14 19:34:51 +01:00
}
2017-09-19 16:51:38 +02:00
void CMasternodeMan : : ProcessMasternodeConnections ( CConnman & connman )
2015-03-02 00:09:33 +01:00
{
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
2017-09-19 16:51:38 +02:00
connman . ForEachNode ( CConnman : : AllNodes , [ ] ( CNode * pnode ) {
2017-12-01 19:53:34 +01:00
# ifdef ENABLE_WALLET
2017-12-04 07:06:07 +01:00
if ( pnode - > fMasternode & & ! privateSendClient . IsMixingMasternode ( pnode ) ) {
# else
if ( pnode - > fMasternode ) {
2017-12-01 19:53:34 +01:00
# endif // ENABLE_WALLET
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
}
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
} ) ;
2015-03-02 00:09:33 +01:00
}
2017-01-31 16:29:27 +01:00
std : : pair < CService , std : : set < uint256 > > CMasternodeMan : : PopScheduledMnbRequestConnection ( )
2017-01-21 20:03:55 +01:00
{
LOCK ( cs ) ;
2017-01-31 16:29:27 +01:00
if ( listScheduledMnbRequestConnections . empty ( ) ) {
return std : : make_pair ( CService ( ) , std : : set < uint256 > ( ) ) ;
}
std : : set < uint256 > setResult ;
listScheduledMnbRequestConnections . sort ( ) ;
std : : pair < CService , uint256 > pairFront = listScheduledMnbRequestConnections . front ( ) ;
// squash hashes from requests with the same CService as the first one into setResult
std : : list < std : : pair < CService , uint256 > > : : iterator it = listScheduledMnbRequestConnections . begin ( ) ;
while ( it ! = listScheduledMnbRequestConnections . end ( ) ) {
if ( pairFront . first = = it - > first ) {
setResult . insert ( it - > second ) ;
it = listScheduledMnbRequestConnections . erase ( it ) ;
} else {
// since list is sorted now, we can be sure that there is no more hashes left
// to ask for from this addr
break ;
}
}
return std : : make_pair ( pairFront . first , setResult ) ;
2017-01-21 20:03:55 +01:00
}
2018-02-01 02:10:52 +01:00
void CMasternodeMan : : ProcessPendingMnbRequests ( CConnman & connman )
{
std : : pair < CService , std : : set < uint256 > > p = PopScheduledMnbRequestConnection ( ) ;
if ( ! ( p . first = = CService ( ) | | p . second . empty ( ) ) ) {
if ( connman . IsMasternodeOrDisconnectRequested ( p . first ) ) return ;
mapPendingMNB . insert ( std : : make_pair ( p . first , std : : make_pair ( GetTime ( ) , p . second ) ) ) ;
connman . AddPendingMasternode ( p . first ) ;
}
std : : map < CService , std : : pair < int64_t , std : : set < uint256 > > > : : iterator itPendingMNB = mapPendingMNB . begin ( ) ;
while ( itPendingMNB ! = mapPendingMNB . end ( ) ) {
bool fDone = connman . ForNode ( itPendingMNB - > first , [ & ] ( CNode * pnode ) {
// compile request vector
std : : vector < CInv > vToFetch ;
std : : set < uint256 > & setHashes = itPendingMNB - > second . second ;
std : : set < uint256 > : : iterator it = setHashes . begin ( ) ;
while ( it ! = setHashes . end ( ) ) {
if ( * it ! = uint256 ( ) ) {
vToFetch . push_back ( CInv ( MSG_MASTERNODE_ANNOUNCE , * it ) ) ;
LogPrint ( " masternode " , " -- asking for mnb %s from addr=%s \n " , it - > ToString ( ) , pnode - > addr . ToString ( ) ) ;
}
+ + it ;
}
// ask for data
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : GETDATA , vToFetch ) ) ;
return true ;
} ) ;
int64_t nTimeAdded = itPendingMNB - > second . first ;
if ( fDone | | ( GetTime ( ) - nTimeAdded > 15 ) ) {
if ( ! fDone ) {
LogPrint ( " masternode " , " CMasternodeMan::%s -- failed to connect to %s \n " , __func__ , itPendingMNB - > first . ToString ( ) ) ;
}
mapPendingMNB . erase ( itPendingMNB + + ) ;
} else {
+ + itPendingMNB ;
}
}
LogPrint ( " masternode " , " %s -- mapPendingMNB size: %d \n " , __func__ , mapPendingMNB . size ( ) ) ;
}
2017-01-21 20:03:55 +01:00
2017-02-06 14:31:37 +01:00
void CMasternodeMan : : ProcessMessage ( CNode * pfrom , const std : : string & strCommand , CDataStream & vRecv , CConnman & connman )
2015-02-23 21:01:21 +01:00
{
2016-10-22 18:52:14 +02:00
if ( fLiteMode ) return ; // disable all Dash specific functionality
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 ( ) ) ;
2017-11-22 15:27:06 +01:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) return ;
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " MNANNOUNCE -- Masternode announce, masternode=%s \n " , mnb . outpoint . ToStringShort ( ) ) ;
2016-12-24 03:49:13 +01:00
2016-11-28 15:21:50 +01:00
int nDos = 0 ;
2015-02-23 21:01:21 +01:00
2017-09-19 16:51:38 +02:00
if ( CheckMnbAndUpdateMasternodeList ( pfrom , mnb , nDos , connman ) ) {
2016-11-28 15:21:50 +01:00
// use announced Masternode as a peer
2017-09-19 16:51:38 +02:00
connman . AddNewAddress ( CAddress ( mnb . addr , NODE_NETWORK ) , pfrom - > addr , 2 * 60 * 60 ) ;
2016-11-28 15:21:50 +01:00
} else if ( nDos > 0 ) {
2018-03-19 14:09:29 +01:00
LOCK ( cs_main ) ;
2016-11-28 15:21:50 +01:00
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 ) {
2017-09-19 16:51:38 +02:00
NotifyMasternodeUpdates ( connman ) ;
2016-11-13 18:52:34 +01:00
}
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 ) ;
2017-11-22 15:27:06 +01:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) return ;
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " MNPING -- Masternode ping, masternode=%s \n " , mnp . masternodeOutpoint . 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
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " MNPING -- Masternode ping, masternode=%s new \n " , mnp . masternodeOutpoint . ToStringShort ( ) ) ;
2016-02-17 19:53:55 +01:00
2016-12-24 03:49:13 +01:00
// see if we have this Masternode
2018-02-15 08:29:44 +01:00
CMasternode * pmn = Find ( mnp . masternodeOutpoint ) ;
2016-12-24 03:49:13 +01:00
2017-07-04 19:31:57 +02:00
if ( pmn & & mnp . fSentinelIsCurrent )
2018-02-25 06:33:27 +01:00
UpdateLastSentinelPingTime ( ) ;
2017-07-04 19:31:57 +02:00
2016-12-24 03:49:13 +01:00
// too late, new MNANNOUNCE is required
if ( pmn & & pmn - > IsNewStartRequired ( ) ) return ;
2016-03-15 00:16:29 +01:00
int nDos = 0 ;
2017-09-19 16:51:38 +02:00
if ( mnp . CheckAndUpdate ( pmn , false , nDos , connman ) ) 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
2018-02-15 08:29:44 +01:00
AskForMN ( pfrom , mnp . masternodeOutpoint , connman ) ;
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 ;
2018-02-15 08:29:44 +01:00
COutPoint masternodeOutpoint ;
if ( pfrom - > nVersion = = 70208 ) {
CTxIn vin ;
vRecv > > vin ;
masternodeOutpoint = vin . prevout ;
} else {
vRecv > > masternodeOutpoint ;
}
2015-02-23 21:01:21 +01:00
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " DSEG -- Masternode list, masternode=%s \n " , masternodeOutpoint . ToStringShort ( ) ) ;
2016-02-17 19:53:55 +01:00
2018-02-21 17:32:08 +01:00
if ( masternodeOutpoint . IsNull ( ) ) {
2018-02-12 13:49:15 +01:00
SyncAll ( pfrom , connman ) ;
} else {
2018-02-15 08:29:44 +01:00
SyncSingle ( pfrom , masternodeOutpoint , connman ) ;
2015-08-31 06:05:10 +02:00
}
2016-10-20 23:11:30 +02:00
} else if ( strCommand = = NetMsgType : : MNVERIFY ) { // Masternode Verify
2018-02-21 17:32:08 +01:00
// Need LOCK2 here to ensure consistent locking order because all functions below call GetBlockHash which locks cs_main
2016-11-30 01:48:05 +01:00
LOCK2 ( cs_main , cs ) ;
2016-11-13 18:52:34 +01:00
2016-10-20 23:11:30 +02:00
CMasternodeVerification mnv ;
vRecv > > mnv ;
2017-11-22 15:27:06 +01:00
pfrom - > setAskFor . erase ( mnv . GetHash ( ) ) ;
if ( ! masternodeSync . IsMasternodeListSynced ( ) ) return ;
2016-10-20 23:11:30 +02:00
if ( mnv . vchSig1 . empty ( ) ) {
// CASE 1: someone asked me to verify myself /IP we are using/
2017-09-19 16:51:38 +02:00
SendVerifyReply ( pfrom , mnv , connman ) ;
2016-10-20 23:11:30 +02:00
} 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 ) ;
}
}
}
2018-02-12 13:49:15 +01:00
void CMasternodeMan : : SyncSingle ( CNode * pnode , const COutPoint & outpoint , CConnman & connman )
{
// do not provide any data until our node is synced
if ( ! masternodeSync . IsSynced ( ) ) return ;
LOCK ( cs ) ;
auto it = mapMasternodes . find ( outpoint ) ;
if ( it ! = mapMasternodes . end ( ) ) {
if ( it - > second . addr . IsRFC1918 ( ) | | it - > second . addr . IsLocal ( ) ) return ; // do not send local network masternode
// NOTE: send masternode regardless of its current state, the other node will need it to verify old votes.
LogPrint ( " masternode " , " CMasternodeMan::%s -- Sending Masternode entry: masternode=%s addr=%s \n " , __func__ , outpoint . ToStringShort ( ) , it - > second . addr . ToString ( ) ) ;
PushDsegInvs ( pnode , it - > second ) ;
LogPrintf ( " CMasternodeMan::%s -- Sent 1 Masternode inv to peer=%d \n " , __func__ , pnode - > id ) ;
}
}
void CMasternodeMan : : SyncAll ( CNode * pnode , CConnman & connman )
{
// do not provide any data until our node is synced
if ( ! masternodeSync . IsSynced ( ) ) return ;
// local network
bool isLocal = ( pnode - > addr . IsRFC1918 ( ) | | pnode - > addr . IsLocal ( ) ) ;
2018-03-08 13:16:52 +01:00
CService addrSquashed = Params ( ) . AllowMultiplePorts ( ) ? ( CService ) pnode - > addr : CService ( pnode - > addr , 0 ) ;
2018-02-12 13:49:15 +01:00
// should only ask for this once
if ( ! isLocal & & Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN ) {
2018-03-19 14:09:29 +01:00
LOCK2 ( cs_main , cs ) ;
2018-03-08 13:16:52 +01:00
auto it = mAskedUsForMasternodeList . find ( addrSquashed ) ;
2018-02-12 13:49:15 +01:00
if ( it ! = mAskedUsForMasternodeList . end ( ) & & it - > second > GetTime ( ) ) {
Misbehaving ( pnode - > GetId ( ) , 34 ) ;
LogPrintf ( " CMasternodeMan::%s -- peer already asked me for the list, peer=%d \n " , __func__ , pnode - > id ) ;
return ;
}
int64_t askAgain = GetTime ( ) + DSEG_UPDATE_SECONDS ;
2018-03-08 13:16:52 +01:00
mAskedUsForMasternodeList [ addrSquashed ] = askAgain ;
2018-02-12 13:49:15 +01:00
}
int nInvCount = 0 ;
2018-03-19 14:09:29 +01:00
LOCK ( cs ) ;
2018-02-12 13:49:15 +01:00
for ( const auto & mnpair : mapMasternodes ) {
if ( mnpair . second . addr . IsRFC1918 ( ) | | mnpair . second . addr . IsLocal ( ) ) continue ; // do not send local network masternode
// NOTE: send masternode regardless of its current state, the other node will need it to verify old votes.
LogPrint ( " masternode " , " CMasternodeMan::%s -- Sending Masternode entry: masternode=%s addr=%s \n " , __func__ , mnpair . first . ToStringShort ( ) , mnpair . second . addr . ToString ( ) ) ;
PushDsegInvs ( pnode , mnpair . second ) ;
nInvCount + + ;
}
connman . PushMessage ( pnode , CNetMsgMaker ( pnode - > GetSendVersion ( ) ) . Make ( NetMsgType : : SYNCSTATUSCOUNT , MASTERNODE_SYNC_LIST , nInvCount ) ) ;
LogPrintf ( " CMasternodeMan::%s -- Sent %d Masternode invs to peer=%d \n " , __func__ , nInvCount , pnode - > id ) ;
}
void CMasternodeMan : : PushDsegInvs ( CNode * pnode , const CMasternode & mn )
{
AssertLockHeld ( cs ) ;
CMasternodeBroadcast mnb ( mn ) ;
CMasternodePing mnp = mnb . lastPing ;
uint256 hashMNB = mnb . GetHash ( ) ;
uint256 hashMNP = mnp . GetHash ( ) ;
pnode - > PushInventory ( CInv ( MSG_MASTERNODE_ANNOUNCE , hashMNB ) ) ;
pnode - > PushInventory ( CInv ( MSG_MASTERNODE_PING , hashMNP ) ) ;
mapSeenMasternodeBroadcast . insert ( std : : make_pair ( hashMNB , std : : make_pair ( GetTime ( ) , mnb ) ) ) ;
mapSeenMasternodePing . insert ( std : : make_pair ( hashMNP , mnp ) ) ;
}
2016-10-22 18:52:14 +02:00
// Verification of masternodes via unique direct requests.
2017-09-19 16:51:38 +02:00
void CMasternodeMan : : DoFullVerificationStep ( CConnman & connman )
2016-10-20 23:11:30 +02:00
{
2018-02-21 17:32:08 +01:00
if ( activeMasternode . outpoint . IsNull ( ) ) return ;
2017-01-14 23:29:08 +01:00
if ( ! masternodeSync . IsSynced ( ) ) return ;
2016-10-20 23:11:30 +02:00
2017-09-14 15:58:29 +02:00
rank_pair_vec_t vecMasternodeRanks ;
GetMasternodeRanks ( vecMasternodeRanks , nCachedBlockHeight - 1 , MIN_POSE_PROTO_VERSION ) ;
2016-10-20 23:11:30 +02:00
2018-03-09 15:15:48 +01:00
LOCK ( cs ) ;
2016-10-20 23:11:30 +02:00
int nCount = 0 ;
int nMyRank = - 1 ;
int nRanksTotal = ( int ) vecMasternodeRanks . size ( ) ;
// send verify requests only if we are in top MAX_POSE_RANK
2018-02-06 12:09:33 +01:00
rank_pair_vec_t : : iterator it = vecMasternodeRanks . begin ( ) ;
2016-10-20 23:11:30 +02:00
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 ;
}
2018-02-15 08:29:44 +01:00
if ( it - > second . outpoint = = activeMasternode . outpoint ) {
2016-10-20 23:11:30 +02:00
nMyRank = it - > first ;
LogPrint ( " masternode " , " CMasternodeMan::DoFullVerificationStep -- Found self at rank %d/%d, verifying up to %d masternodes \n " ,
2017-02-17 21:08:29 +01:00
nMyRank , nRanksTotal , ( int ) MAX_POSE_CONNECTIONS ) ;
2016-10-20 23:11:30 +02:00
break ;
}
+ + it ;
}
// edge case: list is too short and this masternode is not enabled
if ( nMyRank = = - 1 ) return ;
2017-02-17 21:08:29 +01:00
// send verify requests to up to MAX_POSE_CONNECTIONS masternodes
// starting from MAX_POSE_RANK + nMyRank and using MAX_POSE_CONNECTIONS as a step
int nOffset = MAX_POSE_RANK + nMyRank - 1 ;
2016-10-20 23:11:30 +02:00
if ( nOffset > = ( int ) vecMasternodeRanks . size ( ) ) return ;
2018-02-06 12:09:33 +01:00
std : : vector < const CMasternode * > vSortedByAddr ;
for ( const auto & mnpair : mapMasternodes ) {
2017-09-11 16:13:48 +02:00
vSortedByAddr . push_back ( & mnpair . second ) ;
2016-10-20 23:11:30 +02:00
}
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 " : " " ,
2018-02-15 08:29:44 +01:00
it - > second . outpoint . ToStringShort ( ) , it - > second . addr . ToString ( ) ) ;
2017-02-17 21:08:29 +01:00
nOffset + = MAX_POSE_CONNECTIONS ;
if ( nOffset > = ( int ) vecMasternodeRanks . size ( ) ) break ;
it + = MAX_POSE_CONNECTIONS ;
2016-10-20 23:11:30 +02:00
continue ;
}
LogPrint ( " masternode " , " CMasternodeMan::DoFullVerificationStep -- Verifying masternode %s rank %d/%d address %s \n " ,
2018-02-15 08:29:44 +01:00
it - > second . outpoint . ToStringShort ( ) , it - > first , nRanksTotal , it - > second . addr . ToString ( ) ) ;
2017-09-19 16:51:38 +02:00
if ( SendVerifyRequest ( CAddress ( it - > second . addr , NODE_NETWORK ) , vSortedByAddr , connman ) ) {
2016-10-20 23:11:30 +02:00
nCount + + ;
2017-02-17 21:08:29 +01:00
if ( nCount > = MAX_POSE_CONNECTIONS ) break ;
2016-10-20 23:11:30 +02:00
}
2017-02-17 21:08:29 +01:00
nOffset + = MAX_POSE_CONNECTIONS ;
if ( nOffset > = ( int ) vecMasternodeRanks . size ( ) ) break ;
it + = MAX_POSE_CONNECTIONS ;
2016-10-20 23:11:30 +02:00
}
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 ( )
{
2017-09-11 16:13:48 +02:00
if ( ! masternodeSync . IsSynced ( ) | | mapMasternodes . empty ( ) ) return ;
2016-10-20 23:11:30 +02:00
std : : vector < CMasternode * > vBan ;
std : : vector < CMasternode * > vSortedByAddr ;
{
LOCK ( cs ) ;
CMasternode * pprevMasternode = NULL ;
CMasternode * pverifiedMasternode = NULL ;
2017-09-11 16:13:48 +02:00
for ( auto & mnpair : mapMasternodes ) {
vSortedByAddr . push_back ( & mnpair . second ) ;
2016-10-20 23:11:30 +02:00
}
sort ( vSortedByAddr . begin ( ) , vSortedByAddr . end ( ) , CompareByAddr ( ) ) ;
2018-02-06 12:09:33 +01:00
for ( const auto & pmn : vSortedByAddr ) {
2016-10-20 23:11:30 +02:00
// 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
2018-02-06 12:09:33 +01:00
for ( auto & pmn : vBan ) {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CMasternodeMan::CheckSameAddr -- increasing PoSe ban score for masternode %s \n " , pmn - > outpoint . ToStringShort ( ) ) ;
2016-10-30 21:56:47 +01:00
pmn - > IncreasePoSeBanScore ( ) ;
2016-10-20 23:11:30 +02:00
}
}
2018-02-06 12:09:33 +01:00
bool CMasternodeMan : : SendVerifyRequest ( const CAddress & addr , const std : : vector < const CMasternode * > & vSortedByAddr , CConnman & connman )
2016-10-20 23:11:30 +02:00
{
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 ;
}
2018-02-01 02:10:52 +01:00
if ( connman . IsMasternodeOrDisconnectRequested ( addr ) ) return false ;
2016-12-11 07:18:52 +01:00
2018-02-01 02:10:52 +01:00
connman . AddPendingMasternode ( addr ) ;
// use random nonce, store it and require node to reply with correct one later
CMasternodeVerification mnv ( addr , GetRandInt ( 999999 ) , nCachedBlockHeight - 1 ) ;
LOCK ( cs_mapPendingMNV ) ;
mapPendingMNV . insert ( std : : make_pair ( addr , std : : make_pair ( GetTime ( ) , mnv ) ) ) ;
LogPrintf ( " CMasternodeMan::SendVerifyRequest -- verifying node using nonce %d addr=%s \n " , mnv . nonce , addr . ToString ( ) ) ;
2016-12-11 07:18:52 +01:00
return true ;
2016-10-20 23:11:30 +02:00
}
2018-02-01 02:10:52 +01:00
void CMasternodeMan : : ProcessPendingMnvRequests ( CConnman & connman )
{
LOCK ( cs_mapPendingMNV ) ;
std : : map < CService , std : : pair < int64_t , CMasternodeVerification > > : : iterator itPendingMNV = mapPendingMNV . begin ( ) ;
while ( itPendingMNV ! = mapPendingMNV . end ( ) ) {
bool fDone = connman . ForNode ( itPendingMNV - > first , [ & ] ( CNode * pnode ) {
netfulfilledman . AddFulfilledRequest ( pnode - > addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -request " ) ;
// use random nonce, store it and require node to reply with correct one later
mWeAskedForVerification [ pnode - > addr ] = itPendingMNV - > second . second ;
LogPrint ( " masternode " , " -- verifying node using nonce %d addr=%s \n " , itPendingMNV - > second . second . nonce , pnode - > addr . ToString ( ) ) ;
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ; // TODO this gives a warning about version not being set (we should wait for VERSION exchange)
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : MNVERIFY , itPendingMNV - > second . second ) ) ;
return true ;
} ) ;
int64_t nTimeAdded = itPendingMNV - > second . first ;
if ( fDone | | ( GetTime ( ) - nTimeAdded > 15 ) ) {
if ( ! fDone ) {
LogPrint ( " masternode " , " CMasternodeMan::%s -- failed to connect to %s \n " , __func__ , itPendingMNV - > first . ToString ( ) ) ;
}
mapPendingMNV . erase ( itPendingMNV + + ) ;
} else {
+ + itPendingMNV ;
}
}
LogPrint ( " masternode " , " %s -- mapPendingMNV size: %d \n " , __func__ , mapPendingMNV . size ( ) ) ;
}
2017-09-19 16:51:38 +02:00
void CMasternodeMan : : SendVerifyReply ( CNode * pnode , CMasternodeVerification & mnv , CConnman & connman )
2016-10-20 23:11:30 +02:00
{
2018-03-19 14:09:29 +01:00
AssertLockHeld ( cs_main ) ;
2016-10-20 23:11:30 +02:00
// only masternodes can sign this, why would someone ask regular node?
2018-01-26 02:11:01 +01:00
if ( ! fMasternodeMode ) {
2016-10-20 23:11:30 +02:00
// 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 ;
}
2018-02-16 15:54:53 +01:00
std : : string strError ;
2016-10-20 23:11:30 +02:00
2018-02-16 15:54:53 +01:00
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash = mnv . GetSignatureHash1 ( blockHash ) ;
2016-10-20 23:11:30 +02:00
2018-02-16 15:54:53 +01:00
if ( ! CHashSigner : : SignHash ( hash , activeMasternode . keyMasternode , mnv . vchSig1 ) ) {
LogPrintf ( " CMasternodeMan::SendVerifyReply -- SignHash() failed \n " ) ;
return ;
}
2016-10-20 23:11:30 +02:00
2018-02-16 15:54:53 +01:00
if ( ! CHashSigner : : VerifyHash ( hash , activeMasternode . pubKeyMasternode , mnv . vchSig1 , strError ) ) {
LogPrintf ( " CMasternodeMan::SendVerifyReply -- VerifyHash() failed, error: %s \n " , strError ) ;
return ;
}
} else {
std : : string strMessage = strprintf ( " %s%d%s " , activeMasternode . service . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ) ;
if ( ! CMessageSigner : : SignMessage ( strMessage , mnv . vchSig1 , activeMasternode . keyMasternode ) ) {
LogPrintf ( " MasternodeMan::SendVerifyReply -- SignMessage() failed \n " ) ;
return ;
}
if ( ! CMessageSigner : : VerifyMessage ( activeMasternode . pubKeyMasternode , mnv . vchSig1 , strMessage , strError ) ) {
LogPrintf ( " MasternodeMan::SendVerifyReply -- VerifyMessage() failed, error: %s \n " , strError ) ;
return ;
}
2016-10-20 23:11:30 +02:00
}
2016-11-25 20:01:56 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : MNVERIFY , mnv ) ) ;
2016-10-20 23:11:30 +02:00
netfulfilledman . AddFulfilledRequest ( pnode - > addr , strprintf ( " %s " , NetMsgType : : MNVERIFY ) + " -reply " ) ;
}
void CMasternodeMan : : ProcessVerifyReply ( CNode * pnode , CMasternodeVerification & mnv )
{
2018-03-19 14:09:29 +01:00
AssertLockHeld ( cs_main ) ;
2016-10-20 23:11:30 +02:00
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 ;
2018-02-16 15:54:53 +01:00
uint256 hash1 = mnv . GetSignatureHash1 ( blockHash ) ;
2016-10-20 23:11:30 +02:00
std : : string strMessage1 = strprintf ( " %s%d%s " , pnode - > addr . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ) ;
2018-02-16 15:54:53 +01:00
2017-09-11 16:13:48 +02:00
for ( auto & mnpair : mapMasternodes ) {
if ( CAddress ( mnpair . second . addr , NODE_NETWORK ) = = pnode - > addr ) {
2018-02-16 15:54:53 +01:00
bool fFound = false ;
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
fFound = CHashSigner : : VerifyHash ( hash1 , mnpair . second . pubKeyMasternode , mnv . vchSig1 , strError ) ;
// we don't care about mnv with signature in old format
} else {
fFound = CMessageSigner : : VerifyMessage ( mnpair . second . pubKeyMasternode , mnv . vchSig1 , strMessage1 , strError ) ;
}
if ( fFound ) {
2016-10-20 23:11:30 +02:00
// found it!
2017-09-11 16:13:48 +02:00
prealMasternode = & mnpair . second ;
if ( ! mnpair . second . IsPoSeVerified ( ) ) {
mnpair . second . 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
2018-02-21 17:32:08 +01:00
if ( activeMasternode . outpoint . IsNull ( ) ) continue ;
2016-10-20 23:11:30 +02:00
// update ...
2017-09-11 16:13:48 +02:00
mnv . addr = mnpair . second . addr ;
2018-02-15 08:29:44 +01:00
mnv . masternodeOutpoint1 = mnpair . second . outpoint ;
mnv . masternodeOutpoint2 = activeMasternode . outpoint ;
2016-10-20 23:11:30 +02:00
// ... and sign it
std : : string strError ;
2018-02-16 15:54:53 +01:00
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash2 = mnv . GetSignatureHash2 ( blockHash ) ;
if ( ! CHashSigner : : SignHash ( hash2 , activeMasternode . keyMasternode , mnv . vchSig2 ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyReply -- SignHash() failed \n " ) ;
return ;
}
if ( ! CHashSigner : : VerifyHash ( hash2 , activeMasternode . pubKeyMasternode , mnv . vchSig2 , strError ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyReply -- VerifyHash() failed, error: %s \n " , strError ) ;
return ;
}
} else {
std : : string strMessage2 = strprintf ( " %s%d%s%s%s " , mnv . addr . ToString ( false ) , mnv . nonce , blockHash . ToString ( ) ,
mnv . masternodeOutpoint1 . ToStringShort ( ) , mnv . masternodeOutpoint2 . ToStringShort ( ) ) ;
if ( ! CMessageSigner : : SignMessage ( strMessage2 , mnv . vchSig2 , activeMasternode . keyMasternode ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyReply -- SignMessage() failed \n " ) ;
return ;
}
if ( ! CMessageSigner : : VerifyMessage ( activeMasternode . pubKeyMasternode , mnv . vchSig2 , strMessage2 , strError ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyReply -- VerifyMessage() failed, error: %s \n " , strError ) ;
return ;
}
2016-10-20 23:11:30 +02:00
}
mWeAskedForVerification [ pnode - > addr ] = mnv ;
2017-12-13 13:42:37 +01:00
mapSeenMasternodeVerification . insert ( std : : make_pair ( mnv . GetHash ( ) , mnv ) ) ;
2016-10-20 23:11:30 +02:00
mnv . Relay ( ) ;
} else {
2017-09-11 16:13:48 +02:00
vpMasternodesToBan . push_back ( & mnpair . second ) ;
2016-10-20 23:11:30 +02:00
}
}
}
// 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 " ,
2018-02-15 08:29:44 +01:00
prealMasternode - > outpoint . ToStringShort ( ) , pnode - > addr . ToString ( ) ) ;
2016-10-20 23:11:30 +02:00
// increase ban score for everyone else
2018-02-06 12:09:33 +01:00
for ( const auto & pmn : vpMasternodesToBan ) {
2016-10-30 21:56:47 +01:00
pmn - > IncreasePoSeBanScore ( ) ;
2017-12-14 17:50:06 +01:00
LogPrint ( " masternode " , " CMasternodeMan::ProcessVerifyReply -- increased PoSe ban score for %s addr %s, new score %d \n " ,
2018-02-15 08:29:44 +01:00
prealMasternode - > outpoint . ToStringShort ( ) , pnode - > addr . ToString ( ) , pmn - > nPoSeBanScore ) ;
2016-10-20 23:11:30 +02:00
}
2017-12-14 17:50:06 +01:00
if ( ! vpMasternodesToBan . empty ( ) )
LogPrintf ( " CMasternodeMan::ProcessVerifyReply -- PoSe score increased for %d fake masternodes, addr %s \n " ,
( int ) vpMasternodesToBan . size ( ) , pnode - > addr . ToString ( ) ) ;
2016-10-20 23:11:30 +02:00
}
}
void CMasternodeMan : : ProcessVerifyBroadcast ( CNode * pnode , const CMasternodeVerification & mnv )
{
2018-03-19 14:09:29 +01:00
AssertLockHeld ( cs_main ) ;
2016-10-20 23:11:30 +02:00
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
2017-08-25 14:57:05 +02:00
if ( mnv . nBlockHeight < nCachedBlockHeight - MAX_POSE_BLOCKS ) {
2017-06-06 01:47:23 +02:00
LogPrint ( " masternode " , " CMasternodeMan::ProcessVerifyBroadcast -- Outdated: current block %d, verification block %d, peer=%d \n " ,
2017-08-25 14:57:05 +02:00
nCachedBlockHeight , mnv . nBlockHeight , pnode - > id ) ;
2016-10-20 23:11:30 +02:00
return ;
}
2018-02-15 08:29:44 +01:00
if ( mnv . masternodeOutpoint1 = = mnv . masternodeOutpoint2 ) {
LogPrint ( " masternode " , " CMasternodeMan::ProcessVerifyBroadcast -- ERROR: same outpoints %s, peer=%d \n " ,
mnv . masternodeOutpoint1 . ToStringShort ( ) , pnode - > id ) ;
2016-10-20 23:11:30 +02:00
// 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...
2017-06-06 01:47:23 +02:00
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- Can't get block hash for unknown block height %d, peer=%d \n " , mnv . nBlockHeight , pnode - > id ) ;
2016-10-20 23:11:30 +02:00
return ;
}
2017-09-14 15:58:29 +02:00
int nRank ;
2017-04-01 19:40:28 +02:00
2018-02-15 08:29:44 +01:00
if ( ! GetMasternodeRank ( mnv . masternodeOutpoint2 , nRank , mnv . nBlockHeight , MIN_POSE_PROTO_VERSION ) ) {
2017-04-01 19:40:28 +02:00
LogPrint ( " masternode " , " CMasternodeMan::ProcessVerifyBroadcast -- Can't calculate rank for masternode %s \n " ,
2018-02-15 08:29:44 +01:00
mnv . masternodeOutpoint2 . ToStringShort ( ) ) ;
2017-04-01 19:40:28 +02:00
return ;
}
if ( nRank > MAX_POSE_RANK ) {
2017-06-06 01:47:23 +02:00
LogPrint ( " masternode " , " CMasternodeMan::ProcessVerifyBroadcast -- Masternode %s is not in top %d, current rank %d, peer=%d \n " ,
2018-02-15 08:29:44 +01:00
mnv . masternodeOutpoint2 . ToStringShort ( ) , ( int ) MAX_POSE_RANK , nRank , pnode - > id ) ;
2016-10-20 23:11:30 +02:00
return ;
}
{
LOCK ( cs ) ;
2018-02-15 08:29:44 +01:00
CMasternode * pmn1 = Find ( mnv . masternodeOutpoint1 ) ;
2016-10-20 23:11:30 +02:00
if ( ! pmn1 ) {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode1 %s \n " , mnv . masternodeOutpoint1 . ToStringShort ( ) ) ;
2016-10-20 23:11:30 +02:00
return ;
}
2018-02-15 08:29:44 +01:00
CMasternode * pmn2 = Find ( mnv . masternodeOutpoint2 ) ;
2016-10-20 23:11:30 +02:00
if ( ! pmn2 ) {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- can't find masternode2 %s \n " , mnv . masternodeOutpoint2 . ToStringShort ( ) ) ;
2016-10-20 23:11:30 +02:00
return ;
}
if ( pmn1 - > addr ! = mnv . addr ) {
2017-12-14 17:50:06 +01:00
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- addr %s does not match %s \n " , mnv . addr . ToString ( ) , pmn1 - > addr . ToString ( ) ) ;
2016-10-20 23:11:30 +02:00
return ;
}
2018-02-16 15:54:53 +01:00
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash1 = mnv . GetSignatureHash1 ( blockHash ) ;
uint256 hash2 = mnv . GetSignatureHash2 ( blockHash ) ;
2016-10-20 23:11:30 +02:00
2018-02-16 15:54:53 +01:00
if ( ! CHashSigner : : VerifyHash ( hash1 , pmn1 - > pubKeyMasternode , mnv . vchSig1 , strError ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s \n " , strError ) ;
return ;
}
if ( ! CHashSigner : : VerifyHash ( hash2 , pmn2 - > pubKeyMasternode , mnv . vchSig2 , strError ) ) {
LogPrintf ( " MasternodeMan::ProcessVerifyBroadcast -- VerifyHash() failed, error: %s \n " , strError ) ;
return ;
}
} else {
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 . masternodeOutpoint1 . ToStringShort ( ) , mnv . masternodeOutpoint2 . ToStringShort ( ) ) ;
if ( ! CMessageSigner : : VerifyMessage ( pmn1 - > pubKeyMasternode , mnv . vchSig1 , strMessage1 , strError ) ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode1 failed, error: %s \n " , strError ) ;
return ;
}
if ( ! CMessageSigner : : VerifyMessage ( pmn2 - > pubKeyMasternode , mnv . vchSig2 , strMessage2 , strError ) ) {
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- VerifyMessage() for masternode2 failed, error: %s \n " , strError ) ;
return ;
}
2016-10-20 23:11:30 +02:00
}
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 " ,
2018-02-15 08:29:44 +01:00
pmn1 - > outpoint . ToStringShort ( ) , pmn1 - > addr . ToString ( ) ) ;
2016-10-20 23:11:30 +02:00
// increase ban score for everyone else with the same addr
int nCount = 0 ;
2017-09-11 16:13:48 +02:00
for ( auto & mnpair : mapMasternodes ) {
2018-02-15 08:29:44 +01:00
if ( mnpair . second . addr ! = mnv . addr | | mnpair . first = = mnv . masternodeOutpoint1 ) continue ;
2017-09-11 16:13:48 +02:00
mnpair . second . 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 " ,
2017-09-11 16:13:48 +02:00
mnpair . first . ToStringShort ( ) , mnpair . second . addr . ToString ( ) , mnpair . second . nPoSeBanScore ) ;
2016-10-20 23:11:30 +02:00
}
2017-12-14 17:50:06 +01:00
if ( nCount )
LogPrintf ( " CMasternodeMan::ProcessVerifyBroadcast -- PoSe score increased for %d fake masternodes, addr %s \n " ,
nCount , pmn1 - > 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 ;
2017-09-11 16:13:48 +02:00
info < < " Masternodes: " < < ( int ) mapMasternodes . size ( ) < <
2015-03-05 09:10:15 +01:00
" , 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
2017-09-19 16:51:38 +02:00
bool CMasternodeMan : : CheckMnbAndUpdateMasternodeList ( CNode * pfrom , CMasternodeBroadcast mnb , int & nDos , CConnman & connman )
2016-10-20 23:11:30 +02:00
{
2017-07-21 17:21:09 +02:00
// Need to lock cs_main here to ensure consistent locking order because the SimpleCheck call below locks cs_main
LOCK ( cs_main ) ;
2016-10-20 23:11:30 +02:00
2017-07-21 17:21:09 +02:00
{
LOCK ( cs ) ;
nDos = 0 ;
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s \n " , mnb . outpoint . ToStringShort ( ) ) ;
2017-07-21 17:21:09 +02:00
uint256 hash = mnb . GetHash ( ) ;
if ( mapSeenMasternodeBroadcast . count ( hash ) & & ! mnb . fRecovery ) { //seen
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen \n " , mnb . outpoint . ToStringShort ( ) ) ;
2017-07-21 17:21:09 +02: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 ) {
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen update \n " , mnb . outpoint . ToStringShort ( ) ) ;
2017-07-21 17:21:09 +02:00
mapSeenMasternodeBroadcast [ hash ] . first = GetTime ( ) ;
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " CMasternodeMan::CheckMnbAndUpdateMasternodeList - seen " ) ;
2017-07-21 17:21:09 +02: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 ( ) ;
2017-08-29 01:51:44 +02:00
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 ( ) , ( GetAdjustedTime ( ) - mnb . lastPing . sigTime ) / 60 , mnTemp . GetStateString ( ) ) ;
2017-07-21 17:21:09 +02:00
if ( mnTemp . IsValidStateForAutoStart ( mnTemp . nActiveState ) ) {
// this node thinks it's a good one
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s seen good \n " , mnb . outpoint . ToStringShort ( ) ) ;
2017-07-21 17:21:09 +02:00
mMnbRecoveryGoodReplies [ hash ] . push_back ( mnb ) ;
}
2017-01-01 18:48:53 +01:00
}
}
}
2017-07-21 17:21:09 +02:00
return true ;
2017-01-01 18:48:53 +01:00
}
2017-07-21 17:21:09 +02:00
mapSeenMasternodeBroadcast . insert ( std : : make_pair ( hash , std : : make_pair ( GetTime ( ) , mnb ) ) ) ;
2016-03-18 00:37:48 +01:00
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- masternode=%s new \n " , mnb . outpoint . ToStringShort ( ) ) ;
2016-03-18 00:37:48 +01:00
2017-07-21 17:21:09 +02:00
if ( ! mnb . SimpleCheck ( nDos ) ) {
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- SimpleCheck() failed, masternode=%s \n " , mnb . outpoint . ToStringShort ( ) ) ;
2016-10-20 23:11:30 +02:00
return false ;
}
2017-07-21 17:21:09 +02:00
// search Masternode list
2018-02-15 08:29:44 +01:00
CMasternode * pmn = Find ( mnb . outpoint ) ;
2017-07-21 17:21:09 +02:00
if ( pmn ) {
CMasternodeBroadcast mnbOld = mapSeenMasternodeBroadcast [ CMasternodeBroadcast ( * pmn ) . GetHash ( ) ] . second ;
2017-09-19 16:51:38 +02:00
if ( ! mnb . Update ( pmn , nDos , connman ) ) {
2018-02-15 08:29:44 +01:00
LogPrint ( " masternode " , " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Update() failed, masternode=%s \n " , mnb . outpoint . ToStringShort ( ) ) ;
2017-07-21 17:21:09 +02:00
return false ;
}
if ( hash ! = mnbOld . GetHash ( ) ) {
mapSeenMasternodeBroadcast . erase ( mnbOld . GetHash ( ) ) ;
}
return true ;
2016-12-24 03:49:13 +01:00
}
2017-07-21 17:21:09 +02:00
}
if ( mnb . CheckOutpoint ( nDos ) ) {
Add ( mnb ) ;
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " CMasternodeMan::CheckMnbAndUpdateMasternodeList - new " ) ;
2017-07-21 17:21:09 +02:00
// if it matches our Masternode privkey...
2018-01-26 02:11:01 +01:00
if ( fMasternodeMode & & mnb . pubKeyMasternode = = activeMasternode . pubKeyMasternode ) {
2017-07-21 17:21:09 +02:00
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 " ,
2018-02-15 08:29:44 +01:00
mnb . outpoint . ToStringShort ( ) , mnb . sigTime , mnb . addr . ToString ( ) ) ;
2017-09-19 16:51:38 +02:00
activeMasternode . ManageState ( connman ) ;
2017-07-21 17:21:09 +02:00
} 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 ;
2016-10-20 23:11:30 +02:00
}
}
2017-09-19 16:51:38 +02:00
mnb . Relay ( connman ) ;
2017-07-21 17:21:09 +02:00
} else {
2018-02-15 08:29:44 +01:00
LogPrintf ( " CMasternodeMan::CheckMnbAndUpdateMasternodeList -- Rejected Masternode entry: %s addr=%s \n " , mnb . outpoint . ToStringShort ( ) , mnb . addr . ToString ( ) ) ;
2017-07-21 17:21:09 +02:00
return false ;
2016-03-18 00:37:48 +01:00
}
return true ;
}
2016-09-11 22:22:37 +02:00
2017-08-25 14:57:05 +02:00
void CMasternodeMan : : UpdateLastPaid ( const CBlockIndex * pindex )
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
2017-09-11 16:13:48 +02:00
if ( fLiteMode | | ! masternodeSync . IsWinnersListSynced ( ) | | mapMasternodes . empty ( ) ) return ;
2016-09-11 22:22:37 +02:00
2018-03-21 12:08:35 +01:00
static int nLastRunBlockHeight = 0 ;
// Scan at least LAST_PAID_SCAN_BLOCKS but no more than mnpayments.GetStorageLimit()
int nMaxBlocksToScanBack = std : : max ( LAST_PAID_SCAN_BLOCKS , nCachedBlockHeight - nLastRunBlockHeight ) ;
nMaxBlocksToScanBack = std : : min ( nMaxBlocksToScanBack , mnpayments . GetStorageLimit ( ) ) ;
2016-09-11 22:22:37 +02:00
2018-03-21 12:08:35 +01:00
LogPrint ( " masternode " , " CMasternodeMan::UpdateLastPaid -- nCachedBlockHeight=%d, nLastRunBlockHeight=%d, nMaxBlocksToScanBack=%d \n " ,
nCachedBlockHeight , nLastRunBlockHeight , nMaxBlocksToScanBack ) ;
2016-09-11 22:22:37 +02:00
2018-03-21 12:08:35 +01:00
for ( auto & mnpair : mapMasternodes ) {
2017-09-11 16:13:48 +02:00
mnpair . second . UpdateLastPaid ( pindex , nMaxBlocksToScanBack ) ;
2016-09-11 22:22:37 +02:00
}
2018-03-21 12:08:35 +01:00
nLastRunBlockHeight = nCachedBlockHeight ;
2016-09-11 22:22:37 +02:00
}
2016-10-17 20:54:28 +02:00
2018-02-25 06:33:27 +01:00
void CMasternodeMan : : UpdateLastSentinelPingTime ( )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2018-02-25 06:33:27 +01:00
nLastSentinelPingTime = GetTime ( ) ;
2016-10-17 20:54:28 +02:00
}
2018-02-25 06:33:27 +01:00
bool CMasternodeMan : : IsSentinelPingActive ( )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
// Check if any masternodes have voted recently, otherwise return false
2018-02-25 06:33:27 +01:00
return ( GetTime ( ) - nLastSentinelPingTime ) < = MASTERNODE_SENTINEL_PING_MAX_SECONDS ;
2016-10-17 20:54:28 +02:00
}
2017-09-11 16:13:48 +02:00
bool CMasternodeMan : : AddGovernanceVote ( const COutPoint & outpoint , uint256 nGovernanceObjectHash )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
CMasternode * pmn = Find ( outpoint ) ;
if ( ! pmn ) {
2017-04-02 21:58:54 +02:00
return false ;
2016-10-17 20:54:28 +02:00
}
2017-09-11 16:13:48 +02:00
pmn - > AddGovernanceVote ( nGovernanceObjectHash ) ;
2017-04-02 21:58:54 +02:00
return true ;
2016-10-17 20:54:28 +02:00
}
void CMasternodeMan : : RemoveGovernanceObject ( uint256 nGovernanceObjectHash )
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
for ( auto & mnpair : mapMasternodes ) {
mnpair . second . RemoveGovernanceObject ( nGovernanceObjectHash ) ;
2016-10-17 20:54:28 +02:00
}
}
void CMasternodeMan : : CheckMasternode ( const CPubKey & pubKeyMasternode , bool fForce )
{
2018-03-09 15:15:48 +01:00
LOCK2 ( cs_main , cs ) ;
2017-09-11 16:13:48 +02:00
for ( auto & mnpair : mapMasternodes ) {
if ( mnpair . second . pubKeyMasternode = = pubKeyMasternode ) {
mnpair . second . Check ( fForce ) ;
return ;
}
2016-10-17 20:54:28 +02:00
}
}
2017-09-11 16:13:48 +02:00
bool CMasternodeMan : : IsMasternodePingedWithin ( const COutPoint & outpoint , int nSeconds , int64_t nTimeToCheckAt )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
CMasternode * pmn = Find ( outpoint ) ;
return pmn ? pmn - > IsPingedWithin ( nSeconds , nTimeToCheckAt ) : false ;
2016-10-17 20:54:28 +02:00
}
2017-09-11 16:13:48 +02:00
void CMasternodeMan : : SetMasternodeLastPing ( const COutPoint & outpoint , const CMasternodePing & mnp )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2017-09-11 16:13:48 +02:00
CMasternode * pmn = Find ( outpoint ) ;
if ( ! pmn ) {
2016-10-17 20:54:28 +02:00
return ;
}
2017-09-11 16:13:48 +02:00
pmn - > lastPing = mnp ;
if ( mnp . fSentinelIsCurrent ) {
2018-02-25 06:33:27 +01:00
UpdateLastSentinelPingTime ( ) ;
2017-09-11 16:13:48 +02:00
}
2016-10-17 20:54:28 +02:00
mapSeenMasternodePing . insert ( std : : make_pair ( mnp . GetHash ( ) , mnp ) ) ;
2017-09-11 16:13:48 +02:00
CMasternodeBroadcast mnb ( * pmn ) ;
2016-10-17 20:54:28 +02:00
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 )
{
2017-08-25 14:57:05 +02:00
nCachedBlockHeight = pindex - > nHeight ;
LogPrint ( " masternode " , " CMasternodeMan::UpdatedBlockTip -- nCachedBlockHeight=%d \n " , nCachedBlockHeight ) ;
2016-10-20 23:11:30 +02:00
CheckSameAddr ( ) ;
2018-01-26 02:11:01 +01:00
if ( fMasternodeMode ) {
2016-10-20 23:11:30 +02:00
// normal wallet does not need to update this every block, doing update on rpc call should be enough
2017-08-25 14:57:05 +02:00
UpdateLastPaid ( pindex ) ;
2016-10-20 23:11:30 +02:00
}
}
2016-11-13 18:52:34 +01:00
2018-03-15 10:21:12 +01:00
void CMasternodeMan : : WarnMasternodeDaemonUpdates ( )
{
LOCK ( cs ) ;
static bool fWarned = false ;
if ( fWarned | | ! size ( ) | | ! masternodeSync . IsMasternodeListSynced ( ) )
return ;
int nUpdatedMasternodes { 0 } ;
for ( const auto & mnpair : mapMasternodes ) {
if ( mnpair . second . lastPing . nDaemonVersion > CLIENT_VERSION ) {
+ + nUpdatedMasternodes ;
}
}
// Warn only when at least half of known masternodes already updated
if ( nUpdatedMasternodes < size ( ) / 2 )
return ;
std : : string strWarning ;
if ( nUpdatedMasternodes ! = size ( ) ) {
strWarning = strprintf ( _ ( " Warning: At least %d of %d masternodes are running on a newer software version. Please check latest releases, you might need to update too. " ) ,
nUpdatedMasternodes , size ( ) ) ;
} else {
// someone was postponing this update for way too long probably
strWarning = strprintf ( _ ( " Warning: Every masternode (out of %d known ones) is running on a newer software version. Please check latest releases, it's very likely that you missed a major/critical update. " ) ,
size ( ) ) ;
}
// notify GetWarnings(), called by Qt and the JSON-RPC code to warn the user
SetMiscWarning ( strWarning ) ;
// trigger GUI update
uiInterface . NotifyAlertChanged ( SerializeHash ( strWarning ) , CT_NEW ) ;
// trigger cmd-line notification
CAlert : : Notify ( strWarning ) ;
fWarned = true ;
}
2017-09-19 16:51:38 +02:00
void CMasternodeMan : : NotifyMasternodeUpdates ( CConnman & connman )
2016-11-13 18:52:34 +01:00
{
// Avoid double locking
bool fMasternodesAddedLocal = false ;
bool fMasternodesRemovedLocal = false ;
{
LOCK ( cs ) ;
fMasternodesAddedLocal = fMasternodesAdded ;
fMasternodesRemovedLocal = fMasternodesRemoved ;
}
if ( fMasternodesAddedLocal ) {
2017-09-19 16:51:38 +02:00
governance . CheckMasternodeOrphanObjects ( connman ) ;
governance . CheckMasternodeOrphanVotes ( connman ) ;
2016-11-13 18:52:34 +01:00
}
if ( fMasternodesRemovedLocal ) {
governance . UpdateCachesAndClean ( ) ;
}
LOCK ( cs ) ;
fMasternodesAdded = false ;
fMasternodesRemoved = false ;
}