LCOV - code coverage report
Current view: top level - src/governance - object.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 57 79 72.2 %
Date: 2026-06-25 07:23:43 Functions: 46 68 67.6 %

          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             : #ifndef BITCOIN_GOVERNANCE_OBJECT_H
       6             : #define BITCOIN_GOVERNANCE_OBJECT_H
       7             : 
       8             : #include <governance/common.h>
       9             : #include <governance/vote.h>
      10             : #include <governance/votedb.h>
      11             : #include <sync.h>
      12             : 
      13             : #include <span.h>
      14             : 
      15             : #include <exception>
      16             : #include <iosfwd>
      17             : #include <string>
      18             : 
      19             : class CBLSPublicKey;
      20             : class CDeterministicMNList;
      21             : class ChainstateManager;
      22             : class CMasternodeMetaMan;
      23             : struct RPCResult;
      24             : 
      25             : extern RecursiveMutex cs_main; // NOLINT(readability-redundant-declaration)
      26             : 
      27             : enum governance_exception_type_enum_t {
      28             :     /// Default value, normally indicates no exception condition occurred
      29             :     GOVERNANCE_EXCEPTION_NONE = 0,
      30             :     /// Unusual condition requiring no caller action
      31             :     GOVERNANCE_EXCEPTION_WARNING = 1,
      32             :     /// Requested operation cannot be performed
      33             :     GOVERNANCE_EXCEPTION_PERMANENT_ERROR = 2,
      34             :     /// Requested operation not currently possible, may resubmit later
      35             :     GOVERNANCE_EXCEPTION_TEMPORARY_ERROR = 3,
      36             :     /// Unexpected error (ie. should not happen unless there is a bug in the code)
      37             :     GOVERNANCE_EXCEPTION_INTERNAL_ERROR = 4
      38             : };
      39             : 
      40             : std::ostream& operator<<(std::ostream& os, governance_exception_type_enum_t eType);
      41             : 
      42             : /**
      43             :  * A class which encapsulates information about a governance exception condition
      44             :  *
      45             :  * Derives from std::exception so is suitable for throwing
      46             :  * (ie. will be caught by a std::exception handler) but may also be used as a
      47             :  * normal object.
      48             :  */
      49             : class CGovernanceException : public std::exception
      50             : {
      51             : private:
      52             :     std::string strMessage;
      53             : 
      54             :     governance_exception_type_enum_t eType;
      55             : 
      56             :     int nNodePenalty;
      57             : 
      58             : public:
      59             :     explicit CGovernanceException(const std::string& strMessageIn = "",
      60             :         governance_exception_type_enum_t eTypeIn = GOVERNANCE_EXCEPTION_NONE,
      61             :         int nNodePenaltyIn = 0);
      62             : 
      63        3040 :     ~CGovernanceException() noexcept override = default;
      64             : 
      65           0 :     const char* what() const noexcept override
      66             :     {
      67           0 :         return strMessage.c_str();
      68             :     }
      69             : 
      70          20 :     const std::string& GetMessage() const
      71             :     {
      72          20 :         return strMessage;
      73             :     }
      74             : 
      75          20 :     governance_exception_type_enum_t GetType() const
      76             :     {
      77          20 :         return eType;
      78             :     }
      79             : 
      80           0 :     int GetNodePenalty() const
      81             :     {
      82           0 :         return nNodePenalty;
      83             :     }
      84             : };
      85             : 
      86             : static constexpr double GOVERNANCE_FILTER_FP_RATE = 0.001;
      87             : static constexpr CAmount GOVERNANCE_PROPOSAL_FEE_TX = (1 * COIN);
      88             : static constexpr int64_t GOVERNANCE_FEE_CONFIRMATIONS = 6;
      89             : static constexpr int64_t GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS = 1;
      90             : static constexpr int64_t GOVERNANCE_UPDATE_MIN = 60 * 60;
      91             : 
      92             : // FOR SEEN MAP ARRAYS - GOVERNANCE OBJECTS AND VOTES
      93             : enum class SeenObjectStatus {
      94             :     Valid = 0,
      95             :     ErrorInvalid,
      96             :     Executed,
      97             :     Unknown
      98             : };
      99             : 
     100             : using vote_time_pair_t = std::pair<CGovernanceVote, int64_t>;
     101             : 
     102           0 : inline bool operator<(const vote_time_pair_t& p1, const vote_time_pair_t& p2)
     103             : {
     104           0 :     return (p1.first < p2.first);
     105             : }
     106             : 
     107             : struct vote_instance_t {
     108             :     vote_outcome_enum_t eOutcome;
     109             :     int64_t nTime;
     110             :     int64_t nCreationTime;
     111             : 
     112        5960 :     explicit vote_instance_t(vote_outcome_enum_t eOutcomeIn = VOTE_OUTCOME_NONE, int64_t nTimeIn = 0, int64_t nCreationTimeIn = 0) :
     113        2980 :         eOutcome(eOutcomeIn),
     114        2980 :         nTime(nTimeIn),
     115        2980 :         nCreationTime(nCreationTimeIn)
     116        2980 :     {
     117        5960 :     }
     118             : 
     119        3600 :     SERIALIZE_METHODS(vote_instance_t, obj)
     120             :     {
     121             :         int nOutcome;
     122        2400 :         SER_WRITE(obj, nOutcome = int(obj.eOutcome));
     123        1200 :         READWRITE(nOutcome, obj.nTime, obj.nCreationTime);
     124        1200 :         SER_READ(obj, obj.eOutcome = vote_outcome_enum_t(nOutcome));
     125        1200 :     }
     126             : };
     127             : 
     128             : using vote_instance_m_t = std::map<int, vote_instance_t>;
     129             : 
     130             : struct vote_rec_t {
     131             :     vote_instance_m_t mapInstances;
     132             : 
     133        3600 :     SERIALIZE_METHODS(vote_rec_t, obj)
     134             :     {
     135        1200 :         READWRITE(obj.mapInstances);
     136        1200 :     }
     137             : };
     138             : 
     139             : /**
     140             : * Governance Object
     141             : *
     142             : */
     143             : 
     144             : class CGovernanceObject
     145             : {
     146             : public: // Types
     147             :     using vote_m_t = std::map<COutPoint, vote_rec_t>;
     148             : 
     149             : public:
     150             :     /// critical section to protect the inner data structures
     151             :     mutable Mutex cs;
     152             : 
     153             : private:
     154             :     Governance::Object m_obj;
     155             : 
     156             :     /// time this object was marked for deletion
     157           0 :     int64_t nDeletionTime GUARDED_BY(cs){0};
     158             : 
     159             :     /// is valid by blockchain
     160           0 :     bool fCachedLocalValidity{false};
     161             :     std::string strLocalValidityError;
     162             : 
     163             :     // VARIOUS FLAGS FOR OBJECT / SET VIA MASTERNODE VOTING
     164             : 
     165             :     /// true == minimum network support has been reached for this object to be funded (doesn't mean it will for sure though)
     166           0 :     bool fCachedFunding{false};
     167             : 
     168             :     /// true == minimum network has been reached flagging this object as a valid and understood governance object (e.g, the serialized data is correct format, etc)
     169           0 :     bool fCachedValid{true};
     170             : 
     171             :     /// true == minimum network support has been reached saying this object should be deleted from the system entirely
     172           0 :     bool fCachedDelete{false};
     173             : 
     174             :     /** true == minimum network support has been reached flagging this object as endorsed by an elected representative body
     175             :      * (e.g. business review board / technical review board /etc)
     176             :      */
     177           0 :     bool fCachedEndorsed{false};
     178             : 
     179             :     /// object was updated and cached values should be updated soon
     180           0 :     bool fDirtyCache{true};
     181             : 
     182             :     /// Object is no longer of interest
     183           0 :     bool fExpired GUARDED_BY(cs){false};
     184             : 
     185             :     /// Failed to parse object data
     186           0 :     bool fUnparsable{false};
     187             : 
     188             :     vote_m_t mapCurrentMNVotes GUARDED_BY(cs);
     189             : 
     190             :     CGovernanceObjectVoteFile fileVotes GUARDED_BY(cs);
     191             : 
     192             : public:
     193             :     CGovernanceObject();
     194             :     CGovernanceObject(const uint256& nHashParentIn, int nRevisionIn, int64_t nTime, const uint256& nCollateralHashIn, const std::string& strDataHexIn);
     195             :     CGovernanceObject(const CGovernanceObject& other);
     196             :     template <typename Stream>
     197           0 :     CGovernanceObject(deserialize_type, Stream& s) { s >> *this; }
     198             : 
     199             :     // Getters
     200       18340 :     bool IsSetCachedFunding() const { return fCachedFunding; }
     201       48988 :     bool IsSetCachedValid() const { return fCachedValid; }
     202       51829 :     bool IsSetCachedDelete() const { return fCachedDelete; }
     203       18048 :     bool IsSetCachedEndorsed() const { return fCachedEndorsed; }
     204       12926 :     bool IsSetDirtyCache() const { return fDirtyCache; }
     205       25482 :     bool IsSetExpired() const EXCLUSIVE_LOCKS_REQUIRED(!cs)
     206             :     {
     207       50964 :         return WITH_LOCK(cs, return fExpired);
     208             :     }
     209       91468 :     GovernanceObject GetObjectType() const { return m_obj.type; }
     210       49461 :     int64_t GetCreationTime() const { return m_obj.time; }
     211       25852 :     int64_t GetDeletionTime() const EXCLUSIVE_LOCKS_REQUIRED(!cs)
     212             :     {
     213       51704 :         return WITH_LOCK(cs, return nDeletionTime);
     214             :     }
     215             : 
     216        3594 :     const CGovernanceObjectVoteFile& GetVoteFile() const EXCLUSIVE_LOCKS_REQUIRED(cs)
     217             :     {
     218        3594 :         AssertLockHeld(cs);
     219        3594 :         return fileVotes;
     220             :     }
     221       18501 :     const COutPoint& GetMasternodeOutpoint() const { return m_obj.masternodeOutpoint; }
     222         300 :     const Governance::Object& Object() const { return m_obj; }
     223       18048 :     const uint256& GetCollateralHash() const { return m_obj.collateralHash; }
     224             : 
     225             :     // Setters
     226         104 :     void SetExpired() EXCLUSIVE_LOCKS_REQUIRED(!cs)
     227             :     {
     228         208 :         WITH_LOCK(cs, fExpired = true);
     229         104 :     }
     230             :     void SetMasternodeOutpoint(const COutPoint& outpoint);
     231             :     void SetSignature(Span<const uint8_t> sig);
     232             : 
     233             :     // Signature related functions
     234             :     bool CheckSignature(const CBLSPublicKey& pubKey) const;
     235             :     uint256 GetSignatureHash() const;
     236             : 
     237             :     // CORE OBJECT FUNCTIONS
     238             : 
     239             :     bool IsValidLocally(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman, std::string& strError, bool fCheckCollateral) const
     240             :         EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
     241             : 
     242             :     bool IsValidLocally(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman, std::string& strError, bool& fMissingConfirmations, bool fCheckCollateral) const
     243             :         EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
     244             : 
     245             :     /// Check the collateral transaction for the budget proposal/finalized budget
     246             :     bool IsCollateralValid(const ChainstateManager& chainman, std::string& strError, bool& fMissingConfirmations) const
     247             :         EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
     248             : 
     249             :     void UpdateLocalValidity(const CDeterministicMNList& tip_mn_list, const ChainstateManager& chainman)
     250             :         EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
     251             : 
     252             :     void UpdateSentinelVariables(const CDeterministicMNList& tip_mn_list)
     253             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     254             : 
     255         342 :     void PrepareDeletion(int64_t nDeletionTime_) EXCLUSIVE_LOCKS_REQUIRED(!cs)
     256             :     {
     257         342 :         fCachedDelete = true;
     258         342 :         LOCK(cs);
     259         342 :         if (nDeletionTime == 0) {
     260         144 :             nDeletionTime = nDeletionTime_;
     261         144 :         }
     262         342 :     }
     263             : 
     264             :     CAmount GetMinCollateralFee() const;
     265             : 
     266             :     UniValue GetJSONObject() const;
     267             : 
     268             :     uint256 GetHash() const;
     269             :     uint256 GetDataHash() const;
     270             : 
     271             :     // GET VOTE COUNT FOR SIGNAL
     272             : 
     273             :     int CountMatchingVotes(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn) const
     274             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     275             : 
     276             :     int GetAbsoluteYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const
     277             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     278             :     int GetAbsoluteNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const
     279             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     280             :     int GetYesCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const
     281             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     282             :     int GetNoCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const
     283             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     284             :     int GetAbstainCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const
     285             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     286             : 
     287           0 :     struct UniqueVoterCount {
     288           0 :         uint16_t m_regular{0};
     289           0 :         uint16_t m_evo{0};
     290             :     };
     291             :     UniqueVoterCount GetUniqueVoterCount(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t eVoteSignalIn) const
     292             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     293             : 
     294             :     bool GetCurrentMNVotes(const COutPoint& mnCollateralOutpoint, vote_rec_t& voteRecord) const
     295             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     296             : 
     297             :     // FUNCTIONS FOR DEALING WITH DATA STRING
     298             : 
     299             :     std::string GetDataAsHexString() const;
     300             :     std::string GetDataAsPlainString() const;
     301             : 
     302             :     // SERIALIZER
     303             : 
     304             :     template<typename Stream>
     305         896 :     void Serialize(Stream& s) const EXCLUSIVE_LOCKS_REQUIRED(!cs)
     306             :     {
     307             :         // SERIALIZE DATA FOR SAVING/LOADING OR NETWORK FUNCTIONS
     308         896 :         s << m_obj;
     309         896 :         if (s.GetType() & SER_DISK) {
     310             :             // Only include these for the disk file format
     311         240 :             LOCK(cs);
     312         240 :             s << nDeletionTime << fExpired << mapCurrentMNVotes << fileVotes;
     313         240 :         }
     314         896 :     }
     315             : 
     316             :     template<typename Stream>
     317         248 :     void Unserialize(Stream& s) EXCLUSIVE_LOCKS_REQUIRED(!cs)
     318             :     {
     319         248 :         s >> m_obj;
     320         248 :         if (s.GetType() & SER_DISK) {
     321             :             // Only include these for the disk file format
     322           0 :             LOCK(cs);
     323           0 :             s >> nDeletionTime >> fExpired >> mapCurrentMNVotes >> fileVotes;
     324           0 :         }
     325             :         // AFTER DESERIALIZATION OCCURS, CACHED VARIABLES MUST BE CALCULATED MANUALLY
     326         248 :     }
     327             : 
     328             :     // JSON emitters/help
     329             :     [[nodiscard]] static RPCResult GetInnerJsonHelp(const std::string& key, bool optional);
     330             :     [[nodiscard]] UniValue GetInnerJson() const;
     331             : 
     332             :     [[nodiscard]] static RPCResult GetStateJsonHelp(const std::string& key, bool optional, const std::string& local_valid_key);
     333             :     [[nodiscard]] UniValue GetStateJson(const ChainstateManager& chainman, const CDeterministicMNList& tip_mn_list, const std::string& local_valid_key) const
     334             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     335             : 
     336             :     [[nodiscard]] static RPCResult GetVotesJsonHelp(const std::string& key, bool optional);
     337             :     [[nodiscard]] UniValue GetVotesJson(const CDeterministicMNList& tip_mn_list, vote_signal_enum_t signal) const
     338             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     339             : 
     340             :     // FUNCTIONS FOR DEALING WITH DATA STRING
     341             :     void LoadData();
     342             :     void GetData(UniValue& objResult) const;
     343             : 
     344             :     bool ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateChecksEnabled, const CDeterministicMNList& tip_mn_list,
     345             :                      const CGovernanceVote& vote, CGovernanceException& exception) EXCLUSIVE_LOCKS_REQUIRED(!cs);
     346             : 
     347             :     /// Called when MN's which have voted on this object have been removed
     348             :     void ClearMasternodeVotes(const CDeterministicMNList& tip_mn_list)
     349             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     350             : 
     351             :     // Revalidate all votes from this MN and delete them if validation fails.
     352             :     // This is the case for DIP3 MNs that changed voting or operator keys and
     353             :     // also for MNs that were removed from the list completely.
     354             :     // Returns deleted vote hashes.
     355             :     std::set<uint256> RemoveInvalidVotes(const CDeterministicMNList& tip_mn_list, const COutPoint& mnOutpoint)
     356             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     357             : };
     358             : 
     359             : namespace governance {
     360             : /**
     361             :  * Validate the serialized proposal data (hex-encoded JSON).
     362             :  * Returns true on success. On failure, returns false and fills strErrorOut
     363             :  * with a semicolon-delimited list of detected issues.
     364             :  */
     365             : bool ValidateProposal(const std::string& strDataHex, std::string& strErrorOut,
     366             :                       bool fCheckExpiration = true, bool fAllowScript = true);
     367             : } // namespace governance
     368             : 
     369             : #endif // BITCOIN_GOVERNANCE_OBJECT_H

Generated by: LCOV version 1.16