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"
2016-09-16 00:00:06 +02:00
# include "consensus/validation.h"
2016-08-05 21:49:45 +02:00
# include "init.h"
2016-09-16 00:00:06 +02:00
# include "governance.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"
2014-12-09 02:17:57 +01:00
# include "util.h"
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 ( ) :
vin ( ) ,
addr ( ) ,
pubKeyCollateralAddress ( ) ,
pubKeyMasternode ( ) ,
lastPing ( ) ,
vchSig ( ) ,
sigTime ( GetAdjustedTime ( ) ) ,
nLastDsq ( 0 ) ,
nTimeLastChecked ( 0 ) ,
nTimeLastPaid ( 0 ) ,
2016-10-17 20:54:28 +02:00
nTimeLastWatchdogVote ( 0 ) ,
2016-09-16 00:00:06 +02:00
nActiveState ( MASTERNODE_ENABLED ) ,
nCacheCollateralBlock ( 0 ) ,
nBlockLastPaid ( 0 ) ,
nProtocolVersion ( PROTOCOL_VERSION ) ,
2016-10-20 23:11:30 +02:00
nPoSeBanScore ( 0 ) ,
2016-10-30 21:56:47 +01:00
nPoSeBanHeight ( 0 ) ,
2016-09-16 00:00:06 +02:00
fAllowMixingTx ( true ) ,
fUnitTest ( false )
{ }
CMasternode : : CMasternode ( CService addrNew , CTxIn vinNew , CPubKey pubKeyCollateralAddressNew , CPubKey pubKeyMasternodeNew , int nProtocolVersionIn ) :
vin ( vinNew ) ,
addr ( addrNew ) ,
pubKeyCollateralAddress ( pubKeyCollateralAddressNew ) ,
pubKeyMasternode ( pubKeyMasternodeNew ) ,
lastPing ( ) ,
vchSig ( ) ,
sigTime ( GetAdjustedTime ( ) ) ,
nLastDsq ( 0 ) ,
nTimeLastChecked ( 0 ) ,
nTimeLastPaid ( 0 ) ,
2016-10-17 20:54:28 +02:00
nTimeLastWatchdogVote ( 0 ) ,
2016-09-16 00:00:06 +02:00
nActiveState ( MASTERNODE_ENABLED ) ,
nCacheCollateralBlock ( 0 ) ,
nBlockLastPaid ( 0 ) ,
nProtocolVersion ( nProtocolVersionIn ) ,
2016-10-20 23:11:30 +02:00
nPoSeBanScore ( 0 ) ,
2016-10-30 21:56:47 +01:00
nPoSeBanHeight ( 0 ) ,
2016-09-16 00:00:06 +02:00
fAllowMixingTx ( true ) ,
fUnitTest ( false )
{ }
CMasternode : : CMasternode ( const CMasternode & other ) :
vin ( other . vin ) ,
addr ( other . addr ) ,
pubKeyCollateralAddress ( other . pubKeyCollateralAddress ) ,
pubKeyMasternode ( other . pubKeyMasternode ) ,
lastPing ( other . lastPing ) ,
vchSig ( other . vchSig ) ,
sigTime ( other . sigTime ) ,
nLastDsq ( other . nLastDsq ) ,
nTimeLastChecked ( other . nTimeLastChecked ) ,
nTimeLastPaid ( other . nTimeLastPaid ) ,
2016-10-17 20:54:28 +02:00
nTimeLastWatchdogVote ( other . nTimeLastWatchdogVote ) ,
2016-09-16 00:00:06 +02:00
nActiveState ( other . nActiveState ) ,
nCacheCollateralBlock ( other . nCacheCollateralBlock ) ,
nBlockLastPaid ( other . nBlockLastPaid ) ,
nProtocolVersion ( other . nProtocolVersion ) ,
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 ) :
vin ( mnb . vin ) ,
addr ( mnb . addr ) ,
pubKeyCollateralAddress ( mnb . pubKeyCollateralAddress ) ,
pubKeyMasternode ( mnb . pubKeyMasternode ) ,
lastPing ( mnb . lastPing ) ,
vchSig ( mnb . vchSig ) ,
sigTime ( mnb . sigTime ) ,
2016-12-20 00:09:38 +01:00
nLastDsq ( 0 ) ,
2016-09-16 00:00:06 +02:00
nTimeLastChecked ( 0 ) ,
nTimeLastPaid ( 0 ) ,
2016-10-27 18:00:06 +02:00
nTimeLastWatchdogVote ( mnb . sigTime ) ,
2016-12-24 03:49:13 +01:00
nActiveState ( mnb . nActiveState ) ,
2016-09-16 00:00:06 +02:00
nCacheCollateralBlock ( 0 ) ,
nBlockLastPaid ( 0 ) ,
nProtocolVersion ( mnb . nProtocolVersion ) ,
2016-10-20 23:11:30 +02:00
nPoSeBanScore ( 0 ) ,
2016-10-30 21:56:47 +01:00
nPoSeBanHeight ( 0 ) ,
2016-09-16 00:00:06 +02:00
fAllowMixingTx ( true ) ,
fUnitTest ( false )
{ }
2015-04-17 17:10:38 +02:00
//
// When a new masternode broadcast is sent, update our information
//
2015-08-12 03:39:22 +02:00
bool CMasternode : : UpdateFromNewBroadcast ( CMasternodeBroadcast & mnb )
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 ;
2016-12-26 07:44:48 +01:00
if ( mnb . lastPing = = CMasternodePing ( ) | | ( mnb . lastPing ! = CMasternodePing ( ) & & mnb . lastPing . CheckAndUpdate ( this , true , nDos ) ) ) {
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 ...
activeMasternode . ManageState ( ) ;
} else {
// ... otherwise we need to reactivate our node, do not add it to the list and do not relay
// but also do not ban the node we get this message from
LogPrintf ( " 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
{
2016-02-02 16:28:56 +01:00
uint256 aux = ArithToUint256 ( UintToArith256 ( vin . prevout . hash ) + vin . prevout . n ) ;
2015-02-05 23:56:59 +01:00
2015-07-24 17:50:10 +02:00
CHashWriter ss ( SER_GETHASH , PROTOCOL_VERSION ) ;
2016-10-13 11:45:18 +02:00
ss < < blockHash ;
2016-02-02 16:28:56 +01:00
arith_uint256 hash2 = UintToArith256 ( ss . GetHash ( ) ) ;
2015-07-24 17:50:10 +02:00
CHashWriter ss2 ( SER_GETHASH , PROTOCOL_VERSION ) ;
2016-10-13 11:45:18 +02:00
ss2 < < blockHash ;
2015-07-24 17:50:10 +02:00
ss2 < < aux ;
2016-02-02 16:28:56 +01:00
arith_uint256 hash3 = UintToArith256 ( ss2 . GetHash ( ) ) ;
2015-02-07 19:31:15 +01:00
2016-10-13 11:45:18 +02:00
return ( hash3 > hash2 ? hash3 - hash2 : hash2 - hash3 ) ;
2014-12-09 02:17:57 +01:00
}
2017-07-13 11:38:00 +02:00
CMasternode : : CollateralStatus CMasternode : : CheckCollateral ( CTxIn vin )
{
int nHeight ;
return CheckCollateral ( vin , nHeight ) ;
}
CMasternode : : CollateralStatus CMasternode : : CheckCollateral ( CTxIn vin , int & nHeight )
{
AssertLockHeld ( cs_main ) ;
CCoins coins ;
if ( ! pcoinsTip - > GetCoins ( vin . prevout . hash , coins ) | |
( unsigned int ) vin . prevout . n > = coins . vout . size ( ) | |
coins . vout [ vin . prevout . n ] . IsNull ( ) ) {
return COLLATERAL_UTXO_NOT_FOUND ;
}
if ( coins . vout [ vin . prevout . n ] . nValue ! = 1000 * COIN ) {
return COLLATERAL_INVALID_AMOUNT ;
}
nHeight = coins . nHeight ;
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-07-13 11:38:00 +02:00
CollateralStatus err = CheckCollateral ( vin ) ;
if ( err = = COLLATERAL_UTXO_NOT_FOUND ) {
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 ( ) ;
bool fWatchdogExpired = ( fWatchdogActive & & ( ( GetTime ( ) - nTimeLastWatchdogVote ) > MASTERNODE_WATCHDOG_MAX_SECONDS ) ) ;
LogPrint ( " masternode " , " CMasternode::Check -- outpoint=%s, nTimeLastWatchdogVote=%d, GetTime()=%d, fWatchdogExpired=%d \n " ,
vin . prevout . ToStringShort ( ) , nTimeLastWatchdogVote , GetTime ( ) , fWatchdogExpired ) ;
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
}
2016-10-20 23:11:30 +02:00
if ( lastPing . sigTime - sigTime < MASTERNODE_MIN_MNP_SECONDS ) {
nActiveState = MASTERNODE_PRE_ENABLED ;
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-10-17 20:54:28 +02:00
return ;
}
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
}
2017-04-12 09:04:06 +02:00
bool CMasternode : : IsInputAssociatedWithPubkey ( )
{
CScript payee ;
payee = GetScriptForDestination ( pubKeyCollateralAddress . GetID ( ) ) ;
CTransaction tx ;
uint256 hash ;
if ( GetTransaction ( vin . prevout . hash , tx , Params ( ) . GetConsensus ( ) , hash , true ) ) {
BOOST_FOREACH ( CTxOut out , tx . vout )
if ( out . nValue = = 1000 * COIN & & out . scriptPubKey = = payee ) return true ;
}
return false ;
}
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 ( )
{
masternode_info_t info ;
info . vin = vin ;
info . addr = addr ;
info . pubKeyCollateralAddress = pubKeyCollateralAddress ;
info . pubKeyMasternode = pubKeyMasternode ;
info . sigTime = sigTime ;
info . nLastDsq = nLastDsq ;
info . nTimeLastChecked = nTimeLastChecked ;
info . nTimeLastPaid = nTimeLastPaid ;
info . nTimeLastWatchdogVote = nTimeLastWatchdogVote ;
2017-02-10 01:56:52 +01:00
info . nTimeLastPing = lastPing . sigTime ;
2016-10-17 20:54:28 +02:00
info . nActiveState = nActiveState ;
info . nProtocolVersion = nProtocolVersion ;
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
int CMasternode : : GetCollateralAge ( )
{
2016-09-12 20:06:59 +02:00
int nHeight ;
2016-03-02 21:57:24 +01:00
{
2016-09-12 20:06:59 +02:00
TRY_LOCK ( cs_main , lockMain ) ;
if ( ! lockMain | | ! chainActive . Tip ( ) ) return - 1 ;
nHeight = chainActive . Height ( ) ;
}
2016-09-11 22:22:37 +02:00
if ( nCacheCollateralBlock = = 0 ) {
int nInputAge = GetInputAge ( vin ) ;
if ( nInputAge > 0 ) {
2016-09-12 20:06:59 +02:00
nCacheCollateralBlock = nHeight - nInputAge ;
2016-09-11 22:22:37 +02:00
} else {
return nInputAge ;
}
2016-03-02 21:57:24 +01:00
}
2016-09-12 20:06:59 +02:00
return nHeight - nCacheCollateralBlock ;
2016-09-11 22:22:37 +02:00
}
2015-07-21 00:09:42 +02:00
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 ;
CAmount nMasternodePayment = GetMasternodePayment ( BlockReading - > nHeight , block . vtx [ 0 ] . GetValueOut ( ) ) ;
BOOST_FOREACH ( CTxOut txout , block . vtx [ 0 ] . vout )
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
}
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
{
CTxIn txin ;
2016-09-16 00:00:06 +02:00
CPubKey pubKeyCollateralAddressNew ;
CKey keyCollateralAddressNew ;
2016-07-29 07:32:08 +02:00
CPubKey pubKeyMasternodeNew ;
CKey keyMasternodeNew ;
//need correct blocks to send ping
if ( ! fOffline & & ! masternodeSync . IsBlockchainSynced ( ) ) {
2016-09-05 18:09:25 +02:00
strErrorRet = " Sync in progress. Must wait until sync is complete to start Masternode " ;
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
2016-07-29 07:32:08 +02:00
return false ;
}
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : GetKeysFromSecret ( strKeyMasternode , keyMasternodeNew , pubKeyMasternodeNew ) ) {
2016-09-05 18:09:25 +02:00
strErrorRet = strprintf ( " Invalid masternode key %s " , strKeyMasternode ) ;
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
2016-07-29 07:32:08 +02:00
return false ;
}
2016-09-16 00:00:06 +02:00
if ( ! pwalletMain - > GetMasternodeVinAndKeys ( txin , pubKeyCollateralAddressNew , keyCollateralAddressNew , strTxHash , strOutputIndex ) ) {
2016-09-05 18:09:25 +02:00
strErrorRet = strprintf ( " Could not allocate txin %s:%s for masternode %s " , strTxHash , strOutputIndex , strService ) ;
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
2016-07-29 07:32:08 +02:00
return false ;
}
CService service = CService ( strService ) ;
2016-09-05 18:09:25 +02:00
int mainnetDefaultPort = Params ( CBaseChainParams : : MAIN ) . GetDefaultPort ( ) ;
2016-07-29 07:32:08 +02:00
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : MAIN ) {
if ( service . GetPort ( ) ! = mainnetDefaultPort ) {
2016-09-05 18:09:25 +02:00
strErrorRet = strprintf ( " Invalid port %u for masternode %s, only %d is supported on mainnet. " , service . GetPort ( ) , strService , mainnetDefaultPort ) ;
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
2016-07-29 07:32:08 +02:00
return false ;
}
2016-09-05 18:09:25 +02:00
} else if ( service . GetPort ( ) = = mainnetDefaultPort ) {
strErrorRet = strprintf ( " Invalid port %u for masternode %s, %d is the only supported on mainnet. " , service . GetPort ( ) , strService , mainnetDefaultPort ) ;
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
2016-07-29 07:32:08 +02:00
return false ;
}
2016-09-16 00:00:06 +02:00
return Create ( txin , CService ( strService ) , keyCollateralAddressNew , pubKeyCollateralAddressNew , keyMasternodeNew , pubKeyMasternodeNew , strErrorRet , mnbRet ) ;
2016-07-29 07:32:08 +02:00
}
2016-09-16 00:00:06 +02:00
bool CMasternodeBroadcast : : Create ( CTxIn txin , CService service , CKey keyCollateralAddressNew , CPubKey pubKeyCollateralAddressNew , CKey keyMasternodeNew , 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 ( ) ) ;
2016-07-29 07:32:08 +02:00
CMasternodePing mnp ( txin ) ;
if ( ! mnp . Sign ( keyMasternodeNew , pubKeyMasternodeNew ) ) {
2016-09-16 00:00:06 +02:00
strErrorRet = strprintf ( " Failed to sign ping, masternode=%s " , txin . prevout . ToStringShort ( ) ) ;
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 ;
}
2016-09-16 00:00:06 +02:00
mnbRet = CMasternodeBroadcast ( service , txin , pubKeyCollateralAddressNew , pubKeyMasternodeNew , PROTOCOL_VERSION ) ;
2016-10-10 11:13:07 +02:00
if ( ! mnbRet . IsValidNetAddr ( ) ) {
strErrorRet = strprintf ( " Invalid IP address, masternode=%s " , txin . prevout . ToStringShort ( ) ) ;
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
mnbRet = CMasternodeBroadcast ( ) ;
return false ;
}
2016-09-05 18:09:25 +02:00
mnbRet . lastPing = mnp ;
2016-09-16 00:00:06 +02:00
if ( ! mnbRet . Sign ( keyCollateralAddressNew ) ) {
strErrorRet = strprintf ( " Failed to sign broadcast, masternode=%s " , txin . prevout . ToStringShort ( ) ) ;
2016-09-05 18:09:25 +02:00
LogPrintf ( " CMasternodeBroadcast::Create -- %s \n " , strErrorRet ) ;
mnbRet = CMasternodeBroadcast ( ) ;
2016-07-29 07:32:08 +02:00
return false ;
}
return true ;
}
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
2016-10-20 23:11:30 +02:00
bool CMasternodeBroadcast : : Update ( CMasternode * pmn , int & nDos )
{
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 ( ) ) ;
2016-09-16 00:00:06 +02:00
if ( pmn - > UpdateFromNewBroadcast ( ( * this ) ) ) {
2015-08-12 03:39:22 +02:00
pmn - > Check ( ) ;
2016-10-25 16:37:33 +02:00
Relay ( ) ;
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
2016-09-16 00:00:06 +02:00
if ( fMasterNode & & vin . prevout = = activeMasternode . vin . prevout & & 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
2016-12-24 03:49:13 +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
{
TRY_LOCK ( cs_main , lockMain ) ;
2015-08-10 02:38:00 +02:00
if ( ! lockMain ) {
// not mnb fault, let it to be checked again later
2016-10-20 23:11:30 +02:00
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckOutpoint -- Failed to aquire lock, addr=%s " , addr . ToString ( ) ) ;
2015-08-10 02:38:00 +02:00
mnodeman . mapSeenMasternodeBroadcast . erase ( GetHash ( ) ) ;
return false ;
}
2015-07-30 15:44:18 +02:00
2017-07-13 11:38:00 +02:00
int nHeight ;
CollateralStatus err = CheckCollateral ( vin , nHeight ) ;
if ( err = = COLLATERAL_UTXO_NOT_FOUND ) {
2016-10-20 23:11:30 +02:00
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckOutpoint -- Failed to find Masternode UTXO, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
}
2017-07-13 11:38:00 +02:00
if ( err = = COLLATERAL_INVALID_AMOUNT ) {
2016-10-20 23:11:30 +02:00
LogPrint ( " masternode " , " CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO should have 1000 DASH, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
return false ;
}
2017-07-13 11:38:00 +02:00
if ( chainActive . Height ( ) - nHeight + 1 < Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations ) {
2016-10-22 18:52:14 +02:00
LogPrintf ( " CMasternodeBroadcast::CheckOutpoint -- Masternode UTXO must have at least %d confirmations, masternode=%s \n " ,
2016-10-20 23:11:30 +02:00
Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations , vin . prevout . ToStringShort ( ) ) ;
// maybe we miss few blocks, let this mnb to be checked again later
mnodeman . mapSeenMasternodeBroadcast . erase ( GetHash ( ) ) ;
2015-04-17 17:10:38 +02:00
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-04-12 09:04:06 +02:00
// make sure the input that was signed in masternode broadcast message is related to the transaction
// that spawned the Masternode - this is expensive, so it's only done once per Masternode
if ( ! IsInputAssociatedWithPubkey ( ) ) {
2016-10-20 23:11:30 +02:00
LogPrintf ( " CMasternodeMan::CheckOutpoint -- Got mismatched pubKeyCollateralAddress and vin \n " ) ;
2016-05-24 02:08:16 +02:00
nDos = 33 ;
2015-07-30 15:44:18 +02:00
return false ;
}
2015-04-17 17:10:38 +02:00
2015-07-30 15:44:18 +02:00
// verify that sig time is legit in past
2016-05-19 21:03:17 +02:00
// should be at least not earlier than block when 1000 DASH tx got nMasternodeMinimumConfirmations
2016-02-02 16:28:56 +01:00
uint256 hashBlock = uint256 ( ) ;
2015-07-30 15:44:18 +02:00
CTransaction tx2 ;
2016-02-02 16:28:56 +01:00
GetTransaction ( vin . prevout . hash , tx2 , Params ( ) . GetConsensus ( ) , hashBlock , true ) ;
2015-07-30 15:44:18 +02:00
{
2016-03-02 21:57:24 +01:00
LOCK ( cs_main ) ;
BlockMap : : iterator mi = mapBlockIndex . find ( hashBlock ) ;
2016-09-05 18:09:25 +02:00
if ( mi ! = mapBlockIndex . end ( ) & & ( * mi ) . second ) {
2016-03-02 21:57:24 +01:00
CBlockIndex * pMNIndex = ( * mi ) . second ; // block for 1000 DASH tx -> 1 confirmation
2016-05-19 21:03:17 +02:00
CBlockIndex * pConfIndex = chainActive [ pMNIndex - > nHeight + Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations - 1 ] ; // block where tx got nMasternodeMinimumConfirmations
2016-09-16 00:00:06 +02:00
if ( pConfIndex - > GetBlockTime ( ) > sigTime ) {
2016-10-20 23:11:30 +02:00
LogPrintf ( " CMasternodeBroadcast::CheckOutpoint -- Bad sigTime %d (%d conf block is at %d) for Masternode %s %s \n " ,
2016-09-16 00:00:06 +02:00
sigTime , Params ( ) . GetConsensus ( ) . nMasternodeMinimumConfirmations , pConfIndex - > GetBlockTime ( ) , vin . prevout . ToStringShort ( ) , addr . ToString ( ) ) ;
2016-03-02 21:57:24 +01:00
return false ;
}
2015-04-17 17:10:38 +02:00
}
2015-07-30 15:44:18 +02:00
}
2016-05-24 02:08:16 +02:00
2015-07-30 15:44:18 +02:00
return true ;
2015-04-17 17:10:38 +02:00
}
bool CMasternodeBroadcast : : Sign ( 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 ;
}
2016-09-16 00:00:06 +02:00
void CMasternodeBroadcast : : Relay ( )
2015-04-17 17:10:38 +02:00
{
2016-09-16 00:00:06 +02:00
CInv inv ( MSG_MASTERNODE_ANNOUNCE , GetHash ( ) ) ;
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
g_connman - > RelayInv ( inv ) ;
2015-04-17 17:10:38 +02:00
}
2017-07-04 19:31:57 +02:00
CMasternodePing : : CMasternodePing ( CTxIn & vinNew ) :
fSentinelIsCurrent ( false ) ,
2017-07-10 16:41:42 +02:00
nSentinelVersion ( DEFAULT_SENTINEL_VERSION )
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
2016-09-16 00:00:06 +02:00
vin = vinNew ;
blockHash = chainActive [ chainActive . Height ( ) - 12 ] - > GetBlockHash ( ) ;
2015-07-14 07:25:07 +02:00
sigTime = GetAdjustedTime ( ) ;
vchSig = std : : vector < unsigned char > ( ) ;
2015-04-17 17:10:38 +02:00
}
bool CMasternodePing : : Sign ( CKey & keyMasternode , CPubKey & pubKeyMasternode )
{
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 ;
}
2016-12-26 07:44:48 +01:00
bool CMasternodePing : : CheckAndUpdate ( CMasternode * pmn , bool fFromNewBroadcast , int & nDos )
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
}
2016-09-15 15:30:51 +02:00
pmn - > Check ( true ) ; // force update, ignoring cache
if ( ! pmn - > IsEnabled ( ) ) return false ;
LogPrint ( " masternode " , " CMasternodePing::CheckAndUpdate -- Masternode ping acceepted and relayed, masternode=%s \n " , vin . prevout . ToStringShort ( ) ) ;
Relay ( ) ;
return true ;
2015-04-17 17:10:38 +02:00
}
void CMasternodePing : : Relay ( )
{
2015-04-22 16:33:44 +02:00
CInv inv ( MSG_MASTERNODE_PING , GetHash ( ) ) ;
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
g_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-07-04 19:31:57 +02:00
nTimeLastWatchdogVote = ( nVoteTime = = 0 ) ? GetTime ( ) : 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
}
}