2019-01-29 15:53:14 +01:00
// Copyright (c) 2014-2019 The Dash Core developers
2015-04-16 21:58:09 +02:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2016-09-15 08:50:01 +02:00
# include "activemasternode.h"
2018-03-15 10:21:43 +01:00
# include "consensus/validation.h"
2016-09-15 08:50:01 +02:00
# include "governance-classes.h"
2018-11-01 22:58:17 +01:00
# include "init.h"
2015-04-16 21:58:09 +02:00
# include "masternode-payments.h"
2015-07-15 04:44:58 +02:00
# include "masternode-sync.h"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2016-09-27 09:50:04 +02:00
# include "netfulfilledman.h"
2016-11-25 20:01:56 +01:00
# include "netmessagemaker.h"
2015-05-30 19:27:51 +02:00
# include "spork.h"
2016-09-15 08:50:01 +02:00
# include "util.h"
2019-01-03 21:08:34 +01:00
# include "validation.h"
2016-09-15 08:50:01 +02:00
2018-02-15 19:14:28 +01:00
# include "evo/deterministicmns.h"
2018-07-12 11:02:20 +02:00
# include <string>
2015-04-16 21:58:09 +02:00
2016-02-04 20:29:09 +01:00
CMasternodePayments mnpayments ;
2015-07-21 04:24:43 +02:00
2018-08-12 17:27:09 +02:00
bool IsOldBudgetBlockValueValid ( const CBlock & block , int nBlockHeight , CAmount blockReward , std : : string & strErrorRet ) {
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
2018-09-10 16:12:32 +02:00
bool isBlockRewardValueMet = ( block . vtx [ 0 ] - > GetValueOut ( ) < = blockReward ) ;
2018-08-12 17:27:09 +02:00
2018-09-10 16:12:32 +02:00
if ( nBlockHeight < consensusParams . nBudgetPaymentsStartBlock ) {
strErrorRet = strprintf ( " Incorrect block %d, old budgets are not activated yet " , nBlockHeight ) ;
return false ;
2018-08-12 17:27:09 +02:00
}
2018-09-10 16:12:32 +02:00
if ( nBlockHeight > = consensusParams . nSuperblockStartBlock ) {
strErrorRet = strprintf ( " Incorrect block %d, old budgets are no longer active " , nBlockHeight ) ;
return false ;
}
2018-08-12 17:27:09 +02:00
// we are still using budgets, but we have no data about them anymore,
// all we know is predefined budget cycle and window
int nOffset = nBlockHeight % consensusParams . nBudgetPaymentsCycleBlocks ;
if ( nBlockHeight > = consensusParams . nBudgetPaymentsStartBlock & &
nOffset < consensusParams . nBudgetPaymentsWindowBlocks ) {
// NOTE: old budget system is disabled since 12.1
if ( masternodeSync . IsSynced ( ) ) {
// no old budget blocks should be accepted here on mainnet,
// testnet/devnet/regtest should produce regular blocks only
LogPrint ( " gobject " , " %s -- WARNING: Client synced but old budget system is disabled, checking block value against block reward \n " , __func__ ) ;
if ( ! isBlockRewardValueMet ) {
strErrorRet = strprintf ( " coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, old budgets are disabled " ,
nBlockHeight , block . vtx [ 0 ] - > GetValueOut ( ) , blockReward ) ;
}
return isBlockRewardValueMet ;
}
// when not synced, rely on online nodes (all networks)
LogPrint ( " gobject " , " %s -- WARNING: Skipping old budget block value checks, accepting block \n " , __func__ ) ;
return true ;
}
// LogPrint("gobject", "%s -- Block is not in budget cycle window, checking block value against block reward\n", __func__);
if ( ! isBlockRewardValueMet ) {
strErrorRet = strprintf ( " coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, block is not in old budget cycle window " ,
nBlockHeight , block . vtx [ 0 ] - > GetValueOut ( ) , blockReward ) ;
}
return isBlockRewardValueMet ;
}
2016-08-17 09:08:25 +02:00
/**
* IsBlockValueValid
*
* Determine if coinbase outgoing created money is the correct value
*
* Why is this needed ?
* - In Dash some blocks are superblocks , which output much higher amounts of coins
* - Otherblocks are 10 % lower in outgoing value , so in total , no extra coins are created
* - When non - superblocks are detected , the normal schedule should be maintained
*/
2018-02-21 17:32:08 +01:00
bool IsBlockValueValid ( const CBlock & block , int nBlockHeight , CAmount blockReward , std : : string & strErrorRet )
2016-08-22 03:41:40 +02:00
{
2018-09-10 16:12:32 +02:00
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
bool isBlockRewardValueMet = ( block . vtx [ 0 ] - > GetValueOut ( ) < = blockReward ) ;
2016-12-01 22:58:55 +01:00
strErrorRet = " " ;
2018-09-10 16:12:32 +02:00
if ( nBlockHeight < consensusParams . nBudgetPaymentsStartBlock ) {
// old budget system is not activated yet, just make sure we do not exceed the regular block reward
if ( ! isBlockRewardValueMet ) {
strErrorRet = strprintf ( " coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, old budgets are not activated yet " ,
nBlockHeight , block . vtx [ 0 ] - > GetValueOut ( ) , blockReward ) ;
}
return isBlockRewardValueMet ;
} else if ( nBlockHeight < consensusParams . nSuperblockStartBlock ) {
// superblocks are not enabled yet, check if we can pass old budget rules
return IsOldBudgetBlockValueValid ( block , nBlockHeight , blockReward , strErrorRet ) ;
2018-08-12 17:27:09 +02:00
}
2016-11-21 10:51:32 +01:00
if ( fDebug ) LogPrintf ( " block.vtx[0]->GetValueOut() %lld <= blockReward %lld \n " , block . vtx [ 0 ] - > GetValueOut ( ) , blockReward ) ;
2016-08-22 03:41:40 +02:00
2018-08-12 17:27:09 +02:00
CAmount nSuperblockMaxValue = blockReward + CSuperblock : : GetPaymentsLimit ( nBlockHeight ) ;
bool isSuperblockMaxValueMet = ( block . vtx [ 0 ] - > GetValueOut ( ) < = nSuperblockMaxValue ) ;
2016-08-22 03:41:40 +02:00
2018-08-12 17:27:09 +02:00
LogPrint ( " gobject " , " block.vtx[0]->GetValueOut() %lld <= nSuperblockMaxValue %lld \n " , block . vtx [ 0 ] - > GetValueOut ( ) , nSuperblockMaxValue ) ;
2016-08-22 03:41:40 +02:00
2018-08-12 17:27:09 +02:00
if ( ! CSuperblock : : IsValidBlockHeight ( nBlockHeight ) ) {
// can't possibly be a superblock, so lets just check for block reward limits
if ( ! isBlockRewardValueMet ) {
strErrorRet = strprintf ( " coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, only regular blocks are allowed at this height " ,
2016-11-21 10:51:32 +01:00
nBlockHeight , block . vtx [ 0 ] - > GetValueOut ( ) , blockReward ) ;
2016-12-01 22:58:55 +01:00
}
2016-12-08 21:03:46 +01:00
return isBlockRewardValueMet ;
2016-03-02 21:57:24 +01:00
}
2016-08-17 09:08:25 +02:00
2018-08-12 17:27:09 +02:00
// bail out in case superblock limits were exceeded
if ( ! isSuperblockMaxValueMet ) {
strErrorRet = strprintf ( " coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded superblock max value " ,
nBlockHeight , block . vtx [ 0 ] - > GetValueOut ( ) , nSuperblockMaxValue ) ;
return false ;
}
2015-07-04 16:49:49 +02:00
2018-08-12 17:27:09 +02:00
if ( ! masternodeSync . IsSynced ( ) | | fLiteMode ) {
if ( fDebug ) LogPrintf ( " %s -- WARNING: Not enough data, checked superblock max bounds only \n " , __func__ ) ;
// not enough data for full checks but at least we know that the superblock limits were honored.
// We rely on the network to have followed the correct chain in this case
return true ;
}
2015-08-11 23:54:42 +02:00
2018-08-12 17:27:09 +02:00
// we are synced and possibly on a superblock now
2016-07-30 13:04:27 +02:00
2018-08-12 17:27:09 +02:00
if ( ! sporkManager . IsSporkActive ( SPORK_9_SUPERBLOCKS_ENABLED ) ) {
// should NOT allow superblocks at all, when superblocks are disabled
// revert to block reward limits in this case
LogPrint ( " gobject " , " %s -- Superblocks are disabled, no superblocks allowed \n " , __func__ ) ;
2016-12-08 21:03:46 +01:00
if ( ! isBlockRewardValueMet ) {
2018-08-12 17:27:09 +02:00
strErrorRet = strprintf ( " coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, superblocks are disabled " ,
2016-11-21 10:51:32 +01:00
nBlockHeight , block . vtx [ 0 ] - > GetValueOut ( ) , blockReward ) ;
2016-12-01 22:58:55 +01:00
}
2016-12-08 21:03:46 +01:00
return isBlockRewardValueMet ;
2016-08-17 09:08:25 +02:00
}
2018-08-12 17:27:09 +02:00
if ( ! CSuperblockManager : : IsSuperblockTriggered ( nBlockHeight ) ) {
// we are on a valid superblock height but a superblock was not triggered
// revert to block reward limits in this case
2016-12-08 21:03:46 +01:00
if ( ! isBlockRewardValueMet ) {
strErrorRet = strprintf ( " coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, no triggered superblock detected " ,
2016-11-21 10:51:32 +01:00
nBlockHeight , block . vtx [ 0 ] - > GetValueOut ( ) , blockReward ) ;
2016-12-01 22:58:55 +01:00
}
2018-08-12 17:27:09 +02:00
return isBlockRewardValueMet ;
2015-05-30 19:27:51 +02:00
}
2018-08-12 17:27:09 +02:00
// this actually also checks for correct payees and not only amount
if ( ! CSuperblockManager : : IsValid ( * block . vtx [ 0 ] , nBlockHeight , blockReward ) ) {
// triggered but invalid? that's weird
LogPrintf ( " %s -- ERROR: Invalid superblock detected at height %d: %s " , __func__ , nBlockHeight , block . vtx [ 0 ] - > ToString ( ) ) ;
// should NOT allow invalid superblocks, when superblocks are enabled
strErrorRet = strprintf ( " invalid superblock detected at height %d " , nBlockHeight ) ;
return false ;
}
// we got a valid superblock
return true ;
2015-05-30 19:27:51 +02:00
}
2016-08-22 03:41:40 +02:00
bool IsBlockPayeeValid ( const CTransaction & txNew , int nBlockHeight , CAmount blockReward )
2015-05-04 17:04:09 +02:00
{
2019-01-03 10:17:43 +01:00
if ( fLiteMode ) {
2016-08-22 03:41:40 +02:00
//there is no budget data to use to check anything, let's just accept the longest chain
2018-08-12 17:27:09 +02:00
if ( fDebug ) LogPrintf ( " %s -- WARNING: Not enough data, skipping block payee checks \n " , __func__ ) ;
2015-07-18 15:46:54 +02:00
return true ;
}
2016-08-22 03:41:40 +02:00
// we are still using budgets, but we have no data about them anymore,
// we can only check masternode payments
2016-08-17 09:08:25 +02:00
2016-08-22 03:41:40 +02:00
const Consensus : : Params & consensusParams = Params ( ) . GetConsensus ( ) ;
2016-08-17 09:08:25 +02:00
2016-08-22 03:41:40 +02:00
if ( nBlockHeight < consensusParams . nSuperblockStartBlock ) {
2018-02-01 13:42:21 +01:00
// NOTE: old budget system is disabled since 12.1 and we should never enter this branch
// anymore when sync is finished (on mainnet). We have no old budget data but these blocks
// have tons of confirmations and can be safely accepted without payee verification
2018-08-12 17:27:09 +02:00
LogPrint ( " gobject " , " %s -- WARNING: Client synced but old budget system is disabled, accepting any payee \n " , __func__ ) ;
2016-08-22 03:41:40 +02:00
return true ;
2016-08-17 09:08:25 +02:00
}
2016-08-22 03:41:40 +02:00
// superblocks started
// SEE IF THIS IS A VALID SUPERBLOCK
2016-08-17 09:08:25 +02:00
2016-09-20 18:24:18 +02:00
if ( sporkManager . IsSporkActive ( SPORK_9_SUPERBLOCKS_ENABLED ) ) {
if ( CSuperblockManager : : IsSuperblockTriggered ( nBlockHeight ) ) {
if ( CSuperblockManager : : IsValid ( txNew , nBlockHeight , blockReward ) ) {
2018-08-12 17:27:09 +02:00
LogPrint ( " gobject " , " %s -- Valid superblock at height %d: %s " , __func__ , nBlockHeight , txNew . ToString ( ) ) ;
2018-03-03 15:56:01 +01:00
// continue validation, should also pay MN
2018-08-12 17:27:09 +02:00
} else {
LogPrintf ( " %s -- ERROR: Invalid superblock detected at height %d: %s " , __func__ , nBlockHeight , txNew . ToString ( ) ) ;
// should NOT allow such superblocks, when superblocks are enabled
return false ;
2016-09-20 18:24:18 +02:00
}
2018-08-12 17:27:09 +02:00
} else {
LogPrint ( " gobject " , " %s -- No triggered superblock detected at height %d \n " , __func__ , nBlockHeight ) ;
2016-08-22 03:41:40 +02:00
}
2016-09-20 18:24:18 +02:00
} else {
// should NOT allow superblocks at all, when superblocks are disabled
2018-08-12 17:27:09 +02:00
LogPrint ( " gobject " , " %s -- Superblocks are disabled, no superblocks allowed \n " , __func__ ) ;
2016-08-22 03:41:40 +02:00
}
2015-05-30 19:27:51 +02:00
2019-01-03 10:17:43 +01:00
// Check for correct masternode payment
2018-08-12 17:27:09 +02:00
if ( mnpayments . IsTransactionValid ( txNew , nBlockHeight , blockReward ) ) {
LogPrint ( " mnpayments " , " %s -- Valid masternode payment at height %d: %s " , __func__ , nBlockHeight , txNew . ToString ( ) ) ;
2016-08-22 03:41:40 +02:00
return true ;
}
2016-08-17 09:08:25 +02:00
2019-01-03 10:17:43 +01:00
LogPrintf ( " %s -- ERROR: Invalid masternode payment detected at height %d: %s " , __func__ , nBlockHeight , txNew . ToString ( ) ) ;
return false ;
2016-08-22 03:41:40 +02:00
}
2016-08-17 09:08:25 +02:00
2018-08-14 11:58:38 +02:00
void FillBlockPayments ( CMutableTransaction & txNew , int nBlockHeight , CAmount blockReward , std : : vector < CTxOut > & voutMasternodePaymentsRet , std : : vector < CTxOut > & voutSuperblockPaymentsRet )
2016-08-22 03:41:40 +02:00
{
// only create superblocks if spork is enabled AND if superblock is actually triggered
// (height should be validated inside)
2016-08-29 21:16:02 +02:00
if ( sporkManager . IsSporkActive ( SPORK_9_SUPERBLOCKS_ENABLED ) & &
2016-08-22 03:41:40 +02:00
CSuperblockManager : : IsSuperblockTriggered ( nBlockHeight ) ) {
2018-08-12 17:27:09 +02:00
LogPrint ( " gobject " , " %s -- triggered superblock creation at height %d \n " , __func__ , nBlockHeight ) ;
2018-08-14 11:58:38 +02:00
CSuperblockManager : : GetSuperblockPayments ( nBlockHeight , voutSuperblockPaymentsRet ) ;
2018-08-12 17:27:09 +02:00
}
2018-08-14 11:58:38 +02:00
if ( ! mnpayments . GetMasternodeTxOuts ( nBlockHeight , blockReward , voutMasternodePaymentsRet ) ) {
2018-10-30 10:59:03 +01:00
LogPrint ( " mnpayments " , " %s -- no masternode to pay (MN list probably empty) \n " , __func__ ) ;
2018-08-12 17:27:09 +02:00
}
2018-08-14 11:58:38 +02:00
txNew . vout . insert ( txNew . vout . end ( ) , voutMasternodePaymentsRet . begin ( ) , voutMasternodePaymentsRet . end ( ) ) ;
txNew . vout . insert ( txNew . vout . end ( ) , voutSuperblockPaymentsRet . begin ( ) , voutSuperblockPaymentsRet . end ( ) ) ;
2018-08-12 17:27:09 +02:00
2018-08-14 11:58:38 +02:00
std : : string voutMasternodeStr ;
for ( const auto & txout : voutMasternodePaymentsRet ) {
// subtract MN payment from miner reward
txNew . vout [ 0 ] . nValue - = txout . nValue ;
if ( ! voutMasternodeStr . empty ( ) )
voutMasternodeStr + = " , " ;
voutMasternodeStr + = txout . ToString ( ) ;
}
2018-08-12 17:27:09 +02:00
2018-08-14 11:58:38 +02:00
LogPrint ( " mnpayments " , " %s -- nBlockHeight %d blockReward %lld voutMasternodePaymentsRet \" %s \" txNew %s " , __func__ ,
nBlockHeight , blockReward , voutMasternodeStr , txNew . ToString ( ) ) ;
2015-05-30 19:27:51 +02:00
}
2018-04-04 17:20:54 +02:00
std : : string GetRequiredPaymentsString ( int nBlockHeight , const CDeterministicMNCPtr & payee )
{
std : : string strPayee = " Unknown " ;
if ( payee ) {
CTxDestination dest ;
if ( ! ExtractDestination ( payee - > pdmnState - > scriptPayout , dest ) )
assert ( false ) ;
strPayee = CBitcoinAddress ( dest ) . ToString ( ) ;
}
if ( CSuperblockManager : : IsSuperblockTriggered ( nBlockHeight ) ) {
strPayee + = " , " + CSuperblockManager : : GetRequiredPaymentsString ( nBlockHeight ) ;
}
return strPayee ;
}
std : : map < int , std : : string > GetRequiredPaymentsStrings ( int nStartHeight , int nEndHeight )
{
std : : map < int , std : : string > mapPayments ;
LOCK ( cs_main ) ;
int nChainTipHeight = chainActive . Height ( ) ;
bool doProjection = false ;
for ( int h = nStartHeight ; h < nEndHeight ; h + + ) {
2019-01-03 10:17:43 +01:00
if ( h < = nChainTipHeight ) {
auto payee = deterministicMNManager - > GetListForBlock ( chainActive [ h - 1 ] - > GetBlockHash ( ) ) . GetMNPayee ( ) ;
mapPayments . emplace ( h , GetRequiredPaymentsString ( h , payee ) ) ;
2018-04-04 17:20:54 +02:00
} else {
2019-01-03 10:17:43 +01:00
doProjection = true ;
break ;
2018-04-04 17:20:54 +02:00
}
}
if ( doProjection ) {
auto projection = deterministicMNManager - > GetListAtChainTip ( ) . GetProjectedMNPayees ( nEndHeight - nChainTipHeight ) ;
for ( size_t i = 0 ; i < projection . size ( ) ; i + + ) {
auto payee = projection [ i ] ;
int h = nChainTipHeight + 1 + i ;
mapPayments . emplace ( h , GetRequiredPaymentsString ( h , payee ) ) ;
}
}
return mapPayments ;
}
2016-08-17 09:08:25 +02:00
/**
2018-08-14 11:58:38 +02:00
* GetMasternodeTxOuts
2016-08-17 09:08:25 +02:00
*
2018-08-14 11:58:38 +02:00
* Get masternode payment tx outputs
2016-08-17 09:08:25 +02:00
*/
2018-08-14 11:58:38 +02:00
bool CMasternodePayments : : GetMasternodeTxOuts ( int nBlockHeight , CAmount blockReward , std : : vector < CTxOut > & voutMasternodePaymentsRet ) const
2015-05-30 19:27:51 +02:00
{
2016-08-28 12:11:36 +02:00
// make sure it's not filled yet
2018-08-14 11:58:38 +02:00
voutMasternodePaymentsRet . clear ( ) ;
2015-06-25 17:17:53 +02:00
2018-08-14 11:58:38 +02:00
if ( ! GetBlockTxOuts ( nBlockHeight , blockReward , voutMasternodePaymentsRet ) ) {
2019-01-03 10:17:43 +01:00
LogPrintf ( " CMasternodePayments::%s -- no payee (deterministic masternode list empty) \n " , __func__ ) ;
return false ;
2015-05-30 19:27:51 +02:00
}
2018-08-14 11:58:38 +02:00
for ( const auto & txout : voutMasternodePaymentsRet ) {
CTxDestination address1 ;
ExtractDestination ( txout . scriptPubKey , address1 ) ;
CBitcoinAddress address2 ( address1 ) ;
2015-05-30 19:27:51 +02:00
2018-08-14 11:58:38 +02:00
LogPrintf ( " CMasternodePayments::%s -- Masternode payment %lld to %s \n " , __func__ , txout . nValue , address2 . ToString ( ) ) ;
}
2018-08-12 17:27:09 +02:00
return true ;
2015-05-30 19:27:51 +02:00
}
2018-08-14 11:58:38 +02:00
bool CMasternodePayments : : GetBlockTxOuts ( int nBlockHeight , CAmount blockReward , std : : vector < CTxOut > & voutMasternodePaymentsRet ) const
2015-04-16 21:58:09 +02:00
{
2018-08-14 11:58:38 +02:00
voutMasternodePaymentsRet . clear ( ) ;
2015-04-16 21:58:09 +02:00
2018-08-14 11:58:38 +02:00
CAmount masternodeReward = GetMasternodePayment ( nBlockHeight , blockReward ) ;
2019-01-03 10:17:43 +01:00
uint256 blockHash ;
{
LOCK ( cs_main ) ;
blockHash = chainActive [ nBlockHeight - 1 ] - > GetBlockHash ( ) ;
}
uint256 proTxHash ;
auto dmnPayee = deterministicMNManager - > GetListForBlock ( blockHash ) . GetMNPayee ( ) ;
if ( ! dmnPayee ) {
return false ;
}
2018-12-06 14:43:54 +01:00
2019-01-03 10:17:43 +01:00
CAmount operatorReward = 0 ;
if ( dmnPayee - > nOperatorReward ! = 0 & & dmnPayee - > pdmnState - > scriptOperatorPayout ! = CScript ( ) ) {
// This calculation might eventually turn out to result in 0 even if an operator reward percentage is given.
// This will however only happen in a few years when the block rewards drops very low.
operatorReward = ( masternodeReward * dmnPayee - > nOperatorReward ) / 10000 ;
masternodeReward - = operatorReward ;
}
2018-12-06 14:43:54 +01:00
2019-01-03 10:17:43 +01:00
if ( masternodeReward > 0 ) {
voutMasternodePaymentsRet . emplace_back ( masternodeReward , dmnPayee - > pdmnState - > scriptPayout ) ;
2018-08-14 11:58:38 +02:00
}
2019-01-03 10:17:43 +01:00
if ( operatorReward > 0 ) {
voutMasternodePaymentsRet . emplace_back ( operatorReward , dmnPayee - > pdmnState - > scriptOperatorPayout ) ;
}
return true ;
2015-04-22 16:33:44 +02:00
}
2015-04-16 21:58:09 +02:00
2016-09-15 08:50:01 +02:00
// Is this masternode scheduled to get paid soon?
2016-09-21 16:45:29 +02:00
// -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 blocks of votes
2018-12-17 15:45:36 +01:00
bool CMasternodePayments : : IsScheduled ( const CDeterministicMNCPtr & dmnIn , int nNotBlockHeight ) const
2015-05-27 21:47:01 +02:00
{
2018-12-28 08:12:53 +01:00
auto projectedPayees = deterministicMNManager - > GetListAtChainTip ( ) . GetProjectedMNPayees ( 8 ) ;
for ( const auto & dmn : projectedPayees ) {
if ( dmn - > proTxHash = = dmnIn - > proTxHash ) {
return true ;
2015-05-27 21:47:01 +02:00
}
}
return false ;
}
2018-08-12 17:27:09 +02:00
bool CMasternodePayments : : IsTransactionValid ( const CTransaction & txNew , int nBlockHeight , CAmount blockReward ) const
2015-04-22 16:33:44 +02:00
{
2019-01-29 15:54:38 +01:00
if ( ! deterministicMNManager - > IsDIP3Enforced ( nBlockHeight ) ) {
2019-01-03 10:17:43 +01:00
// can't verify historical blocks here
2018-08-27 14:59:54 +02:00
return true ;
2015-04-22 16:33:44 +02:00
}
2019-01-03 10:17:43 +01:00
std : : vector < CTxOut > voutMasternodePayments ;
if ( ! GetBlockTxOuts ( nBlockHeight , blockReward , voutMasternodePayments ) ) {
LogPrintf ( " CMasternodePayments::%s -- ERROR failed to get payees for block at height %s \n " , __func__ , nBlockHeight ) ;
2018-02-15 19:14:28 +01:00
return true ;
}
2019-01-03 10:17:43 +01:00
for ( const auto & txout : voutMasternodePayments ) {
2017-10-17 18:42:44 +02:00
bool found = false ;
2019-01-03 10:17:43 +01:00
for ( const auto & txout2 : txNew . vout ) {
if ( txout = = txout2 ) {
found = true ;
2016-09-19 00:23:52 +02:00
break ;
}
}
2019-01-03 10:17:43 +01:00
if ( ! found ) {
CTxDestination dest ;
if ( ! ExtractDestination ( txout . scriptPubKey , dest ) )
assert ( false ) ;
LogPrintf ( " CMasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s \n " , __func__ , CBitcoinAddress ( dest ) . ToString ( ) , nBlockHeight ) ;
return false ;
2016-09-19 00:23:52 +02:00
}
}
2019-01-03 10:17:43 +01:00
return true ;
2018-11-01 22:58:17 +01:00
}