LCOV - code coverage report
Current view: top level - src/llmq - net_dkg.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 398 429 92.8 %
Date: 2026-06-25 07:23:43 Functions: 55 59 93.2 %

          Line data    Source code
       1             : // Copyright (c) 2018-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 <llmq/net_dkg.h>
       6             : 
       7             : #include <active/dkgsessionhandler.h>
       8             : #include <chainparams.h>
       9             : #include <evo/deterministicmns.h>
      10             : #include <hash.h>
      11             : #include <llmq/blockprocessor.h>
      12             : #include <llmq/commitment.h>
      13             : #include <llmq/debug.h>
      14             : #include <llmq/dkgsession.h>
      15             : #include <llmq/dkgsessionmgr.h>
      16             : #include <llmq/net_quorum.h>
      17             : #include <llmq/options.h>
      18             : #include <llmq/quorumsman.h>
      19             : #include <llmq/utils.h>
      20             : #include <masternode/meta.h>
      21             : #include <net.h>
      22             : #include <netmessagemaker.h>
      23             : #include <protocol.h>
      24             : #include <span.h>
      25             : #include <unordered_lru_cache.h>
      26             : #include <util/std23.h>
      27             : #include <util/thread.h>
      28             : #include <validation.h>
      29             : 
      30             : namespace llmq {
      31             : 
      32             : namespace {
      33             : // returns a set of NodeIds which sent invalid messages
      34             : template <typename Message>
      35       13804 : std::unordered_set<NodeId> BatchVerifyMessageSigs(CDKGSession& session,
      36             :                                                   const std::vector<std::pair<NodeId, std::shared_ptr<Message>>>& messages)
      37             : {
      38       13804 :     if (messages.empty()) {
      39           0 :         return {};
      40             :     }
      41             : 
      42       13804 :     std::unordered_set<NodeId> ret;
      43       13804 :     bool revertToSingleVerification = false;
      44             : 
      45       13804 :     CBLSSignature aggSig;
      46       13804 :     std::vector<CBLSPublicKey> pubKeys;
      47       13804 :     std::vector<uint256> messageHashes;
      48       13804 :     Uint256HashSet messageHashesSet;
      49       13804 :     pubKeys.reserve(messages.size());
      50       13778 :     messageHashes.reserve(messages.size());
      51       13779 :     bool first = true;
      52       51660 :     for (const auto& [nodeId, msg] : messages) {
      53       35476 :         auto member = session.GetMember(msg->proTxHash);
      54       17736 :         if (!member) {
      55             :             // should not happen as it was verified before
      56           0 :             ret.emplace(nodeId);
      57           0 :             continue;
      58             :         }
      59             : 
      60       17736 :         if (first) {
      61       13778 :             aggSig = msg->sig;
      62       13778 :         } else {
      63        3958 :             aggSig.AggregateInsecure(msg->sig);
      64             :         }
      65       17735 :         first = false;
      66             : 
      67       17735 :         auto msgHash = msg->GetSignHash();
      68       17738 :         if (!messageHashesSet.emplace(msgHash).second) {
      69             :             // can only happen in 2 cases:
      70             :             // 1. Someone sent us the same message twice but with differing signature, meaning that at least one of them
      71             :             //    must be invalid. In this case, we'd have to revert to single message verification nevertheless
      72             :             // 2. Someone managed to find a way to create two different binary representations of a message that deserializes
      73             :             //    to the same object representation. This would be some form of malleability. However, this shouldn't be
      74             :             //    possible as only deterministic/unique BLS signatures and very simple data types are involved
      75        1548 :             revertToSingleVerification = true;
      76        1548 :             break;
      77             :         }
      78             : 
      79       16189 :         pubKeys.emplace_back(member->dmn->pdmnState->pubKeyOperator.Get());
      80       16186 :         messageHashes.emplace_back(msgHash);
      81             :     }
      82       13777 :     if (!revertToSingleVerification) {
      83       12229 :         if (aggSig.VerifyInsecureAggregated(pubKeys, messageHashes)) {
      84             :             // all good
      85       12231 :             return ret;
      86             :         }
      87             : 
      88             :         // are all messages from the same node?
      89           1 :         bool nodeIdsAllSame = std::adjacent_find(messages.begin(), messages.end(),
      90           0 :                                                  [](const auto& first, const auto& second) {
      91           0 :                                                      return first.first != second.first;
      92           1 :                                                  }) == messages.end();
      93             : 
      94             :         // if yes, take a short path and return a set with only him
      95           1 :         if (nodeIdsAllSame) {
      96           1 :             ret.emplace(messages[0].first);
      97           1 :             return ret;
      98             :         }
      99             :         // different nodes, let's figure out who are the bad ones
     100           0 :     }
     101             : 
     102        8198 :     for (const auto& [nodeId, msg] : messages) {
     103        3325 :         if (ret.count(nodeId)) {
     104           0 :             continue;
     105             :         }
     106             : 
     107        6650 :         auto member = session.GetMember(msg->proTxHash);
     108        3324 :         bool valid = msg->sig.VerifyInsecure(member->dmn->pdmnState->pubKeyOperator.Get(), msg->GetSignHash());
     109        3325 :         if (!valid) {
     110           0 :             ret.emplace(nodeId);
     111           0 :         }
     112             :     }
     113        1548 :     return ret;
     114       27612 : }
     115             : 
     116       17960 : void RelayInvToParticipants(const CDKGSession& session, const CConnman& connman, PeerManagerInternal& peerman,
     117             :                             const CInv& inv)
     118             : {
     119       17960 :     CDKGLogger logger(session, __func__, __LINE__);
     120       17960 :     std::stringstream ss;
     121       17960 :     const auto& relayMembers = session.RelayMembers();
     122       53002 :     for (const auto& r : relayMembers) {
     123       35042 :         ss << r.ToString().substr(0, 4) << " | ";
     124             :     }
     125       35920 :     logger.Batch("RelayInvToParticipants inv[%s] relayMembers[%d] GetNodeCount[%d] GetNetworkActive[%d] "
     126             :                  "HasMasternodeQuorumNodes[%d] for quorumHash[%s] forMember[%s] relayMembers[%s]",
     127       17960 :                  inv.ToString(), relayMembers.size(), connman.GetNodeCount(ConnectionDirection::Both),
     128       17960 :                  connman.GetNetworkActive(),
     129       17960 :                  connman.HasMasternodeQuorumNodes(session.GetType(), session.BlockIndex()->GetBlockHash()),
     130       17960 :                  session.BlockIndex()->GetBlockHash().ToString(), session.ProTx().ToString().substr(0, 4), ss.str());
     131             : 
     132       17960 :     std::stringstream ss2;
     133      114052 :     connman.ForEachNode([&](const CNode* pnode) {
     134      192184 :         if (pnode->qwatch ||
     135       96092 :             (!pnode->GetVerifiedProRegTxHash().IsNull() && (relayMembers.count(pnode->GetVerifiedProRegTxHash()) != 0))) {
     136       34377 :             peerman.PeerPushInventory(pnode->GetId(), inv);
     137       34377 :         }
     138             : 
     139       96092 :         if (pnode->GetVerifiedProRegTxHash().IsNull()) {
     140       17898 :             logger.Batch("node[%d:%s] not mn", pnode->GetId(), pnode->m_addr_name);
     141       96092 :         } else if (relayMembers.count(pnode->GetVerifiedProRegTxHash()) == 0) {
     142       43817 :             ss2 << pnode->GetVerifiedProRegTxHash().ToString().substr(0, 4) << " | ";
     143       43817 :         }
     144       96092 :     });
     145       17960 :     logger.Batch("forMember[%s] NOTrelayMembers[%s]", session.ProTx().ToString().substr(0, 4), ss2.str());
     146       17960 :     logger.Flush();
     147       17960 : }
     148             : 
     149             : template <typename Message>
     150        5159 : void EnqueueOwn(CDKGPendingMessages& pending, const Message& msg)
     151             : {
     152        5159 :     CDataStream ds(SER_NETWORK, PROTOCOL_VERSION);
     153        5159 :     ds << msg;
     154        5159 :     auto pm = std::make_shared<CDataStream>(std::move(ds));
     155        5159 :     CHashWriter hw(SER_GETHASH, 0);
     156        5159 :     hw.write(AsWritableBytes(Span{*pm}));
     157        5159 :     pending.PushPendingMessage(/*from=*/-1, std::move(pm), hw.GetHash());
     158        5159 : }
     159             : 
     160             : template <typename Message>
     161      138505 : bool ProcessPendingMessageBatch(const CConnman& connman, CDKGSession& session, CDKGPendingMessages& pendingMessages,
     162             :                                 PeerManagerInternal& peerman, size_t maxCount)
     163             : {
     164      138505 :     auto msgs = pendingMessages.PopAndDeserializeMessages<Message>(maxCount);
     165      138505 :     if (msgs.empty()) {
     166      124724 :         return false;
     167             :     }
     168             : 
     169       13781 :     std::vector<std::pair<NodeId, std::shared_ptr<Message>>> preverifiedMessages;
     170       13781 :     preverifiedMessages.reserve(msgs.size());
     171             : 
     172       31743 :     for (const auto& p : msgs) {
     173       17962 :         const NodeId& nodeId = p.first;
     174       17962 :         if (!p.second) {
     175           0 :             LogPrint(BCLog::LLMQ_DKG, "%s -- failed to deserialize message, peer=%d\n", __func__, nodeId);
     176           0 :             peerman.PeerMisbehaving(nodeId, 100);
     177           0 :             continue;
     178             :         }
     179       17962 :         bool ban = false;
     180       17962 :         if (!session.PreVerifyMessage(*p.second, ban)) {
     181           1 :             if (ban) {
     182           1 :                 LogPrint(BCLog::LLMQ_DKG, "%s -- banning node due to failed preverification, peer=%d\n", __func__, nodeId);
     183           1 :                 peerman.PeerMisbehaving(nodeId, 100);
     184           1 :             }
     185           1 :             LogPrint(BCLog::LLMQ_DKG, "%s -- skipping message due to failed preverification, peer=%d\n", __func__, nodeId);
     186           1 :             continue;
     187             :         }
     188       17961 :         preverifiedMessages.emplace_back(p);
     189             :     }
     190       13781 :     if (preverifiedMessages.empty()) {
     191           1 :         return true;
     192             :     }
     193             : 
     194       13780 :     auto badNodes = BatchVerifyMessageSigs(session, preverifiedMessages);
     195       13780 :     if (!badNodes.empty()) {
     196           2 :         for (auto nodeId : badNodes) {
     197           1 :             LogPrint(BCLog::LLMQ_DKG, "%s -- failed to verify signature, peer=%d\n", __func__, nodeId);
     198           1 :             peerman.PeerMisbehaving(nodeId, 100);
     199             :         }
     200           1 :     }
     201             : 
     202       31741 :     for (const auto& p : preverifiedMessages) {
     203       17961 :         const NodeId& nodeId = p.first;
     204       17961 :         if (badNodes.count(nodeId)) {
     205           1 :             continue;
     206             :         }
     207       17960 :         const std::optional<CInv> inv = session.ReceiveMessage(*p.second);
     208       17960 :         if (inv) {
     209       17960 :             RelayInvToParticipants(session, connman, peerman, *inv);
     210       17960 :         }
     211             :     }
     212             : 
     213       13780 :     return true;
     214      138505 : }
     215             : } // namespace
     216             : 
     217             : 
     218          18 : NetDKG::NetDKG(PeerManagerInternal* peer_manager, const CSporkManager& sporkman, CDKGSessionManager& qdkgsman,
     219             :                const ChainstateManager& chainman, CQuorumManager& qman, QuorumRole& role) :
     220           6 :     NetHandler(peer_manager),
     221           6 :     m_qdkgsman{qdkgsman},
     222           6 :     m_qman{qman},
     223           6 :     m_sporkman{sporkman},
     224           6 :     m_chainman{chainman},
     225           6 :     m_active{nullptr}
     226          12 : {
     227          42 :     m_qdkgsman.InitializeHandlers([](const Consensus::LLMQParams& llmq_params,
     228             :                                      [[maybe_unused]] int quorum_idx) -> std::unique_ptr<CDKGSessionHandler> {
     229          36 :         return std::make_unique<CDKGSessionHandler>(llmq_params);
     230             :     });
     231           6 :     m_qman.ConnectManagers(&role, &m_qdkgsman);
     232          12 : }
     233             : 
     234        1320 : NetDKG::NetDKG(PeerManagerInternal* peer_manager, const CSporkManager& sporkman, CDKGSessionManager& qdkgsman,
     235             :                const ChainstateManager& chainman, bool quorums_watch, CQuorumManager& qman, QuorumRole& role,
     236             :                CBLSWorker& bls_worker, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
     237             :                CDKGDebugManager& dkgdbgman, CQuorumBlockProcessor& qblockman, CQuorumSnapshotManager& qsnapman,
     238             :                const CActiveMasternodeManager& mn_activeman, CConnman& connman) :
     239         660 :     NetHandler(peer_manager),
     240         660 :     m_qdkgsman{qdkgsman},
     241         660 :     m_qman{qman},
     242         660 :     m_sporkman{sporkman},
     243         660 :     m_chainman{chainman},
     244         660 :     m_active{std::make_unique<ActiveDKG>(ActiveDKG{dmnman, mn_metaman, dkgdbgman, qblockman, qsnapman, connman})}
     245        1320 : {
     246        1320 :     m_qdkgsman.InitializeHandlers(
     247        4620 :         [&](const Consensus::LLMQParams& llmq_params, int quorum_idx) -> std::unique_ptr<ActiveDKGSessionHandler> {
     248        7920 :             return std::make_unique<ActiveDKGSessionHandler>(bls_worker, dmnman, mn_metaman, dkgdbgman, qdkgsman,
     249        3960 :                                                              qblockman, qsnapman, mn_activeman, chainman, sporkman,
     250        3960 :                                                              llmq_params, quorums_watch, quorum_idx);
     251             :         });
     252         660 :     m_qman.ConnectManagers(&role, &m_qdkgsman);
     253        1320 : }
     254             : 
     255        1998 : NetDKG::~NetDKG()
     256        1332 : {
     257         666 :     Stop();
     258         666 :     m_qman.DisconnectManagers();
     259        1998 : }
     260             : 
     261       94182 : void NetDKG::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv)
     262             : {
     263       94182 :     if (!IsQuorumDKGEnabled(m_sporkman)) return;
     264             : 
     265      163014 :     if (msg_type != NetMsgType::QCONTRIB && msg_type != NetMsgType::QCOMPLAINT && msg_type != NetMsgType::QJUSTIFICATION &&
     266       80489 :         msg_type != NetMsgType::QPCOMMITMENT && msg_type != NetMsgType::QWATCH) {
     267       74927 :         return;
     268             :     }
     269             : 
     270       13130 :     const bool is_masternode = m_active != nullptr;
     271             : 
     272       13130 :     if (msg_type == NetMsgType::QWATCH) {
     273          30 :         if (!is_masternode) {
     274             :             // non-masternodes should never receive this
     275           9 :             m_peer_manager->PeerMisbehaving(pfrom.GetId(), 10);
     276           9 :             return;
     277             :         }
     278          21 :         pfrom.qwatch = true;
     279          21 :         return;
     280             :     }
     281             : 
     282       13100 :     if (vRecv.empty()) {
     283           0 :         m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
     284           0 :         return;
     285             :     }
     286             : 
     287             :     Consensus::LLMQType llmqType;
     288       13100 :     uint256 quorumHash;
     289       13100 :     vRecv >> llmqType;
     290       13100 :     vRecv >> quorumHash;
     291       13100 :     vRecv.Rewind(sizeof(uint256));
     292       13100 :     vRecv.Rewind(sizeof(uint8_t));
     293             : 
     294       13100 :     const auto& llmq_params_opt = Params().GetLLMQ(llmqType);
     295       13100 :     if (!llmq_params_opt.has_value()) {
     296           0 :         LogPrintf("NetDKG -- invalid llmqType [%d]\n", std23::to_underlying(llmqType));
     297           0 :         m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
     298           0 :         return;
     299             :     }
     300       13100 :     const auto& llmq_params = llmq_params_opt.value();
     301             : 
     302       13100 :     int quorumIndex{-1};
     303             :     {
     304       13100 :         LOCK(cs_indexed_quorums_cache);
     305       13100 :         if (indexed_quorums_cache.empty()) {
     306         394 :             utils::InitQuorumsCache(indexed_quorums_cache, m_chainman.GetConsensus());
     307         394 :         }
     308       13100 :         indexed_quorums_cache[llmqType].get(quorumHash, quorumIndex);
     309       13100 :     }
     310             : 
     311       13100 :     if (quorumIndex == -1) {
     312        4822 :         const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(::cs_main,
     313             :                                                              return m_chainman.m_blockman.LookupBlockIndex(quorumHash));
     314        2411 :         if (pQuorumBaseBlockIndex == nullptr) {
     315           0 :             LogPrintf("NetDKG -- unknown quorumHash %s\n", quorumHash.ToString());
     316             :             // NOTE: do not insta-ban for this, we might be lagging behind
     317           0 :             m_peer_manager->PeerMisbehaving(pfrom.GetId(), 10);
     318           0 :             return;
     319             :         }
     320        2411 :         if (!m_chainman.IsQuorumTypeEnabled(llmqType, pQuorumBaseBlockIndex->pprev)) {
     321           0 :             LogPrintf("NetDKG -- llmqType [%d] quorums aren't active\n", std23::to_underlying(llmqType));
     322           0 :             m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
     323           0 :             return;
     324             :         }
     325        2411 :         quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval;
     326        2411 :         const int quorumIndexMax = IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex)
     327        1182 :                                        ? llmq_params.signingActiveQuorumCount - 1
     328             :                                        : 0;
     329        2411 :         if (quorumIndex > quorumIndexMax) {
     330           0 :             LogPrintf("NetDKG -- invalid quorumHash %s\n", quorumHash.ToString());
     331           0 :             m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
     332           0 :             return;
     333             :         }
     334        2411 :     }
     335             : 
     336       13100 :     int inv_type = 0;
     337       13100 :     if (msg_type == NetMsgType::QCONTRIB)
     338        6502 :         inv_type = MSG_QUORUM_CONTRIB;
     339        6598 :     else if (msg_type == NetMsgType::QCOMPLAINT)
     340        1050 :         inv_type = MSG_QUORUM_COMPLAINT;
     341        5548 :     else if (msg_type == NetMsgType::QJUSTIFICATION)
     342          16 :         inv_type = MSG_QUORUM_JUSTIFICATION;
     343        5532 :     else if (msg_type == NetMsgType::QPCOMMITMENT)
     344        5532 :         inv_type = MSG_QUORUM_PREMATURE_COMMITMENT;
     345       13100 :     Assume(inv_type != 0); // guarded by the early-return above
     346             : 
     347       13100 :     auto pm = std::make_shared<CDataStream>(std::move(vRecv));
     348       13100 :     CHashWriter hw(SER_GETHASH, 0);
     349       13100 :     hw.write(AsWritableBytes(Span{*pm}));
     350       13100 :     const uint256 hash = hw.GetHash();
     351             : 
     352       13100 :     const NodeId from = pfrom.GetId();
     353       26200 :     const bool dispatched = m_qdkgsman.DoForHandler({llmqType, quorumIndex}, [&](CDKGSessionHandler& handler) {
     354       13100 :         CDKGPendingMessages* pending = nullptr;
     355       13100 :         switch (inv_type) {
     356             :         case MSG_QUORUM_CONTRIB:
     357        6502 :             pending = &handler.pendingContributions;
     358        6502 :             break;
     359             :         case MSG_QUORUM_COMPLAINT:
     360        1050 :             pending = &handler.pendingComplaints;
     361        1050 :             break;
     362             :         case MSG_QUORUM_JUSTIFICATION:
     363          16 :             pending = &handler.pendingJustifications;
     364          16 :             break;
     365             :         case MSG_QUORUM_PREMATURE_COMMITMENT:
     366        5532 :             pending = &handler.pendingPrematureCommitments;
     367        5532 :             break;
     368             :         }
     369       13100 :         Assume(pending != nullptr);
     370       26200 :         WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(from, CInv{static_cast<uint32_t>(inv_type), hash}));
     371       13100 :         pending->PushPendingMessage(from, std::move(pm), hash);
     372       13100 :     });
     373       13100 :     if (!dispatched) {
     374           0 :         LogPrintf("NetDKG -- no session handlers for quorumIndex [%d]\n", quorumIndex);
     375           0 :         m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
     376           0 :         return;
     377             :     }
     378             : 
     379       26200 :     WITH_LOCK(cs_indexed_quorums_cache, indexed_quorums_cache[llmqType].insert(quorumHash, quorumIndex));
     380       94182 : }
     381             : 
     382       43738 : bool NetDKG::AlreadyHave(const CInv& inv)
     383             : {
     384       43738 :     switch (inv.type) {
     385             :     case MSG_QUORUM_CONTRIB:
     386             :     case MSG_QUORUM_COMPLAINT:
     387             :     case MSG_QUORUM_JUSTIFICATION:
     388             :     case MSG_QUORUM_PREMATURE_COMMITMENT: {
     389       40714 :         if (!IsQuorumDKGEnabled(m_sporkman)) return false;
     390       40707 :         bool seen = false;
     391      284949 :         m_qdkgsman.ForEachHandler([&](CDKGSessionHandler& h) {
     392      244242 :             if (seen) return;
     393      404236 :             if (h.pendingContributions.HasSeen(inv.hash) || h.pendingComplaints.HasSeen(inv.hash) ||
     394      199218 :                 h.pendingJustifications.HasSeen(inv.hash) || h.pendingPrematureCommitments.HasSeen(inv.hash)) {
     395       10367 :                 seen = true;
     396       10367 :             }
     397      244242 :         });
     398       40707 :         return seen;
     399             :     }
     400             :     }
     401        3024 :     return false;
     402       43738 : }
     403             : 
     404       13953 : bool NetDKG::ProcessGetData(CNode& pfrom, const CInv& inv, CConnman& connman, const CNetMsgMaker& msgMaker)
     405             : {
     406             :     // Default implementations of GetContribution and the other virtual methods
     407             :     // return false in observer mode; m_active is only an early exit and does
     408             :     // not affect logic.
     409       13953 :     if (m_active == nullptr) return false;
     410             : 
     411       13953 :     switch (inv.type) {
     412             :     case MSG_QUORUM_CONTRIB: {
     413        6792 :         CDKGContribution o;
     414        6792 :         if (m_qdkgsman.GetContribution(inv.hash, o)) {
     415        6518 :             connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QCONTRIB, o));
     416        6518 :             return true;
     417             :         }
     418         274 :         return false;
     419        6792 :     }
     420             :     case MSG_QUORUM_COMPLAINT: {
     421        1214 :         CDKGComplaint o;
     422        1214 :         if (m_qdkgsman.GetComplaint(inv.hash, o)) {
     423        1057 :             connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QCOMPLAINT, o));
     424        1057 :             return true;
     425             :         }
     426         157 :         return false;
     427        1214 :     }
     428             :     case MSG_QUORUM_JUSTIFICATION: {
     429          16 :         CDKGJustification o;
     430          16 :         if (m_qdkgsman.GetJustification(inv.hash, o)) {
     431          16 :             connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QJUSTIFICATION, o));
     432          16 :             return true;
     433             :         }
     434           0 :         return false;
     435          16 :     }
     436             :     case MSG_QUORUM_PREMATURE_COMMITMENT: {
     437        5579 :         CDKGPrematureCommitment o;
     438        5579 :         if (m_qdkgsman.GetPrematureCommitment(inv.hash, o)) {
     439        5548 :             connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QPCOMMITMENT, o));
     440        5548 :             return true;
     441             :         }
     442          31 :         return false;
     443        5579 :     }
     444             :     }
     445         352 :     return false;
     446       13953 : }
     447             : 
     448         666 : void NetDKG::Start()
     449             : {
     450         666 :     if (m_active == nullptr) return;
     451         660 :     if (!m_phase_threads.empty()) {
     452           0 :         throw std::runtime_error("Tried to start PhaseHandlerThreads again.");
     453             :     }
     454             : 
     455        4620 :     m_qdkgsman.ForEachHandler([this](CDKGSessionHandler& base) {
     456        3960 :         auto& handler = dynamic_cast<ActiveDKGSessionHandler&>(base);
     457        3960 :         std::string thread_name = strprintf("llmq-%d-%d", std23::to_underlying(handler.params.type), handler.QuorumIndex());
     458        7915 :         m_phase_threads.emplace_back([this, name = std::move(thread_name), &handler] {
     459        7915 :             util::TraceThread(name.c_str(), [this, &handler] { PhaseHandlerThread(handler); });
     460        3955 :         });
     461        3960 :     });
     462         666 : }
     463             : 
     464        1998 : void NetDKG::Stop()
     465             : {
     466        1998 :     Interrupt();
     467        5958 :     for (auto& t : m_phase_threads) {
     468        3960 :         if (t.joinable()) t.join();
     469             :     }
     470        1998 :     m_phase_threads.clear();
     471        1998 : }
     472             : 
     473        3330 : void NetDKG::Interrupt()
     474             : {
     475        3330 :     if (m_active == nullptr) return;
     476       23100 :     m_qdkgsman.ForEachHandler([](CDKGSessionHandler& base) {
     477       19800 :         if (auto* handler = dynamic_cast<ActiveDKGSessionHandler*>(&base)) {
     478       19800 :             handler->RequestStop();
     479       19800 :         }
     480       19800 :     });
     481        3330 : }
     482             : 
     483        3960 : void NetDKG::PhaseHandlerThread(ActiveDKGSessionHandler& handler)
     484             : {
     485       17599 :     while (!handler.IsStopRequested()) {
     486             :         try {
     487       13637 :             LogPrint(BCLog::LLMQ_DKG, "NetDKG::%s -- %s qi[%d] - starting HandleDKGRound\n", __func__,
     488             :                      handler.params.name, handler.QuorumIndex());
     489       13637 :             HandleDKGRound(handler);
     490       13637 :         } catch (AbortPhaseException& e) {
     491        9885 :             m_active->dkgdbgman.MarkAborted(handler.params.type, handler.QuorumIndex());
     492        9884 :             LogPrint(BCLog::LLMQ_DKG, "NetDKG::%s -- %s qi[%d] - aborted current DKG session\n", __func__,
     493             :                      handler.params.name, handler.QuorumIndex());
     494        9887 :         }
     495             :     }
     496       13851 : }
     497             : 
     498        3004 : static void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman,
     499             :                                       CMasternodeMetaMan& mn_metaman, const CSporkManager& sporkman,
     500             :                                       const UtilParameters& util_params, const CDeterministicMNList& tip_mn_list,
     501             :                                       const uint256& myProTxHash)
     502             : {
     503        3004 :     assert(mn_metaman.IsValid());
     504             : 
     505        3004 :     if (!IsQuorumPoseEnabled(llmqParams.type, sporkman)) {
     506        2602 :         return;
     507             :     }
     508             : 
     509         402 :     auto members = utils::GetAllQuorumMembers(llmqParams.type, util_params);
     510         402 :     auto curTime = GetTime<std::chrono::seconds>().count();
     511             : 
     512         402 :     Uint256HashSet probeConnections;
     513        2070 :     for (const auto& dmn : members) {
     514        1668 :         if (dmn->proTxHash == myProTxHash) {
     515         402 :             continue;
     516             :         }
     517        1266 :         auto lastOutbound = mn_metaman.GetLastOutboundSuccess(dmn->proTxHash);
     518        1266 :         if (curTime - lastOutbound < 10 * 60) {
     519             :             // avoid re-probing nodes too often
     520         238 :             continue;
     521             :         }
     522        1028 :         probeConnections.emplace(dmn->proTxHash);
     523             :     }
     524             : 
     525         402 :     if (!probeConnections.empty()) {
     526         347 :         if (LogAcceptDebug(BCLog::LLMQ)) {
     527         347 :             std::string debugMsg = strprintf("%s -- adding masternodes probes for quorum %s:\n", __func__,
     528         347 :                                              util_params.m_base_index->GetBlockHash().ToString());
     529        1375 :             for (const auto& c : probeConnections) {
     530        1028 :                 auto dmn = tip_mn_list.GetValidMN(c);
     531        1028 :                 if (!dmn) {
     532          11 :                     debugMsg += strprintf("  %s (not in valid MN set anymore)\n", c.ToString());
     533          11 :                 } else {
     534        2034 :                     debugMsg += strprintf("  %s (%s)\n", c.ToString(),
     535        1017 :                                           dmn->pdmnState->netInfo->GetPrimary().ToStringAddrPort());
     536             :                 }
     537        1028 :             }
     538         347 :             LogPrint(BCLog::NET_NETCONN, debugMsg.c_str()); /* Continued */
     539         347 :         }
     540         347 :         connman.AddPendingProbeConnections(probeConnections);
     541         347 :     }
     542        3004 : }
     543             : 
     544       13637 : void NetDKG::HandleDKGRound(ActiveDKGSessionHandler& handler)
     545             : {
     546       13637 :     auto& active = *Assert(m_active);
     547             : 
     548       14758 :     handler.WaitForNextPhase(std::nullopt, QuorumPhase::Initialized);
     549             : 
     550       11043 :     handler.ClearPendingMessages();
     551       11043 :     uint256 curQuorumHash = handler.GetCurrentQuorumHash();
     552             : 
     553       22086 :     const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(::cs_main,
     554             :                                                          return m_chainman.m_blockman.LookupBlockIndex(curQuorumHash));
     555             : 
     556       11043 :     if (!pQuorumBaseBlockIndex || !handler.InitNewQuorum(pQuorumBaseBlockIndex)) {
     557             :         // should actually never happen
     558        6170 :         handler.WaitForNewQuorum(curQuorumHash);
     559        6170 :         throw AbortPhaseException();
     560             :     }
     561             : 
     562        4873 :     active.dkgdbgman.MarkPhaseAdvanced(handler.params.type, handler.QuorumIndex(), QuorumPhase::Initialized);
     563             : 
     564        4873 :     auto* curSession = handler.GetCurSession();
     565        4873 :     if (handler.params.is_single_member()) {
     566          64 :         auto finalCommitment = curSession->FinalizeSingleCommitment();
     567          64 :         if (!finalCommitment.IsNull()) { // it can be null only if we are not member
     568          33 :             if (auto inv_opt = active.qblockman.AddMineableCommitment(finalCommitment); inv_opt.has_value()) {
     569          33 :                 m_peer_manager->PeerRelayInv(inv_opt.value());
     570          33 :             }
     571          33 :         }
     572          64 :         handler.WaitForNextPhase(QuorumPhase::Initialized, QuorumPhase::Contribute, curQuorumHash);
     573             :         return;
     574          64 :     }
     575             : 
     576        4809 :     const auto tip_mn_list = active.dmnman.GetListAtChainTip();
     577        9618 :     llmq::EnsureQuorumConnections(handler.params, active.connman, m_sporkman,
     578        4809 :                                   {active.dmnman, active.qsnapman, m_chainman, pQuorumBaseBlockIndex}, tip_mn_list,
     579        4809 :                                   curSession->ProTx(), /*is_masternode=*/true, handler.QuorumsWatch());
     580        4809 :     if (curSession->AreWeMember()) {
     581        6008 :         AddQuorumProbeConnections(handler.params, active.connman, active.mn_metaman, m_sporkman,
     582        3004 :                                   {active.dmnman, active.qsnapman, m_chainman, pQuorumBaseBlockIndex}, tip_mn_list,
     583        3004 :                                   curSession->ProTx());
     584        3004 :     }
     585             : 
     586        4809 :     handler.WaitForNextPhase(QuorumPhase::Initialized, QuorumPhase::Contribute, curQuorumHash);
     587             : 
     588             :     // Contribute
     589        8476 :     auto fContributeStart = [curSession, &handler]() {
     590        6840 :         if (auto qc = curSession->Contribute(); qc) {
     591        2602 :             EnqueueOwn(handler.pendingContributions, *qc);
     592        2602 :         }
     593        4238 :     };
     594       47195 :     auto fContributeWait = [this, curSession, &handler, &active] {
     595       85914 :         return ProcessPendingMessageBatch<CDKGContribution>(active.connman, *curSession, handler.pendingContributions,
     596       42957 :                                                             *m_peer_manager, 8);
     597             :     };
     598        8476 :     handler.HandlePhase(QuorumPhase::Contribute, QuorumPhase::Complain, curQuorumHash, 0.05, fContributeStart,
     599        4238 :                         fContributeWait);
     600             : 
     601             :     // Complain
     602        8078 :     auto fComplainStart = [curSession, &handler, &active]() {
     603        4573 :         if (auto qc = curSession->VerifyAndComplain(active.connman); qc) {
     604         534 :             EnqueueOwn(handler.pendingComplaints, *qc);
     605         534 :         }
     606        4039 :     };
     607       32293 :     auto fComplainWait = [this, curSession, &handler, &active] {
     608       56508 :         return ProcessPendingMessageBatch<CDKGComplaint>(active.connman, *curSession, handler.pendingComplaints,
     609       28254 :                                                          *m_peer_manager, 8);
     610             :     };
     611        4039 :     handler.HandlePhase(QuorumPhase::Complain, QuorumPhase::Justify, curQuorumHash, 0.05, fComplainStart, fComplainWait);
     612             : 
     613             :     // Justify
     614        7876 :     auto fJustifyStart = [curSession, &handler]() {
     615        3946 :         if (auto qj = curSession->VerifyAndJustify(); qj) {
     616           8 :             EnqueueOwn(handler.pendingJustifications, *qj);
     617           8 :         }
     618        3938 :     };
     619       31322 :     auto fJustifyWait = [this, curSession, &handler, &active] {
     620       54768 :         return ProcessPendingMessageBatch<CDKGJustification>(active.connman, *curSession, handler.pendingJustifications,
     621       27384 :                                                              *m_peer_manager, 8);
     622             :     };
     623        3938 :     handler.HandlePhase(QuorumPhase::Justify, QuorumPhase::Commit, curQuorumHash, 0.05, fJustifyStart, fJustifyWait);
     624             : 
     625             :     // Commit
     626        7712 :     auto fCommitStart = [curSession, &handler]() {
     627        5871 :         if (auto qc = curSession->VerifyAndCommit(); qc) {
     628        2015 :             EnqueueOwn(handler.pendingPrematureCommitments, *qc);
     629        2015 :         }
     630        3856 :     };
     631       43747 :     auto fCommitWait = [this, curSession, &handler, &active] {
     632       79782 :         return ProcessPendingMessageBatch<CDKGPrematureCommitment>(active.connman, *curSession,
     633       39891 :                                                                    handler.pendingPrematureCommitments, *m_peer_manager,
     634             :                                                                    8);
     635             :     };
     636        3856 :     handler.HandlePhase(QuorumPhase::Commit, QuorumPhase::Finalize, curQuorumHash, 0.1, fCommitStart, fCommitWait);
     637             : 
     638        3727 :     auto finalCommitments = curSession->FinalizeCommitments();
     639        5578 :     for (const auto& fqc : finalCommitments) {
     640        1851 :         if (auto inv_opt = active.qblockman.AddMineableCommitment(fqc); inv_opt.has_value()) {
     641        1383 :             m_peer_manager->PeerRelayInv(inv_opt.value());
     642        1383 :         }
     643             :     }
     644        7978 : }
     645             : 
     646        2603 : void NetDKGStub::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv)
     647             : {
     648        5206 :     if (msg_type == NetMsgType::QCONTRIB || msg_type == NetMsgType::QCOMPLAINT || msg_type == NetMsgType::QJUSTIFICATION ||
     649        2603 :         msg_type == NetMsgType::QPCOMMITMENT || msg_type == NetMsgType::QWATCH) {
     650           9 :         m_peer_manager->PeerMisbehaving(pfrom.GetId(), 10);
     651           9 :     }
     652        2603 : }
     653             : 
     654             : } // namespace llmq

Generated by: LCOV version 1.16