diff --git a/src/flushablestorage.h b/src/flushablestorage.h index 0cba8924c7..bcaac2c5d8 100644 --- a/src/flushablestorage.h +++ b/src/flushablestorage.h @@ -32,7 +32,7 @@ static bool BytesToDbType(const TBytes& bytes, T& value) { stream >> value; // assert(stream.size() == 0); // will fail with partial key matching } - catch (std::ios_base::failure&) { + catch (const std::ios_base::failure&) { return false; } return true; @@ -475,7 +475,11 @@ class CStorageView { bool Read(const KeyType& key, ValueType& value) const { auto vKey = DbTypeToBytes(key); TBytes vValue; - return DB().Read(vKey, vValue) && BytesToDbType(vValue, value); + if (DB().Read(vKey, vValue)) { + BytesToDbType(vValue, value); + return true; + } + return false; } template bool ReadBy(const KeyType& key, ValueType& value) const { @@ -484,7 +488,7 @@ class CStorageView { // second type of 'ReadBy' (may be 'GetBy'?) template std::optional ReadBy(KeyType const & id) const { - ResultType result; + ResultType result{}; if (ReadBy(id, result)) return {result}; return {}; diff --git a/src/init.cpp b/src/init.cpp index 1ecccbbdf6..6972be45e6 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2018,15 +2018,15 @@ bool AppInitMain(InitInterfaces& interfaces) CTxDestination rewardDest; auto optMasternodeID = pcustomcsview->GetMasternodeIdByOperator(operatorId); if (optMasternodeID) { - auto nodePtr = pcustomcsview->GetMasternode(*optMasternodeID); - assert(nodePtr); // this should not happen if MN was found by operator's id + auto nodePtr = pcustomcsview->GetMasternodeV2(*optMasternodeID, chain_active_height); + assert(nodePtr); ownerDest = nodePtr->ownerType == PKHashType ? - CTxDestination(PKHash(nodePtr->ownerAuthAddress)) : - CTxDestination(WitnessV0KeyHash(nodePtr->ownerAuthAddress)); + CTxDestination(PKHash(nodePtr->ownerAuthAddress)) : + CTxDestination(WitnessV0KeyHash(nodePtr->ownerAuthAddress)); if (nodePtr->rewardAddressType != 0) { rewardDest = nodePtr->rewardAddressType == PKHashType ? - CTxDestination(PKHash(nodePtr->rewardAddress)) : - CTxDestination(WitnessV0KeyHash(nodePtr->rewardAddress)); + CTxDestination(PKHash(nodePtr->rewardAddress)) : + CTxDestination(WitnessV0KeyHash(nodePtr->rewardAddress)); } } diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index 6f43b23e61..00934ed04a 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -280,10 +280,10 @@ class ChainImpl : public Chain return pcustomcsview->CanSpend(nodeId, height); } - std::optional mnExists(const uint256 & nodeId) const override + bool mnExists(const uint256 & nodeId) const override { LOCK(cs_main); - return pcustomcsview->GetMasternode(nodeId); + return pcustomcsview->GetMasternode(nodeId).has_value(); } std::unique_ptr existTokenGuessId(const std::string & str, DCT_ID & id) const override { diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 22f10827cd..4001a52ddb 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -151,8 +151,8 @@ class Chain //! populates the values. virtual void findCoins(std::map& coins) = 0; + virtual bool mnExists(const uint256 & nodeId) const = 0; virtual bool mnCanSpend(const uint256 & nodeId, int height) const = 0; - virtual std::optional mnExists(const uint256 & nodeId) const = 0; virtual std::unique_ptr existTokenGuessId(const std::string & str, DCT_ID & id) const = 0; //! Estimate fraction of total transactions verified if blocks up to diff --git a/src/masternodes/masternodes.cpp b/src/masternodes/masternodes.cpp index f09c2decd3..6fa127b879 100644 --- a/src/masternodes/masternodes.cpp +++ b/src/masternodes/masternodes.cpp @@ -76,13 +76,8 @@ CMasternode::CMasternode() , ownerType(0) , operatorAuthAddress() , operatorType(0) - , rewardAddress() - , rewardAddressType(0) , creationHeight(0) , resignHeight(-1) - , version(-1) - , resignTx() - , banTx() { } @@ -160,14 +155,8 @@ bool operator==(CMasternode const & a, CMasternode const & b) a.ownerAuthAddress == b.ownerAuthAddress && a.operatorType == b.operatorType && a.operatorAuthAddress == b.operatorAuthAddress && - a.rewardAddress == b.rewardAddress && - a.rewardAddressType == b.rewardAddressType && a.creationHeight == b.creationHeight && - a.resignHeight == b.resignHeight && - a.version == b.version && - a.resignTx == b.resignTx && - a.banTx == b.banTx - ); + a.resignHeight == b.resignHeight); } bool operator!=(CMasternode const & a, CMasternode const & b) @@ -175,24 +164,36 @@ bool operator!=(CMasternode const & a, CMasternode const & b) return !(a == b); } -/* - * Check that given node is involved in anchor's subsystem for a given height (or smth like that) - */ -//bool IsAnchorInvolved(const uint256 & nodeId, int height) const -//{ -// /// @todo to be implemented -// return false; -//} - - +bool operator==(CMasternodeV2 const & a, CMasternodeV2 const & b) +{ + return static_cast(a) == static_cast(b) && + a.resignTx == b.resignTx && + a.rewardAddress == b.rewardAddress && + a.rewardAddressType == b.rewardAddressType; +} +bool operator!=(CMasternodeV2 const & a, CMasternodeV2 const & b) +{ + return !(a == b); +} /* * CMasternodesView */ -std::optional CMasternodesView::GetMasternode(const uint256 & id) const +std::optional CMasternodesView::GetMasternode(const uint256 & id) const { - return ReadBy(id); + return ReadBy(id); +} + +std::optional CMasternodesView::GetMasternodeV2(const uint256 & id, int height) const +{ + if (height >= Params().GetConsensus().GreatWorldHeight) { + return ReadBy(id); + } + if (auto node = GetMasternode(id)) { + return ConvertMasternode(*node); + } + return {}; } std::optional CMasternodesView::GetMasternodeIdByOperator(const CKeyID & id) const @@ -205,25 +206,69 @@ std::optional CMasternodesView::GetMasternodeIdByOwner(const CKeyID & i return ReadBy(id); } -void CMasternodesView::ForEachMasternode(std::function)> callback, uint256 const & start) +void CMasternodesView::ForEachMasternode(std::function)> callback, uint256 const & start) { - ForEach(callback, start); + ForEach(callback, start); } -void CMasternodesView::IncrementMintedBy(const uint256& nodeId) +void CMasternodesView::ForEachMasternodeV2(std::function)> callback, uint256 const & start) { - auto node = GetMasternode(nodeId); + ForEach(callback, start); +} + +void CMasternodesView::RevertMasternodesToV1(int height) +{ + std::vector> nodes; + ForEachMasternodeV2([&](const uint256& nodeId, CMasternodeV2 node) { + nodes.emplace_back(nodeId, std::move(node)); + return true; + }); + for (auto it = nodes.begin(); it != nodes.end(); it = nodes.erase(it)) { + StoreMasternode(it->first, it->second, height); + } +} + +void CMasternodesView::MigrateMasternodesToV2(int height) +{ + std::vector> nodes; + ForEachMasternode([&](const uint256& nodeId, CMasternodeV1 node) { + nodes.emplace_back(nodeId, std::move(node)); + return true; + }); + for (auto it = nodes.begin(); it != nodes.end(); it = nodes.erase(it)) { + StoreMasternode(it->first, ConvertMasternode(it->second), height); + } +} + +void CMasternodesView::StoreMasternode(const uint256& nodeId, const CMasternodeV2& node, int height) +{ + if (node.rewardAddressType == 0 && node.resignTx.IsNull()) { + // we can safety store cheaper structure + WriteBy(nodeId, static_cast(node)); + return; + } + + if (height >= Params().GetConsensus().GreatWorldHeight) { + WriteBy(nodeId, node); + } else { + WriteBy(nodeId, ConvertMasternode(node)); + } +} + +void CMasternodesView::IncrementMintedBy(const uint256& nodeId, int height) +{ + auto node = GetMasternodeV2(nodeId, height); assert(node); ++node->mintedBlocks; - WriteBy(nodeId, *node); + StoreMasternode(nodeId, *node, height); } -void CMasternodesView::DecrementMintedBy(const uint256& nodeId) +void CMasternodesView::DecrementMintedBy(const uint256& nodeId, int height) { - auto node = GetMasternode(nodeId); + auto node = GetMasternodeV2(nodeId, height); assert(node); --node->mintedBlocks; - WriteBy(nodeId, *node); + StoreMasternode(nodeId, *node, height); } std::optional > CMasternodesView::AmIOperator() const @@ -284,6 +329,7 @@ Res CMasternodesView::CreateMasternode(const uint256 & nodeId, const CMasternode return Res::Err("bad owner and|or operator address (should be P2PKH or P2WPKH only) or node with those addresses exists"); } + // we can safety store cheaper structure WriteBy(nodeId, node); WriteBy(node.ownerAuthAddress, nodeId); WriteBy(node.operatorAuthAddress, nodeId); @@ -298,10 +344,11 @@ Res CMasternodesView::CreateMasternode(const uint256 & nodeId, const CMasternode Res CMasternodesView::ResignMasternode(const uint256 & nodeId, const uint256 & txid, int height) { // auth already checked! - auto node = GetMasternode(nodeId); + auto node = GetMasternodeV2(nodeId, height); if (!node) { return Res::Err("node %s does not exists", nodeId.ToString()); } + auto state = node->GetState(height); if (height >= Params().GetConsensus().EunosPayaHeight) { if (state != CMasternode::ENABLED) { @@ -318,14 +365,14 @@ Res CMasternodesView::ResignMasternode(const uint256 & nodeId, const uint256 & t node->resignTx = txid; node->resignHeight = height; - WriteBy(nodeId, *node); + StoreMasternode(nodeId, *node, height); return Res::Ok(); } Res CMasternodesView::SetForcedRewardAddress(uint256 const & nodeId, const char rewardAddressType, CKeyID const & rewardAddress, int height) { - auto node = GetMasternode(nodeId); + auto node = GetMasternodeV2(nodeId, height); if (!node) { return Res::Err("masternode %s does not exists", nodeId.ToString()); } @@ -334,22 +381,17 @@ Res CMasternodesView::SetForcedRewardAddress(uint256 const & nodeId, const char return Res::Err("masternode %s state is not 'PRE_ENABLED' or 'ENABLED'", nodeId.ToString()); } - // If old masternode update foor new serialisatioono - if (node->version < CMasternode::VERSION0) { - node->version = CMasternode::VERSION0; - } - // Set new reward address node->rewardAddressType = rewardAddressType; node->rewardAddress = rewardAddress; - WriteBy(nodeId, *node); + StoreMasternode(nodeId, *node, height); return Res::Ok(); } Res CMasternodesView::RemForcedRewardAddress(uint256 const & nodeId, int height) { - auto node = GetMasternode(nodeId); + auto node = GetMasternodeV2(nodeId, height); if (!node) { return Res::Err("masternode %s does not exists", nodeId.ToString()); } @@ -360,14 +402,15 @@ Res CMasternodesView::RemForcedRewardAddress(uint256 const & nodeId, int height) node->rewardAddressType = 0; node->rewardAddress.SetNull(); - WriteBy(nodeId, *node); + StoreMasternode(nodeId, *node, height); return Res::Ok(); } -Res CMasternodesView::UpdateMasternode(uint256 const & nodeId, char operatorType, const CKeyID& operatorAuthAddress, int height) { +Res CMasternodesView::UpdateMasternode(uint256 const & nodeId, char operatorType, const CKeyID& operatorAuthAddress, int height) +{ // auth already checked! - auto node = GetMasternode(nodeId); + auto node = GetMasternodeV2(nodeId, height); if (!node) { return Res::Err("node %s does not exists", nodeId.ToString()); } @@ -387,8 +430,7 @@ Res CMasternodesView::UpdateMasternode(uint256 const & nodeId, char operatorType node->operatorType = operatorType; node->operatorAuthAddress = operatorAuthAddress; - // Overwrite and create new record - WriteBy(nodeId, *node); + StoreMasternode(nodeId, *node, height); WriteBy(node->operatorAuthAddress, nodeId); return Res::Ok(); diff --git a/src/masternodes/masternodes.h b/src/masternodes/masternodes.h index 5bf6849b4d..9376f2a8a3 100644 --- a/src/masternodes/masternodes.h +++ b/src/masternodes/masternodes.h @@ -59,11 +59,6 @@ class CMasternode TENYEAR = 520 }; - enum Version : int32_t { - PRE_FORT_CANNING = -1, - VERSION0 = 0, - }; - //! Minted blocks counter uint32_t mintedBlocks; @@ -75,20 +70,10 @@ class CMasternode CKeyID operatorAuthAddress; char operatorType; - //! Consensus-enforced address for operator rewards. - CKeyID rewardAddress; - char rewardAddressType{0}; - //! MN creation block height int32_t creationHeight; //! Resign height int32_t resignHeight; - //! Was used to set a ban height but is now unused - int32_t version; - - //! This fields are for transaction rollback (by disconnecting block) - uint256 resignTx; - uint256 banTx; //! empty constructor CMasternode(); @@ -114,23 +99,76 @@ class CMasternode READWRITE(creationHeight); READWRITE(resignHeight); - READWRITE(version); + } + + //! equality test + friend bool operator==(CMasternode const & a, CMasternode const & b); + friend bool operator!=(CMasternode const & a, CMasternode const & b); +}; + +// intermidate data structure for compatibility +class CMasternodeV1 : public CMasternode { +public: + //! Was used to set a ban height but is now unused + int32_t version; + + //! This fields are for transaction rollback (by disconnecting block) + uint256 resignTx; + uint256 banTx; + + CKeyID rewardAddress; + char rewardAddressType; + + ADD_SERIALIZE_METHODS; + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITEAS(CMasternode, *this); + READWRITE(version); READWRITE(resignTx); READWRITE(banTx); + READWRITE(rewardAddress); + READWRITE(rewardAddressType); + } +}; - // Only available after FortCanning - if (version > PRE_FORT_CANNING) { - READWRITE(rewardAddress); - READWRITE(rewardAddressType); - } +class CMasternodeV2 : public CMasternode { +public: + uint256 resignTx; + + CKeyID rewardAddress; + char rewardAddressType; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action) + { + READWRITEAS(CMasternode, *this); + READWRITE(resignTx); + READWRITE(rewardAddress); + READWRITE(rewardAddressType); } //! equality test - friend bool operator==(CMasternode const & a, CMasternode const & b); - friend bool operator!=(CMasternode const & a, CMasternode const & b); + friend bool operator==(CMasternodeV2 const & a, CMasternodeV2 const & b); + friend bool operator!=(CMasternodeV2 const & a, CMasternodeV2 const & b); }; +template +using masternode_t = std::conditional_t, CMasternodeV2, CMasternodeV1>; + +template> +inline Node2 ConvertMasternode(const Node1& node1) +{ + Node2 node2{}; + node2.resignTx = node1.resignTx; + node2.rewardAddress = node1.rewardAddress; + node2.rewardAddressType = node1.rewardAddressType; + static_cast(node2) = node1; + return node2; +} struct MNBlockTimeKey { @@ -178,18 +216,20 @@ struct SubNodeBlockTimeKey class CMasternodesView : public virtual CStorageView { - std::map> minterTimeCache; + void StoreMasternode(const uint256& nodeId, const CMasternodeV2& node, int height); public: -// CMasternodesView() = default; - - std::optional GetMasternode(uint256 const & id) const; - std::optional GetMasternodeIdByOperator(CKeyID const & id) const; + void RevertMasternodesToV1(int height); + void MigrateMasternodesToV2(int height); + std::optional GetMasternode(uint256 const & id) const; std::optional GetMasternodeIdByOwner(CKeyID const & id) const; - void ForEachMasternode(std::function)> callback, uint256 const & start = uint256()); + std::optional GetMasternodeIdByOperator(CKeyID const & id) const; + std::optional GetMasternodeV2(uint256 const & id, int height) const; + void ForEachMasternode(std::function)> callback, uint256 const & start = uint256()); + void ForEachMasternodeV2(std::function)> callback, uint256 const & start = uint256()); - void IncrementMintedBy(const uint256& nodeId); - void DecrementMintedBy(const uint256& nodeId); + void IncrementMintedBy(const uint256& nodeId, int height); + void DecrementMintedBy(const uint256& nodeId, int height); std::optional> AmIOperator() const; std::optional> AmIOwner() const; diff --git a/src/masternodes/mn_checks.cpp b/src/masternodes/mn_checks.cpp index cec61906ee..25649f7773 100644 --- a/src/masternodes/mn_checks.cpp +++ b/src/masternodes/mn_checks.cpp @@ -888,11 +888,6 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor node.operatorType = obj.operatorType; node.operatorAuthAddress = obj.operatorAuthAddress; - // Set masternode version2 after FC for new serialisation - if (height >= static_cast(Params().GetConsensus().FortCanningHeight)) { - node.version = CMasternode::VERSION0; - } - res = mnview.CreateMasternode(tx.GetHash(), node, obj.timelock); // Build coinage from the point of masternode creation if (res) { @@ -913,27 +908,13 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor } Res operator()(const CSetForcedRewardAddressMessage& obj) const { - auto const node = mnview.GetMasternode(obj.nodeId); - if (!node) { - return Res::Err("masternode %s does not exist", obj.nodeId.ToString()); - } - if (!HasCollateralAuth(obj.nodeId)) { - return Res::Err("%s: %s", obj.nodeId.ToString(), "tx must have at least one input from masternode owner"); - } - - return mnview.SetForcedRewardAddress(obj.nodeId, obj.rewardAddressType, obj.rewardAddress, height); + auto res = HasCollateralAuth(obj.nodeId); + return !res ? res : mnview.SetForcedRewardAddress(obj.nodeId, obj.rewardAddressType, obj.rewardAddress, height); } Res operator()(const CRemForcedRewardAddressMessage& obj) const { - auto const node = mnview.GetMasternode(obj.nodeId); - if (!node) { - return Res::Err("masternode %s does not exist", obj.nodeId.ToString()); - } - if (!HasCollateralAuth(obj.nodeId)) { - return Res::Err("%s: %s", obj.nodeId.ToString(), "tx must have at least one input from masternode owner"); - } - - return mnview.RemForcedRewardAddress(obj.nodeId, height); + auto res = HasCollateralAuth(obj.nodeId); + return !res ? res : mnview.RemForcedRewardAddress(obj.nodeId, height); } Res operator()(const CUpdateMasterNodeMessage& obj) const { diff --git a/src/masternodes/rpc_masternodes.cpp b/src/masternodes/rpc_masternodes.cpp index 6ee3754b8c..348abfbada 100644 --- a/src/masternodes/rpc_masternodes.cpp +++ b/src/masternodes/rpc_masternodes.cpp @@ -3,7 +3,7 @@ #include // Here (but not a class method) just by similarity with other '..ToJSON' -UniValue mnToJSON(uint256 const & nodeId, CMasternode const& node, bool verbose, const std::set>& mnIds, const CWallet* pwallet) +UniValue mnToJSON(uint256 const & nodeId, CMasternodeV2 const& node, bool verbose, const std::set>& mnIds, const CWallet* pwallet) { UniValue ret(UniValue::VOBJ); if (!verbose) { @@ -29,7 +29,7 @@ UniValue mnToJSON(uint256 const & nodeId, CMasternode const& node, bool verbose, obj.pushKV("creationHeight", node.creationHeight); obj.pushKV("resignHeight", node.resignHeight); obj.pushKV("resignTx", node.resignTx.GetHex()); - obj.pushKV("banTx", node.banTx.GetHex()); + obj.pushKV("banTx", uint256{}.GetHex()); obj.pushKV("state", CMasternode::GetHumanReadableState(node.GetState())); obj.pushKV("mintedBlocks", (uint64_t) node.mintedBlocks); isminetype ownerMine = IsMineCached(*pwallet, ownerDest); @@ -653,20 +653,31 @@ UniValue listmasternodes(const JSONRPCRequest& request) } } + pwallet->BlockUntilSyncedToCurrentChain(); + UniValue ret(UniValue::VOBJ); LOCK(cs_main); + auto height = ::ChainActive().Height(); const auto mnIds = pcustomcsview->GetOperatorsMulti(); - pcustomcsview->ForEachMasternode([&](uint256 const& nodeId, CMasternode node) { + + auto processNode = [&](uint256 const& nodeId, CMasternodeV2 node) { if (!including_start) { including_start = true; return (true); } ret.pushKVs(mnToJSON(nodeId, node, verbose, mnIds, pwallet)); - limit--; - return limit != 0; - }, start); + return --limit != 0; + }; + + if (height >= Params().GetConsensus().GreatWorldHeight) { + pcustomcsview->ForEachMasternodeV2(processNode, start); + } else { + pcustomcsview->ForEachMasternode([&](uint256 const& nodeId, CMasternodeV1 node) { + return processNode(nodeId, ConvertMasternode(node)); + }, start); + } return ret; } @@ -691,11 +702,13 @@ UniValue getmasternode(const JSONRPCRequest& request) uint256 id = ParseHashV(request.params[0], "masternode id"); + pwallet->BlockUntilSyncedToCurrentChain(); + LOCK(cs_main); + auto height = ::ChainActive().Height(); const auto mnIds = pcustomcsview->GetOperatorsMulti(); - auto node = pcustomcsview->GetMasternode(id); - if (node) { - return mnToJSON(id, *node, true, mnIds, pwallet); // or maybe just node, w/o id? + if (auto node = pcustomcsview->GetMasternodeV2(id, height)) { + return mnToJSON(id, *node, true, mnIds, pwallet); } throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Masternode not found"); } diff --git a/src/miner.cpp b/src/miner.cpp index ef63f7b134..dac71d7f4d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -718,8 +718,8 @@ namespace pos { } tip = ::ChainActive().Tip(); masternodeID = *optMasternodeID; - auto nodePtr = pcustomcsview->GetMasternode(masternodeID); - if (!nodePtr || !nodePtr->IsActive(tip->height)) /// @todo miner: height+1 or nHeight+1 ??? + auto nodePtr = pcustomcsview->GetMasternodeV2(masternodeID, tip->height); + if (!nodePtr && !nodePtr->IsActive(tip->height)) /// @todo miner: height+1 or nHeight+1 ??? { /// @todo may be new status for not activated (or already resigned) MN?? return Status::initWaiting; @@ -727,7 +727,7 @@ namespace pos { mintedBlocks = nodePtr->mintedBlocks; if (args.coinbaseScript.empty()) { // this is safe cause MN was found - if (tip->height >= chainparams.GetConsensus().FortCanningHeight && nodePtr->rewardAddressType != 0) { + if (nodePtr->rewardAddressType != 0) { scriptPubKey = GetScriptForDestination(nodePtr->rewardAddressType == PKHashType ? CTxDestination(PKHash(nodePtr->rewardAddress)) : CTxDestination(WitnessV0KeyHash(nodePtr->rewardAddress)) @@ -767,7 +767,7 @@ namespace pos { // Plus one to avoid time-too-old error on exact median time. nLastCoinStakeSearchTime = tip->GetMedianTimePast() + 1; } - + lastBlockSeen = tip->GetBlockHash(); } diff --git a/src/validation.cpp b/src/validation.cpp index a3fb2327fd..31d4983058 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1820,7 +1820,7 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI view.SetBestBlock(pindex->pprev->GetBlockHash()); if (!fIsFakeNet) { - mnview.DecrementMintedBy(*nodeId); + mnview.DecrementMintedBy(*nodeId, pindex->nHeight); if (pindex->nHeight >= Params().GetConsensus().EunosPayaHeight) { mnview.EraseSubNodesLastBlockTime(*nodeId, static_cast(pindex->nHeight)); } else { @@ -1829,6 +1829,14 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI } mnview.SetLastHeight(pindex->pprev->nHeight); + // one time upgrade to revert previous structure + if (pindex->nHeight == Params().GetConsensus().GreatWorldHeight) { + auto time = GetTimeMillis(); + LogPrintf("Masternode reverting ...\n"); + mnview.RevertMasternodesToV1(Params().GetConsensus().GreatWorldHeight - 1); + LogPrint(BCLog::BENCH, " - Masternode reverting took: %dms\n", GetTimeMillis() - time); + } + return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN; } @@ -2306,13 +2314,22 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl std::optional nodeId; std::optional nodePtr; + // one time upgrade to purge the old masternode data structure + // we don't neeed it in undos + if (pindex->nHeight == chainparams.GetConsensus().GreatWorldHeight) { + auto time = GetTimeMillis(); + LogPrintf("Masternode migration ...\n"); + mnview.MigrateMasternodesToV2(chainparams.GetConsensus().GreatWorldHeight); + LogPrint(BCLog::BENCH, " - Masternode migration took: %dms\n", GetTimeMillis() - time); + } + // We are forced not to check this due to the block wasn't signed yet if called by TestBlockValidity() if (!fJustCheck && !fIsFakeNet) { // Check only that mintedBlocks counter is correct (MN existence and activation was partially checked before in checkblock()->contextualcheckproofofstake(), but not in the case of fJustCheck) minterKey = pindex->minterKey(); nodeId = mnview.GetMasternodeIdByOperator(minterKey); assert(nodeId); - nodePtr = mnview.GetMasternode(*nodeId); + nodePtr = mnview.GetMasternodeV2(*nodeId, pindex->nHeight); assert(nodePtr); if (nodePtr->mintedBlocks + 1 != block.mintedBlocks) @@ -2829,7 +2846,7 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl } if (!fIsFakeNet) { - mnview.IncrementMintedBy(*nodeId); + mnview.IncrementMintedBy(*nodeId, pindex->nHeight); // Store block staker height for use in coinage if (pindex->nHeight >= static_cast(Params().GetConsensus().EunosPayaHeight)) { @@ -4558,7 +4575,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P // this is safe cause pos::ContextualCheckProofOfStake checked block.ExtractMinterKey(minter); auto nodeId = pcustomcsview->GetMasternodeIdByOperator(minter); - auto node = pcustomcsview->GetMasternode(*nodeId); + auto node = pcustomcsview->GetMasternodeV2(*nodeId, block.height); if (node->rewardAddressType != 0) { CScript rewardScriptPubKey = GetScriptForDestination(node->rewardAddressType == PKHashType ? CTxDestination(PKHash(node->rewardAddress)) :