LCOV - code coverage report
Current view: top level - src/governance - net_governance.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 0 142 0.0 %
Date: 2026-06-25 07:23:51 Functions: 0 9 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2024-2025 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <governance/net_governance.h>
       6             : 
       7             : #include <chainparams.h>
       8             : #include <common/bloom.h>
       9             : #include <evo/deterministicmns.h>
      10             : #include <governance/governance.h>
      11             : #include <governance/object.h>
      12             : #include <logging.h>
      13             : #include <masternode/sync.h>
      14             : #include <net.h>
      15             : #include <netfulfilledman.h>
      16             : #include <netmessagemaker.h>
      17             : #include <scheduler.h>
      18             : 
      19             : class CConnman;
      20             : 
      21           0 : void NetGovernance::Schedule(CScheduler& scheduler)
      22             : {
      23             :     // Code below is meant to be running only if governance validation is enabled
      24             :     //
      25           0 :     if (!m_gov_manager.IsValid()) return;
      26           0 :     scheduler.scheduleEvery(
      27           0 :         [this]() -> void {
      28           0 :             if (!m_node_sync.IsSynced()) return;
      29             : 
      30             :             // Request governance objects for orphan votes
      31           0 :             auto vecOrphanHashes = m_gov_manager.GetOrphanVoteObjectHashes();
      32           0 :             if (!vecOrphanHashes.empty()) {
      33           0 :                 LogPrint(BCLog::GOBJECT, "NetGovernance::Schedule -- requesting %d orphan objects\n",
      34             :                          vecOrphanHashes.size());
      35           0 :                 const CConnman::NodesSnapshot snap{m_connman, CConnman::FullyConnectedOnly};
      36           0 :                 for (const uint256& nHash : vecOrphanHashes) {
      37           0 :                     for (CNode* pnode : snap.Nodes()) {
      38           0 :                         if (!pnode->CanRelay()) continue;
      39           0 :                         CNetMsgMaker msgMaker(pnode->GetCommonVersion());
      40           0 :                         CBloomFilter filter; // Empty filter - we want the object, not votes
      41           0 :                         m_connman.PushMessage(pnode, msgMaker.Make(NetMsgType::MNGOVERNANCESYNC, nHash, filter));
      42           0 :                     }
      43             :                 }
      44           0 :             }
      45             : 
      46             :             // CHECK AND REMOVE - REPROCESS GOVERNANCE OBJECTS
      47           0 :             m_gov_manager.CheckAndRemove();
      48           0 :         },
      49           0 :         std::chrono::minutes{5});
      50             : 
      51           0 :     scheduler.scheduleEvery(
      52           0 :         [this]() -> void {
      53           0 :             auto relay_invs = m_gov_manager.FetchRelayInventory();
      54           0 :             for (const auto& inv : relay_invs) {
      55           0 :                 m_peer_manager->PeerRelayInv(inv);
      56             :             }
      57           0 :         },
      58             :         // Tests need tighter timings to avoid timeouts, use more relaxed pacing otherwise
      59           0 :         Params().IsMockableChain() ? std::chrono::seconds{1} : std::chrono::seconds{5});
      60           0 : }
      61             : 
      62           0 : void NetGovernance::ProcessMessage(CNode& peer, const std::string& msg_type, CDataStream& vRecv)
      63             : {
      64           0 :     if (!m_gov_manager.IsValid()) return;
      65           0 :     if (!m_node_sync.IsBlockchainSynced()) return;
      66             : 
      67             :     // ANOTHER USER IS ASKING US TO HELP THEM SYNC GOVERNANCE OBJECT DATA
      68           0 :     if (msg_type == NetMsgType::MNGOVERNANCESYNC) {
      69             :         // Ignore such requests until we are fully synced.
      70             :         // We could start processing this after masternode list is synced
      71             :         // but this is a heavy one so it's better to finish sync first.
      72           0 :         if (!m_node_sync.IsSynced()) return;
      73             : 
      74           0 :         uint256 nProp;
      75           0 :         CBloomFilter filter;
      76           0 :         vRecv >> nProp;
      77           0 :         vRecv >> filter;
      78             : 
      79           0 :         LogPrint(BCLog::GOBJECT, "MNGOVERNANCESYNC -- syncing governance objects to our peer %s\n", peer.GetLogString());
      80           0 :         if (nProp == uint256()) {
      81             :             // Full sync of all governance objects
      82           0 :             assert(m_netfulfilledman.IsValid());
      83           0 :             if (m_netfulfilledman.HasFulfilledRequest(peer.addr, NetMsgType::MNGOVERNANCESYNC)) {
      84             :                 // Asking for the whole list multiple times in a short period of time is no good
      85           0 :                 LogPrint(BCLog::GOBJECT, "MNGOVERNANCESYNC -- peer already asked me for the list\n");
      86           0 :                 m_peer_manager->PeerMisbehaving(peer.GetId(), 20);
      87           0 :                 return;
      88             :             }
      89           0 :             m_netfulfilledman.AddFulfilledRequest(peer.addr, NetMsgType::MNGOVERNANCESYNC);
      90             : 
      91           0 :             auto invs = m_gov_manager.GetSyncableObjectInvs();
      92           0 :             LogPrint(BCLog::GOBJECT, "MNGOVERNANCESYNC -- syncing %d objects to peer=%d\n", invs.size(), peer.GetId());
      93             : 
      94           0 :             CNetMsgMaker msgMaker(peer.GetCommonVersion());
      95           0 :             m_connman.PushMessage(&peer, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ,
      96           0 :                                                        static_cast<int>(invs.size())));
      97           0 :             for (const auto& inv : invs) {
      98           0 :                 m_peer_manager->PeerRelayInv(inv);
      99             :             }
     100           0 :         } else {
     101             :             // Sync votes for a specific governance object
     102           0 :             auto invs = m_gov_manager.GetSyncableVoteInvs(nProp, filter);
     103           0 :             LogPrint(BCLog::GOBJECT, "MNGOVERNANCESYNC -- syncing %d votes for %s to peer=%d\n", invs.size(),
     104             :                      nProp.ToString(), peer.GetId());
     105             : 
     106           0 :             CNetMsgMaker msgMaker(peer.GetCommonVersion());
     107           0 :             m_connman.PushMessage(&peer, msgMaker.Make(NetMsgType::SYNCSTATUSCOUNT, MASTERNODE_SYNC_GOVOBJ_VOTE,
     108           0 :                                                        static_cast<int>(invs.size())));
     109           0 :             for (const auto& inv : invs) {
     110           0 :                 m_peer_manager->PeerRelayInv(inv);
     111             :             }
     112           0 :         }
     113           0 :     }
     114             :     // A NEW GOVERNANCE OBJECT HAS ARRIVED
     115           0 :     else if (msg_type == NetMsgType::MNGOVERNANCEOBJECT) {
     116             :         // MAKE SURE WE HAVE A VALID REFERENCE TO THE TIP BEFORE CONTINUING
     117           0 :         CGovernanceObject govobj;
     118           0 :         vRecv >> govobj;
     119             : 
     120           0 :         uint256 nHash = govobj.GetHash();
     121             : 
     122           0 :         WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(peer.GetId(), CInv{MSG_GOVERNANCE_OBJECT, nHash}));
     123             : 
     124           0 :         if (!m_node_sync.IsBlockchainSynced()) {
     125           0 :             LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- masternode list not synced\n");
     126           0 :             return;
     127             :         }
     128             : 
     129           0 :         std::string strHash = nHash.ToString();
     130             : 
     131           0 :         LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received object: %s\n", strHash);
     132             : 
     133           0 :         if (!m_gov_manager.AcceptMessage(nHash)) {
     134           0 :             LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECT -- Received unrequested object: %s\n", strHash);
     135           0 :             return;
     136             :         }
     137             : 
     138           0 :         if (!WITH_LOCK(::cs_main, return m_gov_manager.ProcessObject(peer.GetLogString(), nHash, govobj))) {
     139             :             // apply node's ban score
     140           0 :             m_peer_manager->PeerMisbehaving(peer.GetId(), 20);
     141           0 :         }
     142           0 :     }
     143             : 
     144             :     // A NEW GOVERNANCE OBJECT VOTE HAS ARRIVED
     145           0 :     else if (msg_type == NetMsgType::MNGOVERNANCEOBJECTVOTE) {
     146           0 :         CGovernanceVote vote;
     147           0 :         vRecv >> vote;
     148             : 
     149           0 :         uint256 nHash = vote.GetHash();
     150             : 
     151           0 :         WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(peer.GetId(), CInv{MSG_GOVERNANCE_OBJECT_VOTE, nHash}));
     152             : 
     153             :         // Ignore such messages until masternode list is synced
     154           0 :         if (!m_node_sync.IsBlockchainSynced()) {
     155           0 :             LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- masternode list not synced\n");
     156           0 :             return;
     157             :         }
     158             : 
     159           0 :         const auto tip_mn_list = m_gov_manager.GetMNManager().GetListAtChainTip();
     160           0 :         LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Received vote: %s\n", vote.ToString(tip_mn_list));
     161             : 
     162           0 :         std::string strHash = nHash.ToString();
     163             : 
     164           0 :         if (!m_gov_manager.AcceptMessage(nHash)) {
     165           0 :             LogPrint(BCLog::GOBJECT, /* Continued */
     166             :                      "MNGOVERNANCEOBJECTVOTE -- Received unrequested vote object: %s, hash: %s, peer = %d\n",
     167             :                      vote.ToString(tip_mn_list), strHash, peer.GetId());
     168           0 :             return;
     169             :         }
     170             : 
     171           0 :         CGovernanceException exception;
     172           0 :         uint256 hashToRequest;
     173           0 :         if (m_gov_manager.ProcessVote(vote, exception, hashToRequest)) {
     174           0 :             LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- %s new\n", strHash);
     175           0 :             m_node_sync.BumpAssetLastTime("MNGOVERNANCEOBJECTVOTE");
     176             : 
     177           0 :             if (!m_node_sync.IsSynced()) {
     178           0 :                 LogPrint(BCLog::GOBJECT, "%s -- won't relay until fully synced\n", __func__);
     179           0 :                 return;
     180             :             }
     181           0 :             auto dmn = tip_mn_list.GetMNByCollateral(vote.GetMasternodeOutpoint());
     182           0 :             if (!dmn) {
     183           0 :                 return;
     184             :             }
     185           0 :             m_gov_manager.RelayVote(vote);
     186             :             // TODO: figure out why immediate sending of inventory doesn't work here!
     187             :             // m_peer_manager->PeerRelayInv(CInv{MSG_GOVERNANCE_OBJECT_VOTE, nHash});
     188           0 :         } else {
     189           0 :             LogPrint(BCLog::GOBJECT, "MNGOVERNANCEOBJECTVOTE -- Rejected vote, error = %s\n", exception.what());
     190           0 :             if (hashToRequest != uint256()) {
     191             :                 // Orphan vote - request the missing governance object
     192           0 :                 CNetMsgMaker msgMaker(peer.GetCommonVersion());
     193           0 :                 CBloomFilter filter; // Empty filter - we just want the object, not votes
     194           0 :                 m_connman.PushMessage(&peer, msgMaker.Make(NetMsgType::MNGOVERNANCESYNC, hashToRequest, filter));
     195           0 :             }
     196           0 :             if ((exception.GetNodePenalty() != 0) && m_node_sync.IsSynced()) {
     197           0 :                 m_peer_manager->PeerMisbehaving(peer.GetId(), exception.GetNodePenalty());
     198           0 :             }
     199             :         }
     200           0 :     }
     201           0 : }
     202             : 
     203           0 : bool NetGovernance::AlreadyHave(const CInv& inv)
     204             : {
     205           0 :     if (inv.type != MSG_GOVERNANCE_OBJECT && inv.type != MSG_GOVERNANCE_OBJECT_VOTE) {
     206           0 :         return false;
     207             :     }
     208             :     // When governance isn't loaded (e.g. -disablegovernance), claim we already have
     209             :     // the item so we don't fetch or track it. ConfirmInventoryRequest would otherwise
     210             :     // grow m_requested_hash_time unbounded since CheckAndRemove never runs in that mode.
     211           0 :     if (!m_gov_manager.IsValid()) return true;
     212           0 :     return !m_gov_manager.ConfirmInventoryRequest(inv);
     213           0 : }
     214             : 
     215           0 : bool NetGovernance::ProcessGetData(CNode& pfrom, const CInv& inv, CConnman& connman, const CNetMsgMaker& msgMaker)
     216             : {
     217           0 :     if (inv.type == MSG_GOVERNANCE_OBJECT) {
     218           0 :         if (!m_gov_manager.HaveObjectForHash(inv.hash)) return false;
     219           0 :         CDataStream ss(SER_NETWORK, pfrom.GetCommonVersion());
     220           0 :         ss.reserve(1000);
     221           0 :         if (!m_gov_manager.SerializeObjectForHash(inv.hash, ss)) return false;
     222           0 :         connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::MNGOVERNANCEOBJECT, ss));
     223           0 :         return true;
     224           0 :     }
     225           0 :     if (inv.type == MSG_GOVERNANCE_OBJECT_VOTE) {
     226           0 :         if (!m_gov_manager.HaveVoteForHash(inv.hash)) return false;
     227           0 :         CDataStream ss(SER_NETWORK, pfrom.GetCommonVersion());
     228           0 :         ss.reserve(1000);
     229           0 :         if (!m_gov_manager.SerializeVoteForHash(inv.hash, ss)) return false;
     230           0 :         connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::MNGOVERNANCEOBJECTVOTE, ss));
     231           0 :         return true;
     232           0 :     }
     233           0 :     return false;
     234           0 : }

Generated by: LCOV version 1.16