LCOV - code coverage report
Current view: top level - src/llmq - signing.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 324 354 91.5 %
Date: 2026-06-25 07:23:43 Functions: 49 49 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2018-2025 The Dash Core developers
       2             : // Distributed under the MIT/X11 software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <llmq/signing.h>
       6             : 
       7             : #include <llmq/commitment.h>
       8             : #include <llmq/params.h>
       9             : #include <llmq/quorumsman.h>
      10             : #include <llmq/signhash.h>
      11             : 
      12             : #include <chainparams.h>
      13             : #include <dbwrapper.h>
      14             : #include <streams.h>
      15             : #include <util/system.h>
      16             : 
      17             : #include <algorithm>
      18             : #include <ranges>
      19             : #include <unordered_map>
      20             : #include <unordered_set>
      21             : 
      22             : namespace llmq
      23             : {
      24        9189 : CRecoveredSigsDb::CRecoveredSigsDb(const util::DbWrapperParams& db_params) :
      25        3063 :     db{util::MakeDbWrapper({db_params.path / "llmq" / "recsigdb", db_params.memory, db_params.wipe, /*cache_size=*/8 << 20})}
      26        3063 : {
      27        6126 : }
      28             : 
      29        6126 : CRecoveredSigsDb::~CRecoveredSigsDb() = default;
      30             : 
      31       11309 : bool CRecoveredSigsDb::HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const
      32             : {
      33       11309 :     auto k = std::make_tuple(std::string("rs_r"), llmqType, id, msgHash);
      34       11309 :     return db->Exists(k);
      35       11309 : }
      36             : 
      37      178405 : bool CRecoveredSigsDb::HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) const
      38             : {
      39      178405 :     auto cacheKey = std::make_pair(llmqType, id);
      40             :     bool ret;
      41             :     {
      42      178405 :         LOCK(cs_cache);
      43      178405 :         if (hasSigForIdCache.get(cacheKey, ret)) {
      44      144538 :             return ret;
      45             :         }
      46      178405 :     }
      47             : 
      48             : 
      49       33867 :     auto k = std::make_tuple(std::string("rs_r"), llmqType, id);
      50       33867 :     ret = db->Exists(k);
      51             : 
      52       33867 :     LOCK(cs_cache);
      53       33867 :     hasSigForIdCache.insert(cacheKey, ret);
      54       33867 :     return ret;
      55      178405 : }
      56             : 
      57     1639408 : bool CRecoveredSigsDb::HasRecoveredSigForSession(const uint256& signHash) const
      58             : {
      59             :     bool ret;
      60             :     {
      61     1639408 :         LOCK(cs_cache);
      62     1639408 :         if (hasSigForSessionCache.get(signHash, ret)) {
      63     1625013 :             return ret;
      64             :         }
      65     1639408 :     }
      66             : 
      67       14395 :     auto k = std::make_tuple(std::string("rs_s"), signHash);
      68       14395 :     ret = db->Exists(k);
      69             : 
      70       14395 :     LOCK(cs_cache);
      71       14395 :     hasSigForSessionCache.insert(signHash, ret);
      72       14395 :     return ret;
      73     1639408 : }
      74             : 
      75      153604 : bool CRecoveredSigsDb::HasRecoveredSigForHash(const uint256& hash) const
      76             : {
      77             :     bool ret;
      78             :     {
      79      153604 :         LOCK(cs_cache);
      80      153604 :         if (hasSigForHashCache.get(hash, ret)) {
      81      126336 :             return ret;
      82             :         }
      83      153604 :     }
      84             : 
      85       27268 :     auto k = std::make_tuple(std::string("rs_h"), hash);
      86       27268 :     ret = db->Exists(k);
      87             : 
      88       27268 :     LOCK(cs_cache);
      89       27268 :     hasSigForHashCache.insert(hash, ret);
      90       27268 :     return ret;
      91      153604 : }
      92             : 
      93        9440 : bool CRecoveredSigsDb::ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret) const
      94             : {
      95        9440 :     auto k = std::make_tuple(std::string("rs_r"), llmqType, id);
      96             : 
      97        9440 :     CDataStream ds(SER_DISK, CLIENT_VERSION);
      98        9440 :     if (!db->ReadDataStream(k, ds)) {
      99        2888 :         return false;
     100             :     }
     101             : 
     102             :     try {
     103        6552 :         ret.Unserialize(ds);
     104        6552 :         return true;
     105           0 :     } catch (std::exception&) {
     106           0 :         return false;
     107           0 :     }
     108        9440 : }
     109             : 
     110        2691 : bool CRecoveredSigsDb::GetRecoveredSigByHash(const uint256& hash, CRecoveredSig& ret) const
     111             : {
     112        2691 :     auto k1 = std::make_tuple(std::string("rs_h"), hash);
     113        2691 :     std::pair<Consensus::LLMQType, uint256> k2;
     114        2691 :     if (!db->Read(k1, k2)) {
     115           0 :         return false;
     116             :     }
     117             : 
     118        2691 :     return ReadRecoveredSig(k2.first, k2.second, ret);
     119        2691 : }
     120             : 
     121         137 : bool CRecoveredSigsDb::GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret) const
     122             : {
     123         137 :     return ReadRecoveredSig(llmqType, id, ret);
     124             : }
     125             : 
     126       27218 : void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
     127             : {
     128       27218 :     CDBBatch batch(*db);
     129             : 
     130       27218 :     uint32_t curTime = GetTime<std::chrono::seconds>().count();
     131             : 
     132             :     // we put these close to each other to leverage leveldb's key compaction
     133             :     // this way, the second key can be used for fast HasRecoveredSig checks while the first key stores the recSig
     134       27218 :     auto k1 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId());
     135       27218 :     auto k2 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId(), recSig.getMsgHash());
     136       27218 :     batch.Write(k1, recSig);
     137             :     // this key is also used to store the current time, so that we can easily get to the "rs_t" key when we have the id
     138       27218 :     batch.Write(k2, curTime);
     139             : 
     140             :     // store by object hash
     141       27218 :     auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash());
     142       27218 :     batch.Write(k3, std::make_pair(recSig.getLlmqType(), recSig.getId()));
     143             : 
     144             :     // store by signHash
     145       27218 :     auto signHash = recSig.buildSignHash();
     146       27218 :     auto k4 = std::make_tuple(std::string("rs_s"), signHash.Get());
     147       27214 :     batch.Write(k4, (uint8_t)1);
     148             : 
     149             :     // store by current time. Allows fast cleanup of old recSigs
     150       27218 :     auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t)htobe32_internal(curTime), recSig.getLlmqType(), recSig.getId());
     151       27214 :     batch.Write(k5, (uint8_t)1);
     152             : 
     153       27218 :     db->WriteBatch(batch);
     154             : 
     155             :     {
     156       27218 :         LOCK(cs_cache);
     157       27214 :         hasSigForIdCache.insert(std::make_pair(recSig.getLlmqType(), recSig.getId()), true);
     158       27218 :         hasSigForSessionCache.insert(signHash.Get(), true);
     159       27218 :         hasSigForHashCache.insert(recSig.GetHash(), true);
     160       27222 :     }
     161       27260 : }
     162             : 
     163        6612 : void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, bool deleteTimeKey)
     164             : {
     165        6612 :     CRecoveredSig recSig;
     166        6612 :     if (!ReadRecoveredSig(llmqType, id, recSig)) {
     167        2888 :         return;
     168             :     }
     169             : 
     170        3724 :     auto signHash = recSig.buildSignHash();
     171             : 
     172        3724 :     auto k1 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId());
     173        3724 :     auto k2 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId(), recSig.getMsgHash());
     174        3724 :     auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash());
     175        3724 :     auto k4 = std::make_tuple(std::string("rs_s"), signHash.Get());
     176        3724 :     batch.Erase(k1);
     177        3724 :     batch.Erase(k2);
     178        3724 :     if (deleteHashKey) {
     179        1579 :         batch.Erase(k3);
     180        1579 :         batch.Erase(k4);
     181        1579 :     }
     182             : 
     183        3724 :     if (deleteTimeKey) {
     184           0 :         CDataStream writeTimeDs(SER_DISK, CLIENT_VERSION);
     185           0 :         if (db->ReadDataStream(k2, writeTimeDs)) {
     186             :             uint32_t writeTime;
     187           0 :             writeTimeDs >> writeTime;
     188           0 :             auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t) htobe32_internal(writeTime), recSig.getLlmqType(), recSig.getId());
     189           0 :             batch.Erase(k5);
     190           0 :         }
     191           0 :     }
     192             : 
     193        3724 :     LOCK(cs_cache);
     194        3724 :     hasSigForIdCache.erase(std::make_pair(recSig.getLlmqType(), recSig.getId()));
     195        3724 :     if (deleteHashKey) {
     196        1579 :         hasSigForSessionCache.erase(signHash.Get());
     197        1579 :         hasSigForHashCache.erase(recSig.GetHash());
     198        1579 :     }
     199        6612 : }
     200             : 
     201             : // Remove the recovered sig itself and all keys required to get from id -> recSig
     202             : // This will leave the byHash and signHash key in-place so that HasRecoveredSigForHash /
     203             : // late-share filtering still returns true
     204        5023 : void CRecoveredSigsDb::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
     205             : {
     206        5023 :     CDBBatch batch(*db);
     207        5023 :     RemoveRecoveredSig(batch, llmqType, id, false, false);
     208        5023 :     db->WriteBatch(batch);
     209        5023 : }
     210             : 
     211       17341 : void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
     212             : {
     213       17341 :     std::unique_ptr<CDBIterator> pcursor(db->NewIterator());
     214             : 
     215       17341 :     auto start = std::make_tuple(std::string("rs_t"), (uint32_t)0, (Consensus::LLMQType)0, uint256());
     216       17341 :     uint32_t endTime = (uint32_t)(GetTime<std::chrono::seconds>().count() - maxAge);
     217       17341 :     pcursor->Seek(start);
     218             : 
     219       17341 :     std::vector<std::pair<Consensus::LLMQType, uint256>> toDelete;
     220       17341 :     std::vector<decltype(start)> toDelete2;
     221             : 
     222       18930 :     while (pcursor->Valid()) {
     223        7545 :         decltype(start) k;
     224             : 
     225        7545 :         if (!pcursor->GetKey(k) || std::get<0>(k) != "rs_t") {
     226         112 :             break;
     227             :         }
     228        7433 :         if (be32toh_internal(std::get<1>(k)) >= endTime) {
     229        5844 :             break;
     230             :         }
     231             : 
     232        1589 :         toDelete.emplace_back(std::get<2>(k), std::get<3>(k));
     233        1589 :         toDelete2.emplace_back(k);
     234             : 
     235        1589 :         pcursor->Next();
     236        7545 :     }
     237       17341 :     pcursor.reset();
     238             : 
     239       17341 :     if (toDelete.empty()) {
     240       17314 :         return;
     241             :     }
     242             : 
     243          27 :     CDBBatch batch(*db);
     244        1616 :     for (const auto& e : toDelete) {
     245        1589 :         RemoveRecoveredSig(batch, e.first, e.second, true, false);
     246             : 
     247        1589 :         if (batch.SizeEstimate() >= (1 << 24)) {
     248           0 :             db->WriteBatch(batch);
     249           0 :             batch.Clear();
     250           0 :         }
     251             :     }
     252             : 
     253        1616 :     for (const auto& e : toDelete2) {
     254        1589 :         batch.Erase(e);
     255             :     }
     256             : 
     257          27 :     db->WriteBatch(batch);
     258             : 
     259          27 :     LogPrint(BCLog::LLMQ, "CRecoveredSigsDb::%d -- deleted %d entries\n", __func__, toDelete.size());
     260       17341 : }
     261             : 
     262       19484 : bool CRecoveredSigsDb::HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id) const
     263             : {
     264       19484 :     auto k = std::make_tuple(std::string("rs_v"), llmqType, id);
     265       19484 :     return db->Exists(k);
     266       19484 : }
     267             : 
     268        6565 : bool CRecoveredSigsDb::GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const
     269             : {
     270        6565 :     auto k = std::make_tuple(std::string("rs_v"), llmqType, id);
     271        6565 :     return db->Read(k, msgHashRet);
     272        6565 : }
     273             : 
     274       18322 : void CRecoveredSigsDb::WriteVoteForId(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash)
     275             : {
     276       18322 :     auto k1 = std::make_tuple(std::string("rs_v"), llmqType, id);
     277       18322 :     auto k2 = std::make_tuple(std::string("rs_vt"), (uint32_t)htobe32_internal(GetTime<std::chrono::seconds>().count()), llmqType, id);
     278             : 
     279       18322 :     CDBBatch batch(*db);
     280       18322 :     batch.Write(k1, msgHash);
     281       18322 :     batch.Write(k2, (uint8_t)1);
     282             : 
     283       18322 :     db->WriteBatch(batch);
     284       18322 : }
     285             : 
     286       17341 : void CRecoveredSigsDb::CleanupOldVotes(int64_t maxAge)
     287             : {
     288       17341 :     std::unique_ptr<CDBIterator> pcursor(db->NewIterator());
     289             : 
     290       17341 :     auto start = std::make_tuple(std::string("rs_vt"), (uint32_t)0, (Consensus::LLMQType)0, uint256());
     291       17341 :     uint32_t endTime = (uint32_t)(GetTime<std::chrono::seconds>().count() - maxAge);
     292       17341 :     pcursor->Seek(start);
     293             : 
     294       17341 :     CDBBatch batch(*db);
     295       17341 :     size_t cnt = 0;
     296       18818 :     while (pcursor->Valid()) {
     297        6106 :         decltype(start) k;
     298             : 
     299        6106 :         if (!pcursor->GetKey(k) || std::get<0>(k) != "rs_vt") {
     300           0 :             break;
     301             :         }
     302        6106 :         if (be32toh_internal(std::get<1>(k)) >= endTime) {
     303        4629 :             break;
     304             :         }
     305             : 
     306        1477 :         Consensus::LLMQType llmqType = std::get<2>(k);
     307        1477 :         const uint256& id = std::get<3>(k);
     308             : 
     309        1477 :         batch.Erase(k);
     310        1477 :         batch.Erase(std::make_tuple(std::string("rs_v"), llmqType, id));
     311             : 
     312        1477 :         cnt++;
     313             : 
     314        1477 :         pcursor->Next();
     315        6106 :     }
     316       17341 :     pcursor.reset();
     317             : 
     318       17341 :     if (cnt == 0) {
     319       17316 :         return;
     320             :     }
     321             : 
     322          25 :     db->WriteBatch(batch);
     323             : 
     324          25 :     LogPrint(BCLog::LLMQ, "CRecoveredSigsDb::%d -- deleted %d entries\n", __func__, cnt);
     325       17341 : }
     326             : 
     327             : //////////////////
     328             : 
     329        9189 : CSigningManager::CSigningManager(const CQuorumManager& _qman, const util::DbWrapperParams& db_params,
     330             :                                  int64_t max_recsigs_age) :
     331        3063 :     db{db_params},
     332        3063 :     qman{_qman},
     333        3063 :     m_max_recsigs_age{max_recsigs_age}
     334        3063 : {
     335        6126 : }
     336             : 
     337        6126 : CSigningManager::~CSigningManager() = default;
     338             : 
     339       66254 : bool CSigningManager::AlreadyHave(const CInv& inv) const
     340             : {
     341       66254 :     if (inv.type != MSG_QUORUM_RECOVERED_SIG) {
     342           0 :         return false;
     343             :     }
     344             :     {
     345       66254 :         LOCK(cs_pending);
     346       66254 :         if (pendingReconstructedRecoveredSigs.count(inv.hash)) {
     347           7 :             return true;
     348             :         }
     349       66254 :     }
     350             : 
     351       66247 :     return db.HasRecoveredSigForHash(inv.hash);
     352       66254 : }
     353             : 
     354        2691 : bool CSigningManager::GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret) const
     355             : {
     356        2691 :     if (!db.GetRecoveredSigByHash(hash, ret)) {
     357           0 :         return false;
     358             :     }
     359        2691 :     if (!IsQuorumActive(ret.getLlmqType(), qman, ret.getQuorumHash())) {
     360             :         // we don't want to propagate sigs from inactive quorums
     361           0 :         return false;
     362             :     }
     363        2691 :     return true;
     364        2691 : }
     365             : 
     366       33556 : void CSigningManager::VerifyAndProcessRecoveredSig(NodeId from, std::shared_ptr<CRecoveredSig> recoveredSig)
     367             : {
     368       33556 :     auto llmq_type = recoveredSig->getLlmqType();
     369       33556 :     auto quorum = qman.GetQuorum(llmq_type, recoveredSig->getQuorumHash());
     370             : 
     371       33556 :     if (!quorum) {
     372           0 :         LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found\n", __func__,
     373             :                  recoveredSig->getQuorumHash().ToString());
     374           0 :         return;
     375             :     }
     376       33556 :     if (!IsQuorumActive(llmq_type, qman, quorum->qc->quorumHash)) {
     377           0 :         return;
     378             :     }
     379             : 
     380             :     // It's important to only skip seen *valid* sig shares here. See comment for CBatchedSigShare
     381             :     // We don't receive recovered sigs in batches, but we do batched verification per node on these
     382       33556 :     if (db.HasRecoveredSigForHash(recoveredSig->GetHash())) {
     383        7245 :         return;
     384             :     }
     385             : 
     386       26311 :     LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__,
     387             :              recoveredSig->buildSignHash().ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), from);
     388             : 
     389       26311 :     LOCK(cs_pending);
     390       26311 :     if (pendingReconstructedRecoveredSigs.count(recoveredSig->GetHash())) {
     391             :         // no need to perform full verification
     392           0 :         LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already pending reconstructed sig, signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__,
     393             :                  recoveredSig->buildSignHash().ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), from);
     394           0 :         return;
     395             :     }
     396             : 
     397       26311 :     pendingRecoveredSigs[from].emplace_back(std::move(recoveredSig));
     398       33556 : }
     399             : 
     400      378122 : bool CSigningManager::CollectPendingRecoveredSigsToVerify(
     401             :     size_t maxUniqueSessions, std::unordered_map<NodeId, std::list<std::shared_ptr<const CRecoveredSig>>>& retSigShares,
     402             :     std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CBLSPublicKey, StaticSaltedHasher>& ret_pubkeys)
     403             : {
     404      378122 :     bool more_work{false};
     405             : 
     406             :     {
     407      378122 :         LOCK(cs_pending);
     408      378122 :         if (pendingRecoveredSigs.empty()) {
     409      272479 :             return false;
     410             :         }
     411             : 
     412             :         // TODO: refactor it to remove duplicated code with `CSigSharesManager::CollectPendingSigSharesToVerify`
     413      105643 :         std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
     414      666151 :         IterateNodesRandom(pendingRecoveredSigs, [&]() {
     415      454865 :             return uniqueSignHashes.size() < maxUniqueSessions;
     416      560502 :         }, [&](NodeId nodeId, std::list<std::shared_ptr<const CRecoveredSig>>& ns) {
     417      454859 :             if (ns.empty()) {
     418      428616 :                 return false;
     419             :             }
     420       26243 :             auto& recSig = *ns.begin();
     421             : 
     422       26243 :             bool alreadyHave = db.HasRecoveredSigForHash(recSig->GetHash());
     423       26243 :             if (!alreadyHave) {
     424       22431 :                 uniqueSignHashes.emplace(nodeId, recSig->buildSignHash().Get());
     425       22431 :                 retSigShares[nodeId].emplace_back(recSig);
     426       22431 :             }
     427       26243 :             ns.erase(ns.begin());
     428       26243 :             return !ns.empty();
     429      560502 :         }, rnd);
     430             : 
     431      105643 :         if (retSigShares.empty()) {
     432       93395 :             return false;
     433             :         }
     434             : 
     435       24496 :         more_work = std::any_of(pendingRecoveredSigs.begin(), pendingRecoveredSigs.end(),
     436       76920 :                                 [](const auto& p) { return !p.second.empty(); }) ||
     437       12242 :                     !pendingReconstructedRecoveredSigs.empty();
     438      378122 :     }
     439             : 
     440       51886 :     for (auto& [nodeId, v] : retSigShares) {
     441       39638 :         for (auto it = v.begin(); it != v.end();) {
     442       22431 :             const auto& recSig = *it;
     443             : 
     444       22431 :             auto llmqType = recSig->getLlmqType();
     445       22431 :             auto quorumKey = std::make_pair(recSig->getLlmqType(), recSig->getQuorumHash());
     446       22431 :             if (!ret_pubkeys.count(quorumKey)) {
     447       14027 :                 auto quorum = qman.GetQuorum(llmqType, recSig->getQuorumHash());
     448       14027 :                 if (!quorum) {
     449           0 :                     LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found, node=%d\n", __func__,
     450             :                               recSig->getQuorumHash().ToString(), nodeId);
     451           0 :                     it = v.erase(it);
     452           0 :                     continue;
     453             :                 }
     454       14027 :                 if (!IsQuorumActive(llmqType, qman, quorum->qc->quorumHash)) {
     455           0 :                     LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__,
     456             :                               recSig->getQuorumHash().ToString(), nodeId);
     457           0 :                     it = v.erase(it);
     458           0 :                     continue;
     459             :                 }
     460             : 
     461       14027 :                 ret_pubkeys.emplace(quorumKey, quorum->qc->quorumPublicKey);
     462       14027 :             }
     463             : 
     464       22431 :             ++it;
     465             :         }
     466             :     }
     467             : 
     468       12248 :     return more_work;
     469      378122 : }
     470             : 
     471      378122 : Uint256HashMap<std::shared_ptr<const CRecoveredSig>> CSigningManager::FetchPendingReconstructed()
     472             : {
     473      378122 :     Uint256HashMap<std::shared_ptr<const CRecoveredSig>> tmp;
     474      756244 :     WITH_LOCK(cs_pending, swap(tmp, pendingReconstructedRecoveredSigs));
     475      378122 :     return tmp;
     476      378122 : }
     477             : 
     478             : // signature must be verified already
     479       27558 : bool CSigningManager::ProcessRecoveredSig(const std::shared_ptr<const CRecoveredSig>& recoveredSig)
     480             : {
     481       27558 :     auto llmqType = recoveredSig->getLlmqType();
     482             : 
     483       27558 :     if (db.HasRecoveredSigForHash(recoveredSig->GetHash())) {
     484         309 :         return false;
     485             :     }
     486             : 
     487       27249 :     auto signHash = recoveredSig->buildSignHash();
     488             : 
     489       27249 :     LogPrint(BCLog::LLMQ, "CSigningManager::%s -- valid recSig. signHash=%s, id=%s, msgHash=%s\n", __func__,
     490             :             signHash.ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString());
     491             : 
     492       27249 :     if (db.HasRecoveredSigForId(llmqType, recoveredSig->getId())) {
     493          31 :         CRecoveredSig otherRecoveredSig;
     494          31 :         if (db.GetRecoveredSigById(llmqType, recoveredSig->getId(), otherRecoveredSig)) {
     495          31 :             auto otherSignHash = otherRecoveredSig.buildSignHash();
     496          31 :             if (signHash.Get() != otherSignHash.Get()) {
     497             :                 // this should really not happen, as each masternode is participating in only one vote,
     498             :                 // even if it's a member of multiple quorums. so a majority is only possible on one quorum and one msgHash per id
     499          12 :                 LogPrintf("CSigningManager::%s -- conflicting recoveredSig for signHash=%s, id=%s, msgHash=%s, otherSignHash=%s\n", __func__,
     500             :                           signHash.ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), otherSignHash.ToString());
     501          12 :             } else {
     502             :                 // Looks like we're trying to process a recSig that is already known. This might happen if the same
     503             :                 // recSig comes in through regular QRECSIG messages and at the same time through some other message
     504             :                 // which allowed to reconstruct a recSig (e.g. ISLOCK). In this case, just bail out.
     505             :             }
     506          31 :             return false;
     507             :         } else {
     508             :             // This case is very unlikely. It can only happen when cleanup caused this specific recSig to vanish
     509             :             // between the HasRecoveredSigForId and GetRecoveredSigById call. If that happens, treat it as if we
     510             :             // never had that recSig
     511             :         }
     512          31 :     }
     513             : 
     514       27218 :     db.WriteRecoveredSig(*recoveredSig);
     515       54436 :     WITH_LOCK(cs_pending, pendingReconstructedRecoveredSigs.erase(recoveredSig->GetHash()));
     516             : 
     517       27218 :     return true;
     518       27558 : }
     519             : 
     520       27218 : std::vector<CRecoveredSigsListener*> CSigningManager::GetListeners() const
     521             : {
     522       27218 :     LOCK(cs_listeners);
     523       27218 :     return recoveredSigsListeners;
     524       27218 : }
     525             : 
     526         281 : void CSigningManager::PushReconstructedRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig>& recoveredSig)
     527             : {
     528         281 :     LOCK(cs_pending);
     529         281 :     pendingReconstructedRecoveredSigs.emplace(std::piecewise_construct, std::forward_as_tuple(recoveredSig->GetHash()), std::forward_as_tuple(recoveredSig));
     530         281 : }
     531             : 
     532        5023 : void CSigningManager::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
     533             : {
     534        5023 :     db.TruncateRecoveredSig(llmqType, id);
     535        5023 : }
     536             : 
     537       17341 : void CSigningManager::Cleanup()
     538             : {
     539       17341 :     db.CleanupOldRecoveredSigs(m_max_recsigs_age);
     540       17341 :     db.CleanupOldVotes(m_max_recsigs_age);
     541       17341 : }
     542             : 
     543        2640 : void CSigningManager::RegisterRecoveredSigsListener(CRecoveredSigsListener* l)
     544             : {
     545        2640 :     LOCK(cs_listeners);
     546        2640 :     recoveredSigsListeners.emplace_back(l);
     547        2640 : }
     548             : 
     549        2640 : void CSigningManager::UnregisterRecoveredSigsListener(CRecoveredSigsListener* l)
     550             : {
     551        2640 :     LOCK(cs_listeners);
     552        2640 :     auto itRem = std::remove(recoveredSigsListeners.begin(), recoveredSigsListeners.end(), l);
     553        2640 :     recoveredSigsListeners.erase(itRem, recoveredSigsListeners.end());
     554        2640 : }
     555             : 
     556        9873 : bool CSigningManager::HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const
     557             : {
     558        9873 :     return db.HasRecoveredSig(llmqType, id, msgHash);
     559             : }
     560             : 
     561      123007 : bool CSigningManager::HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) const
     562             : {
     563      123007 :     return db.HasRecoveredSigForId(llmqType, id);
     564             : }
     565             : 
     566     1639408 : bool CSigningManager::HasRecoveredSigForSession(const uint256& signHash) const
     567             : {
     568     1639408 :     return db.HasRecoveredSigForSession(signHash);
     569             : }
     570             : 
     571         106 : bool CSigningManager::GetRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id, llmq::CRecoveredSig& retRecSig) const
     572             : {
     573         106 :     if (!db.GetRecoveredSigById(llmqType, id, retRecSig)) {
     574           0 :         return false;
     575             :     }
     576         106 :     return true;
     577         106 : }
     578             : 
     579        9688 : bool CSigningManager::IsConflicting(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const
     580             : {
     581        9688 :     if (!db.HasRecoveredSigForId(llmqType, id)) {
     582             :         // no recovered sig present, so no conflict
     583        8252 :         return false;
     584             :     }
     585             : 
     586        1436 :     if (!db.HasRecoveredSig(llmqType, id, msgHash)) {
     587             :         // recovered sig is present, but not for the given msgHash. That's a conflict!
     588         703 :         return true;
     589             :     }
     590             : 
     591             :     // all good
     592         733 :     return false;
     593        9688 : }
     594             : 
     595        5436 : bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const
     596             : {
     597        5436 :     return db.GetVoteForId(llmqType, id, msgHashRet);
     598             : }
     599             : 
     600      283724 : SignHash CSigBase::buildSignHash() const { return SignHash(llmqType, quorumHash, id, msgHash); }
     601             : 
     602             : 
     603       78963 : bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, const uint256& quorumHash)
     604             : {
     605             :     // sig shares and recovered sigs are only accepted from recent/active quorums
     606             :     // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
     607             :     // fail while we are on the brink of a new quorum
     608       78963 :     const auto& llmq_params_opt = Params().GetLLMQ(llmqType);
     609       78963 :     assert(llmq_params_opt.has_value());
     610       78963 :     auto quorums = qman.ScanQuorums(llmqType, llmq_params_opt->keepOldConnections);
     611      203684 :     return std::ranges::any_of(quorums, [&quorumHash](const auto& q) { return q->qc->quorumHash == quorumHash; });
     612       78963 : }
     613             : 
     614             : } // namespace llmq

Generated by: LCOV version 1.16