2021-04-20 21:33:02 +02:00
// Copyright (c) 2014-2021 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.
2020-03-19 23:46:56 +01:00
# include <governance/governance-object.h>
2021-04-23 00:32:03 +02:00
2020-03-19 23:46:56 +01:00
# include <core_io.h>
2021-04-23 00:32:03 +02:00
# include <evo/deterministicmns.h>
2020-03-19 23:46:56 +01:00
# include <governance/governance-validators.h>
# include <governance/governance.h>
# include <masternode/masternode-meta.h>
# include <masternode/masternode-sync.h>
# include <messagesigner.h>
2021-04-23 00:32:03 +02:00
# include <net.h>
2020-03-19 23:46:56 +01:00
# include <validation.h>
2020-11-09 22:58:04 +01:00
# include <validationinterface.h>
2016-12-20 14:27:59 +01:00
2018-07-12 11:02:20 +02:00
# include <string>
2016-11-24 19:12:05 +01:00
2018-09-28 09:56:17 +02:00
CGovernanceObject : : CGovernanceObject ( ) :
2018-02-21 17:32:08 +01:00
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 ( ) ,
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-09-28 09:56:17 +02:00
CGovernanceObject : : CGovernanceObject ( const uint256 & nHashParentIn , int nRevisionIn , int64_t nTimeIn , const uint256 & nCollateralHashIn , const std : : string & strDataHexIn ) :
2018-02-21 17:32:08 +01:00
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 ( ) ,
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-09-28 09:56:17 +02:00
CGovernanceObject : : CGovernanceObject ( const CGovernanceObject & other ) :
2018-02-21 17:32:08 +01:00
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 ) ,
fileVotes ( other . fileVotes )
2018-09-28 09:56:17 +02:00
{
}
2016-11-24 19:12:05 +01:00
2021-06-26 15:09:09 +02:00
bool CGovernanceObject : : ProcessVote ( const CGovernanceVote & vote , CGovernanceException & exception )
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 " ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " %s \n " , ostr . str ( ) ) ;
2018-03-19 14:08:32 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_NONE ) ;
return false ;
}
2018-12-17 14:34:50 +01:00
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
2019-06-13 11:03:20 +02:00
auto dmn = mnList . GetMNByCollateral ( vote . GetMasternodeOutpoint ( ) ) ;
2018-12-17 14:34:50 +01:00
2019-01-03 21:08:34 +01:00
if ( ! dmn ) {
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 " ;
2019-05-29 20:19:53 +02:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_PERMANENT_ERROR , 20 ) ;
2016-11-24 19:12:05 +01:00
return false ;
}
2021-01-26 04:31:31 +01:00
auto it = mapCurrentMNVotes . emplace ( vote_m_t : : value_type ( vote . GetMasternodeOutpoint ( ) , vote_rec_t ( ) ) ) . first ;
2018-03-20 12:04:59 +01:00
vote_rec_t & voteRecordRef = it - > second ;
2016-11-24 19:12:05 +01:00
vote_signal_enum_t eSignal = vote . GetSignal ( ) ;
2018-09-28 09:56:17 +02:00
if ( eSignal = = VOTE_SIGNAL_NONE ) {
2016-11-24 19:12:05 +01:00
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Vote signal: none " ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_WARNING ) ;
return false ;
}
2018-09-28 09:56:17 +02:00
if ( eSignal > MAX_SUPPORTED_VOTE_SIGNAL ) {
2016-11-24 19:12:05 +01:00
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 ;
}
2021-01-26 04:31:31 +01:00
auto it2 = voteRecordRef . mapInstances . emplace ( vote_instance_m_t : : value_type ( int ( eSignal ) , vote_instance_t ( ) ) ) . first ;
2018-03-20 12:04:59 +01:00
vote_instance_t & voteInstanceRef = it2 - > second ;
2017-02-23 13:29:00 +01:00
// Reject obsolete votes
2018-09-28 09:56:17 +02: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 " ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " %s \n " , ostr . str ( ) ) ;
2017-02-23 13:29:00 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_NONE ) ;
return false ;
2019-04-01 13:10:28 +02:00
} else if ( vote . GetTimestamp ( ) = = voteInstanceRef . nCreationTime ) {
2020-01-08 08:02:49 +01:00
// Someone is doing something fishy, there can be no two votes from the same masternode
2019-04-01 13:10:28 +02:00
// with the same timestamp for the same object and signal and yet different hash/outcome.
std : : ostringstream ostr ;
ostr < < " CGovernanceObject::ProcessVote -- Invalid vote, same timestamp for the different outcome " ;
if ( vote . GetOutcome ( ) < voteInstanceRef . eOutcome ) {
// This is an arbitrary comparison, we have to agree on some way
// to pick the "winning" vote.
ostr < < " , rejected " ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " %s \n " , ostr . str ( ) ) ;
2019-04-01 13:10:28 +02:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_NONE ) ;
return false ;
}
ostr < < " , accepted " ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " %s \n " , ostr . str ( ) ) ;
2017-02-23 13:29:00 +01:00
}
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 ;
2018-09-28 09:56:17 +02:00
if ( governance . AreRateChecksEnabled ( ) ) {
2018-03-20 12:04:59 +01:00
int64_t nTimeDelta = nNow - voteInstanceRef . nTime ;
2018-09-28 09:56:17 +02:00
if ( nTimeDelta < GOVERNANCE_UPDATE_MIN ) {
2016-11-24 19:12:05 +01:00
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 ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
exception = CGovernanceException ( ostr . str ( ) , GOVERNANCE_EXCEPTION_TEMPORARY_ERROR ) ;
return false ;
}
2019-03-30 15:54:39 +01:00
nVoteTimeUpdate = nNow ;
2016-11-24 19:12:05 +01:00
}
2018-03-20 12:04:59 +01:00
2018-12-20 14:27:48 +01:00
bool onlyVotingKeyAllowed = nObjectType = = GOVERNANCE_OBJECT_PROPOSAL & & vote . GetSignal ( ) = = VOTE_SIGNAL_FUNDING ;
2018-08-31 15:31:59 +02:00
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-12-20 14:27:48 +01:00
if ( ! vote . IsValid ( onlyVotingKeyAllowed ) ) {
2016-11-24 19:12:05 +01:00
std : : ostringstream ostr ;
2017-06-06 01:47:23 +02:00
ostr < < " CGovernanceObject::ProcessVote -- Invalid vote "
2018-09-28 09:56:17 +02:00
< < " , MN outpoint = " < < vote . GetMasternodeOutpoint ( ) . ToStringShort ( )
< < " , governance object hash = " < < GetHash ( ) . ToString ( )
< < " , vote hash = " < < vote . GetHash ( ) . ToString ( ) ;
2017-06-06 01:47:23 +02:00
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
2019-01-03 21:08:34 +01:00
if ( ! mmetaman . AddGovernanceVote ( dmn - > proTxHash , 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 ( ) ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : 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 ;
2020-11-09 22:58:04 +01:00
// SEND NOTIFICATION TO SCRIPT/ZMQ
2021-01-22 05:32:15 +01:00
GetMainSignals ( ) . NotifyGovernanceVote ( std : : make_shared < const CGovernanceVote > ( vote ) ) ;
2016-11-24 19:12:05 +01:00
return true ;
}
void CGovernanceObject : : ClearMasternodeVotes ( )
{
2018-03-09 15:15:48 +01:00
LOCK ( cs ) ;
2018-12-17 14:34:50 +01:00
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
2021-01-26 04:31:31 +01:00
auto it = mapCurrentMNVotes . begin ( ) ;
2018-09-28 09:56:17 +02:00
while ( it ! = mapCurrentMNVotes . end ( ) ) {
2019-06-13 11:03:20 +02:00
if ( ! mnList . HasMNByCollateral ( it - > first ) ) {
2017-08-25 14:57:19 +02:00
fileVotes . RemoveVotesFromMasternode ( it - > first ) ;
2016-11-24 19:12:05 +01:00
mapCurrentMNVotes . erase ( it + + ) ;
2019-08-23 20:03:05 +02:00
fDirtyCache = true ;
2018-09-28 09:56:17 +02:00
} else {
2016-11-24 19:12:05 +01:00
+ + it ;
}
}
}
2019-03-30 15:54:22 +01:00
std : : set < uint256 > CGovernanceObject : : RemoveInvalidVotes ( const COutPoint & mnOutpoint )
2018-12-20 14:27:48 +01:00
{
LOCK ( cs ) ;
auto it = mapCurrentMNVotes . find ( mnOutpoint ) ;
if ( it = = mapCurrentMNVotes . end ( ) ) {
// don't even try as we don't have any votes from this MN
return { } ;
}
2019-03-30 15:54:22 +01:00
auto removedVotes = fileVotes . RemoveInvalidVotes ( mnOutpoint , nObjectType = = GOVERNANCE_OBJECT_PROPOSAL ) ;
2018-12-20 14:27:48 +01:00
if ( removedVotes . empty ( ) ) {
return { } ;
}
auto nParentHash = GetHash ( ) ;
for ( auto jt = it - > second . mapInstances . begin ( ) ; jt ! = it - > second . mapInstances . end ( ) ; ) {
CGovernanceVote tmpVote ( mnOutpoint , nParentHash , ( vote_signal_enum_t ) jt - > first , jt - > second . eOutcome ) ;
tmpVote . SetTime ( jt - > second . nCreationTime ) ;
if ( removedVotes . count ( tmpVote . GetHash ( ) ) ) {
jt = it - > second . mapInstances . erase ( jt ) ;
} else {
+ + jt ;
}
}
if ( it - > second . mapInstances . empty ( ) ) {
mapCurrentMNVotes . erase ( it ) ;
}
if ( ! removedVotes . empty ( ) ) {
std : : string removedStr ;
for ( auto & h : removedVotes ) {
removedStr + = strprintf ( " %s \n " , h . ToString ( ) ) ;
}
2020-06-12 17:45:05 +02:00
LogPrintf ( " CGovernanceObject::%s -- Removed %d invalid votes for %s from MN %s: \n %s " , __func__ , removedVotes . size ( ) , nParentHash . ToString ( ) , mnOutpoint . ToString ( ) , removedStr ) ; /* Continued */
2018-12-20 14:27:48 +01:00
fDirtyCache = true ;
}
return removedVotes ;
}
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
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-10-21 21:45:16 +02:00
bool CGovernanceObject : : Sign ( const CBLSSecretKey & key )
{
CBLSSignature sig = key . Sign ( GetSignatureHash ( ) ) ;
2021-02-01 16:23:58 +01:00
if ( ! sig . IsValid ( ) ) {
2018-12-06 08:07:10 +01:00
return false ;
}
2021-02-27 08:36:00 +01:00
vchSig = sig . ToByteVector ( ) ;
2018-10-21 21:45:16 +02:00
return true ;
}
bool CGovernanceObject : : CheckSignature ( const CBLSPublicKey & pubKey ) const
{
2020-12-15 00:26:30 +01:00
if ( ! CBLSSignature ( vchSig ) . VerifyInsecure ( pubKey , GetSignatureHash ( ) ) ) {
2018-10-21 21:45:16 +02:00
LogPrintf ( " CGovernanceObject::CheckSignature -- VerifyInsecure() failed \n " ) ;
return false ;
}
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 .
*/
2021-06-26 15:09:09 +02:00
UniValue CGovernanceObject : : GetJSONObject ( ) const
2016-11-24 19:12:05 +01:00
{
UniValue obj ( UniValue : : VOBJ ) ;
2018-09-28 09:56:17 +02: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 ( ) ;
2018-09-28 09:56:17 +02:00
std : : vector < UniValue > arr2 = arr1 . at ( 0 ) . getValues ( ) ;
obj = arr2 . at ( 1 ) ;
2018-02-28 00:20:16 +01:00
}
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 ( )
{
2018-09-28 09:56:17 +02:00
if ( vchData . empty ( ) ) {
2016-11-24 19:12:05 +01:00
return ;
}
2018-09-28 09:56:17 +02:00
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 ) ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceObject::LoadData -- GetDataAsPlainString = %s \n " , GetDataAsPlainString ( ) ) ;
2016-11-24 19:12:05 +01:00
UniValue obj = GetJSONObject ( ) ;
nObjectType = obj [ " type " ] . get_int ( ) ;
2018-09-28 09:56:17 +02:00
} catch ( std : : exception & e ) {
2016-11-24 19:12:05 +01:00
fUnparsable = true ;
std : : ostringstream ostr ;
ostr < < " CGovernanceObject::LoadData Error parsing JSON "
< < " , e.what() = " < < e . what ( ) ;
2017-06-06 01:47:23 +02:00
LogPrintf ( " %s \n " , ostr . str ( ) ) ;
2016-11-24 19:12:05 +01:00
return ;
2018-09-28 09:56:17 +02:00
} catch ( . . . ) {
2016-11-24 19:12:05 +01:00
fUnparsable = true ;
std : : ostringstream ostr ;
ostr < < " CGovernanceObject::LoadData Unknown Error parsing JSON " ;
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 )
*
*/
2021-06-26 15:09:09 +02:00
void CGovernanceObject : : GetData ( UniValue & objResult ) const
2016-11-24 19:12:05 +01:00
{
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
}
2020-12-01 04:55:29 +01:00
UniValue CGovernanceObject : : ToJson ( ) const
{
UniValue obj ( UniValue : : VOBJ ) ;
obj . pushKV ( " objectHash " , GetHash ( ) . ToString ( ) ) ;
obj . pushKV ( " parentHash " , nHashParent . ToString ( ) ) ;
obj . pushKV ( " collateralHash " , GetCollateralHash ( ) . ToString ( ) ) ;
obj . pushKV ( " createdAt " , GetCreationTime ( ) ) ;
obj . pushKV ( " revision " , nRevision ) ;
UniValue data ;
if ( ! data . read ( GetDataAsPlainString ( ) ) ) {
data . clear ( ) ;
data . setObject ( ) ;
data . pushKV ( " plain " , GetDataAsPlainString ( ) ) ;
data . pushKV ( " hex " , GetDataAsHexString ( ) ) ;
} else {
data . pushKV ( " hex " , GetDataAsHexString ( ) ) ;
}
obj . pushKV ( " data " , data ) ;
return obj ;
}
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 ) ;
2021-01-26 04:31:31 +01:00
}
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
{
2017-07-05 02:31:50 +02:00
bool fMissingConfirmations = false ;
2016-11-24 19:12:05 +01:00
2019-05-29 20:19:53 +02:00
return IsValidLocally ( strError , fMissingConfirmations , fCheckCollateral ) ;
2016-11-24 19:12:05 +01:00
}
2019-05-29 20:19:53 +02:00
bool CGovernanceObject : : IsValidLocally ( std : : string & strError , bool & fMissingConfirmations , bool fCheckCollateral ) const
2016-11-24 19:12:05 +01:00
{
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 ) {
2021-07-17 21:15:21 +02:00
strError = " Object data unparsable " ;
2016-11-24 19:12:05 +01:00
return false ;
}
2018-09-28 09:56:17 +02:00
switch ( nObjectType ) {
case GOVERNANCE_OBJECT_PROPOSAL : {
2019-02-26 11:44:43 +01:00
CProposalValidator validator ( GetDataAsHexString ( ) , true ) ;
2018-09-28 09:56:17 +02:00
// 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?
if ( ! validator . Validate ( false ) ) {
strError = strprintf ( " Invalid proposal data, error messages: %s " , validator . GetErrorMessages ( ) ) ;
2018-02-25 06:33:27 +01:00
return false ;
2018-03-20 12:04:59 +01:00
}
2018-09-28 09:56:17 +02:00
if ( fCheckCollateral & & ! IsCollateralValid ( strError , fMissingConfirmations ) ) {
strError = " Invalid proposal collateral " ;
return false ;
}
return true ;
}
case GOVERNANCE_OBJECT_TRIGGER : {
if ( ! fCheckCollateral ) {
// nothing else we can check here (yet?)
2018-03-20 12:04:59 +01:00
return true ;
}
2016-11-24 19:12:05 +01:00
2018-12-17 15:39:21 +01:00
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
2018-09-28 09:56:17 +02:00
std : : string strOutpoint = masternodeOutpoint . ToStringShort ( ) ;
2019-01-03 10:17:43 +01:00
auto dmn = mnList . GetMNByCollateral ( masternodeOutpoint ) ;
2018-12-17 15:39:21 +01:00
if ( ! dmn ) {
2019-04-30 14:48:21 +02:00
strError = " Failed to find Masternode by UTXO, missing masternode= " + strOutpoint ;
2019-01-03 10:17:43 +01:00
return false ;
}
2018-09-28 09:56:17 +02:00
// Check that we have a valid MN signature
2019-06-13 11:01:26 +02:00
if ( ! CheckSignature ( dmn - > pdmnState - > pubKeyOperator . Get ( ) ) ) {
strError = " Invalid masternode signature for: " + strOutpoint + " , pubkey = " + dmn - > pdmnState - > pubKeyOperator . Get ( ) . ToString ( ) ;
2018-12-17 15:39:21 +01:00
return false ;
2018-03-20 12:04:59 +01:00
}
2016-11-24 19:12:05 +01:00
2018-09-28 09:56:17 +02:00
return true ;
}
default : {
strError = strprintf ( " Invalid object type %d " , nObjectType ) ;
return false ;
}
}
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
2018-09-28 09:56:17 +02:00
switch ( nObjectType ) {
case GOVERNANCE_OBJECT_PROPOSAL :
return GOVERNANCE_PROPOSAL_FEE_TX ;
case GOVERNANCE_OBJECT_TRIGGER :
return 0 ;
default :
return MAX_MONEY ;
2016-11-24 19:12:05 +01:00
}
}
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
2021-08-05 17:46:17 +02:00
if ( ! GetTransaction ( nCollateralHash , txCollateral , Params ( ) . GetConsensus ( ) , nBlockHash ) ) {
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-09-28 09:56:17 +02:00
if ( nBlockHash = = uint256 ( ) ) {
2018-03-19 14:08:32 +01:00
strError = strprintf ( " Collateral tx %s is not mined yet " , txCollateral - > ToString ( ) ) ;
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
return false ;
}
2021-06-06 23:35:29 +02:00
if ( txCollateral - > vout . empty ( ) ) {
strError = " tx vout is empty " ;
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 ) ;
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceObject::IsCollateralValid -- txCollateral->vout.size() = %s, findScript = %s, nMinFee = %lld \n " ,
2019-03-25 07:15:32 +01:00
txCollateral - > vout . size ( ) , ScriptToAsmStr ( findScript , false ) , nMinFee ) ;
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 ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceObject::IsCollateralValid -- txout = %s, output.nValue = %lld, output.scriptPubKey = %s \n " ,
2019-03-25 07:15:32 +01:00
output . ToString ( ) , output . nValue , ScriptToAsmStr ( output . scriptPubKey , false ) ) ;
2018-09-28 09:56:17 +02:00
if ( ! output . scriptPubKey . IsPayToPublicKeyHash ( ) & & ! output . scriptPubKey . IsUnspendable ( ) ) {
2016-12-05 08:01:20 +01:00
strError = strprintf ( " Invalid Script %s " , txCollateral - > ToString ( ) ) ;
2018-09-28 09:56:17 +02:00
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
2016-11-24 19:12:05 +01:00
return false ;
}
2018-09-28 09:56:17 +02:00
if ( output . scriptPubKey = = findScript & & output . nValue > = nMinFee ) {
2016-11-24 19:12:05 +01:00
foundOpReturn = true ;
}
}
2018-09-28 09:56:17 +02:00
if ( ! foundOpReturn ) {
2016-12-05 08:01:20 +01:00
strError = strprintf ( " Couldn't find opReturn %s in %s " , nExpectedHash . ToString ( ) , txCollateral - > ToString ( ) ) ;
2018-09-28 09:56:17 +02:00
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
2016-11-24 19:12:05 +01:00
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 ( ) ) {
2021-06-26 15:09:09 +02:00
const CBlockIndex * pindex = LookupBlockIndex ( nBlockHash ) ;
2018-03-13 19:04:28 +01:00
if ( pindex & & chainActive . Contains ( pindex ) ) {
nConfirmationsIn + = chainActive . Height ( ) - pindex - > nHeight + 1 ;
2016-11-24 19:12:05 +01:00
}
}
2021-06-26 15:09:09 +02:00
if ( nConfirmationsIn < GOVERNANCE_FEE_CONFIRMATIONS ) {
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 " ;
}
2018-09-28 09:56:17 +02:00
LogPrintf ( " CGovernanceObject::IsCollateralValid -- %s \n " , strError ) ;
2017-07-05 02:31:50 +02:00
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 ;
2021-01-26 04:31:31 +01:00
auto it2 = recVote . mapInstances . find ( eVoteSignalIn ) ;
2018-09-28 09:56:17 +02: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 ) ;
2021-01-26 04:31:31 +01:00
auto it = mapCurrentMNVotes . find ( mnCollateralOutpoint ) ;
2016-11-24 19:12:05 +01:00
if ( it = = mapCurrentMNVotes . end ( ) ) {
return false ;
}
voteRecord = it - > second ;
2018-09-28 09:56:17 +02:00
return true ;
2016-11-24 19:12:05 +01:00
}
2021-06-26 15:09:09 +02:00
void CGovernanceObject : : Relay ( CConnman & connman ) const
2016-11-24 19:12:05 +01:00
{
2017-12-14 01:33:58 +01:00
// Do not relay until fully synced
2018-09-28 09:56:17 +02:00
if ( ! masternodeSync . IsSynced ( ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceObject::Relay -- won't relay until fully synced \n " ) ;
2017-12-14 01:33:58 +01:00
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
2018-12-17 15:39:21 +01:00
int nMnCount = ( int ) deterministicMNManager - > GetListAtChainTip ( ) . GetValidMNsCount ( ) ;
2018-09-28 09:56:17 +02:00
if ( nMnCount = = 0 ) return ;
2016-11-24 19:12:05 +01:00
2021-01-26 04:31:31 +01:00
// CALCULATE THE MINIMUM VOTE COUNT REQUIRED FOR FULL SIGNAL
2016-11-24 19:12:05 +01:00
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 ;
2021-01-26 04:31:31 +01:00
// SET SENTINEL FLAGS TO TRUE IF MINIMUM SUPPORT LEVELS ARE REACHED
2016-11-24 19:12:05 +01:00
// ARE ANY OF THESE FLAGS CURRENTLY ACTIVATED?
2018-09-28 09:56:17 +02:00
if ( GetAbsoluteYesCount ( VOTE_SIGNAL_FUNDING ) > = nAbsVoteReq ) fCachedFunding = true ;
if ( ( GetAbsoluteYesCount ( VOTE_SIGNAL_DELETE ) > = nAbsDeleteReq ) & & ! fCachedDelete ) {
2016-11-24 19:12:05 +01:00
fCachedDelete = true ;
2018-09-28 09:56:17 +02:00
if ( nDeletionTime = = 0 ) {
2016-12-14 16:27:46 +01:00
nDeletionTime = GetAdjustedTime ( ) ;
}
2016-11-24 19:12:05 +01:00
}
2018-09-28 09:56:17 +02:00
if ( GetAbsoluteYesCount ( VOTE_SIGNAL_ENDORSED ) > = nAbsVoteReq ) fCachedEndorsed = true ;
2016-11-24 19:12:05 +01:00
2018-09-28 09:56:17 +02:00
if ( GetAbsoluteNoCount ( VOTE_SIGNAL_VALID ) > = nAbsVoteReq ) fCachedValid = false ;
2016-11-24 19:12:05 +01:00
}