LCOV - code coverage report
Current view: top level - src/llmq - quorums.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 15 136 11.0 %
Date: 2026-06-25 07:23:51 Functions: 1 17 5.9 %

          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           0 : uint256 MakeQuorumKey(const CQuorum& q)
      21             : {
      22           0 :     CHashWriter hw(SER_NETWORK, 0);
      23           0 :     hw << q.params.type;
      24           0 :     hw << q.qc->quorumHash;
      25           0 :     for (const auto& dmn : q.members) {
      26           0 :         hw << dmn->proTxHash;
      27             :     }
      28           0 :     return hw.GetHash();
      29             : }
      30             : 
      31         180 : void DataCleanupHelper(CDBWrapper& db, const Uint256HashSet& skip_list, bool compact)
      32             : {
      33         180 :     const auto prefixes = {DB_QUORUM_QUORUM_VVEC, DB_QUORUM_SK_SHARE};
      34             : 
      35         180 :     CDBBatch batch(db);
      36         180 :     std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
      37             : 
      38         540 :     for (const auto& prefix : prefixes) {
      39         360 :         auto start = std::make_tuple(prefix, uint256());
      40         360 :         pcursor->Seek(start);
      41             : 
      42         360 :         int count{0};
      43         360 :         while (pcursor->Valid()) {
      44           0 :             decltype(start) k;
      45             : 
      46           0 :             if (!pcursor->GetKey(k) || std::get<0>(k) != prefix) {
      47           0 :                 break;
      48             :             }
      49             : 
      50           0 :             pcursor->Next();
      51             : 
      52           0 :             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           0 :         }
      62             : 
      63         360 :         db.WriteBatch(batch);
      64             : 
      65         360 :         LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- %s removed %d\n", __func__, prefix, count);
      66         360 :     }
      67             : 
      68         180 :     pcursor.reset();
      69             : 
      70         180 :     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         180 : }
      77             : 
      78           0 : std::string CQuorumDataRequest::GetErrorString() const
      79             : {
      80           0 :     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           0 :             return "QUORUM_VERIFICATION_VECTOR_MISSING";
      93             :         case (Errors::ENCRYPTED_CONTRIBUTIONS_MISSING):
      94           0 :             return "ENCRYPTED_CONTRIBUTIONS_MISSING";
      95             :         case (Errors::UNDEFINED):
      96           0 :             return "UNDEFINED";
      97             :         default:
      98           0 :             return "UNDEFINED";
      99             :     }
     100             :     return "UNDEFINED";
     101           0 : }
     102             : 
     103           0 : CQuorum::CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker,
     104             :                  CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex,
     105             :                  const uint256& _minedBlockHash, Span<CDeterministicMNCPtr> _members) :
     106           0 :     params{_params},
     107           0 :     qc{std::move(_qc)},
     108           0 :     m_quorum_base_block_index{_pQuorumBaseBlockIndex},
     109           0 :     minedBlockHash{_minedBlockHash},
     110           0 :     members{_members.begin(), _members.end()},
     111           0 :     blsCache{_blsWorker}
     112           0 : {
     113             :     assert(qc != nullptr);
     114             :     assert(m_quorum_base_block_index != nullptr);
     115           0 : }
     116             : 
     117           0 : bool CQuorum::SetVerificationVector(const std::vector<CBLSPublicKey>& quorumVecIn)
     118             : {
     119           0 :     const auto quorumVecInSerialized = ::SerializeHash(quorumVecIn);
     120             : 
     121           0 :     LOCK(cs_vvec_shShare);
     122           0 :     if (quorumVecInSerialized != qc->quorumVvecHash) {
     123           0 :         return false;
     124             :     }
     125           0 :     quorumVvec = std::make_shared<std::vector<CBLSPublicKey>>(quorumVecIn);
     126           0 :     return true;
     127           0 : }
     128             : 
     129           0 : bool CQuorum::SetSecretKeyShare(const CBLSSecretKey& secretKeyShare, const uint256& protx_hash)
     130             : {
     131           0 :     if (protx_hash.IsNull() || !secretKeyShare.IsValid() || (secretKeyShare.GetPublicKey() != GetPubKeyShare(GetMemberIndex(protx_hash)))) {
     132           0 :         return false;
     133             :     }
     134           0 :     LOCK(cs_vvec_shShare);
     135           0 :     skShare = secretKeyShare;
     136           0 :     return true;
     137           0 : }
     138             : 
     139           0 : bool CQuorum::IsMember(const uint256& proTxHash) const
     140             : {
     141           0 :     return std::ranges::any_of(members, [&proTxHash](const auto& dmn) { return dmn->proTxHash == proTxHash; });
     142             : }
     143             : 
     144           0 : bool CQuorum::IsValidMember(const uint256& proTxHash) const
     145             : {
     146           0 :     for (const auto i : util::irange(members.size())) {
     147             :         // cppcheck-suppress useStlAlgorithm
     148           0 :         if (members[i]->proTxHash == proTxHash) {
     149           0 :             return qc->validMembers[i];
     150             :         }
     151             :     }
     152           0 :     return false;
     153           0 : }
     154             : 
     155           0 : CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const
     156             : {
     157           0 :     LOCK(cs_vvec_shShare);
     158           0 :     if (!HasVerificationVectorInternal() || memberIdx >= members.size() || !qc->validMembers[memberIdx]) {
     159           0 :         return CBLSPublicKey();
     160             :     }
     161           0 :     const auto& m = members[memberIdx];
     162           0 :     return blsCache.BuildPubKeyShare(m->proTxHash, quorumVvec, CBLSId(m->proTxHash));
     163           0 : }
     164             : 
     165           0 : bool CQuorum::HasVerificationVector() const {
     166           0 :     LOCK(cs_vvec_shShare);
     167           0 :     return HasVerificationVectorInternal();
     168           0 : }
     169             : 
     170           0 : bool CQuorum::HasVerificationVectorInternal() const {
     171           0 :     AssertLockHeld(cs_vvec_shShare);
     172           0 :     return quorumVvec != nullptr;
     173             : }
     174             : 
     175           0 : CBLSSecretKey CQuorum::GetSkShare() const
     176             : {
     177           0 :     LOCK(cs_vvec_shShare);
     178           0 :     return skShare;
     179           0 : }
     180             : 
     181           0 : int CQuorum::GetMemberIndex(const uint256& proTxHash) const
     182             : {
     183           0 :     for (const auto i : util::irange(members.size())) {
     184             :         // cppcheck-suppress useStlAlgorithm
     185           0 :         if (members[i]->proTxHash == proTxHash) {
     186           0 :             return int(i);
     187             :         }
     188             :     }
     189           0 :     return -1;
     190           0 : }
     191             : 
     192           0 : void CQuorum::WriteContributions(CDBWrapper& db) const
     193             : {
     194           0 :     uint256 dbKey = MakeQuorumKey(*this);
     195             : 
     196           0 :     LOCK(cs_vvec_shShare);
     197           0 :     if (HasVerificationVectorInternal()) {
     198           0 :         CDataStream s(SER_DISK, CLIENT_VERSION);
     199           0 :         WriteCompactSize(s, quorumVvec->size());
     200           0 :         for (auto& pubkey : *quorumVvec) {
     201           0 :             s << CBLSPublicKeyVersionWrapper(pubkey, false);
     202             :         }
     203           0 :         db.Write(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), s);
     204           0 :     }
     205           0 :     if (skShare.IsValid()) {
     206           0 :         db.Write(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);
     207           0 :     }
     208           0 : }
     209             : 
     210           0 : bool CQuorum::ReadContributions(const CDBWrapper& db)
     211             : {
     212           0 :     uint256 dbKey = MakeQuorumKey(*this);
     213           0 :     CDataStream s(SER_DISK, CLIENT_VERSION);
     214             : 
     215           0 :     if (!db.ReadDataStream(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), s)) {
     216           0 :         return false;
     217             :     }
     218             : 
     219           0 :     size_t vvec_size = ReadCompactSize(s);
     220           0 :     CBLSPublicKey pubkey;
     221           0 :     std::vector<CBLSPublicKey> qv;
     222           0 :     for ([[maybe_unused]] size_t _ : util::irange(vvec_size)) {
     223           0 :         s >> CBLSPublicKeyVersionWrapper(pubkey, false);
     224           0 :         qv.emplace_back(pubkey);
     225             :     }
     226             : 
     227           0 :     LOCK(cs_vvec_shShare);
     228           0 :     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           0 :     db.Read(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare);
     232             : 
     233           0 :     return true;
     234           0 : }
     235             : } // namespace llmq

Generated by: LCOV version 1.16