LCOV - code coverage report
Current view: top level - src/llmq - quorums.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 118 136 86.8 %
Date: 2026-06-25 07:23:43 Functions: 17 17 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2018-2026 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <llmq/quorums.h>
       6             : 
       7             : #include <evo/deterministicmns.h>
       8             : #include <llmq/commitment.h>
       9             : #include <util/helpers.h>
      10             : 
      11             : #include <dbwrapper.h>
      12             : 
      13             : #include <memory>
      14             : #include <ranges>
      15             : 
      16             : namespace llmq {
      17             : const std::string DB_QUORUM_SK_SHARE = "q_Qsk";
      18             : const std::string DB_QUORUM_QUORUM_VVEC = "q_Qqvvec";
      19             : 
      20        7370 : uint256 MakeQuorumKey(const CQuorum& q)
      21             : {
      22        7370 :     CHashWriter hw(SER_NETWORK, 0);
      23        7370 :     hw << q.params.type;
      24        7370 :     hw << q.qc->quorumHash;
      25       34793 :     for (const auto& dmn : q.members) {
      26       27423 :         hw << dmn->proTxHash;
      27             :     }
      28        7370 :     return hw.GetHash();
      29             : }
      30             : 
      31        6016 : void DataCleanupHelper(CDBWrapper& db, const Uint256HashSet& skip_list, bool compact)
      32             : {
      33        6016 :     const auto prefixes = {DB_QUORUM_QUORUM_VVEC, DB_QUORUM_SK_SHARE};
      34             : 
      35        6016 :     CDBBatch batch(db);
      36        6016 :     std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
      37             : 
      38       11860 :     for (const auto& prefix : prefixes) {
      39        8938 :         auto start = std::make_tuple(prefix, uint256());
      40        8938 :         pcursor->Seek(start);
      41             : 
      42        5844 :         int count{0};
      43        7543 :         while (pcursor->Valid()) {
      44        1699 :             decltype(start) k;
      45             : 
      46        1699 :             if (!pcursor->GetKey(k) || std::get<0>(k) != prefix) {
      47        1547 :                 break;
      48             :             }
      49             : 
      50         152 :             pcursor->Next();
      51             : 
      52         152 :             if (skip_list.find(std::get<1>(k)) != skip_list.end()) continue;
      53             : 
      54           0 :             ++count;
      55           0 :             batch.Erase(k);
      56             : 
      57           0 :             if (batch.SizeEstimate() >= (1 << 24)) {
      58           0 :                 db.WriteBatch(batch);
      59           0 :                 batch.Clear();
      60           0 :             }
      61        1699 :         }
      62             : 
      63        4297 :         db.WriteBatch(batch);
      64             : 
      65        5844 :         LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- %s removed %d\n", __func__, prefix, count);
      66        5844 :     }
      67             : 
      68        2922 :     pcursor.reset();
      69             : 
      70        2922 :     if (compact) {
      71             :         // Avoid using this on regular cleanups, use on db migrations only
      72           0 :         LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- compact start\n", __func__);
      73           0 :         db.CompactFull();
      74           0 :         LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- compact end\n", __func__);
      75           0 :     }
      76       21486 : }
      77             : 
      78          19 : std::string CQuorumDataRequest::GetErrorString() const
      79             : {
      80          19 :     switch (nError) {
      81             :         case (Errors::NONE):
      82           0 :             return "NONE";
      83             :         case (Errors::QUORUM_TYPE_INVALID):
      84           0 :             return "QUORUM_TYPE_INVALID";
      85             :         case (Errors::QUORUM_BLOCK_NOT_FOUND):
      86           0 :             return "QUORUM_BLOCK_NOT_FOUND";
      87             :         case (Errors::QUORUM_NOT_FOUND):
      88           0 :             return "QUORUM_NOT_FOUND";
      89             :         case (Errors::MASTERNODE_IS_NO_MEMBER):
      90           0 :             return "MASTERNODE_IS_NO_MEMBER";
      91             :         case (Errors::QUORUM_VERIFICATION_VECTOR_MISSING):
      92          11 :             return "QUORUM_VERIFICATION_VECTOR_MISSING";
      93             :         case (Errors::ENCRYPTED_CONTRIBUTIONS_MISSING):
      94           8 :             return "ENCRYPTED_CONTRIBUTIONS_MISSING";
      95             :         case (Errors::UNDEFINED):
      96           0 :             return "UNDEFINED";
      97             :         default:
      98           0 :             return "UNDEFINED";
      99             :     }
     100             :     return "UNDEFINED";
     101          19 : }
     102             : 
     103       10710 : CQuorum::CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker,
     104             :                  CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex,
     105             :                  const uint256& _minedBlockHash, Span<CDeterministicMNCPtr> _members) :
     106        5355 :     params{_params},
     107        5355 :     qc{std::move(_qc)},
     108        5355 :     m_quorum_base_block_index{_pQuorumBaseBlockIndex},
     109        5355 :     minedBlockHash{_minedBlockHash},
     110        5355 :     members{_members.begin(), _members.end()},
     111        5355 :     blsCache{_blsWorker}
     112        5355 : {
     113             :     assert(qc != nullptr);
     114             :     assert(m_quorum_base_block_index != nullptr);
     115        5355 : }
     116             : 
     117         130 : bool CQuorum::SetVerificationVector(const std::vector<CBLSPublicKey>& quorumVecIn)
     118             : {
     119         130 :     const auto quorumVecInSerialized = ::SerializeHash(quorumVecIn);
     120             : 
     121         130 :     LOCK(cs_vvec_shShare);
     122         130 :     if (quorumVecInSerialized != qc->quorumVvecHash) {
     123           0 :         return false;
     124             :     }
     125         130 :     quorumVvec = std::make_shared<std::vector<CBLSPublicKey>>(quorumVecIn);
     126         130 :     return true;
     127         130 : }
     128             : 
     129        1933 : bool CQuorum::SetSecretKeyShare(const CBLSSecretKey& secretKeyShare, const uint256& protx_hash)
     130             : {
     131        1933 :     if (protx_hash.IsNull() || !secretKeyShare.IsValid() || (secretKeyShare.GetPublicKey() != GetPubKeyShare(GetMemberIndex(protx_hash)))) {
     132          20 :         return false;
     133             :     }
     134        1913 :     LOCK(cs_vvec_shShare);
     135        1913 :     skShare = secretKeyShare;
     136        1913 :     return true;
     137        1933 : }
     138             : 
     139       87454 : bool CQuorum::IsMember(const uint256& proTxHash) const
     140             : {
     141      357720 :     return std::ranges::any_of(members, [&proTxHash](const auto& dmn) { return dmn->proTxHash == proTxHash; });
     142             : }
     143             : 
     144      392845 : bool CQuorum::IsValidMember(const uint256& proTxHash) const
     145             : {
     146     1270264 :     for (const auto i : util::irange(members.size())) {
     147             :         // cppcheck-suppress useStlAlgorithm
     148     1113451 :         if (members[i]->proTxHash == proTxHash) {
     149      236032 :             return qc->validMembers[i];
     150             :         }
     151             :     }
     152      156813 :     return false;
     153      392845 : }
     154             : 
     155       38425 : CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const
     156             : {
     157       38425 :     LOCK(cs_vvec_shShare);
     158       38425 :     if (!HasVerificationVectorInternal() || memberIdx >= members.size() || !qc->validMembers[memberIdx]) {
     159        1978 :         return CBLSPublicKey();
     160             :     }
     161       36447 :     const auto& m = members[memberIdx];
     162       36447 :     return blsCache.BuildPubKeyShare(m->proTxHash, quorumVvec, CBLSId(m->proTxHash));
     163       38425 : }
     164             : 
     165      169926 : bool CQuorum::HasVerificationVector() const {
     166      169926 :     LOCK(cs_vvec_shShare);
     167      169926 :     return HasVerificationVectorInternal();
     168      169926 : }
     169             : 
     170      210376 : bool CQuorum::HasVerificationVectorInternal() const {
     171      210376 :     AssertLockHeld(cs_vvec_shShare);
     172      210376 :     return quorumVvec != nullptr;
     173             : }
     174             : 
     175      147655 : CBLSSecretKey CQuorum::GetSkShare() const
     176             : {
     177      147655 :     LOCK(cs_vvec_shShare);
     178      147655 :     return skShare;
     179      147655 : }
     180             : 
     181       49295 : int CQuorum::GetMemberIndex(const uint256& proTxHash) const
     182             : {
     183      120297 :     for (const auto i : util::irange(members.size())) {
     184             :         // cppcheck-suppress useStlAlgorithm
     185      120291 :         if (members[i]->proTxHash == proTxHash) {
     186       49289 :             return int(i);
     187             :         }
     188             :     }
     189           6 :     return -1;
     190       49295 : }
     191             : 
     192        2026 : void CQuorum::WriteContributions(CDBWrapper& db) const
     193             : {
     194        2026 :     uint256 dbKey = MakeQuorumKey(*this);
     195             : 
     196        2026 :     LOCK(cs_vvec_shShare);
     197        2026 :     if (HasVerificationVectorInternal()) {
     198        2026 :         CDataStream s(SER_DISK, CLIENT_VERSION);
     199        2026 :         WriteCompactSize(s, quorumVvec->size());
     200        7493 :         for (auto& pubkey : *quorumVvec) {
     201        5467 :             s << CBLSPublicKeyVersionWrapper(pubkey, false);
     202             :         }
     203        2026 :         db.Write(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), s);
     204        2026 :     }
     205        2026 :     if (skShare.IsValid()) {
     206        1913 :         db.Write(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);
     207        1913 :     }
     208        2026 : }
     209             : 
     210        5268 : bool CQuorum::ReadContributions(const CDBWrapper& db)
     211             : {
     212        5268 :     uint256 dbKey = MakeQuorumKey(*this);
     213        5268 :     CDataStream s(SER_DISK, CLIENT_VERSION);
     214             : 
     215        5268 :     if (!db.ReadDataStream(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), s)) {
     216        4346 :         return false;
     217             :     }
     218             : 
     219         922 :     size_t vvec_size = ReadCompactSize(s);
     220         922 :     CBLSPublicKey pubkey;
     221         922 :     std::vector<CBLSPublicKey> qv;
     222        3391 :     for ([[maybe_unused]] size_t _ : util::irange(vvec_size)) {
     223        2469 :         s >> CBLSPublicKeyVersionWrapper(pubkey, false);
     224        2469 :         qv.emplace_back(pubkey);
     225             :     }
     226             : 
     227         922 :     LOCK(cs_vvec_shShare);
     228         922 :     quorumVvec = std::make_shared<std::vector<CBLSPublicKey>>(std::move(qv));
     229             :     // We ignore the return value here as it is ok if this fails. If it fails, it usually means that we are not a
     230             :     // member of the quorum but observed the whole DKG process to have the quorum verification vector.
     231         922 :     db.Read(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);
     232             : 
     233         922 :     return true;
     234        5268 : }
     235             : } // namespace llmq

Generated by: LCOV version 1.16