dash/src/governance-vote.cpp
Tim Flynn f76f6fbb8e Governance Fixes/Refactoring Pack (#995)
* Improved exception handling
 - Removed attempts to catch exceptions in intermediate helper function calls
 - Made helper functions for JSON parsing private

* Governance voting fixes
 - Converted voting defines to enums for better type safety
 - Enabled gobject voteraw rpc command
 - Removed unused parameter from gobject getvotes rpc command

* Fixed help message for gobject get

* Improved encapsulation of CGovernanceVote objects
 - CGovernanceVote data members are now private
 - Necessary to ensure that enum values are used for signals and outcomes since data members remain int's for compatibility with serialiation code

* Removed unused cs_budget mutex (has been replaced with governance.cs)

* Fix code review issues
 - Restored early return in ConvertVoteSignal
 - Removed special case for "none" string to make clear that NONE is
   for invalid strings
 - Removed commented defines (informational comments preserved)

* Fixed code review issues
 - Fixed error messages for vote-conf, vote-alias and voteraw
 - Removed voteraw from gobject command list and help messages because
   it is actually a top-level command
 - Fixed parameter indices for voteraw
2016-09-08 15:40:19 +04:00

306 lines
8.8 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 "core_io.h"
#include "main.h"
#include "init.h"
#include "flat-database.h"
#include "governance.h"
#include "masternode.h"
#include "governance.h"
#include "darksend.h"
#include "masternodeman.h"
#include "masternode-sync.h"
#include "util.h"
#include "addrman.h"
#include <boost/lexical_cast.hpp>
std::string CGovernanceVoting::ConvertOutcomeToString(vote_outcome_enum_t nOutcome)
{
switch(nOutcome)
{
case VOTE_OUTCOME_NONE:
return "NONE"; break;
case VOTE_OUTCOME_YES:
return "YES"; break;
case VOTE_OUTCOME_NO:
return "NO"; break;
case VOTE_OUTCOME_ABSTAIN:
return "ABSTAIN"; break;
}
return "error";
}
std::string CGovernanceVoting::ConvertSignalToString(vote_signal_enum_t nSignal)
{
string strReturn = "NONE";
switch(nSignal)
{
case VOTE_SIGNAL_NONE:
strReturn = "NONE";
break;
case VOTE_SIGNAL_FUNDING:
strReturn = "FUNDING";
break;
case VOTE_SIGNAL_VALID:
strReturn = "VALID";
break;
case VOTE_SIGNAL_DELETE:
strReturn = "DELETE";
break;
case VOTE_SIGNAL_ENDORSED:
strReturn = "ENDORSED";
break;
case VOTE_SIGNAL_NOOP1:
strReturn = "NOOP1";
break;
case VOTE_SIGNAL_NOOP2:
strReturn = "NOOP2";
break;
case VOTE_SIGNAL_NOOP3:
strReturn = "NOOP3";
break;
case VOTE_SIGNAL_NOOP4:
strReturn = "NOOP4";
break;
case VOTE_SIGNAL_NOOP5:
strReturn = "NOOP5";
break;
case VOTE_SIGNAL_NOOP6:
strReturn = "NOOP6";
break;
case VOTE_SIGNAL_NOOP7:
strReturn = "NOOP7";
break;
case VOTE_SIGNAL_NOOP8:
strReturn = "NOOP8";
break;
case VOTE_SIGNAL_NOOP9:
strReturn = "NOOP9";
break;
case VOTE_SIGNAL_NOOP10:
strReturn = "NOOP10";
break;
case VOTE_SIGNAL_NOOP11:
strReturn = "NOOP11";
break;
case VOTE_SIGNAL_CUSTOM1:
strReturn = "CUSTOM1";
break;
case VOTE_SIGNAL_CUSTOM2:
strReturn = "CUSTOM2";
break;
case VOTE_SIGNAL_CUSTOM3:
strReturn = "CUSTOM3";
break;
case VOTE_SIGNAL_CUSTOM4:
strReturn = "CUSTOM4";
break;
case VOTE_SIGNAL_CUSTOM5:
strReturn = "CUSTOM5";
break;
case VOTE_SIGNAL_CUSTOM6:
strReturn = "CUSTOM6";
break;
case VOTE_SIGNAL_CUSTOM7:
strReturn = "CUSTOM7";
break;
case VOTE_SIGNAL_CUSTOM8:
strReturn = "CUSTOM8";
break;
case VOTE_SIGNAL_CUSTOM9:
strReturn = "CUSTOM9";
break;
case VOTE_SIGNAL_CUSTOM10:
strReturn = "CUSTOM10";
break;
case VOTE_SIGNAL_CUSTOM11:
strReturn = "CUSTOM11";
break;
case VOTE_SIGNAL_CUSTOM12:
strReturn = "CUSTOM12";
break;
case VOTE_SIGNAL_CUSTOM13:
strReturn = "CUSTOM13";
break;
case VOTE_SIGNAL_CUSTOM14:
strReturn = "CUSTOM14";
break;
case VOTE_SIGNAL_CUSTOM15:
strReturn = "CUSTOM15";
break;
case VOTE_SIGNAL_CUSTOM16:
strReturn = "CUSTOM16";
break;
case VOTE_SIGNAL_CUSTOM17:
strReturn = "CUSTOM17";
break;
case VOTE_SIGNAL_CUSTOM18:
strReturn = "CUSTOM18";
break;
case VOTE_SIGNAL_CUSTOM19:
strReturn = "CUSTOM19";
break;
case VOTE_SIGNAL_CUSTOM20:
strReturn = "CUSTOM20";
break;
}
return strReturn;
}
vote_outcome_enum_t CGovernanceVoting::ConvertVoteOutcome(std::string strVoteOutcome)
{
vote_outcome_enum_t eVote = VOTE_OUTCOME_NONE;
if(strVoteOutcome == "yes") {
eVote = VOTE_OUTCOME_YES;
}
else if(strVoteOutcome == "no") {
eVote = VOTE_OUTCOME_NO;
}
else if(strVoteOutcome == "abstain") {
eVote = VOTE_OUTCOME_ABSTAIN;
}
return eVote;
}
vote_signal_enum_t CGovernanceVoting::ConvertVoteSignal(std::string strVoteSignal)
{
vote_signal_enum_t eSignal = VOTE_SIGNAL_NONE;
if(strVoteSignal == "funding") {
eSignal = VOTE_SIGNAL_FUNDING;
}
else if(strVoteSignal == "valid") {
eSignal = VOTE_SIGNAL_VALID;
}
if(strVoteSignal == "delete") {
eSignal = VOTE_SIGNAL_DELETE;
}
if(strVoteSignal == "endorsed") {
eSignal = VOTE_SIGNAL_ENDORSED;
}
if(eSignal != VOTE_SIGNAL_NONE) {
return eSignal;
}
// ID FIVE THROUGH CUSTOM_START ARE TO BE USED BY GOVERNANCE ENGINE / TRIGGER SYSTEM
// convert custom sentinel outcomes to integer and store
try {
int i = boost::lexical_cast<int>(strVoteSignal);
if(i < VOTE_SIGNAL_CUSTOM1 || i > VOTE_SIGNAL_CUSTOM20) {
eSignal = VOTE_SIGNAL_NONE;
}
else {
eSignal = vote_signal_enum_t(i);
}
}
catch(std::exception const & e)
{
ostringstream ostr;
ostr << "CGovernanceVote::ConvertVoteSignal: error : " << e.what() << endl;
LogPrintf(ostr.str().c_str());
}
return eSignal;
}
CGovernanceVote::CGovernanceVote()
: fValid(true),
fSynced(false),
nVoteSignal(int(VOTE_SIGNAL_NONE)),
vinMasternode(),
nParentHash(),
nVoteOutcome(int(VOTE_OUTCOME_NONE)),
nTime(0),
vchSig()
{}
CGovernanceVote::CGovernanceVote(CTxIn vinMasternodeIn, uint256 nParentHashIn, vote_signal_enum_t eVoteSignalIn, vote_outcome_enum_t eVoteOutcomeIn)
: fValid(true),
fSynced(false),
nVoteSignal(eVoteSignalIn),
vinMasternode(vinMasternodeIn),
nParentHash(nParentHashIn),
nVoteOutcome(eVoteOutcomeIn),
nTime(GetAdjustedTime()),
vchSig()
{}
void CGovernanceVote::Relay()
{
CInv inv(MSG_GOVERNANCE_OBJECT_VOTE, GetHash());
RelayInv(inv, MSG_GOVERNANCE_PEER_PROTO_VERSION);
}
bool CGovernanceVote::Sign(CKey& keyMasternode, CPubKey& pubKeyMasternode)
{
// Choose coins to use
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
std::string strError;
std::string strMessage = vinMasternode.prevout.ToStringShort() + "|" + nParentHash.ToString() + "|" +
boost::lexical_cast<std::string>(nVoteSignal) + "|" + boost::lexical_cast<std::string>(nVoteOutcome) + "|" + boost::lexical_cast<std::string>(nTime);
if(!darkSendSigner.SignMessage(strMessage, vchSig, keyMasternode)) {
LogPrintf("CGovernanceVote::Sign -- SignMessage() failed\n");
return false;
}
if(!darkSendSigner.VerifyMessage(pubKeyMasternode, vchSig, strMessage, strError)) {
LogPrintf("CGovernanceVote::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
return true;
}
bool CGovernanceVote::IsValid(bool fSignatureCheck)
{
if(nTime > GetTime() + (60*60)){
LogPrint("gobject", "CGovernanceVote::IsValid() - vote is too far ahead of current time - %s - nTime %lli - Max Time %lli\n", GetHash().ToString(), nTime, GetTime() + (60*60));
return false;
}
// support up to 50 actions (implemented in sentinel)
if(nVoteSignal > 50)
{
LogPrint("gobject", "CGovernanceVote::IsValid() - Client attempted to vote on invalid action(%d) - %s\n", nVoteSignal, GetHash().ToString());
return false;
}
// 0=none, 1=yes, 2=no, 3=abstain. Beyond that reject votes
if(nVoteOutcome > 3)
{
LogPrint("gobject", "CGovernanceVote::IsValid() - Client attempted to vote on invalid outcome(%d) - %s\n", nVoteSignal, GetHash().ToString());
return false;
}
CMasternode* pmn = mnodeman.Find(vinMasternode);
if(pmn == NULL)
{
LogPrint("gobject", "CGovernanceVote::IsValid() - Unknown Masternode - %s\n", vinMasternode.ToString());
return false;
}
if(!fSignatureCheck) return true;
std::string strError;
std::string strMessage = vinMasternode.prevout.ToStringShort() + "|" + nParentHash.ToString() + "|" +
boost::lexical_cast<std::string>(nVoteSignal) + "|" + boost::lexical_cast<std::string>(nVoteOutcome) + "|" + boost::lexical_cast<std::string>(nTime);
if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchSig, strMessage, strError)) {
LogPrintf("CGovernanceVote::IsValid -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
return true;
}