diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f71af1dff45..5ee55b530d9 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -195,9 +195,9 @@ class CMainParams : public CChainParams { consensus.vaultCreationFee = 2 * COIN; consensus.props.cfp.fee = COIN / 100; // 1% - consensus.props.cfp.majorityThreshold = COIN / 2; // vote pass with over 50% majority + consensus.props.cfp.approvalThreshold = COIN / 2; // vote pass with over 50% majority consensus.props.voc.fee = 50 * COIN; - consensus.props.voc.majorityThreshold = 66670000; // vote pass with over 66.67% majority + consensus.props.voc.approvalThreshold = 66670000; // vote pass with over 66.67% majority consensus.props.quorum = COIN / 100; // 1% of the masternodes must vote consensus.props.votingPeriod = 130000; // tally votes every 130K blocks @@ -446,9 +446,9 @@ class CTestNetParams : public CChainParams { consensus.vaultCreationFee = 1 * COIN; consensus.props.cfp.fee = COIN / 100; // 1% - consensus.props.cfp.majorityThreshold = COIN / 2; // vote pass with over 50% majority + consensus.props.cfp.approvalThreshold = COIN / 2; // vote pass with over 50% majority consensus.props.voc.fee = 50 * COIN; - consensus.props.voc.majorityThreshold = 66670000; // vote pass with over 66.67% majority + consensus.props.voc.approvalThreshold = 66670000; // vote pass with over 66.67% majority consensus.props.quorum = COIN / 100; // 1% of the masternodes must vote consensus.props.votingPeriod = 70000; // tally votes every 70K blocks @@ -650,9 +650,9 @@ class CDevNetParams : public CChainParams { consensus.vaultCreationFee = 1 * COIN; consensus.props.cfp.fee = COIN / 100; // 1% - consensus.props.cfp.majorityThreshold = COIN / 2; // vote pass with over 50% majority + consensus.props.cfp.approvalThreshold = COIN / 2; // vote pass with over 50% majority consensus.props.voc.fee = 5 * COIN; - consensus.props.voc.majorityThreshold = 66670000; // vote pass with over 66.67% majority + consensus.props.voc.approvalThreshold = 66670000; // vote pass with over 66.67% majority consensus.props.quorum = COIN / 100; // 1% of the masternodes must vote consensus.props.votingPeriod = 100; // tally votes every 1K blocks @@ -846,9 +846,9 @@ class CRegTestParams : public CChainParams { consensus.spv.minConfirmations = 6; consensus.props.cfp.fee = COIN / 100; // 1% - consensus.props.cfp.majorityThreshold = COIN / 2; // vote pass with over 50% majority + consensus.props.cfp.approvalThreshold = COIN / 2; // vote pass with over 50% majority consensus.props.voc.fee = 5 * COIN; - consensus.props.voc.majorityThreshold = 66670000; // vote pass with over 66.67% majority + consensus.props.voc.approvalThreshold = 66670000; // vote pass with over 66.67% majority consensus.props.quorum = COIN / 100; // 1% of the masternodes must vote consensus.props.votingPeriod = 70; // tally votes every 70 blocks diff --git a/src/consensus/params.h b/src/consensus/params.h index d928d98161e..4166671311c 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -208,7 +208,7 @@ struct Params { struct CPropsParams { struct CPropsSpecs { CAmount fee; - CAmount majorityThreshold; + CAmount approvalThreshold; } cfp, brp, voc; uint32_t votingPeriod; CAmount quorum; diff --git a/src/masternodes/masternodes.cpp b/src/masternodes/masternodes.cpp index edc741de6c4..bed2f43ab79 100644 --- a/src/masternodes/masternodes.cpp +++ b/src/masternodes/masternodes.cpp @@ -1330,7 +1330,7 @@ uint32_t CCustomCSView::GetEmergencyPeriodFromAttributes(const CPropType& type) return attributes->GetValue(VOCKey, uint32_t{8640}); } -CAmount CCustomCSView::GetMajorityFromAttributes(const CPropType& type) const +CAmount CCustomCSView::GetApprovalThresholdFromAttributes(const CPropType& type) const { auto attributes = GetAttributes(); assert(attributes); @@ -1340,22 +1340,27 @@ CAmount CCustomCSView::GetMajorityFromAttributes(const CPropType& type) const switch(type) { case CPropType::CommunityFundProposal: - return attributes->GetValue(CFPKey, Params().GetConsensus().props.cfp.majorityThreshold) / 10000; + return attributes->GetValue(CFPKey, Params().GetConsensus().props.cfp.approvalThreshold) / 10000; case CPropType::VoteOfConfidence: - return attributes->GetValue(VOCKey, Params().GetConsensus().props.voc.majorityThreshold) / 10000; + return attributes->GetValue(VOCKey, Params().GetConsensus().props.voc.approvalThreshold) / 10000; } return 0; } -CAmount CCustomCSView::GetQuorumFromAttributes() const +CAmount CCustomCSView::GetQuorumFromAttributes(const CPropType& type, bool emergency) const { auto attributes = GetAttributes(); assert(attributes); - CDataStructureV0 QuorumKey{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::Quorum}; + CDataStructureV0 quorumKey{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::Quorum}; + CDataStructureV0 vocEmergencyQuorumKey{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::VOCEmergencyQuorum}; - return attributes->GetValue(QuorumKey, Params().GetConsensus().props.quorum); + if (type == CPropType::VoteOfConfidence && emergency) { + return attributes->GetValue(vocEmergencyQuorumKey, COIN / 10) / 10000; + } + + return attributes->GetValue(quorumKey, Params().GetConsensus().props.quorum) / 10000; } CAmount CCustomCSView::GetFeeBurnPctFromAttributes() const diff --git a/src/masternodes/masternodes.h b/src/masternodes/masternodes.h index 61cf8faa1e6..5c0ec328004 100644 --- a/src/masternodes/masternodes.h +++ b/src/masternodes/masternodes.h @@ -505,8 +505,8 @@ class CCustomCSView uint32_t GetVotingPeriodFromAttributes() const override; uint32_t GetEmergencyPeriodFromAttributes(const CPropType& type) const override; - CAmount GetMajorityFromAttributes(const CPropType& type) const override; - CAmount GetQuorumFromAttributes() const override; + CAmount GetApprovalThresholdFromAttributes(const CPropType& type) const override; + CAmount GetQuorumFromAttributes(const CPropType& type, bool emergency = false) const override; CAmount GetFeeBurnPctFromAttributes() const override; struct DbVersion { static constexpr uint8_t prefix() { return 'D'; } }; diff --git a/src/masternodes/proposals.cpp b/src/masternodes/proposals.cpp index c5f555073c0..e946c3fcf03 100644 --- a/src/masternodes/proposals.cpp +++ b/src/masternodes/proposals.cpp @@ -51,8 +51,6 @@ Res CPropsView::CreateProp(const CPropId& propId, uint32_t height, const CCreate prop.creationHeight = height; prop.votingPeriod = (emergency ? GetEmergencyPeriodFromAttributes(type) : GetVotingPeriodFromAttributes()); - prop.majority = GetMajorityFromAttributes(type); - prop.quorum = GetQuorumFromAttributes(); prop.fee = fee; prop.feeBurnAmount = MultiplyAmounts(fee, GetFeeBurnPctFromAttributes()); diff --git a/src/masternodes/proposals.h b/src/masternodes/proposals.h index 2afbcebe2f4..98f592809ec 100644 --- a/src/masternodes/proposals.h +++ b/src/masternodes/proposals.h @@ -94,12 +94,9 @@ struct CPropObject : public CCreatePropMessage { uint32_t proposalEndHeight{}; uint32_t votingPeriod; - CAmount majority; - CAmount quorum; CAmount fee; CAmount feeBurnAmount; - // memory only CPropStatusType status{}; uint8_t cycle{}; @@ -114,8 +111,6 @@ struct CPropObject : public CCreatePropMessage { READWRITE(creationHeight); READWRITE(proposalEndHeight); READWRITE(votingPeriod); - READWRITE(majority); - READWRITE(quorum); READWRITE(fee); READWRITE(feeBurnAmount); } @@ -155,8 +150,8 @@ class CPropsView : public virtual CStorageView virtual uint32_t GetVotingPeriodFromAttributes() const = 0; virtual uint32_t GetEmergencyPeriodFromAttributes(const CPropType& type) const = 0; - virtual CAmount GetMajorityFromAttributes(const CPropType& type) const = 0; - virtual CAmount GetQuorumFromAttributes() const = 0; + virtual CAmount GetApprovalThresholdFromAttributes(const CPropType& type) const = 0; + virtual CAmount GetQuorumFromAttributes(const CPropType& type, bool emergency = false) const = 0; virtual CAmount GetFeeBurnPctFromAttributes() const = 0; struct ByType { static constexpr uint8_t prefix() { return 0x2B; } }; diff --git a/src/masternodes/rpc_customtx.cpp b/src/masternodes/rpc_customtx.cpp index c3241db07b5..e92a5d3ec9f 100644 --- a/src/masternodes/rpc_customtx.cpp +++ b/src/masternodes/rpc_customtx.cpp @@ -529,7 +529,7 @@ class CCustomTxRpcVisitor if (auto prop = mnview.GetProp(propId)) { proposalEndHeight = prop->proposalEndHeight; } else { - auto votingPeriod = (emergency ? mnview.GetEmergencyPeriodFromAttributes(type) : mnview.GetVotingPeriodFromAttributes()); + auto votingPeriod = prop->votingPeriod; proposalEndHeight = height + (votingPeriod - height % votingPeriod); for (uint8_t i = 1; i <= obj.nCycles; ++i) { proposalEndHeight += votingPeriod; diff --git a/src/masternodes/rpc_proposals.cpp b/src/masternodes/rpc_proposals.cpp index 2ff2ae221aa..3c49a186846 100644 --- a/src/masternodes/rpc_proposals.cpp +++ b/src/masternodes/rpc_proposals.cpp @@ -3,14 +3,18 @@ #include -UniValue propToJSON(CPropId const& propId, CPropObject const& prop) +UniValue propToJSON(CPropId const& propId, CPropObject const& prop, CCustomCSView const& view) { + auto type = static_cast(prop.type); + bool emergency = prop.options & CPropOption::Emergency; + auto approvalThreshold = view.GetApprovalThresholdFromAttributes(type); + auto quorum = view.GetQuorumFromAttributes(type, emergency); + UniValue ret(UniValue::VOBJ); ret.pushKV("proposalId", propId.GetHex()); ret.pushKV("title", prop.title); ret.pushKV("context", prop.context); ret.pushKV("contextHash", prop.contextHash); - auto type = static_cast(prop.type); ret.pushKV("type", CPropTypeToString(type)); auto status = static_cast(prop.status); ret.pushKV("status", CPropStatusToString(status)); @@ -20,6 +24,11 @@ UniValue propToJSON(CPropId const& propId, CPropObject const& prop) ret.pushKV("cycleEndHeight", static_cast(prop.cycleEndHeight)); ret.pushKV("proposalEndHeight", static_cast(prop.proposalEndHeight)); ret.pushKV("payoutAddress", ScriptToString(prop.address)); + ret.pushKV("votingPeriod", static_cast(prop.votingPeriod)); + ret.pushKV("approvalThreshold", strprintf("%d.%02d%%", approvalThreshold / 100, approvalThreshold % 100)); + ret.pushKV("quorum", strprintf("%d.%02d%%", quorum / 100, quorum % 100)); + ret.pushKV("fee", ValueFromAmount(prop.fee)); + ret.pushKV("feeBurnAmount", ValueFromAmount(prop.feeBurnAmount)); if (prop.options) { UniValue opt = UniValue(UniValue::VARR); @@ -402,26 +411,27 @@ UniValue votegov(const JSONRPCRequest& request) return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex(); } -UniValue listgovvotes(const JSONRPCRequest& request) +UniValue listgovproposalvotes(const JSONRPCRequest& request) { auto pwallet = GetWallet(request); - RPCHelpMan{"listgovvotes", + RPCHelpMan{"listgovproposalvotes", "\nReturns information about proposal votes.\n", { {"proposalId", RPCArg::Type::STR, RPCArg::Optional::NO, "The proposal id)"}, {"masternode", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "mine/all/id (default = mine)"}, + {"cycle", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "cycle: 0 (show current), cycle: N (show cycle N), cycle: -1 (show all) (default = 0)"} }, RPCResult{ "{id:{...},...} (array) Json object with proposal vote information\n" }, RPCExamples{ - HelpExampleCli("listgovvotes", "txid") - + HelpExampleRpc("listgovvotes", "txid") + HelpExampleCli("listgovproposalvotes", "txid") + + HelpExampleRpc("listgovproposalvotes", "txid") }, }.Check(request); - RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR}, true); + RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR, UniValue::VNUM}, true); auto propId = ParseHashV(request.params[0].get_str(), "proposalId"); @@ -436,14 +446,39 @@ UniValue listgovvotes(const JSONRPCRequest& request) mnId = ParseHashV(str, "masternode"); } } + CCustomCSView view(*pcustomcsview); + + uint8_t cycle{1}; + int8_t inputCycle{0}; + if (request.params.size() > 2) { + inputCycle = request.params[2].get_int(); + } + if (inputCycle==0){ + auto prop = view.GetProp(propId); + if (!prop){ + throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Proposal <%s> does not exist", propId.GetHex())); + } + cycle = prop->cycle; + } else if (inputCycle > 0){ + cycle = inputCycle; + } else if (inputCycle == -1){ + cycle = 1; + } else { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Incorrect cycle value"); + } UniValue ret(UniValue::VARR); - CCustomCSView view(*pcustomcsview); - view.ForEachPropVote([&](CPropId const & pId, uint8_t cycle, uint256 const & id, CPropVoteType vote) { + view.ForEachPropVote([&](CPropId const & pId, uint8_t propCycle, uint256 const & id, CPropVoteType vote) { + if (pId != propId) { return false; } + + if(inputCycle != -1 && cycle != propCycle){ + return false; + } + if (isMine) { auto node = view.GetMasternode(id); if (!node) { @@ -452,13 +487,13 @@ UniValue listgovvotes(const JSONRPCRequest& request) auto ownerDest = node->ownerType == 1 ? CTxDestination(PKHash(node->ownerAuthAddress)) : CTxDestination(WitnessV0KeyHash(node->ownerAuthAddress)); if (::IsMineCached(*pwallet, GetScriptForDestination(ownerDest))) { - ret.push_back(propVoteToJSON(propId, cycle, id, vote)); + ret.push_back(propVoteToJSON(propId, propCycle, id, vote)); } } else if (mnId.IsNull() || mnId == id) { - ret.push_back(propVoteToJSON(propId, cycle, id, vote)); + ret.push_back(propVoteToJSON(propId, propCycle, id, vote)); } return true; - }, CMnVotePerCycle{propId, 1, mnId}); + }, CMnVotePerCycle{propId, cycle, mnId}); return ret; } @@ -489,9 +524,6 @@ UniValue getgovproposal(const JSONRPCRequest& request) if (!prop) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Proposal <%s> does not exist", propId.GetHex())); } - if (prop->status != CPropStatusType::Voting) { - return propToJSON(propId, *prop); - } int targetHeight; if (prop->status == CPropStatusType::Voting) { @@ -509,7 +541,7 @@ UniValue getgovproposal(const JSONRPCRequest& request) }); if (activeMasternodes.empty()) { - return propToJSON(propId, *prop); + return propToJSON(propId, *prop, view); } uint32_t voteYes = 0, voters = 0; @@ -527,31 +559,18 @@ UniValue getgovproposal(const JSONRPCRequest& request) }, CMnVotePerCycle{propId, prop->cycle}); if (!voters) { - return propToJSON(propId, *prop); + return propToJSON(propId, *prop, view); } - uint32_t majorityThreshold = 0, votes = 0; + uint32_t votes = 0; + auto type = static_cast(prop->type); + bool emergency = prop->options & CPropOption::Emergency; + auto approvalThreshold = view.GetApprovalThresholdFromAttributes(type); + auto quorum = view.GetQuorumFromAttributes(type, emergency); auto allVotes = lround(voters * 10000.f / activeMasternodes.size()); - CDataStructureV0 cfpMajority{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::CFPMajority}; - CDataStructureV0 vocMajority{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::VOCMajority}; - CDataStructureV0 quorumKey{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::Quorum}; - - auto attributes = view.GetAttributes(); - if (!attributes) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Attributes access failure"); - - auto quorum = attributes->GetValue(quorumKey, Params().GetConsensus().props.quorum) / 10000; auto valid = allVotes > quorum; if (valid) { - switch(prop->type) { - case CPropType::CommunityFundProposal: - majorityThreshold = attributes->GetValue(cfpMajority, Params().GetConsensus().props.cfp.majorityThreshold) / 10000; - break; - case CPropType::VoteOfConfidence: - majorityThreshold = attributes->GetValue(vocMajority, Params().GetConsensus().props.voc.majorityThreshold) / 10000; - break; - } votes = lround(voteYes * 10000.f / voters); } @@ -560,9 +579,8 @@ UniValue getgovproposal(const JSONRPCRequest& request) ret.pushKV("title", prop->title); ret.pushKV("context", prop->context); ret.pushKV("contextHash", prop->contextHash); - auto type = static_cast(prop->type); ret.pushKV("type", CPropTypeToString(type)); - if (valid && votes >= majorityThreshold) { + if (valid && votes >= approvalThreshold) { ret.pushKV("status", "Approved"); } else { ret.pushKV("status", "Rejected"); @@ -572,6 +590,11 @@ UniValue getgovproposal(const JSONRPCRequest& request) ret.pushKV("cycleEndHeight", static_cast(prop->cycleEndHeight)); ret.pushKV("proposalEndHeight", static_cast(prop->proposalEndHeight)); ret.pushKV("payoutAddress", ScriptToString(prop->address)); + ret.pushKV("votingPeriod", static_cast(prop->votingPeriod)); + ret.pushKV("approvalThreshold", strprintf("%d.%02d%%", approvalThreshold / 100, approvalThreshold % 100)); + ret.pushKV("quorum", strprintf("%d.%02d%%", quorum / 100, quorum % 100)); + ret.pushKV("fee", ValueFromAmount(prop->fee)); + ret.pushKV("feeBurnAmount", ValueFromAmount(prop->feeBurnAmount)); if (prop->options) { @@ -585,9 +608,10 @@ UniValue getgovproposal(const JSONRPCRequest& request) ret.pushKV("options", array); } - ret.pushKV("votes", strprintf("%d.%02d of %d.%02d%%", votes / 100, votes % 100, majorityThreshold / 100, majorityThreshold % 100)); + ret.pushKV("votes", strprintf("%d.%02d of %d.%02d%%", votes / 100, votes % 100, approvalThreshold / 100, approvalThreshold % 100)); ret.pushKV("votingPercent", strprintf("%d.%02d of %d.%02d%%", allVotes / 100, allVotes % 100, quorum / 100, quorum % 100)); + return ret; } @@ -599,7 +623,7 @@ UniValue listgovproposals(const JSONRPCRequest& request) {"type", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "cfp/voc/all (default = all)"}, {"status", RPCArg::Type::STR, RPCArg::Optional::OMITTED, - "voting/rejected/completed/all (default = all)"}, + "voting/rejected/completed/all (default = all)"} }, RPCResult{ "{id:{...},...} (array) Json object with proposals information\n" @@ -624,7 +648,7 @@ UniValue listgovproposals(const JSONRPCRequest& request) } } - uint8_t status = 0; + uint8_t status{0}; if (request.params.size() > 1) { auto str = request.params[1].get_str(); if (str == "voting") { @@ -648,7 +672,7 @@ UniValue listgovproposals(const JSONRPCRequest& request) if (type && type != uint8_t(prop.type)) { return true; } - ret.push_back(propToJSON(propId, prop)); + ret.push_back(propToJSON(propId, prop, view)); return true; }, status); @@ -662,7 +686,7 @@ static const CRPCCommand commands[] = {"proposals", "creategovcfp", &creategovcfp, {"data", "inputs"} }, {"proposals", "creategovvoc", &creategovvoc, {"data", "inputs"} }, {"proposals", "votegov", &votegov, {"proposalId", "masternodeId", "decision", "inputs"} }, - {"proposals", "listgovvotes", &listgovvotes, {"proposalId", "masternode"} }, + {"proposals", "listgovproposalvotes", &listgovproposalvotes, {"proposalId", "masternode", "cycle"} }, {"proposals", "getgovproposal", &getgovproposal, {"proposalId"} }, {"proposals", "listgovproposals", &listgovproposals, {"type", "status"} }, }; diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 0985c96f131..77289612ad1 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -355,7 +355,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "creategovcfp", 1, "inputs" }, { "creategovvoc", 0, "data" }, { "creategovvoc", 1, "inputs" }, - { "votegov", 3, "inputs" }, + { "listgovproposalvotes", 2, "cycle" }, }; // clang-format on diff --git a/src/validation.cpp b/src/validation.cpp index a74524070e0..a6b2316a862 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4270,36 +4270,19 @@ void CChainState::ProcessProposalEvents(const CBlockIndex* pindex, CCustomCSView } } - CDataStructureV0 quorumKey{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::Quorum}; - CDataStructureV0 vocEmergencyQuorumKey{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::VOCEmergencyQuorum}; - + auto type = static_cast(prop.type); bool emergency = prop.options & CPropOption::Emergency; - uint64_t quorum; - if (prop.type == CPropType::VoteOfConfidence && emergency) { - quorum = attributes->GetValue(vocEmergencyQuorumKey, COIN / 10) / 10000; - } else { - quorum = attributes->GetValue(quorumKey, chainparams.GetConsensus().props.quorum) / 10000; - } + + auto quorum = cache.GetQuorumFromAttributes(type, emergency); if (lround(voters.size() * 10000.f / activeMasternodes.size()) <= quorum) { cache.UpdatePropStatus(propId, pindex->nHeight, CPropStatusType::Rejected); return true; } - uint32_t majorityThreshold{}; - CDataStructureV0 cfpMajority{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::CFPMajority}; - CDataStructureV0 vocMajority{AttributeTypes::Governance, GovernanceIDs::Proposals, GovernanceKeys::VOCMajority}; - - switch(prop.type) { - case CPropType::CommunityFundProposal: - majorityThreshold = attributes->GetValue(cfpMajority, chainparams.GetConsensus().props.cfp.majorityThreshold) / 10000; - break; - case CPropType::VoteOfConfidence: - majorityThreshold = attributes->GetValue(vocMajority, chainparams.GetConsensus().props.voc.majorityThreshold) / 10000; - break; - } + auto approvalThreshold = cache.GetApprovalThresholdFromAttributes(type) / 10000; - if (lround(voteYes * 10000.f / voters.size()) <= majorityThreshold) { + if (lround(voteYes * 10000.f / voters.size()) <= approvalThreshold) { cache.UpdatePropStatus(propId, pindex->nHeight, CPropStatusType::Rejected); return true; } diff --git a/test/functional/feature_on_chain_government.py b/test/functional/feature_on_chain_government.py index 3e04fafc504..6e92e62ee47 100755 --- a/test/functional/feature_on_chain_government.py +++ b/test/functional/feature_on_chain_government.py @@ -164,25 +164,27 @@ def run_test(self): assert_equal(result[0]["payoutAddress"], address) assert_equal(result[0]["proposalEndHeight"], proposalEndHeight) assert_equal(result[0]["cycleEndHeight"], cycle1) + assert_equal(result[0]["approvalThreshold"], "50.00%") + assert_equal(result[0]["quorum"], "1.00%") # Check individual MN votes - results = self.nodes[1].listgovvotes(tx, mn0) + results = self.nodes[1].listgovproposalvotes(tx, mn0) assert_equal(len(results), 1) result = results[0] assert_equal(result['vote'], 'YES') - results = self.nodes[1].listgovvotes(tx, mn1) + results = self.nodes[1].listgovproposalvotes(tx, mn1) assert_equal(len(results), 1) result = results[0] assert_equal(result['vote'], 'NO') - results = self.nodes[1].listgovvotes(tx, mn2) + results = self.nodes[1].listgovproposalvotes(tx, mn2) assert_equal(len(results), 1) result = results[0] assert_equal(result['vote'], 'YES') # Check total votes - result = self.nodes[1].listgovvotes(tx, "all") + result = self.nodes[1].listgovproposalvotes(tx, "all") assert_equal(len(result), 3) # Move to just before cycle payout @@ -353,25 +355,27 @@ def run_test(self): assert_equal(result[0]["payoutAddress"], address) assert_equal(result[0]["proposalEndHeight"], proposalEndHeight) assert_equal(result[0]["cycleEndHeight"], cycle1) + assert_equal(result[0]["approvalThreshold"], "50.00%") + assert_equal(result[0]["quorum"], "1.00%") # Check individual MN votes - results = self.nodes[1].listgovvotes(propId, mn0) + results = self.nodes[1].listgovproposalvotes(propId, mn0) assert_equal(len(results), 1) result = results[0] assert_equal(result['vote'], 'YES') - results = self.nodes[1].listgovvotes(propId, mn1) + results = self.nodes[1].listgovproposalvotes(propId, mn1) assert_equal(len(results), 1) result = results[0] assert_equal(result['vote'], 'NO') - results = self.nodes[1].listgovvotes(propId, mn2) + results = self.nodes[1].listgovproposalvotes(propId, mn2) assert_equal(len(results), 1) result = results[0] assert_equal(result['vote'], 'YES') # Check total votes - result = self.nodes[1].listgovvotes(propId, "all") + result = self.nodes[1].listgovproposalvotes(propId, "all") assert_equal(len(result), 3) # Move to just before cycle payout @@ -395,6 +399,26 @@ def run_test(self): assert_equal(result["currentCycle"], 2) assert_equal(result["cycleEndHeight"], cycle2) + # vote cycle 2 + self.nodes[0].votegov(propId, mn0, "no") + self.nodes[0].generate(1) + + listvotes = self.nodes[0].listgovproposalvotes(propId) + assert_equal(len(listvotes), 1) + listvotes = self.nodes[0].listgovproposalvotes(propId, 'all', 0) + assert_equal(len(listvotes), 1) + listvotes = self.nodes[0].listgovproposalvotes(propId, 'all', -1) + assert_equal(len(listvotes), 4) + listvotes = self.nodes[0].listgovproposalvotes(propId, 'all', 1) + assert_equal(len(listvotes), 3) + listvotes = self.nodes[0].listgovproposalvotes(propId, mn0, -1) + assert_equal(len(listvotes), 2) + listvotes = self.nodes[0].listgovproposalvotes(propId, mn0, 2) + assert_equal(len(listvotes), 1) + listvotes = self.nodes[0].listgovproposalvotes(propId, 'all', 2) + assert_equal(len(listvotes), 1) + + # Move to just before final height self.nodes[0].generate(proposalEndHeight - self.nodes[0].getblockcount() - 1) bal = self.nodes[0].listcommunitybalances()['CommunityDevelopmentFunds'] @@ -425,7 +449,7 @@ def run_test(self): 'v0/params/feature/gov-payout':'true', 'v0/gov/proposals/voc_emergency_period': f'{emergencyPeriod}', 'v0/gov/proposals/voc_emergency_fee':'20.00000000', - 'v0/gov/proposals/voc_required_votes':'0.4999' + 'v0/gov/proposals/voc_required_votes':'49.99%' }}) self.nodes[0].generate(1) self.sync_blocks() @@ -473,9 +497,11 @@ def run_test(self): assert_equal(result["cycleEndHeight"], cycle1) assert_equal(result["payoutAddress"], '') assert_equal(result["totalCycles"], 1) - assert_equal(result["votingPercent"], "100.00 of 1.00%") + assert_equal(result["votingPercent"], "100.00 of 10.00%") assert_equal(result["options"], ["Emergency"]) assert_equal(result["proposalEndHeight"], proposalEndHeight) + assert_equal(result["approvalThreshold"], "49.99%") + assert_equal(result["quorum"], "10.00%") assert_equal(len(self.nodes[0].listgovproposals("all", "voting")), 1) assert_equal(len(self.nodes[0].listgovproposals("all", "completed")), 0) diff --git a/test/functional/feature_on_chain_government_fee_distribution.py b/test/functional/feature_on_chain_government_fee_distribution.py index 71c1a4738e7..f18759fabc7 100755 --- a/test/functional/feature_on_chain_government_fee_distribution.py +++ b/test/functional/feature_on_chain_government_fee_distribution.py @@ -70,7 +70,7 @@ def test_cfp_fee_distribution(self, amount, expectedFee, burnPct, vote, cycles=2 finalHeight = cycle1 + (cycle1 % 70) + 70 # Check total votes - result = self.nodes[0].listgovvotes(propId, "all") + result = self.nodes[0].listgovproposalvotes(propId, "all") assert_equal(len(result), 3) # Move to final height