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-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
}
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
{
2018-04-23 12:23:58 +02:00
static const std : : map < std : : string , vote_signal_enum_t > mapStrVoteSignals = {
{ " funding " , VOTE_SIGNAL_FUNDING } ,
{ " valid " , VOTE_SIGNAL_VALID } ,
{ " delete " , VOTE_SIGNAL_DELETE } ,
{ " endorsed " , VOTE_SIGNAL_ENDORSED }
} ;
const auto & it = mapStrVoteSignals . find ( strVoteSignal ) ;
if ( it = = mapStrVoteSignals . end ( ) ) {
LogPrintf ( " CGovernanceVoting::%s -- ERROR: Unknown signal %s \n " , __func__ , strVoteSignal ) ;
return VOTE_SIGNAL_NONE ;
}
return it - > second ;
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
2018-04-20 12:53:23 +02:00
std : : string CGovernanceVote : : ToString ( ) const
{
std : : ostringstream ostr ;
ostr < < masternodeOutpoint . ToStringShort ( ) < < " : "
< < nTime < < " : "
< < CGovernanceVoting : : ConvertOutcomeToString ( GetOutcome ( ) ) < < " : "
< < CGovernanceVoting : : ConvertSignalToString ( GetSignal ( ) ) ;
return ostr . str ( ) ;
}
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 ) ;
}
2018-08-11 21:55:56 +02:00
bool CGovernanceVote : : Sign ( const CKey & keyMasternode , const CKeyID & keyIDMasternode )
2018-02-16 15:54:53 +01:00
{
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 ;
}
2018-08-11 21:55:56 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , keyIDMasternode , vchSig , strError ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceVote::Sign -- VerifyHash() failed, error: %s \n " , strError ) ;
return false ;
}
} else {
std : : string strMessage = masternodeOutpoint . ToStringShort ( ) + " | " + nParentHash . ToString ( ) + " | " +
2018-07-12 11:02:20 +02:00
std : : to_string ( nVoteSignal ) + " | " + std : : to_string ( nVoteOutcome ) + " | " + std : : to_string ( nTime ) ;
2018-02-16 15:54:53 +01:00
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , keyMasternode ) ) {
LogPrintf ( " CGovernanceVote::Sign -- SignMessage() failed \n " ) ;
return false ;
}
2018-08-11 21:55:56 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyIDMasternode , vchSig , strMessage , strError ) ) {
2018-02-16 15:54:53 +01:00
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 ;
}
2018-08-11 21:55:56 +02:00
bool CGovernanceVote : : CheckSignature ( const CKeyID & keyIDMasternode ) const
2018-02-16 15:54:53 +01:00
{
std : : string strError ;
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash = GetSignatureHash ( ) ;
2018-08-11 21:55:56 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , keyIDMasternode , vchSig , strError ) ) {
2018-02-16 15:54:53 +01:00
// could be a signature in old format
std : : string strMessage = masternodeOutpoint . ToStringShort ( ) + " | " + nParentHash . ToString ( ) + " | " +
2018-07-12 11:02:20 +02:00
std : : to_string ( nVoteSignal ) + " | " +
std : : to_string ( nVoteOutcome ) + " | " +
std : : to_string ( nTime ) ;
2018-02-16 15:54:53 +01:00
2018-08-11 21:55:56 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyIDMasternode , vchSig , strMessage , strError ) ) {
2018-02-16 15:54:53 +01:00
// 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 ( ) + " | " +
2018-07-12 11:02:20 +02:00
std : : to_string ( nVoteSignal ) + " | " +
std : : to_string ( nVoteOutcome ) + " | " +
std : : to_string ( nTime ) ;
2018-02-16 15:54:53 +01:00
2018-08-11 21:55:56 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyIDMasternode , vchSig , strMessage , strError ) ) {
2018-02-16 15:54:53 +01:00
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 ;
}
2018-04-23 12:23:58 +02:00
// support up to MAX_SUPPORTED_VOTE_SIGNAL, can be extended
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-08-11 21:55:56 +02:00
return CheckSignature ( infoMn . keyIDMasternode ) ;
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 ;
}