text: // Copyright (c) 2014-2015 The Dash developers
  // Copyright (c) 2015-2020 The PIVX developers
  // Copyright (c) 2021 The REBEL Coin developers
  // Distributed under the MIT software license, see the accompanying
  // file COPYING or https://www.opensource.org/licenses/mit-license.php.
  
  #ifndef MASTERNODE_SYNC_H
  #define MASTERNODE_SYNC_H
  
  #include "net.h"    // for NodeId
  #include "uint256.h"
  
  #include <atomic>
  #include <string>
  #include <map>
  
  #define MASTERNODE_SYNC_INITIAL 0
  #define MASTERNODE_SYNC_SPORKS 1
  #define MASTERNODE_SYNC_LIST 2
  #define MASTERNODE_SYNC_MNW 3
  #define MASTERNODE_SYNC_BUDGET 4
  #define MASTERNODE_SYNC_BUDGET_PROP 10
  #define MASTERNODE_SYNC_BUDGET_FIN 11
  #define MASTERNODE_SYNC_FAILED 998
  #define MASTERNODE_SYNC_FINISHED 999
  
  #define MASTERNODE_SYNC_TIMEOUT 5
  #define MASTERNODE_SYNC_THRESHOLD 2
  
  class CMasternodeSync;
  extern CMasternodeSync masternodeSync;
  
  struct TierTwoPeerData {
      // map of message --> last request timestamp, bool hasResponseArrived.
      std::map<const char*, std::pair<int64_t, bool>> mapMsgData;
  };
  
  //
  // CMasternodeSync : Sync masternode assets in stages
  //
  
  class CMasternodeSync
  {
  public:
      std::map<uint256, int> mapSeenSyncMNB;
      std::map<uint256, int> mapSeenSyncMNW;
      std::map<uint256, int> mapSeenSyncBudget;
  
      int64_t lastMasternodeList;
      int64_t lastMasternodeWinner;
      int64_t lastBudgetItem;
      int64_t lastFailure;
      int nCountFailures;
  
      std::atomic<int64_t> lastProcess;
      std::atomic<bool> fBlockchainSynced;
  
      // sum of all counts
      int sumMasternodeList;
      int sumMasternodeWinner;
      int sumBudgetItemProp;
      int sumBudgetItemFin;
      // peers that reported counts
      int countMasternodeList;
      int countMasternodeWinner;
      int countBudgetItemProp;
      int countBudgetItemFin;
  
      // Count peers we've requested the list from
      int RequestedMasternodeAssets;
      int RequestedMasternodeAttempt;
  
      // Time when current masternode asset sync started
      int64_t nAssetSyncStarted;
  
      CMasternodeSync();
  
      void AddedMasternodeList(const uint256& hash);
      void AddedMasternodeWinner(const uint256& hash);
      void AddedBudgetItem(const uint256& hash);
      void GetNextAsset();
      std::string GetSyncStatus();
      void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
      bool IsBudgetFinEmpty();
      bool IsBudgetPropEmpty();
  
      void Reset();
      void Process();
      /*
       * Process sync with a single node.
       * If it returns false, the Process() step is complete.
       * Otherwise Process() calls it again for a different node.
       */
      bool SyncWithNode(CNode* pnode);
      bool IsSynced();
      bool NotCompleted();
      bool IsSporkListSynced();
      bool IsMasternodeListSynced();
      bool IsBlockchainSynced();
      void ClearFulfilledRequest();
  
      bool IsBlockchainSyncedReadOnly() const;
  
      // Sync message dispatcher
      bool MessageDispatcher(CNode* pfrom, std::string& strCommand, CDataStream& vRecv);
  
  private:
  
      // Tier two sync node state
      // map of nodeID --> TierTwoPeerData
      std::map<NodeId, TierTwoPeerData> peersSyncState;
  
      void SyncRegtest(CNode* pnode);
  
      template <typename... Args>
      void RequestDataTo(CNode* pnode, const char* msg, bool forceRequest, Args&&... args);
  
      template <typename... Args>
      void PushMessage(CNode* pnode, const char* msg, Args&&... args);
  
      // update peer sync state data
      bool UpdatePeerSyncState(const NodeId& id, const char* msg, const int nextSyncStatus);
  
      // Check if an update is needed
      void CheckAndUpdateSyncStatus();
  };
  
  #endif
  