LCOV - code coverage report
Current view: top level - src/llmq - snapshot.h (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 70 75 93.3 %
Date: 2026-06-25 07:23:43 Functions: 35 42 83.3 %

          Line data    Source code
       1             : // Copyright (c) 2021-2025 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_SNAPSHOT_H
       6             : #define BITCOIN_LLMQ_SNAPSHOT_H
       7             : 
       8             : #include <evo/smldiff.h>
       9             : #include <llmq/commitment.h>
      10             : #include <llmq/params.h>
      11             : #include <unordered_lru_cache.h>
      12             : #include <util/helpers.h>
      13             : 
      14             : #include <saltedhasher.h>
      15             : #include <serialize.h>
      16             : #include <sync.h>
      17             : #include <threadsafety.h>
      18             : 
      19             : #include <optional>
      20             : 
      21             : class CBlockIndex;
      22             : class CEvoDB;
      23             : struct RPCResult;
      24             : namespace llmq {
      25             : class CQuorumBlockProcessor;
      26             : class CQuorumManager;
      27             : } // namespace llmq
      28             : 
      29             : class UniValue;
      30             : 
      31             : enum class SnapshotSkipMode : int {
      32             :     MODE_NO_SKIPPING = 0,
      33             :     MODE_SKIPPING_ENTRIES = 1,
      34             :     MODE_NO_SKIPPING_ENTRIES = 2,
      35             :     MODE_ALL_SKIPPED = 3
      36             : };
      37             : template<> struct is_serializable_enum<SnapshotSkipMode> : std::true_type {};
      38             : 
      39             : namespace llmq {
      40             : constexpr int WORK_DIFF_DEPTH{8};
      41             : 
      42       22516 : class CQuorumSnapshot
      43             : {
      44             : public:
      45             :     std::vector<bool> activeQuorumMembers;
      46             :     SnapshotSkipMode mnSkipListMode{SnapshotSkipMode::MODE_NO_SKIPPING};
      47             :     std::vector<int> mnSkipList;
      48             : 
      49             : public:
      50             :     CQuorumSnapshot();
      51             :     CQuorumSnapshot(std::vector<bool> active_quorum_members, SnapshotSkipMode skip_mode, std::vector<int> skip_list);
      52             :     ~CQuorumSnapshot();
      53             : 
      54             :     template <typename Stream, typename Operation>
      55        5987 :     inline void SerializationOpBase(Stream& s, Operation ser_action)
      56             :     {
      57        5987 :         READWRITE(mnSkipListMode);
      58        5987 :     }
      59             : 
      60             :     template <typename Stream>
      61        4935 :     void Serialize(Stream& s) const
      62             :     {
      63        4935 :         const_cast<CQuorumSnapshot*>(this)->SerializationOpBase(s, CSerActionSerialize());
      64             : 
      65        4935 :         WriteCompactSize(s, activeQuorumMembers.size());
      66        4935 :         WriteFixedBitSet(s, activeQuorumMembers, activeQuorumMembers.size());
      67        4935 :         WriteCompactSize(s, mnSkipList.size());
      68        7845 :         for (const auto& obj : mnSkipList) {
      69        2910 :             s << obj;
      70             :         }
      71        4935 :     }
      72             : 
      73             :     template <typename Stream>
      74        1052 :     void Unserialize(Stream& s)
      75             :     {
      76        1052 :         SerializationOpBase(s, CSerActionUnserialize());
      77             : 
      78        1052 :         size_t cnt = ReadCompactSize(s);
      79        1052 :         ReadFixedBitSet(s, activeQuorumMembers, cnt);
      80        1052 :         cnt = ReadCompactSize(s);
      81        1742 :         for ([[maybe_unused]] const auto _ : util::irange(cnt)) {
      82             :             int obj;
      83         690 :             s >> obj;
      84         690 :             mnSkipList.push_back(obj);
      85             :         }
      86        1052 :     }
      87             : 
      88             :     [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
      89             :     [[nodiscard]] UniValue ToJson() const;
      90             : };
      91             : 
      92           8 : class CGetQuorumRotationInfo
      93             : {
      94             : public:
      95             :     std::vector<uint256> baseBlockHashes;
      96             :     uint256 blockRequestHash;
      97             :     bool extraShare;
      98             : 
      99          24 :     SERIALIZE_METHODS(CGetQuorumRotationInfo, obj)
     100             :     {
     101           8 :         READWRITE(obj.baseBlockHashes, obj.blockRequestHash, obj.extraShare);
     102           8 :     }
     103             : };
     104             : 
     105       22772 : struct CycleBase {
     106             :     CQuorumSnapshot m_snap;
     107       22772 :     const CBlockIndex* m_cycle_index{nullptr};
     108             : };
     109             : 
     110          85 : struct CycleData : public CycleBase {
     111             :     CSimplifiedMNListDiff m_diff;
     112          47 :     const CBlockIndex* m_work_index{nullptr};
     113             : };
     114             : 
     115             : class CQuorumRotationInfo
     116             : {
     117             : public:
     118             :     bool extraShare{false};
     119             :     CycleData cycleHMinusC;
     120             :     CycleData cycleHMinus2C;
     121             :     CycleData cycleHMinus3C;
     122             :     std::optional<CycleData> cycleHMinus4C;
     123             :     CSimplifiedMNListDiff mnListDiffTip;
     124             :     CSimplifiedMNListDiff mnListDiffH;
     125             :     std::vector<llmq::CFinalCommitment> lastCommitmentPerIndex;
     126             :     std::vector<CQuorumSnapshot> quorumSnapshotList;
     127             :     std::vector<CSimplifiedMNListDiff> mnListDiffList;
     128             : 
     129             : public:
     130             :     CQuorumRotationInfo();
     131             :     CQuorumRotationInfo(const CQuorumRotationInfo& dmn) = delete;
     132             :     ~CQuorumRotationInfo();
     133             : 
     134             :     template <typename Stream, typename Operation>
     135          16 :     inline void SerializationOpBase(Stream& s, Operation ser_action)
     136             :     {
     137          16 :         READWRITE(cycleHMinusC.m_snap,
     138             :                   cycleHMinus2C.m_snap,
     139             :                   cycleHMinus3C.m_snap,
     140             :                   mnListDiffTip,
     141             :                   mnListDiffH,
     142             :                   cycleHMinusC.m_diff,
     143             :                   cycleHMinus2C.m_diff,
     144             :                   cycleHMinus3C.m_diff,
     145             :                   extraShare);
     146          16 :     }
     147             : 
     148             :     template <typename Stream>
     149          12 :     void Serialize(Stream& s) const
     150             :     {
     151          12 :         const_cast<CQuorumRotationInfo*>(this)->SerializationOpBase(s, CSerActionSerialize());
     152             : 
     153          12 :         if (extraShare) {
     154             :             // Needed to maintain compatibility with existing on-disk format
     155           9 :             ::Serialize(s, cycleHMinus4C.value_or(CycleData{}).m_snap);
     156           9 :             ::Serialize(s, cycleHMinus4C.value_or(CycleData{}).m_diff);
     157           9 :         }
     158             : 
     159          12 :         WriteCompactSize(s, lastCommitmentPerIndex.size());
     160          15 :         for (const auto& obj : lastCommitmentPerIndex) {
     161           3 :             ::Serialize(s, obj);
     162             :         }
     163             : 
     164          12 :         WriteCompactSize(s, quorumSnapshotList.size());
     165          15 :         for (const auto& obj : quorumSnapshotList) {
     166           3 :             ::Serialize(s, obj);
     167             :         }
     168             : 
     169          12 :         WriteCompactSize(s, mnListDiffList.size());
     170          12 :         for (const auto& obj : mnListDiffList) {
     171           0 :             ::Serialize(s, obj);
     172             :         }
     173          12 :     }
     174             : 
     175             :     template <typename Stream>
     176           4 :     void Unserialize(Stream& s)
     177             :     {
     178           4 :         SerializationOpBase(s, CSerActionUnserialize());
     179             : 
     180           4 :         if (extraShare) {
     181           3 :             CycleData val{};
     182           3 :             ::Unserialize(s, val.m_snap);
     183           3 :             ::Unserialize(s, val.m_diff);
     184           3 :             cycleHMinus4C = val;
     185           3 :         }
     186             : 
     187           4 :         size_t cnt = ReadCompactSize(s);
     188           5 :         for ([[maybe_unused]] const auto _ : util::irange(cnt)) {
     189           1 :             CFinalCommitment qc;
     190           1 :             ::Unserialize(s, qc);
     191           1 :             lastCommitmentPerIndex.push_back(std::move(qc));
     192           1 :         }
     193             : 
     194           4 :         cnt = ReadCompactSize(s);
     195           5 :         for ([[maybe_unused]] const auto _ : util::irange(cnt)) {
     196           1 :             CQuorumSnapshot snap;
     197           1 :             ::Unserialize(s, snap);
     198           1 :             quorumSnapshotList.push_back(std::move(snap));
     199           1 :         }
     200             : 
     201           4 :         cnt = ReadCompactSize(s);
     202           4 :         for ([[maybe_unused]] const auto _ : util::irange(cnt)) {
     203           0 :             CSimplifiedMNListDiff mnlist;
     204           0 :             ::Unserialize(s, mnlist);
     205           0 :             mnListDiffList.push_back(std::move(mnlist));
     206           0 :         }
     207           4 :     }
     208             : 
     209             :     std::vector<CycleData*> GetCycles();
     210             :     [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
     211             :     [[nodiscard]] UniValue ToJson() const;
     212             : };
     213             : 
     214             : bool BuildQuorumRotationInfo(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman,
     215             :                              const ChainstateManager& chainman, const CQuorumManager& qman,
     216             :                              const CQuorumBlockProcessor& qblockman, const CGetQuorumRotationInfo& request,
     217             :                              bool use_legacy_construction, CQuorumRotationInfo& response, std::string& errorRet)
     218             :     EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
     219             : uint256 GetLastBaseBlockHash(Span<const CBlockIndex*> baseBlockIndexes, const CBlockIndex* blockIndex,
     220             :                              bool use_legacy_construction);
     221             : 
     222             : class CQuorumSnapshotManager
     223             : {
     224             : private:
     225             :     mutable RecursiveMutex snapshotCacheCs;
     226             : 
     227             :     CEvoDB& m_evoDb;
     228             : 
     229             :     Uint256LruHashMap<CQuorumSnapshot> quorumSnapshotCache GUARDED_BY(snapshotCacheCs);
     230             : 
     231             : public:
     232             :     CQuorumSnapshotManager() = delete;
     233             :     CQuorumSnapshotManager(const CQuorumSnapshotManager&) = delete;
     234             :     CQuorumSnapshotManager& operator=(const CQuorumSnapshotManager&) = delete;
     235             :     explicit CQuorumSnapshotManager(CEvoDB& evoDb);
     236             :     ~CQuorumSnapshotManager();
     237             : 
     238             :     std::optional<CQuorumSnapshot> GetSnapshotForBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex);
     239             :     void StoreSnapshotForBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, const CQuorumSnapshot& snapshot);
     240             : };
     241             : } // namespace llmq
     242             : 
     243             : #endif // BITCOIN_LLMQ_SNAPSHOT_H

Generated by: LCOV version 1.16