LCOV - code coverage report
Current view: top level - src/governance - vote.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 88 139 63.3 %
Date: 2026-06-25 07:23:43 Functions: 12 14 85.7 %

          Line data    Source code
       1             : // Copyright (c) 2014-2025 The Dash Core developers
       2             : // Distributed under the MIT/X11 software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <governance/vote.h>
       6             : 
       7             : #include <bls/bls.h>
       8             : #include <evo/deterministicmns.h>
       9             : #include <evo/dmn_types.h>
      10             : #include <masternode/sync.h>
      11             : #include <messagesigner.h>
      12             : 
      13             : #include <chainparams.h>
      14             : #include <logging.h>
      15             : #include <timedata.h>
      16             : #include <util/string.h>
      17             : 
      18        1667 : std::string CGovernanceVoting::ConvertOutcomeToString(vote_outcome_enum_t nOutcome)
      19             : {
      20        1667 :     static const std::map<vote_outcome_enum_t, std::string> mapOutcomeString = {
      21          44 :         { VOTE_OUTCOME_NONE, "none" },
      22          44 :         { VOTE_OUTCOME_YES, "yes" },
      23          44 :         { VOTE_OUTCOME_NO, "no" },
      24          44 :         { VOTE_OUTCOME_ABSTAIN, "abstain" } };
      25             : 
      26        1667 :     const auto& it = mapOutcomeString.find(nOutcome);
      27        1667 :     if (it == mapOutcomeString.end()) {
      28           0 :         LogPrintf("CGovernanceVoting::%s -- ERROR: Unknown outcome %d\n", __func__, nOutcome);
      29           0 :         return "error";
      30             :     }
      31        1667 :     return it->second;
      32        1667 : }
      33             : 
      34        1224 : std::string CGovernanceVoting::ConvertSignalToString(vote_signal_enum_t nSignal)
      35             : {
      36        1224 :     static const std::map<vote_signal_enum_t, std::string> mapSignalsString = {
      37          44 :         { VOTE_SIGNAL_FUNDING, "funding" },
      38          44 :         { VOTE_SIGNAL_VALID, "valid" },
      39          44 :         { VOTE_SIGNAL_DELETE, "delete" },
      40          44 :         { VOTE_SIGNAL_ENDORSED, "endorsed" } };
      41             : 
      42        1224 :     const auto& it = mapSignalsString.find(nSignal);
      43        1224 :     if (it == mapSignalsString.end()) {
      44           0 :         LogPrintf("CGovernanceVoting::%s -- ERROR: Unknown signal %d\n", __func__, nSignal);
      45           0 :         return "none";
      46             :     }
      47        1224 :     return it->second;
      48        1224 : }
      49             : 
      50             : 
      51          40 : vote_outcome_enum_t CGovernanceVoting::ConvertVoteOutcome(const std::string& strVoteOutcome)
      52             : {
      53          40 :     static const std::map<std::string, vote_outcome_enum_t> mapStringOutcome = {
      54           8 :         { "none", VOTE_OUTCOME_NONE },
      55           8 :         { "yes", VOTE_OUTCOME_YES },
      56           8 :         { "no", VOTE_OUTCOME_NO },
      57           8 :         { "abstain", VOTE_OUTCOME_ABSTAIN } };
      58             : 
      59          40 :     const auto& it = mapStringOutcome.find(strVoteOutcome);
      60          40 :     if (it == mapStringOutcome.end()) {
      61           0 :         LogPrintf("CGovernanceVoting::%s -- ERROR: Unknown outcome %s\n", __func__, strVoteOutcome);
      62           0 :         return VOTE_OUTCOME_NONE;
      63             :     }
      64          40 :     return it->second;
      65             : 
      66          40 : }
      67             : 
      68          40 : vote_signal_enum_t CGovernanceVoting::ConvertVoteSignal(const std::string& strVoteSignal)
      69             : {
      70          40 :     static const std::map<std::string, vote_signal_enum_t> mapStrVoteSignals = {
      71           8 :         {"funding", VOTE_SIGNAL_FUNDING},
      72           8 :         {"valid", VOTE_SIGNAL_VALID},
      73           8 :         {"delete", VOTE_SIGNAL_DELETE},
      74           8 :         {"endorsed", VOTE_SIGNAL_ENDORSED}};
      75             : 
      76          40 :     const auto& it = mapStrVoteSignals.find(strVoteSignal);
      77          40 :     if (it == mapStrVoteSignals.end()) {
      78           0 :         LogPrintf("CGovernanceVoting::%s -- ERROR: Unknown signal %s\n", __func__, strVoteSignal);
      79           0 :         return VOTE_SIGNAL_NONE;
      80             :     }
      81          40 :     return it->second;
      82          40 : }
      83             : 
      84         828 : CGovernanceVote::CGovernanceVote(const COutPoint& outpointMasternodeIn, const uint256& nParentHashIn,
      85             :                                  vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) :
      86         276 :     masternodeOutpoint(outpointMasternodeIn),
      87         276 :     nParentHash(nParentHashIn),
      88         276 :     nVoteOutcome(eVoteOutcomeIn),
      89         276 :     nVoteSignal(eVoteSignalIn),
      90         276 :     nTime(GetAdjustedTime())
      91         276 : {
      92             :     UpdateHash();
      93         276 : }
      94             : 
      95        1224 : std::string CGovernanceVote::ToString(const CDeterministicMNList& tip_mn_list) const
      96             : {
      97        1224 :     auto dmn = tip_mn_list.GetMNByCollateral(masternodeOutpoint);
      98        1224 :     int voteWeight = dmn != nullptr ? GetMnType(dmn->nType).voting_weight : 0;
      99        1224 :     return strprintf("%s:%d:%s:%s:%d",
     100        1224 :         masternodeOutpoint.ToStringShort(), nTime,
     101        1224 :         CGovernanceVoting::ConvertOutcomeToString(GetOutcome()), CGovernanceVoting::ConvertSignalToString(GetSignal()),
     102             :         voteWeight);
     103        1224 : }
     104             : 
     105        1656 : void CGovernanceVote::UpdateHash() const
     106             : {
     107             :     // Note: doesn't match serialization
     108             : 
     109        1656 :     CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION);
     110        1656 :     ss << masternodeOutpoint << uint8_t{} << 0xffffffff; // adding dummy values here to match old hashing format
     111        1656 :     ss << nParentHash;
     112        1656 :     ss << nVoteSignal;
     113        1656 :     ss << nVoteOutcome;
     114        1656 :     ss << nTime;
     115        1656 :     *const_cast<uint256*>(&hash) = ss.GetHash();
     116        1656 : }
     117             : 
     118      313411 : uint256 CGovernanceVote::GetHash() const
     119             : {
     120      313411 :     return hash;
     121             : }
     122             : 
     123             : 
     124         680 : bool CGovernanceVote::CheckSignature(const CKeyID& keyID) const
     125             : {
     126         680 :     std::string strError;
     127             : 
     128             :     // Harden Spork6 so that it is active on testnet and no other networks
     129         680 :     if (Params().NetworkIDString() == CBaseChainParams::TESTNET) {
     130           0 :         if (!CHashSigner::VerifyHash(GetSignatureHash(), keyID, vchSig, strError)) {
     131           0 :             LogPrint(BCLog::GOBJECT, "CGovernanceVote::IsValid -- VerifyHash() failed, error: %s\n", strError);
     132           0 :             return false;
     133             :         }
     134           0 :     } else {
     135         680 :         if (!CMessageSigner::VerifyMessage(keyID, vchSig, GetSignatureString(), strError)) {
     136           0 :             LogPrint(BCLog::GOBJECT, "CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s\n", strError);
     137           0 :             return false;
     138             :         }
     139             :     }
     140             : 
     141         680 :     return true;
     142         680 : }
     143             : 
     144         952 : bool CGovernanceVote::CheckSignature(const CBLSPublicKey& pubKey) const
     145             : {
     146         952 :     CBLSSignature sig;
     147         952 :     sig.SetBytes(vchSig, false);
     148         952 :     if (!sig.VerifyInsecure(pubKey, GetSignatureHash(), false)) {
     149           0 :         LogPrintf("CGovernanceVote::CheckSignature -- VerifyInsecure() failed\n");
     150           0 :         return false;
     151             :     }
     152         952 :     return true;
     153         952 : }
     154             : 
     155        1512 : bool CGovernanceVote::IsValid(const CDeterministicMNList& tip_mn_list, bool useVotingKey) const
     156             : {
     157        1512 :     if (nTime > GetAdjustedTime() + (60 * 60)) {
     158           0 :         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));
     159           0 :         return false;
     160             :     }
     161             : 
     162        1512 :     if (nVoteSignal < VOTE_SIGNAL_NONE || nVoteSignal >= VOTE_SIGNAL_UNKNOWN) {
     163           0 :         LogPrint(BCLog::GOBJECT, "CGovernanceVote::IsValid -- Client attempted to vote on invalid signal(%d) - %s\n",
     164             :                  nVoteSignal, GetHash().ToString());
     165           0 :         return false;
     166             :     }
     167             : 
     168        1512 :     if (nVoteOutcome < VOTE_OUTCOME_NONE || nVoteOutcome >= VOTE_OUTCOME_UNKNOWN) {
     169           0 :         LogPrint(BCLog::GOBJECT, "CGovernanceVote::IsValid -- Client attempted to vote on invalid outcome(%d) - %s\n",
     170             :                  nVoteOutcome, GetHash().ToString());
     171           0 :         return false;
     172             :     }
     173             : 
     174        1512 :     auto dmn = tip_mn_list.GetMNByCollateral(masternodeOutpoint);
     175        1512 :     if (!dmn) {
     176           0 :         LogPrint(BCLog::GOBJECT, "CGovernanceVote::IsValid -- Unknown Masternode - %s\n", masternodeOutpoint.ToStringShort());
     177           0 :         return false;
     178             :     }
     179             : 
     180        1512 :     if (useVotingKey) {
     181         560 :         return CheckSignature(dmn->pdmnState->keyIDVoting);
     182             :     } else {
     183         952 :         return CheckSignature(dmn->pdmnState->pubKeyOperator.Get());
     184             :     }
     185        1512 : }
     186             : 
     187             : 
     188           0 : bool operator==(const CGovernanceVote& vote1, const CGovernanceVote& vote2)
     189             : {
     190           0 :     bool fResult = ((vote1.masternodeOutpoint == vote2.masternodeOutpoint) &&
     191           0 :                     (vote1.nParentHash == vote2.nParentHash) &&
     192           0 :                     (vote1.nVoteOutcome == vote2.nVoteOutcome) &&
     193           0 :                     (vote1.nVoteSignal == vote2.nVoteSignal) &&
     194           0 :                     (vote1.nTime == vote2.nTime));
     195           0 :     return fResult;
     196             : }
     197             : 
     198           0 : bool operator<(const CGovernanceVote& vote1, const CGovernanceVote& vote2)
     199             : {
     200           0 :     bool fResult = (vote1.masternodeOutpoint < vote2.masternodeOutpoint);
     201           0 :     if (!fResult) {
     202           0 :         return false;
     203             :     }
     204           0 :     fResult = (vote1.masternodeOutpoint == vote2.masternodeOutpoint);
     205             : 
     206           0 :     fResult = fResult && (vote1.nParentHash < vote2.nParentHash);
     207           0 :     if (!fResult) {
     208           0 :         return false;
     209             :     }
     210           0 :     fResult = (vote1.nParentHash == vote2.nParentHash);
     211             : 
     212           0 :     fResult = fResult && (vote1.nVoteOutcome < vote2.nVoteOutcome);
     213           0 :     if (!fResult) {
     214           0 :         return false;
     215             :     }
     216           0 :     fResult = (vote1.nVoteOutcome == vote2.nVoteOutcome);
     217             : 
     218           0 :     fResult = fResult && (vote1.nVoteSignal == vote2.nVoteSignal);
     219           0 :     if (!fResult) {
     220           0 :         return false;
     221             :     }
     222           0 :     fResult = (vote1.nVoteSignal == vote2.nVoteSignal);
     223             : 
     224           0 :     fResult = fResult && (vote1.nTime < vote2.nTime);
     225             : 
     226           0 :     return fResult;
     227           0 : }

Generated by: LCOV version 1.16