LCOV - code coverage report
Current view: top level - src/llmq - quorums_signing_shares.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 131 883 14.8 %
Date: 2026-08-09 10:51:41 Functions: 16 64 25.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           0 : void CSigShare::UpdateKey()
      29             : {
      30           0 :     key.first = llmq::utils::BuildSignHash(*this);
      31           0 :     key.second = quorumMember;
      32           0 : }
      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           0 : void CSigSharesNodeState::RemoveSession(const uint256& signHash)
     177             : {
     178           0 :     auto it = sessions.find(signHash);
     179           0 :     if (it != sessions.end()) {
     180           0 :         sessionByRecvId.erase(it->second.recvSessionId);
     181           0 :         sessions.erase(it);
     182             :     }
     183           0 :     requestedSigShares.EraseAllForSignHash(signHash);
     184           0 :     pendingIncomingSigShares.EraseAllForSignHash(signHash);
     185           0 : }
     186             : 
     187             : //////////////////////
     188             : 
     189         413 : CSigSharesManager::CSigSharesManager()
     190             : {
     191         413 :     interruptSigningShare.reset();
     192         413 : }
     193             : 
     194         826 : CSigSharesManager::~CSigSharesManager()
     195             : {
     196         826 : }
     197             : 
     198         285 : void CSigSharesManager::StartWorkerThread()
     199             : {
     200         285 :     workThread = std::thread(&TraceThread<std::function<void()>>, "quorum-sigshares", std::function<void()>(std::bind(&CSigSharesManager::WorkThreadMain, this)));
     201         285 : }
     202             : 
     203         295 : void CSigSharesManager::StopWorkerThread()
     204             : {
     205         295 :     if (workThread.joinable()) {
     206         285 :         workThread.join();
     207             :     }
     208         295 : }
     209             : 
     210         285 : void CSigSharesManager::RegisterAsRecoveredSigsListener()
     211             : {
     212         285 :     quorumSigningManager->RegisterRecoveredSigsListener(this);
     213         285 : }
     214             : 
     215         295 : void CSigSharesManager::UnregisterAsRecoveredSigsListener()
     216             : {
     217         295 :     quorumSigningManager->UnregisterRecoveredSigsListener(this);
     218         295 : }
     219             : 
     220         413 : void CSigSharesManager::Interrupt()
     221             : {
     222         413 :     interruptSigningShare();
     223         413 : }
     224             : 
     225           0 : void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
     226             : {
     227             :     // non-masternodes are not interested in sigshares
     228           0 :     if (!activeMasternodeManager) {
     229             :         return;
     230             :     }
     231             : 
     232           0 :     if (strCommand == NetMsgType::QSIGSHARE) {
     233           0 :         std::vector<CSigShare> sigShares;
     234           0 :         vRecv >> sigShares;
     235             : 
     236           0 :         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           0 :         for (auto& sigShare : sigShares) {
     243           0 :             ProcessMessageSigShare(pfrom->GetId(), sigShare, connman);
     244             :         }
     245             :     }
     246             : 
     247           0 :     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           0 :     } 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           0 :     } 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           0 :     } 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           0 : void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare, CConnman& connman)
     477             : {
     478           0 :     auto quorum = quorumManager->GetQuorum((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash);
     479           0 :     if (!quorum) {
     480           0 :         return;
     481             :     }
     482           0 :     if (!llmq::utils::IsQuorumActive((Consensus::LLMQType)sigShare.llmqType, quorum->qc.quorumHash)) {
     483             :         // quorum is too old
     484             :         return;
     485             :     }
     486           0 :     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           0 :     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           0 :     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           0 :     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           0 :     {
     509           0 :         LOCK(cs);
     510             : 
     511           0 :         if (sigShares.Has(sigShare.GetKey())) {
     512           0 :             return;
     513             :         }
     514             : 
     515           0 :         if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) {
     516             :             return;
     517             :         }
     518             : 
     519           0 :         auto& nodeState = nodeStates[fromId];
     520           0 :         nodeState.pendingIncomingSigShares.Add(sigShare.GetKey(), sigShare);
     521             :     }
     522             : 
     523           0 :     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       66233 : 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       66233 :     {
     575       66233 :         LOCK(cs);
     576       66233 :         if (nodeStates.empty()) {
     577       66233 :             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           0 :         std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
     587           0 :         llmq::utils::IterateNodesRandom(nodeStates, [&]() { return uniqueSignHashes.size() < maxUniqueSessions; }, [&](NodeId nodeId, CSigSharesNodeState& ns) {
     588           0 :             if (ns.pendingIncomingSigShares.Empty()) {
     589             :                 return false;
     590             :             }
     591           0 :             auto& sigShare = *ns.pendingIncomingSigShares.GetFirst();
     592             : 
     593           0 :             bool alreadyHave = this->sigShares.Has(sigShare.GetKey());
     594           0 :             if (!alreadyHave) {
     595           0 :                 uniqueSignHashes.emplace(nodeId, sigShare.GetSignHash());
     596           0 :                 retSigShares[nodeId].emplace_back(sigShare);
     597             :             }
     598           0 :             ns.pendingIncomingSigShares.Erase(sigShare.GetKey());
     599           0 :             return !ns.pendingIncomingSigShares.Empty(); }, rnd);
     600             : 
     601           0 :         if (retSigShares.empty()) {
     602       66233 :             return;
     603             :         }
     604             :     }
     605             : 
     606           0 :     {
     607           0 :         LOCK(cs_main);
     608             : 
     609             :         // For the convenience of the caller, also build a map of quorumHash -> quorum
     610             : 
     611           0 :         for (auto& p : retSigShares) {
     612           0 :             for (auto& sigShare : p.second) {
     613           0 :                 auto llmqType = (Consensus::LLMQType)sigShare.llmqType;
     614             : 
     615           0 :                 auto k = std::make_pair(llmqType, sigShare.quorumHash);
     616           0 :                 if (retQuorums.count(k)) {
     617           0 :                     continue;
     618             :                 }
     619             : 
     620           0 :                 CQuorumCPtr quorum = quorumManager->GetQuorum(llmqType, sigShare.quorumHash);
     621           0 :                 assert(quorum != nullptr);
     622           0 :                 retQuorums.emplace(k, quorum);
     623             :             }
     624             :         }
     625             :     }
     626             : }
     627             : 
     628       66233 : bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
     629             : {
     630      132466 :     std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesByNodes;
     631       66233 :     std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
     632             : 
     633       66233 :     CollectPendingSigSharesToVerify(32, sigSharesByNodes, quorums);
     634       66233 :     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           0 :     CBLSBatchVerifier<NodeId, SigShareKey> batchVerifier(false, true);
     641             : 
     642           0 :     cxxtimer::Timer prepareTimer(true);
     643           0 :     size_t verifyCount = 0;
     644           0 :     for (auto& p : sigSharesByNodes) {
     645           0 :         auto nodeId = p.first;
     646           0 :         auto& v = p.second;
     647             : 
     648           0 :         for (auto& sigShare : v) {
     649           0 :             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           0 :             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           0 :             auto quorum = quorums.at(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash));
     662           0 :             auto pubKeyShare = quorum->GetPubKeyShare(sigShare.quorumMember);
     663             : 
     664           0 :             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           0 :             batchVerifier.PushMessage(nodeId, sigShare.GetKey(), sigShare.GetSignHash(), sigShare.sigShare.Get(), pubKeyShare);
     672           0 :             verifyCount++;
     673             :         }
     674             :     }
     675           0 :     prepareTimer.stop();
     676             : 
     677           0 :     cxxtimer::Timer verifyTimer(true);
     678           0 :     batchVerifier.Verify();
     679           0 :     verifyTimer.stop();
     680             : 
     681           0 :     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           0 :     for (auto& p : sigSharesByNodes) {
     684           0 :         auto nodeId = p.first;
     685           0 :         auto& v = p.second;
     686             : 
     687           0 :         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           0 :         ProcessPendingSigSharesFromNode(nodeId, v, quorums, connman);
     696             :     }
     697             : 
     698           0 :     return true;
     699             : }
     700             : 
     701             : // It's ensured that no duplicates are passed to this method
     702           0 : 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           0 :     LOCK(cs);
     708           0 :     auto& nodeState = nodeStates[nodeId];
     709             : 
     710           0 :     cxxtimer::Timer t(true);
     711           0 :     for (auto& sigShare : sigShares) {
     712           0 :         auto quorumKey = std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash);
     713           0 :         ProcessSigShare(nodeId, sigShare, connman, quorums.at(quorumKey));
     714             :     }
     715           0 :     t.stop();
     716             : 
     717           0 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- processed sigShare batch. shares=%d, time=%d, node=%d\n", __func__,
     718             :         sigShares.size(), t.count(), nodeId);
     719           0 : }
     720             : 
     721             : // sig shares are already verified when entering this method
     722           0 : void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare, CConnman& connman, const CQuorumCPtr& quorum)
     723             : {
     724           0 :     auto llmqType = quorum->params.type;
     725             : 
     726           0 :     bool canTryRecovery = false;
     727             : 
     728             :     // prepare node set for direct-push in case this is our sig share
     729           0 :     std::set<NodeId> quorumNodes;
     730             : 
     731           0 :     if (quorumSigningManager->HasRecoveredSigForId(llmqType, sigShare.id)) {
     732           0 :         return;
     733             :     }
     734             : 
     735           0 :     {
     736           0 :         LOCK(cs);
     737             : 
     738           0 :         if (!sigShares.Add(sigShare.GetKey(), sigShare)) {
     739           0 :             return;
     740             :         }
     741           0 :         sigSharesToAnnounce.Add(sigShare.GetKey(), true);
     742             : 
     743             :         // Update the time we've seen the last sigShare
     744           0 :         timeSeenForSessions[sigShare.GetSignHash()] = GetAdjustedTime();
     745             : 
     746             :         // TODO: unreachable
     747           0 :         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           0 :         size_t sigShareCount = sigShares.CountForSignHash(sigShare.GetSignHash());
     760           0 :         if (sigShareCount >= quorum->params.threshold) {
     761           0 :             canTryRecovery = true;
     762             :         }
     763             :     }
     764             : 
     765           0 :     if (canTryRecovery) {
     766           0 :         TryRecoverSig(quorum, sigShare.id, sigShare.msgHash, connman);
     767             :     }
     768             : }
     769             : 
     770           0 : void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash, CConnman& connman)
     771             : {
     772           0 :     if (quorumSigningManager->HasRecoveredSigForId(quorum->params.type, id)) {
     773           0 :         return;
     774             :     }
     775             : 
     776           0 :     std::vector<CBLSSignature> sigSharesForRecovery;
     777           0 :     std::vector<CBLSId> idsForRecovery;
     778           0 :     {
     779           0 :         LOCK(cs);
     780             : 
     781           0 :         auto k = std::make_pair(quorum->params.type, id);
     782             : 
     783           0 :         auto signHash = llmq::utils::BuildSignHash(quorum->params.type, quorum->qc.quorumHash, id, msgHash);
     784           0 :         auto sigShares = this->sigShares.GetAllForSignHash(signHash);
     785           0 :         if (!sigShares) {
     786           0 :             return;
     787             :         }
     788             : 
     789           0 :         sigSharesForRecovery.reserve((size_t)quorum->params.threshold);
     790           0 :         idsForRecovery.reserve((size_t)quorum->params.threshold);
     791           0 :         for (auto it = sigShares->begin(); it != sigShares->end() && sigSharesForRecovery.size() < quorum->params.threshold; ++it) {
     792           0 :             auto& sigShare = it->second;
     793           0 :             sigSharesForRecovery.emplace_back(sigShare.sigShare.Get());
     794           0 :             idsForRecovery.emplace_back(CBLSId(quorum->members[sigShare.quorumMember]->proTxHash));
     795             :         }
     796             : 
     797             :         // check if we can recover the final signature
     798           0 :         if (sigSharesForRecovery.size() < quorum->params.threshold) {
     799             :             return;
     800             :         }
     801             :     }
     802             : 
     803             :     // now recover it
     804           0 :     cxxtimer::Timer t(true);
     805           0 :     CBLSSignature recoveredSig;
     806           0 :     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           0 :     LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- recovered signature. id=%s, msgHash=%s, time=%d\n", __func__,
     813             :         id.ToString(), msgHash.ToString(), t.count());
     814             : 
     815           0 :     CRecoveredSig rs;
     816           0 :     rs.llmqType = quorum->params.type;
     817           0 :     rs.quorumHash = quorum->qc.quorumHash;
     818           0 :     rs.id = id;
     819           0 :     rs.msgHash = msgHash;
     820           0 :     rs.sig.Set(recoveredSig);
     821           0 :     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           0 :     if (((recoveredSigsCounter++) % 100) == 0) {
     827           0 :         auto signHash = llmq::utils::BuildSignHash(rs);
     828           0 :         bool valid = recoveredSig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash);
     829           0 :         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           0 :     quorumSigningManager->ProcessRecoveredSig(-1, rs, quorum, connman);
     838             : }
     839             : 
     840           0 : CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256& id, int attempt)
     841             : {
     842           0 :     assert(attempt < quorum->members.size());
     843             : 
     844           0 :     std::vector<std::pair<uint256, CDeterministicMNCPtr>> v;
     845           0 :     v.reserve(quorum->members.size());
     846           0 :     for (const auto& dmn : quorum->members) {
     847           0 :         auto h = ::SerializeHash(std::make_pair(dmn->proTxHash, id));
     848           0 :         v.emplace_back(h, dmn);
     849             :     }
     850           0 :     std::sort(v.begin(), v.end());
     851             : 
     852           0 :     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       43062 : void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::vector<CSigShare>>& sigSharesToSend, const std::vector<CNode*>& vNodes)
    1006             : {
    1007       43062 :     AssertLockHeld(cs);
    1008             : 
    1009       43062 :     std::unordered_map<uint256, CNode*> proTxToNode;
    1010      110554 :     for (const auto& pnode : vNodes) {
    1011      134984 :         if (pnode->verifiedProRegTxHash.IsNull()) {
    1012       67492 :             continue;
    1013             :         }
    1014       67492 :         proTxToNode.emplace(pnode->verifiedProRegTxHash, pnode);
    1015             :     }
    1016             : 
    1017       43062 :     auto curTime = GetTime<std::chrono::milliseconds>().count();
    1018             : 
    1019       43062 :     for (auto& p : signedSessions) {
    1020           0 :         if (p.second.attempt >= p.second.quorum->params.recoveryMembers) {
    1021           0 :             continue;
    1022             :         }
    1023             : 
    1024           0 :         if (curTime >= p.second.nextAttemptTime) {
    1025           0 :             int64_t waitTime = exp2(p.second.attempt) * EXP_SEND_FOR_RECOVERY_TIMEOUT;
    1026           0 :             waitTime = std::min(MAX_SEND_FOR_RECOVERY_TIMEOUT, waitTime);
    1027           0 :             p.second.nextAttemptTime = curTime + waitTime;
    1028           0 :             auto dmn = SelectMemberForRecovery(p.second.quorum, p.second.sigShare.id, p.second.attempt);
    1029           0 :             p.second.attempt++;
    1030             : 
    1031           0 :             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           0 :             auto it = proTxToNode.find(dmn->proTxHash);
    1035           0 :             if (it == proTxToNode.end()) {
    1036           0 :                 continue;
    1037             :             }
    1038             : 
    1039           0 :             auto& m = sigSharesToSend[it->second->GetId()];
    1040           0 :             m.emplace_back(p.second.sigShare);
    1041             :         }
    1042             :     }
    1043       43062 : }
    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       43062 : bool CSigSharesManager::SendMessages()
    1099             : {
    1100       43062 :     std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToRequest;
    1101       43062 :     std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>> sigShareBatchesToSend;
    1102       43062 :     std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesToSend;
    1103       43062 :     std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToAnnounce;
    1104       43062 :     std::unordered_map<NodeId, std::vector<CSigSesAnn>> sigSessionAnnouncements;
    1105             : 
    1106       43062 :     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       43062 :     };
    1124             : 
    1125       86124 :     std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector(CConnman::FullyConnectedOnly);
    1126             : 
    1127       43062 :     {
    1128       43062 :         LOCK(cs);
    1129       43062 :         CollectSigSharesToSend(sigSharesToSend, vNodesCopy);
    1130             : 
    1131       43062 :         for (auto& p : sigSharesToRequest) {
    1132           0 :             for (auto& p2 : p.second) {
    1133           0 :                 p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
    1134             :             }
    1135             :         }
    1136       43062 :         for (auto& p : sigShareBatchesToSend) {
    1137           0 :             for (auto& p2 : p.second) {
    1138           0 :                 p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
    1139             :             }
    1140             :         }
    1141       43062 :         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       43062 :     bool didSend = false;
    1149             : 
    1150      110554 :     for (auto& pnode : vNodesCopy) {
    1151       67492 :         CNetMsgMaker msgMaker(pnode->GetSendVersion());
    1152             : 
    1153       67492 :         auto it1 = sigSessionAnnouncements.find(pnode->GetId());
    1154       67492 :         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       67492 :         auto it = sigSharesToRequest.find(pnode->GetId());
    1174       67492 :         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       67492 :         auto jt = sigShareBatchesToSend.find(pnode->GetId());
    1194       67492 :         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       67492 :         auto kt = sigSharesToAnnounce.find(pnode->GetId());
    1217       67492 :         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       67492 :         auto lt = sigSharesToSend.find(pnode->GetId());
    1237       67492 :         if (lt != sigSharesToSend.end()) {
    1238           0 :             std::vector<CSigShare> msgs;
    1239           0 :             for (auto& sigShare : lt->second) {
    1240           0 :                 LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSHARE signHash=%s, node=%d\n",
    1241             :                     sigShare.GetSignHash().ToString(), pnode->GetId());
    1242           0 :                 msgs.emplace_back(std::move(sigShare));
    1243           0 :                 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           0 :             if (!msgs.empty()) {
    1250           0 :                 g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs), false);
    1251           0 :                 didSend = true;
    1252             :             }
    1253             :         }
    1254             :     }
    1255             : 
    1256             :     // looped through all nodes, release them
    1257       43062 :     g_connman->ReleaseNodeVector(vNodesCopy);
    1258             : 
    1259       86124 :     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       66233 : void CSigSharesManager::Cleanup()
    1284             : {
    1285       66233 :     int64_t now = GetAdjustedTime();
    1286       66233 :     if (now - lastCleanupTime < 5) {
    1287       63489 :         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        5488 :     std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
    1295             : 
    1296        2744 :     {
    1297        2744 :         LOCK(cs);
    1298        2744 :         sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
    1299           0 :             quorums.emplace(std::make_pair((Consensus::LLMQType) sigShare.llmqType, sigShare.quorumHash), nullptr);
    1300           0 :         });
    1301             :     }
    1302             : 
    1303             :     // Find quorums which became inactive
    1304        2744 :     for (auto it = quorums.begin(); it != quorums.end(); ) {
    1305           0 :         if (llmq::utils::IsQuorumActive(it->first.first, it->first.second)) {
    1306           0 :             it->second = quorumManager->GetQuorum(it->first.first, it->first.second);
    1307        2744 :             ++it;
    1308             :         } else {
    1309           0 :             it = quorums.erase(it);
    1310             :         }
    1311             :     }
    1312             : 
    1313        2744 :     {
    1314             :         // Now delete sessions which are for inactive quorums
    1315        2744 :         LOCK(cs);
    1316        5488 :         std::unordered_set<uint256, StaticSaltedHasher> inactiveQuorumSessions;
    1317        2744 :         sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
    1318           0 :             if (!quorums.count(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash))) {
    1319           0 :                 inactiveQuorumSessions.emplace(sigShare.GetSignHash());
    1320             :             }
    1321           0 :         });
    1322        2744 :         for (auto& signHash : inactiveQuorumSessions) {
    1323           0 :             RemoveSigSharesForSession(signHash);
    1324             :         }
    1325             :     }
    1326             : 
    1327        2744 :     {
    1328        2744 :         LOCK(cs);
    1329             : 
    1330             :         // Remove sessions which were successfully recovered
    1331        5488 :         std::unordered_set<uint256, StaticSaltedHasher> doneSessions;
    1332        2744 :         sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
    1333           0 :             if (doneSessions.count(sigShare.GetSignHash())) {
    1334             :                 return;
    1335             :             }
    1336           0 :             if (quorumSigningManager->HasRecoveredSigForSession(sigShare.GetSignHash())) {
    1337           0 :                 doneSessions.emplace(sigShare.GetSignHash());
    1338             :             }
    1339             :         });
    1340        2744 :         for (auto& signHash : doneSessions) {
    1341           0 :             RemoveSigSharesForSession(signHash);
    1342             :         }
    1343             : 
    1344             :         // Remove sessions which timed out
    1345        5488 :         std::unordered_set<uint256, StaticSaltedHasher> timeoutSessions;
    1346        2744 :         for (auto& p : timeSeenForSessions) {
    1347           0 :             auto& signHash = p.first;
    1348           0 :             int64_t lastSeenTime = p.second;
    1349             : 
    1350           0 :             if (now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) {
    1351           0 :                 timeoutSessions.emplace(signHash);
    1352             :             }
    1353             :         }
    1354        2744 :         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        5488 :     std::unordered_set<NodeId> nodeStatesToDelete;
    1389        2744 :     for (auto& p : nodeStates) {
    1390           0 :         nodeStatesToDelete.emplace(p.first);
    1391             :     }
    1392        2744 :     g_connman->ForEachNode([&](CNode* pnode) {
    1393        3810 :         nodeStatesToDelete.erase(pnode->GetId());
    1394        3810 :     });
    1395             : 
    1396             :     // Now delete these node states
    1397        5488 :     LOCK(cs);
    1398        2744 :     for (auto nodeId : nodeStatesToDelete) {
    1399           0 :         auto& nodeState = nodeStates[nodeId];
    1400             :         // remove global requested state to force a re-request from another node
    1401           0 :         nodeState.requestedSigShares.ForEach([&](const SigShareKey& k, bool) {
    1402           0 :             sigSharesRequested.Erase(k);
    1403             :         });
    1404           0 :         nodeStates.erase(nodeId);
    1405             :     }
    1406             : 
    1407        2744 :     lastCleanupTime = GetAdjustedTime();
    1408             : }
    1409             : 
    1410           0 : void CSigSharesManager::RemoveSigSharesForSession(const uint256& signHash)
    1411             : {
    1412           0 :     for (auto& p : nodeStates) {
    1413           0 :         auto& ns = p.second;
    1414           0 :         ns.RemoveSession(signHash);
    1415             :     }
    1416             : 
    1417           0 :     sigSharesRequested.EraseAllForSignHash(signHash);
    1418           0 :     sigSharesToAnnounce.EraseAllForSignHash(signHash);
    1419           0 :     sigShares.EraseAllForSignHash(signHash);
    1420           0 :     signedSessions.erase(signHash);
    1421           0 :     timeSeenForSessions.erase(signHash);
    1422           0 : }
    1423             : 
    1424       66233 : void CSigSharesManager::RemoveBannedNodeStates()
    1425             : {
    1426             :     // Called regularly to cleanup local node states for banned nodes
    1427             : 
    1428      132466 :     LOCK2(cs, cs_main);
    1429      132466 :     std::unordered_set<NodeId> toRemove;
    1430       66233 :     for (auto it = nodeStates.begin(); it != nodeStates.end();) {
    1431           0 :         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       66233 :             ++it;
    1439             :         }
    1440             :     }
    1441       66233 : }
    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         285 : void CSigSharesManager::WorkThreadMain()
    1471             : {
    1472         285 :     int64_t lastSendTime = 0;
    1473       66233 :     while (!interruptSigningShare) {
    1474       66233 :         bool didWork = false;
    1475             : 
    1476       66233 :         RemoveBannedNodeStates();
    1477       66233 :         didWork |= quorumSigningManager->ProcessPendingRecoveredSigs(*g_connman);
    1478       66233 :         didWork |= ProcessPendingSigShares(*g_connman);
    1479       66233 :         didWork |= SignPendingSigShares();
    1480             : 
    1481       66233 :         if (GetTimeMillis() - lastSendTime > 100) {
    1482       43062 :             SendMessages();
    1483       43062 :             lastSendTime = GetTimeMillis();
    1484             :         }
    1485             : 
    1486       66233 :         Cleanup();
    1487       66233 :         quorumSigningManager->Cleanup();
    1488             : 
    1489             :         // TODO Wakeup when pending signing is needed?
    1490       66233 :         if (!didWork) {
    1491       66233 :             if (!interruptSigningShare.sleep_for(std::chrono::milliseconds(100))) {
    1492             :                 return;
    1493             :             }
    1494             :         }
    1495             :     }
    1496             : }
    1497             : 
    1498           0 : void CSigSharesManager::AsyncSign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash)
    1499             : {
    1500           0 :     LOCK(cs);
    1501           0 :     pendingSigns.emplace_back(quorum, id, msgHash);
    1502           0 : }
    1503             : 
    1504       66233 : bool CSigSharesManager::SignPendingSigShares()
    1505             : {
    1506      132466 :     std::vector<std::tuple<const CQuorumCPtr, uint256, uint256>> v;
    1507       66233 :     {
    1508       66233 :         LOCK(cs);
    1509       66233 :         v = std::move(pendingSigns);
    1510             :     }
    1511             : 
    1512       66233 :     for (auto& t : v) {
    1513           0 :         Sign(std::get<0>(t), std::get<1>(t), std::get<2>(t));
    1514             :     }
    1515             : 
    1516       66233 :     return !v.empty();
    1517             : }
    1518             : 
    1519           0 : void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash)
    1520             : {
    1521           0 :     cxxtimer::Timer t(true);
    1522             : 
    1523           0 :     if (!quorum->IsValidMember(activeMasternodeManager->GetProTx())) {
    1524           0 :         return;
    1525             :     }
    1526             : 
    1527           0 :     CBLSSecretKey skShare = quorum->GetSkShare();
    1528           0 :     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           0 :     int memberIdx = quorum->GetMemberIndex(activeMasternodeManager->GetProTx());
    1534           0 :     if (memberIdx == -1) {
    1535             :         // this should really not happen (IsValidMember gave true)
    1536             :         return;
    1537             :     }
    1538             : 
    1539           0 :     CSigShare sigShare;
    1540           0 :     sigShare.llmqType = quorum->params.type;
    1541           0 :     sigShare.quorumHash = quorum->qc.quorumHash;
    1542           0 :     sigShare.id = id;
    1543           0 :     sigShare.msgHash = msgHash;
    1544           0 :     sigShare.quorumMember = (uint16_t)memberIdx;
    1545           0 :     uint256 signHash = llmq::utils::BuildSignHash(sigShare);
    1546             : 
    1547           0 :     sigShare.sigShare.Set(skShare.Sign(signHash));
    1548           0 :     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           0 :     sigShare.UpdateKey();
    1555             : 
    1556           0 :     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           0 :     ProcessSigShare(-1, sigShare, *g_connman, quorum);
    1559             : 
    1560           0 :     LOCK(cs);
    1561           0 :     auto& session = signedSessions[sigShare.GetSignHash()];
    1562           0 :     session.sigShare = sigShare;
    1563           0 :     session.quorum = quorum;
    1564           0 :     session.nextAttemptTime = 0;
    1565           0 :     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           0 : void CSigSharesManager::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig)
    1594             : {
    1595           0 :     LOCK(cs);
    1596           0 :     RemoveSigSharesForSession(llmq::utils::BuildSignHash(recoveredSig));
    1597           0 : }
    1598             : 
    1599             : } // namespace llmq

Generated by: LCOV version 1.14