PIVX Core  5.6.99
P2P Digital Currency
deterministicmns.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2021 The Dash Core developers
2 // Copyright (c) 2021-2022 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 #include "evo/deterministicmns.h"
7 
8 #include "bls/key_io.h"
9 #include "chain.h"
10 #include "coins.h"
11 #include "chainparams.h"
12 #include "consensus/upgrades.h"
13 #include "consensus/validation.h"
14 #include "core_io.h"
15 #include "key_io.h"
16 #include "guiinterface.h"
17 #include "masternodeman.h" // for mnodeman (!TODO: remove)
18 #include "script/standard.h"
19 #include "spork.h"
20 #include "sync.h"
21 
22 #include <univalue.h>
23 
24 static const std::string DB_LIST_SNAPSHOT = "dmn_S";
25 static const std::string DB_LIST_DIFF = "dmn_D";
26 
27 std::unique_ptr<CDeterministicMNManager> deterministicMNManager;
28 
30 {
31  CTxDestination dest;
32  std::string payoutAddress = "unknown";
33  std::string operatorPayoutAddress = "none";
34  if (ExtractDestination(scriptPayout, dest)) {
35  payoutAddress = EncodeDestination(dest);
36  }
38  operatorPayoutAddress = EncodeDestination(dest);
39  }
40 
41  return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, ownerAddress=%s, operatorPubKey=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)",
44 }
45 
47 {
48  obj.clear();
49  obj.setObject();
50  obj.pushKV("service", addr.ToStringIPPort());
51  obj.pushKV("registeredHeight", nRegisteredHeight);
52  obj.pushKV("lastPaidHeight", nLastPaidHeight);
53  obj.pushKV("PoSePenalty", nPoSePenalty);
54  obj.pushKV("PoSeRevivedHeight", nPoSeRevivedHeight);
55  obj.pushKV("PoSeBanHeight", nPoSeBanHeight);
56  obj.pushKV("revocationReason", nRevocationReason);
57  obj.pushKV("ownerAddress", EncodeDestination(keyIDOwner));
58  obj.pushKV("operatorPubKey", bls::EncodePublic(Params(), pubKeyOperator.Get()));
59  obj.pushKV("votingAddress", EncodeDestination(keyIDVoting));
60 
61  CTxDestination dest1;
62  if (ExtractDestination(scriptPayout, dest1)) {
63  obj.pushKV("payoutAddress", EncodeDestination(dest1));
64  }
65  CTxDestination dest2;
67  obj.pushKV("operatorPayoutAddress", EncodeDestination(dest2));
68  }
69 }
70 
72 {
73  // can't get it if it wasn't set yet
74  assert(internalId != std::numeric_limits<uint64_t>::max());
75  return internalId;
76 }
77 
78 std::string CDeterministicMN::ToString() const
79 {
80  return strprintf("CDeterministicMN(proTxHash=%s, collateralOutpoint=%s, nOperatorReward=%f, state=%s", proTxHash.ToString(), collateralOutpoint.ToStringShort(), (double)nOperatorReward / 100, pdmnState->ToString());
81 }
82 
84 {
85  obj.clear();
86  obj.setObject();
87 
88  UniValue stateObj;
89  pdmnState->ToJson(stateObj);
90 
91  obj.pushKV("proTxHash", proTxHash.ToString());
92  obj.pushKV("collateralHash", collateralOutpoint.hash.ToString());
93  obj.pushKV("collateralIndex", (int)collateralOutpoint.n);
94  obj.pushKV("operatorReward", (double)nOperatorReward / 100);
95  obj.pushKV("dmnstate", stateObj);
96 }
97 
99 {
100  auto p = mnMap.find(proTxHash);
101  if (p == nullptr) {
102  return nullptr;
103  }
104  return *p;
105 }
106 
108 {
109  auto dmn = GetMN(proTxHash);
110  if (dmn && dmn->IsPoSeBanned()) {
111  return nullptr;
112  }
113  return dmn;
114 }
115 
117 {
118  for (const auto& p : mnMap) {
119  if (p.second->pdmnState->pubKeyOperator.Get() == pubKey) {
120  return p.second;
121  }
122  }
123  return nullptr;
124 }
125 
127 {
128  return GetUniquePropertyMN(collateralOutpoint);
129 }
130 
132 {
133  auto dmn = GetMNByCollateral(collateralOutpoint);
134  if (dmn && dmn->IsPoSeBanned()) {
135  return nullptr;
136  }
137  return dmn;
138 }
139 
141 {
142  return GetUniquePropertyMN(service);
143 }
144 
146 {
147  auto proTxHash = mnInternalIdMap.find(internalId);
148  if (!proTxHash) {
149  return nullptr;
150  }
151  return GetMN(*proTxHash);
152 }
153 
154 static int CompareByLastPaidGetHeight(const CDeterministicMN& dmn)
155 {
156  int height = dmn.pdmnState->nLastPaidHeight;
157  if (dmn.pdmnState->nPoSeRevivedHeight != -1 && dmn.pdmnState->nPoSeRevivedHeight > height) {
158  height = dmn.pdmnState->nPoSeRevivedHeight;
159  } else if (height == 0) {
160  height = dmn.pdmnState->nRegisteredHeight;
161  }
162  return height;
163 }
164 
165 static bool CompareByLastPaid(const CDeterministicMN& _a, const CDeterministicMN& _b)
166 {
167  int ah = CompareByLastPaidGetHeight(_a);
168  int bh = CompareByLastPaidGetHeight(_b);
169  if (ah == bh) {
170  return _a.proTxHash < _b.proTxHash;
171  } else {
172  return ah < bh;
173  }
174 }
175 static bool CompareByLastPaid(const CDeterministicMNCPtr& _a, const CDeterministicMNCPtr& _b)
176 {
177  return CompareByLastPaid(*_a, *_b);
178 }
179 
181 {
182  if (mnMap.size() == 0) {
183  return nullptr;
184  }
185 
187  ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
188  if (!best || CompareByLastPaid(dmn, best)) {
189  best = dmn;
190  }
191  });
192 
193  return best;
194 }
195 
196 std::vector<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(unsigned int nCount) const
197 {
198  if (nCount > GetValidMNsCount()) {
199  nCount = GetValidMNsCount();
200  }
201 
202  std::vector<CDeterministicMNCPtr> result;
203  result.reserve(nCount);
204 
205  ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
206  result.emplace_back(dmn);
207  });
208  std::sort(result.begin(), result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) {
209  return CompareByLastPaid(a, b);
210  });
211 
212  result.resize(nCount);
213 
214  return result;
215 }
216 
217 std::vector<CDeterministicMNCPtr> CDeterministicMNList::CalculateQuorum(size_t maxSize, const uint256& modifier) const
218 {
219  auto scores = CalculateScores(modifier);
220 
221  // sort is descending order
222  std::sort(scores.rbegin(), scores.rend(), [](const std::pair<arith_uint256, CDeterministicMNCPtr>& a, std::pair<arith_uint256, CDeterministicMNCPtr>& b) {
223  if (a.first == b.first) {
224  // this should actually never happen, but we should stay compatible with how the non deterministic MNs did the sorting
225  return a.second->collateralOutpoint < b.second->collateralOutpoint;
226  }
227  return a.first < b.first;
228  });
229 
230  // take top maxSize entries and return it
231  std::vector<CDeterministicMNCPtr> result;
232  result.resize(std::min(maxSize, scores.size()));
233  for (size_t i = 0; i < result.size(); i++) {
234  result[i] = std::move(scores[i].second);
235  }
236  return result;
237 }
238 
239 std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> CDeterministicMNList::CalculateScores(const uint256& modifier) const
240 {
241  std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> scores;
242  scores.reserve(GetAllMNsCount());
243  ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
244  if (dmn->pdmnState->confirmedHash.IsNull()) {
245  // we only take confirmed MNs into account to avoid hash grinding on the ProRegTxHash to sneak MNs into a
246  // future quorums
247  return;
248  }
249  // calculate sha256(sha256(proTxHash, confirmedHash), modifier) per MN
250  // Please note that this is not a double-sha256 but a single-sha256
251  // The first part is already precalculated (confirmedHashWithProRegTxHash)
252  // TODO When https://github.com/bitcoin/bitcoin/pull/13191 gets backported, implement something that is similar but for single-sha256
253  uint256 h;
254  CSHA256 sha256;
255  sha256.Write(dmn->pdmnState->confirmedHashWithProRegTxHash.begin(), dmn->pdmnState->confirmedHashWithProRegTxHash.size());
256  sha256.Write(modifier.begin(), modifier.size());
257  sha256.Finalize(h.begin());
258 
259  scores.emplace_back(UintToArith256(h), dmn);
260  });
261 
262  return scores;
263 }
264 
266 {
267  // Maximum PoSe penalty is dynamic and equals the number of registered MNs
268  // It's however at least 100.
269  // This means that the max penalty is usually equal to a full payment cycle
270  return std::max(100, (int)GetAllMNsCount());
271 }
272 
273 int CDeterministicMNList::CalcPenalty(int percent) const
274 {
275  assert(percent > 0);
276  return (CalcMaxPoSePenalty() * percent) / 100;
277 }
278 
279 void CDeterministicMNList::PoSePunish(const uint256& proTxHash, int penalty, bool debugLogs)
280 {
281  assert(penalty > 0);
282 
283  auto dmn = GetMN(proTxHash);
284  if (!dmn) {
285  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
286  }
287 
288  int maxPenalty = CalcMaxPoSePenalty();
289 
290  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
291  newState->nPoSePenalty += penalty;
292  newState->nPoSePenalty = std::min(maxPenalty, newState->nPoSePenalty);
293 
294  if (debugLogs) {
295  LogPrintf("CDeterministicMNList::%s -- punished MN %s, penalty %d->%d (max=%d)\n",
296  __func__, proTxHash.ToString(), dmn->pdmnState->nPoSePenalty, newState->nPoSePenalty, maxPenalty);
297  }
298 
299  if (newState->nPoSePenalty >= maxPenalty && newState->nPoSeBanHeight == -1) {
300  newState->nPoSeBanHeight = nHeight;
301  if (debugLogs) {
302  LogPrintf("CDeterministicMNList::%s -- banned MN %s at height %d\n",
303  __func__, proTxHash.ToString(), nHeight);
304  }
305  }
306  UpdateMN(proTxHash, newState);
307 }
308 
310 {
311  auto dmn = GetMN(proTxHash);
312  if (!dmn) {
313  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
314  }
315  assert(dmn->pdmnState->nPoSePenalty > 0 && dmn->pdmnState->nPoSeBanHeight == -1);
316 
317  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
318  newState->nPoSePenalty--;
319  UpdateMN(proTxHash, newState);
320 }
321 
323 {
324  CDeterministicMNListDiff diffRet;
325 
326  to.ForEachMN(false, [&](const CDeterministicMNCPtr& toPtr) {
327  auto fromPtr = GetMN(toPtr->proTxHash);
328  if (fromPtr == nullptr) {
329  diffRet.addedMNs.emplace_back(toPtr);
330  } else if (fromPtr != toPtr || fromPtr->pdmnState != toPtr->pdmnState) {
331  CDeterministicMNStateDiff stateDiff(*fromPtr->pdmnState, *toPtr->pdmnState);
332  if (stateDiff.fields) {
333  diffRet.updatedMNs.emplace(toPtr->GetInternalId(), std::move(stateDiff));
334  }
335  }
336  });
337  ForEachMN(false, [&](const CDeterministicMNCPtr& fromPtr) {
338  auto toPtr = to.GetMN(fromPtr->proTxHash);
339  if (toPtr == nullptr) {
340  diffRet.removedMns.emplace(fromPtr->GetInternalId());
341  }
342  });
343 
344  // added MNs need to be sorted by internalId so that these are added in correct order when the diff is applied later
345  // otherwise internalIds will not match with the original list
346  std::sort(diffRet.addedMNs.begin(), diffRet.addedMNs.end(), [](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) {
347  return a->GetInternalId() < b->GetInternalId();
348  });
349 
350  return diffRet;
351 }
352 
354 {
355  CDeterministicMNList result = *this;
356  result.blockHash = pindex->GetBlockHash();
357  result.nHeight = pindex->nHeight;
358 
359  for (const auto& id : diff.removedMns) {
360  auto dmn = result.GetMNByInternalId(id);
361  if (!dmn) {
362  throw(std::runtime_error(strprintf("%s: can't find a removed masternode, id=%d", __func__, id)));
363  }
364  result.RemoveMN(dmn->proTxHash);
365  }
366  for (const auto& dmn : diff.addedMNs) {
367  result.AddMN(dmn);
368  }
369  for (const auto& p : diff.updatedMNs) {
370  auto dmn = result.GetMNByInternalId(p.first);
371  result.UpdateMN(dmn, p.second);
372  }
373 
374  return result;
375 }
376 
377 void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn, bool fBumpTotalCount)
378 {
379  assert(dmn != nullptr);
380 
381  if (mnMap.find(dmn->proTxHash)) {
382  throw(std::runtime_error(strprintf("%s: can't add a duplicate masternode with the same proTxHash=%s", __func__, dmn->proTxHash.ToString())));
383  }
384  if (mnInternalIdMap.find(dmn->GetInternalId())) {
385  throw(std::runtime_error(strprintf("%s: can't add a duplicate masternode with the same internalId=%d", __func__, dmn->GetInternalId())));
386  }
387  if (HasUniqueProperty(dmn->pdmnState->addr)) {
388  throw(std::runtime_error(strprintf("%s: can't add a masternode with a duplicate address %s", __func__, dmn->pdmnState->addr.ToStringIPPort())));
389  }
390  if (HasUniqueProperty(dmn->pdmnState->keyIDOwner) || HasUniqueProperty(dmn->pdmnState->pubKeyOperator)) {
391  throw(std::runtime_error(strprintf("%s: can't add a masternode with a duplicate key (%s or %s)", __func__, EncodeDestination(dmn->pdmnState->keyIDOwner), bls::EncodePublic(Params(), dmn->pdmnState->pubKeyOperator.Get()))));
392  }
393 
394  mnMap = mnMap.set(dmn->proTxHash, dmn);
395  mnInternalIdMap = mnInternalIdMap.set(dmn->GetInternalId(), dmn->proTxHash);
396  AddUniqueProperty(dmn, dmn->collateralOutpoint);
397  if (dmn->pdmnState->addr != CService()) {
398  AddUniqueProperty(dmn, dmn->pdmnState->addr);
399  }
400  AddUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
401  AddUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
402 
403  if (fBumpTotalCount) {
404  // nTotalRegisteredCount acts more like a checkpoint, not as a limit,
405  nTotalRegisteredCount = std::max(dmn->GetInternalId() + 1, (uint64_t)nTotalRegisteredCount);
406  }
407 }
408 
410 {
411  assert(oldDmn != nullptr);
412 
413  if (HasUniqueProperty(oldDmn->pdmnState->addr) && GetUniquePropertyMN(oldDmn->pdmnState->addr)->proTxHash != oldDmn->proTxHash) {
414  throw(std::runtime_error(strprintf("%s: can't update a masternode with a duplicate address %s", __func__, oldDmn->pdmnState->addr.ToStringIPPort())));
415  }
416 
417  auto dmn = std::make_shared<CDeterministicMN>(*oldDmn);
418  auto oldState = dmn->pdmnState;
419  dmn->pdmnState = pdmnState;
420  mnMap = mnMap.set(oldDmn->proTxHash, dmn);
421 
422  UpdateUniqueProperty(dmn, oldState->addr, pdmnState->addr);
423  UpdateUniqueProperty(dmn, oldState->keyIDOwner, pdmnState->keyIDOwner);
424  UpdateUniqueProperty(dmn, oldState->pubKeyOperator, pdmnState->pubKeyOperator);
425 }
426 
428 {
429  auto oldDmn = mnMap.find(proTxHash);
430  if (!oldDmn) {
431  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
432  }
433  UpdateMN(*oldDmn, pdmnState);
434 }
435 
437 {
438  assert(oldDmn != nullptr);
439  auto oldState = oldDmn->pdmnState;
440  auto newState = std::make_shared<CDeterministicMNState>(*oldState);
441  stateDiff.ApplyToState(*newState);
442  UpdateMN(oldDmn, newState);
443 }
444 
446 {
447  auto dmn = GetMN(proTxHash);
448  if (!dmn) {
449  throw(std::runtime_error(strprintf("%s: Can't find a masternode with proTxHash=%s", __func__, proTxHash.ToString())));
450  }
452  if (dmn->pdmnState->addr != CService()) {
453  DeleteUniqueProperty(dmn, dmn->pdmnState->addr);
454  }
455  DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOwner);
456  DeleteUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator);
457 
458  mnMap = mnMap.erase(proTxHash);
460 }
461 
463  evoDb(_evoDb)
464 {
465 }
466 
467 bool CDeterministicMNManager::ProcessBlock(const CBlock& block, const CBlockIndex* pindex, CValidationState& _state, bool fJustCheck)
468 {
469  int nHeight = pindex->nHeight;
470  if (!IsDIP3Enforced(nHeight)) {
471  // nothing to do
472  return true;
473  }
474 
475  CDeterministicMNList oldList, newList;
477 
478  try {
479  LOCK(cs);
480 
481  if (!BuildNewListFromBlock(block, pindex->pprev, _state, newList, true)) {
482  // pass the state returned by the function above
483  return false;
484  }
485 
486  if (fJustCheck) {
487  return true;
488  }
489 
490  if (newList.GetHeight() == -1) {
491  newList.SetHeight(nHeight);
492  }
493 
494  newList.SetBlockHash(block.GetHash());
495 
496  oldList = GetListForBlock(pindex->pprev);
497  diff = oldList.BuildDiff(newList);
498 
499  evoDb.Write(std::make_pair(DB_LIST_DIFF, newList.GetBlockHash()), diff);
500  if ((nHeight % DISK_SNAPSHOT_PERIOD) == 0 || oldList.GetHeight() == -1) {
501  evoDb.Write(std::make_pair(DB_LIST_SNAPSHOT, newList.GetBlockHash()), newList);
502  mnListsCache.emplace(newList.GetBlockHash(), newList);
503  LogPrintf("CDeterministicMNManager::%s -- Wrote snapshot. nHeight=%d, mapCurMNs.allMNsCount=%d\n",
504  __func__, nHeight, newList.GetAllMNsCount());
505  }
506 
507  diff.nHeight = pindex->nHeight;
508  mnListDiffsCache.emplace(pindex->GetBlockHash(), diff);
509  } catch (const std::exception& e) {
510  LogPrintf("CDeterministicMNManager::%s -- internal error: %s\n", __func__, e.what());
511  return _state.DoS(100, false, REJECT_INVALID, "failed-dmn-block");
512  }
513 
514  // Don't hold cs while calling signals
515  if (diff.HasChanges()) {
516  GetMainSignals().NotifyMasternodeListChanged(false, oldList, diff);
518  }
519 
520  LOCK(cs);
521  CleanupCache(nHeight);
522 
523  return true;
524 }
525 
526 bool CDeterministicMNManager::UndoBlock(const CBlock& block, const CBlockIndex* pindex)
527 {
528  if (!IsDIP3Enforced(pindex->nHeight)) {
529  // nothing to do
530  return true;
531  }
532 
533  const uint256& blockHash = block.GetHash();
534 
535  CDeterministicMNList curList;
536  CDeterministicMNList prevList;
538  {
539  LOCK(cs);
540  evoDb.Read(std::make_pair(DB_LIST_DIFF, blockHash), diff);
541 
542  if (diff.HasChanges()) {
543  // need to call this before erasing
544  curList = GetListForBlock(pindex);
545  prevList = GetListForBlock(pindex->pprev);
546  }
547 
548  mnListsCache.erase(blockHash);
549  mnListDiffsCache.erase(blockHash);
550  }
551 
552  if (diff.HasChanges()) {
553  auto inversedDiff = curList.BuildDiff(prevList);
554  GetMainSignals().NotifyMasternodeListChanged(true, curList, inversedDiff);
556  }
557 
558  return true;
559 }
560 
562 {
563  LOCK(cs);
564  tipIndex = pindex;
565 }
566 
567 bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, CValidationState& _state, CDeterministicMNList& mnListRet, bool debugLogs)
568 {
570  const auto& consensus = Params().GetConsensus();
571  int nHeight = pindexPrev->nHeight + 1;
572 
573  CDeterministicMNList oldList = GetListForBlock(pindexPrev);
574  CDeterministicMNList newList = oldList;
575  newList.SetBlockHash(UINT256_ZERO); // we can't know the final block hash, so better not return a (invalid) block hash
576  newList.SetHeight(nHeight);
577 
578  auto payee = oldList.GetMNPayee();
579 
580  // we iterate the oldList here and update the newList
581  // this is only valid as long these have not diverged at this point, which is the case as long as we don't add
582  // code above this loop that modifies newList
583  oldList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) {
584  if (!dmn->pdmnState->confirmedHash.IsNull()) {
585  // already confirmed
586  return;
587  }
588  // this works on the previous block, so confirmation will happen one block after nMasternodeMinimumConfirmations
589  // has been reached, but the block hash will then point to the block at nMasternodeMinimumConfirmations
590  int nConfirmations = pindexPrev->nHeight - dmn->pdmnState->nRegisteredHeight;
591  if (nConfirmations >= consensus.MasternodeCollateralMinConf()) {
592  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
593  newState->UpdateConfirmedHash(dmn->proTxHash, pindexPrev->GetBlockHash());
594  newList.UpdateMN(dmn->proTxHash, newState);
595  }
596  });
597 
598  DecreasePoSePenalties(newList);
599 
600  // we skip the coinbase
601  for (int i = 1; i < (int)block.vtx.size(); i++) {
602  const CTransaction& tx = *block.vtx[i];
603 
604  if (tx.nType == CTransaction::TxType::PROREG) {
605  ProRegPL pl;
606  if (!GetTxPayload(tx, pl)) {
607  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
608  }
609 
610  auto dmn = std::make_shared<CDeterministicMN>(newList.GetTotalRegisteredCount());
611  dmn->proTxHash = tx.GetHash();
612 
613  // collateralOutpoint is either pointing to an external collateral or to the ProRegTx itself
614  dmn->collateralOutpoint = pl.collateralOutpoint.hash.IsNull() ? COutPoint(tx.GetHash(), pl.collateralOutpoint.n)
615  : pl.collateralOutpoint;
616 
617  // if the collateral outpoint appears in the legacy masternode list, remove the old node
618  // !TODO: remove this when the transition to DMN is complete
619  CMasternode* old_mn = mnodeman.Find(dmn->collateralOutpoint);
620  if (old_mn) {
621  old_mn->SetSpent();
623  }
624 
625  auto replacedDmn = newList.GetMNByCollateral(dmn->collateralOutpoint);
626  if (replacedDmn != nullptr) {
627  // This might only happen with a ProRegTx that refers an external collateral
628  // In that case the new ProRegTx will replace the old one. This means the old one is removed
629  // and the new one is added like a completely fresh one, which is also at the bottom of the payment list
630  newList.RemoveMN(replacedDmn->proTxHash);
631  if (debugLogs) {
632  LogPrintf("CDeterministicMNManager::%s -- MN %s removed from list because collateral was used for a new ProRegTx. collateralOutpoint=%s, nHeight=%d, mapCurMNs.allMNsCount=%d\n",
633  __func__, replacedDmn->proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort(), nHeight, newList.GetAllMNsCount());
634  }
635  }
636 
637  if (newList.HasUniqueProperty(pl.addr)) {
638  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-IP-address");
639  }
640  if (newList.HasUniqueProperty(pl.keyIDOwner)) {
641  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-owner-key");
642  }
643  if (newList.HasUniqueProperty(pl.pubKeyOperator)) {
644  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-operator-key");
645  }
646 
647  dmn->nOperatorReward = pl.nOperatorReward;
648 
649  auto dmnState = std::make_shared<CDeterministicMNState>(pl);
650  dmnState->nRegisteredHeight = nHeight;
651  if (pl.addr == CService()) {
652  // start in banned pdmnState as we need to wait for a ProUpServTx
653  dmnState->nPoSeBanHeight = nHeight;
654  }
655  dmn->pdmnState = dmnState;
656 
657  newList.AddMN(dmn);
658 
659  if (debugLogs) {
660  LogPrintf("CDeterministicMNManager::%s -- MN %s added at height %d: %s\n",
661  __func__, tx.GetHash().ToString(), nHeight, pl.ToString());
662  }
663 
664  } else if (tx.nType == CTransaction::TxType::PROUPSERV) {
665  ProUpServPL pl;
666  if (!GetTxPayload(tx, pl)) {
667  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
668  }
669 
670  if (newList.HasUniqueProperty(pl.addr) && newList.GetUniquePropertyMN(pl.addr)->proTxHash != pl.proTxHash) {
671  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-addr");
672  }
673 
674  CDeterministicMNCPtr dmn = newList.GetMN(pl.proTxHash);
675  if (!dmn) {
676  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
677  }
678  if (dmn->nOperatorReward == 0 && !pl.scriptOperatorPayout.empty()) {
679  // operator payout address can not be set if the operator reward is 0
680  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-operator-payee");
681  }
682  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
683  newState->addr = pl.addr;
684  newState->scriptOperatorPayout = pl.scriptOperatorPayout;
685 
686  if (newState->nPoSeBanHeight != -1) {
687  // only revive when all keys are set
688  if (newState->pubKeyOperator.Get().IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
689  newState->nPoSePenalty = 0;
690  newState->nPoSeBanHeight = -1;
691  newState->nPoSeRevivedHeight = nHeight;
692 
693  if (debugLogs) {
694  LogPrintf("CDeterministicMNManager::%s -- MN %s revived at height %d\n",
695  __func__, pl.proTxHash.ToString(), nHeight);
696  }
697  }
698  }
699 
700  newList.UpdateMN(pl.proTxHash, newState);
701  if (debugLogs) {
702  LogPrintf("CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
703  __func__, pl.proTxHash.ToString(), nHeight, pl.ToString());
704  }
705 
706  } else if (tx.nType == CTransaction::TxType::PROUPREG) {
707  ProUpRegPL pl;
708  if (!GetTxPayload(tx, pl)) {
709  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
710  }
711 
712  CDeterministicMNCPtr dmn = newList.GetMN(pl.proTxHash);
713  if (!dmn) {
714  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
715  }
716  if (newList.HasUniqueProperty(pl.pubKeyOperator) && newList.GetUniquePropertyMN(pl.pubKeyOperator)->proTxHash != pl.proTxHash) {
717  return _state.DoS(100, false, REJECT_DUPLICATE, "bad-protx-dup-operator-key");
718  }
719  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
720  if (newState->pubKeyOperator.Get() != pl.pubKeyOperator) {
721  // reset all operator related fields and put MN into PoSe-banned state in case the operator key changes
722  newState->ResetOperatorFields();
723  newState->BanIfNotBanned(nHeight);
724  }
725  newState->pubKeyOperator.Set(pl.pubKeyOperator);
726  newState->keyIDVoting = pl.keyIDVoting;
727  newState->scriptPayout = pl.scriptPayout;
728 
729  newList.UpdateMN(pl.proTxHash, newState);
730 
731  if (debugLogs) {
732  LogPrintf("CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
733  __func__, pl.proTxHash.ToString(), nHeight, pl.ToString());
734  }
735 
736  } else if (tx.nType == CTransaction::TxType::PROUPREV) {
737  ProUpRevPL pl;
738  if (!GetTxPayload(tx, pl)) {
739  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-payload");
740  }
741 
742  CDeterministicMNCPtr dmn = newList.GetMN(pl.proTxHash);
743  if (!dmn) {
744  return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash");
745  }
746  auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
747  newState->ResetOperatorFields();
748  newState->BanIfNotBanned(nHeight);
749  newState->nRevocationReason = pl.nReason;
750 
751  newList.UpdateMN(pl.proTxHash, newState);
752 
753  if (debugLogs) {
754  LogPrintf("CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
755  __func__, pl.proTxHash.ToString(), nHeight, pl.ToString());
756  }
757  } else if (tx.nType == CTransaction::TxType::LLMQCOMM) {
758  llmq::LLMQCommPL pl;
759  if (!GetTxPayload(tx, pl)) {
760  return _state.DoS(100, false, REJECT_INVALID, "bad-qc-payload");
761  }
762  if (!pl.commitment.IsNull()) {
763  // Double-check that the quorum index is in the active chain
764  const auto& params = consensus.llmqs.at((Consensus::LLMQType)pl.commitment.llmqType);
765  uint32_t quorumHeight = pl.nHeight - (pl.nHeight % params.dkgInterval);
766  auto quorumIndex = pindexPrev->GetAncestor(quorumHeight);
767  if (!quorumIndex || quorumIndex->GetBlockHash() != pl.commitment.quorumHash) {
768  return _state.DoS(100, false, REJECT_INVALID, "bad-qc-quorum-hash");
769  }
770  // Check for failed DKG participation by MNs
771  HandleQuorumCommitment(pl.commitment, quorumIndex, newList, debugLogs);
772  }
773  }
774 
775  }
776 
777  // check if any existing MN collateral is spent by this transaction
778  // we skip the coinbase
779  for (int i = 1; i < (int)block.vtx.size(); i++) {
780  const CTransaction& tx = *block.vtx[i];
781  for (const auto& in : tx.vin) {
782  auto dmn = newList.GetMNByCollateral(in.prevout);
783  if (dmn && dmn->collateralOutpoint == in.prevout) {
784  newList.RemoveMN(dmn->proTxHash);
785  if (debugLogs) {
786  LogPrintf("CDeterministicMNManager::%s -- MN %s removed from list because collateral was spent. collateralOutpoint=%s, nHeight=%d, mapCurMNs.allMNsCount=%d\n",
787  __func__, dmn->proTxHash.ToString(), dmn->collateralOutpoint.ToStringShort(), nHeight, newList.GetAllMNsCount());
788  }
789  }
790  }
791  }
792 
793  // The payee for the current block was determined by the previous block's list but it might have disappeared in the
794  // current block. We still pay that MN one last time however.
795  if (payee && newList.HasMN(payee->proTxHash)) {
796  auto newState = std::make_shared<CDeterministicMNState>(*newList.GetMN(payee->proTxHash)->pdmnState);
797  newState->nLastPaidHeight = nHeight;
798  newList.UpdateMN(payee->proTxHash, newState);
799  }
800 
801  mnListRet = std::move(newList);
802 
803  return true;
804 }
805 
807 {
808  // The commitment has already been validated at this point so it's safe to use members of it
809 
810  auto members = GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, pindexQuorum);
811 
812  for (size_t i = 0; i < members.size(); i++) {
813  if (!mnList.HasMN(members[i]->proTxHash)) {
814  continue;
815  }
816  if (!qc.validMembers[i]) {
817  // punish MN for failed DKG participation
818  // The idea is to immediately ban a MN when it fails 2 DKG sessions with only a few blocks in-between
819  // If there were enough blocks between failures, the MN has a chance to recover as he reduces his penalty by 1 for every block
820  // If it however fails 3 times in the timespan of a single payment cycle, it should definitely get banned
821  mnList.PoSePunish(members[i]->proTxHash, mnList.CalcPenalty(66), debugLogs);
822  }
823  }
824 }
825 
827 {
828  std::vector<uint256> toDecrease;
829  toDecrease.reserve(mnList.GetValidMNsCount() / 10);
830  // only iterate and decrease for valid ones (not PoSe banned yet)
831  // if a MN ever reaches the maximum, it stays in PoSe banned state until revived
832  mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
833  if (dmn->pdmnState->nPoSePenalty > 0 && dmn->pdmnState->nPoSeBanHeight == -1) {
834  toDecrease.emplace_back(dmn->proTxHash);
835  }
836  });
837 
838  for (const auto& proTxHash : toDecrease) {
839  mnList.PoSeDecrease(proTxHash);
840  }
841 }
842 
844 {
845  LOCK(cs);
846 
847  // Return early before enforcement
848  if (!IsDIP3Enforced(pindex->nHeight)) {
849  return {};
850  }
851 
852  CDeterministicMNList snapshot;
853  std::list<const CBlockIndex*> listDiffIndexes;
854 
855  while (true) {
856  // try using cache before reading from disk
857  auto itLists = mnListsCache.find(pindex->GetBlockHash());
858  if (itLists != mnListsCache.end()) {
859  snapshot = itLists->second;
860  break;
861  }
862 
863  if (evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, pindex->GetBlockHash()), snapshot)) {
864  mnListsCache.emplace(pindex->GetBlockHash(), snapshot);
865  break;
866  }
867 
868  // no snapshot found yet, check diffs
869  auto itDiffs = mnListDiffsCache.find(pindex->GetBlockHash());
870  if (itDiffs != mnListDiffsCache.end()) {
871  listDiffIndexes.emplace_front(pindex);
872  pindex = pindex->pprev;
873  continue;
874  }
875 
877  if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, pindex->GetBlockHash()), diff)) {
878  // no snapshot and no diff on disk means that it's initial snapshot (empty list)
879  // If we get here, then this must be the block before the enforcement of DIP3.
880  if (!IsActivationHeight(pindex->nHeight + 1, Params().GetConsensus(), Consensus::UPGRADE_V6_0)) {
881  std::string err = strprintf("No masternode list data found for block %s at height %d. "
882  "Possible corrupt database.", pindex->GetBlockHash().ToString(), pindex->nHeight);
883  throw std::runtime_error(err);
884  }
885  snapshot = CDeterministicMNList(pindex->GetBlockHash(), -1, 0);
886  mnListsCache.emplace(pindex->GetBlockHash(), snapshot);
887  break;
888  }
889 
890  diff.nHeight = pindex->nHeight;
891  mnListDiffsCache.emplace(pindex->GetBlockHash(), std::move(diff));
892  listDiffIndexes.emplace_front(pindex);
893  pindex = pindex->pprev;
894  }
895 
896  for (const auto& diffIndex : listDiffIndexes) {
897  const auto& diff = mnListDiffsCache.at(diffIndex->GetBlockHash());
898  if (diff.HasChanges()) {
899  snapshot = snapshot.ApplyDiff(diffIndex, diff);
900  } else {
901  snapshot.SetBlockHash(diffIndex->GetBlockHash());
902  snapshot.SetHeight(diffIndex->nHeight);
903  }
904  }
905 
906  if (tipIndex) {
907  // always keep a snapshot for the tip
908  if (snapshot.GetBlockHash() == tipIndex->GetBlockHash()) {
909  mnListsCache.emplace(snapshot.GetBlockHash(), snapshot);
910  } else {
911  // !TODO: keep snapshots for yet alive quorums
912  }
913  }
914 
915  return snapshot;
916 }
917 
919 {
920  LOCK(cs);
921  if (!tipIndex) {
922  return {};
923  }
924  return GetListForBlock(tipIndex);
925 }
926 
928 {
930 }
931 
933 {
934  int tipHeight = WITH_LOCK(cs, return tipIndex ? tipIndex->nHeight : -1;);
935  return IsDIP3Enforced(tipHeight);
936 }
937 
939 {
941 }
942 
944 {
945  int tipHeight = WITH_LOCK(cs, return tipIndex ? tipIndex->nHeight : -1;);
946  return LegacyMNObsolete(tipHeight);
947 }
948 
950 {
952 
953  std::vector<uint256> toDeleteLists;
954  std::vector<uint256> toDeleteDiffs;
955  for (const auto& p : mnListsCache) {
956  if (p.second.GetHeight() + LIST_DIFFS_CACHE_SIZE < nHeight) {
957  toDeleteLists.emplace_back(p.first);
958  continue;
959  }
960  // !TODO: llmq cache cleanup
961  }
962  for (const auto& h : toDeleteLists) {
963  mnListsCache.erase(h);
964  }
965  for (const auto& p : mnListDiffsCache) {
966  if (p.second.nHeight + LIST_DIFFS_CACHE_SIZE < nHeight) {
967  toDeleteDiffs.emplace_back(p.first);
968  }
969  }
970  for (const auto& h : toDeleteDiffs) {
971  mnListDiffsCache.erase(h);
972  }
973 }
974 
975 std::vector<CDeterministicMNCPtr> CDeterministicMNManager::GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum)
976 {
977  auto& params = Params().GetConsensus().llmqs.at(llmqType);
978  auto allMns = GetListForBlock(pindexQuorum);
979  auto modifier = ::SerializeHash(std::make_pair(static_cast<uint8_t>(llmqType), pindexQuorum->GetBlockHash()));
980  return allMns.CalculateQuorum(params.size, modifier);
981 }
982 
983 
arith_uint256 UintToArith256(const uint256 &a)
const CChainParams & Params()
Return the currently selected parameters.
uint256 hash
Definition: transaction.h:35
std::string ToStringShort() const
Definition: transaction.cpp:13
uint32_t n
Definition: transaction.h:36
const BLSObject & Get() const
Definition: bls_wrapper.h:350
uint256 GetHash() const
Definition: block.cpp:15
Definition: block.h:80
std::vector< CTransactionRef > vtx
Definition: block.h:83
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:145
uint256 GetBlockHash() const
Definition: chain.h:215
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:113
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:72
boost::signals2::signal< void(const CDeterministicMNList &)> NotifyMasternodeListChanged
Deterministic Masternode list has changed.
Definition: guiinterface.h:111
CDeterministicMNStateCPtr pdmnState
uint64_t GetInternalId() const
void ToJson(UniValue &obj) const
bool IsPoSeBanned() const
std::string ToString() const
COutPoint collateralOutpoint
std::set< uint64_t > removedMns
std::map< uint64_t, CDeterministicMNStateDiff > updatedMNs
std::vector< CDeterministicMNCPtr > addedMNs
void DeleteUniqueProperty(const CDeterministicMNCPtr &dmn, const T &oldValue)
CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey &pubKey)
CDeterministicMNCPtr GetValidMN(const uint256 &proTxHash) const
CDeterministicMNList ApplyDiff(const CBlockIndex *pindex, const CDeterministicMNListDiff &diff) const
CDeterministicMNCPtr GetMNByService(const CService &service) const
void UpdateMN(const CDeterministicMNCPtr &oldDmn, const CDeterministicMNStateCPtr &pdmnState)
bool HasMN(const uint256 &proTxHash) const
uint32_t GetTotalRegisteredCount() const
void UpdateUniqueProperty(const CDeterministicMNCPtr &dmn, const T &oldValue, const T &newValue)
void SetBlockHash(const uint256 &_blockHash)
void AddMN(const CDeterministicMNCPtr &dmn, bool fBumpTotalCount=true)
void AddUniqueProperty(const CDeterministicMNCPtr &dmn, const T &v)
std::vector< CDeterministicMNCPtr > CalculateQuorum(size_t maxSize, const uint256 &modifier) const
Calculate a quorum based on the modifier.
int CalcMaxPoSePenalty() const
Calculates the maximum penalty which is allowed at the height of this MN list.
void PoSeDecrease(const uint256 &proTxHash)
Decrease penalty score of MN by 1.
size_t GetValidMNsCount() const
int CalcPenalty(int percent) const
Returns a the given percentage from the max penalty for this MN list.
CDeterministicMNCPtr GetMNByInternalId(uint64_t internalId) const
CDeterministicMNCPtr GetMNPayee() const
bool HasUniqueProperty(const T &v) const
std::vector< std::pair< arith_uint256, CDeterministicMNCPtr > > CalculateScores(const uint256 &modifier) const
CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint &collateralOutpoint) const
MnInternalIdMap mnInternalIdMap
const uint256 & GetBlockHash() const
CDeterministicMNListDiff BuildDiff(const CDeterministicMNList &to) const
void SetHeight(int _height)
void ForEachMN(bool onlyValid, Callback &&cb) const
void RemoveMN(const uint256 &proTxHash)
void PoSePunish(const uint256 &proTxHash, int penalty, bool debugLogs)
Punishes a MN for misbehavior.
CDeterministicMNCPtr GetMN(const uint256 &proTxHash) const
size_t GetAllMNsCount() const
CDeterministicMNCPtr GetMNByCollateral(const COutPoint &collateralOutpoint) const
CDeterministicMNCPtr GetUniquePropertyMN(const T &v) const
std::vector< CDeterministicMNCPtr > GetProjectedMNPayees(unsigned int nCount) const
Calculates the projected MN payees for the next count blocks.
CDeterministicMNList GetListForBlock(const CBlockIndex *pindex)
bool UndoBlock(const CBlock &block, const CBlockIndex *pindex)
CDeterministicMNManager(CEvoDB &_evoDb)
static const int LIST_DIFFS_CACHE_SIZE
void SetTipIndex(const CBlockIndex *pindex)
void CleanupCache(int nHeight)
static const int DISK_SNAPSHOT_PERIOD
bool ProcessBlock(const CBlock &block, const CBlockIndex *pindex, CValidationState &state, bool fJustCheck)
const CBlockIndex * tipIndex
CDeterministicMNList GetListAtChainTip()
std::vector< CDeterministicMNCPtr > GetAllQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex *pindexQuorum)
void DecreasePoSePenalties(CDeterministicMNList &mnList)
std::unordered_map< uint256, CDeterministicMNListDiff, StaticSaltedHasher > mnListDiffsCache
bool BuildNewListFromBlock(const CBlock &block, const CBlockIndex *pindexPrev, CValidationState &state, CDeterministicMNList &mnListRet, bool debugLogs)
std::unordered_map< uint256, CDeterministicMNList, StaticSaltedHasher > mnListsCache
void HandleQuorumCommitment(llmq::CFinalCommitment &qc, const CBlockIndex *pindexQuorum, CDeterministicMNList &mnList, bool debugLogs)
void ApplyToState(CDeterministicMNState &target) const
CBLSLazyPublicKey pubKeyOperator
std::string ToString() const
void ToJson(UniValue &obj) const
Definition: evodb.h:32
void Write(const K &key, const V &value)
Definition: evodb.h:69
bool Read(const K &key, V &value)
Definition: evodb.h:62
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList &oldMNList, const CDeterministicMNListDiff &diff)
void SetSpent()
Definition: masternode.h:180
int CheckAndRemove(bool forceExpiredRemoval=false)
Check all Masternodes and remove inactive. Return the total masternode count.
CMasternode * Find(const COutPoint &collateralOut)
Find an entry.
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:72
A hasher class for SHA-256.
Definition: sha256.h:13
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:484
std::string ToStringIPPort() const
Definition: netaddress.cpp:945
int64_t GetSporkValue(SporkId nSporkID)
Definition: spork.cpp:226
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:244
const int16_t nType
Definition: transaction.h:273
std::vector< CTxIn > vin
Definition: transaction.h:270
const uint256 & GetHash() const
Definition: transaction.h:301
Capture information about block/transaction validation.
Definition: validation.h:24
bool DoS(int level, bool ret=false, unsigned int chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false, const std::string &strDebugMessageIn="")
Definition: validation.h:39
std::string ToString() const
Definition: providertx.cpp:26
COutPoint collateralOutpoint
Definition: providertx.h:29
uint16_t nOperatorReward
Definition: providertx.h:35
CBLSPublicKey pubKeyOperator
Definition: providertx.h:32
CKeyID keyIDOwner
Definition: providertx.h:31
CService addr
Definition: providertx.h:30
CKeyID keyIDVoting
Definition: providertx.h:113
CScript scriptPayout
Definition: providertx.h:114
std::string ToString() const
Definition: providertx.cpp:133
uint256 proTxHash
Definition: providertx.h:110
CBLSPublicKey pubKeyOperator
Definition: providertx.h:112
uint16_t nReason
Definition: providertx.h:152
uint256 proTxHash
Definition: providertx.h:151
std::string ToString() const
Definition: providertx.cpp:180
std::string ToString() const
Definition: providertx.cpp:102
CService addr
Definition: providertx.h:81
uint256 proTxHash
Definition: providertx.h:80
CScript scriptOperatorPayout
Definition: providertx.h:82
bool setObject()
Definition: univalue.cpp:101
void clear()
Definition: univalue.cpp:15
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
unsigned int size() const
Definition: uint256.h:83
std::string ToString() const
Definition: uint256.cpp:65
bool IsNull() const
Definition: uint256.h:36
unsigned char * begin()
Definition: uint256.h:63
std::vector< bool > validMembers
CFinalCommitment commitment
bool empty() const
Definition: prevector.h:281
256-bit opaque blob.
Definition: uint256.h:138
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
std::shared_ptr< const CDeterministicMNState > CDeterministicMNStateCPtr
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
std::unique_ptr< CEvoDB > evoDb
Definition: evodb.cpp:10
if(!read_stdin(buffer))
Definition: fuzz.cpp:72
CClientUIInterface uiInterface
Definition: init.cpp:109
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
Definition: hash.h:289
@ LOCK
Definition: lockunlock.h:16
CMasternodeMan mnodeman
Masternode manager.
@ UPGRADE_V6_0
Definition: params.h:41
LLMQType
Definition: params.h:90
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
std::string EncodePublic(const CChainParams &params, const CBLSPublicKey &pk)
Definition: key_io.cpp:55
Internal SHA-256 implementation.
Definition: sha256.cpp:17
@ proTxHash
Definition: rpcevo.cpp:50
CSporkManager sporkManager
Definition: spork.cpp:29
@ SPORK_21_LEGACY_MNS_MAX_HEIGHT
Definition: sporkid.h:28
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet, bool fColdStake)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:162
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const
Returns true if the given network upgrade is active as of the given block height.
Definition: params.cpp:12
std::map< LLMQType, LLMQParams > llmqs
Definition: params.h:279
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:247
#define AssertLockHeld(cs)
Definition: sync.h:75
#define strprintf
Definition: tinyformat.h:1056
bool GetTxPayload(const std::vector< unsigned char > &payload, T &obj)
Definition: transaction.h:464
const uint256 UINT256_ZERO
constant uint256 instances
Definition: uint256.h:175
bool IsActivationHeight(int nHeight, const Consensus::Params &params, Consensus::UpgradeIndex idx)
Returns true if the given block height is the activation height for the given upgrade.
Definition: upgrades.cpp:124
CMainSignals & GetMainSignals()