LCOV - code coverage report
Current view: top level - src/llmq - quorums.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 68 68 100.0 %
Date: 2026-06-25 07:23:43 Functions: 37 37 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             : #ifndef BITCOIN_LLMQ_QUORUMS_H
       6             : #define BITCOIN_LLMQ_QUORUMS_H
       7             : 
       8             : #include <bls/bls_worker.h>
       9             : #include <evo/types.h>
      10             : #include <llmq/params.h>
      11             : #include <llmq/types.h>
      12             : #include <saltedhasher.h>
      13             : 
      14             : #include <serialize.h>
      15             : #include <span.h>
      16             : #include <sync.h>
      17             : #include <threadsafety.h>
      18             : #include <uint256.h>
      19             : #include <util/time.h>
      20             : 
      21             : #include <set>
      22             : #include <string>
      23             : #include <vector>
      24             : 
      25             : class CBlockIndex;
      26             : class CDBWrapper;
      27             : namespace llmq {
      28             : class CQuorum;
      29             : class CQuorumDataRequest;
      30             : class CQuorumManager;
      31             : class QuorumRole;
      32             : } // namespace llmq
      33             : 
      34             : namespace llmq {
      35             : 
      36             : enum class DataRequestStatus : uint8_t {
      37             :     NotFound,
      38             :     Requested,
      39             :     Pending,
      40             :     Processed,
      41             : };
      42             : 
      43             : extern const std::string DB_QUORUM_SK_SHARE;
      44             : extern const std::string DB_QUORUM_QUORUM_VVEC;
      45             : 
      46             : uint256 MakeQuorumKey(const CQuorum& q);
      47             : void DataCleanupHelper(CDBWrapper& db, const Uint256HashSet& skip_list, bool compact = false);
      48             : 
      49             : /**
      50             :  * Object used as a key to store CQuorumDataRequest
      51             :  */
      52             : struct CQuorumDataRequestKey
      53             : {
      54             :     uint256 proRegTx;
      55             :     bool m_we_requested;
      56             :     uint256 quorumHash;
      57             :     Consensus::LLMQType llmqType;
      58             : 
      59        1795 :     CQuorumDataRequestKey(const uint256& proRegTxIn, const bool _m_we_requested, const uint256& quorumHashIn, const Consensus::LLMQType llmqTypeIn) :
      60         898 :         proRegTx(proRegTxIn),
      61         898 :         m_we_requested(_m_we_requested),
      62         898 :         quorumHash(quorumHashIn),
      63         898 :         llmqType(llmqTypeIn)
      64        1795 :         {}
      65             : 
      66         306 :     bool operator ==(const CQuorumDataRequestKey& obj) const
      67             :     {
      68         306 :         return (proRegTx == obj.proRegTx && m_we_requested == obj.m_we_requested && quorumHash == obj.quorumHash && llmqType == obj.llmqType);
      69             :     }
      70             : };
      71             : 
      72             : /**
      73             :  * An object of this class represents a QGETDATA request or a QDATA response header
      74             :  */
      75             : class CQuorumDataRequest
      76             : {
      77             : public:
      78             : 
      79             :     enum Flags : uint16_t {
      80             :         QUORUM_VERIFICATION_VECTOR = 0x0001,
      81             :         ENCRYPTED_CONTRIBUTIONS = 0x0002,
      82             :     };
      83             :     enum Errors : uint8_t {
      84             :         NONE = 0x00,
      85             :         QUORUM_TYPE_INVALID = 0x01,
      86             :         QUORUM_BLOCK_NOT_FOUND = 0x02,
      87             :         QUORUM_NOT_FOUND = 0x03,
      88             :         MASTERNODE_IS_NO_MEMBER = 0x04,
      89             :         QUORUM_VERIFICATION_VECTOR_MISSING = 0x05,
      90             :         ENCRYPTED_CONTRIBUTIONS_MISSING = 0x06,
      91             :         UNDEFINED = 0xFF,
      92             :     };
      93             : 
      94             : private:
      95         502 :     Consensus::LLMQType llmqType{Consensus::LLMQType::LLMQ_NONE};
      96             :     uint256 quorumHash;
      97         502 :     uint16_t nDataMask{0};
      98             :     uint256 proTxHash;
      99         675 :     Errors nError{UNDEFINED};
     100             : 
     101         173 :     int64_t nTime{GetTime()};
     102         675 :     bool fProcessed{false};
     103             : 
     104             :     static constexpr int64_t EXPIRATION_TIMEOUT{300};
     105             :     static constexpr int64_t EXPIRATION_BIAS{60};
     106             : 
     107             : public:
     108             : 
     109        3012 :     CQuorumDataRequest() : nTime(GetTime()) {}
     110         346 :     CQuorumDataRequest(const Consensus::LLMQType llmqTypeIn, const uint256& quorumHashIn, const uint16_t nDataMaskIn, const uint256& proTxHashIn = uint256()) :
     111         173 :         llmqType(llmqTypeIn),
     112         173 :         quorumHash(quorumHashIn),
     113         173 :         nDataMask(nDataMaskIn),
     114         173 :         proTxHash(proTxHashIn)
     115         346 :         {}
     116             : 
     117        2994 :     SERIALIZE_METHODS(CQuorumDataRequest, obj)
     118             :     {
     119         998 :         bool fRead{false};
     120        1500 :         SER_READ(obj, fRead = true);
     121         998 :         READWRITE(obj.llmqType, obj.quorumHash, obj.nDataMask, obj.proTxHash);
     122         998 :         if (fRead) {
     123             :             try {
     124         502 :                 READWRITE(obj.nError);
     125         502 :             } catch (...) {
     126         646 :                 SER_READ(obj, obj.nError = UNDEFINED);
     127         323 :             }
     128         998 :         } else if (obj.nError != UNDEFINED) {
     129         323 :             READWRITE(obj.nError);
     130         323 :         }
     131        1321 :     }
     132             : 
     133        1347 :     Consensus::LLMQType GetLLMQType() const { return llmqType; }
     134        1260 :     const uint256& GetQuorumHash() const { return quorumHash; }
     135         853 :     uint16_t GetDataMask() const { return nDataMask; }
     136         205 :     const uint256& GetProTxHash() const { return proTxHash; }
     137             : 
     138         343 :     void SetError(Errors nErrorIn) { nError = nErrorIn; }
     139         456 :     Errors GetError() const { return nError; }
     140             :     std::string GetErrorString() const;
     141             : 
     142         575 :     bool IsExpired(bool add_bias) const { return (GetTime() - nTime) >= (EXPIRATION_TIMEOUT + (add_bias ? EXPIRATION_BIAS : 0)); }
     143         173 :     bool IsProcessed() const { return fProcessed; }
     144         149 :     void SetProcessed() { fProcessed = true; }
     145             : 
     146         167 :     bool operator==(const CQuorumDataRequest& other) const
     147             :     {
     148         334 :         return llmqType == other.llmqType &&
     149         167 :                quorumHash == other.quorumHash &&
     150         167 :                nDataMask == other.nDataMask &&
     151         149 :                proTxHash == other.proTxHash;
     152             :     }
     153         167 :     bool operator!=(const CQuorumDataRequest& other) const
     154             :     {
     155         167 :         return !(*this == other);
     156             :     }
     157             : };
     158             : 
     159             : /**
     160             :  * An object of this class represents a quorum which was mined on-chain (through a quorum commitment)
     161             :  * It at least contains information about the members and the quorum public key which is needed to verify recovered
     162             :  * signatures from this quorum.
     163             :  *
     164             :  * In case the local node is a member of the same quorum and successfully participated in the DKG, the quorum object
     165             :  * will also contain the secret key share and the quorum verification vector. The quorum vvec is then used to recover
     166             :  * the public key shares of individual members, which are needed to verify signature shares of these members.
     167             :  */
     168             : class CQuorum
     169             : {
     170             :     friend class CQuorumManager;
     171             : 
     172             : public:
     173             :     const Consensus::LLMQParams params;
     174             :     const CFinalCommitmentPtr qc;
     175             :     const CBlockIndex* m_quorum_base_block_index;
     176             :     const uint256 minedBlockHash;
     177             :     const std::vector<CDeterministicMNCPtr> members;
     178             : 
     179             : private:
     180             :     // Recovery of public key shares is very slow, so we start a background thread that pre-populates a cache so that
     181             :     // the public key shares are ready when needed later
     182             :     mutable CBLSWorkerCache blsCache;
     183             :     mutable std::atomic<bool> fQuorumDataRecoveryThreadRunning{false};
     184             : 
     185             :     mutable Mutex cs_vvec_shShare;
     186             :     // These are only valid when we either participated in the DKG or fully watched it
     187             :     BLSVerificationVectorPtr quorumVvec GUARDED_BY(cs_vvec_shShare);
     188             :     CBLSSecretKey skShare GUARDED_BY(cs_vvec_shShare);
     189             : 
     190             : public:
     191             :     CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker,
     192             :             CFinalCommitmentPtr _qc, const CBlockIndex* _pQuorumBaseBlockIndex, const uint256& _minedBlockHash, Span<CDeterministicMNCPtr> _members);
     193             : 
     194       10710 :     ~CQuorum() = default;
     195             : 
     196             :     bool SetVerificationVector(const std::vector<CBLSPublicKey>& quorumVecIn) EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare);
     197        1896 :     void SetVerificationVector(BLSVerificationVectorPtr vvec_in) EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare)
     198             :     {
     199        1896 :         LOCK(cs_vvec_shShare);
     200        1896 :         quorumVvec = std::move(vvec_in);
     201        1896 :     }
     202             :     bool SetSecretKeyShare(const CBLSSecretKey& secretKeyShare, const uint256& protx_hash)
     203             :         EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare);
     204             : 
     205             :     bool HasVerificationVector() const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare);
     206         307 :     std::shared_ptr<const std::vector<CBLSPublicKey>> GetVerificationVector() const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare)
     207             :     {
     208         307 :         LOCK(cs_vvec_shShare);
     209         307 :         return quorumVvec;
     210         307 :     }
     211             :     bool IsMember(const uint256& proTxHash) const;
     212             :     bool IsValidMember(const uint256& proTxHash) const;
     213             :     int GetMemberIndex(const uint256& proTxHash) const;
     214             : 
     215             :     CBLSPublicKey GetPubKeyShare(size_t memberIdx) const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare);
     216             :     CBLSSecretKey GetSkShare() const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare);
     217             : 
     218             :     //! Try to claim exclusive data recovery for this quorum. Returns true if claimed.
     219        2665 :     bool TryClaimRecovery() const { bool expected = false; return fQuorumDataRecoveryThreadRunning.compare_exchange_strong(expected, true); }
     220       83234 :     bool IsRecoveryRunning() const { return fQuorumDataRecoveryThreadRunning; }
     221        2627 :     void ReleaseRecovery() const { fQuorumDataRecoveryThreadRunning = false; }
     222             : 
     223             : private:
     224             :     bool HasVerificationVectorInternal() const EXCLUSIVE_LOCKS_REQUIRED(cs_vvec_shShare);
     225             :     void WriteContributions(CDBWrapper& db) const EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare);
     226             :     bool ReadContributions(const CDBWrapper& db) EXCLUSIVE_LOCKS_REQUIRED(!cs_vvec_shShare);
     227             : };
     228             : } // namespace llmq
     229             : 
     230             : template<typename T> struct SaltedHasherImpl;
     231             : template<>
     232             : struct SaltedHasherImpl<llmq::CQuorumDataRequestKey>
     233             : {
     234         898 :     static std::size_t CalcHash(const llmq::CQuorumDataRequestKey& v, uint64_t k0, uint64_t k1)
     235             :     {
     236         898 :         CSipHasher c(k0, k1);
     237         898 :         c.Write(reinterpret_cast<const unsigned char*>(&v.proRegTx), sizeof(v.proRegTx));
     238         898 :         c.Write(reinterpret_cast<const unsigned char*>(&v.m_we_requested), sizeof(v.m_we_requested));
     239         898 :         c.Write(reinterpret_cast<const unsigned char*>(&v.quorumHash), sizeof(v.quorumHash));
     240         898 :         c.Write(reinterpret_cast<const unsigned char*>(&v.llmqType), sizeof(v.llmqType));
     241         898 :         return c.Finalize();
     242             :     }
     243             : };
     244             : 
     245             : template<> struct is_serializable_enum<llmq::CQuorumDataRequest::Errors> : std::true_type {};
     246             : 
     247             : #endif // BITCOIN_LLMQ_QUORUMS_H

Generated by: LCOV version 1.16