2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash Core developers
2016-11-24 19:12:05 +01:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include "core_io.h"
# include "governance.h"
2016-12-20 14:27:59 +01:00
# include "governance-classes.h"
2016-11-24 19:12:05 +01:00
# include "governance-object.h"
# include "governance-vote.h"
2018-03-21 12:09:13 +01:00
# include "governance-validators.h"
2017-08-25 14:56:48 +02:00
# include "instantx.h"
2017-12-14 01:33:58 +01:00
# include "masternode-sync.h"
2016-11-24 19:12:05 +01:00
# include "masternodeman.h"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2016-11-24 19:12:05 +01:00
# include "util.h"
2016-12-20 14:27:59 +01:00
2016-11-24 19:12:05 +01:00
# include <univalue.h>
2018-07-12 11:02:20 +02:00
# include <string>
2016-11-24 19:12:05 +01:00
2018-02-21 17:32:08 +01:00
CGovernanceObject : : CGovernanceObject ( ) :
cs ( ) ,
nObjectType ( GOVERNANCE_OBJECT_UNKNOWN ) ,
nHashParent ( ) ,
nRevision ( 0 ) ,
nTime ( 0 ) ,
nDeletionTime ( 0 ) ,
nCollateralHash ( ) ,
vchData ( ) ,
masternodeOutpoint ( ) ,
vchSig ( ) ,
fCachedLocalValidity ( false ) ,
strLocalValidityError ( ) ,
fCachedFunding ( false ) ,
fCachedValid ( true ) ,
fCachedDelete ( false ) ,
fCachedEndorsed ( false ) ,
fDirtyCache ( true ) ,
fExpired ( false ) ,
fUnparsable ( false ) ,
mapCurrentMNVotes ( ) ,
cmmapOrphanVotes ( ) ,
fileVotes ( )
2016-11-24 19:12:05 +01:00
{
2018-02-15 15:43:17 +01:00
// PARSE JSON DATA STORAGE (VCHDATA)
2016-11-24 19:12:05 +01:00
LoadData ( ) ;
}
2018-02-21 17:32:08 +01:00
CGovernanceObject : : CGovernanceObject ( const uint256 & nHashParentIn , int nRevisionIn , int64_t nTimeIn , const uint256 & nCollateralHashIn , const std : : string & strDataHexIn ) :
cs ( ) ,
nObjectType ( GOVERNANCE_OBJECT_UNKNOWN ) ,
nHashParent ( nHashParentIn ) ,
nRevision ( nRevisionIn ) ,
nTime ( nTimeIn ) ,
nDeletionTime ( 0 ) ,
nCollateralHash ( nCollateralHashIn ) ,
vchData ( ParseHex ( strDataHexIn ) ) ,
masternodeOutpoint ( ) ,
vchSig ( ) ,
fCachedLocalValidity ( false ) ,
strLocalValidityError ( ) ,
fCachedFunding ( false ) ,
fCachedValid ( true ) ,
fCachedDelete ( false ) ,
fCachedEndorsed ( false ) ,
fDirtyCache ( true ) ,
fExpired ( false ) ,
fUnparsable ( false ) ,
mapCurrentMNVotes ( ) ,
cmmapOrphanVotes ( ) ,
fileVotes ( )
2016-11-24 19:12:05 +01:00
{
2018-02-15 15:43:17 +01:00
// PARSE JSON DATA STORAGE (VCHDATA)
2016-11-24 19:12:05 +01:00
LoadData ( ) ;
}
2018-02-21 17:32:08 +01:00
CGovernanceObject : : CGovernanceObject ( const CGovernanceObject & other ) :
cs ( ) ,
nObjectType ( other . nObjectType ) ,
nHashParent ( other . nHashParent ) ,
nRevision ( other . nRevision ) ,
nTime ( other . nTime ) ,
nDeletionTime ( other . nDeletionTime ) ,
nCollateralHash ( other . nCollateralHash ) ,
vchData ( other . vchData ) ,
masternodeOutpoint ( other . masternodeOutpoint ) ,
vchSig ( other . vchSig ) ,
fCachedLocalValidity ( other . fCachedLocalValidity ) ,
strLocalValidityError ( other . strLocalValidityError ) ,
fCachedFunding ( other . fCachedFunding ) ,
fCachedValid ( other . fCachedValid ) ,
fCachedDelete ( other . fCachedDelete ) ,
fCachedEndorsed ( other . fCachedEndorsed ) ,
fDirtyCache ( other . fDirtyCache ) ,
fExpired ( other . fExpired ) ,
fUnparsable ( other . fUnparsable ) ,
mapCurrentMNVotes ( other . mapCurrentMNVotes ) ,
cmmapOrphanVotes ( other . cmmapOrphanVotes ) ,
fileVotes ( other . fileVotes )
2016-11-24 19:12:05 +01:00
{ }
bool CGovernanceObject : : ProcessVote ( CNode * pfrom ,
const CGovernanceVote & vote ,
2017-09-19 16:51:38 +02:00
CGovernanceException & exception ,
CConnman & connman )
2016-11-24 19:12:05 +01:00
{
2018-03-14 18:50:07 +01:00
LOCK ( cs ) ;
2018-03-19 14:08:32 +01:00
// do not process already known valid votes twice
if ( fileVotes . HasVote ( vote . GetHash ( ) ) ) {
// nothing to do here, not an error
std : : ostringstream ostr ;
ostr < < " CGovernanceObject::ProcessVote -- Already known valid vote " ;
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_NONE ) ;
return false ;
}
2017-09-11 16:13:48 +02:00
if ( ! mnodeman . Has ( vote . GetMasternodeOutpoint ( ) ) ) {
2016-11-24 19:12:05 +01:00
std : : ostringstream ostr ;
2018-02-26 12:10:20 +01:00
ostr < < " CGovernanceObject::ProcessVote -- Masternode " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( ) < < " not found " ;
2016-11-24 19:12:05 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_WARNING ) ;
2018-02-06 12:08:43 +01:00
if ( cmmapOrphanVotes . Insert ( vote . GetMasternodeOutpoint ( ) , vote_time_pair_t ( vote , GetAdjustedTime ( ) + GOVERNANCE_ORPHAN_EXPIRATION_TIME ) ) ) {
2016-11-24 19:12:05 +01:00
if ( pfrom ) {
2017-09-19 16:51:38 +02:00
mnodeman . AskForMN ( pfrom , vote . GetMasternodeOutpoint ( ) , connman ) ;
2016-11-24 19:12:05 +01:00
}
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
}
else {
2017-06-06 01:47:23 +02:00
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
}
return false ;
}
2018-03-20 12:04:59 +01:00
vote_m_it it = mapCurrentMNVotes . emplace ( vote_m_t : : value_type ( vote . GetMasternodeOutpoint ( ) , vote_rec_t ( ) ) ) . first ;
vote_rec_t & voteRecordRef = it - > second ;
2016-11-24 19:12:05 +01:00
vote_signal_enum_t eSignal = vote . GetSignal ( ) ;
if ( eSignal = = VOTE_SIGNAL_NONE ) {
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Vote signal: none " ;
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_WARNING ) ;
return false ;
}
if ( eSignal > MAX_SUPPORTED_VOTE_SIGNAL ) {
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Unsupported vote signal: " < < CGovernanceVoting : : ConvertSignalToString ( vote . GetSignal ( ) ) ;
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_PERMANENT_ERROR , 20 ) ;
return false ;
}
2018-03-20 12:04:59 +01:00
vote_instance_m_it it2 = voteRecordRef . mapInstances . emplace ( vote_instance_m_t : : value_type ( int ( eSignal ) , vote_instance_t ( ) ) ) . first ;
vote_instance_t & voteInstanceRef = it2 - > second ;
2017-02-23 13:29:00 +01:00
// Reject obsolete votes
2018-03-20 12:04:59 +01:00
if ( vote . GetTimestamp ( ) < voteInstanceRef . nCreationTime ) {
2017-02-23 13:29:00 +01:00
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Obsolete vote " ;
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
2017-02-23 13:29:00 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_NONE ) ;
return false ;
}
2017-08-29 01:51:44 +02:00
int64_t nNow = GetAdjustedTime ( ) ;
2018-03-20 12:04:59 +01:00
int64_t nVoteTimeUpdate = voteInstanceRef . nTime ;
2016-11-24 19:12:05 +01:00
if ( governance . AreRateChecksEnabled ( ) ) {
2018-03-20 12:04:59 +01:00
int64_t nTimeDelta = nNow - voteInstanceRef . nTime ;
2016-11-24 19:12:05 +01:00
if ( nTimeDelta < GOVERNANCE_UPDATE_MIN ) {
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Masternode voting too often "
2017-09-11 16:13:48 +02:00
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( )
2016-11-24 19:12:05 +01:00
< < " , governance object hash = " < < GetHash ( ) . ToString ( )
2017-06-06 01:47:23 +02:00
< < " , time delta = " < < nTimeDelta ;
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_TEMPORARY_ERROR ) ;
2016-12-08 21:00:49 +01:00
nVoteTimeUpdate = nNow ;
2016-11-24 19:12:05 +01:00
return false ;
}
}
2018-03-20 12:04:59 +01:00
2018-08-31 15:31:59 +02:00
bool onlyOwnerAllowed = nObjectType = = GOVERNANCE_OBJECT_PROPOSAL ;
2016-11-24 19:12:05 +01:00
// Finally check that the vote is actually valid (done last because of cost of signature verification)
2018-08-31 15:31:59 +02:00
if ( ! vote . IsValid ( onlyOwnerAllowed ) ) {
2016-11-24 19:12:05 +01:00
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Invalid vote "
2017-09-11 16:13:48 +02:00
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( )
2016-11-24 19:12:05 +01:00
< < " , governance object hash = " < < GetHash ( ) . ToString ( )
2017-06-06 01:47:23 +02:00
< < " , vote hash = " < < vote . GetHash ( ) . ToString ( ) ;
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_PERMANENT_ERROR , 20 ) ;
governance . AddInvalidVote ( vote ) ;
return false ;
}
2018-03-20 12:04:59 +01:00
2017-09-11 16:13:48 +02:00
if ( ! mnodeman . AddGovernanceVote ( vote . GetMasternodeOutpoint ( ) , vote . GetParentHash ( ) ) ) {
2017-04-02 21:58:54 +02:00
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Unable to add governance vote "
2017-09-11 16:13:48 +02:00
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( )
2017-06-06 01:47:23 +02:00
< < " , governance object hash = " < < GetHash ( ) . ToString ( ) ;
LogPrint ( " gobject " , " %s \n " , ostr . str ( ) ) ;
2017-04-02 21:58:54 +02:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_PERMANENT_ERROR ) ;
return false ;
}
2018-03-14 18:50:07 +01:00
2018-03-20 12:04:59 +01:00
voteInstanceRef = vote_instance_t ( vote . GetOutcome ( ) , nVoteTimeUpdate , vote . GetTimestamp ( ) ) ;
2018-03-19 14:08:32 +01:00
fileVotes . AddVote ( vote ) ;
2016-11-24 19:12:05 +01:00
fDirtyCache = true ;
return true ;
}
void CGovernanceObject : : ClearMasternodeVotes ( )
{
2018-03-09 15:15:48 +01:00
LOCK ( cs ) ;
2016-11-24 19:12:05 +01:00
vote_m_it it = mapCurrentMNVotes . begin ( ) ;
while ( it ! = mapCurrentMNVotes . end ( ) ) {
2017-08-25 14:57:19 +02:00
if ( ! mnodeman . Has ( it - > first ) ) {
fileVotes . RemoveVotesFromMasternode ( it - > first ) ;
2016-11-24 19:12:05 +01:00
mapCurrentMNVotes . erase ( it + + ) ;
}
else {
+ + it ;
}
}
}
2016-12-20 04:25:20 +01:00
std : : string CGovernanceObject : : GetSignatureMessage ( ) const
{
LOCK ( cs ) ;
std : : string strMessage = nHashParent . ToString ( ) + " | " +
2018-07-12 11:02:20 +02:00
std : : to_string ( nRevision ) + " | " +
std : : to_string ( nTime ) + " | " +
2018-02-15 15:43:17 +01:00
GetDataAsHexString ( ) + " | " +
2018-02-15 08:29:44 +01:00
masternodeOutpoint . ToStringShort ( ) + " | " +
2016-12-20 04:25:20 +01:00
nCollateralHash . ToString ( ) ;
return strMessage ;
}
2018-02-16 15:54:53 +01:00
uint256 CGovernanceObject : : GetHash ( ) const
{
// Note: doesn't match serialization
// CREATE HASH OF ALL IMPORTANT PIECES OF DATA
CHashWriter ss ( SER_GETHASH , PROTOCOL_VERSION ) ;
ss < < nHashParent ;
ss < < nRevision ;
ss < < nTime ;
ss < < GetDataAsHexString ( ) ;
ss < < masternodeOutpoint < < uint8_t { } < < 0xffffffff ; // adding dummy values here to match old hashing
ss < < vchSig ;
// fee_tx is left out on purpose
2018-04-20 12:53:23 +02:00
DBG ( printf ( " CGovernanceObject::GetHash %i %li %s \n " , nRevision , nTime , GetDataAsHexString ( ) . c_str ( ) ) ; ) ;
2018-02-16 15:54:53 +01:00
return ss . GetHash ( ) ;
}
uint256 CGovernanceObject : : GetSignatureHash ( ) const
{
return SerializeHash ( * this ) ;
}
2018-02-15 08:29:44 +01:00
void CGovernanceObject : : SetMasternodeOutpoint ( const COutPoint & outpoint )
2016-11-24 19:12:05 +01:00
{
2018-02-15 08:29:44 +01:00
masternodeOutpoint = outpoint ;
2016-11-24 19:12:05 +01:00
}
2018-08-31 15:31:59 +02:00
bool CGovernanceObject : : Sign ( const CKey & key , const CKeyID & keyID )
2016-11-24 19:12:05 +01:00
{
std : : string strError ;
2016-12-20 04:25:20 +01:00
2018-02-16 15:54:53 +01:00
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash = GetSignatureHash ( ) ;
2016-11-24 19:12:05 +01:00
2018-08-31 15:31:59 +02:00
if ( ! CHashSigner : : SignHash ( hash , key , vchSig ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceObject::Sign -- SignHash() failed \n " ) ;
return false ;
}
2016-11-24 19:12:05 +01:00
2018-08-31 15:31:59 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , keyID , vchSig , strError ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceObject::Sign -- VerifyHash() failed, error: %s \n " , strError ) ;
return false ;
}
} else {
std : : string strMessage = GetSignatureMessage ( ) ;
2018-08-31 15:31:59 +02:00
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , key ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceObject::Sign -- SignMessage() failed \n " ) ;
return false ;
}
2018-08-31 15:31:59 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyID , vchSig , strMessage , strError ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceObject::Sign -- VerifyMessage() failed, error: %s \n " , strError ) ;
return false ;
}
2016-11-24 19:12:05 +01:00
}
2018-02-15 08:29:44 +01:00
LogPrint ( " gobject " , " CGovernanceObject::Sign -- pubkey id = %s, masternode = %s \n " ,
2018-08-31 15:31:59 +02:00
keyID . ToString ( ) , masternodeOutpoint . ToStringShort ( ) ) ;
2016-11-24 19:12:05 +01:00
return true ;
}
2018-08-31 15:31:59 +02:00
bool CGovernanceObject : : CheckSignature ( const CKeyID & keyID ) const
2016-11-24 19:12:05 +01:00
{
std : : string strError ;
2018-02-16 15:54:53 +01:00
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash = GetSignatureHash ( ) ;
2016-12-20 04:25:20 +01:00
2018-08-31 15:31:59 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , keyID , vchSig , strError ) ) {
2018-02-16 15:54:53 +01:00
// could be an old object
std : : string strMessage = GetSignatureMessage ( ) ;
2016-11-24 19:12:05 +01:00
2018-08-31 15:31:59 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyID , vchSig , strMessage , strError ) ) {
2018-02-16 15:54:53 +01:00
// nope, not in old format either
LogPrintf ( " CGovernance::CheckSignature -- VerifyMessage() failed, error: %s \n " , strError ) ;
return false ;
}
}
} else {
std : : string strMessage = GetSignatureMessage ( ) ;
2016-11-24 19:12:05 +01:00
2018-08-31 15:31:59 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyID , vchSig , strMessage , strError ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernance::CheckSignature -- VerifyMessage() failed, error: %s \n " , strError ) ;
return false ;
}
}
2016-11-24 19:12:05 +01:00
2018-02-16 15:54:53 +01:00
return true ;
2016-11-24 19:12:05 +01:00
}
/**
2018-02-15 15:43:17 +01:00
Return the actual object from the vchData JSON structure .
2016-11-24 19:12:05 +01:00
Returns an empty object on error .
*/
UniValue CGovernanceObject : : GetJSONObject ( )
{
UniValue obj ( UniValue : : VOBJ ) ;
2018-02-15 15:43:17 +01:00
if ( vchData . empty ( ) ) {
2016-11-24 19:12:05 +01:00
return obj ;
}
UniValue objResult ( UniValue : : VOBJ ) ;
GetData ( objResult ) ;
2018-02-28 00:20:16 +01:00
if ( objResult . isObject ( ) ) {
obj = objResult ;
} else {
std : : vector < UniValue > arr1 = objResult . getValues ( ) ;
std : : vector < UniValue > arr2 = arr1 . at ( 0 ) . getValues ( ) ;
obj = arr2 . at ( 1 ) ;
}
2016-11-24 19:12:05 +01:00
return obj ;
}
/**
* LoadData
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
2018-02-15 15:43:17 +01:00
* Attempt to load data from vchData
2016-11-24 19:12:05 +01:00
*
*/
void CGovernanceObject : : LoadData ( )
{
// todo : 12.1 - resolved
//return;
2018-02-15 15:43:17 +01:00
if ( vchData . empty ( ) ) {
2016-11-24 19:12:05 +01:00
return ;
}
try {
2018-02-15 15:43:17 +01:00
// ATTEMPT TO LOAD JSON STRING FROM VCHDATA
2016-11-24 19:12:05 +01:00
UniValue objResult ( UniValue : : VOBJ ) ;
GetData ( objResult ) ;
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " CGovernanceObject::LoadData GetDataAsPlainString = "
2018-02-15 15:43:17 +01:00
< < GetDataAsPlainString ( )
2018-02-21 21:24:28 +01:00
< < std : : endl ; ) ;
2016-11-24 19:12:05 +01:00
UniValue obj = GetJSONObject ( ) ;
nObjectType = obj [ " type " ] . get_int ( ) ;
}
catch ( std : : exception & e ) {
fUnparsable = true ;
std : : ostringstream ostr ;
ostr < < " CGovernanceObject::LoadData Error parsing JSON "
< < " , e.what() = " < < e . what ( ) ;
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < ostr . str ( ) < < std : : endl ; ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
return ;
}
catch ( . . . ) {
fUnparsable = true ;
std : : ostringstream ostr ;
ostr < < " CGovernanceObject::LoadData Unknown Error parsing JSON " ;
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < ostr . str ( ) < < std : : endl ; ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
return ;
}
}
/**
* GetData - Example usage :
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* Decode governance object data into UniValue ( VOBJ )
*
*/
void CGovernanceObject : : GetData ( UniValue & objResult )
{
UniValue o ( UniValue : : VOBJ ) ;
2018-02-15 15:43:17 +01:00
std : : string s = GetDataAsPlainString ( ) ;
2016-11-24 19:12:05 +01:00
o . read ( s ) ;
objResult = o ;
}
/**
* GetData - As
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
*/
2018-02-15 15:43:17 +01:00
std : : string CGovernanceObject : : GetDataAsHexString ( ) const
2016-11-24 19:12:05 +01:00
{
2018-02-15 15:43:17 +01:00
return HexStr ( vchData ) ;
2016-11-24 19:12:05 +01:00
}
2018-02-15 15:43:17 +01:00
std : : string CGovernanceObject : : GetDataAsPlainString ( ) const
2016-11-24 19:12:05 +01:00
{
2018-02-15 15:43:17 +01:00
return std : : string ( vchData . begin ( ) , vchData . end ( ) ) ;
2016-11-24 19:12:05 +01:00
}
2017-01-03 19:32:52 +01:00
void CGovernanceObject : : UpdateLocalValidity ( )
2016-11-24 19:12:05 +01:00
{
2017-07-13 11:38:00 +02:00
LOCK ( cs_main ) ;
2016-11-24 19:12:05 +01:00
// THIS DOES NOT CHECK COLLATERAL, THIS IS CHECKED UPON ORIGINAL ARRIVAL
2017-01-03 19:32:52 +01:00
fCachedLocalValidity = IsValidLocally ( strLocalValidityError , false ) ;
2016-11-24 19:12:05 +01:00
} ;
2018-03-20 12:04:59 +01:00
bool CGovernanceObject : : IsValidLocally ( std : : string & strError , bool fCheckCollateral ) const
2016-11-24 19:12:05 +01:00
{
bool fMissingMasternode = false ;
2017-07-05 02:31:50 +02:00
bool fMissingConfirmations = false ;
2016-11-24 19:12:05 +01:00
2017-07-05 02:31:50 +02:00
return IsValidLocally ( strError , fMissingMasternode , fMissingConfirmations , fCheckCollateral ) ;
2016-11-24 19:12:05 +01:00
}
2018-03-20 12:04:59 +01:00
bool CGovernanceObject : : IsValidLocally ( std : : string & strError , bool & fMissingMasternode , bool & fMissingConfirmations , bool fCheckCollateral ) const
2016-11-24 19:12:05 +01:00
{
fMissingMasternode = false ;
2017-07-05 02:31:50 +02:00
fMissingConfirmations = false ;
2016-11-24 19:12:05 +01:00
2018-03-20 12:04:59 +01:00
if ( fUnparsable ) {
2016-11-24 19:12:05 +01:00
strError = " Object data unparseable " ;
return false ;
}
switch ( nObjectType ) {
2018-03-20 12:04:59 +01:00
case GOVERNANCE_OBJECT_WATCHDOG : {
2018-02-25 06:33:27 +01:00
// watchdogs are deprecated
return false ;
2018-03-20 12:04:59 +01:00
}
case GOVERNANCE_OBJECT_PROPOSAL : {
2018-03-21 12:09:13 +01:00
CProposalValidator validator ( GetDataAsHexString ( ) ) ;
// Note: It's ok to have expired proposals
// they are going to be cleared by CGovernanceManager::UpdateCachesAndClean()
// TODO: should they be tagged as "expired" to skip vote downloading?
2018-06-06 18:06:23 +02:00
if ( ! validator . Validate ( false ) ) {
2018-03-21 12:09:13 +01:00
strError = strprintf ( " Invalid proposal data, error messages: %s " , validator . GetErrorMessages ( ) ) ;
return false ;
}
2018-03-20 12:04:59 +01:00
if ( fCheckCollateral & & ! IsCollateralValid ( strError , fMissingConfirmations ) ) {
strError = " Invalid proposal collateral " ;
2018-02-15 15:43:17 +01:00
return false ;
}
2018-03-20 12:04:59 +01:00
return true ;
}
case GOVERNANCE_OBJECT_TRIGGER : {
if ( ! fCheckCollateral )
// nothing else we can check here (yet?)
return true ;
2016-11-24 19:12:05 +01:00
2018-02-15 08:29:44 +01:00
std : : string strOutpoint = masternodeOutpoint . ToStringShort ( ) ;
2017-09-11 16:13:48 +02:00
masternode_info_t infoMn ;
2018-03-20 12:04:59 +01:00
if ( ! mnodeman . GetMasternodeInfo ( masternodeOutpoint , infoMn ) ) {
2017-07-13 11:38:00 +02:00
2018-08-11 21:55:56 +02:00
CMasternode : : CollateralStatus err = CMasternode : : CheckCollateral ( masternodeOutpoint , CKeyID ( ) ) ;
2017-12-21 14:03:02 +01:00
if ( err = = CMasternode : : COLLATERAL_UTXO_NOT_FOUND ) {
2017-09-11 16:13:48 +02:00
strError = " Failed to find Masternode UTXO, missing masternode= " + strOutpoint + " \n " ;
2018-02-15 18:25:20 +01:00
} else if ( err = = CMasternode : : COLLATERAL_UTXO_NOT_PROTX ) {
strError = " Masternode UTXO is not a ProTx, missing masternode= " + strOutpoint + " \n " ;
2017-07-13 11:38:00 +02:00
} else if ( err = = CMasternode : : COLLATERAL_INVALID_AMOUNT ) {
2017-09-11 16:13:48 +02:00
strError = " Masternode UTXO should have 1000 DASH, missing masternode= " + strOutpoint + " \n " ;
2017-12-21 14:03:02 +01:00
} else if ( err = = CMasternode : : COLLATERAL_INVALID_PUBKEY ) {
fMissingMasternode = true ;
strError = " Masternode not found: " + strOutpoint ;
} else if ( err = = CMasternode : : COLLATERAL_OK ) {
// this should never happen with CPubKey() as a param
strError = " CheckCollateral critical failure! Masternode: " + strOutpoint ;
2017-07-13 11:38:00 +02:00
}
2016-11-24 19:12:05 +01:00
return false ;
}
// Check that we have a valid MN signature
2018-08-31 15:31:59 +02:00
if ( ! CheckSignature ( infoMn . keyIDOperator ) ) {
strError = " Invalid masternode signature for: " + strOutpoint + " , pubkey id = " + infoMn . keyIDOperator . ToString ( ) ;
2016-11-24 19:12:05 +01:00
return false ;
}
return true ;
}
2018-03-20 12:04:59 +01:00
default : {
strError = strprintf ( " Invalid object type %d " , nObjectType ) ;
2016-11-24 19:12:05 +01:00
return false ;
2018-03-20 12:04:59 +01:00
}
2016-11-24 19:12:05 +01:00
}
}
2018-03-20 12:04:59 +01:00
CAmount CGovernanceObject : : GetMinCollateralFee ( ) const
2016-11-24 19:12:05 +01:00
{
// Only 1 type has a fee for the moment but switch statement allows for future object types
switch ( nObjectType ) {
case GOVERNANCE_OBJECT_PROPOSAL : return GOVERNANCE_PROPOSAL_FEE_TX ;
case GOVERNANCE_OBJECT_TRIGGER : return 0 ;
case GOVERNANCE_OBJECT_WATCHDOG : return 0 ;
default : return MAX_MONEY ;
}
}
2018-03-20 12:04:59 +01:00
bool CGovernanceObject : : IsCollateralValid ( std : : string & strError , bool & fMissingConfirmations ) const
2016-11-24 19:12:05 +01:00
{
strError = " " ;
2017-07-05 02:31:50 +02:00
fMissingConfirmations = false ;
2016-11-24 19:12:05 +01:00
CAmount nMinFee = GetMinCollateralFee ( ) ;
uint256 nExpectedHash = GetHash ( ) ;
2016-12-05 08:01:20 +01:00
CTransactionRef txCollateral ;
2016-11-24 19:12:05 +01:00
uint256 nBlockHash ;
// RETRIEVE TRANSACTION IN QUESTION
if ( ! GetTransaction ( nCollateralHash , txCollateral , Params ( ) . GetConsensus ( ) , nBlockHash , true ) ) {
2018-04-05 14:34:40 +02:00
strError = strprintf ( " Can't find collateral tx %s " , nCollateralHash . ToString ( ) ) ;
2016-11-24 19:12:05 +01:00
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
return false ;
}
2018-03-19 14:08:32 +01:00
if ( nBlockHash = = uint256 ( ) ) {
strError = strprintf ( " Collateral tx %s is not mined yet " , txCollateral - > ToString ( ) ) ;
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
return false ;
}
2016-12-05 08:01:20 +01:00
if ( txCollateral - > vout . size ( ) < 1 ) {
strError = strprintf ( " tx vout size less than 1 | %d " , txCollateral - > vout . size ( ) ) ;
2016-11-24 19:12:05 +01:00
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
return false ;
}
// LOOK FOR SPECIALIZED GOVERNANCE SCRIPT (PROOF OF BURN)
CScript findScript ;
findScript < < OP_RETURN < < ToByteVector ( nExpectedHash ) ;
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " IsCollateralValid: txCollateral->vout.size() = " < < txCollateral - > vout . size ( ) < < std : : endl ; ) ;
2016-11-24 19:12:05 +01:00
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " IsCollateralValid: findScript = " < < ScriptToAsmStr ( findScript , false ) < < std : : endl ; ) ;
2016-11-24 19:12:05 +01:00
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " IsCollateralValid: nMinFee = " < < nMinFee < < std : : endl ; ) ;
2016-11-24 19:12:05 +01:00
bool foundOpReturn = false ;
2018-02-06 12:09:33 +01:00
for ( const auto & output : txCollateral - > vout ) {
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " IsCollateralValid txout : " < < output . ToString ( )
2018-02-06 12:09:33 +01:00
< < " , output.nValue = " < < output . nValue
< < " , output.scriptPubKey = " < < ScriptToAsmStr ( output . scriptPubKey , false )
2018-02-21 21:24:28 +01:00
< < std : : endl ; ) ;
2018-02-06 12:09:33 +01:00
if ( ! output . scriptPubKey . IsPayToPublicKeyHash ( ) & & ! output . scriptPubKey . IsUnspendable ( ) ) {
2016-12-05 08:01:20 +01:00
strError = strprintf ( " Invalid Script %s " , txCollateral - > ToString ( ) ) ;
2016-11-24 19:12:05 +01:00
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
return false ;
}
2018-02-06 12:09:33 +01:00
if ( output . scriptPubKey = = findScript & & output . nValue > = nMinFee ) {
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " IsCollateralValid foundOpReturn = true " < < std : : endl ; ) ;
2016-11-24 19:12:05 +01:00
foundOpReturn = true ;
}
else {
2018-02-21 21:24:28 +01:00
DBG ( std : : cout < < " IsCollateralValid No match, continuing " < < std : : endl ; ) ;
2016-11-24 19:12:05 +01:00
}
}
if ( ! foundOpReturn ) {
2016-12-05 08:01:20 +01:00
strError = strprintf ( " Couldn't find opReturn %s in %s " , nExpectedHash . ToString ( ) , txCollateral - > ToString ( ) ) ;
2016-11-24 19:12:05 +01:00
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
return false ;
}
// GET CONFIRMATIONS FOR TRANSACTION
2017-07-13 11:38:00 +02:00
AssertLockHeld ( cs_main ) ;
2018-07-28 18:39:37 +02:00
int nConfirmationsIn = 0 ;
2016-11-24 19:12:05 +01:00
if ( nBlockHash ! = uint256 ( ) ) {
BlockMap : : iterator mi = mapBlockIndex . find ( nBlockHash ) ;
if ( mi ! = mapBlockIndex . end ( ) & & ( * mi ) . second ) {
CBlockIndex * pindex = ( * mi ) . second ;
if ( chainActive . Contains ( pindex ) ) {
nConfirmationsIn + = chainActive . Height ( ) - pindex - > nHeight + 1 ;
}
}
}
2018-07-28 18:39:37 +02:00
if ( ( nConfirmationsIn < GOVERNANCE_FEE_CONFIRMATIONS ) & &
( ! instantsend . IsLockedInstantSendTransaction ( nCollateralHash ) ) ) {
2017-07-05 02:31:50 +02:00
strError = strprintf ( " Collateral requires at least %d confirmations to be relayed throughout the network (it has only %d) " , GOVERNANCE_FEE_CONFIRMATIONS , nConfirmationsIn ) ;
if ( nConfirmationsIn > = GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS ) {
fMissingConfirmations = true ;
strError + = " , pre-accepted -- waiting for required confirmations " ;
} else {
strError + = " , rejected -- try again later " ;
}
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
2016-11-24 19:12:05 +01:00
return false ;
}
2017-07-05 02:31:50 +02:00
strError = " valid " ;
2016-11-24 19:12:05 +01:00
return true ;
}
int CGovernanceObject : : CountMatchingVotes ( vote_signal_enum_t eVoteSignalIn , vote_outcome_enum_t eVoteOutcomeIn ) const
{
2018-03-09 15:15:48 +01:00
LOCK ( cs ) ;
2016-11-24 19:12:05 +01:00
int nCount = 0 ;
2018-03-20 12:04:59 +01:00
for ( const auto & votepair : mapCurrentMNVotes ) {
const vote_rec_t & recVote = votepair . second ;
2016-11-24 19:12:05 +01:00
vote_instance_m_cit it2 = recVote . mapInstances . find ( eVoteSignalIn ) ;
2018-03-20 12:04:59 +01:00
if ( it2 ! = recVote . mapInstances . end ( ) & & it2 - > second . eOutcome = = eVoteOutcomeIn ) {
2016-11-24 19:12:05 +01:00
+ + nCount ;
}
}
return nCount ;
}
/**
* Get specific vote counts for each outcome ( funding , validity , etc )
*/
int CGovernanceObject : : GetAbsoluteYesCount ( vote_signal_enum_t eVoteSignalIn ) const
{
return GetYesCount ( eVoteSignalIn ) - GetNoCount ( eVoteSignalIn ) ;
}
int CGovernanceObject : : GetAbsoluteNoCount ( vote_signal_enum_t eVoteSignalIn ) const
{
return GetNoCount ( eVoteSignalIn ) - GetYesCount ( eVoteSignalIn ) ;
}
int CGovernanceObject : : GetYesCount ( vote_signal_enum_t eVoteSignalIn ) const
{
return CountMatchingVotes ( eVoteSignalIn , VOTE_OUTCOME_YES ) ;
}
int CGovernanceObject : : GetNoCount ( vote_signal_enum_t eVoteSignalIn ) const
{
return CountMatchingVotes ( eVoteSignalIn , VOTE_OUTCOME_NO ) ;
}
int CGovernanceObject : : GetAbstainCount ( vote_signal_enum_t eVoteSignalIn ) const
{
return CountMatchingVotes ( eVoteSignalIn , VOTE_OUTCOME_ABSTAIN ) ;
}
2018-03-20 12:04:59 +01:00
bool CGovernanceObject : : GetCurrentMNVotes ( const COutPoint & mnCollateralOutpoint , vote_rec_t & voteRecord ) const
2016-11-24 19:12:05 +01:00
{
2018-03-09 15:15:48 +01:00
LOCK ( cs ) ;
2018-03-20 12:04:59 +01:00
vote_m_cit it = mapCurrentMNVotes . find ( mnCollateralOutpoint ) ;
2016-11-24 19:12:05 +01:00
if ( it = = mapCurrentMNVotes . end ( ) ) {
return false ;
}
voteRecord = it - > second ;
return true ;
}
2017-09-19 16:51:38 +02:00
void CGovernanceObject : : Relay ( CConnman & connman )
2016-11-24 19:12:05 +01:00
{
2017-12-14 01:33:58 +01:00
// Do not relay until fully synced
if ( ! masternodeSync . IsSynced ( ) ) {
LogPrint ( " gobject " , " CGovernanceObject::Relay -- won't relay until fully synced \n " ) ;
return ;
}
2016-11-24 19:12:05 +01:00
CInv inv ( MSG_GOVERNANCE_OBJECT , GetHash ( ) ) ;
2017-10-04 22:12:53 +02:00
connman . RelayInv ( inv , MIN_GOVERNANCE_PEER_PROTO_VERSION ) ;
2016-11-24 19:12:05 +01:00
}
2016-12-11 07:17:38 +01:00
void CGovernanceObject : : UpdateSentinelVariables ( )
2016-11-24 19:12:05 +01:00
{
// CALCULATE MINIMUM SUPPORT LEVELS REQUIRED
int nMnCount = mnodeman . CountEnabled ( ) ;
if ( nMnCount = = 0 ) return ;
// CALCULATE THE MINUMUM VOTE COUNT REQUIRED FOR FULL SIGNAL
int nAbsVoteReq = std : : max ( Params ( ) . GetConsensus ( ) . nGovernanceMinQuorum , nMnCount / 10 ) ;
2016-11-25 15:08:48 +01:00
int nAbsDeleteReq = std : : max ( Params ( ) . GetConsensus ( ) . nGovernanceMinQuorum , ( 2 * nMnCount ) / 3 ) ;
2016-11-24 19:12:05 +01:00
// SET SENTINEL FLAGS TO FALSE
fCachedFunding = false ;
fCachedValid = true ; //default to valid
fCachedEndorsed = false ;
fDirtyCache = false ;
// SET SENTINEL FLAGS TO TRUE IF MIMIMUM SUPPORT LEVELS ARE REACHED
// ARE ANY OF THESE FLAGS CURRENTLY ACTIVATED?
if ( GetAbsoluteYesCount ( VOTE_SIGNAL_FUNDING ) > = nAbsVoteReq ) fCachedFunding = true ;
2016-12-14 16:27:46 +01:00
if ( ( GetAbsoluteYesCount ( VOTE_SIGNAL_DELETE ) > = nAbsDeleteReq ) & & ! fCachedDelete ) {
2016-11-24 19:12:05 +01:00
fCachedDelete = true ;
2016-12-14 16:27:46 +01:00
if ( nDeletionTime = = 0 ) {
nDeletionTime = GetAdjustedTime ( ) ;
}
2016-11-24 19:12:05 +01:00
}
if ( GetAbsoluteYesCount ( VOTE_SIGNAL_ENDORSED ) > = nAbsVoteReq ) fCachedEndorsed = true ;
if ( GetAbsoluteNoCount ( VOTE_SIGNAL_VALID ) > = nAbsVoteReq ) fCachedValid = false ;
}
2017-09-19 16:51:38 +02:00
void CGovernanceObject : : CheckOrphanVotes ( CConnman & connman )
2016-11-24 19:12:05 +01:00
{
int64_t nNow = GetAdjustedTime ( ) ;
2018-02-06 12:08:43 +01:00
const vote_cmm_t : : list_t & listVotes = cmmapOrphanVotes . GetItemList ( ) ;
vote_cmm_t : : list_cit it = listVotes . begin ( ) ;
2016-11-24 19:12:05 +01:00
while ( it ! = listVotes . end ( ) ) {
bool fRemove = false ;
2017-09-11 16:13:48 +02:00
const COutPoint & key = it - > key ;
2016-11-24 19:12:05 +01:00
const vote_time_pair_t & pairVote = it - > value ;
const CGovernanceVote & vote = pairVote . first ;
if ( pairVote . second < nNow ) {
fRemove = true ;
}
2017-09-11 16:13:48 +02:00
else if ( ! mnodeman . Has ( vote . GetMasternodeOutpoint ( ) ) ) {
2016-11-24 19:12:05 +01:00
+ + it ;
continue ;
}
CGovernanceException exception ;
2018-07-12 11:08:43 +02:00
if ( ! ProcessVote ( nullptr , vote , exception , connman ) ) {
2016-11-24 19:12:05 +01:00
LogPrintf ( " CGovernanceObject::CheckOrphanVotes -- Failed to add orphan vote: %s \n " , exception . what ( ) ) ;
}
else {
2017-09-19 16:51:38 +02:00
vote . Relay ( connman ) ;
2016-11-24 19:12:05 +01:00
fRemove = true ;
}
+ + it ;
if ( fRemove ) {
2018-02-06 12:08:43 +01:00
cmmapOrphanVotes . Erase ( key , pairVote ) ;
2016-11-24 19:12:05 +01:00
}
}
}