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.
2016-08-05 21:49:45 +02:00
# include "activemasternode.h"
2017-12-01 19:53:34 +01:00
# include "base58.h"
2016-08-05 21:49:45 +02:00
# include "init.h"
2017-09-03 15:29:10 +02:00
# include "netbase.h"
2014-12-09 02:17:57 +01:00
# include "masternode.h"
2016-01-24 20:05:31 +01:00
# include "masternode-payments.h"
# include "masternode-sync.h"
2015-02-23 21:01:21 +01:00
# include "masternodeman.h"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2017-12-01 19:53:34 +01:00
# include "script/standard.h"
2014-12-09 02:17:57 +01:00
# include "util.h"
2017-12-01 19:53:34 +01:00
# ifdef ENABLE_WALLET
# include "wallet/wallet.h"
# endif // ENABLE_WALLET
2014-12-09 02:17:57 +01:00
2016-09-16 00:00:06 +02:00
# include <boost/lexical_cast.hpp>
2015-02-05 23:56:59 +01:00
2015-02-23 21:01:21 +01:00
2016-09-16 00:00:06 +02:00
CMasternode : : CMasternode ( ) :
2017-08-11 20:52:06 +02:00
masternode_info_t { MASTERNODE_ENABLED , PROTOCOL_VERSION , GetAdjustedTime ( ) } ,
fAllowMixingTx ( true )
2016-09-16 00:00:06 +02:00
{ }
2017-09-11 16:13:48 +02:00
CMasternode : : CMasternode ( CService addr , COutPoint outpoint , CPubKey pubKeyCollateralAddress , CPubKey pubKeyMasternode , int nProtocolVersionIn ) :
2017-08-11 20:52:06 +02:00
masternode_info_t { MASTERNODE_ENABLED , nProtocolVersionIn , GetAdjustedTime ( ) ,
2017-09-11 16:13:48 +02:00
outpoint , addr , pubKeyCollateralAddress , pubKeyMasternode } ,
2017-08-11 20:52:06 +02:00
fAllowMixingTx ( true )
2016-09-16 00:00:06 +02:00
{ }
CMasternode : : CMasternode ( const CMasternode & other ) :
2017-08-11 20:52:06 +02:00
masternode_info_t { other } ,
2016-09-16 00:00:06 +02:00
lastPing ( other . lastPing ) ,
vchSig ( other . vchSig ) ,
2017-09-14 15:58:29 +02:00
nCollateralMinConfBlockHash ( other . nCollateralMinConfBlockHash ) ,
2016-09-16 00:00:06 +02:00
nBlockLastPaid ( other . nBlockLastPaid ) ,
2016-10-20 23:11:30 +02:00
nPoSeBanScore ( other . nPoSeBanScore ) ,
2016-10-30 21:56:47 +01:00
nPoSeBanHeight ( other . nPoSeBanHeight ) ,
2016-09-16 00:00:06 +02:00
fAllowMixingTx ( other . fAllowMixingTx ) ,
fUnitTest ( other . fUnitTest )
{ }
CMasternode : : CMasternode ( const CMasternodeBroadcast & mnb ) :
2017-08-11 20:52:06 +02:00
masternode_info_t { mnb . nActiveState , mnb . nProtocolVersion , mnb . sigTime ,
2017-09-11 16:13:48 +02:00
mnb . vin . prevout , mnb . addr , mnb . pubKeyCollateralAddress , mnb . pubKeyMasternode ,
2017-08-11 20:52:06 +02:00
mnb . sigTime /*nTimeLastWatchdogVote*/ } ,
2016-09-16 00:00:06 +02:00
lastPing ( mnb . lastPing ) ,
vchSig ( mnb . vchSig ) ,
2017-08-11 20:52:06 +02:00
fAllowMixingTx ( true )
2016-09-16 00:00:06 +02:00
{ }
2015-04-17 17:10:38 +02:00
//
// When a new masternode broadcast is sent, update our information
//
2017-09-19 16:51:38 +02:00
bool CMasternode : : UpdateFromNewBroadcast ( CMasternodeBroadcast & mnb , CConnman & connman )
2015-04-17 17:10:38 +02:00
{
2017-01-01 18:48:53 +01:00
if ( mnb . sigTime < = sigTime & & ! mnb . fRecovery ) return false ;
2016-10-20 23:11:30 +02:00
pubKeyMasternode = mnb . pubKeyMasternode ;
sigTime = mnb . sigTime ;
vchSig = mnb . vchSig ;
nProtocolVersion = mnb . nProtocolVersion ;
addr = mnb . addr ;
nPoSeBanScore = 0 ;
2016-10-30 21:56:47 +01:00
nPoSeBanHeight = 0 ;
2016-10-20 23:11:30 +02:00
nTimeLastChecked = 0 ;
int nDos = 0 ;
2017-09-19 16:51:38 +02:00
if ( mnb . lastPing = = CMasternodePing ( ) | | ( mnb . lastPing ! = CMasternodePing ( ) & & mnb . lastPing . CheckAndUpdate ( this , true , nDos , connman ) ) ) {
2016-10-20 23:11:30 +02:00
lastPing = mnb . lastPing ;
mnodeman . mapSeenMasternodePing . insert ( std : : make_pair ( lastPing . GetHash ( ) , lastPing ) ) ;
}
// if it matches our Masternode privkey...
if ( fMasterNode & & pubKeyMasternode = = activeMasternode . pubKeyMasternode ) {
nPoSeBanScore = - MASTERNODE_POSE_BAN_MAX_SCORE ;
if ( nProtocolVersion = = PROTOCOL_VERSION ) {
// ... and PROTOCOL_VERSION, then we've been remotely activated ...
2017-09-19 16:51:38 +02:00
activeMasternode . ManageState ( connman ) ;
2016-10-20 23:11:30 +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 ( " CMasternode::UpdateFromNewBroadcast -- wrong PROTOCOL_VERSION, re-activate your MN: message nProtocolVersion=%d PROTOCOL_VERSION=%d \n " , nProtocolVersion , PROTOCOL_VERSION ) ;
return false ;
2015-08-12 03:39:22 +02:00
}
2015-07-14 07:25:07 +02:00
}
2016-10-20 23:11:30 +02:00
return true ;
2015-02-23 21:01:21 +01:00
}
2014-12-09 02:17:57 +01:00
//
2015-03-05 09:11:56 +01:00
// Deterministically calculate a given "score" for a Masternode depending on how close it's hash is to
2014-12-09 02:17:57 +01:00
// the proof of work for that block. The further away they are the better, the furthest will win the election
// and get paid this block
//
2016-10-13 11:45:18 +02:00
arith_uint256 CMasternode : : CalculateScore ( const uint256 & blockHash )
2014-12-09 02:17:57 +01:00
{
2017-12-07 10:43:23 +01:00
// Deterministically calculate a "score" for a Masternode based on any given (block)hash
2015-07-24 17:50:10 +02:00
CHashWriter ss ( SER_GETHASH , PROTOCOL_VERSION ) ;
2017-12-07 10:43:23 +01:00
ss < < vin . prevout < < nCollateralMinConfBlockHash < < blockHash ;
return UintToArith256 ( ss . GetHash ( ) ) ;
2014-12-09 02:17:57 +01:00
}
2017-12-21 14:03:02 +01:00
CMasternode : : CollateralStatus CMasternode : : CheckCollateral ( const COutPoint & outpoint , const CPubKey & pubkey )
2017-07-13 11:38:00 +02:00
{
int nHeight ;
2017-12-21 14:03:02 +01:00
return CheckCollateral ( outpoint , pubkey , nHeight ) ;
2017-07-13 11:38:00 +02:00
}
2017-12-21 14:03:02 +01:00
CMasternode : : CollateralStatus CMasternode : : CheckCollateral ( const COutPoint & outpoint , const CPubKey & pubkey , int & nHeightRet )
2017-07-13 11:38:00 +02:00
{
AssertLockHeld ( cs_main ) ;
2017-09-26 16:33:46 +02:00
Coin coin ;
if ( ! GetUTXOCoin ( outpoint , coin ) ) {
2017-07-13 11:38:00 +02:00
return COLLATERAL_UTXO_NOT_FOUND ;
}
2017-09-26 16:33:46 +02:00
if ( coin . out . nValue ! = 1000 * COIN ) {
2017-07-13 11:38:00 +02:00
return COLLATERAL_INVALID_AMOUNT ;
}
2017-12-21 14:03:02 +01:00
if ( pubkey = = CPubKey ( ) | | coin . out . scriptPubKey ! = GetScriptForDestination ( pubkey . GetID ( ) ) ) {
return COLLATERAL_INVALID_PUBKEY ;
}
2017-09-26 16:33:46 +02:00
nHeightRet = coin . nHeight ;
2017-07-13 11:38:00 +02:00
return COLLATERAL_OK ;
}
2016-09-16 00:00:06 +02:00
void CMasternode : : Check ( bool fForce )
2014-12-09 02:17:57 +01:00
{
2016-10-17 20:54:28 +02:00
LOCK ( cs ) ;
2015-07-03 00:09:14 +02:00
if ( ShutdownRequested ( ) ) return ;
2016-09-16 00:00:06 +02:00
if ( ! fForce & & ( GetTime ( ) - nTimeLastChecked < MASTERNODE_CHECK_SECONDS ) ) return ;
nTimeLastChecked = GetTime ( ) ;
2015-08-08 12:36:30 +02:00
2016-11-30 02:33:47 +01:00
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
//once spent, stop doing the checks
2016-12-24 03:49:13 +01:00
if ( IsOutpointSpent ( ) ) return ;
2016-11-30 02:33:47 +01:00
2016-10-30 21:56:47 +01:00
int nHeight = 0 ;
2016-10-20 23:11:30 +02:00
if ( ! fUnitTest ) {
TRY_LOCK ( cs_main , lockMain ) ;
if ( ! lockMain ) return ;
2017-12-21 14:03:02 +01:00
Coin coin ;
if ( ! GetUTXOCoin ( vin . prevout , coin ) ) {
2016-10-20 23:11:30 +02:00
nActiveState = MASTERNODE_OUTPOINT_SPENT ;
LogPrint ( " masternode " , " CMasternode::Check -- Failed to find Masternode UTXO, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return ;
}
2016-10-17 20:54:28 +02:00
2016-10-30 21:56:47 +01:00
nHeight = chainActive . Height ( ) ;
}
2015-08-08 12:36:30 +02:00
2016-12-24 03:49:13 +01:00
if ( IsPoSeBanned ( ) ) {
2016-10-30 21:56:47 +01:00
if ( nHeight < nPoSeBanHeight ) return ; // too early?
// Otherwise give it a chance to proceed further to do all the usual checks and to change its state.
// Masternode still will be on the edge and can be banned back easily if it keeps ignoring mnverify
// or connect attempts. Will require few mnverify messages to strengthen its position in mn list.
LogPrintf ( " CMasternode::Check -- Masternode %s is unbanned and back in list now \n " , vin . prevout . ToStringShort ( ) ) ;
DecreasePoSeBanScore ( ) ;
2016-10-20 23:11:30 +02:00
} else if ( nPoSeBanScore > = MASTERNODE_POSE_BAN_MAX_SCORE ) {
nActiveState = MASTERNODE_POSE_BAN ;
2016-10-30 21:56:47 +01:00
// ban for the whole payment cycle
nPoSeBanHeight = nHeight + mnodeman . size ( ) ;
LogPrintf ( " CMasternode::Check -- Masternode %s is banned till block %d now \n " , vin . prevout . ToStringShort ( ) , nPoSeBanHeight ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2016-12-06 20:50:54 +01:00
int nActiveStatePrev = nActiveState ;
2016-12-24 03:49:13 +01:00
bool fOurMasternode = fMasterNode & & activeMasternode . pubKeyMasternode = = pubKeyMasternode ;
2016-12-06 20:50:54 +01:00
2016-10-30 21:56:47 +01:00
// masternode doesn't meet payment protocol requirements ...
2016-12-24 03:49:13 +01:00
bool fRequireUpdate = nProtocolVersion < mnpayments . GetMinMasternodePaymentsProto ( ) | |
2016-10-30 21:56:47 +01:00
// or it's our own node and we just updated it to the new protocol but we are still waiting for activation ...
2016-12-24 03:49:13 +01:00
( fOurMasternode & & nProtocolVersion < PROTOCOL_VERSION ) ;
2016-10-30 21:56:47 +01:00
2016-12-24 03:49:13 +01:00
if ( fRequireUpdate ) {
nActiveState = MASTERNODE_UPDATE_REQUIRED ;
2016-12-06 20:50:54 +01:00
if ( nActiveStatePrev ! = nActiveState ) {
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state now \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
}
2014-12-09 02:17:57 +01:00
return ;
}
2016-12-24 03:49:13 +01:00
// keep old masternodes on start, give them a chance to receive updates...
bool fWaitForPing = ! masternodeSync . IsMasternodeListSynced ( ) & & ! IsPingedWithin ( MASTERNODE_MIN_MNP_SECONDS ) ;
2016-10-20 23:11:30 +02:00
2016-12-24 03:49:13 +01:00
if ( fWaitForPing & & ! fOurMasternode ) {
// ...but if it was already expired before the initial check - return right away
if ( IsExpired ( ) | | IsWatchdogExpired ( ) | | IsNewStartRequired ( ) ) {
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state, waiting for ping \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
return ;
2016-12-06 20:50:54 +01:00
}
2016-03-16 16:30:22 +01:00
}
2016-12-24 03:49:13 +01:00
// don't expire if we are still in "waiting for ping" mode unless it's our own masternode
if ( ! fWaitForPing | | fOurMasternode ) {
2016-12-02 18:42:45 +01:00
2016-12-24 03:49:13 +01:00
if ( ! IsPingedWithin ( MASTERNODE_NEW_START_REQUIRED_SECONDS ) ) {
nActiveState = MASTERNODE_NEW_START_REQUIRED ;
if ( nActiveStatePrev ! = nActiveState ) {
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state now \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
}
return ;
}
bool fWatchdogActive = masternodeSync . IsSynced ( ) & & mnodeman . IsWatchdogActive ( ) ;
2017-08-29 01:51:44 +02:00
bool fWatchdogExpired = ( fWatchdogActive & & ( ( GetAdjustedTime ( ) - nTimeLastWatchdogVote ) > MASTERNODE_WATCHDOG_MAX_SECONDS ) ) ;
2016-12-24 03:49:13 +01:00
2017-08-29 01:51:44 +02:00
LogPrint ( " masternode " , " CMasternode::Check -- outpoint=%s, nTimeLastWatchdogVote=%d, GetAdjustedTime()=%d, fWatchdogExpired=%d \n " ,
vin . prevout . ToStringShort ( ) , nTimeLastWatchdogVote , GetAdjustedTime ( ) , fWatchdogExpired ) ;
2016-12-24 03:49:13 +01:00
if ( fWatchdogExpired ) {
nActiveState = MASTERNODE_WATCHDOG_EXPIRED ;
if ( nActiveStatePrev ! = nActiveState ) {
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state now \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
}
return ;
}
if ( ! IsPingedWithin ( MASTERNODE_EXPIRATION_SECONDS ) ) {
nActiveState = MASTERNODE_EXPIRED ;
if ( nActiveStatePrev ! = nActiveState ) {
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state now \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
}
return ;
2016-12-06 20:50:54 +01:00
}
2014-12-09 02:17:57 +01:00
}
2017-12-20 12:45:01 +01:00
// Allow MNs to become ENABLED immediately in regtest/devnet
// On mainnet/testnet, we require them to be in PRE_ENABLED state for some time before they get into ENABLED state
if ( Params ( ) . NetworkIDString ( ) ! = CBaseChainParams : : REGTEST & & Params ( ) . NetworkIDString ( ) ! = CBaseChainParams : : DEVNET ) {
if ( lastPing . sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS ) {
nActiveState = MASTERNODE_PRE_ENABLED ;
if ( nActiveStatePrev ! = nActiveState ) {
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state now \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
}
return ;
2016-12-06 20:50:54 +01:00
}
2016-10-17 20:54:28 +02:00
}
2016-09-16 00:00:06 +02:00
nActiveState = MASTERNODE_ENABLED ; // OK
2016-12-06 20:50:54 +01:00
if ( nActiveStatePrev ! = nActiveState ) {
LogPrint ( " masternode " , " CMasternode::Check -- Masternode %s is in %s state now \n " , vin . prevout . ToStringShort ( ) , GetStateString ( ) ) ;
}
2016-09-16 00:00:06 +02:00
}
2016-10-10 11:13:07 +02:00
bool CMasternode : : IsValidNetAddr ( )
2016-12-15 17:27:24 +01:00
{
return IsValidNetAddr ( addr ) ;
}
bool CMasternode : : IsValidNetAddr ( CService addrIn )
2016-10-10 11:13:07 +02:00
{
// TODO: regtest is fine with any addresses for now,
// should probably be a bit smarter if one day we start to implement tests for this
return Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : REGTEST | |
2016-12-15 17:27:24 +01:00
( addrIn . IsIPv4 ( ) & & IsReachable ( addrIn ) & & addrIn . IsRoutable ( ) ) ;
2016-10-10 11:13:07 +02:00
}
2016-10-17 20:54:28 +02:00
masternode_info_t CMasternode : : GetInfo ( )
{
2017-08-11 20:52:06 +02:00
masternode_info_t info { * this } ;
2017-02-10 01:56:52 +01:00
info . nTimeLastPing = lastPing . sigTime ;
2016-10-17 20:54:28 +02:00
info . fInfoValid = true ;
return info ;
}
2016-10-26 23:21:39 +02:00
std : : string CMasternode : : StateToString ( int nStateIn )
2016-09-16 00:00:06 +02:00
{
2016-10-26 23:21:39 +02:00
switch ( nStateIn ) {
2016-12-24 03:49:13 +01:00
case MASTERNODE_PRE_ENABLED : return " PRE_ENABLED " ;
case MASTERNODE_ENABLED : return " ENABLED " ;
case MASTERNODE_EXPIRED : return " EXPIRED " ;
case MASTERNODE_OUTPOINT_SPENT : return " OUTPOINT_SPENT " ;
case MASTERNODE_UPDATE_REQUIRED : return " UPDATE_REQUIRED " ;
case MASTERNODE_WATCHDOG_EXPIRED : return " WATCHDOG_EXPIRED " ;
case MASTERNODE_NEW_START_REQUIRED : return " NEW_START_REQUIRED " ;
case MASTERNODE_POSE_BAN : return " POSE_BAN " ;
default : return " UNKNOWN " ;
2016-09-16 00:00:06 +02:00
}
2015-04-17 17:10:38 +02:00
}
2016-10-26 23:21:39 +02:00
std : : string CMasternode : : GetStateString ( ) const
{
return StateToString ( nActiveState ) ;
}
std : : string CMasternode : : GetStatus ( ) const
{
// TODO: return smth a bit more human readable here
return GetStateString ( ) ;
}
2016-09-11 22:22:37 +02:00
void CMasternode : : UpdateLastPaid ( const CBlockIndex * pindex , int nMaxBlocksToScanBack )
{
if ( ! pindex ) return ;
2015-07-21 00:09:42 +02:00
2016-09-11 22:22:37 +02:00
const CBlockIndex * BlockReading = pindex ;
2015-07-22 01:11:49 +02:00
2016-09-16 00:00:06 +02:00
CScript mnpayee = GetScriptForDestination ( pubKeyCollateralAddress . GetID ( ) ) ;
2016-09-11 22:22:37 +02:00
// LogPrint("masternode", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s\n", vin.prevout.ToStringShort());
2015-07-22 01:11:49 +02:00
2016-09-11 22:22:37 +02:00
LOCK ( cs_mapMasternodeBlocks ) ;
2015-07-22 01:57:21 +02:00
2016-09-11 22:22:37 +02:00
for ( int i = 0 ; BlockReading & & BlockReading - > nHeight > nBlockLastPaid & & i < nMaxBlocksToScanBack ; i + + ) {
if ( mnpayments . mapMasternodeBlocks . count ( BlockReading - > nHeight ) & &
mnpayments . mapMasternodeBlocks [ BlockReading - > nHeight ] . HasPayeeWithVotes ( mnpayee , 2 ) )
{
CBlock block ;
if ( ! ReadBlockFromDisk ( block , BlockReading , Params ( ) . GetConsensus ( ) ) ) // shouldn't really happen
continue ;
2016-11-21 10:51:32 +01:00
CAmount nMasternodePayment = GetMasternodePayment ( BlockReading - > nHeight , block . vtx [ 0 ] - > GetValueOut ( ) ) ;
2016-09-11 22:22:37 +02:00
2016-11-21 10:51:32 +01:00
BOOST_FOREACH ( CTxOut txout , block . vtx [ 0 ] - > vout )
2016-09-11 22:22:37 +02:00
if ( mnpayee = = txout . scriptPubKey & & nMasternodePayment = = txout . nValue ) {
nBlockLastPaid = BlockReading - > nHeight ;
nTimeLastPaid = BlockReading - > nTime ;
LogPrint ( " masternode " , " CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- found new %d \n " , vin . prevout . ToStringShort ( ) , nBlockLastPaid ) ;
return ;
}
2015-07-21 00:09:42 +02:00
}
2015-07-22 01:57:21 +02:00
if ( BlockReading - > pprev = = NULL ) { assert ( BlockReading ) ; break ; }
BlockReading = BlockReading - > pprev ;
2015-07-21 00:09:42 +02:00
}
2015-06-23 18:38:28 +02:00
2016-09-11 22:22:37 +02:00
// Last payment for this masternode wasn't found in latest mnpayments blocks
// or it was found in mnpayments blocks but wasn't found in the blockchain.
// LogPrint("masternode", "CMasternode::UpdateLastPaidBlock -- searching for block with payment to %s -- keeping old %d\n", vin.prevout.ToStringShort(), nBlockLastPaid);
2015-06-23 18:38:28 +02:00
}
2017-12-01 19:53:34 +01:00
# ifdef ENABLE_WALLET
2016-09-05 18:09:25 +02:00
bool CMasternodeBroadcast : : Create ( std : : string strService , std : : string strKeyMasternode , std : : string strTxHash , std : : string strOutputIndex , std : : string & strErrorRet , CMasternodeBroadcast & mnbRet , bool fOffline )
2016-07-29 07:32:08 +02:00
{
2017-09-11 16:13:48 +02:00
COutPoint outpoint ;
2016-09-16 00:00:06 +02:00
CPubKey pubKeyCollateralAddressNew ;
CKey keyCollateralAddressNew ;
2016-07-29 07:32:08 +02:00
CPubKey pubKeyMasternodeNew ;
CKey keyMasternodeNew ;
2017-08-11 20:52:06 +02:00
auto Log = [ & strErrorRet ] ( std : : string sErr ) - > bool
{
strErrorRet = sErr ;
2016-09-05 18:09:25 +02:00
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
2016-07-29 07:32:08 +02:00
return false ;
2017-08-11 20:52:06 +02:00
} ;
2016-07-29 07:32:08 +02:00
2017-08-11 20:52:06 +02:00
//need correct blocks to send ping
if ( ! fOffline & & ! masternodeSync . IsBlockchainSynced ( ) )
return Log ( " Sync in progress. Must wait until sync is complete to start Masternode " ) ;
2016-07-29 07:32:08 +02:00
2017-08-11 20:52:06 +02:00
if ( ! CMessageSigner : : GetKeysFromSecret ( strKeyMasternode , keyMasternodeNew , pubKeyMasternodeNew ) )
return Log ( strprintf ( " Invalid masternode key %s " , strKeyMasternode ) ) ;
2017-09-11 16:13:48 +02:00
if ( ! pwalletMain - > GetMasternodeOutpointAndKeys ( outpoint , pubKeyCollateralAddressNew , keyCollateralAddressNew , strTxHash , strOutputIndex ) )
return Log ( strprintf ( " Could not allocate outpoint %s:%s for masternode %s " , strTxHash , strOutputIndex , strService ) ) ;
2016-07-29 07:32:08 +02:00
2017-09-03 15:29:10 +02:00
CService service ;
if ( ! Lookup ( strService . c_str ( ) , service , 0 , false ) )
return Log ( strprintf ( " Invalid address %s for masternode. " , strService ) ) ;
2016-09-05 18:09:25 +02:00
int mainnetDefaultPort = Params ( CBaseChainParams : : MAIN ) . GetDefaultPort ( ) ;
2017-08-11 20:52:06 +02:00
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN ) {
if ( service . GetPort ( ) ! = mainnetDefaultPort )
return Log ( strprintf ( " Invalid port %u for masternode %s, only %d is supported on mainnet. " , service . GetPort ( ) , strService , mainnetDefaultPort ) ) ;
} else if ( service . GetPort ( ) = = mainnetDefaultPort )
return Log ( strprintf ( " Invalid port %u for masternode %s, %d is the only supported on mainnet. " , service . GetPort ( ) , strService , mainnetDefaultPort ) ) ;
2016-07-29 07:32:08 +02:00
2017-09-11 16:13:48 +02:00
return Create ( outpoint , service , keyCollateralAddressNew , pubKeyCollateralAddressNew , keyMasternodeNew , pubKeyMasternodeNew , strErrorRet , mnbRet ) ;
2016-07-29 07:32:08 +02:00
}
2017-09-11 16:13:48 +02:00
bool CMasternodeBroadcast : : Create ( const COutPoint & outpoint , const CService & service , const CKey & keyCollateralAddressNew , const CPubKey & pubKeyCollateralAddressNew , const CKey & keyMasternodeNew , const CPubKey & pubKeyMasternodeNew , std : : string & strErrorRet , CMasternodeBroadcast & mnbRet )
2016-07-29 07:32:08 +02:00
{
// wait for reindex and/or import to finish
if ( fImporting | | fReindex ) return false ;
2016-10-25 16:37:33 +02:00
LogPrint ( " masternode " , " CMasternodeBroadcast::Create -- pubKeyCollateralAddressNew = %s, pubKeyMasternodeNew.GetID() = %s \n " ,
CBitcoinAddress ( pubKeyCollateralAddressNew . GetID ( ) ) . ToString ( ) ,
pubKeyMasternodeNew . GetID ( ) . ToString ( ) ) ;
2017-08-11 20:52:06 +02:00
auto Log = [ & strErrorRet , & mnbRet ] ( std : : string sErr ) - > bool
{
strErrorRet = sErr ;
2016-10-22 18:52:14 +02:00
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
2016-09-05 18:09:25 +02:00
mnbRet = CMasternodeBroadcast ( ) ;
2016-07-29 07:32:08 +02:00
return false ;
2017-08-11 20:52:06 +02:00
} ;
2017-09-11 16:13:48 +02:00
CMasternodePing mnp ( outpoint ) ;
2017-08-11 20:52:06 +02:00
if ( ! mnp . Sign ( keyMasternodeNew , pubKeyMasternodeNew ) )
2017-09-11 16:13:48 +02:00
return Log ( strprintf ( " Failed to sign ping, masternode=%s " , outpoint . ToStringShort ( ) ) ) ;
2016-07-29 07:32:08 +02:00
2017-09-11 16:13:48 +02:00
mnbRet = CMasternodeBroadcast ( service , outpoint , pubKeyCollateralAddressNew , pubKeyMasternodeNew , PROTOCOL_VERSION ) ;
2016-10-10 11:13:07 +02:00
2017-08-11 20:52:06 +02:00
if ( ! mnbRet . IsValidNetAddr ( ) )
2017-09-11 16:13:48 +02:00
return Log ( strprintf ( " Invalid IP address, masternode=%s " , outpoint . ToStringShort ( ) ) ) ;
2016-10-10 11:13:07 +02:00
2016-09-05 18:09:25 +02:00
mnbRet . lastPing = mnp ;
2017-08-11 20:52:06 +02:00
if ( ! mnbRet . Sign ( keyCollateralAddressNew ) )
2017-09-11 16:13:48 +02:00
return Log ( strprintf ( " Failed to sign broadcast, masternode=%s " , outpoint . ToStringShort ( ) ) ) ;
2016-07-29 07:32:08 +02:00
return true ;
}
2017-12-01 19:53:34 +01:00
# endif // ENABLE_WALLET
2016-07-29 07:32:08 +02:00
2016-10-20 23:11:30 +02:00
bool CMasternodeBroadcast : : SimpleCheck ( int & nDos )
2015-04-17 17:10:38 +02:00
{
2016-06-03 06:59:19 +02:00
nDos = 0 ;
2016-10-20 23:11:30 +02:00
// make sure addr is valid
if ( ! IsValidNetAddr ( ) ) {
LogPrintf ( " CMasternodeBroadcast::SimpleCheck -- Invalid addr, rejected: masternode=%s addr=%s \n " ,
vin . prevout . ToStringShort ( ) , addr . ToString ( ) ) ;
return false ;
}
2015-04-17 17:10:38 +02:00
// make sure signature isn't in the future (past is OK)
if ( sigTime > GetAdjustedTime ( ) + 60 * 60 ) {
2016-10-20 23:11:30 +02:00
LogPrintf ( " CMasternodeBroadcast::SimpleCheck -- Signature rejected, too far into the future: masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
2015-07-14 07:25:07 +02:00
nDos = 1 ;
2015-04-17 17:10:38 +02:00
return false ;
}
2016-11-30 20:32:36 +01:00
// empty ping or incorrect sigTime/unknown blockhash
if ( lastPing = = CMasternodePing ( ) | | ! lastPing . SimpleCheck ( nDos ) ) {
2016-12-24 03:49:13 +01:00
// one of us is probably forked or smth, just mark it as expired and check the rest of the rules
nActiveState = MASTERNODE_EXPIRED ;
2016-09-05 18:09:25 +02:00
}
2016-03-16 16:30:22 +01:00
2016-09-16 00:00:06 +02:00
if ( nProtocolVersion < mnpayments . GetMinMasternodePaymentsProto ( ) ) {
2016-10-20 23:11:30 +02:00
LogPrintf ( " CMasternodeBroadcast::SimpleCheck -- ignoring outdated Masternode: masternode=%s nProtocolVersion=%d \n " , vin . prevout . ToStringShort ( ) , nProtocolVersion ) ;
2015-04-17 17:10:38 +02:00
return false ;
}
CScript pubkeyScript ;
2016-09-16 00:00:06 +02:00
pubkeyScript = GetScriptForDestination ( pubKeyCollateralAddress . GetID ( ) ) ;
2015-04-17 17:10:38 +02:00
if ( pubkeyScript . size ( ) ! = 25 ) {
2016-10-20 23:11:30 +02:00
LogPrintf ( " CMasternodeBroadcast::SimpleCheck -- pubKeyCollateralAddress has the wrong size \n " ) ;
2015-04-17 17:10:38 +02:00
nDos = 100 ;
return false ;
}
CScript pubkeyScript2 ;
2016-09-16 00:00:06 +02:00
pubkeyScript2 = GetScriptForDestination ( pubKeyMasternode . GetID ( ) ) ;
2015-04-17 17:10:38 +02:00
if ( pubkeyScript2 . size ( ) ! = 25 ) {
2016-10-20 23:11:30 +02:00
LogPrintf ( " CMasternodeBroadcast::SimpleCheck -- pubKeyMasternode has the wrong size \n " ) ;
2015-04-17 17:10:38 +02:00
nDos = 100 ;
return false ;
}
if ( ! vin . scriptSig . empty ( ) ) {
2016-10-20 23:11:30 +02:00
LogPrintf ( " CMasternodeBroadcast::SimpleCheck -- Ignore Not Empty ScriptSig %s \n " , vin . ToString ( ) ) ;
2016-12-24 03:49:13 +01:00
nDos = 100 ;
2015-04-17 17:10:38 +02:00
return false ;
}
2016-02-17 17:00:17 +01:00
int mainnetDefaultPort = Params ( CBaseChainParams : : MAIN ) . GetDefaultPort ( ) ;
2016-02-02 16:28:56 +01:00
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN ) {
2016-02-17 17:00:17 +01:00
if ( addr . GetPort ( ) ! = mainnetDefaultPort ) return false ;
} else if ( addr . GetPort ( ) = = mainnetDefaultPort ) return false ;
2015-04-17 17:10:38 +02:00
2016-10-20 23:11:30 +02:00
return true ;
}
2015-06-20 21:56:56 +02:00
2017-09-19 16:51:38 +02:00
bool CMasternodeBroadcast : : Update ( CMasternode * pmn , int & nDos , CConnman & connman )
2016-10-20 23:11:30 +02:00
{
2016-12-24 03:49:13 +01:00
nDos = 0 ;
2017-01-01 18:48:53 +01:00
if ( pmn - > sigTime = = sigTime & & ! fRecovery ) {
2016-10-20 23:11:30 +02:00
// mapSeenMasternodeBroadcast in CMasternodeMan::CheckMnbAndUpdateMasternodeList should filter legit duplicates
// but this still can happen if we just started, which is ok, just do nothing here.
2016-12-24 03:49:13 +01:00
return false ;
2016-10-20 23:11:30 +02:00
}
2016-03-16 16:30:22 +01:00
2016-10-20 23:11:30 +02:00
// this broadcast is older than the one that we already have - it's bad and should never happen
2016-03-16 16:30:22 +01:00
// unless someone is doing something fishy
2016-10-20 23:11:30 +02:00
if ( pmn - > sigTime > sigTime ) {
LogPrintf ( " CMasternodeBroadcast::Update -- Bad sigTime %d (existing broadcast is at %d) for Masternode %s %s \n " ,
2016-09-16 00:00:06 +02:00
sigTime , pmn - > sigTime , vin . prevout . ToStringShort ( ) , addr . ToString ( ) ) ;
2016-03-16 16:30:22 +01:00
return false ;
2016-03-07 09:42:37 +01:00
}
2015-07-14 07:25:07 +02:00
2016-10-20 23:11:30 +02:00
pmn - > Check ( ) ;
// masternode is banned by PoSe
if ( pmn - > IsPoSeBanned ( ) ) {
LogPrintf ( " CMasternodeBroadcast::Update -- Banned by PoSe, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
}
// IsVnAssociatedWithPubkey is validated once in CheckOutpoint, after that they just need to match
if ( pmn - > pubKeyCollateralAddress ! = pubKeyCollateralAddress ) {
2016-12-24 03:49:13 +01:00
LogPrintf ( " CMasternodeBroadcast::Update -- Got mismatched pubKeyCollateralAddress and vin \n " ) ;
2016-10-20 23:11:30 +02:00
nDos = 33 ;
return false ;
}
2016-03-16 16:30:22 +01:00
2016-12-24 03:49:13 +01:00
if ( ! CheckSignature ( nDos ) ) {
LogPrintf ( " CMasternodeBroadcast::Update -- CheckSignature() failed, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
}
2016-10-20 23:11:30 +02:00
// if ther was no masternode broadcast recently or if it matches our Masternode privkey...
if ( ! pmn - > IsBroadcastedWithin ( MASTERNODE_MIN_MNB_SECONDS ) | | ( fMasterNode & & pubKeyMasternode = = activeMasternode . pubKeyMasternode ) ) {
// take the newest entry
LogPrintf ( " CMasternodeBroadcast::Update -- Got UPDATED Masternode entry: addr=%s \n " , addr . ToString ( ) ) ;
2017-09-19 16:51:38 +02:00
if ( pmn - > UpdateFromNewBroadcast ( * this , connman ) ) {
2015-08-12 03:39:22 +02:00
pmn - > Check ( ) ;
2017-09-19 16:51:38 +02:00
Relay ( connman ) ;
2015-08-12 03:39:22 +02:00
}
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " CMasternodeBroadcast::Update " ) ;
2015-04-17 17:10:38 +02:00
}
return true ;
}
2016-10-20 23:11:30 +02:00
bool CMasternodeBroadcast : : CheckOutpoint ( int & nDos )
2015-04-17 17:10:38 +02:00
{
2015-07-14 07:25:07 +02:00
// we are a masternode with the same vin (i.e. already activated) and this mnb is ours (matches our Masternode privkey)
// so nothing to do here for us
2017-09-11 16:13:48 +02:00
if ( fMasterNode & & vin . prevout = = activeMasternode . outpoint & & pubKeyMasternode = = activeMasternode . pubKeyMasternode ) {
2016-03-16 16:30:22 +01:00
return false ;
2016-09-05 18:09:25 +02:00
}
2016-03-16 16:30:22 +01:00
2017-12-21 14:03:02 +01:00
AssertLockHeld ( cs_main ) ;
int nHeight ;
CollateralStatus err = CheckCollateral ( vin . prevout , pubKeyCollateralAddress , nHeight ) ;
if ( err = = COLLATERAL_UTXO_NOT_FOUND ) {
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckOutpoint -- Failed to find Masternode UTXO, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
2016-12-24 03:49:13 +01:00
return false ;
}
2017-12-21 14:03:02 +01:00
if ( err = = COLLATERAL_INVALID_AMOUNT ) {
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should have 1000 DASH, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
nDos = 33 ;
return false ;
}
2017-07-13 11:38:00 +02:00
2017-12-21 14:03:02 +01:00
if ( err = = COLLATERAL_INVALID_PUBKEY ) {
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should match pubKeyCollateralAddress, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
nDos = 33 ;
return false ;
}
2017-07-13 11:38:00 +02:00
2017-12-21 14:03:02 +01:00
if ( chainActive . Height ( ) - nHeight + 1 < Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations ) {
LogPrintf ( " CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO must have at least %d confirmations, masternode=%s \n " ,
Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations , vin . prevout . ToStringShort ( ) ) ;
// UTXO is legit but has not enough confirmations.
// Maybe we miss few blocks, let this mnb be checked again later.
mnodeman . mapSeenMasternodeBroadcast . erase ( GetHash ( ) ) ;
return false ;
2015-07-30 15:44:18 +02:00
}
2015-04-17 17:10:38 +02:00
2016-10-20 23:11:30 +02:00
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO verified \n " ) ;
2016-05-24 02:08:16 +02:00
2017-12-21 14:03:02 +01:00
// Verify that sig time is legit, should be at least not earlier than the timestamp of the block
// at which collateral became nMasternodeMinimumConfirmations blocks deep.
// NOTE: this is not accurate because block timestamp is NOT guaranteed to be 100% correct one.
CBlockIndex * pRequiredConfIndex = chainActive [ nHeight + Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations - 1 ] ; // block where tx got nMasternodeMinimumConfirmations
if ( pRequiredConfIndex - > GetBlockTime ( ) > sigTime ) {
LogPrintf ( " CMasternodeBroadcast::CheckOutpoint -- Bad sigTime %d (%d conf block is at %d) for Masternode %s %s \n " ,
sigTime , Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations , pRequiredConfIndex - > GetBlockTime ( ) , vin . prevout . ToStringShort ( ) , addr . ToString ( ) ) ;
2015-07-30 15:44:18 +02:00
return false ;
}
2015-04-17 17:10:38 +02:00
2017-12-21 14:03:02 +01:00
if ( ! CheckSignature ( nDos ) ) {
LogPrintf ( " CMasternodeBroadcast::CheckOutpoint -- CheckSignature() failed, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
2015-07-30 15:44:18 +02:00
}
2016-05-24 02:08:16 +02:00
2017-12-21 14:03:02 +01:00
// remember the block hash when collateral for this masternode had minimum required confirmations
nCollateralMinConfBlockHash = pRequiredConfIndex - > GetBlockHash ( ) ;
2015-07-30 15:44:18 +02:00
return true ;
2015-04-17 17:10:38 +02:00
}
2017-09-11 16:13:48 +02:00
bool CMasternodeBroadcast : : Sign ( const CKey & keyCollateralAddress )
2015-06-24 01:44:31 +02:00
{
2016-08-19 13:50:04 +02:00
std : : string strError ;
2016-06-03 06:59:19 +02:00
std : : string strMessage ;
2015-04-17 17:10:38 +02:00
sigTime = GetAdjustedTime ( ) ;
2016-06-03 06:59:19 +02:00
strMessage = addr . ToString ( false ) + boost : : lexical_cast < std : : string > ( sigTime ) +
2016-09-16 00:00:06 +02:00
pubKeyCollateralAddress . GetID ( ) . ToString ( ) + pubKeyMasternode . GetID ( ) . ToString ( ) +
boost : : lexical_cast < std : : string > ( nProtocolVersion ) ;
2015-04-17 17:10:38 +02:00
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , keyCollateralAddress ) ) {
2016-08-19 13:50:04 +02:00
LogPrintf ( " CMasternodeBroadcast::Sign -- SignMessage() failed \n " ) ;
2015-04-17 17:10:38 +02:00
return false ;
}
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : VerifyMessage ( pubKeyCollateralAddress , vchSig , strMessage , strError ) ) {
2016-08-19 13:50:04 +02:00
LogPrintf ( " CMasternodeBroadcast::Sign -- VerifyMessage() failed, error: %s \n " , strError ) ;
2016-06-03 06:59:19 +02:00
return false ;
}
2016-03-16 16:30:22 +01:00
return true ;
}
2016-09-16 00:00:06 +02:00
bool CMasternodeBroadcast : : CheckSignature ( int & nDos )
2016-03-16 16:30:22 +01:00
{
2016-05-30 09:31:57 +02:00
std : : string strMessage ;
2016-08-19 13:50:04 +02:00
std : : string strError = " " ;
2016-06-03 06:59:19 +02:00
nDos = 0 ;
2017-03-14 07:22:00 +01:00
strMessage = addr . ToString ( false ) + boost : : lexical_cast < std : : string > ( sigTime ) +
pubKeyCollateralAddress . GetID ( ) . ToString ( ) + pubKeyMasternode . GetID ( ) . ToString ( ) +
boost : : lexical_cast < std : : string > ( nProtocolVersion ) ;
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckSignature -- strMessage: %s pubKeyCollateralAddress address: %s sig: %s \n " , strMessage , CBitcoinAddress ( pubKeyCollateralAddress . GetID ( ) ) . ToString ( ) , EncodeBase64 ( & vchSig [ 0 ] , vchSig . size ( ) ) ) ;
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : VerifyMessage ( pubKeyCollateralAddress , vchSig , strMessage , strError ) ) {
2017-03-14 07:22:00 +01:00
LogPrintf ( " CMasternodeBroadcast::CheckSignature -- Got bad Masternode announce signature, error: %s \n " , strError ) ;
nDos = 100 ;
return false ;
2015-04-17 17:10:38 +02:00
}
return true ;
}
2017-09-19 16:51:38 +02:00
void CMasternodeBroadcast : : Relay ( CConnman & connman )
2015-04-17 17:10:38 +02:00
{
2017-12-14 01:33:58 +01:00
// Do not relay until fully synced
if ( ! masternodeSync . IsSynced ( ) ) {
LogPrint ( " masternode " , " CMasternodeBroadcast::Relay -- won't relay until fully synced \n " ) ;
return ;
}
2016-09-16 00:00:06 +02:00
CInv inv ( MSG_MASTERNODE_ANNOUNCE , GetHash ( ) ) ;
2017-09-19 16:51:38 +02:00
connman . RelayInv ( inv ) ;
2015-04-17 17:10:38 +02:00
}
2017-09-11 16:13:48 +02:00
CMasternodePing : : CMasternodePing ( const COutPoint & outpoint )
2015-04-17 17:10:38 +02:00
{
2016-09-16 00:00:06 +02:00
LOCK ( cs_main ) ;
if ( ! chainActive . Tip ( ) | | chainActive . Height ( ) < 12 ) return ;
2016-03-02 21:57:24 +01:00
2017-09-11 16:13:48 +02:00
vin = CTxIn ( outpoint ) ;
2016-09-16 00:00:06 +02:00
blockHash = chainActive [ chainActive . Height ( ) - 12 ] - > GetBlockHash ( ) ;
2015-07-14 07:25:07 +02:00
sigTime = GetAdjustedTime ( ) ;
2015-04-17 17:10:38 +02:00
}
2017-09-11 16:13:48 +02:00
bool CMasternodePing : : Sign ( const CKey & keyMasternode , const CPubKey & pubKeyMasternode )
2015-04-17 17:10:38 +02:00
{
2016-08-19 13:50:04 +02:00
std : : string strError ;
2015-04-17 17:10:38 +02:00
std : : string strMasterNodeSignMessage ;
2017-07-04 19:31:57 +02:00
// TODO: add sentinel data
2015-04-17 17:10:38 +02:00
sigTime = GetAdjustedTime ( ) ;
2015-06-09 03:36:33 +02:00
std : : string strMessage = vin . ToString ( ) + blockHash . ToString ( ) + boost : : lexical_cast < std : : string > ( sigTime ) ;
2015-04-17 17:10:38 +02:00
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , keyMasternode ) ) {
2016-08-19 13:50:04 +02:00
LogPrintf ( " CMasternodePing::Sign -- SignMessage() failed \n " ) ;
2015-04-17 17:10:38 +02:00
return false ;
}
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : VerifyMessage ( pubKeyMasternode , vchSig , strMessage , strError ) ) {
2016-08-19 13:50:04 +02:00
LogPrintf ( " CMasternodePing::Sign -- VerifyMessage() failed, error: %s \n " , strError ) ;
2015-04-17 17:10:38 +02:00
return false ;
}
return true ;
}
2016-09-16 00:00:06 +02:00
bool CMasternodePing : : CheckSignature ( CPubKey & pubKeyMasternode , int & nDos )
{
2017-07-04 19:31:57 +02:00
// TODO: add sentinel data
2016-03-16 16:30:22 +01:00
std : : string strMessage = vin . ToString ( ) + blockHash . ToString ( ) + boost : : lexical_cast < std : : string > ( sigTime ) ;
2016-08-19 13:50:04 +02:00
std : : string strError = " " ;
2016-06-03 06:59:19 +02:00
nDos = 0 ;
2016-03-16 16:30:22 +01:00
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : VerifyMessage ( pubKeyMasternode , vchSig , strMessage , strError ) ) {
2016-09-16 00:00:06 +02:00
LogPrintf ( " CMasternodePing::CheckSignature -- Got bad Masternode ping signature, masternode=%s, error: %s \n " , vin . prevout . ToStringShort ( ) , strError ) ;
2016-03-16 16:30:22 +01:00
nDos = 33 ;
return false ;
}
return true ;
}
2016-11-30 20:32:36 +01:00
bool CMasternodePing : : SimpleCheck ( int & nDos )
2015-04-17 17:10:38 +02:00
{
2016-11-30 20:32:36 +01:00
// don't ban by default
nDos = 0 ;
2015-04-17 17:10:38 +02:00
if ( sigTime > GetAdjustedTime ( ) + 60 * 60 ) {
2016-11-30 20:32:36 +01:00
LogPrintf ( " CMasternodePing::SimpleCheck -- Signature rejected, too far into the future, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
2015-07-14 07:25:07 +02:00
nDos = 1 ;
2015-04-17 17:10:38 +02:00
return false ;
}
2016-10-20 23:12:42 +02:00
{
2017-07-17 15:59:04 +02:00
AssertLockHeld ( cs_main ) ;
2016-10-20 23:12:42 +02:00
BlockMap : : iterator mi = mapBlockIndex . find ( blockHash ) ;
if ( mi = = mapBlockIndex . end ( ) ) {
2016-11-30 20:32:36 +01:00
LogPrint ( " masternode " , " CMasternodePing::SimpleCheck -- Masternode ping is invalid, unknown block hash: masternode=%s blockHash=%s \n " , vin . prevout . ToStringShort ( ) , blockHash . ToString ( ) ) ;
2016-10-20 23:12:42 +02:00
// maybe we stuck or forked so we shouldn't ban this node, just fail to accept this ping
// TODO: or should we also request this block?
return false ;
}
2016-11-30 20:32:36 +01:00
}
LogPrint ( " masternode " , " CMasternodePing::SimpleCheck -- Masternode ping verified: masternode=%s blockHash=%s sigTime=%d \n " , vin . prevout . ToStringShort ( ) , blockHash . ToString ( ) , sigTime ) ;
return true ;
}
2017-09-19 16:51:38 +02:00
bool CMasternodePing : : CheckAndUpdate ( CMasternode * pmn , bool fFromNewBroadcast , int & nDos , CConnman & connman )
2016-11-30 20:32:36 +01:00
{
// don't ban by default
nDos = 0 ;
if ( ! SimpleCheck ( nDos ) ) {
return false ;
}
2016-12-24 03:49:13 +01:00
if ( pmn = = NULL ) {
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- Couldn't find Masternode entry, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
}
2016-12-26 07:44:48 +01:00
if ( ! fFromNewBroadcast ) {
if ( pmn - > IsUpdateRequired ( ) ) {
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- masternode protocol is outdated, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
}
if ( pmn - > IsNewStartRequired ( ) ) {
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- masternode is completely expired, new start is required, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
}
}
2016-11-30 20:32:36 +01:00
{
LOCK ( cs_main ) ;
BlockMap : : iterator mi = mapBlockIndex . find ( blockHash ) ;
2016-10-20 23:12:42 +02:00
if ( ( * mi ) . second & & ( * mi ) . second - > nHeight < chainActive . Height ( ) - 24 ) {
LogPrintf ( " CMasternodePing::CheckAndUpdate -- Masternode ping is invalid, block hash is too old: masternode=%s blockHash=%s \n " , vin . prevout . ToStringShort ( ) , blockHash . ToString ( ) ) ;
2016-12-24 03:49:13 +01:00
// nDos = 1;
2016-10-20 23:12:42 +02:00
return false ;
}
}
2016-09-15 15:30:51 +02:00
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- New ping: masternode=%s blockHash=%s sigTime=%d \n " , vin . prevout . ToStringShort ( ) , blockHash . ToString ( ) , sigTime ) ;
2015-07-20 20:43:10 +02:00
2016-09-15 15:30:51 +02:00
// LogPrintf("mnping - Found corresponding mn for vin: %s\n", vin.prevout.ToStringShort());
// update only if there is no known ping for this masternode or
// last ping was more then MASTERNODE_MIN_MNP_SECONDS-60 ago comparing to this one
if ( pmn - > IsPingedWithin ( MASTERNODE_MIN_MNP_SECONDS - 60 , sigTime ) ) {
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- Masternode ping arrived too early, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
//nDos = 1; //disable, this is happening frequently and causing banned peers
return false ;
}
2015-07-14 07:25:07 +02:00
2016-09-16 00:00:06 +02:00
if ( ! CheckSignature ( pmn - > pubKeyMasternode , nDos ) ) return false ;
2015-07-26 06:13:17 +02:00
2017-03-20 02:20:43 +01:00
// so, ping seems to be ok
// if we are still syncing and there was no known ping for this mn for quite a while
// (NOTE: assuming that MASTERNODE_EXPIRATION_SECONDS/2 should be enough to finish mn list sync)
if ( ! masternodeSync . IsMasternodeListSynced ( ) & & ! pmn - > IsPingedWithin ( MASTERNODE_EXPIRATION_SECONDS / 2 ) ) {
// let's bump sync timeout
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- bumping sync timeout, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
2017-08-09 18:07:03 +02:00
masternodeSync . BumpAssetLastTime ( " CMasternodePing::CheckAndUpdate " ) ;
2017-03-20 02:20:43 +01:00
}
// let's store this ping as the last one
2016-09-15 15:30:51 +02:00
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- Masternode ping accepted, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
pmn - > lastPing = * this ;
2015-07-14 07:25:07 +02:00
2016-09-15 15:30:51 +02:00
// and update mnodeman.mapSeenMasternodeBroadcast.lastPing which is probably outdated
CMasternodeBroadcast mnb ( * pmn ) ;
uint256 hash = mnb . GetHash ( ) ;
if ( mnodeman . mapSeenMasternodeBroadcast . count ( hash ) ) {
2016-12-26 07:44:36 +01:00
mnodeman . mapSeenMasternodeBroadcast [ hash ] . second . lastPing = * this ;
2015-04-17 17:10:38 +02:00
}
2017-10-31 15:46:42 +01:00
// force update, ignoring cache
pmn - > Check ( true ) ;
// relay ping for nodes in ENABLED/EXPIRED/WATCHDOG_EXPIRED state only, skip everyone else
if ( ! pmn - > IsEnabled ( ) & & ! pmn - > IsExpired ( ) & & ! pmn - > IsWatchdogExpired ( ) ) return false ;
2016-09-15 15:30:51 +02:00
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- Masternode ping acceepted and relayed, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
2017-09-19 16:51:38 +02:00
Relay ( connman ) ;
2016-09-15 15:30:51 +02:00
return true ;
2015-04-17 17:10:38 +02:00
}
2017-09-19 16:51:38 +02:00
void CMasternodePing : : Relay ( CConnman & connman )
2015-04-17 17:10:38 +02:00
{
2017-12-14 01:33:58 +01:00
// Do not relay until fully synced
if ( ! masternodeSync . IsSynced ( ) ) {
LogPrint ( " masternode " , " CMasternodePing::Relay -- won't relay until fully synced \n " ) ;
return ;
}
2015-04-22 16:33:44 +02:00
CInv inv ( MSG_MASTERNODE_PING , GetHash ( ) ) ;
2017-09-19 16:51:38 +02:00
connman . RelayInv ( inv ) ;
2015-06-09 03:36:33 +02:00
}
2016-08-17 09:08:25 +02:00
void CMasternode : : AddGovernanceVote ( uint256 nGovernanceObjectHash )
{
2016-10-17 20:54:28 +02:00
if ( mapGovernanceObjectsVotedOn . count ( nGovernanceObjectHash ) ) {
mapGovernanceObjectsVotedOn [ nGovernanceObjectHash ] + + ;
2016-08-17 09:08:25 +02:00
} else {
2016-10-17 20:54:28 +02:00
mapGovernanceObjectsVotedOn . insert ( std : : make_pair ( nGovernanceObjectHash , 1 ) ) ;
2016-08-17 09:08:25 +02:00
}
}
2016-10-17 20:54:28 +02:00
void CMasternode : : RemoveGovernanceObject ( uint256 nGovernanceObjectHash )
{
std : : map < uint256 , int > : : iterator it = mapGovernanceObjectsVotedOn . find ( nGovernanceObjectHash ) ;
if ( it = = mapGovernanceObjectsVotedOn . end ( ) ) {
return ;
}
mapGovernanceObjectsVotedOn . erase ( it ) ;
}
2017-07-04 19:31:57 +02:00
void CMasternode : : UpdateWatchdogVoteTime ( uint64_t nVoteTime )
2016-10-17 20:54:28 +02:00
{
LOCK ( cs ) ;
2017-08-29 01:51:44 +02:00
nTimeLastWatchdogVote = ( nVoteTime = = 0 ) ? GetAdjustedTime ( ) : nVoteTime ;
2016-10-17 20:54:28 +02:00
}
2016-09-16 00:00:06 +02:00
/**
2016-08-17 09:08:25 +02:00
* FLAG GOVERNANCE ITEMS AS DIRTY
*
* - When masternode come and go on the network , we must flag the items they voted on to recalc it ' s cached flags
*
*/
void CMasternode : : FlagGovernanceItemsAsDirty ( )
{
2016-10-17 20:54:28 +02:00
std : : vector < uint256 > vecDirty ;
{
std : : map < uint256 , int > : : iterator it = mapGovernanceObjectsVotedOn . begin ( ) ;
while ( it ! = mapGovernanceObjectsVotedOn . end ( ) ) {
vecDirty . push_back ( it - > first ) ;
+ + it ;
}
}
for ( size_t i = 0 ; i < vecDirty . size ( ) ; + + i ) {
mnodeman . AddDirtyGovernanceObjectHash ( vecDirty [ i ] ) ;
2016-08-17 09:08:25 +02:00
}
}