forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
deterministicmns.h
626 lines (540 loc) · 23.9 KB
/
deterministicmns.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
// Copyright (c) 2018-2022 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_EVO_DETERMINISTICMNS_H
#define BITCOIN_EVO_DETERMINISTICMNS_H
#include <evo/dmnstate.h>
#include <arith_uint256.h>
#include <consensus/params.h>
#include <crypto/common.h>
#include <evo/dmn_types.h>
#include <evo/evodb.h>
#include <evo/providertx.h>
#include <saltedhasher.h>
#include <scheduler.h>
#include <sync.h>
#include <immer/map.hpp>
#include <limits>
#include <numeric>
#include <unordered_map>
#include <utility>
class CConnman;
class CBlock;
class CBlockIndex;
class TxValidationState;
extern RecursiveMutex cs_main;
namespace llmq
{
class CFinalCommitment;
} // namespace llmq
class CDeterministicMN
{
private:
uint64_t internalId{std::numeric_limits<uint64_t>::max()};
public:
static constexpr uint16_t MN_OLD_FORMAT = 0;
static constexpr uint16_t MN_TYPE_FORMAT = 1;
static constexpr uint16_t MN_VERSION_FORMAT = 2;
static constexpr uint16_t MN_CURRENT_FORMAT = MN_VERSION_FORMAT;
uint256 proTxHash;
COutPoint collateralOutpoint;
uint16_t nOperatorReward{0};
MnType nType{MnType::Regular};
std::shared_ptr<const CDeterministicMNState> pdmnState;
CDeterministicMN() = delete; // no default constructor, must specify internalId
explicit CDeterministicMN(uint64_t _internalId, MnType mnType = MnType::Regular) :
internalId(_internalId),
nType(mnType)
{
// only non-initial values
assert(_internalId != std::numeric_limits<uint64_t>::max());
}
template <typename Stream>
CDeterministicMN(deserialize_type, Stream& s, const uint8_t format_version)
{
SerializationOp(s, CSerActionUnserialize(), format_version);
}
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, const uint8_t format_version)
{
READWRITE(proTxHash);
READWRITE(VARINT(internalId));
READWRITE(collateralOutpoint);
READWRITE(nOperatorReward);
// We need to read CDeterministicMNState using the old format only when called with MN_OLD_FORMAT or MN_TYPE_FORMAT on Unserialize()
// Serialisation (writing) will be done always using new format
if (ser_action.ForRead() && format_version == MN_OLD_FORMAT) {
CDeterministicMNState_Oldformat old_state;
READWRITE(old_state);
pdmnState = std::make_shared<const CDeterministicMNState>(old_state);
} else if (ser_action.ForRead() && format_version == MN_TYPE_FORMAT) {
CDeterministicMNState_mntype_format old_state;
READWRITE(old_state);
pdmnState = std::make_shared<const CDeterministicMNState>(old_state);
} else {
READWRITE(pdmnState);
}
// We need to read/write nType if:
// format_version is set to MN_TYPE_FORMAT (For writing (serialisation) it is always the case) Needed for the MNLISTDIFF Migration in evoDB
// We can't know if we are serialising for the Disk or for the Network here (s.GetType() is not accessible)
// Therefore if s.GetVersion() == CLIENT_VERSION -> Then we know we are serialising for the Disk
// Otherwise, we can safely check with protocol versioning logic so we won't break old clients
if (format_version >= MN_TYPE_FORMAT && (s.GetVersion() == CLIENT_VERSION || s.GetVersion() >= DMN_TYPE_PROTO_VERSION)) {
READWRITE(nType);
} else {
nType = MnType::Regular;
}
}
template<typename Stream>
void Serialize(Stream& s) const
{
const_cast<CDeterministicMN*>(this)->SerializationOp(s, CSerActionSerialize(), MN_CURRENT_FORMAT);
}
template <typename Stream>
void Unserialize(Stream& s, const uint8_t format_version = MN_CURRENT_FORMAT)
{
SerializationOp(s, CSerActionUnserialize(), format_version);
}
[[nodiscard]] uint64_t GetInternalId() const;
[[nodiscard]] std::string ToString() const;
void ToJson(UniValue& obj) const;
};
using CDeterministicMNCPtr = std::shared_ptr<const CDeterministicMN>;
class CDeterministicMNListDiff;
template <typename Stream, typename K, typename T, typename Hash, typename Equal>
void SerializeImmerMap(Stream& os, const immer::map<K, T, Hash, Equal>& m)
{
WriteCompactSize(os, m.size());
for (typename immer::map<K, T, Hash, Equal>::const_iterator mi = m.begin(); mi != m.end(); ++mi)
Serialize(os, (*mi));
}
template <typename Stream, typename K, typename T, typename Hash, typename Equal>
void UnserializeImmerMap(Stream& is, immer::map<K, T, Hash, Equal>& m)
{
m = immer::map<K, T, Hash, Equal>();
unsigned int nSize = ReadCompactSize(is);
for (unsigned int i = 0; i < nSize; i++) {
std::pair<K, T> item;
Unserialize(is, item);
m = m.set(item.first, item.second);
}
}
// For some reason the compiler is not able to choose the correct Serialize/Deserialize methods without a specialized
// version of SerReadWrite. It otherwise always chooses the version that calls a.Serialize()
template<typename Stream, typename K, typename T, typename Hash, typename Equal>
inline void SerReadWrite(Stream& s, const immer::map<K, T, Hash, Equal>& m, CSerActionSerialize ser_action)
{
::SerializeImmerMap(s, m);
}
template<typename Stream, typename K, typename T, typename Hash, typename Equal>
inline void SerReadWrite(Stream& s, immer::map<K, T, Hash, Equal>& obj, CSerActionUnserialize ser_action)
{
::UnserializeImmerMap(s, obj);
}
class CDeterministicMNList
{
private:
struct ImmerHasher
{
size_t operator()(const uint256& hash) const { return ReadLE64(hash.begin()); }
};
public:
using MnMap = immer::map<uint256, CDeterministicMNCPtr, ImmerHasher>;
using MnInternalIdMap = immer::map<uint64_t, uint256>;
using MnUniquePropertyMap = immer::map<uint256, std::pair<uint256, uint32_t>, ImmerHasher>;
private:
uint256 blockHash;
int nHeight{-1};
uint32_t nTotalRegisteredCount{0};
MnMap mnMap;
MnInternalIdMap mnInternalIdMap;
// map of unique properties like address and keys
// we keep track of this as checking for duplicates would otherwise be painfully slow
MnUniquePropertyMap mnUniquePropertyMap;
public:
CDeterministicMNList() = default;
explicit CDeterministicMNList(const uint256& _blockHash, int _height, uint32_t _totalRegisteredCount) :
blockHash(_blockHash),
nHeight(_height),
nTotalRegisteredCount(_totalRegisteredCount)
{
}
template <typename Stream, typename Operation>
inline void SerializationOpBase(Stream& s, Operation ser_action)
{
READWRITE(blockHash);
READWRITE(nHeight);
READWRITE(nTotalRegisteredCount);
}
template<typename Stream>
void Serialize(Stream& s) const
{
const_cast<CDeterministicMNList*>(this)->SerializationOpBase(s, CSerActionSerialize());
// Serialize the map as a vector
WriteCompactSize(s, mnMap.size());
for (const auto& p : mnMap) {
s << *p.second;
}
}
template<typename Stream>
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_CURRENT_FORMAT) {
mnMap = MnMap();
mnUniquePropertyMap = MnUniquePropertyMap();
mnInternalIdMap = MnInternalIdMap();
SerializationOpBase(s, CSerActionUnserialize());
bool evodb_migration = (format_version == CDeterministicMN::MN_OLD_FORMAT || format_version == CDeterministicMN::MN_TYPE_FORMAT);
size_t cnt = ReadCompactSize(s);
for (size_t i = 0; i < cnt; i++) {
if (evodb_migration) {
const auto dmn = std::make_shared<CDeterministicMN>(deserialize, s, format_version);
mnMap = mnMap.set(dmn->proTxHash, dmn);
} else {
AddMN(std::make_shared<CDeterministicMN>(deserialize, s, format_version), false);
}
}
}
[[nodiscard]] size_t GetAllMNsCount() const
{
return mnMap.size();
}
[[nodiscard]] size_t GetValidMNsCount() const
{
return ranges::count_if(mnMap, [](const auto& p){ return IsMNValid(*p.second); });
}
[[nodiscard]] size_t GetAllHPMNsCount() const
{
return ranges::count_if(mnMap, [](const auto& p) { return p.second->nType == MnType::HighPerformance; });
}
[[nodiscard]] size_t GetValidHPMNsCount() const
{
return ranges::count_if(mnMap, [](const auto& p) { return p.second->nType == MnType::HighPerformance && IsMNValid(*p.second); });
}
[[nodiscard]] size_t GetValidWeightedMNsCount() const
{
return std::accumulate(mnMap.begin(), mnMap.end(), 0, [](auto res, const auto& p) {
if (!IsMNValid(*p.second)) return res;
return res + GetMnType(p.second->nType).voting_weight;
});
}
/**
* Execute a callback on all masternodes in the mnList. This will pass a reference
* of each masternode to the callback function. This should be preferred over ForEachMNShared.
* @param onlyValid Run on all masternodes, or only "valid" (not banned) masternodes
* @param cb callback to execute
*/
template <typename Callback>
void ForEachMN(bool onlyValid, Callback&& cb) const
{
for (const auto& p : mnMap) {
if (!onlyValid || IsMNValid(*p.second)) {
cb(*p.second);
}
}
}
/**
* Prefer ForEachMN. Execute a callback on all masternodes in the mnList.
* This will pass a non-null shared_ptr of each masternode to the callback function.
* Use this function only when a shared_ptr is needed in order to take shared ownership.
* @param onlyValid Run on all masternodes, or only "valid" (not banned) masternodes
* @param cb callback to execute
*/
template <typename Callback>
void ForEachMNShared(bool onlyValid, Callback&& cb) const
{
for (const auto& p : mnMap) {
if (!onlyValid || IsMNValid(*p.second)) {
cb(p.second);
}
}
}
[[nodiscard]] const uint256& GetBlockHash() const
{
return blockHash;
}
void SetBlockHash(const uint256& _blockHash)
{
blockHash = _blockHash;
}
[[nodiscard]] int GetHeight() const
{
return nHeight;
}
void SetHeight(int _height)
{
nHeight = _height;
}
[[nodiscard]] uint32_t GetTotalRegisteredCount() const
{
return nTotalRegisteredCount;
}
[[nodiscard]] bool IsMNValid(const uint256& proTxHash) const;
[[nodiscard]] bool IsMNPoSeBanned(const uint256& proTxHash) const;
static bool IsMNValid(const CDeterministicMN& dmn);
static bool IsMNPoSeBanned(const CDeterministicMN& dmn);
[[nodiscard]] bool HasMN(const uint256& proTxHash) const
{
return GetMN(proTxHash) != nullptr;
}
[[nodiscard]] bool HasMNByCollateral(const COutPoint& collateralOutpoint) const
{
return GetMNByCollateral(collateralOutpoint) != nullptr;
}
[[nodiscard]] bool HasValidMNByCollateral(const COutPoint& collateralOutpoint) const
{
return GetValidMNByCollateral(collateralOutpoint) != nullptr;
}
[[nodiscard]] CDeterministicMNCPtr GetMN(const uint256& proTxHash) const;
[[nodiscard]] CDeterministicMNCPtr GetValidMN(const uint256& proTxHash) const;
[[nodiscard]] CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey& pubKey) const;
[[nodiscard]] CDeterministicMNCPtr GetMNByCollateral(const COutPoint& collateralOutpoint) const;
[[nodiscard]] CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint& collateralOutpoint) const;
[[nodiscard]] CDeterministicMNCPtr GetMNByService(const CService& service) const;
[[nodiscard]] CDeterministicMNCPtr GetMNByInternalId(uint64_t internalId) const;
[[nodiscard]] CDeterministicMNCPtr GetMNPayee(const CBlockIndex* pIndex) const;
/**
* Calculates the projected MN payees for the next *count* blocks. The result is not guaranteed to be correct
* as PoSe banning might occur later
* @param nCount the number of payees to return. "nCount = max()"" means "all", use it to avoid calling GetValidWeightedMNsCount twice.
* @return
*/
[[nodiscard]] std::vector<CDeterministicMNCPtr> GetProjectedMNPayees(int nCount = std::numeric_limits<int>::max()) const;
/**
* Calculate a quorum based on the modifier. The resulting list is deterministically sorted by score
* @param maxSize
* @param modifier
* @return
*/
[[nodiscard]] std::vector<CDeterministicMNCPtr> CalculateQuorum(size_t maxSize, const uint256& modifier, const bool onlyHighPerformanceMasternodes = false) const;
[[nodiscard]] std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> CalculateScores(const uint256& modifier, const bool onlyHighPerformanceMasternodes) const;
/**
* Calculates the maximum penalty which is allowed at the height of this MN list. It is dynamic and might change
* for every block.
* @return
*/
[[nodiscard]] int CalcMaxPoSePenalty() const;
/**
* Returns a the given percentage from the max penalty for this MN list. Always use this method to calculate the
* value later passed to PoSePunish. The percentage should be high enough to take per-block penalty decreasing for MNs
* into account. This means, if you want to accept 2 failures per payment cycle, you should choose a percentage that
* is higher then 50%, e.g. 66%.
* @param percent
* @return
*/
[[nodiscard]] int CalcPenalty(int percent) const;
/**
* Punishes a MN for misbehavior. If the resulting penalty score of the MN reaches the max penalty, it is banned.
* Penalty scores are only increased when the MN is not already banned, which means that after banning the penalty
* might appear lower then the current max penalty, while the MN is still banned.
* @param proTxHash
* @param penalty
*/
void PoSePunish(const uint256& proTxHash, int penalty, bool debugLogs);
/**
* Decrease penalty score of MN by 1.
* Only allowed on non-banned MNs.
* @param proTxHash
*/
void PoSeDecrease(const uint256& proTxHash);
[[nodiscard]] CDeterministicMNListDiff BuildDiff(const CDeterministicMNList& to) const;
[[nodiscard]] CDeterministicMNList ApplyDiff(const CBlockIndex* pindex, const CDeterministicMNListDiff& diff) const;
void AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount = true);
void UpdateMN(const CDeterministicMN& oldDmn, const std::shared_ptr<const CDeterministicMNState>& pdmnState);
void UpdateMN(const uint256& proTxHash, const std::shared_ptr<const CDeterministicMNState>& pdmnState);
void UpdateMN(const CDeterministicMN& oldDmn, const CDeterministicMNStateDiff& stateDiff);
void RemoveMN(const uint256& proTxHash);
template <typename T>
[[nodiscard]] bool HasUniqueProperty(const T& v) const
{
return mnUniquePropertyMap.count(::SerializeHash(v)) != 0;
}
template <typename T>
[[nodiscard]] CDeterministicMNCPtr GetUniquePropertyMN(const T& v) const
{
auto p = mnUniquePropertyMap.find(::SerializeHash(v));
if (!p) {
return nullptr;
}
return GetMN(p->first);
}
private:
template <typename T>
[[nodiscard]] bool AddUniqueProperty(const CDeterministicMN& dmn, const T& v, std::optional<bool> specific_legacy_bls_scheme = std::nullopt)
{
static const T nullValue;
if (v == nullValue) {
return false;
}
uint256 hash;
if constexpr (std::is_same<T, CBLSLazyPublicKey>()) {
assert(specific_legacy_bls_scheme.has_value());
CBLSPublicKey local_pub_key = v.Get();
CBLSPublicKeyVersionWrapper wrapped_pub_key(local_pub_key, specific_legacy_bls_scheme.value());
hash = ::SerializeHash(wrapped_pub_key);
} else {
assert(!specific_legacy_bls_scheme.has_value());
hash = ::SerializeHash(v);
}
auto oldEntry = mnUniquePropertyMap.find(hash);
if (oldEntry != nullptr && oldEntry->first != dmn.proTxHash) {
return false;
}
std::pair<uint256, uint32_t> newEntry(dmn.proTxHash, 1);
if (oldEntry != nullptr) {
newEntry.second = oldEntry->second + 1;
}
mnUniquePropertyMap = mnUniquePropertyMap.set(hash, newEntry);
return true;
}
template <typename T>
[[nodiscard]] bool DeleteUniqueProperty(const CDeterministicMN& dmn, const T& oldValue, std::optional<bool> specific_legacy_bls_scheme = std::nullopt)
{
static const T nullValue;
if (oldValue == nullValue) {
return false;
}
uint256 oldHash;
if constexpr (std::is_same<T, CBLSLazyPublicKey>()) {
assert(specific_legacy_bls_scheme.has_value());
CBLSPublicKey local_pub_key = oldValue.Get();
CBLSPublicKeyVersionWrapper wrapped_pub_key(local_pub_key, specific_legacy_bls_scheme.value());
oldHash = ::SerializeHash(wrapped_pub_key);
} else {
assert(!specific_legacy_bls_scheme.has_value());
oldHash = ::SerializeHash(oldValue);
}
auto p = mnUniquePropertyMap.find(oldHash);
if (p == nullptr || p->first != dmn.proTxHash) {
return false;
}
if (p->second == 1) {
mnUniquePropertyMap = mnUniquePropertyMap.erase(oldHash);
} else {
mnUniquePropertyMap = mnUniquePropertyMap.set(oldHash, std::make_pair(dmn.proTxHash, p->second - 1));
}
return true;
}
template <typename T>
[[nodiscard]] bool UpdateUniqueProperty(const CDeterministicMN& dmn, const T& oldValue, const T& newValue, std::optional<bool> specific_legacy_bls_scheme = std::nullopt)
{
if (oldValue == newValue) {
return true;
}
static const T nullValue;
if (oldValue != nullValue && !DeleteUniqueProperty(dmn, oldValue, specific_legacy_bls_scheme)) {
return false;
}
if (newValue != nullValue && !AddUniqueProperty(dmn, newValue, specific_legacy_bls_scheme)) {
return false;
}
return true;
}
};
class CDeterministicMNListDiff
{
public:
int nHeight{-1}; //memory only
std::vector<CDeterministicMNCPtr> addedMNs;
// keys are all relating to the internalId of MNs
std::unordered_map<uint64_t, CDeterministicMNStateDiff> updatedMNs;
std::set<uint64_t> removedMns;
template<typename Stream>
void Serialize(Stream& s) const
{
s << addedMNs;
WriteCompactSize(s, updatedMNs.size());
for (const auto& p : updatedMNs) {
WriteVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s, p.first);
s << p.second;
}
WriteCompactSize(s, removedMns.size());
for (const auto& p : removedMns) {
WriteVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s, p);
}
}
template <typename Stream>
void Unserialize(Stream& s, const uint8_t format_version = CDeterministicMN::MN_CURRENT_FORMAT)
{
updatedMNs.clear();
removedMns.clear();
size_t tmp;
uint64_t tmp2;
tmp = ReadCompactSize(s);
for (size_t i = 0; i < tmp; i++) {
CDeterministicMN mn(0);
mn.Unserialize(s, format_version);
auto dmn = std::make_shared<CDeterministicMN>(mn);
addedMNs.push_back(dmn);
}
tmp = ReadCompactSize(s);
for (size_t i = 0; i < tmp; i++) {
CDeterministicMNStateDiff diff;
// CDeterministicMNState hold new fields {nConsecutivePayments, platformNodeID, platformP2PPort, platformHTTPPort} but no migration is needed here since:
// CDeterministicMNStateDiff is always serialised using a bitmask.
// Because the new field have a new bit guide value then we are good to continue
tmp2 = ReadVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s);
s >> diff;
updatedMNs.emplace(tmp2, std::move(diff));
}
tmp = ReadCompactSize(s);
for (size_t i = 0; i < tmp; i++) {
tmp2 = ReadVarInt<Stream, VarIntMode::DEFAULT, uint64_t>(s);
removedMns.emplace(tmp2);
}
}
bool HasChanges() const
{
return !addedMNs.empty() || !updatedMNs.empty() || !removedMns.empty();
}
};
class CDeterministicMNManager
{
static constexpr int DISK_SNAPSHOT_PERIOD = 576; // once per day
static constexpr int DISK_SNAPSHOTS = 3; // keep cache for 3 disk snapshots to have 2 full days covered
static constexpr int LIST_DIFFS_CACHE_SIZE = DISK_SNAPSHOT_PERIOD * DISK_SNAPSHOTS;
public:
Mutex cs;
private:
Mutex cs_cleanup;
// We have performed CleanupCache() on this height.
int did_cleanup GUARDED_BY(cs_cleanup) {0};
// Main thread has indicated we should perform cleanup up to this height
std::atomic<int> to_cleanup {0};
CEvoDB& m_evoDb;
CConnman& connman;
std::unordered_map<uint256, CDeterministicMNList, StaticSaltedHasher> mnListsCache GUARDED_BY(cs);
std::unordered_map<uint256, CDeterministicMNListDiff, StaticSaltedHasher> mnListDiffsCache GUARDED_BY(cs);
const CBlockIndex* tipIndex GUARDED_BY(cs) {nullptr};
public:
explicit CDeterministicMNManager(CEvoDB& evoDb, CConnman& _connman) :
m_evoDb(evoDb), connman(_connman) {}
~CDeterministicMNManager() = default;
bool ProcessBlock(const CBlock& block, const CBlockIndex* pindex, BlockValidationState& state,
const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs);
bool UndoBlock(const CBlock& block, const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
void UpdatedBlockTip(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs);
// the returned list will not contain the correct block hash (we can't know it yet as the coinbase TX is not updated yet)
bool BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, BlockValidationState& state, const CCoinsViewCache& view,
CDeterministicMNList& mnListRet, bool debugLogs) EXCLUSIVE_LOCKS_REQUIRED(cs);
static void HandleQuorumCommitment(const llmq::CFinalCommitment& qc, const CBlockIndex* pQuorumBaseBlockIndex, CDeterministicMNList& mnList, bool debugLogs);
static void DecreasePoSePenalties(CDeterministicMNList& mnList);
CDeterministicMNList GetListForBlock(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs) {
LOCK(cs);
return GetListForBlockInternal(pindex);
};
CDeterministicMNList GetListAtChainTip() LOCKS_EXCLUDED(cs);
// Test if given TX is a ProRegTx which also contains the collateral at index n
static bool IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n);
bool IsDIP3Enforced(int nHeight = -1) LOCKS_EXCLUDED(cs);
bool MigrateDBIfNeeded();
bool MigrateDBIfNeeded2();
void DoMaintenance() LOCKS_EXCLUDED(cs);
private:
void CleanupCache(int nHeight) EXCLUSIVE_LOCKS_REQUIRED(cs);
CDeterministicMNList GetListForBlockInternal(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs);
};
bool CheckProRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs);
bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs);
bool CheckProUpRegTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, const CCoinsViewCache& view, bool check_sigs);
bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state, bool check_sigs);
extern std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
#endif // BITCOIN_EVO_DETERMINISTICMNS_H