Line data Source code
1 : // Copyright (c) 2018-2021 The Dash Core developers
2 : // Copyright (c) 2021 The PIVX Core developers
3 : // Distributed under the MIT software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #ifndef PIVX_EVO_DETERMINISTICMNS_H
7 : #define PIVX_EVO_DETERMINISTICMNS_H
8 :
9 : #include "arith_uint256.h"
10 : #include "bls/bls_wrapper.h"
11 : #include "dbwrapper.h"
12 : #include "evo/evodb.h"
13 : #include "evo/providertx.h"
14 : #include "llmq/quorums_commitment.h"
15 : #include "netaddress.h"
16 : #include "saltedhasher.h"
17 : #include "serialize.h"
18 : #include "sync.h"
19 : #include "version.h"
20 :
21 : #include <immer/map.hpp>
22 : #include <immer/map_transient.hpp>
23 :
24 : #include <unordered_map>
25 :
26 : class CBlock;
27 : class CBlockIndex;
28 : class CValidationState;
29 :
30 : class CDeterministicMNState
31 : {
32 : public:
33 : int nRegisteredHeight{-1};
34 : int nLastPaidHeight{0};
35 : int nPoSePenalty{0};
36 : int nPoSeRevivedHeight{-1};
37 : int nPoSeBanHeight{-1};
38 : uint16_t nRevocationReason{ProUpRevPL::REASON_NOT_SPECIFIED};
39 :
40 : // the block hash X blocks after registration, used in quorum calculations
41 : uint256 confirmedHash;
42 : // sha256(proTxHash, confirmedHash) to speed up quorum calculations
43 : // please note that this is NOT a double-sha256 hash
44 : uint256 confirmedHashWithProRegTxHash;
45 :
46 : CKeyID keyIDOwner;
47 : CBLSLazyPublicKey pubKeyOperator;
48 : CKeyID keyIDVoting;
49 : CService addr;
50 : CScript scriptPayout;
51 : CScript scriptOperatorPayout;
52 :
53 : public:
54 46955 : CDeterministicMNState() {}
55 480 : explicit CDeterministicMNState(const ProRegPL& pl)
56 2400 : {
57 480 : keyIDOwner = pl.keyIDOwner;
58 480 : pubKeyOperator.Set(pl.pubKeyOperator);
59 480 : keyIDVoting = pl.keyIDVoting;
60 480 : addr = pl.addr;
61 480 : scriptPayout = pl.scriptPayout;
62 480 : scriptOperatorPayout = pl.scriptOperatorPayout;
63 480 : }
64 : template <typename Stream>
65 90 : CDeterministicMNState(deserialize_type, Stream& s) { s >> *this; }
66 :
67 2418 : SERIALIZE_METHODS(CDeterministicMNState, obj)
68 : {
69 1209 : READWRITE(obj.nRegisteredHeight);
70 1209 : READWRITE(obj.nLastPaidHeight);
71 1209 : READWRITE(obj.nPoSePenalty);
72 1209 : READWRITE(obj.nPoSeRevivedHeight);
73 1209 : READWRITE(obj.nPoSeBanHeight);
74 1209 : READWRITE(obj.nRevocationReason);
75 1209 : READWRITE(obj.confirmedHash);
76 1209 : READWRITE(obj.confirmedHashWithProRegTxHash);
77 1209 : READWRITE(obj.keyIDOwner);
78 1209 : READWRITE(obj.pubKeyOperator);
79 1209 : READWRITE(obj.keyIDVoting);
80 1209 : READWRITE(obj.addr);
81 1209 : READWRITE(obj.scriptPayout);
82 1209 : READWRITE(obj.scriptOperatorPayout);
83 1209 : }
84 :
85 52 : void ResetOperatorFields()
86 : {
87 104 : pubKeyOperator.Set(CBLSPublicKey());
88 52 : addr = CService();
89 52 : scriptOperatorPayout = CScript();
90 52 : nRevocationReason = ProUpRevPL::REASON_NOT_SPECIFIED;
91 52 : }
92 52 : void BanIfNotBanned(int height)
93 : {
94 52 : if (nPoSeBanHeight == -1) {
95 34 : nPoSeBanHeight = height;
96 : }
97 : }
98 475 : void UpdateConfirmedHash(const uint256& _proTxHash, const uint256& _confirmedHash)
99 : {
100 475 : confirmedHash = _confirmedHash;
101 475 : CSHA256 h;
102 475 : h.Write(_proTxHash.begin(), _proTxHash.size());
103 475 : h.Write(_confirmedHash.begin(), _confirmedHash.size());
104 475 : h.Finalize(confirmedHashWithProRegTxHash.begin());
105 475 : }
106 :
107 : public:
108 : std::string ToString() const;
109 : void ToJson(UniValue& obj) const;
110 : };
111 : typedef std::shared_ptr<CDeterministicMNState> CDeterministicMNStatePtr;
112 : typedef std::shared_ptr<const CDeterministicMNState> CDeterministicMNStateCPtr;
113 :
114 82913 : class CDeterministicMNStateDiff
115 : {
116 : public:
117 : enum Field : uint32_t {
118 : Field_nRegisteredHeight = 0x0001,
119 : Field_nLastPaidHeight = 0x0002,
120 : Field_nPoSePenalty = 0x0004,
121 : Field_nPoSeRevivedHeight = 0x0008,
122 : Field_nPoSeBanHeight = 0x0010,
123 : Field_nRevocationReason = 0x0020,
124 : Field_confirmedHash = 0x0040,
125 : Field_confirmedHashWithProRegTxHash = 0x0080,
126 : Field_keyIDOwner = 0x0100,
127 : Field_pubKeyOperator = 0x0200,
128 : Field_keyIDVoting = 0x0400,
129 : Field_addr = 0x0800,
130 : Field_scriptPayout = 0x1000,
131 : Field_scriptOperatorPayout = 0x2000,
132 : };
133 :
134 : #define DMN_STATE_DIFF_ALL_FIELDS \
135 : DMN_STATE_DIFF_LINE(nRegisteredHeight) \
136 : DMN_STATE_DIFF_LINE(nLastPaidHeight) \
137 : DMN_STATE_DIFF_LINE(nPoSePenalty) \
138 : DMN_STATE_DIFF_LINE(nPoSeRevivedHeight) \
139 : DMN_STATE_DIFF_LINE(nPoSeBanHeight) \
140 : DMN_STATE_DIFF_LINE(nRevocationReason) \
141 : DMN_STATE_DIFF_LINE(confirmedHash) \
142 : DMN_STATE_DIFF_LINE(confirmedHashWithProRegTxHash) \
143 : DMN_STATE_DIFF_LINE(keyIDOwner) \
144 : DMN_STATE_DIFF_LINE(pubKeyOperator) \
145 : DMN_STATE_DIFF_LINE(keyIDVoting) \
146 : DMN_STATE_DIFF_LINE(addr) \
147 : DMN_STATE_DIFF_LINE(scriptPayout) \
148 : DMN_STATE_DIFF_LINE(scriptOperatorPayout)
149 :
150 : public:
151 : uint32_t fields{0};
152 : // we reuse the state class, but only the members as noted by fields are valid
153 : CDeterministicMNState state;
154 :
155 : public:
156 134 : CDeterministicMNStateDiff() {}
157 9257 : CDeterministicMNStateDiff(const CDeterministicMNState& a, const CDeterministicMNState& b)
158 9257 : {
159 : #define DMN_STATE_DIFF_LINE(f) if (a.f != b.f) { state.f = b.f; fields |= Field_##f; }
160 9257 : DMN_STATE_DIFF_ALL_FIELDS
161 : #undef DMN_STATE_DIFF_LINE
162 9257 : }
163 :
164 54770 : SERIALIZE_METHODS(CDeterministicMNStateDiff, obj)
165 : {
166 27385 : READWRITE(VARINT(obj.fields));
167 : #define DMN_STATE_DIFF_LINE(f) if (obj.fields & Field_##f) READWRITE(obj.state.f);
168 27385 : DMN_STATE_DIFF_ALL_FIELDS
169 : #undef DMN_STATE_DIFF_LINE
170 27385 : }
171 :
172 10762 : void ApplyToState(CDeterministicMNState& target) const
173 : {
174 : #define DMN_STATE_DIFF_LINE(f) if (fields & Field_##f) target.f = state.f;
175 10810 : DMN_STATE_DIFF_ALL_FIELDS
176 : #undef DMN_STATE_DIFF_LINE
177 10762 : }
178 : };
179 :
180 50452 : class CDeterministicMN
181 : {
182 : private:
183 : uint64_t internalId{std::numeric_limits<uint64_t>::max()};
184 :
185 : public:
186 : CDeterministicMN() = delete; // no default constructor, must specify internalId
187 4972 : explicit CDeterministicMN(uint64_t _internalId) : internalId(_internalId)
188 : {
189 : // only non-initial values
190 2486 : assert(_internalId != std::numeric_limits<uint64_t>::max());
191 2486 : }
192 : // TODO: can be removed in a future version
193 : CDeterministicMN(const CDeterministicMN& mn, uint64_t _internalId) : CDeterministicMN(mn) {
194 : // only non-initial values
195 : assert(_internalId != std::numeric_limits<uint64_t>::max());
196 : internalId = _internalId;
197 : }
198 :
199 : template <typename Stream>
200 18 : CDeterministicMN(deserialize_type, Stream& s)
201 36 : {
202 18 : s >> *this;
203 18 : }
204 :
205 : uint256 proTxHash;
206 : COutPoint collateralOutpoint;
207 : uint16_t nOperatorReward;
208 : CDeterministicMNStateCPtr pdmnState;
209 :
210 : public:
211 2418 : SERIALIZE_METHODS(CDeterministicMN, obj)
212 : {
213 1209 : READWRITE(obj.proTxHash);
214 1209 : READWRITE(VARINT(obj.internalId));
215 1209 : READWRITE(obj.collateralOutpoint);
216 1209 : READWRITE(obj.nOperatorReward);
217 1209 : READWRITE(obj.pdmnState);
218 1209 : }
219 :
220 : uint64_t GetInternalId() const;
221 234734 : bool IsPoSeBanned() const { return pdmnState->nPoSeBanHeight != -1; }
222 :
223 : std::string ToString() const;
224 : void ToJson(UniValue& obj) const;
225 : };
226 :
227 : typedef std::shared_ptr<const CDeterministicMN> CDeterministicMNCPtr;
228 :
229 : class CDeterministicMNListDiff;
230 :
231 : template <typename Stream, typename K, typename T, typename Hash, typename Equal>
232 : void SerializeImmerMap(Stream& os, const immer::map<K, T, Hash, Equal>& m)
233 : {
234 : WriteCompactSize(os, m.size());
235 : for (typename immer::map<K, T, Hash, Equal>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
236 : Serialize(os, (*mi));
237 : }
238 :
239 : template <typename Stream, typename K, typename T, typename Hash, typename Equal>
240 : void UnserializeImmerMap(Stream& is, immer::map<K, T, Hash, Equal>& m)
241 : {
242 : m = immer::map<K, T, Hash, Equal>();
243 : unsigned int nSize = ReadCompactSize(is);
244 : for (unsigned int i = 0; i < nSize; i++) {
245 : std::pair<K, T> item;
246 : Unserialize(is, item);
247 : m = m.set(item.first, item.second);
248 : }
249 : }
250 :
251 : // For some reason the compiler is not able to choose the correct Serialize/Deserialize methods without a specialized
252 : // version of SerReadWrite. It otherwise always chooses the version that calls a.Serialize()
253 : template<typename Stream, typename K, typename T, typename Hash, typename Equal>
254 : inline void SerReadWrite(Stream& s, const immer::map<K, T, Hash, Equal>& m, CSerActionSerialize ser_action)
255 : {
256 : ::SerializeImmerMap(s, m);
257 : }
258 :
259 : template<typename Stream, typename K, typename T, typename Hash, typename Equal>
260 : inline void SerReadWrite(Stream& s, immer::map<K, T, Hash, Equal>& obj, CSerActionUnserialize ser_action)
261 : {
262 : ::UnserializeImmerMap(s, obj);
263 : }
264 :
265 27438 : class CDeterministicMNList
266 : {
267 : public:
268 : typedef immer::map<uint256, CDeterministicMNCPtr> MnMap;
269 : typedef immer::map<uint64_t, uint256> MnInternalIdMap;
270 : typedef immer::map<uint256, std::pair<uint256, uint32_t> > MnUniquePropertyMap;
271 :
272 : private:
273 : uint256 blockHash;
274 : int nHeight{-1};
275 : uint32_t nTotalRegisteredCount{0};
276 : MnMap mnMap;
277 : MnInternalIdMap mnInternalIdMap;
278 :
279 : // map of unique properties like address and keys
280 : // we keep track of this as checking for duplicates would otherwise be painfully slow
281 : MnUniquePropertyMap mnUniquePropertyMap;
282 :
283 : public:
284 831454 : CDeterministicMNList() {}
285 0 : explicit CDeterministicMNList(const uint256& _blockHash, int _height, uint32_t _totalRegisteredCount) :
286 : blockHash(_blockHash),
287 : nHeight(_height),
288 0 : nTotalRegisteredCount(_totalRegisteredCount)
289 : {
290 0 : }
291 :
292 : template<typename Stream>
293 214 : void Serialize(Stream& s) const
294 : {
295 214 : s << blockHash;
296 214 : s << nHeight;
297 214 : s << nTotalRegisteredCount;
298 : // Serialize the map as a vector
299 214 : WriteCompactSize(s, mnMap.size());
300 432 : for (const auto& p : mnMap) {
301 4 : s << *p.second;
302 : }
303 214 : }
304 :
305 : template<typename Stream>
306 2 : void Unserialize(Stream& s) {
307 2 : mnMap = MnMap();
308 2 : mnUniquePropertyMap = MnUniquePropertyMap();
309 2 : mnInternalIdMap = MnInternalIdMap();
310 :
311 2 : s >> blockHash;
312 2 : s >> nHeight;
313 2 : s >> nTotalRegisteredCount;
314 2 : size_t cnt = ReadCompactSize(s);
315 2 : for (size_t i = 0; i < cnt; i++) {
316 0 : AddMN(std::make_shared<CDeterministicMN>(deserialize, s), false);
317 : }
318 2 : }
319 :
320 : public:
321 5072 : size_t GetAllMNsCount() const
322 : {
323 5072 : return mnMap.size();
324 : }
325 :
326 16905 : size_t GetValidMNsCount() const
327 : {
328 16905 : size_t count = 0;
329 141512 : for (const auto& p : mnMap) {
330 53851 : if (!p.second->IsPoSeBanned()) {
331 53377 : count++;
332 : }
333 : }
334 16905 : return count;
335 : }
336 :
337 : template <typename Callback>
338 61936 : void ForEachMN(bool onlyValid, Callback&& cb) const
339 : {
340 715086 : for (const auto& p : mnMap) {
341 295607 : if (!onlyValid || !p.second->IsPoSeBanned()) {
342 294209 : cb(p.second);
343 : }
344 : }
345 61936 : }
346 :
347 : public:
348 106484 : const uint256& GetBlockHash() const { return blockHash; }
349 902525 : int GetHeight() const { return nHeight; }
350 486 : uint32_t GetTotalRegisteredCount() const { return nTotalRegisteredCount; }
351 11384 : void SetHeight(int _height) { nHeight = _height; }
352 20015 : void SetBlockHash(const uint256& _blockHash) { blockHash = _blockHash; }
353 :
354 8789 : bool HasMN(const uint256& proTxHash) const
355 : {
356 8789 : return GetMN(proTxHash) != nullptr;
357 : }
358 207 : bool HasMNByCollateral(const COutPoint& collateralOutpoint) const
359 : {
360 207 : return GetMNByCollateral(collateralOutpoint) != nullptr;
361 : }
362 : bool HasValidMNByCollateral(const COutPoint& collateralOutpoint) const
363 : {
364 : return GetValidMNByCollateral(collateralOutpoint) != nullptr;
365 : }
366 : CDeterministicMNCPtr GetMN(const uint256& proTxHash) const;
367 : CDeterministicMNCPtr GetValidMN(const uint256& proTxHash) const;
368 : CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey& pubKey);
369 : CDeterministicMNCPtr GetMNByCollateral(const COutPoint& collateralOutpoint) const;
370 : CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint& collateralOutpoint) const;
371 : CDeterministicMNCPtr GetMNByService(const CService& service) const;
372 : CDeterministicMNCPtr GetMNByInternalId(uint64_t internalId) const;
373 : CDeterministicMNCPtr GetMNPayee() const;
374 :
375 : /**
376 : * Calculates the projected MN payees for the next *count* blocks. The result is not guaranteed to be correct
377 : * as PoSe banning might occur later
378 : * @param count
379 : * @return
380 : */
381 : std::vector<CDeterministicMNCPtr> GetProjectedMNPayees(unsigned int nCount) const;
382 :
383 : /**
384 : * Calculate a quorum based on the modifier. The resulting list is deterministically sorted by score
385 : * @param maxSize
386 : * @param modifier
387 : * @return
388 : */
389 : std::vector<CDeterministicMNCPtr> CalculateQuorum(size_t maxSize, const uint256& modifier) const;
390 : std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> CalculateScores(const uint256& modifier) const;
391 :
392 : /**
393 : * Calculates the maximum penalty which is allowed at the height of this MN list. It is dynamic and might change
394 : * for every block.
395 : * @return
396 : */
397 : int CalcMaxPoSePenalty() const;
398 :
399 : /**
400 : * Returns a the given percentage from the max penalty for this MN list. Always use this method to calculate the
401 : * value later passed to PoSePunish. The percentage should be high enough to take per-block penalty decreasing for MNs
402 : * into account. This means, if you want to accept 2 failures per payment cycle, you should choose a percentage that
403 : * is higher then 50%, e.g. 66%.
404 : * @param percent
405 : * @return
406 : */
407 : int CalcPenalty(int percent) const;
408 :
409 : /**
410 : * Punishes a MN for misbehavior. If the resulting penalty score of the MN reaches the max penalty, it is banned.
411 : * Penalty scores are only increased when the MN is not already banned, which means that after banning the penalty
412 : * might appear lower then the current max penalty, while the MN is still banned.
413 : * @param proTxHash
414 : * @param penalty
415 : */
416 : void PoSePunish(const uint256& proTxHash, int penalty, bool debugLogs);
417 :
418 : /**
419 : * Decrease penalty score of MN by 1.
420 : * Only allowed on non-banned MNs.
421 : * @param proTxHash
422 : */
423 : void PoSeDecrease(const uint256& proTxHash);
424 :
425 : CDeterministicMNListDiff BuildDiff(const CDeterministicMNList& to) const;
426 : CDeterministicMNList ApplyDiff(const CBlockIndex* pindex, const CDeterministicMNListDiff& diff) const;
427 :
428 : void AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount = true);
429 : void UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateCPtr& pdmnState);
430 : void UpdateMN(const uint256& proTxHash, const CDeterministicMNStateCPtr& pdmnState);
431 : void UpdateMN(const CDeterministicMNCPtr& oldDmn, const CDeterministicMNStateDiff& stateDiff);
432 : void RemoveMN(const uint256& proTxHash);
433 :
434 : template <typename T>
435 29629 : bool HasUniqueProperty(const T& v) const
436 : {
437 29629 : return mnUniquePropertyMap.count(::SerializeHash(v, SER_GETHASH, PROTOCOL_VERSION | ADDRV2_FORMAT)) != 0;
438 : }
439 : template <typename T>
440 556671 : CDeterministicMNCPtr GetUniquePropertyMN(const T& v) const
441 : {
442 556671 : auto p = mnUniquePropertyMap.find(::SerializeHash(v, SER_GETHASH, PROTOCOL_VERSION | ADDRV2_FORMAT));
443 556671 : if (!p) {
444 556671 : return nullptr;
445 : }
446 23015 : return GetMN(p->first);
447 : }
448 :
449 : private:
450 : template <typename T>
451 4426 : void AddUniqueProperty(const CDeterministicMNCPtr& dmn, const T& v)
452 : {
453 4499 : static const T nullValue;
454 4426 : assert(v != nullValue);
455 :
456 4426 : auto hash = ::SerializeHash(v, SER_GETHASH, PROTOCOL_VERSION | ADDRV2_FORMAT);
457 4426 : auto oldEntry = mnUniquePropertyMap.find(hash);
458 4426 : assert(!oldEntry || oldEntry->first == dmn->proTxHash);
459 4426 : std::pair<uint256, uint32_t> newEntry(dmn->proTxHash, 1);
460 4426 : if (oldEntry) {
461 0 : newEntry.second = oldEntry->second + 1;
462 : }
463 4426 : mnUniquePropertyMap = mnUniquePropertyMap.set(hash, newEntry);
464 4426 : }
465 : template <typename T>
466 353 : void DeleteUniqueProperty(const CDeterministicMNCPtr& dmn, const T& oldValue)
467 : {
468 367 : static const T nullValue;
469 353 : assert(oldValue != nullValue);
470 :
471 353 : auto oldHash = ::SerializeHash(oldValue, SER_GETHASH, PROTOCOL_VERSION | ADDRV2_FORMAT);
472 353 : auto p = mnUniquePropertyMap.find(oldHash);
473 353 : assert(p && p->first == dmn->proTxHash);
474 353 : if (p->second == 1) {
475 353 : mnUniquePropertyMap = mnUniquePropertyMap.erase(oldHash);
476 : } else {
477 0 : mnUniquePropertyMap = mnUniquePropertyMap.set(oldHash, std::make_pair(dmn->proTxHash, p->second - 1));
478 : }
479 353 : }
480 : template <typename T>
481 65922 : void UpdateUniqueProperty(const CDeterministicMNCPtr& dmn, const T& oldValue, const T& newValue)
482 : {
483 65922 : if (oldValue == newValue) {
484 : return;
485 : }
486 201 : static const T nullValue;
487 :
488 201 : if (oldValue != nullValue) {
489 165 : DeleteUniqueProperty(dmn, oldValue);
490 : }
491 :
492 201 : if (newValue != nullValue) {
493 98 : AddUniqueProperty(dmn, newValue);
494 : }
495 : }
496 : };
497 :
498 18809 : class CDeterministicMNListDiff
499 : {
500 : public:
501 : int nHeight{-1}; //memory only
502 :
503 : std::vector<CDeterministicMNCPtr> addedMNs;
504 : // keys are all relating to the internalId of MNs
505 : std::map<uint64_t, CDeterministicMNStateDiff> updatedMNs;
506 : std::set<uint64_t> removedMns;
507 :
508 : public:
509 : template<typename Stream>
510 25723 : void Serialize(Stream& s) const
511 : {
512 25723 : s << addedMNs;
513 25723 : WriteCompactSize(s, updatedMNs.size());
514 52974 : for (const auto& p : updatedMNs) {
515 27251 : s << VARINT(p.first);
516 27251 : s << p.second;
517 : }
518 25723 : WriteCompactSize(s, removedMns.size());
519 25789 : for (const auto& p : removedMns) {
520 66 : s << VARINT(p);
521 : }
522 25723 : }
523 :
524 : template<typename Stream>
525 124 : void Unserialize(Stream& s)
526 : {
527 124 : updatedMNs.clear();
528 124 : removedMns.clear();
529 :
530 : size_t tmp;
531 : uint64_t tmp2;
532 124 : s >> addedMNs;
533 124 : tmp = ReadCompactSize(s);
534 258 : for (size_t i = 0; i < tmp; i++) {
535 268 : CDeterministicMNStateDiff diff;
536 134 : s >> VARINT(tmp2);
537 134 : s >> diff;
538 134 : updatedMNs.emplace(tmp2, std::move(diff));
539 : }
540 124 : tmp = ReadCompactSize(s);
541 124 : for (size_t i = 0; i < tmp; i++) {
542 0 : s >> VARINT(tmp2);
543 0 : removedMns.emplace(tmp2);
544 : }
545 124 : }
546 :
547 : public:
548 18816 : bool HasChanges() const
549 : {
550 18816 : return !addedMNs.empty() || !updatedMNs.empty() || !removedMns.empty();
551 : }
552 : };
553 :
554 772 : class CDeterministicMNManager
555 : {
556 : static const int DISK_SNAPSHOT_PERIOD = 1440; // once per day
557 : static const int DISK_SNAPSHOTS = 3; // keep cache for 3 disk snapshots to have 2 full days covered
558 : static const int LIST_DIFFS_CACHE_SIZE = DISK_SNAPSHOT_PERIOD * DISK_SNAPSHOTS;
559 :
560 : public:
561 : mutable RecursiveMutex cs;
562 :
563 : private:
564 : CEvoDB& evoDb;
565 :
566 : std::unordered_map<uint256, CDeterministicMNList, StaticSaltedHasher> mnListsCache;
567 : std::unordered_map<uint256, CDeterministicMNListDiff, StaticSaltedHasher> mnListDiffsCache;
568 : const CBlockIndex* tipIndex{nullptr};
569 :
570 : public:
571 : explicit CDeterministicMNManager(CEvoDB& _evoDb);
572 :
573 : bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& state, bool fJustCheck);
574 : bool UndoBlock(const CBlock& block, const CBlockIndex* pindex);
575 :
576 : void SetTipIndex(const CBlockIndex* pindex);
577 :
578 : // the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet)
579 : bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& state, CDeterministicMNList& mnListRet, bool debugLogs);
580 : void HandleQuorumCommitment(llmq::CFinalCommitment& qc, const CBlockIndex* pindexQuorum, CDeterministicMNList& mnList, bool debugLogs);
581 : void DecreasePoSePenalties(CDeterministicMNList& mnList);
582 :
583 : // to return a valid list, it must have been built first, so never call it with a block not-yet connected (e.g. from CheckBlock).
584 : CDeterministicMNList GetListForBlock(const CBlockIndex* pindex);
585 : CDeterministicMNList GetListAtChainTip();
586 :
587 : // Whether DMNs are enforced at provided height, or at the chain-tip
588 : bool IsDIP3Enforced(int nHeight) const;
589 : bool IsDIP3Enforced() const;
590 :
591 : // Whether Legacy MNs are disabled at provided height, or at the chain-tip
592 : bool LegacyMNObsolete(int nHeight) const;
593 : bool LegacyMNObsolete() const;
594 :
595 : // Get the list of members for a given quorum type and index
596 : std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum);
597 :
598 : private:
599 : void CleanupCache(int nHeight);
600 : };
601 :
602 : extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
603 :
604 : #endif // PIVX_EVO_DETERMINISTICMNS_H
|