LCOV - code coverage report
Current view: top level - src/llmq - quorums_signing_shares.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 372 883 42.1 %
Date: 2025-04-02 01:23:23 Functions: 32 64 50.0 %

          Line data    Source code
       1             : // Copyright (c) 2018 The Dash Core developers
       2             : // Copyright (c) 2023 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : #include "quorums_signing.h"
       7             : 
       8             : #include "activemasternode.h"
       9             : #include "bls/bls_batchverifier.h"
      10             : #include "cxxtimer.h"
      11             : #include "init.h"
      12             : #include "net.h"
      13             : #include "net_processing.h"
      14             : #include "netmessagemaker.h"
      15             : #include "quorums_signing_shares.h"
      16             : #include "quorums_utils.h"
      17             : #include "random.h"
      18             : #include "shutdown.h"
      19             : #include "tiertwo/masternode_meta_manager.h" // for g_mmetaman
      20             : #include "tiertwo/net_masternodes.h"
      21             : #include "validation.h"
      22             : 
      23             : namespace llmq
      24             : {
      25             : 
      26             : std::unique_ptr<CSigSharesManager> quorumSigSharesManager{nullptr};
      27             : 
      28        1840 : void CSigShare::UpdateKey()
      29             : {
      30        1840 :     key.first = llmq::utils::BuildSignHash(*this);
      31        1840 :     key.second = quorumMember;
      32        1840 : }
      33             : 
      34           0 : std::string CSigSesAnn::ToString() const
      35             : {
      36           0 :     return strprintf("sessionId=%d, llmqType=%d, quorumHash=%s, id=%s, msgHash=%s",
      37           0 :         sessionId, llmqType, quorumHash.ToString(), id.ToString(), msgHash.ToString());
      38             : }
      39             : 
      40           0 : void CSigSharesInv::Merge(const CSigSharesInv& inv2)
      41             : {
      42           0 :     for (size_t i = 0; i < inv.size(); i++) {
      43           0 :         if (inv2.inv[i]) {
      44           0 :             inv[i] = inv2.inv[i];
      45             :         }
      46             :     }
      47           0 : }
      48             : 
      49           0 : size_t CSigSharesInv::CountSet() const
      50             : {
      51           0 :     return (size_t)std::count(inv.begin(), inv.end(), true);
      52             : }
      53             : 
      54           0 : std::string CSigSharesInv::ToString() const
      55             : {
      56           0 :     std::string str = "(";
      57           0 :     bool first = true;
      58           0 :     for (size_t i = 0; i < inv.size(); i++) {
      59           0 :         if (!inv[i]) {
      60           0 :             continue;
      61             :         }
      62             : 
      63           0 :         if (!first) {
      64           0 :             str += ",";
      65             :         }
      66           0 :         first = false;
      67           0 :         str += strprintf("%d", i);
      68             :     }
      69           0 :     str += ")";
      70           0 :     return str;
      71             : }
      72             : 
      73           0 : void CSigSharesInv::Init(size_t size)
      74             : {
      75           0 :     inv.resize(size, false);
      76           0 : }
      77             : 
      78           0 : bool CSigSharesInv::IsSet(uint16_t quorumMember) const
      79             : {
      80           0 :     assert(quorumMember < inv.size());
      81           0 :     return inv[quorumMember];
      82             : }
      83             : 
      84           0 : void CSigSharesInv::Set(uint16_t quorumMember, bool v)
      85             : {
      86           0 :     assert(quorumMember < inv.size());
      87           0 :     inv[quorumMember] = v;
      88           0 : }
      89             : 
      90           0 : void CSigSharesInv::SetAll(bool v)
      91             : {
      92           0 :     for (size_t i = 0; i < inv.size(); i++) {
      93           0 :         inv[i] = v;
      94             :     }
      95           0 : }
      96             : 
      97           0 : std::string CBatchedSigShares::ToInvString() const
      98             : {
      99           0 :     CSigSharesInv inv;
     100             :     // we use 400 here no matter what the real size is. We don't really care about that size as we just want to call ToString()
     101           0 :     inv.Init(400);
     102           0 :     for (size_t i = 0; i < sigShares.size(); i++) {
     103           0 :         inv.inv[sigShares[i].first] = true;
     104             :     }
     105           0 :     return inv.ToString();
     106             : }
     107             : 
     108             : template <typename T>
     109           0 : static void InitSession(CSigSharesNodeState::Session& s, const uint256& signHash, T& from)
     110             : {
     111           0 :     const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)from.llmqType);
     112             : 
     113           0 :     s.llmqType = (Consensus::LLMQType)from.llmqType;
     114           0 :     s.quorumHash = from.quorumHash;
     115           0 :     s.id = from.id;
     116           0 :     s.msgHash = from.msgHash;
     117           0 :     s.signHash = signHash;
     118           0 :     s.announced.Init((size_t)params.size);
     119           0 :     s.requested.Init((size_t)params.size);
     120           0 :     s.knows.Init((size_t)params.size);
     121           0 : }
     122             : 
     123           0 : CSigSharesNodeState::Session& CSigSharesNodeState::GetOrCreateSessionFromShare(const llmq::CSigShare& sigShare)
     124             : {
     125           0 :     auto& s = sessions[sigShare.GetSignHash()];
     126           0 :     if (s.announced.inv.empty()) {
     127           0 :         InitSession(s, sigShare.GetSignHash(), sigShare);
     128             :     }
     129           0 :     return s;
     130             : }
     131             : 
     132           0 : CSigSharesNodeState::Session& CSigSharesNodeState::GetOrCreateSessionFromAnn(const llmq::CSigSesAnn& ann)
     133             : {
     134           0 :     auto signHash = llmq::utils::BuildSignHash((Consensus::LLMQType)ann.llmqType, ann.quorumHash, ann.id, ann.msgHash);
     135           0 :     auto& s = sessions[signHash];
     136           0 :     if (s.announced.inv.empty()) {
     137           0 :         InitSession(s, signHash, ann);
     138             :     }
     139           0 :     return s;
     140             : }
     141             : 
     142           0 : CSigSharesNodeState::Session* CSigSharesNodeState::GetSessionBySignHash(const uint256& signHash)
     143             : {
     144           0 :     auto it = sessions.find(signHash);
     145           0 :     if (it == sessions.end()) {
     146             :         return nullptr;
     147             :     }
     148           0 :     return &it->second;
     149             : }
     150             : 
     151           0 : CSigSharesNodeState::Session* CSigSharesNodeState::GetSessionByRecvId(uint32_t sessionId)
     152             : {
     153           0 :     auto it = sessionByRecvId.find(sessionId);
     154           0 :     if (it == sessionByRecvId.end()) {
     155             :         return nullptr;
     156             :     }
     157           0 :     return it->second;
     158             : }
     159             : 
     160           0 : bool CSigSharesNodeState::GetSessionInfoByRecvId(uint32_t sessionId, SessionInfo& retInfo)
     161             : {
     162           0 :     auto s = GetSessionByRecvId(sessionId);
     163           0 :     if (!s) {
     164             :         return false;
     165             :     }
     166           0 :     retInfo.llmqType = s->llmqType;
     167           0 :     retInfo.quorumHash = s->quorumHash;
     168           0 :     retInfo.id = s->id;
     169           0 :     retInfo.msgHash = s->msgHash;
     170           0 :     retInfo.signHash = s->signHash;
     171           0 :     retInfo.quorum = s->quorum;
     172             : 
     173           0 :     return true;
     174             : }
     175             : 
     176        4611 : void CSigSharesNodeState::RemoveSession(const uint256& signHash)
     177             : {
     178        4611 :     auto it = sessions.find(signHash);
     179        4611 :     if (it != sessions.end()) {
     180           0 :         sessionByRecvId.erase(it->second.recvSessionId);
     181           0 :         sessions.erase(it);
     182             :     }
     183        4611 :     requestedSigShares.EraseAllForSignHash(signHash);
     184        4611 :     pendingIncomingSigShares.EraseAllForSignHash(signHash);
     185        4611 : }
     186             : 
     187             : //////////////////////
     188             : 
     189         475 : CSigSharesManager::CSigSharesManager()
     190             : {
     191         475 :     interruptSigningShare.reset();
     192         475 : }
     193             : 
     194         950 : CSigSharesManager::~CSigSharesManager()
     195             : {
     196         950 : }
     197             : 
     198         347 : void CSigSharesManager::StartWorkerThread()
     199             : {
     200         347 :     workThread = std::thread(&TraceThread<std::function<void()>>, "quorum-sigshares", std::function<void()>(std::bind(&CSigSharesManager::WorkThreadMain, this)));
     201         347 : }
     202             : 
     203         357 : void CSigSharesManager::StopWorkerThread()
     204             : {
     205         357 :     if (workThread.joinable()) {
     206         347 :         workThread.join();
     207             :     }
     208         357 : }
     209             : 
     210         347 : void CSigSharesManager::RegisterAsRecoveredSigsListener()
     211             : {
     212         347 :     quorumSigningManager->RegisterRecoveredSigsListener(this);
     213         347 : }
     214             : 
     215         357 : void CSigSharesManager::UnregisterAsRecoveredSigsListener()
     216             : {
     217         357 :     quorumSigningManager->UnregisterRecoveredSigsListener(this);
     218         357 : }
     219             : 
     220         475 : void CSigSharesManager::Interrupt()
     221             : {
     222         475 :     interruptSigningShare();
     223         475 : }
     224             : 
     225         662 : void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
     226             : {
     227             :     // non-masternodes are not interested in sigshares
     228         662 :     if (!activeMasternodeManager) {
     229             :         return;
     230             :     }
     231             : 
     232         662 :     if (strCommand == NetMsgType::QSIGSHARE) {
     233        1324 :         std::vector<CSigShare> sigShares;
     234         662 :         vRecv >> sigShares;
     235             : 
     236         662 :         if (sigShares.size() > MAX_MSGS_SIG_SHARES) {
     237           0 :             LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- too many sigs in QSIGSHARE message. cnt=%d, max=%d, node=%d\n", __func__, sigShares.size(), MAX_MSGS_SIG_SHARES, pfrom->GetId());
     238           0 :             BanNode(pfrom->GetId());
     239           0 :             return;
     240             :         }
     241             : 
     242        1534 :         for (auto& sigShare : sigShares) {
     243         872 :             ProcessMessageSigShare(pfrom->GetId(), sigShare, connman);
     244             :         }
     245             :     }
     246             : 
     247         662 :     if (strCommand == NetMsgType::QSIGSESANN) {
     248           0 :         std::vector<CSigSesAnn> msgs;
     249           0 :         vRecv >> msgs;
     250           0 :         if (msgs.size() > MAX_MSGS_CNT_QSIGSESANN) {
     251           0 :             LogPrintf("CSigSharesManager::%s -- too many announcements in QSIGSESANN message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSESANN, pfrom->GetId());
     252           0 :             BanNode(pfrom->GetId());
     253           0 :             return;
     254             :         }
     255           0 :         for (auto& ann : msgs) {
     256           0 :             if (!ProcessMessageSigSesAnn(pfrom, ann, connman)) {
     257           0 :                 BanNode(pfrom->GetId());
     258           0 :                 return;
     259             :             }
     260             :         }
     261         662 :     } else if (strCommand == NetMsgType::QSIGSHARESINV) {
     262           0 :         std::vector<CSigSharesInv> msgs;
     263           0 :         vRecv >> msgs;
     264           0 :         if (msgs.size() > MAX_MSGS_CNT_QSIGSHARESINV) {
     265           0 :             LogPrintf("CSigSharesManager::%s -- too many invs in QSIGSHARESINV message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSHARESINV, pfrom->GetId());
     266           0 :             BanNode(pfrom->GetId());
     267           0 :             return;
     268             :         }
     269           0 :         for (auto& inv : msgs) {
     270           0 :             if (!ProcessMessageSigSharesInv(pfrom, inv, connman)) {
     271           0 :                 BanNode(pfrom->GetId());
     272           0 :                 return;
     273             :             }
     274             :         }
     275         662 :     } else if (strCommand == NetMsgType::QGETSIGSHARES) {
     276           0 :         std::vector<CSigSharesInv> msgs;
     277           0 :         vRecv >> msgs;
     278           0 :         if (msgs.size() > MAX_MSGS_CNT_QGETSIGSHARES) {
     279           0 :             LogPrintf("CSigSharesManager::%s -- too many invs in QGETSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QGETSIGSHARES, pfrom->GetId());
     280           0 :             BanNode(pfrom->GetId());
     281           0 :             return;
     282             :         }
     283           0 :         for (auto& inv : msgs) {
     284           0 :             if (!ProcessMessageGetSigShares(pfrom, inv, connman)) {
     285           0 :                 BanNode(pfrom->GetId());
     286           0 :                 return;
     287             :             }
     288             :         }
     289         662 :     } else if (strCommand == NetMsgType::QBSIGSHARES) {
     290           0 :         std::vector<CBatchedSigShares> msgs;
     291           0 :         vRecv >> msgs;
     292           0 :         size_t totalSigsCount = 0;
     293           0 :         for (auto& bs : msgs) {
     294           0 :             totalSigsCount += bs.sigShares.size();
     295             :         }
     296           0 :         if (totalSigsCount > MAX_MSGS_TOTAL_BATCHED_SIGS) {
     297           0 :             LogPrintf("CSigSharesManager::%s -- too many sigs in QBSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_TOTAL_BATCHED_SIGS, pfrom->GetId());
     298           0 :             BanNode(pfrom->GetId());
     299           0 :             return;
     300             :         }
     301           0 :         for (auto& bs : msgs) {
     302           0 :             if (!ProcessMessageBatchedSigShares(pfrom, bs, connman)) {
     303           0 :                 BanNode(pfrom->GetId());
     304           0 :                 return;
     305             :             }
     306             :         }
     307             :     }
     308             : }
     309             : 
     310           0 : bool CSigSharesManager::ProcessMessageSigSesAnn(CNode* pfrom, const CSigSesAnn& ann, CConnman& connman)
     311             : {
     312           0 :     auto llmqType = (Consensus::LLMQType)ann.llmqType;
     313           0 :     if (!Params().GetConsensus().llmqs.count(llmqType)) {
     314           0 :         return false;
     315             :     }
     316           0 :     if (ann.sessionId == (uint32_t)-1 || ann.quorumHash.IsNull() || ann.id.IsNull() || ann.msgHash.IsNull()) {
     317             :         return false;
     318             :     }
     319             : 
     320           0 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- ann={%s}, node=%d\n", __func__, ann.ToString(), pfrom->GetId());
     321             : 
     322           0 :     auto quorum = quorumManager->GetQuorum(llmqType, ann.quorumHash);
     323           0 :     if (!quorum) {
     324             :         // TODO should we ban here?
     325           0 :         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorum %s not found, node=%d\n", __func__,
     326             :             ann.quorumHash.ToString(), pfrom->GetId());
     327           0 :         return true; // let's still try other announcements from the same message
     328             :     }
     329             : 
     330           0 :     auto signHash = llmq::utils::BuildSignHash(llmqType, ann.quorumHash, ann.id, ann.msgHash);
     331             : 
     332           0 :     LOCK(cs);
     333           0 :     auto& nodeState = nodeStates[pfrom->GetId()];
     334           0 :     auto& session = nodeState.GetOrCreateSessionFromAnn(ann);
     335           0 :     nodeState.sessionByRecvId.erase(session.recvSessionId);
     336           0 :     nodeState.sessionByRecvId.erase(ann.sessionId);
     337           0 :     session.recvSessionId = ann.sessionId;
     338           0 :     session.quorum = quorum;
     339           0 :     nodeState.sessionByRecvId.emplace(ann.sessionId, &session);
     340             : 
     341           0 :     return true;
     342             : }
     343             : 
     344           0 : bool CSigSharesManager::VerifySigSharesInv(NodeId from, Consensus::LLMQType llmqType, const CSigSharesInv& inv)
     345             : {
     346           0 :     size_t quorumSize = (size_t)Params().GetConsensus().llmqs.at(llmqType).size;
     347             : 
     348           0 :     if (inv.inv.size() != quorumSize) {
     349           0 :         return false;
     350             :     }
     351             :     return true;
     352             : }
     353             : 
     354           0 : bool CSigSharesManager::ProcessMessageSigSharesInv(CNode* pfrom, const CSigSharesInv& inv, CConnman& connman)
     355             : {
     356           0 :     CSigSharesNodeState::SessionInfo sessionInfo;
     357           0 :     if (!GetSessionInfoByRecvId(pfrom->GetId(), inv.sessionId, sessionInfo)) {
     358             :         return true;
     359             :     }
     360             : 
     361           0 :     if (!VerifySigSharesInv(pfrom->GetId(), sessionInfo.llmqType, inv)) {
     362             :         return false;
     363             :     }
     364             : 
     365             :     // TODO for PoSe, we should consider propagating shares even if we already have a recovered sig
     366           0 :     if (quorumSigningManager->HasRecoveredSigForSession(sessionInfo.signHash)) {
     367             :         return true;
     368             :     }
     369             : 
     370           0 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__,
     371             :         sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId());
     372             : 
     373           0 :     if (sessionInfo.quorum->quorumVvec == nullptr) {
     374             :         // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
     375           0 :         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, not requesting sig shares. node=%d\n", __func__,
     376             :             sessionInfo.quorumHash.ToString(), pfrom->GetId());
     377           0 :         return true;
     378             :     }
     379             : 
     380           0 :     LOCK(cs);
     381           0 :     auto& nodeState = nodeStates[pfrom->GetId()];
     382           0 :     auto session = nodeState.GetSessionByRecvId(inv.sessionId);
     383           0 :     if (!session) {
     384             :         return true;
     385             :     }
     386           0 :     session->announced.Merge(inv);
     387           0 :     session->knows.Merge(inv);
     388           0 :     return true;
     389             : }
     390             : 
     391           0 : bool CSigSharesManager::ProcessMessageGetSigShares(CNode* pfrom, const CSigSharesInv& inv, CConnman& connman)
     392             : {
     393           0 :     CSigSharesNodeState::SessionInfo sessionInfo;
     394           0 :     if (!GetSessionInfoByRecvId(pfrom->GetId(), inv.sessionId, sessionInfo)) {
     395             :         return true;
     396             :     }
     397             : 
     398           0 :     if (!VerifySigSharesInv(pfrom->GetId(), sessionInfo.llmqType, inv)) {
     399             :         return false;
     400             :     }
     401             : 
     402             :     // TODO for PoSe, we should consider propagating shares even if we already have a recovered sig
     403           0 :     if (quorumSigningManager->HasRecoveredSigForSession(sessionInfo.signHash)) {
     404             :         return true;
     405             :     }
     406             : 
     407           0 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__,
     408             :         sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId());
     409             : 
     410           0 :     LOCK(cs);
     411           0 :     auto& nodeState = nodeStates[pfrom->GetId()];
     412           0 :     auto session = nodeState.GetSessionByRecvId(inv.sessionId);
     413           0 :     if (!session) {
     414             :         return true;
     415             :     }
     416           0 :     session->requested.Merge(inv);
     417           0 :     session->knows.Merge(inv);
     418           0 :     return true;
     419             : }
     420             : 
     421           0 : bool CSigSharesManager::ProcessMessageBatchedSigShares(CNode* pfrom, const CBatchedSigShares& batchedSigShares, CConnman& connman)
     422             : {
     423           0 :     CSigSharesNodeState::SessionInfo sessionInfo;
     424           0 :     if (!GetSessionInfoByRecvId(pfrom->GetId(), batchedSigShares.sessionId, sessionInfo)) {
     425             :         return true;
     426             :     }
     427             : 
     428           0 :     bool ban = false;
     429           0 :     if (!PreVerifyBatchedSigShares(pfrom->GetId(), sessionInfo, batchedSigShares, ban)) {
     430           0 :         return !ban;
     431             :     }
     432             : 
     433           0 :     std::vector<CSigShare> sigShares;
     434           0 :     sigShares.reserve(batchedSigShares.sigShares.size());
     435             : 
     436           0 :     {
     437           0 :         LOCK(cs);
     438           0 :         auto& nodeState = nodeStates[pfrom->GetId()];
     439             : 
     440           0 :         for (size_t i = 0; i < batchedSigShares.sigShares.size(); i++) {
     441           0 :             CSigShare sigShare = RebuildSigShare(sessionInfo, batchedSigShares, i);
     442           0 :             nodeState.requestedSigShares.Erase(sigShare.GetKey());
     443             : 
     444             :             // TODO track invalid sig shares received for PoSe?
     445             :             // It's important to only skip seen *valid* sig shares here. If a node sends us a
     446             :             // batch of mostly valid sig shares with a single invalid one and thus batched
     447             :             // verification fails, we'd skip the valid ones in the future if received from other nodes
     448           0 :             if (this->sigShares.Has(sigShare.GetKey())) {
     449           0 :                 continue;
     450             :             }
     451             : 
     452             :             // TODO for PoSe, we should consider propagating shares even if we already have a recovered sig
     453           0 :             if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) {
     454           0 :                 continue;
     455             :             }
     456             : 
     457           0 :             sigShares.emplace_back(sigShare);
     458             :         }
     459             :     }
     460             : 
     461           0 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, shares=%d, new=%d, inv={%s}, node=%d\n", __func__,
     462             :         sessionInfo.signHash.ToString(), batchedSigShares.sigShares.size(), sigShares.size(), batchedSigShares.ToInvString(), pfrom->GetId());
     463             : 
     464           0 :     if (sigShares.empty()) {
     465             :         return true;
     466             :     }
     467             : 
     468           0 :     LOCK(cs);
     469           0 :     auto& nodeState = nodeStates[pfrom->GetId()];
     470           0 :     for (auto& s : sigShares) {
     471           0 :         nodeState.pendingIncomingSigShares.Add(s.GetKey(), s);
     472             :     }
     473           0 :     return true;
     474             : }
     475             : 
     476         872 : void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare, CConnman& connman)
     477             : {
     478        1484 :     auto quorum = quorumManager->GetQuorum((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash);
     479         872 :     if (!quorum) {
     480         260 :         return;
     481             :     }
     482         872 :     if (!llmq::utils::IsQuorumActive((Consensus::LLMQType)sigShare.llmqType, quorum->qc.quorumHash)) {
     483             :         // quorum is too old
     484             :         return;
     485             :     }
     486         872 :     if (!quorum->IsMember(activeMasternodeManager->GetProTx())) {
     487             :         // we're not a member so we can't verify it (we actually shouldn't have received it)
     488             :         return;
     489             :     }
     490         872 :     if (quorum->quorumVvec == nullptr) {
     491             :         // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
     492           0 :         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__,
     493             :             quorum->qc.quorumHash.ToString(), fromId);
     494           0 :         return;
     495             :     }
     496             : 
     497         872 :     if (sigShare.quorumMember >= quorum->members.size()) {
     498           0 :         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember out of bounds\n", __func__);
     499           0 :         BanNode(fromId);
     500             :         return;
     501             :     }
     502         872 :     if (!quorum->qc.validMembers[sigShare.quorumMember]) {
     503           0 :         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember not valid\n", __func__);
     504           0 :         BanNode(fromId);
     505             :         return;
     506             :     }
     507             : 
     508         872 :     {
     509         872 :         LOCK(cs);
     510             : 
     511         872 :         if (sigShares.Has(sigShare.GetKey())) {
     512         260 :             return;
     513             :         }
     514             : 
     515         872 :         if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) {
     516             :             return;
     517             :         }
     518             : 
     519         612 :         auto& nodeState = nodeStates[fromId];
     520         612 :         nodeState.pendingIncomingSigShares.Add(sigShare.GetKey(), sigShare);
     521             :     }
     522             : 
     523        2448 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, id=%s, msgHash=%s, member=%d, node=%d\n", __func__,
     524             :         sigShare.GetSignHash().ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), sigShare.quorumMember, fromId);
     525             : }
     526             : 
     527           0 : bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares, bool& retBan)
     528             : {
     529           0 :     retBan = false;
     530             : 
     531           0 :     if (!llmq::utils::IsQuorumActive(session.llmqType, session.quorum->qc.quorumHash)) {
     532             :         // quorum is too old
     533             :         return false;
     534             :     }
     535           0 :     if (!session.quorum->IsMember(activeMasternodeManager->GetProTx())) {
     536             :         // we're not a member so we can't verify it (we actually shouldn't have received it)
     537             :         return false;
     538             :     }
     539           0 :     if (session.quorum->quorumVvec == nullptr) {
     540             :         // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
     541           0 :         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__,
     542             :             session.quorumHash.ToString(), nodeId);
     543           0 :         return false;
     544             :     }
     545             : 
     546           0 :     std::unordered_set<uint16_t> dupMembers;
     547             : 
     548           0 :     for (size_t i = 0; i < batchedSigShares.sigShares.size(); i++) {
     549           0 :         auto quorumMember = batchedSigShares.sigShares[i].first;
     550           0 :         if (!dupMembers.emplace(quorumMember).second) {
     551           0 :             retBan = true;
     552           0 :             return false;
     553             :         }
     554             : 
     555           0 :         if (quorumMember >= session.quorum->members.size()) {
     556           0 :             LogPrintf("CSigSharesManager::%s -- quorumMember out of bounds\n", __func__);
     557           0 :             retBan = true;
     558           0 :             return false;
     559             :         }
     560           0 :         if (!session.quorum->qc.validMembers[quorumMember]) {
     561           0 :             LogPrintf("CSigSharesManager::%s -- quorumMember not valid\n", __func__);
     562           0 :             retBan = true;
     563           0 :             return false;
     564             :         }
     565             :     }
     566             :     return true;
     567             : }
     568             : 
     569      155386 : void CSigSharesManager::CollectPendingSigSharesToVerify(
     570             :     size_t maxUniqueSessions,
     571             :     std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
     572             :     std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
     573             : {
     574      155386 :     {
     575      155386 :         LOCK(cs);
     576      155386 :         if (nodeStates.empty()) {
     577      155031 :             return;
     578             :         }
     579             : 
     580             :         // This will iterate node states in random order and pick one sig share at a time. This avoids processing
     581             :         // of large batches at once from the same node while other nodes also provided shares. If we wouldn't do this,
     582             :         // other nodes would be able to poison us with a large batch with N-1 valid shares and the last one being
     583             :         // invalid, making batch verification fail and revert to per-share verification, which in turn would slow down
     584             :         // the whole verification process
     585             : 
     586       10568 :         std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
     587       24179 :         llmq::utils::IterateNodesRandom(nodeStates, [&]() { return uniqueSignHashes.size() < maxUniqueSessions; }, [&](NodeId nodeId, CSigSharesNodeState& ns) {
     588       24179 :             if (ns.pendingIncomingSigShares.Empty()) {
     589             :                 return false;
     590             :             }
     591         593 :             auto& sigShare = *ns.pendingIncomingSigShares.GetFirst();
     592             : 
     593         593 :             bool alreadyHave = this->sigShares.Has(sigShare.GetKey());
     594         593 :             if (!alreadyHave) {
     595         593 :                 uniqueSignHashes.emplace(nodeId, sigShare.GetSignHash());
     596         593 :                 retSigShares[nodeId].emplace_back(sigShare);
     597             :             }
     598         593 :             ns.pendingIncomingSigShares.Erase(sigShare.GetKey());
     599       10806 :             return !ns.pendingIncomingSigShares.Empty(); }, rnd);
     600             : 
     601       10213 :         if (retSigShares.empty()) {
     602      164889 :             return;
     603             :         }
     604             :     }
     605             : 
     606         355 :     {
     607         710 :         LOCK(cs_main);
     608             : 
     609             :         // For the convenience of the caller, also build a map of quorumHash -> quorum
     610             : 
     611         812 :         for (auto& p : retSigShares) {
     612        1050 :             for (auto& sigShare : p.second) {
     613         593 :                 auto llmqType = (Consensus::LLMQType)sigShare.llmqType;
     614             : 
     615         593 :                 auto k = std::make_pair(llmqType, sigShare.quorumHash);
     616         593 :                 if (retQuorums.count(k)) {
     617         213 :                     continue;
     618             :                 }
     619             : 
     620         760 :                 CQuorumCPtr quorum = quorumManager->GetQuorum(llmqType, sigShare.quorumHash);
     621         380 :                 assert(quorum != nullptr);
     622         380 :                 retQuorums.emplace(k, quorum);
     623             :             }
     624             :         }
     625             :     }
     626             : }
     627             : 
     628      155386 : bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
     629             : {
     630      310772 :     std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesByNodes;
     631      155386 :     std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
     632             : 
     633      155386 :     CollectPendingSigSharesToVerify(32, sigSharesByNodes, quorums);
     634      155386 :     if (sigSharesByNodes.empty()) {
     635             :         return false;
     636             :     }
     637             : 
     638             :     // It's ok to perform insecure batched verification here as we verify against the quorum public key shares,
     639             :     // which are not craftable by individual entities, making the rogue public key attack impossible
     640         355 :     CBLSBatchVerifier<NodeId, SigShareKey> batchVerifier(false, true);
     641             : 
     642         355 :     cxxtimer::Timer prepareTimer(true);
     643         355 :     size_t verifyCount = 0;
     644         812 :     for (auto& p : sigSharesByNodes) {
     645         457 :         auto nodeId = p.first;
     646         457 :         auto& v = p.second;
     647             : 
     648        1050 :         for (auto& sigShare : v) {
     649         593 :             if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) {
     650           0 :                 continue;
     651             :             }
     652             : 
     653             :             // we didn't check this earlier because we use a lazy BLS signature and tried to avoid doing the expensive
     654             :             // deserialization in the message thread
     655         593 :             if (!sigShare.sigShare.Get().IsValid()) {
     656           0 :                 BanNode(nodeId);
     657             :                 // don't process any additional shares from this node
     658           0 :                 break;
     659             :             }
     660             : 
     661        1186 :             auto quorum = quorums.at(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash));
     662         593 :             auto pubKeyShare = quorum->GetPubKeyShare(sigShare.quorumMember);
     663             : 
     664         593 :             if (!pubKeyShare.IsValid()) {
     665             :                 // this should really not happen (we already ensured we have the quorum vvec,
     666             :                 // so we should also be able to create all pubkey shares)
     667           0 :                 LogPrintf("CSigSharesManager::%s -- pubKeyShare is invalid, which should not be possible here.\n", __func__);
     668           0 :                 assert(false);
     669             :             }
     670             : 
     671         593 :             batchVerifier.PushMessage(nodeId, sigShare.GetKey(), sigShare.GetSignHash(), sigShare.sigShare.Get(), pubKeyShare);
     672         593 :             verifyCount++;
     673             :         }
     674             :     }
     675         355 :     prepareTimer.stop();
     676             : 
     677         710 :     cxxtimer::Timer verifyTimer(true);
     678         355 :     batchVerifier.Verify();
     679         355 :     verifyTimer.stop();
     680             : 
     681         355 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- verified sig shares. count=%d, pt=%d, vt=%d, nodes=%d\n", __func__, verifyCount, prepareTimer.count(), verifyTimer.count(), sigSharesByNodes.size());
     682             : 
     683         812 :     for (auto& p : sigSharesByNodes) {
     684         457 :         auto nodeId = p.first;
     685         457 :         auto& v = p.second;
     686             : 
     687         457 :         if (batchVerifier.badSources.count(nodeId)) {
     688           0 :             LogPrintf("CSigSharesManager::%s -- invalid sig shares from other node, banning peer=%d\n",
     689             :                 __func__, nodeId);
     690             :             // this will also cause re-requesting of the shares that were sent by this node
     691           0 :             BanNode(nodeId);
     692           0 :             continue;
     693             :         }
     694             : 
     695         457 :         ProcessPendingSigSharesFromNode(nodeId, v, quorums, connman);
     696             :     }
     697             : 
     698         355 :     return true;
     699             : }
     700             : 
     701             : // It's ensured that no duplicates are passed to this method
     702         457 : void CSigSharesManager::ProcessPendingSigSharesFromNode(NodeId nodeId,
     703             :     const std::vector<CSigShare>& sigShares,
     704             :     const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& quorums,
     705             :     CConnman& connman)
     706             : {
     707         457 :     LOCK(cs);
     708         457 :     auto& nodeState = nodeStates[nodeId];
     709             : 
     710         914 :     cxxtimer::Timer t(true);
     711        1050 :     for (auto& sigShare : sigShares) {
     712         593 :         auto quorumKey = std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash);
     713         593 :         ProcessSigShare(nodeId, sigShare, connman, quorums.at(quorumKey));
     714             :     }
     715         457 :     t.stop();
     716             : 
     717         457 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- processed sigShare batch. shares=%d, time=%d, node=%d\n", __func__,
     718             :         sigShares.size(), t.count(), nodeId);
     719         457 : }
     720             : 
     721             : // sig shares are already verified when entering this method
     722        1561 : void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare, CConnman& connman, const CQuorumCPtr& quorum)
     723             : {
     724        1561 :     auto llmqType = quorum->params.type;
     725             : 
     726        1561 :     bool canTryRecovery = false;
     727             : 
     728             :     // prepare node set for direct-push in case this is our sig share
     729        3053 :     std::set<NodeId> quorumNodes;
     730             : 
     731        1561 :     if (quorumSigningManager->HasRecoveredSigForId(llmqType, sigShare.id)) {
     732          69 :         return;
     733             :     }
     734             : 
     735        1492 :     {
     736        1492 :         LOCK(cs);
     737             : 
     738        1492 :         if (!sigShares.Add(sigShare.GetKey(), sigShare)) {
     739           0 :             return;
     740             :         }
     741        1492 :         sigSharesToAnnounce.Add(sigShare.GetKey(), true);
     742             : 
     743             :         // Update the time we've seen the last sigShare
     744        1492 :         timeSeenForSessions[sigShare.GetSignHash()] = GetAdjustedTime();
     745             : 
     746             :         // TODO: unreachable
     747        1492 :         if (!quorumNodes.empty()) {
     748             :             // don't announce and wait for other nodes to request this share and directly send it to them
     749             :             // there is no way the other nodes know about this share as this is the one created on this node
     750           0 :             for (auto otherNodeId : quorumNodes) {
     751           0 :                 auto& nodeState = nodeStates[otherNodeId];
     752           0 :                 auto& session = nodeState.GetOrCreateSessionFromShare(sigShare);
     753           0 :                 session.quorum = quorum;
     754           0 :                 session.requested.Set(sigShare.quorumMember, true);
     755           0 :                 session.knows.Set(sigShare.quorumMember, true);
     756             :             }
     757             :         }
     758             : 
     759        1492 :         size_t sigShareCount = sigShares.CountForSignHash(sigShare.GetSignHash());
     760        1492 :         if (sigShareCount >= quorum->params.threshold) {
     761         385 :             canTryRecovery = true;
     762             :         }
     763             :     }
     764             : 
     765        1492 :     if (canTryRecovery) {
     766         385 :         TryRecoverSig(quorum, sigShare.id, sigShare.msgHash, connman);
     767             :     }
     768             : }
     769             : 
     770         385 : void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash, CConnman& connman)
     771             : {
     772         385 :     if (quorumSigningManager->HasRecoveredSigForId(quorum->params.type, id)) {
     773           0 :         return;
     774             :     }
     775             : 
     776         770 :     std::vector<CBLSSignature> sigSharesForRecovery;
     777         385 :     std::vector<CBLSId> idsForRecovery;
     778         385 :     {
     779         385 :         LOCK(cs);
     780             : 
     781         385 :         auto k = std::make_pair(quorum->params.type, id);
     782             : 
     783         385 :         auto signHash = llmq::utils::BuildSignHash(quorum->params.type, quorum->qc.quorumHash, id, msgHash);
     784         385 :         auto sigShares = this->sigShares.GetAllForSignHash(signHash);
     785         385 :         if (!sigShares) {
     786           0 :             return;
     787             :         }
     788             : 
     789         385 :         sigSharesForRecovery.reserve((size_t)quorum->params.threshold);
     790         385 :         idsForRecovery.reserve((size_t)quorum->params.threshold);
     791        1155 :         for (auto it = sigShares->begin(); it != sigShares->end() && sigSharesForRecovery.size() < quorum->params.threshold; ++it) {
     792         770 :             auto& sigShare = it->second;
     793         770 :             sigSharesForRecovery.emplace_back(sigShare.sigShare.Get());
     794         770 :             idsForRecovery.emplace_back(CBLSId(quorum->members[sigShare.quorumMember]->proTxHash));
     795             :         }
     796             : 
     797             :         // check if we can recover the final signature
     798         385 :         if (sigSharesForRecovery.size() < quorum->params.threshold) {
     799             :             return;
     800             :         }
     801             :     }
     802             : 
     803             :     // now recover it
     804         770 :     cxxtimer::Timer t(true);
     805         385 :     CBLSSignature recoveredSig;
     806         385 :     if (!recoveredSig.Recover(sigSharesForRecovery, idsForRecovery)) {
     807           0 :         LogPrintf("CSigSharesManager::%s -- failed to recover signature. id=%s, msgHash=%s, time=%d\n", __func__,
     808           0 :             id.ToString(), msgHash.ToString(), t.count());
     809           0 :         return;
     810             :     }
     811             : 
     812        1155 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- recovered signature. id=%s, msgHash=%s, time=%d\n", __func__,
     813             :         id.ToString(), msgHash.ToString(), t.count());
     814             : 
     815         770 :     CRecoveredSig rs;
     816         385 :     rs.llmqType = quorum->params.type;
     817         385 :     rs.quorumHash = quorum->qc.quorumHash;
     818         385 :     rs.id = id;
     819         385 :     rs.msgHash = msgHash;
     820         385 :     rs.sig.Set(recoveredSig);
     821         385 :     rs.UpdateHash();
     822             : 
     823             :     // There should actually be no need to verify the self-recovered signatures as it should always succeed. Let's
     824             :     // however still verify it from time to time, so that we have a chance to catch bugs. We do only this sporadic
     825             :     // verification because this is unbatched and thus slow verification that happens here.
     826         385 :     if (((recoveredSigsCounter++) % 100) == 0) {
     827          18 :         auto signHash = llmq::utils::BuildSignHash(rs);
     828          18 :         bool valid = recoveredSig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash);
     829          18 :         if (!valid) {
     830             :             // this should really not happen as we have verified all signature shares before
     831           0 :             LogPrintf("CSigSharesManager::%s -- own recovered signature is invalid. id=%s, msgHash=%s\n", __func__,
     832           0 :                 id.ToString(), msgHash.ToString());
     833           0 :             return;
     834             :         }
     835             :     }
     836             : 
     837         385 :     quorumSigningManager->ProcessRecoveredSig(-1, rs, quorum, connman);
     838             : }
     839             : 
     840        1218 : CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256& id, int attempt)
     841             : {
     842        1218 :     assert(attempt < quorum->members.size());
     843             : 
     844        1218 :     std::vector<std::pair<uint256, CDeterministicMNCPtr>> v;
     845        1218 :     v.reserve(quorum->members.size());
     846        4872 :     for (const auto& dmn : quorum->members) {
     847        3654 :         auto h = ::SerializeHash(std::make_pair(dmn->proTxHash, id));
     848        3654 :         v.emplace_back(h, dmn);
     849             :     }
     850        1218 :     std::sort(v.begin(), v.end());
     851             : 
     852        1218 :     return v[attempt].second;
     853             : }
     854             : 
     855             : // TODO unused
     856           0 : void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToRequest)
     857             : {
     858           0 :     AssertLockHeld(cs);
     859             : 
     860           0 :     int64_t now = GetAdjustedTime();
     861           0 :     const size_t maxRequestsForNode = 32;
     862             : 
     863             :     // avoid requesting from same nodes all the time
     864           0 :     std::vector<NodeId> shuffledNodeIds;
     865           0 :     shuffledNodeIds.reserve(nodeStates.size());
     866           0 :     for (auto& p : nodeStates) {
     867           0 :         if (p.second.sessions.empty()) {
     868           0 :             continue;
     869             :         }
     870           0 :         shuffledNodeIds.emplace_back(p.first);
     871             :     }
     872           0 :     Shuffle(shuffledNodeIds.begin(), shuffledNodeIds.end(), rnd);
     873             : 
     874           0 :     for (auto& nodeId : shuffledNodeIds) {
     875           0 :         auto& nodeState = nodeStates[nodeId];
     876             : 
     877           0 :         if (nodeState.banned) {
     878           0 :             continue;
     879             :         }
     880             : 
     881           0 :         nodeState.requestedSigShares.EraseIf([&](const SigShareKey& k, int64_t t) {
     882           0 :             if (now - t >= SIG_SHARE_REQUEST_TIMEOUT) {
     883             :                 // timeout while waiting for this one, so retry it with another node
     884           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::CollectSigSharesToRequest -- timeout while waiting for %s-%d, node=%d\n",
     885             :                     k.first.ToString(), k.second, nodeId);
     886           0 :                 return true;
     887             :             }
     888             :             return false;
     889             :         });
     890             : 
     891           0 :         decltype(sigSharesToRequest.begin()->second)* invMap = nullptr;
     892             : 
     893           0 :         for (auto& p2 : nodeState.sessions) {
     894           0 :             auto& signHash = p2.first;
     895           0 :             auto& session = p2.second;
     896             : 
     897           0 :             if (quorumSigningManager->HasRecoveredSigForSession(signHash)) {
     898           0 :                 continue;
     899             :             }
     900             : 
     901           0 :             for (size_t i = 0; i < session.announced.inv.size(); i++) {
     902           0 :                 if (!session.announced.inv[i]) {
     903           0 :                     continue;
     904             :                 }
     905           0 :                 auto k = std::make_pair(signHash, (uint16_t)i);
     906           0 :                 if (sigShares.Has(k)) {
     907             :                     // we already have it
     908           0 :                     session.announced.inv[i] = false;
     909           0 :                     continue;
     910             :                 }
     911           0 :                 if (nodeState.requestedSigShares.Size() >= maxRequestsForNode) {
     912             :                     // too many pending requests for this node
     913             :                     break;
     914             :                 }
     915           0 :                 auto p = sigSharesRequested.Get(k);
     916           0 :                 if (p) {
     917           0 :                     if (now - p->second >= SIG_SHARE_REQUEST_TIMEOUT && nodeId != p->first) {
     918             :                         // other node timed out, re-request from this node
     919           0 :                         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- other node timeout while waiting for %s-%d, re-request from=%d, node=%d\n", __func__,
     920             :                             k.first.ToString(), k.second, nodeId, p->first);
     921             :                     } else {
     922           0 :                         continue;
     923             :                     }
     924             :                 }
     925             :                 // if we got this far we should do a request
     926             : 
     927             :                 // track when we initiated the request so that we can detect timeouts
     928           0 :                 nodeState.requestedSigShares.Add(k, now);
     929             : 
     930             :                 // don't request it from other nodes until a timeout happens
     931           0 :                 auto& r = sigSharesRequested.GetOrAdd(k);
     932           0 :                 r.first = nodeId;
     933           0 :                 r.second = now;
     934             : 
     935           0 :                 if (!invMap) {
     936           0 :                     invMap = &sigSharesToRequest[nodeId];
     937             :                 }
     938           0 :                 auto& inv = (*invMap)[signHash];
     939           0 :                 if (inv.inv.empty()) {
     940           0 :                     const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)session.llmqType);
     941           0 :                     inv.Init((size_t)params.size);
     942             :                 }
     943           0 :                 inv.inv[k.second] = true;
     944             : 
     945             :                 // don't request it again from this node
     946           0 :                 session.announced.inv[i] = false;
     947             :             }
     948             :         }
     949             :     }
     950           0 : }
     951             : 
     952             : // TODO: unused
     953           0 : void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>>& sigSharesToSend)
     954             : {
     955           0 :     AssertLockHeld(cs);
     956             : 
     957           0 :     for (auto& p : nodeStates) {
     958           0 :         auto nodeId = p.first;
     959           0 :         auto& nodeState = p.second;
     960             : 
     961           0 :         if (nodeState.banned) {
     962           0 :             continue;
     963             :         }
     964             : 
     965           0 :         decltype(sigSharesToSend.begin()->second)* sigSharesToSend2 = nullptr;
     966             : 
     967           0 :         for (auto& p2 : nodeState.sessions) {
     968           0 :             auto& signHash = p2.first;
     969           0 :             auto& session = p2.second;
     970             : 
     971           0 :             if (quorumSigningManager->HasRecoveredSigForSession(signHash)) {
     972           0 :                 continue;
     973             :             }
     974             : 
     975           0 :             CBatchedSigShares batchedSigShares;
     976             : 
     977           0 :             for (size_t i = 0; i < session.requested.inv.size(); i++) {
     978           0 :                 if (!session.requested.inv[i]) {
     979           0 :                     continue;
     980             :                 }
     981           0 :                 session.requested.inv[i] = false;
     982             : 
     983           0 :                 auto k = std::make_pair(signHash, (uint16_t)i);
     984           0 :                 const CSigShare* sigShare = sigShares.Get(k);
     985           0 :                 if (!sigShare) {
     986             :                     // he requested something we don'have
     987           0 :                     session.requested.inv[i] = false;
     988           0 :                     continue;
     989             :                 }
     990             : 
     991           0 :                 batchedSigShares.sigShares.emplace_back((uint16_t)i, sigShare->sigShare);
     992             :             }
     993             : 
     994           0 :             if (!batchedSigShares.sigShares.empty()) {
     995           0 :                 if (sigSharesToSend2 == nullptr) {
     996             :                     // only create the map if we actually add a batched sig
     997           0 :                     sigSharesToSend2 = &sigSharesToSend[nodeId];
     998             :                 }
     999           0 :                 (*sigSharesToSend2).emplace(signHash, std::move(batchedSigShares));
    1000             :             }
    1001             :         }
    1002             :     }
    1003           0 : }
    1004             : 
    1005       83875 : void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::vector<CSigShare>>& sigSharesToSend, const std::vector<CNode*>& vNodes)
    1006             : {
    1007       83875 :     AssertLockHeld(cs);
    1008             : 
    1009       83875 :     std::unordered_map<uint256, CNode*> proTxToNode;
    1010      486588 :     for (const auto& pnode : vNodes) {
    1011      805426 :         if (pnode->verifiedProRegTxHash.IsNull()) {
    1012      377385 :             continue;
    1013             :         }
    1014      402713 :         proTxToNode.emplace(pnode->verifiedProRegTxHash, pnode);
    1015             :     }
    1016             : 
    1017       83875 :     auto curTime = GetTime<std::chrono::milliseconds>().count();
    1018             : 
    1019      121868 :     for (auto& p : signedSessions) {
    1020       37993 :         if (p.second.attempt >= p.second.quorum->params.recoveryMembers) {
    1021       31467 :             continue;
    1022             :         }
    1023             : 
    1024        6526 :         if (curTime >= p.second.nextAttemptTime) {
    1025        1218 :             int64_t waitTime = exp2(p.second.attempt) * EXP_SEND_FOR_RECOVERY_TIMEOUT;
    1026        1218 :             waitTime = std::min(MAX_SEND_FOR_RECOVERY_TIMEOUT, waitTime);
    1027        1218 :             p.second.nextAttemptTime = curTime + waitTime;
    1028        2090 :             auto dmn = SelectMemberForRecovery(p.second.quorum, p.second.sigShare.id, p.second.attempt);
    1029        1218 :             p.second.attempt++;
    1030             : 
    1031        3654 :             LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, sending to %s, attempt=%d\n", __func__,
    1032             :                 p.second.sigShare.GetSignHash().ToString(), dmn->proTxHash.ToString(), p.second.attempt);
    1033             : 
    1034        1218 :             auto it = proTxToNode.find(dmn->proTxHash);
    1035        1218 :             if (it == proTxToNode.end()) {
    1036         692 :                 continue;
    1037             :             }
    1038             : 
    1039         872 :             auto& m = sigSharesToSend[it->second->GetId()];
    1040         872 :             m.emplace_back(p.second.sigShare);
    1041             :         }
    1042             :     }
    1043       83875 : }
    1044             : 
    1045             : // TODO unused
    1046           0 : void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToAnnounce)
    1047             : {
    1048           0 :     AssertLockHeld(cs);
    1049             : 
    1050           0 :     std::unordered_map<std::pair<Consensus::LLMQType, uint256>, std::unordered_set<NodeId>, StaticSaltedHasher> quorumNodesMap;
    1051             : 
    1052           0 :     this->sigSharesToAnnounce.ForEach([&](const SigShareKey& sigShareKey, bool) {
    1053           0 :         auto& signHash = sigShareKey.first;
    1054           0 :         auto quorumMember = sigShareKey.second;
    1055           0 :         const CSigShare* sigShare = sigShares.Get(sigShareKey);
    1056           0 :         if (!sigShare) {
    1057           0 :             return;
    1058             :         }
    1059             : 
    1060             :         // announce to the nodes which we know through the intra-quorum-communication system
    1061           0 :         auto quorumKey = std::make_pair((Consensus::LLMQType)sigShare->llmqType, sigShare->quorumHash);
    1062           0 :         auto it = quorumNodesMap.find(quorumKey);
    1063           0 :         if (it == quorumNodesMap.end()) {
    1064           0 :             auto nodeIds = g_connman->GetTierTwoConnMan()->getQuorumNodes(quorumKey.first, quorumKey.second);
    1065           0 :             it = quorumNodesMap.emplace(std::piecewise_construct, std::forward_as_tuple(quorumKey), std::forward_as_tuple(nodeIds.begin(), nodeIds.end())).first;
    1066             :         }
    1067             : 
    1068           0 :         auto& quorumNodes = it->second;
    1069             : 
    1070           0 :         for (auto& nodeId : quorumNodes) {
    1071           0 :             auto& nodeState = nodeStates[nodeId];
    1072             : 
    1073           0 :             if (nodeState.banned) {
    1074           0 :                 continue;
    1075             :             }
    1076             : 
    1077           0 :             auto& session = nodeState.GetOrCreateSessionFromShare(*sigShare);
    1078             : 
    1079           0 :             if (session.knows.inv[quorumMember]) {
    1080             :                 // he already knows that one
    1081           0 :                 continue;
    1082             :             }
    1083             : 
    1084           0 :             auto& inv = sigSharesToAnnounce[nodeId][signHash];
    1085           0 :             if (inv.inv.empty()) {
    1086           0 :                 const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)sigShare->llmqType);
    1087           0 :                 inv.Init((size_t)params.size);
    1088             :             }
    1089           0 :             inv.inv[quorumMember] = true;
    1090           0 :             session.knows.inv[quorumMember] = true;
    1091             :         }
    1092             :     });
    1093             : 
    1094             :     // don't announce these anymore
    1095           0 :     this->sigSharesToAnnounce.Clear();
    1096           0 : }
    1097             : 
    1098       83875 : bool CSigSharesManager::SendMessages()
    1099             : {
    1100       83875 :     std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToRequest;
    1101       83875 :     std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>> sigShareBatchesToSend;
    1102       83875 :     std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesToSend;
    1103       83875 :     std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToAnnounce;
    1104       83875 :     std::unordered_map<NodeId, std::vector<CSigSesAnn>> sigSessionAnnouncements;
    1105             : 
    1106       83875 :     auto addSigSesAnnIfNeeded = [&](NodeId nodeId, const uint256& signHash) {
    1107           0 :         auto& nodeState = nodeStates[nodeId];
    1108           0 :         auto session = nodeState.GetSessionBySignHash(signHash);
    1109           0 :         assert(session);
    1110           0 :         if (session->sendSessionId == (uint32_t)-1) {
    1111           0 :             session->sendSessionId = nodeState.nextSendSessionId++;
    1112             : 
    1113           0 :             CSigSesAnn sigSesAnn;
    1114           0 :             sigSesAnn.sessionId = session->sendSessionId;
    1115           0 :             sigSesAnn.llmqType = (uint8_t)session->llmqType;
    1116           0 :             sigSesAnn.quorumHash = session->quorumHash;
    1117           0 :             sigSesAnn.id = session->id;
    1118           0 :             sigSesAnn.msgHash = session->msgHash;
    1119             : 
    1120           0 :             sigSessionAnnouncements[nodeId].emplace_back(sigSesAnn);
    1121             :         }
    1122           0 :         return session->sendSessionId;
    1123       83875 :     };
    1124             : 
    1125      167750 :     std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector(CConnman::FullyConnectedOnly);
    1126             : 
    1127       83875 :     {
    1128       83875 :         LOCK(cs);
    1129       83875 :         CollectSigSharesToSend(sigSharesToSend, vNodesCopy);
    1130             : 
    1131       83875 :         for (auto& p : sigSharesToRequest) {
    1132           0 :             for (auto& p2 : p.second) {
    1133           0 :                 p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
    1134             :             }
    1135             :         }
    1136       83875 :         for (auto& p : sigShareBatchesToSend) {
    1137           0 :             for (auto& p2 : p.second) {
    1138           0 :                 p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
    1139             :             }
    1140             :         }
    1141       83875 :         for (auto& p : sigSharesToAnnounce) {
    1142           0 :             for (auto& p2 : p.second) {
    1143           0 :                 p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
    1144             :             }
    1145             :         }
    1146             :     }
    1147             : 
    1148       83875 :     bool didSend = false;
    1149             : 
    1150      486588 :     for (auto& pnode : vNodesCopy) {
    1151      402713 :         CNetMsgMaker msgMaker(pnode->GetSendVersion());
    1152             : 
    1153      402713 :         auto it1 = sigSessionAnnouncements.find(pnode->GetId());
    1154      402713 :         if (it1 != sigSessionAnnouncements.end()) {
    1155           0 :             std::vector<CSigSesAnn> msgs;
    1156           0 :             msgs.reserve(it1->second.size());
    1157           0 :             for (auto& sigSesAnn : it1->second) {
    1158           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSESANN signHash=%s, sessionId=%d, node=%d\n",
    1159             :                     llmq::utils::BuildSignHash(sigSesAnn).ToString(), sigSesAnn.sessionId, pnode->GetId());
    1160           0 :                 msgs.emplace_back(sigSesAnn);
    1161           0 :                 if (msgs.size() == MAX_MSGS_CNT_QSIGSESANN) {
    1162           0 :                     g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs), false);
    1163           0 :                     msgs.clear();
    1164             :                     didSend = true;
    1165             :                 }
    1166             :             }
    1167           0 :             if (!msgs.empty()) {
    1168           0 :                 g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs), false);
    1169           0 :                 didSend = true;
    1170             :             }
    1171             :         }
    1172             : 
    1173      402713 :         auto it = sigSharesToRequest.find(pnode->GetId());
    1174      402713 :         if (it != sigSharesToRequest.end()) {
    1175           0 :             std::vector<CSigSharesInv> msgs;
    1176           0 :             for (auto& p : it->second) {
    1177           0 :                 assert(p.second.CountSet() != 0);
    1178           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QGETSIGSHARES signHash=%s, inv={%s}, node=%d\n",
    1179             :                     p.first.ToString(), p.second.ToString(), pnode->GetId());
    1180           0 :                 msgs.emplace_back(std::move(p.second));
    1181           0 :                 if (msgs.size() == MAX_MSGS_CNT_QGETSIGSHARES) {
    1182           0 :                     g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs), false);
    1183           0 :                     msgs.clear();
    1184             :                     didSend = true;
    1185             :                 }
    1186             :             }
    1187           0 :             if (!msgs.empty()) {
    1188           0 :                 g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs), false);
    1189           0 :                 didSend = true;
    1190             :             }
    1191             :         }
    1192             : 
    1193      402713 :         auto jt = sigShareBatchesToSend.find(pnode->GetId());
    1194      402713 :         if (jt != sigShareBatchesToSend.end()) {
    1195           0 :             size_t totalSigsCount = 0;
    1196           0 :             std::vector<CBatchedSigShares> msgs;
    1197           0 :             for (auto& p : jt->second) {
    1198           0 :                 assert(!p.second.sigShares.empty());
    1199           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QBSIGSHARES signHash=%s, inv={%s}, node=%d\n",
    1200             :                     p.first.ToString(), p.second.ToInvString(), pnode->GetId());
    1201           0 :                 if (totalSigsCount + p.second.sigShares.size() > MAX_MSGS_TOTAL_BATCHED_SIGS) {
    1202           0 :                     g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, msgs), false);
    1203           0 :                     msgs.clear();
    1204             :                     totalSigsCount = 0;
    1205             :                     didSend = true;
    1206             :                 }
    1207           0 :                 totalSigsCount += p.second.sigShares.size();
    1208           0 :                 msgs.emplace_back(std::move(p.second));
    1209             :             }
    1210           0 :             if (!msgs.empty()) {
    1211           0 :                 g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, std::move(msgs)), false);
    1212           0 :                 didSend = true;
    1213             :             }
    1214             :         }
    1215             : 
    1216      402713 :         auto kt = sigSharesToAnnounce.find(pnode->GetId());
    1217      402713 :         if (kt != sigSharesToAnnounce.end()) {
    1218           0 :             std::vector<CSigSharesInv> msgs;
    1219           0 :             for (auto& p : kt->second) {
    1220           0 :                 assert(p.second.CountSet() != 0);
    1221           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSHARESINV signHash=%s, inv={%s}, node=%d\n",
    1222             :                     p.first.ToString(), p.second.ToString(), pnode->GetId());
    1223           0 :                 msgs.emplace_back(std::move(p.second));
    1224           0 :                 if (msgs.size() == MAX_MSGS_CNT_QSIGSHARESINV) {
    1225           0 :                     g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs), false);
    1226           0 :                     msgs.clear();
    1227             :                     didSend = true;
    1228             :                 }
    1229             :             }
    1230           0 :             if (!msgs.empty()) {
    1231           0 :                 g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs), false);
    1232           0 :                 didSend = true;
    1233             :             }
    1234             :         }
    1235             : 
    1236      402713 :         auto lt = sigSharesToSend.find(pnode->GetId());
    1237      402713 :         if (lt != sigSharesToSend.end()) {
    1238        1324 :             std::vector<CSigShare> msgs;
    1239        1534 :             for (auto& sigShare : lt->second) {
    1240        1744 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSHARE signHash=%s, node=%d\n",
    1241             :                     sigShare.GetSignHash().ToString(), pnode->GetId());
    1242         872 :                 msgs.emplace_back(std::move(sigShare));
    1243         872 :                 if (msgs.size() == MAX_MSGS_SIG_SHARES) {
    1244           0 :                     g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs), false);
    1245           0 :                     msgs.clear();
    1246           0 :                     didSend = true;
    1247             :                 }
    1248             :             }
    1249         662 :             if (!msgs.empty()) {
    1250         662 :                 g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs), false);
    1251         662 :                 didSend = true;
    1252             :             }
    1253             :         }
    1254             :     }
    1255             : 
    1256             :     // looped through all nodes, release them
    1257       83875 :     g_connman->ReleaseNodeVector(vNodesCopy);
    1258             : 
    1259      167750 :     return didSend;
    1260             : }
    1261             : 
    1262           0 : bool CSigSharesManager::GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo)
    1263             : {
    1264           0 :     LOCK(cs);
    1265           0 :     return nodeStates[nodeId].GetSessionInfoByRecvId(sessionId, retInfo);
    1266             : }
    1267             : 
    1268           0 : CSigShare CSigSharesManager::RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares, size_t idx)
    1269             : {
    1270           0 :     assert(idx < batchedSigShares.sigShares.size());
    1271           0 :     auto& s = batchedSigShares.sigShares[idx];
    1272           0 :     CSigShare sigShare;
    1273           0 :     sigShare.llmqType = session.llmqType;
    1274           0 :     sigShare.quorumHash = session.quorumHash;
    1275           0 :     sigShare.quorumMember = s.first;
    1276           0 :     sigShare.id = session.id;
    1277           0 :     sigShare.msgHash = session.msgHash;
    1278           0 :     sigShare.sigShare = s.second;
    1279           0 :     sigShare.UpdateKey();
    1280           0 :     return sigShare;
    1281             : }
    1282             : 
    1283      155386 : void CSigSharesManager::Cleanup()
    1284             : {
    1285      155386 :     int64_t now = GetAdjustedTime();
    1286      155386 :     if (now - lastCleanupTime < 5) {
    1287      148990 :         return;
    1288             :     }
    1289             : 
    1290             :     // This map is first filled with all quorums found in all sig shares. Then we remove all inactive quorums and
    1291             :     // loop through all sig shares again to find the ones belonging to the inactive quorums. We then delete the
    1292             :     // sessions belonging to the sig shares. At the same time, we use this map as a cache when we later need to resolve
    1293             :     // quorumHash -> quorumPtr (as GetQuorum() requires cs_main, leading to deadlocks with cs held)
    1294       12792 :     std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
    1295             : 
    1296        6396 :     {
    1297        6396 :         LOCK(cs);
    1298        6396 :         sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
    1299         793 :             quorums.emplace(std::make_pair((Consensus::LLMQType) sigShare.llmqType, sigShare.quorumHash), nullptr);
    1300         793 :         });
    1301             :     }
    1302             : 
    1303             :     // Find quorums which became inactive
    1304        6396 :     for (auto it = quorums.begin(); it != quorums.end(); ) {
    1305         228 :         if (llmq::utils::IsQuorumActive(it->first.first, it->first.second)) {
    1306         216 :             it->second = quorumManager->GetQuorum(it->first.first, it->first.second);
    1307        6840 :             ++it;
    1308             :         } else {
    1309          12 :             it = quorums.erase(it);
    1310             :         }
    1311             :     }
    1312             : 
    1313        6396 :     {
    1314             :         // Now delete sessions which are for inactive quorums
    1315        6396 :         LOCK(cs);
    1316       12792 :         std::unordered_set<uint256, StaticSaltedHasher> inactiveQuorumSessions;
    1317        6396 :         sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
    1318         793 :             if (!quorums.count(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash))) {
    1319          60 :                 inactiveQuorumSessions.emplace(sigShare.GetSignHash());
    1320             :             }
    1321         793 :         });
    1322        6456 :         for (auto& signHash : inactiveQuorumSessions) {
    1323          60 :             RemoveSigSharesForSession(signHash);
    1324             :         }
    1325             :     }
    1326             : 
    1327        6396 :     {
    1328        6396 :         LOCK(cs);
    1329             : 
    1330             :         // Remove sessions which were successfully recovered
    1331       12792 :         std::unordered_set<uint256, StaticSaltedHasher> doneSessions;
    1332        6396 :         sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
    1333         733 :             if (doneSessions.count(sigShare.GetSignHash())) {
    1334             :                 return;
    1335             :             }
    1336         733 :             if (quorumSigningManager->HasRecoveredSigForSession(sigShare.GetSignHash())) {
    1337           0 :                 doneSessions.emplace(sigShare.GetSignHash());
    1338             :             }
    1339             :         });
    1340        6396 :         for (auto& signHash : doneSessions) {
    1341           0 :             RemoveSigSharesForSession(signHash);
    1342             :         }
    1343             : 
    1344             :         // Remove sessions which timed out
    1345       12792 :         std::unordered_set<uint256, StaticSaltedHasher> timeoutSessions;
    1346        7129 :         for (auto& p : timeSeenForSessions) {
    1347         733 :             auto& signHash = p.first;
    1348         733 :             int64_t lastSeenTime = p.second;
    1349             : 
    1350         733 :             if (now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) {
    1351         733 :                 timeoutSessions.emplace(signHash);
    1352             :             }
    1353             :         }
    1354        6396 :         for (auto& signHash : timeoutSessions) {
    1355           0 :             size_t count = sigShares.CountForSignHash(signHash);
    1356             : 
    1357           0 :             if (count > 0) {
    1358           0 :                 auto m = sigShares.GetAllForSignHash(signHash);
    1359           0 :                 assert(m);
    1360             : 
    1361           0 :                 auto& oneSigShare = m->begin()->second;
    1362             : 
    1363           0 :                 std::string strMissingMembers;
    1364           0 :                 if (LogAcceptCategory(BCLog::LogFlags::LLMQ)) {
    1365           0 :                     auto quorumIt = quorums.find(std::make_pair((Consensus::LLMQType)oneSigShare.llmqType, oneSigShare.quorumHash));
    1366           0 :                     if (quorumIt != quorums.end()) {
    1367           0 :                         auto& quorum = quorumIt->second;
    1368           0 :                         for (size_t i = 0; i < quorum->members.size(); i++) {
    1369           0 :                             if (!m->count((uint16_t)i)) {
    1370           0 :                                 auto& dmn = quorum->members[i];
    1371           0 :                                 strMissingMembers += strprintf("\n  %s", dmn->proTxHash.ToString());
    1372             :                             }
    1373             :                         }
    1374             :                     }
    1375             :                 }
    1376             : 
    1377           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signing session timed out. signHash=%s, id=%s, msgHash=%s, sigShareCount=%d, missingMembers=%s\n", __func__,
    1378             :                     signHash.ToString(), oneSigShare.id.ToString(), oneSigShare.msgHash.ToString(), count, strMissingMembers);
    1379             :             } else {
    1380           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signing session timed out. signHash=%s, sigShareCount=%d\n", __func__,
    1381             :                     signHash.ToString(), count);
    1382             :             }
    1383           0 :             RemoveSigSharesForSession(signHash);
    1384             :         }
    1385             :     }
    1386             : 
    1387             :     // Find node states for peers that disappeared from CConnman
    1388       12792 :     std::unordered_set<NodeId> nodeStatesToDelete;
    1389        6822 :     for (auto& p : nodeStates) {
    1390         426 :         nodeStatesToDelete.emplace(p.first);
    1391             :     }
    1392        6396 :     g_connman->ForEachNode([&](CNode* pnode) {
    1393       21605 :         nodeStatesToDelete.erase(pnode->GetId());
    1394       21605 :     });
    1395             : 
    1396             :     // Now delete these node states
    1397       12792 :     LOCK(cs);
    1398        6398 :     for (auto nodeId : nodeStatesToDelete) {
    1399           2 :         auto& nodeState = nodeStates[nodeId];
    1400             :         // remove global requested state to force a re-request from another node
    1401           2 :         nodeState.requestedSigShares.ForEach([&](const SigShareKey& k, bool) {
    1402           0 :             sigSharesRequested.Erase(k);
    1403             :         });
    1404           2 :         nodeStates.erase(nodeId);
    1405             :     }
    1406             : 
    1407        6396 :     lastCleanupTime = GetAdjustedTime();
    1408             : }
    1409             : 
    1410        2109 : void CSigSharesManager::RemoveSigSharesForSession(const uint256& signHash)
    1411             : {
    1412        6720 :     for (auto& p : nodeStates) {
    1413        4611 :         auto& ns = p.second;
    1414        4611 :         ns.RemoveSession(signHash);
    1415             :     }
    1416             : 
    1417        2109 :     sigSharesRequested.EraseAllForSignHash(signHash);
    1418        2109 :     sigSharesToAnnounce.EraseAllForSignHash(signHash);
    1419        2109 :     sigShares.EraseAllForSignHash(signHash);
    1420        2109 :     signedSessions.erase(signHash);
    1421        2109 :     timeSeenForSessions.erase(signHash);
    1422        2109 : }
    1423             : 
    1424      155386 : void CSigSharesManager::RemoveBannedNodeStates()
    1425             : {
    1426             :     // Called regularly to cleanup local node states for banned nodes
    1427             : 
    1428      310772 :     LOCK2(cs, cs_main);
    1429      310772 :     std::unordered_set<NodeId> toRemove;
    1430      155386 :     for (auto it = nodeStates.begin(); it != nodeStates.end();) {
    1431       24041 :         if (IsBanned(it->first)) {
    1432             :             // re-request sigshares from other nodes
    1433           0 :             it->second.requestedSigShares.ForEach([&](const SigShareKey& k, int64_t) {
    1434           0 :                 sigSharesRequested.Erase(k);
    1435             :             });
    1436           0 :             it = nodeStates.erase(it);
    1437             :         } else {
    1438      203468 :             ++it;
    1439             :         }
    1440             :     }
    1441      155386 : }
    1442             : 
    1443           0 : void CSigSharesManager::BanNode(NodeId nodeId)
    1444             : {
    1445           0 :     if (nodeId == -1) {
    1446           0 :         return;
    1447             :     }
    1448             : 
    1449           0 :     {
    1450           0 :         LOCK(cs_main);
    1451           0 :         Misbehaving(nodeId, 100);
    1452             :     }
    1453             : 
    1454           0 :     LOCK(cs);
    1455           0 :     auto it = nodeStates.find(nodeId);
    1456           0 :     if (it == nodeStates.end()) {
    1457           0 :         return;
    1458             :     }
    1459           0 :     auto& nodeState = it->second;
    1460             : 
    1461             :     // Whatever we requested from him, let's request it from someone else now
    1462           0 :     nodeState.requestedSigShares.ForEach([&](const SigShareKey& k, int64_t) {
    1463           0 :         sigSharesRequested.Erase(k);
    1464             :     });
    1465           0 :     nodeState.requestedSigShares.Clear();
    1466             : 
    1467           0 :     nodeState.banned = true;
    1468             : }
    1469             : 
    1470         347 : void CSigSharesManager::WorkThreadMain()
    1471             : {
    1472         347 :     int64_t lastSendTime = 0;
    1473      155386 :     while (!interruptSigningShare) {
    1474      155386 :         bool didWork = false;
    1475             : 
    1476      155386 :         RemoveBannedNodeStates();
    1477      155386 :         didWork |= quorumSigningManager->ProcessPendingRecoveredSigs(*g_connman);
    1478      155386 :         didWork |= ProcessPendingSigShares(*g_connman);
    1479      155386 :         didWork |= SignPendingSigShares();
    1480             : 
    1481      155386 :         if (GetTimeMillis() - lastSendTime > 100) {
    1482       83875 :             SendMessages();
    1483       83875 :             lastSendTime = GetTimeMillis();
    1484             :         }
    1485             : 
    1486      155386 :         Cleanup();
    1487      155386 :         quorumSigningManager->Cleanup();
    1488             : 
    1489             :         // TODO Wakeup when pending signing is needed?
    1490      155386 :         if (!didWork) {
    1491      154029 :             if (!interruptSigningShare.sleep_for(std::chrono::milliseconds(100))) {
    1492             :                 return;
    1493             :             }
    1494             :         }
    1495             :     }
    1496             : }
    1497             : 
    1498         968 : void CSigSharesManager::AsyncSign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash)
    1499             : {
    1500         968 :     LOCK(cs);
    1501         968 :     pendingSigns.emplace_back(quorum, id, msgHash);
    1502         968 : }
    1503             : 
    1504      155386 : bool CSigSharesManager::SignPendingSigShares()
    1505             : {
    1506      310772 :     std::vector<std::tuple<const CQuorumCPtr, uint256, uint256>> v;
    1507      155386 :     {
    1508      155386 :         LOCK(cs);
    1509      155386 :         v = std::move(pendingSigns);
    1510             :     }
    1511             : 
    1512      156354 :     for (auto& t : v) {
    1513         968 :         Sign(std::get<0>(t), std::get<1>(t), std::get<2>(t));
    1514             :     }
    1515             : 
    1516      155386 :     return !v.empty();
    1517             : }
    1518             : 
    1519         968 : void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash)
    1520             : {
    1521        1936 :     cxxtimer::Timer t(true);
    1522             : 
    1523         968 :     if (!quorum->IsValidMember(activeMasternodeManager->GetProTx())) {
    1524           0 :         return;
    1525             :     }
    1526             : 
    1527        1936 :     CBLSSecretKey skShare = quorum->GetSkShare();
    1528         968 :     if (!skShare.IsValid()) {
    1529           0 :         LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum->qc.quorumHash.ToString());
    1530           0 :         return;
    1531             :     }
    1532             : 
    1533         968 :     int memberIdx = quorum->GetMemberIndex(activeMasternodeManager->GetProTx());
    1534         968 :     if (memberIdx == -1) {
    1535             :         // this should really not happen (IsValidMember gave true)
    1536             :         return;
    1537             :     }
    1538             : 
    1539        1936 :     CSigShare sigShare;
    1540         968 :     sigShare.llmqType = quorum->params.type;
    1541         968 :     sigShare.quorumHash = quorum->qc.quorumHash;
    1542         968 :     sigShare.id = id;
    1543         968 :     sigShare.msgHash = msgHash;
    1544         968 :     sigShare.quorumMember = (uint16_t)memberIdx;
    1545         968 :     uint256 signHash = llmq::utils::BuildSignHash(sigShare);
    1546             : 
    1547         968 :     sigShare.sigShare.Set(skShare.Sign(signHash));
    1548         968 :     if (!sigShare.sigShare.Get().IsValid()) {
    1549           0 :         LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHahs=%s, id=%s, msgHash=%s, time=%s\n", __func__,
    1550           0 :             signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), t.count());
    1551           0 :         return;
    1552             :     }
    1553             : 
    1554         968 :     sigShare.UpdateKey();
    1555             : 
    1556        4840 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signed sigShare. signHash=%s, id=%s, msgHash=%s, llmqType=%d, quorum=%s, time=%s\n", __func__,
    1557             :         signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), quorum->params.type, quorum->qc.quorumHash.ToString(), t.count());
    1558         968 :     ProcessSigShare(-1, sigShare, *g_connman, quorum);
    1559             : 
    1560        1936 :     LOCK(cs);
    1561         968 :     auto& session = signedSessions[sigShare.GetSignHash()];
    1562         968 :     session.sigShare = sigShare;
    1563         968 :     session.quorum = quorum;
    1564         968 :     session.nextAttemptTime = 0;
    1565         968 :     session.attempt = 0;
    1566             : }
    1567             : 
    1568             : // causes all known sigShares to be re-announced
    1569           0 : void CSigSharesManager::ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash)
    1570             : {
    1571           0 :     LOCK(cs);
    1572           0 :     auto signHash = llmq::utils::BuildSignHash(llmqType, quorum->qc.quorumHash, id, msgHash);
    1573           0 :     auto sigs = sigShares.GetAllForSignHash(signHash);
    1574           0 :     if (sigs) {
    1575           0 :         for (auto& p : *sigs) {
    1576             :             // re-announce every sigshare to every node
    1577           0 :             sigSharesToAnnounce.Add(std::make_pair(signHash, p.first), true);
    1578             :         }
    1579             :     }
    1580           0 :     for (auto& p : nodeStates) {
    1581           0 :         CSigSharesNodeState& nodeState = p.second;
    1582           0 :         auto session = nodeState.GetSessionBySignHash(signHash);
    1583           0 :         if (!session) {
    1584           0 :             continue;
    1585             :         }
    1586             :         // pretend that the other node doesn't know about any shares so that we re-announce everything
    1587           0 :         session->knows.SetAll(false);
    1588             :         // we need to use a new session id as we don't know if the other node has run into a timeout already
    1589           0 :         session->sendSessionId = (uint32_t)-1;
    1590             :     }
    1591           0 : }
    1592             : 
    1593        2049 : void CSigSharesManager::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig)
    1594             : {
    1595        2049 :     LOCK(cs);
    1596        2049 :     RemoveSigSharesForSession(llmq::utils::BuildSignHash(recoveredSig));
    1597        2049 : }
    1598             : 
    1599             : } // namespace llmq

Generated by: LCOV version 1.14