diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 8f1140fd97..0f79db6667 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -151,6 +151,15 @@ CDeterministicMNCPtr CDeterministicMNList::GetMNByCollateral(const COutPoint& co return GetUniquePropertyMN(collateralOutpoint); } +CDeterministicMNCPtr CDeterministicMNList::GetValidMNByCollateral(const COutPoint& collateralOutpoint) const +{ + auto dmn = GetMNByCollateral(collateralOutpoint); + if (dmn && !IsMNValid(dmn)) { + return nullptr; + } + return dmn; +} + static int CompareByLastPaid_GetHeight(const CDeterministicMN& dmn) { int height = dmn.pdmnState->nLastPaidHeight; @@ -826,20 +835,6 @@ CDeterministicMNList CDeterministicMNManager::GetListAtChainTip() return GetListForBlock(tipBlockHash); } -bool CDeterministicMNManager::HasValidMNCollateralAtChainTip(const COutPoint& outpoint) -{ - auto mnList = GetListAtChainTip(); - auto dmn = mnList.GetMNByCollateral(outpoint); - return dmn && mnList.IsMNValid(dmn); -} - -bool CDeterministicMNManager::HasMNCollateralAtChainTip(const COutPoint& outpoint) -{ - auto mnList = GetListAtChainTip(); - auto dmn = mnList.GetMNByCollateral(outpoint); - return dmn != nullptr; -} - bool CDeterministicMNManager::IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n) { if (tx->nVersion != 3 || tx->nType != TRANSACTION_PROVIDER_REGISTER) { diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index 48729c0b92..6a8469b117 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -289,10 +289,23 @@ public: { return GetMN(proTxHash) != nullptr; } + bool HasValidMN(const uint256& proTxHash) const + { + return GetValidMN(proTxHash) != nullptr; + } + bool HasMNByCollateral(const COutPoint& collateralOutpoint) const + { + return GetMNByCollateral(collateralOutpoint) != nullptr; + } + bool HasValidMNByCollateral(const COutPoint& collateralOutpoint) const + { + return GetValidMNByCollateral(collateralOutpoint) != nullptr; + } CDeterministicMNCPtr GetMN(const uint256& proTxHash) const; CDeterministicMNCPtr GetValidMN(const uint256& proTxHash) const; CDeterministicMNCPtr GetMNByOperatorKey(const CBLSPublicKey& pubKey); CDeterministicMNCPtr GetMNByCollateral(const COutPoint& collateralOutpoint) const; + CDeterministicMNCPtr GetValidMNByCollateral(const COutPoint& collateralOutpoint) const; CDeterministicMNCPtr GetMNPayee() const; /** @@ -479,10 +492,6 @@ public: CDeterministicMNList GetListForBlock(const uint256& blockHash); CDeterministicMNList GetListAtChainTip(); - // TODO remove after removal of old non-deterministic lists - bool HasValidMNCollateralAtChainTip(const COutPoint& outpoint); - bool HasMNCollateralAtChainTip(const COutPoint& outpoint); - // Test if given TX is a ProRegTx which also contains the collateral at index n bool IsProTxWithCollateral(const CTransactionRef& tx, uint32_t n); diff --git a/src/governance-object.cpp b/src/governance-object.cpp index 5eaba3c54e..d8694ee20e 100644 --- a/src/governance-object.cpp +++ b/src/governance-object.cpp @@ -116,14 +116,13 @@ bool CGovernanceObject::ProcessVote(CNode* pfrom, return false; } - if (!mnodeman.Has(vote.GetMasternodeOutpoint())) { + auto mnList = deterministicMNManager->GetListAtChainTip(); + + if (!mnList.HasValidMNByCollateral(vote.GetMasternodeOutpoint())) { std::ostringstream ostr; ostr << "CGovernanceObject::ProcessVote -- Masternode " << vote.GetMasternodeOutpoint().ToStringShort() << " not found"; exception = CGovernanceException(ostr.str(), GOVERNANCE_EXCEPTION_WARNING); if (cmmapOrphanVotes.Insert(vote.GetMasternodeOutpoint(), vote_time_pair_t(vote, GetAdjustedTime() + GOVERNANCE_ORPHAN_EXPIRATION_TIME))) { - if (pfrom) { - mnodeman.AskForMN(pfrom, vote.GetMasternodeOutpoint(), connman); - } LogPrintf("%s\n", ostr.str()); } else { LogPrint("gobject", "%s\n", ostr.str()); @@ -212,9 +211,11 @@ void CGovernanceObject::ClearMasternodeVotes() { LOCK(cs); + auto mnList = deterministicMNManager->GetListAtChainTip(); + vote_m_it it = mapCurrentMNVotes.begin(); while (it != mapCurrentMNVotes.end()) { - if (!mnodeman.Has(it->first)) { + if (!mnList.HasValidMNByCollateral(it->first)) { fileVotes.RemoveVotesFromMasternode(it->first); mapCurrentMNVotes.erase(it++); } else { @@ -552,9 +553,11 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast return true; } + auto mnList = deterministicMNManager->GetListAtChainTip(); + std::string strOutpoint = masternodeOutpoint.ToStringShort(); - masternode_info_t infoMn; - if (!mnodeman.GetMasternodeInfo(masternodeOutpoint, infoMn)) { + auto dmn = mnList.GetValidMNByCollateral(masternodeOutpoint); + if (!dmn) { CMasternode::CollateralStatus err = CMasternode::CheckCollateral(masternodeOutpoint, CKeyID()); if (err == CMasternode::COLLATERAL_UTXO_NOT_FOUND) { strError = "Failed to find Masternode UTXO, missing masternode=" + strOutpoint + "\n"; @@ -572,16 +575,9 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast } // Check that we have a valid MN signature - if (deterministicMNManager->IsDIP3Active()) { - if (!CheckSignature(infoMn.blsPubKeyOperator)) { - strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey id = " + infoMn.blsPubKeyOperator.ToString(); - return false; - } - } else { - if (!CheckSignature(infoMn.legacyKeyIDOperator)) { - strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey id = " + infoMn.legacyKeyIDOperator.ToString(); - return false; - } + if (!CheckSignature(dmn->pdmnState->pubKeyOperator)) { + strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.ToString(); + return false; } return true; @@ -779,7 +775,7 @@ void CGovernanceObject::UpdateSentinelVariables() { // CALCULATE MINIMUM SUPPORT LEVELS REQUIRED - int nMnCount = mnodeman.CountEnabled(); + int nMnCount = (int)deterministicMNManager->GetListAtChainTip().GetValidMNsCount(); if (nMnCount == 0) return; // CALCULATE THE MINUMUM VOTE COUNT REQUIRED FOR FULL SIGNAL @@ -812,6 +808,7 @@ void CGovernanceObject::UpdateSentinelVariables() void CGovernanceObject::CheckOrphanVotes(CConnman& connman) { int64_t nNow = GetAdjustedTime(); + auto mnList = deterministicMNManager->GetListAtChainTip(); const vote_cmm_t::list_t& listVotes = cmmapOrphanVotes.GetItemList(); vote_cmm_t::list_cit it = listVotes.begin(); while (it != listVotes.end()) { @@ -821,7 +818,7 @@ void CGovernanceObject::CheckOrphanVotes(CConnman& connman) const CGovernanceVote& vote = pairVote.first; if (pairVote.second < nNow) { fRemove = true; - } else if (!mnodeman.Has(vote.GetMasternodeOutpoint())) { + } else if (!mnList.HasValidMNByCollateral(vote.GetMasternodeOutpoint())) { ++it; continue; } diff --git a/src/governance-vote.cpp b/src/governance-vote.cpp index 64ea647973..2b80cf8367 100644 --- a/src/governance-vote.cpp +++ b/src/governance-vote.cpp @@ -256,20 +256,16 @@ bool CGovernanceVote::IsValid(bool useVotingKey) const return false; } - masternode_info_t infoMn; - if (!mnodeman.GetMasternodeInfo(masternodeOutpoint, infoMn)) { + auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(masternodeOutpoint); + if (!dmn) { LogPrint("gobject", "CGovernanceVote::IsValid -- Unknown Masternode - %s\n", masternodeOutpoint.ToStringShort()); return false; } if (useVotingKey) { - return CheckSignature(infoMn.keyIDVoting); + return CheckSignature(dmn->pdmnState->keyIDVoting); } else { - if (deterministicMNManager->IsDIP3Active()) { - return CheckSignature(infoMn.blsPubKeyOperator); - } else { - return CheckSignature(infoMn.legacyKeyIDOperator); - } + return CheckSignature(dmn->pdmnState->pubKeyOperator); } } diff --git a/src/governance.cpp b/src/governance.cpp index 496427a409..665f37debb 100644 --- a/src/governance.cpp +++ b/src/governance.cpp @@ -515,12 +515,17 @@ std::vector CGovernanceManager::GetCurrentVotes(const uint256& if (it == mapObjects.end()) return vecResult; const CGovernanceObject& govobj = it->second; - CMasternode mn; - std::map mapMasternodes; + auto mnList = deterministicMNManager->GetListAtChainTip(); + std::map mapMasternodes; if (mnCollateralOutpointFilter.IsNull()) { - mapMasternodes = mnodeman.GetFullMasternodeMap(); - } else if (mnodeman.Get(mnCollateralOutpointFilter, mn)) { - mapMasternodes[mnCollateralOutpointFilter] = mn; + mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) { + mapMasternodes.emplace(dmn->collateralOutpoint, dmn); + }); + } else { + auto dmn = mnList.GetValidMNByCollateral(mnCollateralOutpointFilter); + if (dmn) { + mapMasternodes.emplace(dmn->collateralOutpoint, dmn); + } } // Loop thru each MN collateral outpoint and get the votes for the `nParentHash` governance object @@ -1074,7 +1079,7 @@ int CGovernanceManager::RequestGovernanceObjectVotes(const std::vector& int nMaxObjRequestsPerNode = 1; size_t nProjectedVotes = 2000; if (Params().NetworkIDString() != CBaseChainParams::MAIN) { - nMaxObjRequestsPerNode = std::max(1, int(nProjectedVotes / std::max(1, mnodeman.size()))); + nMaxObjRequestsPerNode = std::max(1, int(nProjectedVotes / std::max(1, (int)deterministicMNManager->GetListAtChainTip().GetValidMNsCount()))); } { diff --git a/src/instantx.cpp b/src/instantx.cpp index db2e2cc0ea..408d3dbccf 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -245,8 +245,7 @@ void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman) int nRank; uint256 quorumModifierHash; - int nMinRequiredProtocol = std::max(MIN_INSTANTSEND_PROTO_VERSION, mnpayments.GetMinMasternodePaymentsProto()); - if (!mnodeman.GetMasternodeRank(activeMasternodeInfo.outpoint, nRank, quorumModifierHash, nLockInputHeight, nMinRequiredProtocol)) { + if (!mnodeman.GetMasternodeRank(activeMasternodeInfo.outpoint, nRank, quorumModifierHash, nLockInputHeight)) { LogPrint("instantsend", "CInstantSend::Vote -- Can't calculate rank for masternode %s\n", activeMasternodeInfo.outpoint.ToStringShort()); continue; } @@ -469,7 +468,8 @@ void CInstantSend::UpdateVotedOutpoints(const CTxLockVote& vote, CTxLockCandidat txLockCandidate.MarkOutpointAsAttacked(vote.GetOutpoint()); it2->second.MarkOutpointAsAttacked(vote.GetOutpoint()); // apply maximum PoSe ban score to this masternode i.e. PoSe-ban it instantly - mnodeman.PoSeBan(vote.GetMasternodeOutpoint()); + // TODO Call new PoSe system when it's ready + //mnodeman.PoSeBan(vote.GetMasternodeOutpoint()); // NOTE: This vote must be relayed further to let all other nodes know about such // misbehaviour of this masternode. This way they should also be able to construct // conflicting lock and PoSe-ban this masternode. @@ -1029,22 +1029,25 @@ bool CTxLockRequest::IsSimple() const bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const { - if (!mnodeman.Has(outpointMasternode)) { + auto mnList = deterministicMNManager->GetListAtChainTip(); + + if (!mnList.HasValidMNByCollateral(outpointMasternode)) { LogPrint("instantsend", "CTxLockVote::IsValid -- Unknown masternode %s\n", outpointMasternode.ToStringShort()); mnodeman.AskForMN(pnode, outpointMasternode, connman); return false; } // Verify that masternodeProTxHash belongs to the same MN referred by the collateral - // Only v13 nodes will send us locks with this field set, and only after spork15 activation + // This is a leftover from the legacy non-deterministic MN list where we used the collateral to identify MNs + // TODO eventually remove the collateral from CTxLockVote if (!masternodeProTxHash.IsNull()) { - masternode_info_t mnInfo; - if (!mnodeman.GetMasternodeInfo(masternodeProTxHash, mnInfo) || mnInfo.outpoint != outpointMasternode) { + auto dmn = mnList.GetValidMN(masternodeProTxHash); + if (!dmn || dmn->collateralOutpoint != outpointMasternode) { LogPrint("instantsend", "CTxLockVote::IsValid -- invalid masternodeProTxHash %s\n", masternodeProTxHash.ToString()); return false; } - } else if (deterministicMNManager->IsDIP3Active()) { - LogPrint("instantsend", "CTxLockVote::IsValid -- missing masternodeProTxHash while DIP3 is active\n"); + } else { + LogPrint("instantsend", "CTxLockVote::IsValid -- missing masternodeProTxHash\n"); return false; } @@ -1058,8 +1061,7 @@ bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const int nRank; uint256 expectedQuorumModifierHash; - int nMinRequiredProtocol = std::max(MIN_INSTANTSEND_PROTO_VERSION, mnpayments.GetMinMasternodePaymentsProto()); - if (!mnodeman.GetMasternodeRank(outpointMasternode, nRank, expectedQuorumModifierHash, nLockInputHeight, nMinRequiredProtocol)) { + if (!mnodeman.GetMasternodeRank(outpointMasternode, nRank, expectedQuorumModifierHash, nLockInputHeight)) { //can be caused by past versions trying to vote with an invalid protocol LogPrint("instantsend", "CTxLockVote::IsValid -- Can't calculate rank for masternode %s\n", outpointMasternode.ToStringShort()); return false; @@ -1105,83 +1107,33 @@ bool CTxLockVote::CheckSignature() const { std::string strError; - masternode_info_t infoMn; - - if (!mnodeman.GetMasternodeInfo(outpointMasternode, infoMn)) { - LogPrintf("CTxLockVote::CheckSignature -- Unknown Masternode: masternode=%s\n", outpointMasternode.ToString()); + auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(masternodeProTxHash); + if (!dmn) { + LogPrintf("CTxLockVote::CheckSignature -- Unknown Masternode: masternode=%s\n", masternodeProTxHash.ToString()); return false; } - if (deterministicMNManager->IsDIP3Active()) { - uint256 hash = GetSignatureHash(); + uint256 hash = GetSignatureHash(); - CBLSSignature sig; - sig.SetBuf(vchMasternodeSignature); - if (!sig.IsValid() || !sig.VerifyInsecure(infoMn.blsPubKeyOperator, hash)) { - LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); - return false; - } - } else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::VerifyHash(hash, infoMn.legacyKeyIDOperator, vchMasternodeSignature, strError)) { - // could be a signature in old format - std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); - if (!CMessageSigner::VerifyMessage(infoMn.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) { - // nope, not in old format either - LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); - return false; - } - } - } else { - std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); - if (!CMessageSigner::VerifyMessage(infoMn.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) { - LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError); - return false; - } + CBLSSignature sig; + sig.SetBuf(vchMasternodeSignature); + if (!sig.IsValid() || !sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator, hash)) { + LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); + return false; } - return true; } bool CTxLockVote::Sign() { - std::string strError; - if (deterministicMNManager->IsDIP3Active()) { - uint256 hash = GetSignatureHash(); + uint256 hash = GetSignatureHash(); - CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); - if (!sig.IsValid()) { - return false; - } - sig.GetBuf(vchMasternodeSignature); - } else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchMasternodeSignature)) { - LogPrintf("CTxLockVote::Sign -- SignHash() failed\n"); - return false; - } - - if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchMasternodeSignature, strError)) { - LogPrintf("CTxLockVote::Sign -- VerifyHash() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = txHash.ToString() + outpoint.ToStringShort(); - - if (!CMessageSigner::SignMessage(strMessage, vchMasternodeSignature, activeMasternodeInfo.legacyKeyOperator)) { - LogPrintf("CTxLockVote::Sign -- SignMessage() failed\n"); - return false; - } - - if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchMasternodeSignature, strMessage, strError)) { - LogPrintf("CTxLockVote::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } + CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); + if (!sig.IsValid()) { + return false; } - + sig.GetBuf(vchMasternodeSignature); return true; } diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index aca4b632b4..bbab429894 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -641,36 +641,16 @@ bool CMasternodePayments::GetBlockTxOuts(int nBlockHeight, CAmount blockReward, // Is this masternode scheduled to get paid soon? // -- Only look ahead up to 8 blocks to allow for propagation of the latest 2 blocks of votes -bool CMasternodePayments::IsScheduled(const masternode_info_t& mnInfo, int nNotBlockHeight) const +bool CMasternodePayments::IsScheduled(const CDeterministicMNCPtr& dmnIn, int nNotBlockHeight) const { LOCK(cs_mapMasternodeBlocks); - if (deterministicMNManager->IsDIP3Active()) { - auto projectedPayees = deterministicMNManager->GetListAtChainTip().GetProjectedMNPayees(8); - for (const auto &dmn : projectedPayees) { - if (dmn->collateralOutpoint == mnInfo.outpoint) { - return true; - } - } - return false; - } - - if(!masternodeSync.IsMasternodeListSynced()) return false; - - CScript mnpayee; - mnpayee = GetScriptForDestination(mnInfo.keyIDCollateralAddress); - - for(int64_t h = nCachedBlockHeight; h <= nCachedBlockHeight + 8; h++){ - if(h == nNotBlockHeight) continue; - std::vector voutMasternodePayments; - if(GetBlockTxOuts(h, 0, voutMasternodePayments)) { - for (const auto& txout : voutMasternodePayments) { - if (txout.scriptPubKey == mnpayee) - return true; - } + auto projectedPayees = deterministicMNManager->GetListAtChainTip().GetProjectedMNPayees(8); + for (const auto &dmn : projectedPayees) { + if (dmn->proTxHash == dmnIn->proTxHash) { + return true; } } - return false; } @@ -1046,7 +1026,7 @@ void CMasternodePayments::CheckBlockVotes(int nBlockHeight) voteHash.ToString()); continue; } - if (itVote->second.masternodeOutpoint == mn.second.outpoint) { + if (itVote->second.masternodeOutpoint == mn.second->collateralOutpoint) { payee = itVote->second.payee; found = true; break; @@ -1061,12 +1041,12 @@ void CMasternodePayments::CheckBlockVotes(int nBlockHeight) CBitcoinAddress address2(address1); debugStr += strprintf(" - %s - voted for %s\n", - mn.second.outpoint.ToStringShort(), address2.ToString()); + mn.second->collateralOutpoint.ToStringShort(), address2.ToString()); } else { - mapMasternodesDidNotVote.emplace(mn.second.outpoint, 0).first->second++; + mapMasternodesDidNotVote.emplace(mn.second->collateralOutpoint, 0).first->second++; debugStr += strprintf(" - %s - no vote received\n", - mn.second.outpoint.ToStringShort()); + mn.second->collateralOutpoint.ToStringShort()); } if (++i >= MNPAYMENTS_SIGNATURES_TOTAL) break; diff --git a/src/masternode-payments.h b/src/masternode-payments.h index 984551c923..9a41dae0c3 100644 --- a/src/masternode-payments.h +++ b/src/masternode-payments.h @@ -200,7 +200,7 @@ public: bool GetBlockTxOuts(int nBlockHeight, CAmount blockReward, std::vector& voutMasternodePaymentsRet) const; bool IsTransactionValid(const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const; - bool IsScheduled(const masternode_info_t& mnInfo, int nNotBlockHeight) const; + bool IsScheduled(const CDeterministicMNCPtr& dmn, int nNotBlockHeight) const; bool UpdateLastVote(const CMasternodePaymentVote& vote); diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 42bf3301b0..8ef74f5cf1 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -42,10 +42,10 @@ struct CompareLastPaidBlock struct CompareScoreMN { - bool operator()(const std::pair& t1, - const std::pair& t2) const + bool operator()(const std::pair& t1, + const std::pair& t2) const { - return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->outpoint < t2.second->outpoint); + return (t1.first != t2.first) ? (t1.first < t2.first) : (t1.second->collateralOutpoint < t2.second->collateralOutpoint); } }; @@ -127,6 +127,16 @@ void CMasternodeMan::AskForMN(CNode* pnode, const COutPoint& outpoint, CConnman& connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSEG, outpoint)); } +bool CMasternodeMan::IsValidForMixingTxes(const COutPoint& outpoint) +{ + LOCK(cs); + CMasternode* pmn = Find(outpoint); + if (!pmn) { + return false; + } + return pmn->IsValidForMixingTxes(); +} + bool CMasternodeMan::AllowMixing(const COutPoint &outpoint) { LOCK(cs); @@ -153,6 +163,16 @@ bool CMasternodeMan::DisallowMixing(const COutPoint &outpoint) return true; } +int64_t CMasternodeMan::GetLastDsq(const COutPoint& outpoint) +{ + LOCK(cs); + CMasternode* pmn = Find(outpoint); + if (!pmn) { + return 0; + } + return pmn->nLastDsq; +} + bool CMasternodeMan::PoSeBan(const COutPoint &outpoint) { LOCK(cs); @@ -237,9 +257,9 @@ void CMasternodeMan::CheckAndRemove(CConnman& connman) // ask first MNB_RECOVERY_QUORUM_TOTAL masternodes we can connect to and we haven't asked recently for(int i = 0; setRequested.size() < MNB_RECOVERY_QUORUM_TOTAL && i < (int)vecMasternodeRanks.size(); i++) { // avoid banning - if(mWeAskedForMasternodeListEntry.count(it->first) && mWeAskedForMasternodeListEntry[it->first].count(vecMasternodeRanks[i].second.addr)) continue; + if(mWeAskedForMasternodeListEntry.count(it->first) && mWeAskedForMasternodeListEntry[it->first].count(vecMasternodeRanks[i].second->pdmnState->addr)) continue; // didn't ask recently, ok to ask now - CService addr = vecMasternodeRanks[i].second.addr; + CService addr = vecMasternodeRanks[i].second->pdmnState->addr; setRequested.insert(addr); listScheduledMnbRequestConnections.push_back(std::make_pair(addr, hash)); fAskedForMnbRecovery = true; @@ -633,7 +653,7 @@ bool CMasternodeMan::Has(const COutPoint& outpoint) { LOCK(cs); if (deterministicMNManager->IsDIP3Active()) { - return deterministicMNManager->HasValidMNCollateralAtChainTip(outpoint); + return deterministicMNManager->GetListAtChainTip().HasValidMNByCollateral(outpoint); } else { return mapMasternodes.find(outpoint) != mapMasternodes.end(); } @@ -679,7 +699,7 @@ bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool f if(mnpair.second.nProtocolVersion < mnpayments.GetMinMasternodePaymentsProto()) continue; //it's in the list (up to 8 entries ahead of current block to allow propagation) -- so let's skip it - if(mnpayments.IsScheduled(mnpair.second, nBlockHeight)) continue; + //if(mnpayments.IsScheduled(mnpair.second, nBlockHeight)) continue; //it's too new, wait for a cycle if(fFilterSigTime && mnpair.second.sigTime + (nMnCount*2.6*60) > GetAdjustedTime()) continue; @@ -727,51 +747,6 @@ bool CMasternodeMan::GetNextMasternodeInQueueForPayment(int nBlockHeight, bool f return mnInfoRet.fInfoValid; } -masternode_info_t CMasternodeMan::FindRandomNotInVec(const std::vector &vecToExclude, int nProtocolVersion) -{ - LOCK(cs); - - nProtocolVersion = nProtocolVersion == -1 ? mnpayments.GetMinMasternodePaymentsProto() : nProtocolVersion; - - int nCountEnabled = CountEnabled(nProtocolVersion); - int nCountNotExcluded = nCountEnabled - vecToExclude.size(); - - LogPrintf("CMasternodeMan::FindRandomNotInVec -- %d enabled masternodes, %d masternodes to choose from\n", nCountEnabled, nCountNotExcluded); - if(nCountNotExcluded < 1) return masternode_info_t(); - - // fill a vector of pointers - std::vector vpMasternodesShuffled; - for (const auto& mnpair : mapMasternodes) { - vpMasternodesShuffled.push_back(&mnpair.second); - } - - FastRandomContext insecure_rand; - // shuffle pointers - std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), insecure_rand); - bool fExclude; - - // loop through - for (const auto& pmn : vpMasternodesShuffled) { - if(pmn->nProtocolVersion < nProtocolVersion || !pmn->IsEnabled()) continue; - fExclude = false; - for (const auto& outpointToExclude : vecToExclude) { - if(pmn->outpoint == outpointToExclude) { - fExclude = true; - break; - } - } - if(fExclude) continue; - if (deterministicMNManager->IsDIP3Active() && !deterministicMNManager->HasValidMNCollateralAtChainTip(pmn->outpoint)) - continue; - // found the one not in vecToExclude - LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec -- found, masternode=%s\n", pmn->outpoint.ToStringShort()); - return pmn->GetInfo(); - } - - LogPrint("masternode", "CMasternodeMan::FindRandomNotInVec -- failed\n"); - return masternode_info_t(); -} - std::map CMasternodeMan::GetFullMasternodeMap() { LOCK(cs); @@ -791,33 +766,18 @@ std::map CMasternodeMan::GetFullMasternodeMap() } } -bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeMan::score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol) +bool CMasternodeMan::GetMasternodeScores(const uint256& nBlockHash, CMasternodeMan::score_pair_vec_t& vecMasternodeScoresRet) { AssertLockHeld(cs); vecMasternodeScoresRet.clear(); - if (deterministicMNManager->IsDIP3Active()) { - auto mnList = deterministicMNManager->GetListAtChainTip(); - auto scores = mnList.CalculateScores(nBlockHash); - for (const auto& p : scores) { - auto* mn = Find(p.second->collateralOutpoint); - vecMasternodeScoresRet.emplace_back(p.first, mn); - } - } else { - if (!masternodeSync.IsMasternodeListSynced()) - return false; - - if (mapMasternodes.empty()) - return false; - - // calculate scores - for (const auto& mnpair : mapMasternodes) { - if (mnpair.second.nProtocolVersion >= nMinProtocol) { - vecMasternodeScoresRet.push_back(std::make_pair(mnpair.second.CalculateScore(nBlockHash), &mnpair.second)); - } - } + auto mnList = deterministicMNManager->GetListAtChainTip(); + auto scores = mnList.CalculateScores(nBlockHash); + for (const auto& p : scores) { + vecMasternodeScoresRet.emplace_back(p.first, p.second); } + sort(vecMasternodeScoresRet.rbegin(), vecMasternodeScoresRet.rend(), CompareScoreMN()); return !vecMasternodeScoresRet.empty(); } @@ -845,13 +805,13 @@ bool CMasternodeMan::GetMasternodeRank(const COutPoint& outpoint, int& nRankRet, LOCK(cs); score_pair_vec_t vecMasternodeScores; - if (!GetMasternodeScores(blockHashRet, vecMasternodeScores, nMinProtocol)) + if (!GetMasternodeScores(blockHashRet, vecMasternodeScores)) return false; int nRank = 0; for (const auto& scorePair : vecMasternodeScores) { nRank++; - if(scorePair.second->outpoint == outpoint) { + if(scorePair.second->collateralOutpoint == outpoint) { nRankRet = nRank; return true; } @@ -877,13 +837,13 @@ bool CMasternodeMan::GetMasternodeRanks(CMasternodeMan::rank_pair_vec_t& vecMast LOCK(cs); score_pair_vec_t vecMasternodeScores; - if (!GetMasternodeScores(nBlockHash, vecMasternodeScores, nMinProtocol)) + if (!GetMasternodeScores(nBlockHash, vecMasternodeScores)) return false; int nRank = 0; for (const auto& scorePair : vecMasternodeScores) { nRank++; - vecMasternodeRanksRet.push_back(std::make_pair(nRank, *scorePair.second)); + vecMasternodeRanksRet.push_back(std::make_pair(nRank, scorePair.second)); } return true; @@ -891,17 +851,17 @@ bool CMasternodeMan::GetMasternodeRanks(CMasternodeMan::rank_pair_vec_t& vecMast void CMasternodeMan::ProcessMasternodeConnections(CConnman& connman) { - std::vector vecMnInfo; // will be empty when no wallet + std::vector vecDmns; // will be empty when no wallet #ifdef ENABLE_WALLET - privateSendClient.GetMixingMasternodesInfo(vecMnInfo); + privateSendClient.GetMixingMasternodesInfo(vecDmns); #endif // ENABLE_WALLET - connman.ForEachNode(CConnman::AllNodes, [&vecMnInfo](CNode* pnode) { + connman.ForEachNode(CConnman::AllNodes, [&](CNode* pnode) { if (pnode->fMasternode) { #ifdef ENABLE_WALLET bool fFound = false; - for (const auto& mnInfo : vecMnInfo) { - if (pnode->addr == mnInfo.addr) { + for (const auto& dmn : vecDmns) { + if (pnode->addr == dmn->pdmnState->addr) { fFound = true; break; } @@ -1213,7 +1173,7 @@ void CMasternodeMan::DoFullVerificationStep(CConnman& connman) (int)MAX_POSE_RANK); return; } - if(rankPair.second.outpoint == activeMasternodeInfo.outpoint) { + if(rankPair.second->collateralOutpoint == activeMasternodeInfo.outpoint) { nMyRank = rankPair.first; LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Found self at rank %d/%d, verifying up to %d masternodes\n", nMyRank, nRanksTotal, (int)MAX_POSE_CONNECTIONS); @@ -1231,20 +1191,20 @@ void CMasternodeMan::DoFullVerificationStep(CConnman& connman) auto it = vecMasternodeRanks.begin() + nOffset; while(it != vecMasternodeRanks.end()) { - if(it->second.IsPoSeVerified() || it->second.IsPoSeBanned()) { - LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Already %s%s%s masternode %s address %s, skipping...\n", - it->second.IsPoSeVerified() ? "verified" : "", - it->second.IsPoSeVerified() && it->second.IsPoSeBanned() ? " and " : "", - it->second.IsPoSeBanned() ? "banned" : "", - it->second.outpoint.ToStringShort(), it->second.addr.ToString()); - nOffset += MAX_POSE_CONNECTIONS; - if(nOffset >= (int)vecMasternodeRanks.size()) break; - it += MAX_POSE_CONNECTIONS; - continue; - } +// if(it->second.IsPoSeVerified() || it->second.IsPoSeBanned()) { +// LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Already %s%s%s masternode %s address %s, skipping...\n", +// it->second.IsPoSeVerified() ? "verified" : "", +// it->second.IsPoSeVerified() && it->second.IsPoSeBanned() ? " and " : "", +// it->second.IsPoSeBanned() ? "banned" : "", +// it->second.outpoint.ToStringShort(), it->second.addr.ToString()); +// nOffset += MAX_POSE_CONNECTIONS; +// if(nOffset >= (int)vecMasternodeRanks.size()) break; +// it += MAX_POSE_CONNECTIONS; +// continue; +// } LogPrint("masternode", "CMasternodeMan::DoFullVerificationStep -- Verifying masternode %s rank %d/%d address %s\n", - it->second.outpoint.ToStringShort(), it->first, nRanksTotal, it->second.addr.ToString()); - CAddress addr = CAddress(it->second.addr, NODE_NETWORK); + it->second->collateralOutpoint.ToStringShort(), it->first, nRanksTotal, it->second->pdmnState->addr.ToString()); + CAddress addr = CAddress(it->second->pdmnState->addr, NODE_NETWORK); if(CheckVerifyRequestAddr(addr, connman)) { vAddr.push_back(addr); if((int)vAddr.size() >= MAX_POSE_CONNECTIONS) break; diff --git a/src/masternodeman.h b/src/masternodeman.h index 853fed8683..aa30b2e4fc 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -8,6 +8,8 @@ #include "masternode.h" #include "sync.h" +#include "evo/deterministicmns.h" + class CMasternodeMan; class CConnman; @@ -16,9 +18,9 @@ extern CMasternodeMan mnodeman; class CMasternodeMan { public: - typedef std::pair score_pair_t; + typedef std::pair score_pair_t; typedef std::vector score_pair_vec_t; - typedef std::pair rank_pair_t; + typedef std::pair rank_pair_t; typedef std::vector rank_pair_vec_t; private: @@ -80,7 +82,7 @@ private: /// Find an entry CMasternode* Find(const COutPoint& outpoint); - bool GetMasternodeScores(const uint256& nBlockHash, score_pair_vec_t& vecMasternodeScoresRet, int nMinProtocol = 0); + bool GetMasternodeScores(const uint256& nBlockHash, score_pair_vec_t& vecMasternodeScoresRet); void SyncSingle(CNode* pnode, const COutPoint& outpoint, CConnman& connman); void SyncAll(CNode* pnode, CConnman& connman); @@ -137,8 +139,10 @@ public: void AskForMN(CNode *pnode, const COutPoint& outpoint, CConnman& connman); bool PoSeBan(const COutPoint &outpoint); + bool IsValidForMixingTxes(const COutPoint &outpoint); bool AllowMixing(const COutPoint &outpoint); bool DisallowMixing(const COutPoint &outpoint); + int64_t GetLastDsq(const COutPoint &outpoint); /// Check all Masternodes void Check(); @@ -180,9 +184,6 @@ public: /// Same as above but use current block height bool GetNextMasternodeInQueueForPayment(bool fFilterSigTime, int& nCountRet, masternode_info_t& mnInfoRet); - /// Find a random entry - masternode_info_t FindRandomNotInVec(const std::vector &vecToExclude, int nProtocolVersion = -1); - std::map GetFullMasternodeMap(); bool GetMasternodeRanks(rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight = -1, int nMinProtocol = 0); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 699a3244dc..57e2d445a8 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2079,21 +2079,20 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; // not an error } - CMasternode mn; - - if(!mnodeman.Get(dstx.masternodeOutpoint, mn)) { + auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(dstx.masternodeOutpoint); + if(!dmn) { LogPrint("privatesend", "DSTX -- Can't find masternode %s to verify %s\n", dstx.masternodeOutpoint.ToStringShort(), hashTx.ToString()); return false; } - if(!mn.IsValidForMixingTxes()) { + if(!mnodeman.IsValidForMixingTxes(dstx.masternodeOutpoint)) { LogPrint("privatesend", "DSTX -- Masternode %s is sending too many transactions %s\n", dstx.masternodeOutpoint.ToStringShort(), hashTx.ToString()); return true; // TODO: Not an error? Could it be that someone is relaying old DSTXes // we have no idea about (e.g we were offline)? How to handle them? } - if (!dstx.CheckSignature(mn.legacyKeyIDOperator, mn.blsPubKeyOperator)) { + if (!dstx.CheckSignature(dmn->pdmnState->pubKeyOperator)) { LogPrint("privatesend", "DSTX -- CheckSignature() failed for %s\n", hashTx.ToString()); return false; } diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 13b43e97f8..5088cda586 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -61,12 +61,13 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& if (dsq.IsExpired()) return; - masternode_info_t infoMn; - if (!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, infoMn)) return; + auto mnList = deterministicMNManager->GetListAtChainTip(); + auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint); + if (!dmn) return; - if (!dsq.CheckSignature(infoMn.legacyKeyIDOperator, infoMn.blsPubKeyOperator)) { - // we probably have outdated info - mnodeman.AskForMN(pfrom, dsq.masternodeOutpoint, connman); + if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator)) { + LOCK(cs_main); + Misbehaving(pfrom->id, 10); return; } @@ -74,9 +75,9 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& if (dsq.fReady) { LOCK(cs_deqsessions); for (auto& session : deqSessions) { - masternode_info_t mnMixing; - if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing.addr == infoMn.addr && session.GetState() == POOL_STATE_QUEUE) { - LogPrint("privatesend", "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), infoMn.addr.ToString()); + CDeterministicMNCPtr mnMixing; + if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->pdmnState->addr == dmn->pdmnState->addr && session.GetState() == POOL_STATE_QUEUE) { + LogPrint("privatesend", "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); session.SubmitDenominate(connman); return; } @@ -89,25 +90,26 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& for (const auto& q : vecPrivateSendQueue) { if (q.masternodeOutpoint == dsq.masternodeOutpoint) { // no way same mn can send another "not yet ready" dsq this soon - LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", infoMn.addr.ToString()); + LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", dmn->pdmnState->ToString()); return; } } - int nThreshold = infoMn.nLastDsq + mnodeman.CountMasternodes() / 5; - LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", infoMn.nLastDsq, nThreshold, mnodeman.nDsqCount); + int64_t nLastDsq = mnodeman.GetLastDsq(dsq.masternodeOutpoint); + int nThreshold = nLastDsq + mnList.GetValidMNsCount() / 5; + LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", nLastDsq, nThreshold, mnodeman.nDsqCount); //don't allow a few nodes to dominate the queuing process - if (infoMn.nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) { - LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", infoMn.addr.ToString()); + if (nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) { + LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->proTxHash.ToString()); return; } if (!mnodeman.AllowMixing(dsq.masternodeOutpoint)) return; - LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), infoMn.addr.ToString()); + LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); for (auto& session : deqSessions) { - masternode_info_t mnMixing; - if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing.outpoint == dsq.masternodeOutpoint) { + CDeterministicMNCPtr mnMixing; + if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->collateralOutpoint == dsq.masternodeOutpoint) { dsq.fTried = true; } } @@ -139,8 +141,8 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string& return; } - if (!infoMixingMasternode.fInfoValid) return; - if (infoMixingMasternode.addr != pfrom->addr) { + if (!mixingMasternode) return; + if (mixingMasternode->pdmnState->addr != pfrom->addr) { //LogPrintf("DSSTATUSUPDATE -- message doesn't match current Masternode: infoMixingMasternode %s addr %s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString()); return; } @@ -181,8 +183,8 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string& return; } - if (!infoMixingMasternode.fInfoValid) return; - if (infoMixingMasternode.addr != pfrom->addr) { + if (!mixingMasternode) return; + if (mixingMasternode->pdmnState->addr != pfrom->addr) { //LogPrintf("DSFINALTX -- message doesn't match current Masternode: infoMixingMasternode %s addr %s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString()); return; } @@ -208,9 +210,9 @@ void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string& return; } - if (!infoMixingMasternode.fInfoValid) return; - if (infoMixingMasternode.addr != pfrom->addr) { - LogPrint("privatesend", "DSCOMPLETE -- message doesn't match current Masternode: infoMixingMasternode=%s addr=%s\n", infoMixingMasternode.addr.ToString(), pfrom->addr.ToString()); + if (!mixingMasternode) return; + if (mixingMasternode->pdmnState->addr != pfrom->addr) { + LogPrint("privatesend", "DSCOMPLETE -- message doesn't match current Masternode: infoMixingMasternode=%s addr=%s\n", mixingMasternode->pdmnState->addr.ToString(), pfrom->addr.ToString()); return; } @@ -258,7 +260,7 @@ void CPrivateSendClientSession::SetNull() // Client side nEntriesCount = 0; fLastEntryAccepted = false; - infoMixingMasternode = masternode_info_t(); + mixingMasternode = nullptr; pendingDsaRequest = CPendingDsaRequest(); CPrivateSendBaseSession::SetNull(); @@ -368,22 +370,22 @@ std::string CPrivateSendClientManager::GetSessionDenoms() return strSessionDenoms.empty() ? "N/A" : strSessionDenoms; } -bool CPrivateSendClientSession::GetMixingMasternodeInfo(masternode_info_t& mnInfoRet) const +bool CPrivateSendClientSession::GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const { - mnInfoRet = infoMixingMasternode.fInfoValid ? infoMixingMasternode : masternode_info_t(); - return infoMixingMasternode.fInfoValid; + ret = mixingMasternode; + return ret != nullptr; } -bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vector& vecMnInfoRet) const +bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vector& vecDmnsRet) const { LOCK(cs_deqsessions); for (const auto& session : deqSessions) { - masternode_info_t mnInfo; - if (session.GetMixingMasternodeInfo(mnInfo)) { - vecMnInfoRet.push_back(mnInfo); + CDeterministicMNCPtr dmn; + if (session.GetMixingMasternodeInfo(dmn)) { + vecDmnsRet.push_back(dmn); } } - return !vecMnInfoRet.empty(); + return !vecDmnsRet.empty(); } // @@ -578,7 +580,7 @@ bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTr if (!pwalletMain) return false; if (fMasternodeMode || pnode == nullptr) return false; - if (!infoMixingMasternode.fInfoValid) return false; + if (!mixingMasternode) return false; finalMutableTransaction = finalTransactionNew; LogPrintf("CPrivateSendClientSession::SignFinalTransaction -- finalMutableTransaction=%s", finalMutableTransaction.ToString()); @@ -588,7 +590,7 @@ bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTr sort(finalMutableTransaction.vout.begin(), finalMutableTransaction.vout.end(), CompareOutputBIP69()); if (finalMutableTransaction.GetHash() != finalTransactionNew.GetHash()) { - LogPrintf("CPrivateSendClientSession::SignFinalTransaction -- WARNING! Masternode %s is not BIP69 compliant!\n", infoMixingMasternode.outpoint.ToStringShort()); + LogPrintf("CPrivateSendClientSession::SignFinalTransaction -- WARNING! Masternode %s is not BIP69 compliant!\n", mixingMasternode->proTxHash.ToString()); UnlockCoins(); keyHolderStorage.ReturnAll(); SetNull(); @@ -832,7 +834,7 @@ bool CPrivateSendClientSession::DoAutomaticDenominating(CConnman& connman, bool return false; } - if (mnodeman.size() == 0) { + if (deterministicMNManager->GetListAtChainTip().GetValidMNsCount() == 0) { LogPrint("privatesend", "CPrivateSendClientSession::DoAutomaticDenominating -- No Masternodes detected\n"); strAutoDenomResult = _("No Masternodes detected."); return false; @@ -952,7 +954,7 @@ bool CPrivateSendClientManager::DoAutomaticDenominating(CConnman& connman, bool return false; } - int nMnCountEnabled = mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION); + int nMnCountEnabled = deterministicMNManager->GetListAtChainTip().GetValidMNsCount(); // If we've used 90% of the Masternode list then drop the oldest first ~30% int nThreshold_high = nMnCountEnabled * 0.9; @@ -990,31 +992,65 @@ void CPrivateSendClientManager::AddUsedMasternode(const COutPoint& outpointMn) vecMasternodesUsed.push_back(outpointMn); } -masternode_info_t CPrivateSendClientManager::GetNotUsedMasternode() +CDeterministicMNCPtr CPrivateSendClientManager::GetRandomNotUsedMasternode() { - return mnodeman.FindRandomNotInVec(vecMasternodesUsed, MIN_PRIVATESEND_PEER_PROTO_VERSION); + auto mnList = deterministicMNManager->GetListAtChainTip(); + + int nCountEnabled = mnList.GetValidMNsCount(); + int nCountNotExcluded = nCountEnabled - vecMasternodesUsed.size(); + + LogPrintf("CPrivateSendClientManager::%s -- %d enabled masternodes, %d masternodes to choose from\n", __func__, nCountEnabled, nCountNotExcluded); + if(nCountNotExcluded < 1) { + return nullptr; + } + + // fill a vector + std::vector vpMasternodesShuffled; + vpMasternodesShuffled.reserve((size_t)nCountEnabled); + mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) { + vpMasternodesShuffled.emplace_back(dmn); + }); + + FastRandomContext insecure_rand; + // shuffle pointers + std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), insecure_rand); + + std::set excludeSet(vecMasternodesUsed.begin(), vecMasternodesUsed.end()); + + // loop through + for (const auto& dmn : vpMasternodesShuffled) { + if (excludeSet.count(dmn->collateralOutpoint)) { + continue; + } + + LogPrint("masternode", "CPrivateSendClientManager::%s -- found, masternode=%s\n", __func__, dmn->collateralOutpoint.ToStringShort()); + return dmn; + } + + LogPrint("masternode", "CPrivateSendClientManager::%s -- failed\n", __func__); + return nullptr; } bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman) { if (!pwalletMain) return false; + auto mnList = deterministicMNManager->GetListAtChainTip(); + std::vector vecStandardDenoms = CPrivateSend::GetStandardDenominations(); // Look through the queues and see if anything matches CPrivateSendQueue dsq; while (privateSendClient.GetQueueItemAndTry(dsq)) { - masternode_info_t infoMn; + auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint); - if (!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, infoMn)) { + if (!dmn) { LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- dsq masternode is not in masternode list, masternode=%s\n", dsq.masternodeOutpoint.ToStringShort()); continue; } - if (infoMn.nProtocolVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) continue; - // skip next mn payments winners - if (mnpayments.IsScheduled(infoMn, 0)) { - LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping winner, masternode=%s\n", infoMn.outpoint.ToStringShort()); + if (mnpayments.IsScheduled(dmn, 0)) { + LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping winner, masternode=%s\n", dmn->proTxHash.ToString()); continue; } @@ -1042,20 +1078,20 @@ bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymize privateSendClient.AddUsedMasternode(dsq.masternodeOutpoint); - if (connman.IsMasternodeOrDisconnectRequested(infoMn.addr)) { - LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString()); + if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) { + LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString()); continue; } nSessionDenom = dsq.nDenom; - infoMixingMasternode = infoMn; - pendingDsaRequest = CPendingDsaRequest(infoMn.addr, CPrivateSendAccept(nSessionDenom, txMyCollateral)); - connman.AddPendingMasternode(infoMn.addr); + mixingMasternode = dmn; + pendingDsaRequest = CPendingDsaRequest(dmn->pdmnState->addr, CPrivateSendAccept(nSessionDenom, txMyCollateral)); + connman.AddPendingMasternode(dmn->pdmnState->addr); // TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION SetState(POOL_STATE_QUEUE); nTimeLastSuccessfulStep = GetTime(); LogPrintf("CPrivateSendClientSession::JoinExistingQueue -- pending connection (from queue): nSessionDenom: %d (%s), addr=%s\n", - nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), infoMn.addr.ToString()); + nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), dmn->pdmnState->addr.ToString()); strAutoDenomResult = _("Trying to connect..."); return true; } @@ -1068,7 +1104,7 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nValueMin, CAmount nBalanc if (!pwalletMain) return false; int nTries = 0; - int nMnCount = mnodeman.CountMasternodes(); + int nMnCount = deterministicMNManager->GetListAtChainTip().GetValidMNsCount(); // ** find the coins we'll use std::vector vecTxIn; @@ -1082,39 +1118,40 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nValueMin, CAmount nBalanc // otherwise, try one randomly while (nTries < 10) { - masternode_info_t infoMn = privateSendClient.GetNotUsedMasternode(); + auto dmn = privateSendClient.GetRandomNotUsedMasternode(); - if (!infoMn.fInfoValid) { + if (!dmn) { LogPrintf("CPrivateSendClientSession::StartNewQueue -- Can't find random masternode!\n"); strAutoDenomResult = _("Can't find random Masternode."); return false; } - privateSendClient.AddUsedMasternode(infoMn.outpoint); + privateSendClient.AddUsedMasternode(dmn->collateralOutpoint); // skip next mn payments winners - if (mnpayments.IsScheduled(infoMn, 0)) { - LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping winner, masternode=%s\n", infoMn.outpoint.ToStringShort()); + if (mnpayments.IsScheduled(dmn, 0)) { + LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping winner, masternode=%s\n", dmn->proTxHash.ToString()); nTries++; continue; } - if (infoMn.nLastDsq != 0 && infoMn.nLastDsq + nMnCount / 5 > mnodeman.nDsqCount) { + int64_t nLastDsq = mnodeman.GetLastDsq(dmn->collateralOutpoint); + if (nLastDsq != 0 && nLastDsq + nMnCount / 5 > mnodeman.nDsqCount) { LogPrintf("CPrivateSendClientSession::StartNewQueue -- Too early to mix on this masternode!" " masternode=%s addr=%s nLastDsq=%d CountEnabled/5=%d nDsqCount=%d\n", - infoMn.outpoint.ToStringShort(), infoMn.addr.ToString(), infoMn.nLastDsq, + dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToString(), nLastDsq, nMnCount / 5, mnodeman.nDsqCount); nTries++; continue; } - if (connman.IsMasternodeOrDisconnectRequested(infoMn.addr)) { - LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping masternode connection, addr=%s\n", infoMn.addr.ToString()); + if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) { + LogPrintf("CPrivateSendClientSession::StartNewQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString()); nTries++; continue; } - LogPrintf("CPrivateSendClientSession::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, infoMn.addr.ToString()); + LogPrintf("CPrivateSendClientSession::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, dmn->pdmnState->addr.ToString()); std::vector vecAmounts; pwalletMain->ConvertList(vecTxIn, vecAmounts); @@ -1123,14 +1160,14 @@ bool CPrivateSendClientSession::StartNewQueue(CAmount nValueMin, CAmount nBalanc nSessionDenom = CPrivateSend::GetDenominationsByAmounts(vecAmounts); } - infoMixingMasternode = infoMn; - connman.AddPendingMasternode(infoMn.addr); - pendingDsaRequest = CPendingDsaRequest(infoMn.addr, CPrivateSendAccept(nSessionDenom, txMyCollateral)); + mixingMasternode = dmn; + connman.AddPendingMasternode(dmn->pdmnState->addr); + pendingDsaRequest = CPendingDsaRequest(dmn->pdmnState->addr, CPrivateSendAccept(nSessionDenom, txMyCollateral)); // TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION SetState(POOL_STATE_QUEUE); nTimeLastSuccessfulStep = GetTime(); LogPrintf("CPrivateSendClientSession::StartNewQueue -- pending connection, nSessionDenom: %d (%s), addr=%s\n", - nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), infoMn.addr.ToString()); + nSessionDenom, CPrivateSend::GetDenominationsToString(nSessionDenom), dmn->pdmnState->addr.ToString()); strAutoDenomResult = _("Trying to connect..."); return true; } @@ -1596,9 +1633,9 @@ bool CPrivateSendClientSession::CreateDenominated(const CompactTallyItem& tallyI void CPrivateSendClientSession::RelayIn(const CPrivateSendEntry& entry, CConnman& connman) { - if (!infoMixingMasternode.fInfoValid) return; + if (!mixingMasternode) return; - connman.ForNode(infoMixingMasternode.addr, [&entry, &connman](CNode* pnode) { + connman.ForNode(mixingMasternode->pdmnState->addr, [&entry, &connman](CNode* pnode) { LogPrintf("CPrivateSendClientSession::RelayIn -- found master, relaying message to %s\n", pnode->addr.ToString()); CNetMsgMaker msgMaker(pnode->GetSendVersion()); connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSVIN, entry)); diff --git a/src/privatesend-client.h b/src/privatesend-client.h index aec8a97d3d..1ab1b31c15 100644 --- a/src/privatesend-client.h +++ b/src/privatesend-client.h @@ -10,8 +10,11 @@ #include "privatesend.h" #include "wallet/wallet.h" +#include "evo/deterministicmns.h" + class CPrivateSendClientManager; class CConnman; +class CNode; static const int DENOMS_COUNT_MAX = 100; @@ -92,7 +95,7 @@ private: std::string strLastMessage; std::string strAutoDenomResult; - masternode_info_t infoMixingMasternode; + CDeterministicMNCPtr mixingMasternode; CMutableTransaction txMyCollateral; // client side collateral CPendingDsaRequest pendingDsaRequest; @@ -139,7 +142,7 @@ public: fLastEntryAccepted(false), strLastMessage(), strAutoDenomResult(), - infoMixingMasternode(), + mixingMasternode(), txMyCollateral(), pendingDsaRequest(), keyHolderStorage() @@ -154,7 +157,7 @@ public: std::string GetStatus(bool fWaitForBlock); - bool GetMixingMasternodeInfo(masternode_info_t& mnInfoRet) const; + bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const; /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false); @@ -235,7 +238,7 @@ public: std::string GetStatuses(); std::string GetSessionDenoms(); - bool GetMixingMasternodesInfo(std::vector& vecMnInfoRet) const; + bool GetMixingMasternodesInfo(std::vector& vecDmnsRet) const; /// Passively run mixing in the background according to the configuration in settings bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false); @@ -245,7 +248,7 @@ public: void ProcessPendingDsaRequest(CConnman& connman); void AddUsedMasternode(const COutPoint& outpointMn); - masternode_info_t GetNotUsedMasternode(); + CDeterministicMNCPtr GetRandomNotUsedMasternode(); void UpdatedSuccessBlock(); diff --git a/src/privatesend-server.cpp b/src/privatesend-server.cpp index 57f8267f67..c30da8e420 100644 --- a/src/privatesend-server.cpp +++ b/src/privatesend-server.cpp @@ -10,6 +10,7 @@ #include "init.h" #include "masternode-sync.h" #include "masternodeman.h" +#include "net_processing.h" #include "netmessagemaker.h" #include "script/interpreter.h" #include "txmempool.h" @@ -44,8 +45,9 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm LogPrint("privatesend", "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CPrivateSend::GetDenominationsToString(dsa.nDenom), dsa.txCollateral.ToString()); - masternode_info_t mnInfo; - if (!mnodeman.GetMasternodeInfo(activeMasternodeInfo.outpoint, mnInfo)) { + auto mnList = deterministicMNManager->GetListAtChainTip(); + auto dmn = mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint); + if (!dmn) { PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman); return; } @@ -65,7 +67,8 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm } } - if (mnInfo.nLastDsq != 0 && mnInfo.nLastDsq + mnodeman.CountMasternodes() / 5 > mnodeman.nDsqCount) { + int64_t nLastDsq = mnodeman.GetLastDsq(dmn->collateralOutpoint); + if (nLastDsq != 0 && nLastDsq + mnList.GetValidMNsCount() / 5 > mnodeman.nDsqCount) { LogPrintf("DSACCEPT -- last dsq too recent, must wait: addr=%s\n", pfrom->addr.ToString()); PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman); return; @@ -111,12 +114,13 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm if (dsq.IsExpired()) return; - masternode_info_t mnInfo; - if (!mnodeman.GetMasternodeInfo(dsq.masternodeOutpoint, mnInfo)) return; + auto mnList = deterministicMNManager->GetListAtChainTip(); + auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint); + if (!dmn) return; - if (!dsq.CheckSignature(mnInfo.legacyKeyIDOperator, mnInfo.blsPubKeyOperator)) { - // we probably have outdated info - mnodeman.AskForMN(pfrom, dsq.masternodeOutpoint, connman); + if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator)) { + LOCK(cs_main); + Misbehaving(pfrom->id, 10); return; } @@ -124,21 +128,22 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm for (const auto& q : vecPrivateSendQueue) { if (q.masternodeOutpoint == dsq.masternodeOutpoint) { // no way same mn can send another "not yet ready" dsq this soon - LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", mnInfo.addr.ToString()); + LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", dmn->pdmnState->addr.ToString()); return; } } - int nThreshold = mnInfo.nLastDsq + mnodeman.CountMasternodes() / 5; - LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", mnInfo.nLastDsq, nThreshold, mnodeman.nDsqCount); + int64_t nLastDsq = mnodeman.GetLastDsq(dmn->collateralOutpoint); + int nThreshold = nLastDsq + mnList.GetValidMNsCount() / 5; + LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", nLastDsq, nThreshold, mnodeman.nDsqCount); //don't allow a few nodes to dominate the queuing process - if (mnInfo.nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) { - LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", mnInfo.addr.ToString()); + if (nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) { + LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->pdmnState->addr.ToString()); return; } mnodeman.AllowMixing(dsq.masternodeOutpoint); - LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), mnInfo.addr.ToString()); + LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString()); vecPrivateSendQueue.push_back(dsq); dsq.Relay(connman); } diff --git a/src/privatesend.cpp b/src/privatesend.cpp index 01db2b1cc6..da06c49ab9 100644 --- a/src/privatesend.cpp +++ b/src/privatesend.cpp @@ -50,77 +50,26 @@ bool CPrivateSendQueue::Sign() { if (!fMasternodeMode) return false; - std::string strError = ""; - if (deterministicMNManager->IsDIP3Active()) { - uint256 hash = GetSignatureHash(); - CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); - if (!sig.IsValid()) { - return false; - } - sig.GetBuf(vchSig); - } else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) { - LogPrintf("CPrivateSendQueue::Sign -- SignHash() failed\n"); - return false; - } - - if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) { - LogPrintf("CPrivateSendQueue::Sign -- VerifyHash() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = CTxIn(masternodeOutpoint).ToString() + - std::to_string(nDenom) + - std::to_string(nTime) + - std::to_string(fReady); - - if (!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) { - LogPrintf("CPrivateSendQueue::Sign -- SignMessage() failed, %s\n", ToString()); - return false; - } - - if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CPrivateSendQueue::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } + uint256 hash = GetSignatureHash(); + CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); + if (!sig.IsValid()) { + return false; } + sig.GetBuf(vchSig); return true; } -bool CPrivateSendQueue::CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const +bool CPrivateSendQueue::CheckSignature(const CBLSPublicKey& blsPubKey) const { - std::string strError = ""; - if (deterministicMNManager->IsDIP3Active()) { - uint256 hash = GetSignatureHash(); + uint256 hash = GetSignatureHash(); - CBLSSignature sig; - sig.SetBuf(vchSig); - if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) { - LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); - return false; - } - } else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) { - // we don't care about queues with old signature format - LogPrintf("CPrivateSendQueue::CheckSignature -- VerifyHash() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = CTxIn(masternodeOutpoint).ToString() + - std::to_string(nDenom) + - std::to_string(nTime) + - std::to_string(fReady); - - if (!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CPrivateSendQueue::CheckSignature -- Got bad Masternode queue signature: %s; error: %s\n", ToString(), strError); - return false; - } + CBLSSignature sig; + sig.SetBuf(vchSig); + if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) { + LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); + return false; } return true; @@ -145,73 +94,28 @@ bool CPrivateSendBroadcastTx::Sign() { if (!fMasternodeMode) return false; - std::string strError = ""; - if (deterministicMNManager->IsDIP3Active()) { - uint256 hash = GetSignatureHash(); + uint256 hash = GetSignatureHash(); - CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); - if (!sig.IsValid()) { - return false; - } - sig.GetBuf(vchSig); - } else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::SignHash(hash, activeMasternodeInfo.legacyKeyOperator, vchSig)) { - LogPrintf("CPrivateSendBroadcastTx::Sign -- SignHash() failed\n"); - return false; - } - - if (!CHashSigner::VerifyHash(hash, activeMasternodeInfo.legacyKeyIDOperator, vchSig, strError)) { - LogPrintf("CPrivateSendBroadcastTx::Sign -- VerifyHash() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = tx->GetHash().ToString() + std::to_string(sigTime); - - if (!CMessageSigner::SignMessage(strMessage, vchSig, activeMasternodeInfo.legacyKeyOperator)) { - LogPrintf("CPrivateSendBroadcastTx::Sign -- SignMessage() failed\n"); - return false; - } - - if (!CMessageSigner::VerifyMessage(activeMasternodeInfo.legacyKeyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CPrivateSendBroadcastTx::Sign -- VerifyMessage() failed, error: %s\n", strError); - return false; - } + CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); + if (!sig.IsValid()) { + return false; } + sig.GetBuf(vchSig); return true; } -bool CPrivateSendBroadcastTx::CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const +bool CPrivateSendBroadcastTx::CheckSignature(const CBLSPublicKey& blsPubKey) const { - std::string strError = ""; - if (deterministicMNManager->IsDIP3Active()) { - uint256 hash = GetSignatureHash(); + uint256 hash = GetSignatureHash(); - CBLSSignature sig; - sig.SetBuf(vchSig); - if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) { - LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); - return false; - } - } else if (sporkManager.IsSporkActive(SPORK_6_NEW_SIGS)) { - uint256 hash = GetSignatureHash(); - - if (!CHashSigner::VerifyHash(hash, keyIDOperator, vchSig, strError)) { - // we don't care about dstxes with old signature format - LogPrintf("CPrivateSendBroadcastTx::CheckSignature -- VerifyHash() failed, error: %s\n", strError); - return false; - } - } else { - std::string strMessage = tx->GetHash().ToString() + std::to_string(sigTime); - - if (!CMessageSigner::VerifyMessage(keyIDOperator, vchSig, strMessage, strError)) { - LogPrintf("CPrivateSendBroadcastTx::CheckSignature -- Got bad dstx signature, error: %s\n", strError); - return false; - } + CBLSSignature sig; + sig.SetBuf(vchSig); + if (!sig.IsValid() || !sig.VerifyInsecure(blsPubKey, hash)) { + LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); + return false; } return true; diff --git a/src/privatesend.h b/src/privatesend.h index 440da1e7a0..f8e85097e3 100644 --- a/src/privatesend.h +++ b/src/privatesend.h @@ -225,7 +225,7 @@ public: */ bool Sign(); /// Check if we have a valid Masternode address - bool CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const; + bool CheckSignature(const CBLSPublicKey& blsPubKey) const; bool Relay(CConnman& connman); @@ -306,7 +306,7 @@ public: uint256 GetSignatureHash() const; bool Sign(); - bool CheckSignature(const CKeyID& keyIDOperator, const CBLSPublicKey& blsPubKey) const; + bool CheckSignature(const CBLSPublicKey& blsPubKey) const; void SetConfirmedHeight(int nConfirmedHeightIn) { nConfirmedHeight = nConfirmedHeightIn; } bool IsExpired(int nHeight); diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 07ff4ddcbb..8d506d918b 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -83,10 +83,10 @@ int ClientModel::getNumConnections(unsigned int flags) const QString ClientModel::getMasternodeCountString() const { // return tr("Total: %1 (PS compatible: %2 / Enabled: %3) (IPv4: %4, IPv6: %5, TOR: %6)").arg(QString::number((int)mnodeman.size())) - return tr("Total: %1 (PS compatible: %2 / Enabled: %3)") - .arg(QString::number((int)mnodeman.CountMasternodes(0))) - .arg(QString::number((int)mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION))) - .arg(QString::number((int)mnodeman.CountEnabled())); + auto mnList = deterministicMNManager->GetListAtChainTip(); + return tr("Total: %1 (Enabled: %2)") + .arg(QString::number((int)mnList.GetAllMNsCount())) + .arg(QString::number((int)mnList.GetValidMNsCount())); // .arg(QString::number((int)mnodeman.CountByIP(NET_IPV4))) // .arg(QString::number((int)mnodeman.CountByIP(NET_IPV6))) // .arg(QString::number((int)mnodeman.CountByIP(NET_TOR))); diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index f6733db998..16ad1c891d 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -261,7 +261,8 @@ UniValue gobject_submit(const JSONRPCRequest& request) throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Must wait for client to sync with masternode network. Try again in a minute or so."); } - bool fMnFound = mnodeman.Has(activeMasternodeInfo.outpoint); + auto mnList = deterministicMNManager->GetListAtChainTip(); + bool fMnFound = mnList.HasValidMNByCollateral(activeMasternodeInfo.outpoint); DBG( std::cout << "gobject: submit activeMasternodeInfo.keyIDOperator = " << activeMasternodeInfo.legacyKeyIDOperator.ToString() << ", outpoint = " << activeMasternodeInfo.outpoint.ToStringShort() @@ -412,10 +413,9 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request) UniValue statusObj(UniValue::VOBJ); UniValue returnObj(UniValue::VOBJ); - CMasternode mn; - bool fMnFound = mnodeman.Get(activeMasternodeInfo.outpoint, mn); + auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(activeMasternodeInfo.outpoint); - if (!fMnFound) { + if (!dmn) { nFailed++; statusObj.push_back(Pair("result", "failed")); statusObj.push_back(Pair("errorMessage", "Can't find masternode by collateral output")); @@ -425,19 +425,16 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request) return returnObj; } - CGovernanceVote vote(mn.outpoint, hash, eVoteSignal, eVoteOutcome); + CGovernanceVote vote(dmn->collateralOutpoint, hash, eVoteSignal, eVoteOutcome); bool signSuccess = false; - if (deterministicMNManager->IsDIP3Active()) { - if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && eVoteSignal == VOTE_SIGNAL_FUNDING) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Can't use vote-conf for proposals when deterministic masternodes are active"); - } - if (activeMasternodeInfo.blsKeyOperator) { - signSuccess = vote.Sign(*activeMasternodeInfo.blsKeyOperator); - } - } else { - signSuccess = vote.Sign(activeMasternodeInfo.legacyKeyOperator, activeMasternodeInfo.legacyKeyIDOperator); + if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && eVoteSignal == VOTE_SIGNAL_FUNDING) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Can't use vote-conf for proposals"); } + if (activeMasternodeInfo.blsKeyOperator) { + signSuccess = vote.Sign(*activeMasternodeInfo.blsKeyOperator); + } + if (!signSuccess) { nFailed++; statusObj.push_back(Pair("result", "failed")); @@ -466,9 +463,9 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request) return returnObj; } -UniValue VoteWithMasternodeList(const std::vector& entries, - const uint256& hash, vote_signal_enum_t eVoteSignal, - vote_outcome_enum_t eVoteOutcome) +UniValue VoteWithMasternodes(const std::map& keys, + const uint256& hash, vote_signal_enum_t eVoteSignal, + vote_outcome_enum_t eVoteOutcome) { int govObjType; { @@ -483,59 +480,31 @@ UniValue VoteWithMasternodeList(const std::vectorGetListAtChainTip(); + UniValue resultsObj(UniValue::VOBJ); - for (const auto& mne : entries) { - CPubKey pubKeyOperator; - CKey keyOperator; + for (const auto& p : keys) { + const auto& proTxHash = p.first; + const auto& key = p.second; UniValue statusObj(UniValue::VOBJ); - if (!CMessageSigner::GetKeysFromSecret(mne.getPrivKey(), keyOperator, pubKeyOperator)) { + auto dmn = mnList.GetValidMN(proTxHash); + if (!dmn) { nFailed++; statusObj.push_back(Pair("result", "failed")); - statusObj.push_back(Pair("errorMessage", "Masternode signing error, could not set key correctly")); - resultsObj.push_back(Pair(mne.getAlias(), statusObj)); + statusObj.push_back(Pair("errorMessage", "Can't find masternode by proTxHash")); + resultsObj.push_back(Pair(proTxHash.ToString(), statusObj)); continue; } - uint256 nTxHash; - nTxHash.SetHex(mne.getTxHash()); - - int nOutputIndex = 0; - if (!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) { - continue; - } - - COutPoint outpoint(nTxHash, nOutputIndex); - - CMasternode mn; - bool fMnFound = mnodeman.Get(outpoint, mn); - - if (!fMnFound) { - nFailed++; - statusObj.push_back(Pair("result", "failed")); - statusObj.push_back(Pair("errorMessage", "Can't find masternode by collateral output")); - resultsObj.push_back(Pair(mne.getAlias(), statusObj)); - continue; - } - - if (deterministicMNManager->IsDIP3Active()) { - if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && mn.keyIDVoting != pubKeyOperator.GetID()) { - nFailed++; - statusObj.push_back(Pair("result", "failed")); - statusObj.push_back(Pair("errorMessage", "Can't vote on proposal when key does not match voting key")); - resultsObj.push_back(Pair(mne.getAlias(), statusObj)); - continue; - } - } - - CGovernanceVote vote(mn.outpoint, hash, eVoteSignal, eVoteOutcome); - if (!vote.Sign(keyOperator, pubKeyOperator.GetID())) { + CGovernanceVote vote(dmn->collateralOutpoint, hash, eVoteSignal, eVoteOutcome); + if (!vote.Sign(key, key.GetPubKey().GetID())) { nFailed++; statusObj.push_back(Pair("result", "failed")); statusObj.push_back(Pair("errorMessage", "Failure to sign.")); - resultsObj.push_back(Pair(mne.getAlias(), statusObj)); + resultsObj.push_back(Pair(proTxHash.ToString(), statusObj)); continue; } @@ -549,7 +518,7 @@ UniValue VoteWithMasternodeList(const std::vector \n" - "Vote on a governance object by all masternodes (using masternode.conf setup)\n" + "Vote on a governance object by all masternodes for which the voting key is present in the local wallet\n" "\nArguments:\n" "1. governance-hash (string, required) hash of the governance object\n" "2. vote (string, required) vote, possible values: [funding|valid|delete|endorsed]\n" @@ -592,66 +562,33 @@ UniValue gobject_vote_many(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'"); } - std::vector entries = masternodeConfig.getEntries(); - -#ifdef ENABLE_WALLET - // This is a hack to maintain code-level backwards compatibility with masternode.conf and the deterministic masternodes. - // Deterministic masternode keys are managed inside the wallet instead of masternode.conf - // This allows voting on proposals when you have the MN voting key in your wallet - // We can remove this when we remove support for masternode.conf and only support wallet based masternode - // management - if (deterministicMNManager->IsDIP3Active()) { - if (!pwalletMain) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-many not supported when wallet is disabled."); - } - entries.clear(); - - auto mnList = deterministicMNManager->GetListAtChainTip(); - mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) { - bool found = false; - for (const auto &mne : entries) { - uint256 nTxHash; - nTxHash.SetHex(mne.getTxHash()); - - int nOutputIndex = 0; - if(!ParseInt32(mne.getOutputIndex(), &nOutputIndex)) { - continue; - } - - if (nTxHash == dmn->collateralOutpoint.hash && (uint32_t)nOutputIndex == dmn->collateralOutpoint.n) { - found = true; - break; - } - } - if (!found) { - CKey ownerKey; - if (pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, ownerKey)) { - CBitcoinSecret secret(ownerKey); - CMasternodeConfig::CMasternodeEntry mne(dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToStringIPPort(false), secret.ToString(), dmn->collateralOutpoint.hash.ToString(), itostr(dmn->collateralOutpoint.n)); - entries.push_back(mne); - } - } - }); - } -#else - if (deterministicMNManager->IsDIP3Active()) { + if (!pwalletMain) { throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-many not supported when wallet is disabled."); } -#endif - return VoteWithMasternodeList(entries, hash, eVoteSignal, eVoteOutcome); + std::map votingKeys; + + auto mnList = deterministicMNManager->GetListAtChainTip(); + mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) { + CKey votingKey; + if (pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) { + votingKeys.emplace(dmn->proTxHash, votingKey); + } + }); + + return VoteWithMasternodes(votingKeys, hash, eVoteSignal, eVoteOutcome); } void gobject_vote_alias_help() { throw std::runtime_error( "gobject vote-alias \n" - "Vote on a governance object by masternode alias (using masternode.conf setup)\n" + "Vote on a governance object by masternode's voting key (if present in local wallet)\n" "\nArguments:\n" "1. governance-hash (string, required) hash of the governance object\n" "2. vote (string, required) vote, possible values: [funding|valid|delete|endorsed]\n" "3. vote-outcome (string, required) vote outcome, possible values: [yes|no|abstain]\n" - "4. alias-name (string, required) masternode alias or proTxHash after DIP3 activation" + "4. protx-hash (string, required) masternode's proTxHash" ); } @@ -676,41 +613,27 @@ UniValue gobject_vote_alias(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'"); } - std::vector entries; - - if (deterministicMNManager->IsDIP3Active()) { -#ifdef ENABLE_WALLET - if (!pwalletMain) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-alias not supported when wallet is disabled"); - } - - uint256 proTxHash = ParseHashV(request.params[4], "alias-name"); - auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(proTxHash); - if (!dmn) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid or unknown proTxHash"); - } - - CKey votingKey; - if (!pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Voting ekey %s not known by wallet", CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString())); - } - - CBitcoinSecret secret(votingKey); - CMasternodeConfig::CMasternodeEntry mne(dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToStringIPPort(false), secret.ToString(), dmn->collateralOutpoint.hash.ToString(), itostr(dmn->collateralOutpoint.n)); - entries.push_back(mne); -#else + if (!pwalletMain) { throw JSONRPCError(RPC_INVALID_PARAMETER, "vote-alias not supported when wallet is disabled"); -#endif - } else { - std::string strAlias = request.params[4].get_str(); - for (const auto& mne : masternodeConfig.getEntries()) { - if (strAlias == mne.getAlias()) - entries.push_back(mne); - } } - return VoteWithMasternodeList(entries, hash, eVoteSignal, eVoteOutcome); + uint256 proTxHash = ParseHashV(request.params[4], "protx-hash"); + auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMN(proTxHash); + if (!dmn) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid or unknown proTxHash"); + } + + CKey votingKey; + if (!pwalletMain->GetKey(dmn->pdmnState->keyIDVoting, votingKey)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Voting key %s not known by wallet", CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString())); + } + + std::map votingKeys; + votingKeys.emplace(proTxHash, votingKey); + + return VoteWithMasternodes(votingKeys, hash, eVoteSignal, eVoteOutcome); } +#endif UniValue ListObjects(const std::string& strCachedSignal, const std::string& strType, int nStartTime) { @@ -1063,10 +986,12 @@ UniValue gobject(const JSONRPCRequest& request) return gobject_submit(request); } else if (strCommand == "vote-conf") { return gobject_vote_conf(request); +#ifdef ENABLE_WALLET } else if (strCommand == "vote-many") { return gobject_vote_many(request); } else if (strCommand == "vote-alias") { return gobject_vote_alias(request); +#endif } else if (strCommand == "list") { // USERS CAN QUERY THE SYSTEM FOR A LIST OF VARIOUS GOVERNANCE ITEMS return gobject_list(request); @@ -1133,10 +1058,9 @@ UniValue voteraw(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); } - CMasternode mn; - bool fMnFound = mnodeman.Get(outpoint, mn); + auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(outpoint); - if (!fMnFound) { + if (!dmn) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Failure to find masternode in list : " + outpoint.ToStringShort()); } diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 5e8281648d..9bf61955c5 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -99,13 +99,13 @@ UniValue getpoolinfo(const JSONRPCRequest& request) // obj.push_back(Pair("entries", pprivateSendBase->GetEntriesCount())); obj.push_back(Pair("status", privateSendClient.GetStatuses())); - std::vector vecMnInfo; - if (privateSendClient.GetMixingMasternodesInfo(vecMnInfo)) { + std::vector vecDmns; + if (privateSendClient.GetMixingMasternodesInfo(vecDmns)) { UniValue pools(UniValue::VARR); - for (const auto& mnInfo : vecMnInfo) { + for (const auto& dmn : vecDmns) { UniValue pool(UniValue::VOBJ); - pool.push_back(Pair("outpoint", mnInfo.outpoint.ToStringShort())); - pool.push_back(Pair("addr", mnInfo.addr.ToString())); + pool.push_back(Pair("outpoint", dmn->collateralOutpoint.ToStringShort())); + pool.push_back(Pair("addr", dmn->pdmnState->addr.ToString())); pools.push_back(pool); } obj.push_back(Pair("pools", pools)); @@ -136,26 +136,21 @@ void masternode_list_help() "2. \"filter\" (string, optional) Filter results. Partial match by outpoint by default in all modes,\n" " additional matches in some modes are also available\n" "\nAvailable modes:\n" - " activeseconds - Print number of seconds masternode recognized by the network as enabled\n" - " (since latest issued \"masternode start/start-many/start-alias\")\n" " addr - Print ip address associated with a masternode (can be additionally filtered, partial match)\n" - " daemon - Print daemon version of a masternode (can be additionally filtered, exact match)\n" - " full - Print info in format 'status protocol payee lastseen activeseconds lastpaidtime lastpaidblock IP'\n" + " full - Print info in format 'status payee lastpaidtime lastpaidblock IP'\n" " (can be additionally filtered, partial match)\n" - " info - Print info in format 'status protocol payee lastseen activeseconds sentinelversion sentinelstate IP'\n" + " info - Print info in format 'status payee IP'\n" " (can be additionally filtered, partial match)\n" " json - Print info in JSON format (can be additionally filtered, partial match)\n" + " keyIDOwner - Print the masternode owner key id\n" + " keyIDVoting - Print the masternode voting key id\n" " lastpaidblock - Print the last block height a node was paid on the network\n" " lastpaidtime - Print the last time a node was paid on the network\n" - " lastseen - Print timestamp of when a masternode was last seen on the network\n" " payee - Print Dash address associated with a masternode (can be additionally filtered,\n" " partial match)\n" - " protocol - Print protocol of a masternode (can be additionally filtered, exact match)\n" - " keyid - Print the masternode (not collateral) key id\n" - " rank - Print rank of a masternode based on current block\n" - " sentinel - Print sentinel version of a masternode (can be additionally filtered, exact match)\n" - " status - Print masternode status: PRE_ENABLED / ENABLED / EXPIRED / SENTINEL_PING_EXPIRED / NEW_START_REQUIRED /\n" - " UPDATE_REQUIRED / POSE_BAN / OUTPOINT_SPENT (can be additionally filtered, partial match)\n" + " pubKeyOperator - Print the masternode operator public key\n" + " status - Print masternode status: ENABLED / POSE_BAN / OUTPOINT_SPENT\n" + " (can be additionally filtered, partial match)\n" ); } @@ -224,25 +219,15 @@ UniValue masternode_count(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 2) masternode_count_help(); - int nCount; - int total = mnodeman.CountMasternodes(0); - if (deterministicMNManager->IsDIP3Active()) { - nCount = mnodeman.CountEnabled(); - } else { - masternode_info_t mnInfo; - mnodeman.GetNextMasternodeInQueueForPayment(true, nCount, mnInfo); - } - - int ps = mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION); - int enabled = mnodeman.CountEnabled(); + auto mnList = deterministicMNManager->GetListAtChainTip(); + int total = mnList.GetAllMNsCount(); + int enabled = mnList.GetValidMNsCount(); if (request.params.size() == 1) { UniValue obj(UniValue::VOBJ); obj.push_back(Pair("total", total)); - obj.push_back(Pair("ps_compatible", ps)); obj.push_back(Pair("enabled", enabled)); - obj.push_back(Pair("qualify", nCount)); return obj; } @@ -252,47 +237,24 @@ UniValue masternode_count(const JSONRPCRequest& request) if (strMode == "total") return total; - if (strMode == "ps") - return ps; - if (strMode == "enabled") return enabled; - if (strMode == "qualify") - return nCount; - if (strMode == "all") - return strprintf("Total: %d (PS Compatible: %d / Enabled: %d / Qualify: %d)", - total, ps, enabled, nCount); + return strprintf("Total: %d (Enabled: %d)", + total, enabled); throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown mode value"); } UniValue GetNextMasternodeForPayment(int heightShift) { - int nCount; - int nHeight; - masternode_info_t mnInfo; - CBlockIndex* pindex = NULL; - { - LOCK(cs_main); - pindex = chainActive.Tip(); - } - - nHeight = pindex->nHeight + heightShift; - mnodeman.UpdateLastPaid(pindex); - - CScript payeeScript; - if (deterministicMNManager->IsDIP3Active()) { - auto payee = deterministicMNManager->GetListAtChainTip().GetMNPayee(); - if (!payee || !mnodeman.GetMasternodeInfo(payee->proTxHash, mnInfo)) - return "unknown"; - payeeScript = payee->pdmnState->scriptPayout; - } else { - if (!mnodeman.GetNextMasternodeInQueueForPayment(nHeight, true, nCount, mnInfo)) - return "unknown"; - payeeScript = GetScriptForDestination(mnInfo.keyIDCollateralAddress); - } + auto mnList = deterministicMNManager->GetListAtChainTip(); + auto payees = mnList.GetProjectedMNPayees(heightShift); + if (payees.empty()) + return "unknown"; + auto payee = payees[heightShift - 9]; + CScript payeeScript = payee->pdmnState->scriptPayout; CTxDestination payeeDest; CBitcoinAddress payeeAddr; @@ -302,13 +264,11 @@ UniValue GetNextMasternodeForPayment(int heightShift) UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("height", nHeight)); - obj.push_back(Pair("IP:port", mnInfo.addr.ToString())); - obj.push_back(Pair("protocol", mnInfo.nProtocolVersion)); - obj.push_back(Pair("outpoint", mnInfo.outpoint.ToStringShort())); + obj.push_back(Pair("height", mnList.GetHeight() + heightShift)); + obj.push_back(Pair("IP:port", payee->pdmnState->addr.ToString())); + obj.push_back(Pair("proTxHash", payee->proTxHash.ToString())); + obj.push_back(Pair("outpoint", payee->collateralOutpoint.ToStringShort())); obj.push_back(Pair("payee", payeeAddr.IsValid() ? payeeAddr.ToString() : "UNKNOWN")); - obj.push_back(Pair("lastseen", mnInfo.nTimeLastPing)); - obj.push_back(Pair("activeseconds", mnInfo.nTimeLastPing - mnInfo.sigTime)); return obj; } @@ -853,11 +813,14 @@ UniValue masternodelist(const JSONRPCRequest& request) if (request.params.size() >= 1) strMode = request.params[0].get_str(); if (request.params.size() == 2) strFilter = request.params[1].get_str(); + std::transform(strMode.begin(), strMode.end(), strMode.begin(), ::tolower); + if (request.fHelp || ( - strMode != "activeseconds" && strMode != "addr" && strMode != "daemon" && strMode != "full" && strMode != "info" && strMode != "json" && - strMode != "lastseen" && strMode != "lastpaidtime" && strMode != "lastpaidblock" && - strMode != "protocol" && strMode != "payee" && strMode != "pubkey" && - strMode != "rank" && strMode != "sentinel" && strMode != "status")) + strMode != "addr" && strMode != "full" && strMode != "info" && strMode != "json" && + strMode != "keyidowner" && strMode != "keyidvoting" && + strMode != "lastpaidtime" && strMode != "lastpaidblock" && + strMode != "payee" && strMode != "pubkeyoperator" && + strMode != "status")) { masternode_list_help(); } @@ -872,147 +835,108 @@ UniValue masternodelist(const JSONRPCRequest& request) } UniValue obj(UniValue::VOBJ); - if (strMode == "rank") { - CMasternodeMan::rank_pair_vec_t vMasternodeRanks; - mnodeman.GetMasternodeRanks(vMasternodeRanks); - for (const auto& rankpair : vMasternodeRanks) { - std::string strOutpoint = rankpair.second.outpoint.ToStringShort(); - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, rankpair.first)); + + auto mnList = deterministicMNManager->GetListAtChainTip(); + auto dmnToStatus = [&](const CDeterministicMNCPtr& dmn) { + if (mnList.IsMNValid(dmn)) { + return "ENABLED"; } - } else { - std::map mapMasternodes = mnodeman.GetFullMasternodeMap(); - for (const auto& mnpair : mapMasternodes) { - CMasternode mn = mnpair.second; - std::string strOutpoint = mnpair.first.ToStringShort(); - - CScript payeeScript; - if (deterministicMNManager->IsDIP3Active()) { - auto dmn = deterministicMNManager->GetListAtChainTip().GetMNByCollateral(mn.outpoint); - if (dmn) { - payeeScript = dmn->pdmnState->scriptPayout; - } - } else { - payeeScript = GetScriptForDestination(mn.keyIDCollateralAddress); - } - - CTxDestination payeeDest; - std::string payeeStr = "UNKOWN"; - if (ExtractDestination(payeeScript, payeeDest)) { - payeeStr = CBitcoinAddress(payeeDest).ToString(); - } - - if (strMode == "activeseconds") { - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, (int64_t)(mn.lastPing.sigTime - mn.sigTime))); - } else if (strMode == "addr") { - std::string strAddress = mn.addr.ToString(); - if (strFilter !="" && strAddress.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, strAddress)); - } else if (strMode == "daemon") { - std::string strDaemon = mn.lastPing.GetDaemonString(); - if (strFilter !="" && strDaemon.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, strDaemon)); - } else if (strMode == "sentinel") { - std::string strSentinel = mn.lastPing.GetSentinelString(); - if (strFilter !="" && strSentinel.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, strSentinel)); - } else if (strMode == "full") { - std::ostringstream streamFull; - streamFull << std::setw(18) << - mn.GetStatus() << " " << - mn.nProtocolVersion << " " << - payeeStr << " " << - (int64_t)mn.lastPing.sigTime << " " << std::setw(8) << - (int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " << std::setw(10) << - mn.GetLastPaidTime() << " " << std::setw(6) << - mn.GetLastPaidBlock() << " " << - mn.addr.ToString(); - std::string strFull = streamFull.str(); - if (strFilter !="" && strFull.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, strFull)); - } else if (strMode == "info") { - std::ostringstream streamInfo; - streamInfo << std::setw(18) << - mn.GetStatus() << " " << - mn.nProtocolVersion << " " << - payeeStr << " " << - (int64_t)mn.lastPing.sigTime << " " << std::setw(8) << - (int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " << - mn.lastPing.GetSentinelString() << " " << - (mn.lastPing.fSentinelIsCurrent ? "current" : "expired") << " " << - mn.addr.ToString(); - std::string strInfo = streamInfo.str(); - if (strFilter !="" && strInfo.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, strInfo)); - } else if (strMode == "json") { - std::ostringstream streamInfo; - streamInfo << mn.addr.ToString() << " " << - CBitcoinAddress(mn.pubKeyCollateralAddress.GetID()).ToString() << " " << - mn.GetStatus() << " " << - mn.nProtocolVersion << " " << - mn.lastPing.nDaemonVersion << " " << - mn.lastPing.GetSentinelString() << " " << - (mn.lastPing.fSentinelIsCurrent ? "current" : "expired") << " " << - (int64_t)mn.lastPing.sigTime << " " << - (int64_t)(mn.lastPing.sigTime - mn.sigTime) << " " << - mn.GetLastPaidTime() << " " << - mn.GetLastPaidBlock(); - std::string strInfo = streamInfo.str(); - if (strFilter !="" && strInfo.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - UniValue objMN(UniValue::VOBJ); - objMN.push_back(Pair("address", mn.addr.ToString())); - objMN.push_back(Pair("payee", CBitcoinAddress(mn.pubKeyCollateralAddress.GetID()).ToString())); - objMN.push_back(Pair("status", mn.GetStatus())); - objMN.push_back(Pair("protocol", mn.nProtocolVersion)); - objMN.push_back(Pair("daemonversion", mn.lastPing.GetDaemonString())); - objMN.push_back(Pair("sentinelversion", mn.lastPing.GetSentinelString())); - objMN.push_back(Pair("sentinelstate", (mn.lastPing.fSentinelIsCurrent ? "current" : "expired"))); - objMN.push_back(Pair("lastseen", (int64_t)mn.lastPing.sigTime)); - objMN.push_back(Pair("activeseconds", (int64_t)(mn.lastPing.sigTime - mn.sigTime))); - objMN.push_back(Pair("lastpaidtime", mn.GetLastPaidTime())); - objMN.push_back(Pair("lastpaidblock", mn.GetLastPaidBlock())); - obj.push_back(Pair(strOutpoint, objMN)); - } else if (strMode == "lastpaidblock") { - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, mn.GetLastPaidBlock())); - } else if (strMode == "lastpaidtime") { - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, mn.GetLastPaidTime())); - } else if (strMode == "lastseen") { - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, (int64_t)mn.lastPing.sigTime)); - } else if (strMode == "payee") { - if (strFilter !="" && payeeStr.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, payeeStr)); - } else if (strMode == "protocol") { - if (strFilter !="" && strFilter != strprintf("%d", mn.nProtocolVersion) && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, mn.nProtocolVersion)); - } else if (strMode == "keyIDOwner") { - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, HexStr(mn.keyIDOwner))); - } else if (strMode == "keyIDOperator") { - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, HexStr(mn.legacyKeyIDOperator))); - } else if (strMode == "keyIDVoting") { - if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, HexStr(mn.keyIDVoting))); - } else if (strMode == "status") { - std::string strStatus = mn.GetStatus(); - if (strFilter !="" && strStatus.find(strFilter) == std::string::npos && - strOutpoint.find(strFilter) == std::string::npos) continue; - obj.push_back(Pair(strOutpoint, strStatus)); - } + if (mnList.IsMNPoSeBanned(dmn)) { + return "POSE_BANNED"; } - } + return "UNKNOWN"; + }; + auto dmnToLastPaidTime = [&](const CDeterministicMNCPtr& dmn) { + if (dmn->pdmnState->nLastPaidHeight == 0) { + return (int)0; + } + + LOCK(cs_main); + const CBlockIndex* pindex = chainActive[dmn->pdmnState->nLastPaidHeight]; + return (int)pindex->nTime; + }; + + mnList.ForEachMN(false, [&](const CDeterministicMNCPtr& dmn) { + std::string strOutpoint = dmn->collateralOutpoint.ToStringShort(); + + CScript payeeScript = dmn->pdmnState->scriptPayout; + CTxDestination payeeDest; + std::string payeeStr = "UNKOWN"; + if (ExtractDestination(payeeScript, payeeDest)) { + payeeStr = CBitcoinAddress(payeeDest).ToString(); + } + + if (strMode == "addr") { + std::string strAddress = dmn->pdmnState->addr.ToString(false); + if (strFilter !="" && strAddress.find(strFilter) == std::string::npos && + strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, strAddress)); + } else if (strMode == "full") { + std::ostringstream streamFull; + streamFull << std::setw(18) << + dmnToStatus(dmn) << " " << + payeeStr << " " << std::setw(10) << + dmnToLastPaidTime(dmn) << " " << std::setw(6) << + dmn->pdmnState->nLastPaidHeight << " " << + dmn->pdmnState->addr.ToString(); + std::string strFull = streamFull.str(); + if (strFilter !="" && strFull.find(strFilter) == std::string::npos && + strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, strFull)); + } else if (strMode == "info") { + std::ostringstream streamInfo; + streamInfo << std::setw(18) << + dmnToStatus(dmn) << " " << + payeeStr << " " << + dmn->pdmnState->addr.ToString(); + std::string strInfo = streamInfo.str(); + if (strFilter !="" && strInfo.find(strFilter) == std::string::npos && + strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, strInfo)); + } else if (strMode == "json") { + std::ostringstream streamInfo; + streamInfo << dmn->pdmnState->addr.ToString() << " " << + CBitcoinAddress(dmn->pdmnState->scriptPayout).ToString() << " " << + dmnToStatus(dmn) << " " << + dmnToLastPaidTime(dmn) << " " << + dmn->pdmnState->nLastPaidHeight; + std::string strInfo = streamInfo.str(); + if (strFilter !="" && strInfo.find(strFilter) == std::string::npos && + strOutpoint.find(strFilter) == std::string::npos) return; + UniValue objMN(UniValue::VOBJ); + objMN.push_back(Pair("address", dmn->pdmnState->addr.ToString())); + objMN.push_back(Pair("payee", CBitcoinAddress(dmn->pdmnState->scriptPayout).ToString())); + objMN.push_back(Pair("status", dmnToStatus(dmn))); + objMN.push_back(Pair("lastpaidtime", dmnToLastPaidTime(dmn))); + objMN.push_back(Pair("lastpaidblock", dmn->pdmnState->nLastPaidHeight)); + obj.push_back(Pair(strOutpoint, objMN)); + } else if (strMode == "lastpaidblock") { + if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, dmn->pdmnState->nLastPaidHeight)); + } else if (strMode == "lastpaidtime") { + if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, dmnToLastPaidTime(dmn))); + } else if (strMode == "payee") { + if (strFilter !="" && payeeStr.find(strFilter) == std::string::npos && + strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, payeeStr)); + } else if (strMode == "keyidowner") { + if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, HexStr(dmn->pdmnState->keyIDOwner))); + } else if (strMode == "pubkeyoperator") { + if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, dmn->pdmnState->pubKeyOperator.ToString())); + } else if (strMode == "keyidvoting") { + if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, HexStr(dmn->pdmnState->keyIDVoting))); + } else if (strMode == "status") { + std::string strStatus = dmnToStatus(dmn); + if (strFilter !="" && strStatus.find(strFilter) == std::string::npos && + strOutpoint.find(strFilter) == std::string::npos) return; + obj.push_back(Pair(strOutpoint, strStatus)); + } + }); + return obj; } diff --git a/src/validation.cpp b/src/validation.cpp index 786c68fbeb..e51e3034cd 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1828,35 +1828,7 @@ int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Para ThresholdState state = VersionBitsState(pindexPrev, params, pos, versionbitscache); const struct BIP9DeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos]; if (vbinfo.check_mn_protocol && state == THRESHOLD_STARTED && fCheckMasternodesUpgraded) { - if (deterministicMNManager->IsDIP3Active()) { - auto mnList = deterministicMNManager->GetListForBlock(pindexPrev->GetBlockHash()); - auto payee = mnList.GetMNPayee(); - if (!payee) { - continue; - } - } else { - std::vector voutMasternodePayments; - masternode_info_t mnInfo; - if (!mnpayments.GetBlockTxOuts(pindexPrev->nHeight + 1, 0, voutMasternodePayments)) { - // no votes for this block - continue; - } - bool mnKnown = false; - for (const auto& txout : voutMasternodePayments) { - if (mnodeman.GetMasternodeInfo(txout.scriptPubKey, mnInfo)) { - mnKnown = true; - break; - } - } - if (!mnKnown) { - // unknown masternode - continue; - } - if (mnInfo.nProtocolVersion < DMN_PROTO_VERSION) { - // masternode is not upgraded yet - continue; - } - } + // TODO implement new logic for MN upgrade checks (e.g. with LLMQ based feature/version voting) } if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED) { nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 553a912d7b..d0982ba94a 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1121,10 +1121,11 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFlushOnClose) } AddToSpends(hash); + auto mnList = deterministicMNManager->GetListAtChainTip(); for(unsigned int i = 0; i < wtx.tx->vout.size(); ++i) { if (IsMine(wtx.tx->vout[i]) && !IsSpent(hash, i)) { setWalletUTXO.insert(COutPoint(hash, i)); - if (deterministicMNManager->IsProTxWithCollateral(wtx.tx, i) || deterministicMNManager->HasMNCollateralAtChainTip(COutPoint(hash, i))) { + if (deterministicMNManager->IsProTxWithCollateral(wtx.tx, i) || mnList.HasMNByCollateral(COutPoint(hash, i))) { LockCoin(COutPoint(hash, i)); } } @@ -3989,11 +3990,13 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) // This avoids accidential spending of collaterals. They can still be unlocked manually if a spend is really intended. void CWallet::AutoLockMasternodeCollaterals() { + auto mnList = deterministicMNManager->GetListAtChainTip(); + LOCK2(cs_main, cs_wallet); for (const auto& pair : mapWallet) { for (unsigned int i = 0; i < pair.second.tx->vout.size(); ++i) { if (IsMine(pair.second.tx->vout[i]) && !IsSpent(pair.first, i)) { - if (deterministicMNManager->IsProTxWithCollateral(pair.second.tx, i) || deterministicMNManager->HasMNCollateralAtChainTip(COutPoint(pair.first, i))) { + if (deterministicMNManager->IsProTxWithCollateral(pair.second.tx, i) || mnList.HasMNByCollateral(COutPoint(pair.first, i))) { LockCoin(COutPoint(pair.first, i)); } } @@ -4643,11 +4646,13 @@ void CWallet::ListLockedCoins(std::vector& vOutpts) void CWallet::ListProTxCoins(std::vector& vOutpts) { + auto mnList = deterministicMNManager->GetListAtChainTip(); + AssertLockHeld(cs_wallet); for (const auto &o : setWalletUTXO) { if (mapWallet.count(o.hash)) { const auto &p = mapWallet[o.hash]; - if (deterministicMNManager->IsProTxWithCollateral(p.tx, o.n) || deterministicMNManager->HasMNCollateralAtChainTip(o)) { + if (deterministicMNManager->IsProTxWithCollateral(p.tx, o.n) || mnList.HasMNByCollateral(o)) { vOutpts.emplace_back(o); } }