2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash Core developers
2016-04-08 19:47:00 +02:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2016-12-20 14:27:59 +01:00
# include "governance-vote.h"
2017-10-04 22:12:53 +02:00
# include "governance-object.h"
2017-12-14 01:33:58 +01:00
# include "masternode-sync.h"
2016-04-14 00:41:40 +02:00
# include "masternodeman.h"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2016-04-14 00:41:40 +02:00
# include "util.h"
2016-12-20 14:27:59 +01:00
# include <boost/lexical_cast.hpp>
2016-08-17 09:08:25 +02:00
2016-09-08 13:40:19 +02:00
std : : string CGovernanceVoting : : ConvertOutcomeToString ( vote_outcome_enum_t nOutcome )
2016-08-17 09:08:25 +02:00
{
switch ( nOutcome )
{
case VOTE_OUTCOME_NONE :
return " NONE " ; break ;
case VOTE_OUTCOME_YES :
return " YES " ; break ;
case VOTE_OUTCOME_NO :
return " NO " ; break ;
case VOTE_OUTCOME_ABSTAIN :
return " ABSTAIN " ; break ;
}
return " error " ;
}
2016-09-08 13:40:19 +02:00
std : : string CGovernanceVoting : : ConvertSignalToString ( vote_signal_enum_t nSignal )
2016-08-17 09:08:25 +02:00
{
2018-02-21 20:26:53 +01:00
std : : string strReturn = " NONE " ;
2016-08-17 09:08:25 +02:00
switch ( nSignal )
{
case VOTE_SIGNAL_NONE :
2016-09-08 13:40:19 +02:00
strReturn = " NONE " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_FUNDING :
2016-09-08 13:40:19 +02:00
strReturn = " FUNDING " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_VALID :
2016-09-08 13:40:19 +02:00
strReturn = " VALID " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_DELETE :
2016-09-08 13:40:19 +02:00
strReturn = " DELETE " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_ENDORSED :
2016-09-08 13:40:19 +02:00
strReturn = " ENDORSED " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP1 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP1 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP2 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP2 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP3 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP3 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP4 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP4 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP5 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP5 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP6 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP6 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP7 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP7 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP8 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP8 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP9 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP9 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP10 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP10 " ;
break ;
2016-08-17 09:08:25 +02:00
case VOTE_SIGNAL_NOOP11 :
2016-09-08 13:40:19 +02:00
strReturn = " NOOP11 " ;
break ;
case VOTE_SIGNAL_CUSTOM1 :
strReturn = " CUSTOM1 " ;
break ;
case VOTE_SIGNAL_CUSTOM2 :
strReturn = " CUSTOM2 " ;
break ;
case VOTE_SIGNAL_CUSTOM3 :
strReturn = " CUSTOM3 " ;
break ;
case VOTE_SIGNAL_CUSTOM4 :
strReturn = " CUSTOM4 " ;
break ;
case VOTE_SIGNAL_CUSTOM5 :
strReturn = " CUSTOM5 " ;
break ;
case VOTE_SIGNAL_CUSTOM6 :
strReturn = " CUSTOM6 " ;
break ;
case VOTE_SIGNAL_CUSTOM7 :
strReturn = " CUSTOM7 " ;
break ;
case VOTE_SIGNAL_CUSTOM8 :
strReturn = " CUSTOM8 " ;
break ;
case VOTE_SIGNAL_CUSTOM9 :
strReturn = " CUSTOM9 " ;
break ;
case VOTE_SIGNAL_CUSTOM10 :
strReturn = " CUSTOM10 " ;
break ;
case VOTE_SIGNAL_CUSTOM11 :
strReturn = " CUSTOM11 " ;
break ;
case VOTE_SIGNAL_CUSTOM12 :
strReturn = " CUSTOM12 " ;
break ;
case VOTE_SIGNAL_CUSTOM13 :
strReturn = " CUSTOM13 " ;
break ;
case VOTE_SIGNAL_CUSTOM14 :
strReturn = " CUSTOM14 " ;
break ;
case VOTE_SIGNAL_CUSTOM15 :
strReturn = " CUSTOM15 " ;
break ;
case VOTE_SIGNAL_CUSTOM16 :
strReturn = " CUSTOM16 " ;
break ;
case VOTE_SIGNAL_CUSTOM17 :
strReturn = " CUSTOM17 " ;
break ;
case VOTE_SIGNAL_CUSTOM18 :
strReturn = " CUSTOM18 " ;
break ;
case VOTE_SIGNAL_CUSTOM19 :
strReturn = " CUSTOM19 " ;
break ;
case VOTE_SIGNAL_CUSTOM20 :
strReturn = " CUSTOM20 " ;
break ;
2016-08-17 09:08:25 +02:00
}
2016-09-08 13:40:19 +02:00
return strReturn ;
2016-08-17 09:08:25 +02:00
}
2018-02-12 13:49:00 +01:00
vote_outcome_enum_t CGovernanceVoting : : ConvertVoteOutcome ( const std : : string & strVoteOutcome )
2016-08-17 09:08:25 +02:00
{
2016-09-08 13:40:19 +02:00
vote_outcome_enum_t eVote = VOTE_OUTCOME_NONE ;
if ( strVoteOutcome = = " yes " ) {
eVote = VOTE_OUTCOME_YES ;
}
else if ( strVoteOutcome = = " no " ) {
eVote = VOTE_OUTCOME_NO ;
}
else if ( strVoteOutcome = = " abstain " ) {
eVote = VOTE_OUTCOME_ABSTAIN ;
}
return eVote ;
2016-08-17 09:08:25 +02:00
}
2018-02-12 13:49:00 +01:00
vote_signal_enum_t CGovernanceVoting : : ConvertVoteSignal ( const std : : string & strVoteSignal )
2016-08-17 09:08:25 +02:00
{
2016-09-08 13:40:19 +02:00
vote_signal_enum_t eSignal = VOTE_SIGNAL_NONE ;
if ( strVoteSignal = = " funding " ) {
eSignal = VOTE_SIGNAL_FUNDING ;
}
else if ( strVoteSignal = = " valid " ) {
eSignal = VOTE_SIGNAL_VALID ;
}
if ( strVoteSignal = = " delete " ) {
eSignal = VOTE_SIGNAL_DELETE ;
}
if ( strVoteSignal = = " endorsed " ) {
eSignal = VOTE_SIGNAL_ENDORSED ;
}
if ( eSignal ! = VOTE_SIGNAL_NONE ) {
return eSignal ;
}
2016-08-17 09:08:25 +02:00
// ID FIVE THROUGH CUSTOM_START ARE TO BE USED BY GOVERNANCE ENGINE / TRIGGER SYSTEM
// convert custom sentinel outcomes to integer and store
try {
2016-09-12 09:40:00 +02:00
int i = boost : : lexical_cast < int > ( strVoteSignal ) ;
2016-09-08 13:40:19 +02:00
if ( i < VOTE_SIGNAL_CUSTOM1 | | i > VOTE_SIGNAL_CUSTOM20 ) {
eSignal = VOTE_SIGNAL_NONE ;
}
else {
eSignal = vote_signal_enum_t ( i ) ;
}
2016-08-17 09:08:25 +02:00
}
catch ( std : : exception const & e )
{
2016-09-12 09:40:00 +02:00
std : : ostringstream ostr ;
ostr < < " CGovernanceVote::ConvertVoteSignal: error : " < < e . what ( ) < < std : : endl ;
2016-09-08 13:40:19 +02:00
LogPrintf ( ostr . str ( ) . c_str ( ) ) ;
2016-08-17 09:08:25 +02:00
}
2016-09-08 13:40:19 +02:00
return eSignal ;
2016-08-17 09:08:25 +02:00
}
2016-05-23 19:53:05 +02:00
CGovernanceVote : : CGovernanceVote ( )
2016-09-08 13:40:19 +02:00
: fValid ( true ) ,
fSynced ( false ) ,
nVoteSignal ( int ( VOTE_SIGNAL_NONE ) ) ,
2018-02-15 08:29:44 +01:00
masternodeOutpoint ( ) ,
2016-09-08 13:40:19 +02:00
nParentHash ( ) ,
nVoteOutcome ( int ( VOTE_OUTCOME_NONE ) ) ,
nTime ( 0 ) ,
vchSig ( )
{ }
2018-02-21 17:35:37 +01:00
CGovernanceVote : : CGovernanceVote ( const COutPoint & outpointMasternodeIn , const uint256 & nParentHashIn , vote_signal_enum_t eVoteSignalIn , vote_outcome_enum_t eVoteOutcomeIn )
2016-09-08 13:40:19 +02:00
: fValid ( true ) ,
fSynced ( false ) ,
nVoteSignal ( eVoteSignalIn ) ,
2018-02-15 08:29:44 +01:00
masternodeOutpoint ( outpointMasternodeIn ) ,
2016-09-08 13:40:19 +02:00
nParentHash ( nParentHashIn ) ,
nVoteOutcome ( eVoteOutcomeIn ) ,
nTime ( GetAdjustedTime ( ) ) ,
vchSig ( )
2018-02-21 17:35:37 +01:00
{
UpdateHash ( ) ;
}
2016-04-08 19:47:00 +02:00
2017-09-19 16:51:38 +02:00
void CGovernanceVote : : Relay ( CConnman & connman ) const
2016-04-08 19:47:00 +02:00
{
2017-12-14 01:33:58 +01:00
// Do not relay until fully synced
if ( ! masternodeSync . IsSynced ( ) ) {
LogPrint ( " gobject " , " CGovernanceVote::Relay -- won't relay until fully synced \n " ) ;
return ;
}
2016-08-05 18:25:03 +02:00
CInv inv ( MSG_GOVERNANCE_OBJECT_VOTE , GetHash ( ) ) ;
2017-10-04 22:12:53 +02:00
connman . RelayInv ( inv , MIN_GOVERNANCE_PEER_PROTO_VERSION ) ;
2016-04-08 19:47:00 +02:00
}
2018-02-21 17:35:37 +01:00
void CGovernanceVote : : UpdateHash ( ) const
2016-04-08 19:47:00 +02:00
{
2018-02-16 15:54:53 +01:00
// Note: doesn't match serialization
CHashWriter ss ( SER_GETHASH , PROTOCOL_VERSION ) ;
ss < < masternodeOutpoint < < uint8_t { } < < 0xffffffff ; // adding dummy values here to match old hashing format
ss < < nParentHash ;
ss < < nVoteSignal ;
ss < < nVoteOutcome ;
ss < < nTime ;
2018-02-21 17:35:37 +01:00
* const_cast < uint256 * > ( & hash ) = ss . GetHash ( ) ;
}
uint256 CGovernanceVote : : GetHash ( ) const
{
return hash ;
2018-02-16 15:54:53 +01:00
}
2016-04-08 19:47:00 +02:00
2018-02-16 15:54:53 +01:00
uint256 CGovernanceVote : : GetSignatureHash ( ) const
{
return SerializeHash ( * this ) ;
}
bool CGovernanceVote : : Sign ( const CKey & keyMasternode , const CPubKey & pubKeyMasternode )
{
2016-08-19 13:50:04 +02:00
std : : string strError ;
2016-04-08 19:47:00 +02:00
2018-02-16 15:54:53 +01:00
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash = GetSignatureHash ( ) ;
if ( ! CHashSigner : : SignHash ( hash , keyMasternode , vchSig ) ) {
LogPrintf ( " CGovernanceVote::Sign -- SignHash() failed \n " ) ;
return false ;
}
if ( ! CHashSigner : : VerifyHash ( hash , pubKeyMasternode , vchSig , strError ) ) {
LogPrintf ( " CGovernanceVote::Sign -- VerifyHash() failed, error: %s \n " , strError ) ;
return false ;
}
} else {
std : : string strMessage = masternodeOutpoint . ToStringShort ( ) + " | " + nParentHash . ToString ( ) + " | " +
boost : : lexical_cast < std : : string > ( nVoteSignal ) + " | " + boost : : lexical_cast < std : : string > ( nVoteOutcome ) + " | " + boost : : lexical_cast < std : : string > ( nTime ) ;
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , keyMasternode ) ) {
LogPrintf ( " CGovernanceVote::Sign -- SignMessage() failed \n " ) ;
return false ;
}
if ( ! CMessageSigner : : VerifyMessage ( pubKeyMasternode , vchSig , strMessage , strError ) ) {
LogPrintf ( " CGovernanceVote::Sign -- VerifyMessage() failed, error: %s \n " , strError ) ;
return false ;
}
2016-04-26 19:45:06 +02:00
}
2016-04-08 19:47:00 +02:00
2018-02-16 15:54:53 +01:00
return true ;
}
bool CGovernanceVote : : CheckSignature ( const CPubKey & pubKeyMasternode ) const
{
std : : string strError ;
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash = GetSignatureHash ( ) ;
if ( ! CHashSigner : : VerifyHash ( hash , pubKeyMasternode , vchSig , strError ) ) {
// could be a signature in old format
std : : string strMessage = masternodeOutpoint . ToStringShort ( ) + " | " + nParentHash . ToString ( ) + " | " +
boost : : lexical_cast < std : : string > ( nVoteSignal ) + " | " +
boost : : lexical_cast < std : : string > ( nVoteOutcome ) + " | " +
boost : : lexical_cast < std : : string > ( nTime ) ;
if ( ! CMessageSigner : : VerifyMessage ( pubKeyMasternode , vchSig , strMessage , strError ) ) {
// nope, not in old format either
LogPrint ( " gobject " , " CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s \n " , strError ) ;
return false ;
}
}
} else {
std : : string strMessage = masternodeOutpoint . ToStringShort ( ) + " | " + nParentHash . ToString ( ) + " | " +
boost : : lexical_cast < std : : string > ( nVoteSignal ) + " | " +
boost : : lexical_cast < std : : string > ( nVoteOutcome ) + " | " +
boost : : lexical_cast < std : : string > ( nTime ) ;
if ( ! CMessageSigner : : VerifyMessage ( pubKeyMasternode , vchSig , strMessage , strError ) ) {
LogPrint ( " gobject " , " CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s \n " , strError ) ;
return false ;
}
2016-04-26 19:45:06 +02:00
}
2016-04-08 19:47:00 +02:00
return true ;
}
2016-11-13 18:52:34 +01:00
bool CGovernanceVote : : IsValid ( bool fSignatureCheck ) const
2016-04-08 19:47:00 +02:00
{
2017-08-29 01:51:44 +02:00
if ( nTime > GetAdjustedTime ( ) + ( 60 * 60 ) ) {
LogPrint ( " gobject " , " CGovernanceVote::IsValid -- vote is too far ahead of current time - %s - nTime %lli - Max Time %lli \n " , GetHash ( ) . ToString ( ) , nTime , GetAdjustedTime ( ) + ( 60 * 60 ) ) ;
2016-04-08 19:47:00 +02:00
return false ;
}
2016-04-26 06:08:36 +02:00
// support up to 50 actions (implemented in sentinel)
2016-11-13 18:52:34 +01:00
if ( nVoteSignal > MAX_SUPPORTED_VOTE_SIGNAL )
2016-04-26 06:08:36 +02:00
{
2016-09-12 09:40:00 +02:00
LogPrint ( " gobject " , " CGovernanceVote::IsValid -- Client attempted to vote on invalid signal(%d) - %s \n " , nVoteSignal , GetHash ( ) . ToString ( ) ) ;
2016-04-26 06:08:36 +02:00
return false ;
}
2016-04-14 00:41:40 +02:00
2016-04-26 06:08:36 +02:00
// 0=none, 1=yes, 2=no, 3=abstain. Beyond that reject votes
if ( nVoteOutcome > 3 )
{
2016-09-12 09:40:00 +02:00
LogPrint ( " gobject " , " CGovernanceVote::IsValid -- Client attempted to vote on invalid outcome(%d) - %s \n " , nVoteSignal , GetHash ( ) . ToString ( ) ) ;
return false ;
2016-04-26 06:08:36 +02:00
}
2017-09-11 16:13:48 +02:00
masternode_info_t infoMn ;
2018-02-15 08:29:44 +01:00
if ( ! mnodeman . GetMasternodeInfo ( masternodeOutpoint , infoMn ) ) {
LogPrint ( " gobject " , " CGovernanceVote::IsValid -- Unknown Masternode - %s \n " , masternodeOutpoint . ToStringShort ( ) ) ;
2016-04-26 19:45:06 +02:00
return false ;
}
2016-04-08 19:47:00 +02:00
if ( ! fSignatureCheck ) return true ;
2018-02-16 15:54:53 +01:00
return CheckSignature ( infoMn . pubKeyMasternode ) ;
2016-08-17 09:08:25 +02:00
}
2016-11-13 18:52:34 +01:00
bool operator = = ( const CGovernanceVote & vote1 , const CGovernanceVote & vote2 )
{
2018-02-15 08:29:44 +01:00
bool fResult = ( ( vote1 . masternodeOutpoint = = vote2 . masternodeOutpoint ) & &
2016-11-13 18:52:34 +01:00
( vote1 . nParentHash = = vote2 . nParentHash ) & &
( vote1 . nVoteOutcome = = vote2 . nVoteOutcome ) & &
( vote1 . nVoteSignal = = vote2 . nVoteSignal ) & &
( vote1 . nTime = = vote2 . nTime ) ) ;
return fResult ;
}
bool operator < ( const CGovernanceVote & vote1 , const CGovernanceVote & vote2 )
{
2018-02-15 08:29:44 +01:00
bool fResult = ( vote1 . masternodeOutpoint < vote2 . masternodeOutpoint ) ;
2016-11-13 18:52:34 +01:00
if ( ! fResult ) {
return false ;
}
2018-02-15 08:29:44 +01:00
fResult = ( vote1 . masternodeOutpoint = = vote2 . masternodeOutpoint ) ;
2016-11-13 18:52:34 +01:00
fResult = fResult & & ( vote1 . nParentHash < vote2 . nParentHash ) ;
if ( ! fResult ) {
return false ;
}
fResult = fResult & & ( vote1 . nParentHash = = vote2 . nParentHash ) ;
fResult = fResult & & ( vote1 . nVoteOutcome < vote2 . nVoteOutcome ) ;
if ( ! fResult ) {
return false ;
}
fResult = fResult & & ( vote1 . nVoteOutcome = = vote2 . nVoteOutcome ) ;
fResult = fResult & & ( vote1 . nVoteSignal = = vote2 . nVoteSignal ) ;
if ( ! fResult ) {
return false ;
}
fResult = fResult & & ( vote1 . nVoteSignal = = vote2 . nVoteSignal ) ;
fResult = fResult & & ( vote1 . nTime < vote2 . nTime ) ;
return fResult ;
}