text: // Copyright (c) 2014-2017 The DigitSlate 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<CTxIn,int> index_m_t;
  
      typedef index_m_t::iterator index_m_it;
  
      typedef index_m_t::const_iterator index_m_cit;
  
      typedef std::map<int,CTxIn> 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 <typename Stream, typename Operation>
      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<CTxIn,int> 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_CONNECTIONS       = 10;
      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_MAX_ASK_ENTRIES   = 10;
      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<CMasternode> vMasternodes;
      // who's asked for the Masternode list and the last time
      std::map<CNetAddr, int64_t> mAskedUsForMasternodeList;
      // who we asked for the Masternode list and the last time
      std::map<CNetAddr, int64_t> mWeAskedForMasternodeList;
      // which Masternodes we've asked for
      std::map<COutPoint, std::map<CNetAddr, int64_t> > mWeAskedForMasternodeListEntry;
      // who we asked for the masternode verification
      std::map<CNetAddr, CMasternodeVerification> mWeAskedForVerification;
  
      // these maps are used for masternode recovery from MASTERNODE_NEW_START_REQUIRED state
      std::map<uint256, std::pair< int64_t, std::set<CNetAddr> > > mMnbRecoveryRequests;
      std::map<uint256, std::vector<CMasternodeBroadcast> > mMnbRecoveryGoodReplies;
      std::list< std::pair<CService, uint256> > listScheduledMnbRequestConnections;
  
      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<uint256> vecDirtyGovernanceObjectHashes;
  
      int64_t nLastWatchdogVoteTime;
  
      friend class CMasternodeSync;
  
  public:
      // Keep track of all broadcasts I've seen
      std::map<uint256, std::pair<int64_t, CMasternodeBroadcast> > mapSeenMasternodeBroadcast;
      // Keep track of all pings I've seen
      std::map<uint256, CMasternodePing> mapSeenMasternodePing;
      // Keep track of all verifications I've seen
      std::map<uint256, CMasternodeVerification> mapSeenMasternodeVerification;
      // keep track of dsq count to prevent masternodes from gaming darksend queue
      int64_t nDsqCount;
  
  
      ADD_SERIALIZE_METHODS;
  
      template <typename Stream, typename Operation>
      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);
      void AskForMnb(CNode *pnode, const uint256 &hash);
  
      /// 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<CTxIn> &vecToExclude, int nProtocolVersion = -1);
  
      std::vector<CMasternode> GetFullMasternodeVector() { return vMasternodes; }
  
      std::vector<std::pair<int, CMasternode> > 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();
      std::pair<CService, std::set<uint256> > PopScheduledMnbRequestConnection();
  
      void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
  
      void DoFullVerificationStep();
      void CheckSameAddr();
      bool SendVerifyRequest(const CAddress& addr, const std::vector<CMasternode*>& 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<uint256> GetAndClearDirtyGovernanceObjectHashes()
      {
          LOCK(cs);
          std::vector<uint256> vecTmp = vecDirtyGovernanceObjectHashes;
          vecDirtyGovernanceObjectHashes.clear();
          return vecTmp;;
      }
  
      bool IsWatchdogActive();
      void UpdateWatchdogVoteTime(const CTxIn& vin);
      bool 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
  