neobytes/src/rpcmasternode-budget.cpp

470 lines
19 KiB
C++
Raw Normal View History

// Copyright (c) 2014-2016 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "main.h"
#include "db.h"
#include "init.h"
#include "activemasternode.h"
2016-04-15 04:54:11 +02:00
#include "governance.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
#include "masternodeconfig.h"
#include "masternodeman.h"
#include "rpcserver.h"
#include "utilmoneystr.h"
2016-01-28 20:33:10 +01:00
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <univalue.h>
#include <iostream>
#include <sstream>
using namespace std;
int ConvertVoteAction(std::string strVoteAction)
{
int nVote = -1;
if(strVoteAction == "yes") nVote = VOTE_OUTCOME_YES;
if(strVoteAction == "no") nVote = VOTE_OUTCOME_NO;
if(strVoteAction == "abstain") nVote = VOTE_OUTCOME_ABSTAIN;
if(strVoteAction == "none") nVote = VOTE_OUTCOME_NONE;
return nVote;
}
int ConvertVoteOutcome(std::string strVoteOutcome)
{
if(strVoteOutcome == "none") return 0;
if(strVoteOutcome == "funding") return 1;
if(strVoteOutcome == "valid") return 2;
if(strVoteOutcome == "delete") return 3;
if(strVoteOutcome == "clear_registers") return 4;
if(strVoteOutcome == "endorsed") return 5;
if(strVoteOutcome == "release_bounty1") return 6;
if(strVoteOutcome == "release_bounty2") return 7;
if(strVoteOutcome == "release_bounty3") return 8;
// convert custom sentinel outcomes to integer and store
try {
int i = std::stoi(strVoteOutcome);
if(i < VOTE_ACTION_CUSTOM_START || i > VOTE_ACTION_CUSTOM_END) return -1;
return i;
}
catch(std::exception const & e)
{
cout<<"error : " << e.what() <<endl;
}
return -1;
}
2016-04-17 02:29:41 +02:00
/**
* NOTE: 12.1 - code needs to be rewritten, much of it's in the incorrect context
*
* Governance Object Creation and Voting
* -------------------------------------------------------
*
* This code allows users to create new types of objects. To correctly use the system
* please see the governance wiki and code-as-law implementation. Any conflicting entries will be
* automatically downvoted and deleted, requiring resubmission to correct.
*
* command structure:
*
* For instructions on creating registers, see dashbrain
*
*
* governance prepare new nTypeIn nParentID "name" epoch-start epoch-end register1 register2 register3
2016-04-17 02:29:41 +02:00
* >> fee transaction hash
*
* governance submit fee-hash nTypeIn nParentID, "name", epoch-start, epoch-end, fee-hash, register1, register2, register3
2016-04-17 02:29:41 +02:00
* >> governance object hash
*
* governance vote(-alias|many) type hash yes|no|abstain
* >> success|failure
*
* governance list
* >> flat data representation of the governance system
* >> NOTE: this shouldn't be altered, we'll analyze the system outside of this project
2016-04-17 02:29:41 +02:00
*
* governance get hash
* >> show one proposal
2016-04-17 02:29:41 +02:00
*
*/
UniValue mngovernance(const UniValue& params, bool fHelp)
{
string strCommand;
if (params.size() >= 1)
strCommand = params[0].get_str();
if (fHelp ||
(strCommand != "vote-many" && strCommand != "vote-alias" && strCommand != "prepare" && strCommand != "submit" &&
strCommand != "vote" && strCommand != "get" && strCommand != "list" && strCommand != "diff"))
throw runtime_error(
"mngovernance \"command\"...\n"
"Manage proposals\n"
"\nAvailable commands:\n"
" prepare - Prepare proposal by signing and creating tx\n"
" submit - Submit proposal to network\n"
" get - Get proposal hash(es) by proposal name\n"
" list - List all proposals\n"
" diff - List differences since last diff\n"
2016-04-26 06:08:36 +02:00
" vote-alias - Vote on a proposal by masternode alias\n"
);
if(strCommand == "prepare")
{
if (params.size() != 7)
2016-04-26 06:08:36 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance prepare <parent-hash> <revision> <time> <name> <registers-hex>'");
int nBlockMin = 0;
LOCK(cs_main);
CBlockIndex* pindex = chainActive.Tip();
2015-05-04 11:31:31 +02:00
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
2016-04-26 06:08:36 +02:00
uint256 hashParent = ParseHashV(params[0], "parameter 1");
int nRevision = params[1].get_int();
int nTime = params[2].get_int();
2016-04-26 06:08:36 +02:00
std::string strName = SanitizeString(params[3].get_str());
if(strName != params[1].get_str())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Name is invalid");
2016-04-26 06:08:36 +02:00
std::string strRegisters = params[4].get_str();
//*************************************************************************
// create transaction 15 minutes into the future, to allow for confirmation time
CGovernanceObject budgetProposalBroadcast(hashParent, nRevision, strName, nTime, uint256());
2015-07-14 16:05:33 +02:00
std::string strError = "";
if(!budgetProposalBroadcast.IsValid(pindex, strError, false))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError);
2015-07-14 16:05:33 +02:00
CWalletTx wtx;
if(!pwalletMain->GetBudgetSystemCollateralTX(wtx, budgetProposalBroadcast.GetHash(), false)){
throw JSONRPCError(RPC_INTERNAL_ERROR, "Error making collateral transaction for proposal. Please check your wallet balance and make sure your wallet is unlocked.");
}
// make our change address
CReserveKey reservekey(pwalletMain);
//send the tx to the network
pwalletMain->CommitTransaction(wtx, reservekey, NetMsgType::TX);
return wtx.GetHash().ToString();
}
if(strCommand == "submit")
{
if (params.size() != 8)
2016-04-26 06:08:36 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance submit <parent-hash> <revision> <time> <name> <registers-hex>'");
2016-04-26 06:08:36 +02:00
if(!masternodeSync.IsBlockchainSynced()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Must wait for client to sync with masternode network. Try again in a minute or so.");
}
int nBlockMin = 0;
LOCK(cs_main);
CBlockIndex* pindex = chainActive.Tip();
2015-05-04 11:31:31 +02:00
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
2016-04-26 06:08:36 +02:00
uint256 hashParent = ParseHashV(params[0], "parameter 1");
int nRevision = params[1].get_int();
int nTime = params[2].get_int();
2016-04-26 06:08:36 +02:00
std::string strName = SanitizeString(params[3].get_str());
if(strName != params[1].get_str())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Name is invalid");
2016-04-26 06:08:36 +02:00
std::string strRegisters = params[4].get_str();
// CGovernanceObject budgetProposalBroadcast(strName, GetTime(), 253370764800, uint256());
CGovernanceObject budgetProposalBroadcast(hashParent, nRevision, strName, nTime, uint256());
std::string strError = "";
if(!budgetProposalBroadcast.IsValid(pindex, strError)){
throw JSONRPCError(RPC_INTERNAL_ERROR, "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError);
}
// int nConf = 0;
// if(!IsCollateralValid(hash, budgetProposalBroadcast.GetHash(), strError, budgetProposalBroadcast.nTime, nConf, GOVERNANCE_FEE_TX)){
// throw JSONRPCError(RPC_INTERNAL_ERROR, "Proposal FeeTX is not valid - " + hash.ToString() + " - " + strError);
// }
2016-04-10 16:46:19 +02:00
governance.mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
budgetProposalBroadcast.Relay();
2016-04-10 16:46:19 +02:00
governance.AddProposal(budgetProposalBroadcast);
return budgetProposalBroadcast.GetHash().ToString();
}
if(strCommand == "vote-alias")
{
if(params.size() != 4)
2016-04-26 20:36:07 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance vote-alias <governance-hash> <vote-action> [yes|no|abstain] <alias-name>'");
uint256 hash;
std::string strVote;
2016-04-26 06:08:36 +02:00
hash = ParseHashV(params[1], "Object hash");
strVote = params[2].get_str();
std::string strAlias = params[3].get_str();
std::string strVoteAction = params[4].get_str();
std::string strVoteOutcome = params[5].get_str();
int nVoteAction = ConvertVoteAction(strVoteAction);
if(nVoteAction == VOTE_OUTCOME_NONE || nVoteAction == -1)
2016-04-26 20:36:07 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'");
int nVoteOutcome = ConvertVoteOutcome(strVoteOutcome);
if(nVoteOutcome == VOTE_OUTCOME_NONE || nVoteAction == -1)
2016-04-26 20:36:07 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote action. Please using one of the following: (funding|valid|delete|clear_registers|endorsed|release_bounty1|release_bounty2|release_bounty3) OR `custom sentinel code` ");
int success = 0;
int failed = 0;
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
UniValue resultsObj(UniValue::VOBJ);
BOOST_FOREACH(CMasternodeConfig::CMasternodeEntry mne, masternodeConfig.getEntries()) {
if( strAlias != mne.getAlias()) continue;
std::string errorMessage;
std::vector<unsigned char> vchMasterNodeSignature;
std::string strMasterNodeSignMessage;
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
CPubKey pubKeyMasternode;
CKey keyMasternode;
UniValue statusObj(UniValue::VOBJ);
if(!darkSendSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
failed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Masternode signing error, could not set key correctly: " + errorMessage));
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
continue;
}
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
if(pmn == NULL)
{
failed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Can't find masternode by pubkey"));
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
continue;
}
2016-04-26 06:08:36 +02:00
CBudgetVote vote(pmn->vin, hash, nVoteOutcome, nVoteAction);
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
failed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("errorMessage", "Failure to sign."));
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
continue;
}
std::string strError = "";
2016-04-10 16:46:19 +02:00
if(governance.UpdateProposal(vote, NULL, strError)) {
governance.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
success++;
statusObj.push_back(Pair("result", "success"));
} else {
failed++;
statusObj.push_back(Pair("result", strError.c_str()));
}
resultsObj.push_back(Pair(mne.getAlias(), statusObj));
}
UniValue returnObj(UniValue::VOBJ);
returnObj.push_back(Pair("overall", strprintf("Voted successfully %d time(s) and failed %d time(s).", success, failed)));
returnObj.push_back(Pair("detail", resultsObj));
return returnObj;
}
if(strCommand == "list" || strCommand == "diff")
{
if (params.size() > 2)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance list [valid]'");
2015-07-15 00:52:07 +02:00
std::string strShow = "valid";
if (params.size() == 2) strShow = params[1].get_str();
2016-04-15 04:14:27 +02:00
UniValue resultObj(UniValue::VOBJ);
CBlockIndex* pindex;
{
LOCK(cs_main);
pindex = chainActive.Tip();
}
std::vector<CGovernanceObject*> winningProps = governance.GetAllProposals(governance.GetLastDiffTime());
governance.UpdateLastDiffTime(GetTime());
2016-04-16 19:19:17 +02:00
BOOST_FOREACH(CGovernanceObject* pbudgetProposal, winningProps)
{
2015-07-15 00:52:07 +02:00
if(strShow == "valid" && !pbudgetProposal->fValid) continue;
UniValue bObj(UniValue::VOBJ);
bObj.push_back(Pair("Name", pbudgetProposal->GetName()));
bObj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString()));
bObj.push_back(Pair("FeeTXHash", pbudgetProposal->nFeeTXHash.ToString()));
2016-04-26 06:08:36 +02:00
// vote data for funding
bObj.push_back(Pair("AbsoluteYesCount", (int64_t)pbudgetProposal->GetYesCount(VOTE_ACTION_FUNDING)-(int64_t)pbudgetProposal->GetNoCount(VOTE_ACTION_FUNDING)));
bObj.push_back(Pair("YesCount", (int64_t)pbudgetProposal->GetYesCount(VOTE_ACTION_FUNDING)));
bObj.push_back(Pair("NoCount", (int64_t)pbudgetProposal->GetNoCount(VOTE_ACTION_FUNDING)));
bObj.push_back(Pair("AbstainCount", (int64_t)pbudgetProposal->GetAbstainCount(VOTE_ACTION_FUNDING)));
// bObj.push_back(Pair("IsEstablished", pbudgetProposal->IsEstablished(VOTE_ACTION_FUNDING)));
std::string strError = "";
bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(pindex, strError)));
bObj.push_back(Pair("IsValidReason", strError.c_str()));
bObj.push_back(Pair("fValid", pbudgetProposal->fValid));
resultObj.push_back(Pair(pbudgetProposal->GetName(), bObj));
}
return resultObj;
}
if(strCommand == "getproposal")
{
if (params.size() != 2)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance getproposal <proposal-hash>'");
uint256 hash = ParseHashV(params[1], "Proposal hash");
2016-04-16 19:19:17 +02:00
CGovernanceObject* pbudgetProposal = governance.FindProposal(hash);
if(pbudgetProposal == NULL)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown proposal");
CBlockIndex* pindex;
{
LOCK(cs_main);
pindex = chainActive.Tip();
}
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("Name", pbudgetProposal->GetName()));
obj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString()));
obj.push_back(Pair("FeeTXHash", pbudgetProposal->nFeeTXHash.ToString()));
obj.push_back(Pair("AbsoluteYesCount", (int64_t)pbudgetProposal->GetYesCount(VOTE_ACTION_FUNDING)-(int64_t)pbudgetProposal->GetNoCount(VOTE_ACTION_FUNDING)));
obj.push_back(Pair("YesCount", (int64_t)pbudgetProposal->GetYesCount(VOTE_ACTION_FUNDING)));
obj.push_back(Pair("NoCount", (int64_t)pbudgetProposal->GetNoCount(VOTE_ACTION_FUNDING)));
obj.push_back(Pair("AbstainCount", (int64_t)pbudgetProposal->GetAbstainCount(VOTE_ACTION_FUNDING)));
2015-07-07 00:06:09 +02:00
std::string strError = "";
obj.push_back(Pair("IsValid", pbudgetProposal->IsValid(chainActive.Tip(), strError)));
obj.push_back(Pair("fValid", pbudgetProposal->fValid));
2015-07-07 00:06:09 +02:00
return obj;
}
if(strCommand == "getvotes")
{
if (params.size() != 3)
throw runtime_error(
2016-04-26 20:34:53 +02:00
"Correct usage is 'mngovernance getvotes <governance-hash> <vote-outcome>'"
);
uint256 hash = ParseHashV(params[1], "Governance hash");
std::string strVoteOutcome = params[2].get_str();
int nVoteOutcome = ConvertVoteOutcome(strVoteOutcome);
if(nVoteOutcome == -1)
{
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please using one of the following: (funding|valid|delete|clear_registers|endorsed|release_bounty1|release_bounty2|release_bounty3) OR `custom sentinel code` ");
}
2016-04-16 19:19:17 +02:00
CGovernanceObject* pbudgetProposal = governance.FindProposal(hash);
if(pbudgetProposal == NULL)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown governance-hash");
2015-07-17 16:38:35 +02:00
UniValue bObj(UniValue::VOBJ);
bObj.push_back(Pair("AbsoluteYesCount", (int64_t)pbudgetProposal->GetYesCount(nVoteOutcome)-(int64_t)pbudgetProposal->GetNoCount(nVoteOutcome)));
bObj.push_back(Pair("YesCount", (int64_t)pbudgetProposal->GetYesCount(nVoteOutcome)));
bObj.push_back(Pair("NoCount", (int64_t)pbudgetProposal->GetNoCount(nVoteOutcome)));
bObj.push_back(Pair("AbstainCount", (int64_t)pbudgetProposal->GetAbstainCount(nVoteOutcome)));
2015-07-17 16:38:35 +02:00
return bObj;
}
return NullUniValue;
}
2016-05-05 19:44:46 +02:00
UniValue voteraw(const UniValue& params, bool fHelp)
2015-09-23 02:15:23 +02:00
{
if (fHelp || params.size() != 6)
throw runtime_error(
2016-05-05 19:44:46 +02:00
"voteraw <masternode-tx-hash> <masternode-tx-index> <governance-hash> <vote-outcome> [yes|no|abstain] <time> <vote-sig>\n"
"Compile and relay a governance vote with provided external signature instead of signing vote internally\n"
2015-09-23 02:15:23 +02:00
);
uint256 hashMnTx = ParseHashV(params[0], "mn tx hash");
int nMnTxIndex = params[1].get_int();
CTxIn vin = CTxIn(hashMnTx, nMnTxIndex);
2016-04-26 20:34:53 +02:00
uint256 hashProposal = ParseHashV(params[2], "Governance hash");
std::string strVoteAction = params[3].get_str();
std::string strVoteOutcome = params[4].get_str();
int nVoteAction = ConvertVoteAction(strVoteAction);
if(nVoteAction == VOTE_OUTCOME_NONE || nVoteAction == -1)
2016-04-26 20:36:07 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain'");
2016-04-26 20:34:53 +02:00
int nVoteOutcome = ConvertVoteOutcome(strVoteOutcome);
if(nVoteOutcome == VOTE_OUTCOME_NONE || nVoteAction == -1)
2016-04-26 20:36:07 +02:00
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid vote action. Please using one of the following: (funding|valid|delete|clear_registers|endorsed|release_bounty1|release_bounty2|release_bounty3) OR `custom sentinel code` ");
2015-09-23 02:15:23 +02:00
2016-04-15 04:14:27 +02:00
2015-09-23 02:15:23 +02:00
int64_t nTime = params[4].get_int64();
std::string strSig = params[5].get_str();
bool fInvalid = false;
vector<unsigned char> vchSig = DecodeBase64(strSig.c_str(), &fInvalid);
if (fInvalid)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
CMasternode* pmn = mnodeman.Find(vin);
if(pmn == NULL)
{
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failure to find masternode in list : " + vin.ToString());
2015-09-23 02:15:23 +02:00
}
2016-04-26 20:34:53 +02:00
CBudgetVote vote(vin, hashProposal, nVoteOutcome, VOTE_ACTION_NONE);
2015-09-23 02:15:23 +02:00
vote.nTime = nTime;
vote.vchSig = vchSig;
2016-03-06 16:44:58 +01:00
if(!vote.IsValid(true)){
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failure to verify vote.");
2015-09-23 02:15:23 +02:00
}
std::string strError = "";
2016-04-10 16:46:19 +02:00
if(governance.UpdateProposal(vote, NULL, strError)){
governance.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
2015-09-23 02:15:23 +02:00
vote.Relay();
return "Voted successfully";
} else {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Error voting : " + strError);
2015-09-23 02:15:23 +02:00
}
2016-04-14 23:28:33 +02:00
}