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 810 : 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 273 : inline void SerializationOpBase(Stream& s, Operation ser_action)
56 : {
57 273 : READWRITE(mnSkipListMode);
58 273 : }
59 :
60 : template <typename Stream>
61 240 : void Serialize(Stream& s) const
62 : {
63 240 : const_cast<CQuorumSnapshot*>(this)->SerializationOpBase(s, CSerActionSerialize());
64 :
65 240 : WriteCompactSize(s, activeQuorumMembers.size());
66 240 : WriteFixedBitSet(s, activeQuorumMembers, activeQuorumMembers.size());
67 240 : WriteCompactSize(s, mnSkipList.size());
68 427 : for (const auto& obj : mnSkipList) {
69 187 : s << obj;
70 : }
71 240 : }
72 :
73 : template <typename Stream>
74 33 : void Unserialize(Stream& s)
75 : {
76 33 : SerializationOpBase(s, CSerActionUnserialize());
77 :
78 33 : size_t cnt = ReadCompactSize(s);
79 33 : ReadFixedBitSet(s, activeQuorumMembers, cnt);
80 33 : cnt = ReadCompactSize(s);
81 174 : for ([[maybe_unused]] const auto _ : util::irange(cnt)) {
82 : int obj;
83 141 : s >> obj;
84 141 : mnSkipList.push_back(obj);
85 : }
86 33 : }
87 :
88 : [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional);
89 : [[nodiscard]] UniValue ToJson() const;
90 : };
91 :
92 4 : 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 2368 : struct CycleBase {
106 : CQuorumSnapshot m_snap;
107 2368 : const CBlockIndex* m_cycle_index{nullptr};
108 : };
109 :
110 41 : struct CycleData : public CycleBase {
111 : CSimplifiedMNListDiff m_diff;
112 19 : 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
|