2018-09-28 09:56:17 +02:00
// Copyright (c) 2014-2018 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
{
2018-10-11 16:32:31 +02:00
static const std : : map < vote_outcome_enum_t , std : : string > mapOutcomeString = {
{ VOTE_OUTCOME_NONE , " none " } ,
{ VOTE_OUTCOME_YES , " yes " } ,
{ VOTE_OUTCOME_NO , " no " } ,
{ VOTE_OUTCOME_ABSTAIN , " abstain " } } ;
const auto & it = mapOutcomeString . find ( nOutcome ) ;
if ( it = = mapOutcomeString . end ( ) ) {
LogPrintf ( " CGovernanceVoting::%s -- ERROR: Unknown outcome %d \n " , __func__ , nOutcome ) ;
return " error " ;
2016-08-17 09:08:25 +02:00
}
2018-10-11 16:32:31 +02:00
return it - > second ;
2016-08-17 09:08:25 +02:00
}
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-10-11 16:32:31 +02:00
static const std : : map < vote_signal_enum_t , std : : string > mapSignalsString = {
{ VOTE_SIGNAL_FUNDING , " funding " } ,
{ VOTE_SIGNAL_VALID , " valid " } ,
{ VOTE_SIGNAL_DELETE , " delete " } ,
{ VOTE_SIGNAL_ENDORSED , " endorsed " } } ;
2016-08-17 09:08:25 +02:00
2018-10-11 16:32:31 +02:00
const auto & it = mapSignalsString . find ( nSignal ) ;
if ( it = = mapSignalsString . end ( ) ) {
LogPrintf ( " CGovernanceVoting::%s -- ERROR: Unknown signal %d \n " , __func__ , nSignal ) ;
return " none " ;
}
return it - > second ;
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
{
2018-10-11 16:32:31 +02:00
static const std : : map < std : : string , vote_outcome_enum_t > mapStringOutcome = {
{ " none " , VOTE_OUTCOME_NONE } ,
{ " yes " , VOTE_OUTCOME_YES } ,
{ " no " , VOTE_OUTCOME_NO } ,
{ " abstain " , VOTE_OUTCOME_ABSTAIN } } ;
const auto & it = mapStringOutcome . find ( strVoteOutcome ) ;
if ( it = = mapStringOutcome . end ( ) ) {
LogPrintf ( " CGovernanceVoting::%s -- ERROR: Unknown outcome %s \n " , __func__ , strVoteOutcome ) ;
return VOTE_OUTCOME_NONE ;
2016-09-08 13:40:19 +02:00
}
2018-10-11 16:32:31 +02:00
return it - > second ;
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-09-28 09:56:17 +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 } } ;
2018-04-23 12:23:58 +02:00
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
}
2018-09-28 09:56:17 +02:00
CGovernanceVote : : CGovernanceVote ( ) :
fValid ( true ) ,
fSynced ( false ) ,
nVoteSignal ( int ( VOTE_SIGNAL_NONE ) ) ,
masternodeOutpoint ( ) ,
nParentHash ( ) ,
nVoteOutcome ( int ( VOTE_OUTCOME_NONE ) ) ,
nTime ( 0 ) ,
vchSig ( )
{
}
CGovernanceVote : : CGovernanceVote ( const COutPoint & outpointMasternodeIn , const uint256 & nParentHashIn , vote_signal_enum_t eVoteSignalIn , vote_outcome_enum_t eVoteOutcomeIn ) :
fValid ( true ) ,
fSynced ( false ) ,
nVoteSignal ( eVoteSignalIn ) ,
masternodeOutpoint ( outpointMasternodeIn ) ,
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
2018-09-28 09:56:17 +02:00
if ( ! masternodeSync . IsSynced ( ) ) {
2017-12-14 01:33:58 +01:00
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-31 15:31:59 +02:00
bool CGovernanceVote : : Sign ( const CKey & key , const CKeyID & keyID )
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 ( ) ;
2018-09-28 09:56:17 +02:00
if ( ! CHashSigner : : SignHash ( hash , key , vchSig ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceVote::Sign -- SignHash() failed \n " ) ;
return false ;
}
2018-08-31 15:31:59 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , keyID , 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-09-28 09:56:17 +02:00
std : : to_string ( nVoteSignal ) + " | " + std : : to_string ( nVoteOutcome ) + " | " + std : : to_string ( nTime ) ;
2018-02-16 15:54:53 +01:00
2018-09-28 09:56:17 +02:00
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , key ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceVote::Sign -- SignMessage() failed \n " ) ;
return false ;
}
2018-09-28 09:56:17 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyID , 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-31 15:31:59 +02:00
bool CGovernanceVote : : CheckSignature ( const CKeyID & keyID ) const
2018-02-16 15:54:53 +01:00
{
std : : string strError ;
if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
uint256 hash = GetSignatureHash ( ) ;
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 a signature in old format
std : : string strMessage = masternodeOutpoint . ToStringShort ( ) + " | " + nParentHash . ToString ( ) + " | " +
2018-09-28 09:56:17 +02:00
std : : to_string ( nVoteSignal ) + " | " +
std : : to_string ( nVoteOutcome ) + " | " +
std : : to_string ( nTime ) ;
2018-02-16 15:54:53 +01:00
2018-09-28 09:56:17 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyID , 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-09-28 09:56:17 +02:00
std : : to_string ( nVoteSignal ) + " | " +
std : : to_string ( nVoteOutcome ) + " | " +
std : : to_string ( nTime ) ;
2018-02-16 15:54:53 +01:00
2018-09-28 09:56:17 +02:00
if ( ! CMessageSigner : : VerifyMessage ( keyID , 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 ;
}
2018-10-21 21:45:16 +02:00
bool CGovernanceVote : : Sign ( const CBLSSecretKey & key )
{
uint256 hash = GetSignatureHash ( ) ;
CBLSSignature sig = key . Sign ( hash ) ;
sig . GetBuf ( vchSig ) ;
return true ;
}
bool CGovernanceVote : : CheckSignature ( const CBLSPublicKey & pubKey ) const
{
uint256 hash = GetSignatureHash ( ) ;
CBLSSignature sig ;
sig . SetBuf ( vchSig ) ;
if ( ! sig . VerifyInsecure ( pubKey , hash ) ) {
LogPrintf ( " CGovernanceVote::CheckSignature -- VerifyInsecure() failed \n " ) ;
return false ;
}
return true ;
}
2018-08-31 15:31:59 +02:00
bool CGovernanceVote : : IsValid ( bool useVotingKey ) const
2016-04-08 19:47:00 +02:00
{
2018-09-28 09:56:17 +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
2018-09-28 09:56:17 +02:00
if ( nVoteSignal > MAX_SUPPORTED_VOTE_SIGNAL ) {
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
2018-09-28 09:56:17 +02:00
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-09-28 09:56:17 +02:00
if ( ! mnodeman . GetMasternodeInfo ( masternodeOutpoint , infoMn ) ) {
2018-02-15 08:29:44 +01:00
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
2018-10-21 21:45:16 +02:00
if ( useVotingKey ) {
return CheckSignature ( infoMn . keyIDVoting ) ;
} else {
if ( deterministicMNManager - > IsDeterministicMNsSporkActive ( ) ) {
return CheckSignature ( infoMn . blsPubKeyOperator ) ;
} else {
return CheckSignature ( infoMn . legacyKeyIDOperator ) ;
}
}
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 ) ;
2018-09-28 09:56:17 +02:00
if ( ! fResult ) {
2016-11-13 18:52:34 +01:00
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 ) ;
2018-09-28 09:56:17 +02:00
if ( ! fResult ) {
2016-11-13 18:52:34 +01:00
return false ;
}
fResult = fResult & & ( vote1 . nParentHash = = vote2 . nParentHash ) ;
fResult = fResult & & ( vote1 . nVoteOutcome < vote2 . nVoteOutcome ) ;
2018-09-28 09:56:17 +02:00
if ( ! fResult ) {
2016-11-13 18:52:34 +01:00
return false ;
}
fResult = fResult & & ( vote1 . nVoteOutcome = = vote2 . nVoteOutcome ) ;
fResult = fResult & & ( vote1 . nVoteSignal = = vote2 . nVoteSignal ) ;
2018-09-28 09:56:17 +02:00
if ( ! fResult ) {
2016-11-13 18:52:34 +01:00
return false ;
}
fResult = fResult & & ( vote1 . nVoteSignal = = vote2 . nVoteSignal ) ;
fResult = fResult & & ( vote1 . nTime < vote2 . nTime ) ;
return fResult ;
}