24 static const std::string DB_LIST_SNAPSHOT =
"dmn_S";
25 static const std::string DB_LIST_DIFF =
"dmn_D";
32 std::string payoutAddress =
"unknown";
33 std::string operatorPayoutAddress =
"none";
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)",
74 assert(
internalId != std::numeric_limits<uint64_t>::max());
95 obj.
pushKV(
"dmnstate", stateObj);
118 for (
const auto& p :
mnMap) {
119 if (p.second->pdmnState->pubKeyOperator.Get() == pubKey) {
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;
167 int ah = CompareByLastPaidGetHeight(_a);
168 int bh = CompareByLastPaidGetHeight(_b);
177 return CompareByLastPaid(*_a, *_b);
182 if (
mnMap.size() == 0) {
188 if (!best || CompareByLastPaid(dmn, best)) {
202 std::vector<CDeterministicMNCPtr> result;
203 result.reserve(nCount);
206 result.emplace_back(dmn);
209 return CompareByLastPaid(a, b);
212 result.resize(nCount);
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) {
225 return a.second->collateralOutpoint < b.second->collateralOutpoint;
227 return a.first < b.first;
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);
241 std::vector<std::pair<arith_uint256, CDeterministicMNCPtr>> scores;
244 if (dmn->pdmnState->confirmedHash.IsNull()) {
255 sha256.Write(dmn->pdmnState->confirmedHashWithProRegTxHash.begin(), dmn->pdmnState->confirmedHashWithProRegTxHash.size());
257 sha256.Finalize(h.begin());
285 throw(std::runtime_error(
strprintf(
"%s: Can't find a masternode with proTxHash=%s", __func__,
proTxHash.ToString())));
290 auto newState = std::make_shared<CDeterministicMNState>(*dmn->
pdmnState);
291 newState->nPoSePenalty += penalty;
292 newState->nPoSePenalty = std::min(maxPenalty, newState->nPoSePenalty);
295 LogPrintf(
"CDeterministicMNList::%s -- punished MN %s, penalty %d->%d (max=%d)\n",
296 __func__,
proTxHash.ToString(), dmn->
pdmnState->nPoSePenalty, newState->nPoSePenalty, maxPenalty);
299 if (newState->nPoSePenalty >= maxPenalty && newState->nPoSeBanHeight == -1) {
300 newState->nPoSeBanHeight =
nHeight;
302 LogPrintf(
"CDeterministicMNList::%s -- banned MN %s at height %d\n",
313 throw(std::runtime_error(
strprintf(
"%s: Can't find a masternode with proTxHash=%s", __func__,
proTxHash.ToString())));
317 auto newState = std::make_shared<CDeterministicMNState>(*dmn->
pdmnState);
318 newState->nPoSePenalty--;
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) {
333 diffRet.
updatedMNs.emplace(toPtr->GetInternalId(), std::move(stateDiff));
338 auto toPtr = to.
GetMN(fromPtr->proTxHash);
339 if (toPtr ==
nullptr) {
340 diffRet.
removedMns.emplace(fromPtr->GetInternalId());
347 return a->GetInternalId() < b->GetInternalId();
362 throw(std::runtime_error(
strprintf(
"%s: can't find a removed masternode, id=%d", __func__,
id)));
366 for (
const auto& dmn : diff.
addedMNs) {
379 assert(dmn !=
nullptr);
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())));
385 throw(std::runtime_error(
strprintf(
"%s: can't add a duplicate masternode with the same internalId=%d", __func__, dmn->GetInternalId())));
388 throw(std::runtime_error(
strprintf(
"%s: can't add a masternode with a duplicate address %s", __func__, dmn->pdmnState->addr.ToStringIPPort())));
397 if (dmn->pdmnState->addr !=
CService()) {
403 if (fBumpTotalCount) {
411 assert(oldDmn !=
nullptr);
414 throw(std::runtime_error(
strprintf(
"%s: can't update a masternode with a duplicate address %s", __func__, oldDmn->pdmnState->addr.ToStringIPPort())));
417 auto dmn = std::make_shared<CDeterministicMN>(*oldDmn);
431 throw(std::runtime_error(
strprintf(
"%s: Can't find a masternode with proTxHash=%s", __func__,
proTxHash.ToString())));
438 assert(oldDmn !=
nullptr);
439 auto oldState = oldDmn->pdmnState;
440 auto newState = std::make_shared<CDeterministicMNState>(*oldState);
449 throw(std::runtime_error(
strprintf(
"%s: Can't find a masternode with proTxHash=%s", __func__,
proTxHash.ToString())));
503 LogPrintf(
"CDeterministicMNManager::%s -- Wrote snapshot. nHeight=%d, mapCurMNs.allMNsCount=%d\n",
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");
540 evoDb.
Read(std::make_pair(DB_LIST_DIFF, blockHash), diff);
553 auto inversedDiff = curList.
BuildDiff(prevList);
571 int nHeight = pindexPrev->
nHeight + 1;
584 if (!dmn->pdmnState->confirmedHash.IsNull()) {
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);
601 for (
int i = 1; i < (int)block.
vtx.size(); i++) {
604 if (tx.
nType == CTransaction::TxType::PROREG) {
607 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-payload");
626 if (replacedDmn !=
nullptr) {
630 newList.
RemoveMN(replacedDmn->proTxHash);
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());
638 return _state.
DoS(100,
false, REJECT_DUPLICATE,
"bad-protx-dup-IP-address");
641 return _state.
DoS(100,
false, REJECT_DUPLICATE,
"bad-protx-dup-owner-key");
644 return _state.
DoS(100,
false, REJECT_DUPLICATE,
"bad-protx-dup-operator-key");
649 auto dmnState = std::make_shared<CDeterministicMNState>(pl);
650 dmnState->nRegisteredHeight = nHeight;
653 dmnState->nPoSeBanHeight = nHeight;
655 dmn->pdmnState = dmnState;
660 LogPrintf(
"CDeterministicMNManager::%s -- MN %s added at height %d: %s\n",
664 }
else if (tx.
nType == CTransaction::TxType::PROUPSERV) {
667 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-payload");
671 return _state.
DoS(100,
false, REJECT_DUPLICATE,
"bad-protx-dup-addr");
676 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-hash");
680 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-operator-payee");
682 auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
683 newState->addr = pl.
addr;
686 if (newState->nPoSeBanHeight != -1) {
688 if (newState->pubKeyOperator.Get().IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) {
689 newState->nPoSePenalty = 0;
690 newState->nPoSeBanHeight = -1;
691 newState->nPoSeRevivedHeight = nHeight;
694 LogPrintf(
"CDeterministicMNManager::%s -- MN %s revived at height %d\n",
702 LogPrintf(
"CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
706 }
else if (tx.
nType == CTransaction::TxType::PROUPREG) {
709 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-payload");
714 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-hash");
717 return _state.
DoS(100,
false, REJECT_DUPLICATE,
"bad-protx-dup-operator-key");
719 auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
722 newState->ResetOperatorFields();
723 newState->BanIfNotBanned(nHeight);
732 LogPrintf(
"CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
736 }
else if (tx.
nType == CTransaction::TxType::PROUPREV) {
739 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-payload");
744 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-protx-hash");
746 auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
747 newState->ResetOperatorFields();
748 newState->BanIfNotBanned(nHeight);
749 newState->nRevocationReason = pl.
nReason;
754 LogPrintf(
"CDeterministicMNManager::%s -- MN %s updated at height %d: %s\n",
757 }
else if (tx.
nType == CTransaction::TxType::LLMQCOMM) {
760 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-qc-payload");
765 uint32_t quorumHeight = pl.
nHeight - (pl.
nHeight % params.dkgInterval);
766 auto quorumIndex = pindexPrev->
GetAncestor(quorumHeight);
768 return _state.
DoS(100,
false, REJECT_INVALID,
"bad-qc-quorum-hash");
779 for (
int i = 1; i < (int)block.
vtx.size(); i++) {
781 for (
const auto& in : tx.
vin) {
783 if (dmn && dmn->collateralOutpoint == in.prevout) {
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());
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);
801 mnListRet = std::move(newList);
812 for (
size_t i = 0; i < members.size(); i++) {
813 if (!mnList.
HasMN(members[i]->proTxHash)) {
828 std::vector<uint256> toDecrease;
833 if (dmn->pdmnState->nPoSePenalty > 0 && dmn->pdmnState->nPoSeBanHeight == -1) {
834 toDecrease.emplace_back(dmn->proTxHash);
838 for (
const auto&
proTxHash : toDecrease) {
853 std::list<const CBlockIndex*> listDiffIndexes;
859 snapshot = itLists->second;
871 listDiffIndexes.emplace_front(pindex);
872 pindex = pindex->
pprev;
881 std::string err =
strprintf(
"No masternode list data found for block %s at height %d. "
883 throw std::runtime_error(err);
892 listDiffIndexes.emplace_front(pindex);
893 pindex = pindex->
pprev;
896 for (
const auto& diffIndex : listDiffIndexes) {
898 if (diff.HasChanges()) {
899 snapshot = snapshot.
ApplyDiff(diffIndex, diff);
953 std::vector<uint256> toDeleteLists;
954 std::vector<uint256> toDeleteDiffs;
957 toDeleteLists.emplace_back(p.first);
962 for (
const auto& h : toDeleteLists) {
967 toDeleteDiffs.emplace_back(p.first);
970 for (
const auto& h : toDeleteDiffs) {
980 return allMns.CalculateQuorum(params.size, modifier);
arith_uint256 UintToArith256(const uint256 &a)
const CChainParams & Params()
Return the currently selected parameters.
std::string ToStringShort() const
const BLSObject & Get() const
std::vector< CTransactionRef > vtx
The block chain is a tree shaped structure starting with the genesis block at the root,...
CBlockIndex * pprev
pointer to the index of the predecessor of this block
uint256 GetBlockHash() const
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
int nHeight
height of the entry in the chain. The genesis block has height 0
const Consensus::Params & GetConsensus() const
boost::signals2::signal< void(const CDeterministicMNList &)> NotifyMasternodeListChanged
Deterministic Masternode list has changed.
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
uint32_t nTotalRegisteredCount
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)
bool LegacyMNObsolete() const
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
bool IsDIP3Enforced() const
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
CScript scriptOperatorPayout
std::string ToString() const
void ToJson(UniValue &obj) const
uint16_t nRevocationReason
void Write(const K &key, const V &value)
bool Read(const K &key, V &value)
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList &oldMNList, const CDeterministicMNListDiff &diff)
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.
A hasher class for SHA-256.
A combination of a network address (CNetAddr) and a (TCP) port.
std::string ToStringIPPort() const
int64_t GetSporkValue(SporkId nSporkID)
The basic transaction that is broadcasted on the network and contained in blocks.
const uint256 & GetHash() const
Capture information about block/transaction validation.
bool DoS(int level, bool ret=false, unsigned int chRejectCodeIn=0, std::string strRejectReasonIn="", bool corruptionIn=false, const std::string &strDebugMessageIn="")
std::string ToString() const
COutPoint collateralOutpoint
CBLSPublicKey pubKeyOperator
std::string ToString() const
CBLSPublicKey pubKeyOperator
std::string ToString() const
std::string ToString() const
CScript scriptOperatorPayout
bool pushKV(const std::string &key, const UniValue &val)
unsigned int size() const
std::string ToString() const
std::vector< bool > validMembers
CFinalCommitment commitment
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
std::shared_ptr< const CDeterministicMNState > CDeterministicMNStateCPtr
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
std::unique_ptr< CEvoDB > evoDb
CClientUIInterface uiInterface
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
CMasternodeMan mnodeman
Masternode manager.
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
std::string EncodePublic(const CChainParams ¶ms, const CBLSPublicKey &pk)
Internal SHA-256 implementation.
CSporkManager sporkManager
@ SPORK_21_LEGACY_MNS_MAX_HEIGHT
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet, bool fColdStake)
Parse a standard scriptPubKey for the destination address.
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
bool NetworkUpgradeActive(int nHeight, Consensus::UpgradeIndex idx) const
Returns true if the given network upgrade is active as of the given block height.
std::map< LLMQType, LLMQParams > llmqs
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
#define AssertLockHeld(cs)
bool GetTxPayload(const std::vector< unsigned char > &payload, T &obj)
const uint256 UINT256_ZERO
constant uint256 instances
bool IsActivationHeight(int nHeight, const Consensus::Params ¶ms, Consensus::UpgradeIndex idx)
Returns true if the given block height is the activation height for the given upgrade.
CMainSignals & GetMainSignals()