// Copyright (c) 2014-2017 The Dash Core developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef MASTERNODEMAN_H #define MASTERNODEMAN_H #include "masternode.h" #include "sync.h" using namespace std; class CMasternodeMan; extern CMasternodeMan mnodeman; /** * Provides a forward and reverse index between MN vin's and integers. * * This mapping is normally add-only and is expected to be permanent * It is only rebuilt if the size of the index exceeds the expected maximum number * of MN's and the current number of known MN's. * * The external interface to this index is provided via delegation by CMasternodeMan */ class CMasternodeIndex { public: // Types typedef std::map index_m_t; typedef index_m_t::iterator index_m_it; typedef index_m_t::const_iterator index_m_cit; typedef std::map rindex_m_t; typedef rindex_m_t::iterator rindex_m_it; typedef rindex_m_t::const_iterator rindex_m_cit; private: int nSize; index_m_t mapIndex; rindex_m_t mapReverseIndex; public: CMasternodeIndex(); int GetSize() const { return nSize; } /// Retrieve masternode vin by index bool Get(int nIndex, CTxIn& vinMasternode) const; /// Get index of a masternode vin int GetMasternodeIndex(const CTxIn& vinMasternode) const; void AddMasternodeVIN(const CTxIn& vinMasternode); void Clear(); ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(mapIndex); if(ser_action.ForRead()) { RebuildIndex(); } } private: void RebuildIndex(); }; class CMasternodeMan { public: typedef std::map index_m_t; typedef index_m_t::iterator index_m_it; typedef index_m_t::const_iterator index_m_cit; private: static const int MAX_EXPECTED_INDEX_SIZE = 30000; /// Only allow 1 index rebuild per hour static const int64_t MIN_INDEX_REBUILD_TIME = 3600; static const std::string SERIALIZATION_VERSION_STRING; static const int DSEG_UPDATE_SECONDS = 3 * 60 * 60; static const int LAST_PAID_SCAN_BLOCKS = 100; static const int MIN_POSE_PROTO_VERSION = 70203; static const int MAX_POSE_RANK = 10; static const int MAX_POSE_BLOCKS = 10; static const int MNB_RECOVERY_QUORUM_TOTAL = 10; static const int MNB_RECOVERY_QUORUM_REQUIRED = 6; static const int MNB_RECOVERY_WAIT_SECONDS = 60; static const int MNB_RECOVERY_RETRY_SECONDS = 3 * 60 * 60; // critical section to protect the inner data structures mutable CCriticalSection cs; // Keep track of current block index const CBlockIndex *pCurrentBlockIndex; // map to hold all MNs std::vector vMasternodes; // who's asked for the Masternode list and the last time std::map mAskedUsForMasternodeList; // who we asked for the Masternode list and the last time std::map mWeAskedForMasternodeList; // which Masternodes we've asked for std::map > mWeAskedForMasternodeListEntry; // who we asked for the masternode verification std::map mWeAskedForVerification; // these maps are used for masternode recovery from MASTERNODE_NEW_START_REQUIRED state std::map > > mMnbRecoveryRequests; std::map > mMnbRecoveryGoodReplies; int64_t nLastIndexRebuildTime; CMasternodeIndex indexMasternodes; CMasternodeIndex indexMasternodesOld; /// Set when index has been rebuilt, clear when read bool fIndexRebuilt; /// Set when masternodes are added, cleared when CGovernanceManager is notified bool fMasternodesAdded; /// Set when masternodes are removed, cleared when CGovernanceManager is notified bool fMasternodesRemoved; std::vector vecDirtyGovernanceObjectHashes; int64_t nLastWatchdogVoteTime; friend class CMasternodeSync; public: // Keep track of all broadcasts I've seen std::map > mapSeenMasternodeBroadcast; // Keep track of all pings I've seen std::map mapSeenMasternodePing; // Keep track of all verifications I've seen std::map mapSeenMasternodeVerification; // keep track of dsq count to prevent masternodes from gaming darksend queue int64_t nDsqCount; ADD_SERIALIZE_METHODS; template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { LOCK(cs); std::string strVersion; if(ser_action.ForRead()) { READWRITE(strVersion); } else { strVersion = SERIALIZATION_VERSION_STRING; READWRITE(strVersion); } READWRITE(vMasternodes); READWRITE(mAskedUsForMasternodeList); READWRITE(mWeAskedForMasternodeList); READWRITE(mWeAskedForMasternodeListEntry); READWRITE(mMnbRecoveryRequests); READWRITE(mMnbRecoveryGoodReplies); READWRITE(nLastWatchdogVoteTime); READWRITE(nDsqCount); READWRITE(mapSeenMasternodeBroadcast); READWRITE(mapSeenMasternodePing); READWRITE(indexMasternodes); if(ser_action.ForRead() && (strVersion != SERIALIZATION_VERSION_STRING)) { Clear(); } } CMasternodeMan(); /// Add an entry bool Add(CMasternode &mn); /// Ask (source) node for mnb void AskForMN(CNode *pnode, const CTxIn &vin); /// Check all Masternodes void Check(); /// Check all Masternodes and remove inactive void CheckAndRemove(); /// Clear Masternode vector void Clear(); /// Count Masternodes filtered by nProtocolVersion. /// Masternode nProtocolVersion should match or be above the one specified in param here. int CountMasternodes(int nProtocolVersion = -1); /// Count enabled Masternodes filtered by nProtocolVersion. /// Masternode nProtocolVersion should match or be above the one specified in param here. int CountEnabled(int nProtocolVersion = -1); /// Count Masternodes by network type - NET_IPV4, NET_IPV6, NET_TOR // int CountByIP(int nNetworkType); void DsegUpdate(CNode* pnode); /// Find an entry CMasternode* Find(const CScript &payee); CMasternode* Find(const CTxIn& vin); CMasternode* Find(const CPubKey& pubKeyMasternode); /// Versions of Find that are safe to use from outside the class bool Get(const CPubKey& pubKeyMasternode, CMasternode& masternode); bool Get(const CTxIn& vin, CMasternode& masternode); /// Retrieve masternode vin by index bool Get(int nIndex, CTxIn& vinMasternode, bool& fIndexRebuiltOut) { LOCK(cs); fIndexRebuiltOut = fIndexRebuilt; return indexMasternodes.Get(nIndex, vinMasternode); } bool GetIndexRebuiltFlag() { LOCK(cs); return fIndexRebuilt; } /// Get index of a masternode vin int GetMasternodeIndex(const CTxIn& vinMasternode) { LOCK(cs); return indexMasternodes.GetMasternodeIndex(vinMasternode); } /// Get old index of a masternode vin int GetMasternodeIndexOld(const CTxIn& vinMasternode) { LOCK(cs); return indexMasternodesOld.GetMasternodeIndex(vinMasternode); } /// Get masternode VIN for an old index value bool GetMasternodeVinForIndexOld(int nMasternodeIndex, CTxIn& vinMasternodeOut) { LOCK(cs); return indexMasternodesOld.Get(nMasternodeIndex, vinMasternodeOut); } /// Get index of a masternode vin, returning rebuild flag int GetMasternodeIndex(const CTxIn& vinMasternode, bool& fIndexRebuiltOut) { LOCK(cs); fIndexRebuiltOut = fIndexRebuilt; return indexMasternodes.GetMasternodeIndex(vinMasternode); } void ClearOldMasternodeIndex() { LOCK(cs); indexMasternodesOld.Clear(); fIndexRebuilt = false; } bool Has(const CTxIn& vin); masternode_info_t GetMasternodeInfo(const CTxIn& vin); masternode_info_t GetMasternodeInfo(const CPubKey& pubKeyMasternode); /// Find an entry in the masternode list that is next to be paid CMasternode* GetNextMasternodeInQueueForPayment(int nBlockHeight, bool fFilterSigTime, int& nCount); /// Same as above but use current block height CMasternode* GetNextMasternodeInQueueForPayment(bool fFilterSigTime, int& nCount); /// Find a random entry CMasternode* FindRandomNotInVec(const std::vector &vecToExclude, int nProtocolVersion = -1); std::vector GetFullMasternodeVector() { return vMasternodes; } std::vector > GetMasternodeRanks(int nBlockHeight = -1, int nMinProtocol=0); int GetMasternodeRank(const CTxIn &vin, int nBlockHeight, int nMinProtocol=0, bool fOnlyActive=true); CMasternode* GetMasternodeByRank(int nRank, int nBlockHeight, int nMinProtocol=0, bool fOnlyActive=true); void ProcessMasternodeConnections(); void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); void DoFullVerificationStep(); void CheckSameAddr(); bool SendVerifyRequest(const CAddress& addr, const std::vector& vSortedByAddr); void SendVerifyReply(CNode* pnode, CMasternodeVerification& mnv); void ProcessVerifyReply(CNode* pnode, CMasternodeVerification& mnv); void ProcessVerifyBroadcast(CNode* pnode, const CMasternodeVerification& mnv); /// Return the number of (unique) Masternodes int size() { return vMasternodes.size(); } std::string ToString() const; /// Update masternode list and maps using provided CMasternodeBroadcast void UpdateMasternodeList(CMasternodeBroadcast mnb); /// Perform complete check and only then update list and maps bool CheckMnbAndUpdateMasternodeList(CNode* pfrom, CMasternodeBroadcast mnb, int& nDos); bool IsMnbRecoveryRequested(const uint256& hash) { return mMnbRecoveryRequests.count(hash); } void UpdateLastPaid(); void CheckAndRebuildMasternodeIndex(); void AddDirtyGovernanceObjectHash(const uint256& nHash) { LOCK(cs); vecDirtyGovernanceObjectHashes.push_back(nHash); } std::vector GetAndClearDirtyGovernanceObjectHashes() { LOCK(cs); std::vector vecTmp = vecDirtyGovernanceObjectHashes; vecDirtyGovernanceObjectHashes.clear(); return vecTmp;; } bool IsWatchdogActive(); void UpdateWatchdogVoteTime(const CTxIn& vin); void AddGovernanceVote(const CTxIn& vin, uint256 nGovernanceObjectHash); void RemoveGovernanceObject(uint256 nGovernanceObjectHash); void CheckMasternode(const CTxIn& vin, bool fForce = false); void CheckMasternode(const CPubKey& pubKeyMasternode, bool fForce = false); int GetMasternodeState(const CTxIn& vin); int GetMasternodeState(const CPubKey& pubKeyMasternode); bool IsMasternodePingedWithin(const CTxIn& vin, int nSeconds, int64_t nTimeToCheckAt = -1); void SetMasternodeLastPing(const CTxIn& vin, const CMasternodePing& mnp); void UpdatedBlockTip(const CBlockIndex *pindex); /** * Called to notify CGovernanceManager that the masternode index has been updated. * Must be called while not holding the CMasternodeMan::cs mutex */ void NotifyMasternodeUpdates(); }; #endif