LCOV - code coverage report
Current view: top level - src/llmq - signing_shares.h (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 0 141 0.0 %
Date: 2026-06-25 07:23:51 Functions: 0 126 0.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             : #ifndef BITCOIN_LLMQ_SIGNING_SHARES_H
       6             : #define BITCOIN_LLMQ_SIGNING_SHARES_H
       7             : 
       8             : #include <bls/bls.h>
       9             : #include <evo/types.h>
      10             : #include <llmq/signhash.h>
      11             : #include <llmq/signing.h>
      12             : #include <util/std23.h>
      13             : 
      14             : #include <random.h>
      15             : #include <saltedhasher.h>
      16             : #include <serialize.h>
      17             : #include <sync.h>
      18             : #include <uint256.h>
      19             : #include <util/time.h>
      20             : 
      21             : #include <atomic>
      22             : #include <functional>
      23             : #include <limits>
      24             : #include <memory>
      25             : #include <optional>
      26             : #include <string>
      27             : #include <unordered_map>
      28             : #include <utility>
      29             : #include <vector>
      30             : 
      31             : class CActiveMasternodeManager;
      32             : class ChainstateManager;
      33             : class CNode;
      34             : class CConnman;
      35             : class CSporkManager;
      36             : 
      37             : namespace llmq
      38             : {
      39             : class CSigningManager;
      40             : 
      41             : // <signHash, quorumMember>
      42             : using SigShareKey = std::pair<uint256, uint16_t>;
      43             : 
      44             : constexpr uint32_t UNINITIALIZED_SESSION_ID{std::numeric_limits<uint32_t>::max()};
      45             : 
      46             : class CSigShare : virtual public CSigBase
      47             : {
      48             : protected:
      49           0 :     uint16_t quorumMember{std::numeric_limits<uint16_t>::max()};
      50             : public:
      51             :     CBLSLazySignature sigShare;
      52             : 
      53             :     SigShareKey key;
      54             : 
      55           0 :     [[nodiscard]] auto getQuorumMember() const {
      56           0 :         return quorumMember;
      57             :     }
      58             : 
      59           0 :     CSigShare(Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id, const uint256& _msgHash,
      60             :               uint16_t _quorumMember, const CBLSLazySignature& _sigShare) :
      61           0 :                     CSigBase(_llmqType, _quorumHash, _id, _msgHash),
      62           0 :                     quorumMember(_quorumMember),
      63           0 :                     sigShare(_sigShare) {};
      64             : 
      65             :     // This should only be used for serialization
      66           0 :     CSigShare() = default;
      67             : 
      68             : 
      69             : public:
      70             :     void UpdateKey();
      71           0 :     const SigShareKey& GetKey() const
      72             :     {
      73           0 :         return key;
      74             :     }
      75           0 :     const uint256& GetSignHash() const
      76             :     {
      77           0 :         assert(!key.first.IsNull());
      78           0 :         return key.first;
      79             :     }
      80             : 
      81           0 :     SERIALIZE_METHODS(CSigShare, obj)
      82             :     {
      83           0 :         READWRITE(obj.llmqType, obj.quorumHash, obj.quorumMember, obj.id, obj.msgHash, obj.sigShare);
      84           0 :         SER_READ(obj, obj.UpdateKey());
      85           0 :     }
      86             : };
      87             : 
      88             : // Nodes will first announce a signing session with a sessionId to be used in all future P2P messages related to that
      89             : // session. We locally keep track of the mapping for each node. We also assign new sessionIds for outgoing sessions
      90             : // and send QSIGSESANN messages appropriately. All values except the max value for uint32_t are valid as sessionId
      91             : class CSigSesAnn : virtual public CSigBase
      92             : {
      93             : private:
      94           0 :     uint32_t sessionId{UNINITIALIZED_SESSION_ID};
      95             : 
      96             : public:
      97           0 :     CSigSesAnn(uint32_t _sessionId, Consensus::LLMQType _llmqType, const uint256& _quorumHash, const uint256& _id,
      98           0 :                const uint256& _msgHash) : CSigBase(_llmqType, _quorumHash, _id, _msgHash), sessionId(_sessionId) {};
      99             :     // ONLY FOR SERIALIZATION
     100           0 :     CSigSesAnn() = default;
     101             : 
     102             : 
     103             : 
     104           0 :     [[nodiscard]] auto getSessionId() const {
     105           0 :         return sessionId;
     106             :     }
     107             : 
     108           0 :     SERIALIZE_METHODS(CSigSesAnn, obj)
     109             :     {
     110           0 :         READWRITE(VARINT(obj.sessionId), obj.llmqType, obj.quorumHash, obj.id, obj.msgHash);
     111           0 :     }
     112             : 
     113             :     [[nodiscard]] std::string ToString() const;
     114             : };
     115             : 
     116           0 : class CSigSharesInv
     117             : {
     118             : public:
     119           0 :     uint32_t sessionId{UNINITIALIZED_SESSION_ID};
     120             :     std::vector<bool> inv;
     121             : 
     122             : public:
     123           0 :     SERIALIZE_METHODS(CSigSharesInv, obj)
     124             :     {
     125           0 :         uint64_t invSize = obj.inv.size();
     126           0 :         READWRITE(VARINT(obj.sessionId), COMPACTSIZE(invSize));
     127           0 :         autobitset_t bitset = std::make_pair(obj.inv, (size_t)invSize);
     128           0 :         READWRITE(AUTOBITSET(bitset));
     129           0 :         SER_READ(obj, obj.inv = bitset.first);
     130           0 :     }
     131             : 
     132             :     void Init(size_t size);
     133             :     void Set(uint16_t quorumMember, bool v);
     134             :     void SetAll(bool v);
     135             :     void Merge(const CSigSharesInv& inv2);
     136             : 
     137             :     [[nodiscard]] size_t CountSet() const;
     138             :     [[nodiscard]] std::string ToString() const;
     139             : };
     140             : 
     141             : // sent through the message QBSIGSHARES as a vector of multiple batches
     142           0 : class CBatchedSigShares
     143             : {
     144             : public:
     145           0 :     uint32_t sessionId{UNINITIALIZED_SESSION_ID};
     146             :     std::vector<std::pair<uint16_t, CBLSLazySignature>> sigShares;
     147             : 
     148             : public:
     149           0 :     SERIALIZE_METHODS(CBatchedSigShares, obj)
     150             :     {
     151           0 :         READWRITE(VARINT(obj.sessionId), obj.sigShares);
     152           0 :     }
     153             : 
     154             :     [[nodiscard]] std::string ToInvString() const;
     155             : };
     156             : 
     157             : template<typename T>
     158             : class SigShareMap
     159             : {
     160             : private:
     161             :     Uint256HashMap<std::unordered_map<uint16_t, T>> internalMap;
     162             : 
     163             : public:
     164           0 :     bool Add(const SigShareKey& k, const T& v)
     165             :     {
     166           0 :         auto& m = internalMap[k.first];
     167           0 :         return m.emplace(k.second, v).second;
     168             :     }
     169             : 
     170           0 :     void Erase(const SigShareKey& k)
     171             :     {
     172           0 :         auto it = internalMap.find(k.first);
     173           0 :         if (it == internalMap.end()) {
     174           0 :             return;
     175             :         }
     176           0 :         it->second.erase(k.second);
     177           0 :         if (it->second.empty()) {
     178           0 :             internalMap.erase(it);
     179           0 :         }
     180           0 :     }
     181             : 
     182           0 :     void Clear()
     183             :     {
     184           0 :         internalMap.clear();
     185           0 :     }
     186             : 
     187           0 :     [[nodiscard]] bool Has(const SigShareKey& k) const
     188             :     {
     189           0 :         auto it = internalMap.find(k.first);
     190           0 :         if (it == internalMap.end()) {
     191           0 :             return false;
     192             :         }
     193           0 :         return it->second.count(k.second) != 0;
     194           0 :     }
     195             : 
     196           0 :     T* Get(const SigShareKey& k)
     197             :     {
     198           0 :         auto it = internalMap.find(k.first);
     199           0 :         if (it == internalMap.end()) {
     200           0 :             return nullptr;
     201             :         }
     202             : 
     203           0 :         auto jt = it->second.find(k.second);
     204           0 :         if (jt == it->second.end()) {
     205           0 :             return nullptr;
     206             :         }
     207             : 
     208           0 :         return &jt->second;
     209           0 :     }
     210             : 
     211           0 :     T& GetOrAdd(const SigShareKey& k)
     212             :     {
     213           0 :         T* v = Get(k);
     214           0 :         if (!v) {
     215           0 :             Add(k, T());
     216           0 :             v = Get(k);
     217           0 :         }
     218           0 :         return *v;
     219             :     }
     220             : 
     221           0 :     const T* GetFirst() const
     222             :     {
     223           0 :         if (internalMap.empty()) {
     224           0 :             return nullptr;
     225             :         }
     226           0 :         return &internalMap.begin()->second.begin()->second;
     227           0 :     }
     228             : 
     229           0 :     [[nodiscard]] size_t Size() const
     230             :     {
     231           0 :         return std23::ranges::fold_left(internalMap, size_t{0},
     232           0 :                                         [](size_t s, const auto& p) { return s + p.second.size(); });
     233             :     }
     234             : 
     235           0 :     [[nodiscard]] size_t CountForSignHash(const uint256& signHash) const
     236             :     {
     237           0 :         auto it = internalMap.find(signHash);
     238           0 :         if (it == internalMap.end()) {
     239           0 :             return 0;
     240             :         }
     241           0 :         return it->second.size();
     242           0 :     }
     243             : 
     244           0 :     [[nodiscard]] bool Empty() const
     245             :     {
     246           0 :         return internalMap.empty();
     247             :     }
     248             : 
     249           0 :     const std::unordered_map<uint16_t, T>* GetAllForSignHash(const uint256& signHash) const
     250             :     {
     251           0 :         auto it = internalMap.find(signHash);
     252           0 :         if (it == internalMap.end()) {
     253           0 :             return nullptr;
     254             :         }
     255           0 :         return &it->second;
     256           0 :     }
     257             : 
     258           0 :     void EraseAllForSignHash(const uint256& signHash)
     259             :     {
     260           0 :         internalMap.erase(signHash);
     261           0 :     }
     262             : 
     263             :     template<typename F>
     264           0 :     void EraseIf(F&& f)
     265             :     {
     266           0 :         for (auto it = internalMap.begin(); it != internalMap.end(); ) {
     267           0 :             SigShareKey k;
     268           0 :             k.first = it->first;
     269           0 :             for (auto jt = it->second.begin(); jt != it->second.end(); ) {
     270           0 :                 k.second = jt->first;
     271           0 :                 if (f(k, jt->second)) {
     272           0 :                     jt = it->second.erase(jt);
     273           0 :                 } else {
     274           0 :                     ++jt;
     275             :                 }
     276             :             }
     277           0 :             if (it->second.empty()) {
     278           0 :                 it = internalMap.erase(it);
     279           0 :             } else {
     280           0 :                 ++it;
     281             :             }
     282             :         }
     283           0 :     }
     284             : 
     285             :     template<typename F>
     286           0 :     void ForEach(F&& f)
     287             :     {
     288           0 :         for (auto& p : internalMap) {
     289           0 :             SigShareKey k;
     290           0 :             k.first = p.first;
     291           0 :             for (auto& p2 : p.second) {
     292           0 :                 k.second = p2.first;
     293           0 :                 f(k, p2.second);
     294             :             }
     295             :         }
     296           0 :     }
     297             : };
     298             : 
     299           0 : class CSigSharesNodeState
     300             : {
     301             : public:
     302             :     // Used to avoid holding locks too long
     303           0 :     struct SessionInfo
     304             :     {
     305           0 :         Consensus::LLMQType llmqType{Consensus::LLMQType::LLMQ_NONE};
     306             :         uint256 quorumHash;
     307             :         uint256 id;
     308             :         uint256 msgHash;
     309             :         llmq::SignHash signHash;
     310             : 
     311             :         CQuorumCPtr quorum;
     312             :     };
     313             : 
     314           0 :     struct Session {
     315           0 :         uint32_t recvSessionId{UNINITIALIZED_SESSION_ID};
     316           0 :         uint32_t sendSessionId{UNINITIALIZED_SESSION_ID};
     317             : 
     318             :         Consensus::LLMQType llmqType;
     319             :         uint256 quorumHash;
     320             :         uint256 id;
     321             :         uint256 msgHash;
     322             :         llmq::SignHash signHash;
     323             : 
     324             :         CQuorumCPtr quorum;
     325             : 
     326             :         CSigSharesInv announced;
     327             :         CSigSharesInv requested;
     328             :         CSigSharesInv knows;
     329             :     };
     330             :     // TODO limit number of sessions per node
     331             :     Uint256HashMap<Session> sessions;
     332             : 
     333             :     std::unordered_map<uint32_t, Session*> sessionByRecvId;
     334             : 
     335             :     SigShareMap<CSigShare> pendingIncomingSigShares;
     336             :     SigShareMap<int64_t> requestedSigShares;
     337             : 
     338           0 :     bool banned{false};
     339             : 
     340             :     Session& GetOrCreateSessionFromShare(const CSigShare& sigShare);
     341             :     Session& GetOrCreateSessionFromAnn(const CSigSesAnn& ann);
     342             :     Session* GetSessionBySignHash(const uint256& signHash);
     343             :     Session* GetSessionByRecvId(uint32_t sessionId);
     344             :     bool GetSessionInfoByRecvId(uint32_t sessionId, SessionInfo& retInfo);
     345             : 
     346             :     void RemoveSession(const uint256& signHash);
     347             : };
     348             : 
     349           0 : class CSignedSession
     350             : {
     351             : public:
     352             :     CSigShare sigShare;
     353             :     CQuorumCPtr quorum;
     354             : 
     355           0 :     int64_t nextAttemptTime{0};
     356           0 :     int attempt{0};
     357             : };
     358             : 
     359             : struct PendingSignatureData {
     360             :     const CQuorumCPtr quorum;
     361             :     const uint256 id;
     362             :     const uint256 msgHash;
     363             : 
     364           0 :     PendingSignatureData(CQuorumCPtr quorum, const uint256& id, const uint256& msgHash) :
     365           0 :         quorum(std::move(quorum)),
     366           0 :         id(id),
     367           0 :         msgHash(msgHash)
     368           0 :     {
     369           0 :     }
     370             : };
     371             : 
     372             : class CSigSharesManager : public llmq::CRecoveredSigsListener
     373             : {
     374             : private:
     375             :     static constexpr int64_t SESSION_NEW_SHARES_TIMEOUT{60};
     376             :     static constexpr int64_t SIG_SHARE_REQUEST_TIMEOUT{5};
     377             : 
     378             : public:
     379             :     // we try to keep total message size below 10k
     380             :     static constexpr size_t MAX_MSGS_CNT_QSIGSESANN{100};
     381             :     static constexpr size_t MAX_MSGS_CNT_QSIGSHARES{200};
     382             :     // 400 is the maximum quorum size, so this is also the maximum number of sigs we need to support
     383             :     static constexpr size_t MAX_MSGS_TOTAL_BATCHED_SIGS{400};
     384             :     static constexpr size_t MAX_MSGS_SIG_SHARES{32};
     385             : 
     386             : private:
     387             :     static constexpr int64_t EXP_SEND_FOR_RECOVERY_TIMEOUT{2000};
     388             :     static constexpr int64_t MAX_SEND_FOR_RECOVERY_TIMEOUT{10000};
     389             : 
     390             :     mutable Mutex cs;
     391             : 
     392             :     SigShareMap<CSigShare> sigShares GUARDED_BY(cs);
     393             :     Uint256HashMap<CSignedSession> signedSessions GUARDED_BY(cs);
     394             : 
     395             :     // stores time of last receivedSigShare. Used to detect timeouts
     396             :     Uint256HashMap<int64_t> timeSeenForSessions GUARDED_BY(cs);
     397             : 
     398             :     std::unordered_map<NodeId, CSigSharesNodeState> nodeStates GUARDED_BY(cs);
     399             :     SigShareMap<std::pair<NodeId, int64_t>> sigSharesRequested GUARDED_BY(cs);
     400             :     SigShareMap<bool> sigSharesQueuedToAnnounce GUARDED_BY(cs);
     401             : 
     402             :     Mutex cs_pendingSigns;
     403             :     std::vector<PendingSignatureData> pendingSigns GUARDED_BY(cs_pendingSigns);
     404             : 
     405             :     FastRandomContext rnd GUARDED_BY(cs);
     406             : 
     407             :     CConnman& m_connman;
     408             :     const ChainstateManager& m_chainman;
     409             :     CSigningManager& sigman;
     410             :     const CActiveMasternodeManager& m_mn_activeman;
     411             :     const CQuorumManager& qman;
     412             :     const CSporkManager& m_sporkman;
     413             : 
     414             :     CleanupThrottler<NodeClock> cleanupThrottler;
     415             :     std::atomic<uint32_t> recoveredSigsCounter{0};
     416             : 
     417             : public:
     418             :     CSigSharesManager() = delete;
     419             :     CSigSharesManager(const CSigSharesManager&) = delete;
     420             :     CSigSharesManager& operator=(const CSigSharesManager&) = delete;
     421             :     explicit CSigSharesManager(CConnman& connman, const ChainstateManager& chainman, CSigningManager& _sigman,
     422             :                                const CActiveMasternodeManager& mn_activeman, const CQuorumManager& _qman,
     423             :                                const CSporkManager& sporkman);
     424             :     ~CSigSharesManager() override;
     425             : 
     426             :     void RegisterRecoveryInterface() EXCLUSIVE_LOCKS_REQUIRED(!cs);
     427             :     void UnregisterRecoveryInterface() EXCLUSIVE_LOCKS_REQUIRED(!cs);
     428             : 
     429             :     void AsyncSign(CQuorumCPtr quorum, const uint256& id, const uint256& msgHash)
     430             :         EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs);
     431             :     std::optional<CSigShare> CreateSigShare(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const
     432             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     433             :     void ForceReAnnouncement(const CQuorum& quorum, Consensus::LLMQType llmqType, const uint256& id,
     434             :                              const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs);
     435             : 
     436             :     [[nodiscard]] RecoveredSigResult HandleNewRecoveredSig(const CRecoveredSig& recoveredSig) override
     437             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     438             : 
     439             :     static CDeterministicMNCPtr SelectMemberForRecovery(const CQuorum& quorum, const uint256& id, int attempt);
     440             : 
     441             :     bool AsyncSignIfMember(Consensus::LLMQType llmqType, CSigningManager& sigman, const uint256& id,
     442             :                            const uint256& msgHash, const uint256& quorumHash = uint256(), bool allowReSign = false,
     443             :                            bool allowDiffMsgHashSigning = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs);
     444             : private:
     445             :     std::optional<CSigShare> CreateSigShareForSingleMember(const CQuorum& quorum, const uint256& id, const uint256& msgHash) const;
     446             : 
     447             : public:
     448             :     // all of these return false when the currently processed message should be aborted (as each message actually contains multiple messages) and ban node
     449             :     bool ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSesAnn& ann) EXCLUSIVE_LOCKS_REQUIRED(!cs);
     450             :     bool ProcessMessageSigShares(const CNode& pfrom, const CSigSharesInv& inv, const std::string& msg_type)
     451             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     452             :     bool ProcessMessageBatchedSigShares(const CNode& pfrom, const CBatchedSigShares& batchedSigShares)
     453             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     454             : 
     455             :     // if ProcessMessageSigShare returns false the node should be banned
     456             :     bool ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare) EXCLUSIVE_LOCKS_REQUIRED(!cs);
     457             : 
     458             :     // CollectPendingSigSharesToVerify returns true if there's more work to do
     459             :     bool CollectPendingSigSharesToVerify(
     460             :         size_t maxUniqueSessions, std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
     461             :         std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
     462             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     463             : 
     464             :     std::vector<std::shared_ptr<CRecoveredSig>> ProcessPendingSigShares(
     465             :         const std::vector<CSigShare>& sigSharesToProcess,
     466             :         const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& quorums)
     467             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     468             : 
     469             : private:
     470             :     [[nodiscard]] std::shared_ptr<CRecoveredSig> ProcessSigShare(const CSigShare& sigShare, const CQuorumCPtr& quorum)
     471             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     472             :     [[nodiscard]] std::shared_ptr<CRecoveredSig> TryRecoverSig(const CQuorum& quorum, const uint256& id,
     473             :                                                                const uint256& msgHash) EXCLUSIVE_LOCKS_REQUIRED(!cs);
     474             : 
     475             :     bool GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo)
     476             :         EXCLUSIVE_LOCKS_REQUIRED(!cs);
     477             :     static CSigShare RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const std::pair<uint16_t, CBLSLazySignature>& in);
     478             : 
     479             :     void RemoveSigSharesForSession(const uint256& signHash) EXCLUSIVE_LOCKS_REQUIRED(cs);
     480             : 
     481             : public:
     482             :     void RemoveNodesIf(std::function<bool(NodeId)> predicate) EXCLUSIVE_LOCKS_REQUIRED(!cs);
     483             :     void MarkAsBanned(NodeId nodeId) EXCLUSIVE_LOCKS_REQUIRED(!cs);
     484             : 
     485             : private:
     486             :     void CollectSigSharesToRequest(std::unordered_map<NodeId, Uint256HashMap<CSigSharesInv>>& sigSharesToRequest)
     487             :         EXCLUSIVE_LOCKS_REQUIRED(cs);
     488             :     void CollectSigSharesToSend(std::unordered_map<NodeId, Uint256HashMap<CBatchedSigShares>>& sigSharesToSend)
     489             :         EXCLUSIVE_LOCKS_REQUIRED(cs);
     490             :     void CollectSigSharesToSendConcentrated(std::unordered_map<NodeId, std::vector<CSigShare>>& sigSharesToSend, const std::vector<CNode*>& vNodes) EXCLUSIVE_LOCKS_REQUIRED(cs);
     491             :     void CollectSigSharesToAnnounce(std::unordered_map<NodeId, Uint256HashMap<CSigSharesInv>>& sigSharesToAnnounce)
     492             :         EXCLUSIVE_LOCKS_REQUIRED(cs);
     493             : 
     494             : public:
     495             :     void Cleanup() EXCLUSIVE_LOCKS_REQUIRED(!cs);
     496             :     bool SendMessages() EXCLUSIVE_LOCKS_REQUIRED(!cs);
     497             : 
     498             :     // Dispatcher functions
     499             :     std::vector<PendingSignatureData> DispatchPendingSigns() EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns);
     500             :     // Worker pool task functions
     501             :     bool IsAnyPendingProcessing() const EXCLUSIVE_LOCKS_REQUIRED(!cs);
     502             :     [[nodiscard]] std::shared_ptr<CRecoveredSig> SignAndProcessSingleShare(PendingSignatureData work)
     503             :         EXCLUSIVE_LOCKS_REQUIRED(!cs_pendingSigns, !cs);
     504             : };
     505             : } // namespace llmq
     506             : 
     507             : #endif // BITCOIN_LLMQ_SIGNING_SHARES_H

Generated by: LCOV version 1.16