Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

deterministicmns.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2019 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 #include <evo/deterministicmns.h>
6 #include <evo/specialtx.h>
7 
8 #include <base58.h>
9 #include <chainparams.h>
10 #include <core_io.h>
11 #include <script/standard.h>
12 #include <ui_interface.h>
13 #include <validation.h>
14 #include <validationinterface.h>
15 
17 #include <llmq/quorums_utils.h>
18 
19 #include <univalue.h>
20 
21 static const std::string DB_LIST_SNAPSHOT = "dmn_S";
22 static const std::string DB_LIST_DIFF = "dmn_D";
23 
24 std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
25 
27 {
28  CTxDestination dest;
29  std::string payoutAddress = "unknown";
30  std::string operatorPayoutAddress = "none";
31  if (ExtractDestination(scriptPayout, dest)) {
32  payoutAddress = EncodeDestination(dest);
33  }
35  operatorPayoutAddress = EncodeDestination(dest);
36  }
37 
38  return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, "
39  "ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)",
41  EncodeDestination(keyIDOwner), pubKeyOperator.Get().ToString(), EncodeDestination(keyIDVoting), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress);
42 }
43 
45 {
46  obj.clear();
47  obj.setObject();
48  obj.push_back(Pair("service", addr.ToStringIPPort(false)));
49  obj.push_back(Pair("registeredHeight", nRegisteredHeight));
50  obj.push_back(Pair("lastPaidHeight", nLastPaidHeight));
51  obj.push_back(Pair("PoSePenalty", nPoSePenalty));
52  obj.push_back(Pair("PoSeRevivedHeight", nPoSeRevivedHeight));
53  obj.push_back(Pair("PoSeBanHeight", nPoSeBanHeight));
54  obj.push_back(Pair("revocationReason", nRevocationReason));
55  obj.push_back(Pair("ownerAddress", EncodeDestination(keyIDOwner)));
56  obj.push_back(Pair("votingAddress", EncodeDestination(keyIDVoting)));
57 
58  CTxDestination dest;
59  if (ExtractDestination(scriptPayout, dest)) {
60  obj.push_back(Pair("payoutAddress", EncodeDestination(dest)));
61  }
62  obj.push_back(Pair("pubKeyOperator", pubKeyOperator.Get().ToString()));
64  obj.push_back(Pair("operatorPayoutAddress", EncodeDestination(dest)));
65  }
66 }
67 
69 {
70  // can't get it if it wasn't set yet
71  assert(internalId != std::numeric_limits<uint64_t>::max());
72  return internalId;
73 }
74 
75 std::string CDeterministicMN::ToString() const
76 {
77  return strprintf("CDeterministicMN(proTxHash=%s, collateralOutpoint=%s, nOperatorReward=%f, state=%s", proTxHash.ToString(), collateralOutpoint.ToStringShort(), (double)nOperatorReward / 100, pdmnState->ToString());
78 }
79 
81 {
82  obj.clear();
83  obj.setObject();
84 
85  UniValue stateObj;
86  pdmnState->ToJson(stateObj);
87 
88  obj.push_back(Pair("proTxHash", proTxHash.ToString()));
89  obj.push_back(Pair("collateralHash", collateralOutpoint.hash.ToString()));
90  obj.push_back(Pair("collateralIndex", (int)collateralOutpoint.n));
91 
92  Coin coin;
93  if (GetUTXOCoin(collateralOutpoint, coin)) {
94  CTxDestination dest;
95  if (ExtractDestination(coin.out.scriptPubKey, dest)) {
96  obj.push_back(Pair("collateralAddress", EncodeDestination(dest)));
97  }
98  }
99 
100  obj.push_back(Pair("operatorReward", (double)nOperatorReward / 100));
101  obj.push_back(Pair("state", stateObj));
102 }
103 
104 bool CDeterministicMNList::IsMNValid(const uint256& proTxHash) const
105 {
106  auto p = mnMap.find(proTxHash);
107  if (p == nullptr) {
108  return false;
109  }
110  return IsMNValid(*p);
111 }
112 
113 bool CDeterministicMNList::IsMNPoSeBanned(const uint256& proTxHash) const
114 {
115  auto p = mnMap.find(proTxHash);
116  if (p == nullptr) {
117  return false;
118  }
119  return IsMNPoSeBanned(*p);
120 }
121 
123 {
124  return !IsMNPoSeBanned(dmn);
125 }
126 
128 {
129  assert(dmn);
130  const CDeterministicMNState& state = *dmn->pdmnState;
131  return state.nPoSeBanHeight != -1;
132 }
133 
135 {
136  auto p = mnMap.find(proTxHash);
137  if (p == nullptr) {
138  return nullptr;
139  }
140  return *p;
141 }
142 
144 {
145  auto dmn = GetMN(proTxHash);
146  if (dmn && !IsMNValid(dmn)) {
147  return nullptr;
148  }
149  return dmn;
150 }
151 
153 {
154  for (const auto& p : mnMap) {
155  if (p.second->pdmnState->pubKeyOperator.Get() == pubKey) {
156  return p.second;
157  }
158  }
159  return nullptr;
160 }
161 
163 {
164  return GetUniquePropertyMN(collateralOutpoint);
165 }
166 
168 {
169  auto dmn = GetMNByCollateral(collateralOutpoint);
170  if (dmn && !IsMNValid(dmn)) {
171  return nullptr;
172  }
173  return dmn;
174 }
175 
177 {
178  return GetUniquePropertyMN(service);
179 }
180 
182 {
183  auto proTxHash = mnInternalIdMap.find(internalId);
184  if (!proTxHash) {
185  return nullptr;
186  }
187  return GetMN(*proTxHash);
188 }
189 
191 {
192  int height = dmn.pdmnState->nLastPaidHeight;
193  if (dmn.pdmnState->nPoSeRevivedHeight != -1 && dmn.pdmnState->nPoSeRevivedHeight > height) {
194  height = dmn.pdmnState->nPoSeRevivedHeight;
195  } else if (height == 0) {
196  height = dmn.pdmnState->nRegisteredHeight;
197  }
198  return height;
199 }
200 
201 static bool CompareByLastPaid(const CDeterministicMN& _a, const CDeterministicMN& _b)
202 {
203  int ah = CompareByLastPaid_GetHeight(_a);
204  int bh = CompareByLastPaid_GetHeight(_b);
205  if (ah == bh) {
206  return _a.proTxHash < _b.proTxHash;
207  } else {
208  return ah < bh;
209  }
210 }
212 {
213  return CompareByLastPaid(*_a, *_b);
214 }
215 
217 {
218  if (mnMap.size() == 0) {
219  return nullptr;
220  }
221 
223  ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
224  if (!best || CompareByLastPaid(dmn, best)) {
225  best = dmn;
226  }
227  });
228 
229  return best;
230 }
231 
232 std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(int nCount) const
233 {
234  if (nCount > GetValidMNsCount()) {
235  nCount = GetValidMNsCount();
236  }
237 
238  std::vector<CDeterministicMNCPtr> result;
239  result.reserve(nCount);
240 
241  ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
242  result.emplace_back(dmn);
243  });
244  std::sort(result.begin(), result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) {
245  return CompareByLastPaid(a, b);
246  });
247 
248  result.resize(nCount);
249 
250  return result;
251 }
252 
253 std::vector<CDeterministicMNCPtr> CDeterministicMNList::CalculateQuorum(size_t maxSize, const uint256& modifier) const
254 {
255  auto scores = CalculateScores(modifier);
256 
257  // sort is descending order
258  std::sort(scores.rbegin(), scores.rend(), [](const std::pair<arith_uint256, CDeterministicMNCPtr>& a, std::pair<arith_uint256, CDeterministicMNCPtr>& b) {
259  if (a.first == b.first) {
260  // this should actually never happen, but we should stay compatible with how the non deterministic MNs did the sorting
261  return a.second->collateralOutpoint < b.second->collateralOutpoint;
262  }
263  return a.first < b.first;
264  });
265 
266  // take top maxSize entries and return it
267  std::vector<CDeterministicMNCPtr> result;
268  result.resize(std::min(maxSize, scores.size()));
269  for (size_t i = 0; i < result.size(); i++) {
270  result[i] = std::move(scores[i].second);
271  }
272  return result;
273 }
274 
275 std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> CDeterministicMNList::CalculateScores(const uint256& modifier) const
276 {
277  std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> scores;
278  scores.reserve(GetAllMNsCount());
279  ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
280  if (dmn->pdmnState->confirmedHash.IsNull()) {
281  // we only take confirmed MNs into account to avoid hash grinding on the ProRegTxHash to sneak MNs into a
282  // future quorums
283  return;
284  }
285  // calculate sha256(sha256(proTxHash, confirmedHash), modifier) per MN
286  // Please note that this is not a double-sha256 but a single-sha256
287  // The first part is already precalculated (confirmedHashWithProRegTxHash)
288  // TODO When https://github.com/bitcoin/bitcoin/pull/13191 gets backported, implement something that is similar but for single-sha256
289  uint256 h;
290  CSHA256 sha256;
291  sha256.Write(dmn->pdmnState->confirmedHashWithProRegTxHash.begin(), dmn->pdmnState->confirmedHashWithProRegTxHash.size());
292  sha256.Write(modifier.begin(), modifier.size());
293  sha256.Finalize(h.begin());
294 
295  scores.emplace_back(UintToArith256(h), dmn);
296  });
297 
298  return scores;
299 }
300 
302 {
303  // Maximum PoSe penalty is dynamic and equals the number of registered MNs
304  // It's however at least 100.
305  // This means that the max penalty is usually equal to a full payment cycle
306  return std::max(100, (int)GetAllMNsCount());
307 }
308 
309 int CDeterministicMNList::CalcPenalty(int percent) const
310 {
311  assert(percent > 0);
312  return (CalcMaxPoSePenalty() * percent) / 100;
313 }
314 
315 void CDeterministicMNList::PoSePunish(const uint256& proTxHash, int penalty, bool debugLogs)
316 {
317  assert(penalty > 0);
318 
319  auto dmn = GetMN(proTxHash);
320  if (!dmn) {
321  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
322  }
323 
324  int maxPenalty = CalcMaxPoSePenalty();
325 
326  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
327  newState->nPoSePenalty += penalty;
328  newState->nPoSePenalty = std::min(maxPenalty, newState->nPoSePenalty);
329 
330  if (debugLogs) {
331  LogPrintf("CDeterministicMNList::%s -- punished MN %s, penalty %d->%d (max=%d)\n",
332  __func__, proTxHash.ToString(), dmn->pdmnState->nPoSePenalty, newState->nPoSePenalty, maxPenalty);
333  }
334 
335  if (newState->nPoSePenalty >= maxPenalty && newState->nPoSeBanHeight == -1) {
336  newState->nPoSeBanHeight = nHeight;
337  if (debugLogs) {
338  LogPrintf("CDeterministicMNList::%s -- banned MN %s at height %d\n",
339  __func__, proTxHash.ToString(), nHeight);
340  }
341  }
342  UpdateMN(proTxHash, newState);
343 }
344 
346 {
347  auto dmn = GetMN(proTxHash);
348  if (!dmn) {
349  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
350  }
351  assert(dmn->pdmnState->nPoSePenalty > 0 && dmn->pdmnState->nPoSeBanHeight == -1);
352 
353  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
354  newState->nPoSePenalty--;
355  UpdateMN(proTxHash, newState);
356 }
357 
359 {
360  CDeterministicMNListDiff diffRet;
361 
362  to.ForEachMN(false, [&](const CDeterministicMNCPtr& toPtr) {
363  auto fromPtr = GetMN(toPtr->proTxHash);
364  if (fromPtr == nullptr) {
365  diffRet.addedMNs.emplace_back(toPtr);
366  } else if (fromPtr != toPtr || fromPtr->pdmnState != toPtr->pdmnState) {
367  CDeterministicMNStateDiff stateDiff(*fromPtr->pdmnState, *toPtr->pdmnState);
368  if (stateDiff.fields) {
369  diffRet.updatedMNs.emplace(toPtr->GetInternalId(), std::move(stateDiff));
370  }
371  }
372  });
373  ForEachMN(false, [&](const CDeterministicMNCPtr& fromPtr) {
374  auto toPtr = to.GetMN(fromPtr->proTxHash);
375  if (toPtr == nullptr) {
376  diffRet.removedMns.emplace(fromPtr->GetInternalId());
377  }
378  });
379 
380  // added MNs need to be sorted by internalId so that these are added in correct order when the diff is applied later
381  // otherwise internalIds will not match with the original list
382  std::sort(diffRet.addedMNs.begin(), diffRet.addedMNs.end(), [](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) {
383  return a->GetInternalId() < b->GetInternalId();
384  });
385 
386  return diffRet;
387 }
388 
390 {
391  CSimplifiedMNListDiff diffRet;
392  diffRet.baseBlockHash = blockHash;
393  diffRet.blockHash = to.blockHash;
394 
395  to.ForEachMN(false, [&](const CDeterministicMNCPtr& toPtr) {
396  auto fromPtr = GetMN(toPtr->proTxHash);
397  if (fromPtr == nullptr) {
398  diffRet.mnList.emplace_back(*toPtr);
399  } else {
400  CSimplifiedMNListEntry sme1(*toPtr);
401  CSimplifiedMNListEntry sme2(*fromPtr);
402  if (sme1 != sme2) {
403  diffRet.mnList.emplace_back(*toPtr);
404  }
405  }
406  });
407  ForEachMN(false, [&](const CDeterministicMNCPtr& fromPtr) {
408  auto toPtr = to.GetMN(fromPtr->proTxHash);
409  if (toPtr == nullptr) {
410  diffRet.deletedMNs.emplace_back(fromPtr->proTxHash);
411  }
412  });
413 
414  return diffRet;
415 }
416 
418 {
419  CDeterministicMNList result = *this;
420  result.blockHash = pindex->GetBlockHash();
421  result.nHeight = pindex->nHeight;
422 
423  for (const auto& id : diff.removedMns) {
424  auto dmn = result.GetMNByInternalId(id);
425  if (!dmn) {
426  throw(std::runtime_error(strprintf("%s: can't find a removed masternode, id=%d", __func__, id)));
427  }
428  result.RemoveMN(dmn->proTxHash);
429  }
430  for (const auto& dmn : diff.addedMNs) {
431  result.AddMN(dmn);
432  }
433  for (const auto& p : diff.updatedMNs) {
434  auto dmn = result.GetMNByInternalId(p.first);
435  result.UpdateMN(dmn, p.second);
436  }
437 
438  return result;
439 }
440 
441 void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount)
442 {
443  assert(dmn != nullptr);
444 
445  if (mnMap.find(dmn->proTxHash)) {
446  throw(std::runtime_error(strprintf("%s: can't add a duplicate masternode with the same proTxHash=%s", __func__, dmn->proTxHash.ToString())));
447  }
448  if (mnInternalIdMap.find(dmn->GetInternalId())) {
449  throw(std::runtime_error(strprintf("%s: can't add a duplicate masternode with the same internalId=%d", __func__, dmn->GetInternalId())));
450  }
451  if (HasUniqueProperty(dmn->pdmnState->addr)) {
452  throw(std::runtime_error(strprintf("%s: can't add a masternode with a duplicate address %s", __func__, dmn->pdmnState->addr.ToStringIPPort(false))));
453  }
454  if (HasUniqueProperty(dmn->pdmnState->keyIDOwner) || HasUniqueProperty(dmn->pdmnState->pubKeyOperator)) {
455  throw(std::runtime_error(strprintf("%s: can't add a masternode with a duplicate key (%s or %s)", __func__, EncodeDestination(dmn->pdmnState->keyIDOwner), dmn->pdmnState->pubKeyOperator.Get().ToString())));
456  }
457 
458  mnMap = mnMap.set(dmn->proTxHash, dmn);
459  mnInternalIdMap = mnInternalIdMap.set(dmn->GetInternalId(), dmn->proTxHash);
460  AddUniqueProperty(dmn, dmn->collateralOutpoint);
461  if (dmn->pdmnState->addr != CService()) {
462  AddUniqueProperty(dmn, dmn->pdmnState->addr);
463  }
464  AddUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
465  if (dmn->pdmnState->pubKeyOperator.Get().IsValid()) {
466  AddUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
467  }
468  if (fBumpTotalCount) {
469  // nTotalRegisteredCount acts more like a checkpoint, not as a limit,
470  nTotalRegisteredCount = std::max(dmn->GetInternalId() + 1, (uint64_t)nTotalRegisteredCount);
471  }
472 }
473 
475 {
476  assert(oldDmn != nullptr);
477 
478  if (HasUniqueProperty(oldDmn->pdmnState->addr) && GetUniquePropertyMN(oldDmn->pdmnState->addr)->proTxHash != oldDmn->proTxHash) {
479  throw(std::runtime_error(strprintf("%s: can't update a masternode with a duplicate address %s", __func__, oldDmn->pdmnState->addr.ToStringIPPort(false))));
480  }
481 
482  auto dmn = std::make_shared<CDeterministicMN>(*oldDmn);
483  auto oldState = dmn->pdmnState;
484  dmn->pdmnState = pdmnState;
485  mnMap = mnMap.set(oldDmn->proTxHash, dmn);
486 
487  UpdateUniqueProperty(dmn, oldState->addr, pdmnState->addr);
488  UpdateUniqueProperty(dmn, oldState->keyIDOwner, pdmnState->keyIDOwner);
489  UpdateUniqueProperty(dmn, oldState->pubKeyOperator, pdmnState->pubKeyOperator);
490 }
491 
492 void CDeterministicMNList::UpdateMN(const uint256& proTxHash, const CDeterministicMNStateCPtr& pdmnState)
493 {
494  auto oldDmn = mnMap.find(proTxHash);
495  if (!oldDmn) {
496  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
497  }
498  UpdateMN(*oldDmn, pdmnState);
499 }
500 
502 {
503  assert(oldDmn != nullptr);
504  auto oldState = oldDmn->pdmnState;
505  auto newState = std::make_shared<CDeterministicMNState>(*oldState);
506  stateDiff.ApplyToState(*newState);
507  UpdateMN(oldDmn, newState);
508 }
509 
511 {
512  auto dmn = GetMN(proTxHash);
513  if (!dmn) {
514  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
515  }
516  DeleteUniqueProperty(dmn, dmn->collateralOutpoint);
517  if (dmn->pdmnState->addr != CService()) {
518  DeleteUniqueProperty(dmn, dmn->pdmnState->addr);
519  }
520  DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
521  if (dmn->pdmnState->pubKeyOperator.Get().IsValid()) {
522  DeleteUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
523  }
524  mnMap = mnMap.erase(proTxHash);
525  mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
526 }
527 
529  evoDb(_evoDb)
530 {
531 }
532 
533 bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& _state, bool fJustCheck)
534 {
536 
537  const auto& consensusParams = Params().GetConsensus();
538  bool fDIP0003Active = pindex->nHeight >= consensusParams.DIP0003Height;
539  if (!fDIP0003Active) {
540  return true;
541  }
542 
543  CDeterministicMNList oldList, newList;
545 
546  int nHeight = pindex->nHeight;
547 
548  try {
549  LOCK(cs);
550 
551  if (!BuildNewListFromBlock(block, pindex->pprev, _state, newList, true)) {
552  // pass the state returned by the function above
553  return false;
554  }
555 
556  if (fJustCheck) {
557  return true;
558  }
559 
560  if (newList.GetHeight() == -1) {
561  newList.SetHeight(nHeight);
562  }
563 
564  newList.SetBlockHash(block.GetHash());
565 
566  oldList = GetListForBlock(pindex->pprev);
567  diff = oldList.BuildDiff(newList);
568 
569  evoDb.Write(std::make_pair(DB_LIST_DIFF, newList.GetBlockHash()), diff);
570  if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0 || oldList.GetHeight() == -1) {
571  evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, newList.GetBlockHash()), newList);
572  mnListsCache.emplace(newList.GetBlockHash(), newList);
573  LogPrintf("CDeterministicMNManager::%s -- Wrote snapshot. nHeight=%d, mapCurMNs.allMNsCount=%d\n",
574  __func__, nHeight, newList.GetAllMNsCount());
575  }
576 
577  diff.nHeight = pindex->nHeight;
578  mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
579  } catch (const std::exception& e) {
580  LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
581  return _state.DoS(100, false, REJECT_INVALID, "failed-dmn-block");
582  }
583 
584  // Don't hold cs while calling signals
585  if (diff.HasChanges()) {
586  GetMainSignals().NotifyMasternodeListChanged(false, oldList, diff);
588  }
589 
590  if (nHeight == consensusParams.DIP0003EnforcementHeight) {
591  if (!consensusParams.DIP0003EnforcementHash.IsNull() && consensusParams.DIP0003EnforcementHash != pindex->GetBlockHash()) {
592  LogPrintf("CDeterministicMNManager::%s -- DIP3 enforcement block has wrong hash: hash=%s, expected=%s, nHeight=%d\n", __func__,
593  pindex->GetBlockHash().ToString(), consensusParams.DIP0003EnforcementHash.ToString(), nHeight);
594  return _state.DoS(100, false, REJECT_INVALID, "bad-dip3-enf-block");
595  }
596  LogPrintf("CDeterministicMNManager::%s -- DIP3 is enforced now. nHeight=%d\n", __func__, nHeight);
597  }
598 
599  LOCK(cs);
600  CleanupCache(nHeight);
601 
602  return true;
603 }
604 
605 bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex* pindex)
606 {
607  int nHeight = pindex->nHeight;
608  uint256 blockHash = block.GetHash();
609 
610  CDeterministicMNList curList;
611  CDeterministicMNList prevList;
613  {
614  LOCK(cs);
615  evoDb.Read(std::make_pair(DB_LIST_DIFF, blockHash), diff);
616 
617  if (diff.HasChanges()) {
618  // need to call this before erasing
619  curList = GetListForBlock(pindex);
620  prevList = GetListForBlock(pindex->pprev);
621  }
622 
623  mnListsCache.erase(blockHash);
624  mnListDiffsCache.erase(blockHash);
625  }
626 
627  if (diff.HasChanges()) {
628  auto inversedDiff = curList.BuildDiff(prevList);
629  GetMainSignals().NotifyMasternodeListChanged(true, curList, inversedDiff);
631  }
632 
633  const auto& consensusParams = Params().GetConsensus();
634  if (nHeight == consensusParams.DIP0003EnforcementHeight) {
635  LogPrintf("CDeterministicMNManager::%s -- DIP3 is not enforced anymore. nHeight=%d\n", __func__, nHeight);
636  }
637 
638  return true;
639 }
640 
642 {
643  LOCK(cs);
644 
645  tipIndex = pindex;
646 }
647 
648 bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& _state, CDeterministicMNList& mnListRet, bool debugLogs)
649 {
651 
652  int nHeight = pindexPrev->nHeight + 1;
653 
654  CDeterministicMNList oldList = GetListForBlock(pindexPrev);
655  CDeterministicMNList newList = oldList;
656  newList.SetBlockHash(uint256()); // we can't know the final block hash, so better not return a (invalid) block hash
657  newList.SetHeight(nHeight);
658 
659  auto payee = oldList.GetMNPayee();
660 
661  // we iterate the oldList here and update the newList
662  // this is only valid as long these have not diverged at this point, which is the case as long as we don't add
663  // code above this loop that modifies newList
664  oldList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
665  if (!dmn->pdmnState->confirmedHash.IsNull()) {
666  // already confirmed
667  return;
668  }
669  // this works on the previous block, so confirmation will happen one block after nMasternodeMinimumConfirmations
670  // has been reached, but the block hash will then point to the block at nMasternodeMinimumConfirmations
671  int nConfirmations = pindexPrev->nHeight - dmn->pdmnState->nRegisteredHeight;
672  if (nConfirmations >= Params().GetConsensus().nMasternodeMinimumConfirmations) {
673  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
674  newState->UpdateConfirmedHash(dmn->proTxHash, pindexPrev->GetBlockHash());
675  newList.UpdateMN(dmn->proTxHash, newState);
676  }
677  });
678 
679  DecreasePoSePenalties(newList);
680 
681  // we skip the coinbase
682  for (int i = 1; i < (int)block.vtx.size(); i++) {
683  const CTransaction& tx = *block.vtx[i];
684 
685  if (tx.nVersion != 3) {
686  // only interested in special TXs
687  continue;
688  }
689 
691  CProRegTx proTx;
692  if (!GetTxPayload(tx, proTx)) {
693  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
694  }
695 
696  auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount());
697  dmn->proTxHash = tx.GetHash();
698 
699  // collateralOutpoint is either pointing to an external collateral or to the ProRegTx itself
700  if (proTx.collateralOutpoint.hash.IsNull()) {
701  dmn->collateralOutpoint = COutPoint(tx.GetHash(), proTx.collateralOutpoint.n);
702  } else {
703  dmn->collateralOutpoint = proTx.collateralOutpoint;
704  }
705 
706  Coin coin;
707  if (!proTx.collateralOutpoint.hash.IsNull() && (!GetUTXOCoin(dmn->collateralOutpoint, coin) || coin.out.nValue != 1000 * COIN)) {
708  // should actually never get to this point as CheckProRegTx should have handled this case.
709  // We do this additional check nevertheless to be 100% sure
710  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-collateral");
711  }
712 
713  auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);
714  if (replacedDmn != nullptr) {
715  // This might only happen with a ProRegTx that refers an external collateral
716  // In that case the new ProRegTx will replace the old one. This means the old one is removed
717  // and the new one is added like a completely fresh one, which is also at the bottom of the payment list
718  newList.RemoveMN(replacedDmn->proTxHash);
719  if (debugLogs) {
720  LogPrintf("CDeterministicMNManager::%s -- MN %s removed from list because collateral was used for a new ProRegTx. collateralOutpoint=%s, nHeight=%d, mapCurMNs.allMNsCount=%d\n",
721  __func__, replacedDmn->proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort(), nHeight, newList.GetAllMNsCount());
722  }
723  }
724 
725  if (newList.HasUniqueProperty(proTx.addr)) {
726  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
727  }
728  if (newList.HasUniqueProperty(proTx.keyIDOwner) || newList.HasUniqueProperty(proTx.pubKeyOperator)) {
729  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-key");
730  }
731 
732  dmn->nOperatorReward = proTx.nOperatorReward;
733 
734  auto dmnState = std::make_shared<CDeterministicMNState>(proTx);
735  dmnState->nRegisteredHeight = nHeight;
736  if (proTx.addr == CService()) {
737  // start in banned pdmnState as we need to wait for a ProUpServTx
738  dmnState->nPoSeBanHeight = nHeight;
739  }
740  dmn->pdmnState = dmnState;
741 
742  newList.AddMN(dmn);
743 
744  if (debugLogs) {
745  LogPrintf("CDeterministicMNManager::%s -- MN %s added at height %d: %s\n",
746  __func__, tx.GetHash().ToString(), nHeight, proTx.ToString());
747  }
748  } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_SERVICE) {
749  CProUpServTx proTx;
750  if (!GetTxPayload(tx, proTx)) {
751  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
752  }
753 
754  if (newList.HasUniqueProperty(proTx.addr) && newList.GetUniquePropertyMN(proTx.addr)->proTxHash != proTx.proTxHash) {
755  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
756  }
757 
758  CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
759  if (!dmn) {
760  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
761  }
762  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
763  newState->addr = proTx.addr;
764  newState->scriptOperatorPayout = proTx.scriptOperatorPayout;
765 
766  if (newState->nPoSeBanHeight != -1) {
767  // only revive when all keys are set
768  if (newState->pubKeyOperator.Get().IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
769  newState->nPoSePenalty = 0;
770  newState->nPoSeBanHeight = -1;
771  newState->nPoSeRevivedHeight = nHeight;
772 
773  if (debugLogs) {
774  LogPrintf("CDeterministicMNManager::%s -- MN %s revived at height %d\n",
775  __func__, proTx.proTxHash.ToString(), nHeight);
776  }
777  }
778  }
779 
780  newList.UpdateMN(proTx.proTxHash, newState);
781  if (debugLogs) {
782  LogPrintf("CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
783  __func__, proTx.proTxHash.ToString(), nHeight, proTx.ToString());
784  }
785  } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REGISTRAR) {
786  CProUpRegTx proTx;
787  if (!GetTxPayload(tx, proTx)) {
788  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
789  }
790 
791  CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
792  if (!dmn) {
793  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
794  }
795  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
796  if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) {
797  // reset all operator related fields and put MN into PoSe-banned state in case the operator key changes
798  newState->ResetOperatorFields();
799  newState->BanIfNotBanned(nHeight);
800  }
801  newState->pubKeyOperator.Set(proTx.pubKeyOperator);
802  newState->keyIDVoting = proTx.keyIDVoting;
803  newState->scriptPayout = proTx.scriptPayout;
804 
805  newList.UpdateMN(proTx.proTxHash, newState);
806 
807  if (debugLogs) {
808  LogPrintf("CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
809  __func__, proTx.proTxHash.ToString(), nHeight, proTx.ToString());
810  }
811  } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) {
812  CProUpRevTx proTx;
813  if (!GetTxPayload(tx, proTx)) {
814  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
815  }
816 
817  CDeterministicMNCPtr dmn = newList.GetMN(proTx.proTxHash);
818  if (!dmn) {
819  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
820  }
821  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
822  newState->ResetOperatorFields();
823  newState->BanIfNotBanned(nHeight);
824  newState->nRevocationReason = proTx.nReason;
825 
826  newList.UpdateMN(proTx.proTxHash, newState);
827 
828  if (debugLogs) {
829  LogPrintf("CDeterministicMNManager::%s -- MN %s revoked operator key at height %d: %s\n",
830  __func__, proTx.proTxHash.ToString(), nHeight, proTx.ToString());
831  }
832  } else if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) {
834  if (!GetTxPayload(tx, qc)) {
835  return _state.DoS(100, false, REJECT_INVALID, "bad-qc-payload");
836  }
837  if (!qc.commitment.IsNull()) {
838  const auto& params = Params().GetConsensus().llmqs.at(qc.commitment.llmqType);
839  int quorumHeight = qc.nHeight - (qc.nHeight % params.dkgInterval);
840  auto quorumIndex = pindexPrev->GetAncestor(quorumHeight);
841  if (!quorumIndex || quorumIndex->GetBlockHash() != qc.commitment.quorumHash) {
842  // we should actually never get into this case as validation should have catched it...but lets be sure
843  return _state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash");
844  }
845 
846  HandleQuorumCommitment(qc.commitment, quorumIndex, newList, debugLogs);
847  }
848  }
849  }
850 
851  // we skip the coinbase
852  for (int i = 1; i < (int)block.vtx.size(); i++) {
853  const CTransaction& tx = *block.vtx[i];
854 
855  // check if any existing MN collateral is spent by this transaction
856  for (const auto& in : tx.vin) {
857  auto dmn = newList.GetMNByCollateral(in.prevout);
858  if (dmn && dmn->collateralOutpoint == in.prevout) {
859  newList.RemoveMN(dmn->proTxHash);
860 
861  if (debugLogs) {
862  LogPrintf("CDeterministicMNManager::%s -- MN %s removed from list because collateral was spent. collateralOutpoint=%s, nHeight=%d, mapCurMNs.allMNsCount=%d\n",
863  __func__, dmn->proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort(), nHeight, newList.GetAllMNsCount());
864  }
865  }
866  }
867  }
868 
869  // The payee for the current block was determined by the previous block's list but it might have disappeared in the
870  // current block. We still pay that MN one last time however.
871  if (payee && newList.HasMN(payee->proTxHash)) {
872  auto newState = std::make_shared<CDeterministicMNState>(*newList.GetMN(payee->proTxHash)->pdmnState);
873  newState->nLastPaidHeight = nHeight;
874  newList.UpdateMN(payee->proTxHash, newState);
875  }
876 
877  mnListRet = std::move(newList);
878 
879  return true;
880 }
881 
883 {
884  // The commitment has already been validated at this point so it's safe to use members of it
885 
886  auto members = llmq::CLLMQUtils::GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, pindexQuorum);
887 
888  for (size_t i = 0; i < members.size(); i++) {
889  if (!mnList.HasMN(members[i]->proTxHash)) {
890  continue;
891  }
892  if (!qc.validMembers[i]) {
893  // punish MN for failed DKG participation
894  // The idea is to immediately ban a MN when it fails 2 DKG sessions with only a few blocks in-between
895  // If there were enough blocks between failures, the MN has a chance to recover as he reduces his penalty by 1 for every block
896  // If it however fails 3 times in the timespan of a single payment cycle, it should definitely get banned
897  mnList.PoSePunish(members[i]->proTxHash, mnList.CalcPenalty(66), debugLogs);
898  }
899  }
900 }
901 
903 {
904  std::vector<uint256> toDecrease;
905  toDecrease.reserve(mnList.GetValidMNsCount() / 10);
906  // only iterate and decrease for valid ones (not PoSe banned yet)
907  // if a MN ever reaches the maximum, it stays in PoSe banned state until revived
908  mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
909  if (dmn->pdmnState->nPoSePenalty > 0 && dmn->pdmnState->nPoSeBanHeight == -1) {
910  toDecrease.emplace_back(dmn->proTxHash);
911  }
912  });
913 
914  for (const auto& proTxHash : toDecrease) {
915  mnList.PoSeDecrease(proTxHash);
916  }
917 }
918 
920 {
921  LOCK(cs);
922 
923  CDeterministicMNList snapshot;
924  std::list<const CBlockIndex*> listDiffIndexes;
925 
926  while (true) {
927  // try using cache before reading from disk
928  auto itLists = mnListsCache.find(pindex->GetBlockHash());
929  if (itLists != mnListsCache.end()) {
930  snapshot = itLists->second;
931  break;
932  }
933 
934  if (evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), snapshot)) {
935  mnListsCache.emplace(pindex->GetBlockHash(), snapshot);
936  break;
937  }
938 
939  // no snapshot found yet, check diffs
940  auto itDiffs = mnListDiffsCache.find(pindex->GetBlockHash());
941  if (itDiffs != mnListDiffsCache.end()) {
942  listDiffIndexes.emplace_front(pindex);
943  pindex = pindex->pprev;
944  continue;
945  }
946 
948  if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), diff)) {
949  // no snapshot and no diff on disk means that it's the initial snapshot
950  snapshot = CDeterministicMNList(pindex->GetBlockHash(), -1, 0);
951  mnListsCache.emplace(pindex->GetBlockHash(), snapshot);
952  break;
953  }
954 
955  diff.nHeight = pindex->nHeight;
956  mnListDiffsCache.emplace(pindex->GetBlockHash(), std::move(diff));
957  listDiffIndexes.emplace_front(pindex);
958  pindex = pindex->pprev;
959  }
960 
961  for (const auto& diffIndex : listDiffIndexes) {
962  const auto& diff = mnListDiffsCache.at(diffIndex->GetBlockHash());
963  if (diff.HasChanges()) {
964  snapshot = snapshot.ApplyDiff(diffIndex, diff);
965  } else {
966  snapshot.SetBlockHash(diffIndex->GetBlockHash());
967  snapshot.SetHeight(diffIndex->nHeight);
968  }
969  }
970 
971  if (tipIndex) {
972  // always keep a snapshot for the tip
973  if (snapshot.GetBlockHash() == tipIndex->GetBlockHash()) {
974  mnListsCache.emplace(snapshot.GetBlockHash(), snapshot);
975  } else {
976  // keep snapshots for yet alive quorums
977  for (auto& p_llmq : Params().GetConsensus().llmqs) {
978  if ((snapshot.GetHeight() % p_llmq.second.dkgInterval == 0) && (snapshot.GetHeight() + p_llmq.second.dkgInterval * (p_llmq.second.keepOldConnections + 1) >= tipIndex->nHeight)) {
979  mnListsCache.emplace(snapshot.GetBlockHash(), snapshot);
980  break;
981  }
982  }
983  }
984  }
985 
986  return snapshot;
987 }
988 
990 {
991  LOCK(cs);
992  if (!tipIndex) {
993  return {};
994  }
995  return GetListForBlock(tipIndex);
996 }
997 
999 {
1000  if (tx->nVersion != 3 || tx->nType != TRANSACTION_PROVIDER_REGISTER) {
1001  return false;
1002  }
1003  CProRegTx proTx;
1004  if (!GetTxPayload(*tx, proTx)) {
1005  return false;
1006  }
1007 
1008  if (!proTx.collateralOutpoint.hash.IsNull()) {
1009  return false;
1010  }
1011  if (proTx.collateralOutpoint.n >= tx->vout.size() || proTx.collateralOutpoint.n != n) {
1012  return false;
1013  }
1014  if (tx->vout[n].nValue != 1000 * COIN) {
1015  return false;
1016  }
1017  return true;
1018 }
1019 
1021 {
1022  LOCK(cs);
1023 
1024  if (nHeight == -1) {
1025  nHeight = tipIndex->nHeight;
1026  }
1027 
1028  return nHeight >= Params().GetConsensus().DIP0003EnforcementHeight;
1029 }
1030 
1032 {
1033  AssertLockHeld(cs);
1034 
1035  std::vector<uint256> toDeleteLists;
1036  std::vector<uint256> toDeleteDiffs;
1037  for (const auto& p : mnListsCache) {
1038  if (p.second.GetHeight() + LIST_DIFFS_CACHE_SIZE < nHeight) {
1039  toDeleteLists.emplace_back(p.first);
1040  continue;
1041  }
1042  bool fQuorumCache{false};
1043  for (auto& p_llmq : Params().GetConsensus().llmqs) {
1044  if ((p.second.GetHeight() % p_llmq.second.dkgInterval == 0) && (p.second.GetHeight() + p_llmq.second.dkgInterval * (p_llmq.second.keepOldConnections + 1) >= nHeight)) {
1045  fQuorumCache = true;
1046  break;
1047  }
1048  }
1049  if (fQuorumCache) {
1050  // at least one quorum could be using it, keep it
1051  continue;
1052  }
1053  // no alive quorums using it, see if it was a cache for the tip or for a now outdated quorum
1054  if (tipIndex && tipIndex->pprev && (p.first == tipIndex->pprev->GetBlockHash())) {
1055  toDeleteLists.emplace_back(p.first);
1056  } else {
1057  for (auto& p_llmq : Params().GetConsensus().llmqs) {
1058  if (p.second.GetHeight() % p_llmq.second.dkgInterval == 0) {
1059  toDeleteLists.emplace_back(p.first);
1060  break;
1061  }
1062  }
1063  }
1064  }
1065  for (const auto& h : toDeleteLists) {
1066  mnListsCache.erase(h);
1067  }
1068  for (const auto& p : mnListDiffsCache) {
1069  if (p.second.nHeight + LIST_DIFFS_CACHE_SIZE < nHeight) {
1070  toDeleteDiffs.emplace_back(p.first);
1071  }
1072  }
1073  for (const auto& h : toDeleteDiffs) {
1074  mnListDiffsCache.erase(h);
1075  }
1076 }
1077 
1078 void CDeterministicMNManager::UpgradeDiff(CDBBatch& batch, const CBlockIndex* pindexNext, const CDeterministicMNList& curMNList, CDeterministicMNList& newMNList)
1079 {
1080  CDataStream oldDiffData(SER_DISK, CLIENT_VERSION);
1081  if (!evoDb.GetRawDB().ReadDataStream(std::make_pair(DB_LIST_DIFF, pindexNext->GetBlockHash()), oldDiffData)) {
1082  LogPrintf("CDeterministicMNManager::%s -- no diff found for %s\n", __func__, pindexNext->GetBlockHash().ToString());
1083  newMNList = curMNList;
1084  newMNList.SetBlockHash(pindexNext->GetBlockHash());
1085  newMNList.SetHeight(pindexNext->nHeight);
1086  return;
1087  }
1088 
1090  oldDiffData >> oldDiff;
1091 
1092  CDeterministicMNListDiff newDiff;
1093  size_t addedCount = 0;
1094  for (auto& p : oldDiff.addedMNs) {
1095  auto dmn = std::make_shared<CDeterministicMN>(*p.second, curMNList.GetTotalRegisteredCount() + addedCount);
1096  newDiff.addedMNs.emplace_back(dmn);
1097  addedCount++;
1098  }
1099  for (auto& p : oldDiff.removedMns) {
1100  auto dmn = curMNList.GetMN(p);
1101  newDiff.removedMns.emplace(dmn->GetInternalId());
1102  }
1103 
1104  // applies added/removed MNs
1105  newMNList = curMNList.ApplyDiff(pindexNext, newDiff);
1106 
1107  // manually apply updated MNs and calc new state diffs
1108  for (auto& p : oldDiff.updatedMNs) {
1109  auto oldMN = newMNList.GetMN(p.first);
1110  if (!oldMN) {
1111  throw(std::runtime_error(strprintf("%s: Can't find an old masternode with proTxHash=%s", __func__, p.first.ToString())));
1112  }
1113  newMNList.UpdateMN(p.first, p.second);
1114  auto newMN = newMNList.GetMN(p.first);
1115  if (!newMN) {
1116  throw(std::runtime_error(strprintf("%s: Can't find a new masternode with proTxHash=%s", __func__, p.first.ToString())));
1117  }
1118 
1119  newDiff.updatedMNs.emplace(std::piecewise_construct,
1120  std::forward_as_tuple(oldMN->GetInternalId()),
1121  std::forward_as_tuple(*oldMN->pdmnState, *newMN->pdmnState));
1122  }
1123 
1124  batch.Write(std::make_pair(DB_LIST_DIFF, pindexNext->GetBlockHash()), newDiff);
1125 
1126  return;
1127 }
1128 
1129 // TODO this can be completely removed in a future version
1131 {
1132  LOCK(cs_main);
1133 
1134  if (chainActive.Tip() == nullptr) {
1135  return true;
1136  }
1137 
1139  return true;
1140  }
1141 
1142  // Removing the old EVODB_BEST_BLOCK value early results in older version to crash immediately, even if the upgrade
1143  // process is cancelled in-between. But if the new version sees that the old EVODB_BEST_BLOCK is already removed,
1144  // then we must assume that the upgrade process was already running before but was interrupted.
1145  if (chainActive.Height() > 1 && !evoDb.GetRawDB().Exists(std::string("b_b"))) {
1146  return false;
1147  }
1148  evoDb.GetRawDB().Erase(std::string("b_b"));
1149 
1151  // not reached DIP3 height yet, so no upgrade needed
1152  auto dbTx = evoDb.BeginTransaction();
1154  dbTx->Commit();
1155  return true;
1156  }
1157 
1158  LogPrintf("CDeterministicMNManager::%s -- upgrading DB to use compact diffs\n", __func__);
1159 
1160  CDBBatch batch(evoDb.GetRawDB());
1161 
1162  CDeterministicMNList curMNList;
1163  curMNList.SetHeight(Params().GetConsensus().DIP0003Height - 1);
1164  curMNList.SetBlockHash(chainActive[Params().GetConsensus().DIP0003Height - 1]->GetBlockHash());
1165 
1166  for (int nHeight = Params().GetConsensus().DIP0003Height; nHeight <= chainActive.Height(); nHeight++) {
1167  auto pindex = chainActive[nHeight];
1168 
1169  CDeterministicMNList newMNList;
1170  UpgradeDiff(batch, pindex, curMNList, newMNList);
1171 
1172  if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0) {
1173  batch.Write(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), newMNList);
1174  evoDb.GetRawDB().WriteBatch(batch);
1175  batch.Clear();
1176  }
1177 
1178  curMNList = newMNList;
1179  }
1180 
1181  evoDb.GetRawDB().WriteBatch(batch);
1182 
1183  LogPrintf("CDeterministicMNManager::%s -- done upgrading\n", __func__);
1184 
1185  // Writing EVODB_BEST_BLOCK (which is b_b2 now) marks the DB as upgraded
1186  auto dbTx = evoDb.BeginTransaction();
1188  dbTx->Commit();
1189 
1191 
1192  return true;
1193 }
bool Exists(const K &key) const
Definition: dbwrapper.h:306
int CalcMaxPoSePenalty() const
Calculates the maximum penalty which is allowed at the height of this MN list.
bool GetTxPayload(const std::vector< unsigned char > &payload, T &obj)
Definition: specialtx.h:21
CAmount nValue
Definition: transaction.h:147
CDeterministicMNList GetListAtChainTip()
bool GetBlockHash(uint256 &hashRet, int nBlockHeight)
Return true if hash can be found in chainActive at nBlockHeight height.
CDeterministicMNManager(CEvoDB &_evoDb)
CDeterministicMNCPtr GetValidMN(const uint256 &proTxHash) const
uint256 proTxHash
Definition: providertx.h:142
std::string ToString() const
void SetBlockHash(const uint256 &_blockHash)
void PoSePunish(const uint256 &proTxHash, int penalty, bool debugLogs)
Punishes a MN for misbehavior.
uint256 proTxHash
Definition: providertx.h:95
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:80
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:158
void UpdatedBlockTip(const CBlockIndex *pindex)
CDeterministicMNCPtr GetUniquePropertyMN(const T &v) const
CKeyID keyIDVoting
Definition: providertx.h:145
Definition: evodb.h:32
CScript scriptPubKey
Definition: transaction.h:148
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:177
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:49
COutPoint collateralOutpoint
Definition: providertx.h:28
static const std::string EVODB_BEST_BLOCK
Definition: evodb.h:14
A UTXO entry.
Definition: coins.h:29
Definition: block.h:72
CDeterministicMNCPtr GetMN(const uint256 &proTxHash) const
size_t GetValidMNsCount() const
#define strprintf
Definition: tinyformat.h:1066
void UpdateMN(const CDeterministicMNCPtr &oldDmn, const CDeterministicMNStateCPtr &pdmnState)
uint64_t GetInternalId() const
void ApplyToState(CDeterministicMNState &target) const
static const CAmount COIN
Definition: amount.h:14
void Write(const K &key, const V &value)
Definition: evodb.h:69
std::shared_ptr< const CDeterministicMNState > CDeterministicMNStateCPtr
map set(key_type k, mapped_type v) const
Definition: map.hpp:263
std::vector< CDeterministicMNCPtr > GetProjectedMNPayees(int nCount) const
Calculates the projected MN payees for the next count blocks.
int Height() const
Return the maximal height in the chain.
Definition: chain.h:484
CCriticalSection cs_main
Definition: validation.cpp:213
CTxOut out
unspent transaction output
Definition: coins.h:33
std::string ToString() const
Definition: providertx.cpp:447
void UpgradeDiff(CDBBatch &batch, const CBlockIndex *pindexNext, const CDeterministicMNList &curMNList, CDeterministicMNList &newMNList)
void AddMN(const CDeterministicMNCPtr &dmn, bool fBumpTotalCount=true)
CScript scriptOperatorPayout
Definition: providertx.h:97
bool Read(const K &key, V &value)
Definition: evodb.h:62
std::unique_ptr< CEvoDB > evoDb
Definition: evodb.cpp:7
const T * find(const K &k) const
Definition: map.hpp:236
bool DoS(int level, bool ret=false, unsigned int chRejectCodeIn=0, const std::string &strRejectReasonIn="", bool corruptionIn=false, const std::string &strDebugMessageIn="")
Definition: validation.h:36
size_t GetAllMNsCount() const
Consensus::LLMQType llmqType
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
bool IsMNValid(const uint256 &proTxHash) const
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
static const std::string DB_LIST_SNAPSHOT
CDeterministicMNListDiff BuildDiff(const CDeterministicMNList &to) const
bool IsDIP3Enforced(int nHeight=-1)
std::string ToString() const
Definition: providertx.cpp:435
CBLSPublicKey pubKeyOperator
Definition: providertx.h:144
void AddUniqueProperty(const CDeterministicMNCPtr &dmn, const T &v)
void ForEachMN(bool onlyValid, Callback &&cb) const
unsigned char * begin()
Definition: uint256.h:57
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:345
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
static const unsigned char REJECT_INVALID
Definition: validation.h:13
bool ReadDataStream(const K &key, CDataStream &ssValue) const
Definition: dbwrapper.h:246
std::string ToString() const
Definition: providertx.cpp:459
CDeterministicMNStateCPtr pdmnState
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList &oldMNList, const CDeterministicMNListDiff &diff)
bool IsNull() const
Definition: uint256.h:33
CDBWrapper & GetRawDB()
Definition: evodb.h:89
void ToJson(UniValue &obj) const
Definition: simplifiedmns.h:24
const std::vector< CTxIn > vin
Definition: transaction.h:215
arith_uint256 UintToArith256(const uint256 &a)
void WriteBestBlock(const uint256 &hash)
Definition: evodb.cpp:75
std::vector< CDeterministicMNCPtr > CalculateQuorum(size_t maxSize, const uint256 &modifier) const
Calculate a quorum based on the modifier.
CDeterministicMNCPtr GetMNByInternalId(uint64_t internalId) const
uint256 GetBlockHash() const
Definition: chain.h:292
LLMQType
Definition: params.h:48
CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint &collateralOutpoint) const
bool GetUTXOCoin(const COutPoint &outpoint, Coin &coin)
Definition: validation.cpp:439
CDeterministicMNCPtr GetMNPayee() const
static const int DISK_SNAPSHOT_PERIOD
bool push_back(const UniValue &val)
Definition: univalue.cpp:110
#define LogPrintf(...)
Definition: util.h:203
const uint256 & GetBlockHash() const
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:330
std::unordered_map< uint256, CDeterministicMNList, StaticSaltedHasher > mnListsCache
std::string ToString() const
Definition: bls.h:210
#define LOCK(cs)
Definition: sync.h:178
const uint256 & GetHash() const
Definition: transaction.h:256
void HandleQuorumCommitment(llmq::CFinalCommitment &qc, const CBlockIndex *pindexQuorum, CDeterministicMNList &mnList, bool debugLogs)
void UpdateUniqueProperty(const CDeterministicMNCPtr &dmn, const T &oldValue, const T &newValue)
CService addr
Definition: providertx.h:96
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:143
static const int LIST_DIFFS_CACHE_SIZE
void PoSeDecrease(const uint256 &proTxHash)
Decrease penalty score of MN by 1.
int DIP0003Height
Block height at which DIP0003 becomes active.
Definition: params.h:158
uint32_t n
Definition: transaction.h:30
const BLSObject & Get() const
Definition: bls.h:402
boost::signals2::signal< void(const CDeterministicMNList &)> NotifyMasternodeListChanged
Masternode list has changed.
Definition: ui_interface.h:111
CKeyID keyIDOwner
Definition: providertx.h:30
uint32_t GetTotalRegisteredCount() const
void Write(const K &key, const V &value)
Definition: dbwrapper.h:75
CMainSignals & GetMainSignals()
std::string ToString() const
std::string ToString() const
Definition: uint256.cpp:62
unsigned int size() const
Definition: uint256.h:77
std::unique_ptr< CEvoDBScopedCommitter > BeginTransaction()
Definition: evodb.h:49
static std::pair< std::string, UniValue > Pair(const char *cKey, const char *cVal)
Definition: univalue.h:185
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
bool BuildNewListFromBlock(const CBlock &block, const CBlockIndex *pindexPrev, CValidationState &state, CDeterministicMNList &mnListRet, bool debugLogs)
bool IsProTxWithCollateral(const CTransactionRef &tx, uint32_t n)
static const unsigned char REJECT_DUPLICATE
Definition: validation.h:15
CScript scriptPayout
Definition: providertx.h:146
std::map< LLMQType, LLMQParams > llmqs
Definition: params.h:189
void CompactFull() const
Definition: dbwrapper.h:393
bool IsMNPoSeBanned(const uint256 &proTxHash) const
const int16_t nVersion
Definition: transaction.h:217
uint16_t nOperatorReward
Definition: providertx.h:33
void DeleteUniqueProperty(const CDeterministicMNCPtr &dmn, const T &oldValue)
int DIP0003EnforcementHeight
Block height at which DIP0003 becomes enforced.
Definition: params.h:160
uint256 GetHash() const
Definition: block.cpp:14
Capture information about block/transaction validation.
Definition: validation.h:22
256-bit opaque blob.
Definition: uint256.h:123
size_type size() const
Definition: map.hpp:177
CBLSLazyPublicKey pubKeyOperator
CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey &pubKey)
std::vector< CTransactionRef > vtx
Definition: block.h:76
std::string ToString() const
Definition: providertx.cpp:423
void CleanupCache(int nHeight)
std::string EncodeDestination(const CTxDestination &dest)
Definition: base58.cpp:329
bool HasMN(const uint256 &proTxHash) const
static int CompareByLastPaid_GetHeight(const CDeterministicMN &dmn)
CSimplifiedMNListDiff BuildSimplifiedDiff(const CDeterministicMNList &to) const
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:170
const CChainParams & Params()
Return the currently selected parameters.
COutPoint collateralOutpoint
Internal SHA-256 implementation.
Definition: sha256.cpp:46
const CBlockIndex * tipIndex
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:453
void DecreasePoSePenalties(CDeterministicMNList &mnList)
bool setObject()
Definition: univalue.cpp:103
bool HasUniqueProperty(const T &v) const
bool ProcessBlock(const CBlock &block, const CBlockIndex *pindex, CValidationState &state, bool fJustCheck)
uint16_t nReason
Definition: providertx.h:204
std::string ToStringIPPort(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:572
MnInternalIdMap mnInternalIdMap
std::vector< CDeterministicMNCPtr > addedMNs
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:157
void clear()
Definition: univalue.cpp:17
void ToJson(UniValue &obj) const
CDeterministicMNList ApplyDiff(const CBlockIndex *pindex, const CDeterministicMNListDiff &diff) const
bool UndoBlock(const CBlock &block, const CBlockIndex *pindex)
CClientUIInterface uiInterface
Definition: ui_interface.cpp:8
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:198
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:183
CDeterministicMNList GetListForBlock(const CBlockIndex *pindex)
void SetHeight(int _height)
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:54
std::set< uint64_t > removedMns
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:110
int CalcPenalty(int percent) const
Returns a the given percentage from the max penalty for this MN list.
CChain & chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:217
std::vector< std::pair< arith_uint256, CDeterministicMNCPtr > > CalculateScores(const uint256 &modifier) const
AssertLockHeld(g_cs_orphans)
A hasher class for SHA-256.
Definition: sha256.h:13
CDeterministicMNCPtr GetMNByCollateral(const COutPoint &collateralOutpoint) const
static const int CLIENT_VERSION
dashd-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
const int16_t nType
Definition: transaction.h:218
std::map< uint64_t, CDeterministicMNStateDiff > updatedMNs
CBLSPublicKey pubKeyOperator
Definition: providertx.h:31
static bool CompareByLastPaid(const CDeterministicMN &_a, const CDeterministicMN &_b)
void RemoveMN(const uint256 &proTxHash)
std::vector< bool > validMembers
std::vector< uint256 > deletedMNs
std::unordered_map< uint256, CDeterministicMNListDiff, StaticSaltedHasher > mnListDiffsCache
std::vector< CSimplifiedMNListEntry > mnList
uint256 proTxHash
Definition: providertx.h:203
int nMasternodeMinimumConfirmations
Definition: params.h:147
static std::vector< CDeterministicMNCPtr > GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex *pindexQuorum)
map erase(const K &k) const
Definition: map.hpp:286
CService addr
Definition: providertx.h:29
static const std::string DB_LIST_DIFF
uint256 hash
Definition: transaction.h:29
std::string ToStringShort() const
Definition: transaction.cpp:17
CDeterministicMNCPtr GetMNByService(const CService &service) const
Released under the MIT license