From 6b3d650280f98496afb6700d49a442f263bd1ecd Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Tue, 11 Sep 2018 16:33:07 +0200 Subject: [PATCH] After DIP3 activation, allow voting with voting keys stored in your wallet (#2281) * Implement temporary solution to allow voting with owner keys from your wallet Will later be removed and properly reimplemented when cleaning up legacy masternode code * When MN keys from masternode.conf are used, only allow voting when they match with keyIDVoting --- src/rpc/governance.cpp | 84 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index f200400b9b..52ae2bb27d 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -362,6 +362,16 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'"); } + int govObjType; + { + LOCK(governance.cs); + CGovernanceObject *pGovObj = governance.FindGovernanceObject(hash); + if (!pGovObj) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Governance object not found"); + } + govObjType = pGovObj->GetObjectType(); + } + int nSuccessful = 0; int nFailed = 0; @@ -383,6 +393,18 @@ UniValue gobject_vote_conf(const JSONRPCRequest& request) return returnObj; } + if (deterministicMNManager->IsDeterministicMNsSporkActive()) { + if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && mn.keyIDVoting != activeMasternodeInfo.keyIDOperator) { + nFailed++; + statusObj.push_back(Pair("result", "failed")); + statusObj.push_back(Pair("errorMessage", "Can't vote on proposal when operator key does not match voting key")); + resultsObj.push_back(Pair("dash.conf", statusObj)); + returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", nSuccessful, nFailed))); + returnObj.push_back(Pair("detail", resultsObj)); + return returnObj; + } + } + CGovernanceVote vote(mn.outpoint, hash, eVoteSignal, eVoteOutcome); if (!vote.Sign(activeMasternodeInfo.keyOperator, activeMasternodeInfo.keyIDOperator)) { nFailed++; @@ -416,6 +438,16 @@ UniValue VoteWithMasternodeList(const std::vectorGetObjectType(); + } + int nSuccessful = 0; int nFailed = 0; @@ -456,6 +488,16 @@ UniValue VoteWithMasternodeList(const std::vectorIsDeterministicMNsSporkActive()) { + 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())) { nFailed++; @@ -518,7 +560,47 @@ 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'"); } - return VoteWithMasternodeList(masternodeConfig.getEntries(), hash, eVoteSignal, eVoteOutcome); + 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->IsDeterministicMNsSporkActive()) { + auto mnList = deterministicMNManager->GetListAtChainTip(); + for (const auto &dmn : mnList.valid_range()) { + 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->proTxHash && (uint32_t)nOutputIndex == dmn->nCollateralIndex) { + found = true; + break; + } + } + if (found) { + continue; + } + + 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->proTxHash.ToString(), itostr(dmn->nCollateralIndex)); + entries.push_back(mne); + } + } + } +#endif + + return VoteWithMasternodeList(entries, hash, eVoteSignal, eVoteOutcome); } void gobject_vote_alias_help()