2021-04-20 21:33:02 +02:00
// Copyright (c) 2014-2021 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.
2021-10-01 21:19:08 +02:00
# include <governance/vote.h>
2021-04-23 00:32:03 +02:00
# include <bls/bls.h>
# include <key.h>
2021-10-01 21:19:08 +02:00
# include <masternode/sync.h>
2020-03-19 23:46:56 +01:00
# include <messagesigner.h>
2021-04-23 00:32:03 +02:00
# include <net.h>
2021-06-27 08:33:13 +02:00
# include <util/system.h>
2016-04-14 00:41:40 +02:00
2020-03-19 23:46:56 +01:00
# include <evo/deterministicmns.h>
2019-01-03 21:08:34 +01: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
{
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 ( ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceVote::Relay -- won't relay until fully synced \n " ) ;
2017-12-14 01:33:58 +01:00
return ;
}
2019-05-29 10:56:51 +02:00
auto mnList = deterministicMNManager - > GetListAtChainTip ( ) ;
auto dmn = mnList . GetMNByCollateral ( masternodeOutpoint ) ;
if ( ! dmn ) {
return ;
}
// When this vote is from non-valid (PoSe banned) MN, we should only announce it to v0.14.0.1 nodes as older nodes
// will ban us otherwise.
int minVersion = MIN_GOVERNANCE_PEER_PROTO_VERSION ;
2021-06-06 23:35:29 +02:00
if ( ! CDeterministicMNList : : IsMNValid ( dmn ) ) {
2019-05-29 10:56:51 +02:00
minVersion = GOVERNANCE_POSE_BANNED_VOTES_VERSION ;
}
2016-08-05 18:25:03 +02:00
CInv inv ( MSG_GOVERNANCE_OBJECT_VOTE , GetHash ( ) ) ;
2019-05-29 10:56:51 +02:00
connman . RelayInv ( inv , minVersion ) ;
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
2020-08-30 16:22:21 +02:00
// Harden Spork6 so that it is active on testnet and no other networks
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : TESTNET ) {
2021-08-06 23:55:51 +02:00
uint256 signatureHash = GetSignatureHash ( ) ;
2018-02-16 15:54:53 +01:00
2021-08-06 23:55:51 +02:00
if ( ! CHashSigner : : SignHash ( signatureHash , key , vchSig ) ) {
2018-02-16 15:54:53 +01:00
LogPrintf ( " CGovernanceVote::Sign -- SignHash() failed \n " ) ;
return false ;
}
2021-08-06 23:55:51 +02:00
if ( ! CHashSigner : : VerifyHash ( signatureHash , 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 ;
2020-08-30 16:22:21 +02:00
// Harden Spork6 so that it is active on testnet and no other networks
if ( Params ( ) . NetworkIDString ( ) = = CBaseChainParams : : TESTNET ) {
2021-08-06 23:55:51 +02:00
if ( ! CHashSigner : : VerifyHash ( GetSignatureHash ( ) , keyID , vchSig , strError ) ) {
2020-08-30 16:22:21 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceVote::IsValid -- VerifyHash() failed, error: %s \n " , strError ) ;
return false ;
2018-02-16 15:54:53 +01:00
}
} 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 ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
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 )
{
2021-08-06 23:55:51 +02:00
CBLSSignature sig = key . Sign ( GetSignatureHash ( ) ) ;
2018-12-06 08:07:10 +01:00
if ( ! sig . IsValid ( ) ) {
return false ;
}
2021-02-27 08:36:00 +01:00
vchSig = sig . ToByteVector ( ) ;
2018-10-21 21:45:16 +02:00
return true ;
}
bool CGovernanceVote : : 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 ( " 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 ) ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : 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 ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : 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 ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : GOBJECT , " CGovernanceVote::IsValid -- Client attempted to vote on invalid outcome(%d) - %s \n " , nVoteSignal , GetHash ( ) . ToString ( ) ) ;
2016-09-12 09:40:00 +02:00
return false ;
2016-04-26 06:08:36 +02:00
}
2019-05-29 10:56:51 +02:00
auto dmn = deterministicMNManager - > GetListAtChainTip ( ) . GetMNByCollateral ( masternodeOutpoint ) ;
2018-12-17 15:39:21 +01:00
if ( ! dmn ) {
2019-05-22 23:51:39 +02:00
LogPrint ( BCLog : : 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 ) {
2018-12-17 15:39:21 +01:00
return CheckSignature ( dmn - > pdmnState - > keyIDVoting ) ;
2018-10-21 21:45:16 +02:00
} else {
2019-06-13 11:01:26 +02:00
return CheckSignature ( dmn - > pdmnState - > pubKeyOperator . Get ( ) ) ;
2018-10-21 21:45:16 +02:00
}
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 ;
}
2021-01-26 04:31:31 +01:00
fResult = ( vote1 . nParentHash = = vote2 . nParentHash ) ;
2016-11-13 18:52:34 +01:00
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 ;
}
2021-01-26 04:31:31 +01:00
fResult = ( vote1 . nVoteOutcome = = vote2 . nVoteOutcome ) ;
2016-11-13 18:52:34 +01:00
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 ;
}
2021-01-26 04:31:31 +01:00
fResult = ( vote1 . nVoteSignal = = vote2 . nVoteSignal ) ;
2016-11-13 18:52:34 +01:00
fResult = fResult & & ( vote1 . nTime < vote2 . nTime ) ;
return fResult ;
}