neobytes/src/rpcmasternode-budget.cpp

439 lines
17 KiB
C++

// 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"
#include "governance.h"
#include "masternode-payments.h"
#include "masternode-sync.h"
#include "masternodeconfig.h"
#include "masternodeman.h"
#include "rpcserver.h"
#include "utilmoneystr.h"
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <univalue.h>
#include <iostream>
#include <sstream>
using namespace std;
/**
* 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
* >> fee transaction hash
*
* governance submit fee-hash nTypeIn nParentID, "name", epoch-start, epoch-end, fee-hash, register1, register2, register3
* >> 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
*
* governance get hash
* >> show one proposal
*
*/
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"
" vote-alias - Vote on a proposal by masternode alias\n"
);
if(strCommand == "prepare")
{
if (params.size() != 7)
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();
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
uint256 hashParent = ParseHashV(params[0], "parameter 1");
int nRevision = params[1].get_int();
int nTime = params[2].get_int();
std::string strName = SanitizeString(params[3].get_str());
if(strName != params[1].get_str())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Name is invalid");
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());
std::string strError = "";
if(!budgetProposalBroadcast.IsValid(pindex, strError, false))
throw JSONRPCError(RPC_INTERNAL_ERROR, "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError);
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)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance submit <parent-hash> <revision> <time> <name> <registers-hex>'");
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();
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
uint256 hashParent = ParseHashV(params[0], "parameter 1");
int nRevision = params[1].get_int();
int nTime = params[2].get_int();
std::string strName = SanitizeString(params[3].get_str());
if(strName != params[1].get_str())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Name is invalid");
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);
// }
governance.mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
budgetProposalBroadcast.Relay();
governance.AddProposal(budgetProposalBroadcast);
return budgetProposalBroadcast.GetHash().ToString();
}
if(strCommand == "vote-alias")
{
if(params.size() != 4)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance vote-alias <object-hash> <vote-action> [yes|no|abstain] <alias-name>'");
uint256 hash;
std::string strVote;
hash = ParseHashV(params[1], "Object hash");
strVote = params[2].get_str();
std::string strAlias = params[3].get_str();
int nVoteAction = params[4].get_int();
int nVoteOutcome = VOTE_OUTCOME_NONE;
if(strVote == "yes") nVoteOutcome = VOTE_OUTCOME_YES;
if(strVote == "no") nVoteOutcome = VOTE_OUTCOME_NO;
if(strVote == "abstain") nVoteOutcome = VOTE_OUTCOME_ABSTAIN;
if(nVoteOutcome == VOTE_OUTCOME_NONE)
throw JSONRPCError(RPC_INVALID_PARAMETER, "You can only vote 'yes', 'no' or 'abstain'");
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;
}
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 = "";
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]'");
std::string strShow = "valid";
if (params.size() == 2) strShow = params[1].get_str();
UniValue resultObj(UniValue::VOBJ);
CBlockIndex* pindex;
{
LOCK(cs_main);
pindex = chainActive.Tip();
}
std::vector<CGovernanceObject*> winningProps = governance.GetAllProposals(governance.GetLastDiffTime());
governance.UpdateLastDiffTime(GetTime());
BOOST_FOREACH(CGovernanceObject* pbudgetProposal, winningProps)
{
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()));
// bObj.push_back(Pair("StartTime", (int64_t)pbudgetProposal->GetStartTime()));
// bObj.push_back(Pair("EndTime", (int64_t)pbudgetProposal->GetEndTime()));
// 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");
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("StartTime", (int64_t)pbudgetProposal->GetStartTime()));
// obj.push_back(Pair("EndTime", (int64_t)pbudgetProposal->GetEndTime()));
// obj.push_back(Pair("AbsoluteYesCount", (int64_t)pbudgetProposal->GetYesCount()-(int64_t)pbudgetProposal->GetNoCount()));
// obj.push_back(Pair("YesCount", (int64_t)pbudgetProposal->GetYesCount()));
// obj.push_back(Pair("NoCount", (int64_t)pbudgetProposal->GetNoCount()));
// obj.push_back(Pair("AbstainCount", (int64_t)pbudgetProposal->GetAbstainCount()));
obj.push_back(Pair("IsEstablished", pbudgetProposal->IsEstablished()));
std::string strError = "";
obj.push_back(Pair("IsValid", pbudgetProposal->IsValid(chainActive.Tip(), strError)));
obj.push_back(Pair("fValid", pbudgetProposal->fValid));
return obj;
}
if(strCommand == "getvotes")
{
if (params.size() != 2)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Correct usage is 'mngovernance getvotes <proposal-hash>'");
uint256 hash = ParseHashV(params[1], "Proposal hash");
UniValue obj(UniValue::VOBJ);
CGovernanceObject* pbudgetProposal = governance.FindProposal(hash);
if(pbudgetProposal == NULL)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown proposal");
// 12.1 - rewrite
// std::map<uint256, CBudgetVote>::iterator it = pbudgetProposal->mapVotes.begin();
// while(it != pbudgetProposal->mapVotes.end()){
// UniValue bObj(UniValue::VOBJ);
// bObj.push_back(Pair("nHash", (*it).first.ToString().c_str()));
// bObj.push_back(Pair("Vote", (*it).second.GetVoteString()));
// bObj.push_back(Pair("nTime", (int64_t)(*it).second.nTime));
// bObj.push_back(Pair("fValid", (*it).second.fValid));
// obj.push_back(Pair((*it).second.vin.prevout.ToStringShort(), bObj));
// it++;
// }
return obj;
}
return NullUniValue;
}
UniValue mngovernancevoteraw(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 6)
throw runtime_error(
"mngovernancevoteraw <masternode-tx-hash> <masternode-tx-index> <proposal-hash> [yes|no] <time> <vote-sig>\n"
"Compile and relay a proposal vote with provided external signature instead of signing vote internally\n"
);
uint256 hashMnTx = ParseHashV(params[0], "mn tx hash");
int nMnTxIndex = params[1].get_int();
CTxIn vin = CTxIn(hashMnTx, nMnTxIndex);
uint256 hashProposal = ParseHashV(params[2], "Proposal hash");
std::string strVote = params[3].get_str();
int nVote = VOTE_OUTCOME_NONE;
if(strVote == "yes") nVote = VOTE_OUTCOME_YES;
if(strVote == "no") nVote = VOTE_OUTCOME_NO;
if(strVote == "abstain") nVote = VOTE_OUTCOME_ABSTAIN;
if(nVote == VOTE_OUTCOME_NONE)
throw JSONRPCError(RPC_INVALID_PARAMETER, "You can only vote 'yes', 'no' or 'abstain'");
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());
}
CBudgetVote vote(vin, hashProposal, nVote, VOTE_ACTION_NONE);
vote.nTime = nTime;
vote.vchSig = vchSig;
if(!vote.IsValid(true)){
throw JSONRPCError(RPC_INTERNAL_ERROR, "Failure to verify vote.");
}
std::string strError = "";
if(governance.UpdateProposal(vote, NULL, strError)){
governance.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
return "Voted successfully";
} else {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Error voting : " + strError);
}
}