2016-12-20 14:26:45 +01:00
// Copyright (c) 2014-2017 The Dash Core developers
2016-08-17 09:08:25 +02:00
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//#define ENABLE_DASH_DEBUG
# include "activemasternode.h"
# include "governance.h"
2016-12-20 14:27:59 +01:00
# include "governance-vote.h"
# include "governance-classes.h"
2017-06-26 15:56:29 +02:00
# include "governance-validators.h"
2016-12-20 14:27:59 +01:00
# include "init.h"
2017-08-09 02:19:06 +02:00
# include "validation.h"
2016-10-17 20:54:28 +02:00
# include "masternode.h"
2016-08-17 09:08:25 +02:00
# include "masternode-sync.h"
# include "masternodeconfig.h"
# include "masternodeman.h"
2017-04-12 09:04:06 +02:00
# include "messagesigner.h"
2017-07-03 15:13:34 +02:00
# include "rpc/server.h"
2016-12-20 14:27:59 +01:00
# include "util.h"
2016-08-17 09:08:25 +02:00
# include "utilmoneystr.h"
2016-12-20 14:27:59 +01:00
# include <boost/lexical_cast.hpp>
2016-08-17 09:08:25 +02:00
UniValue gobject ( const UniValue & params , bool fHelp )
{
2016-09-12 09:40:00 +02:00
std : : string strCommand ;
2016-08-17 09:08:25 +02:00
if ( params . size ( ) > = 1 )
strCommand = params [ 0 ] . get_str ( ) ;
if ( fHelp | |
2016-12-12 02:44:46 +01:00
( strCommand ! = " vote-many " & & strCommand ! = " vote-conf " & & strCommand ! = " vote-alias " & & strCommand ! = " prepare " & & strCommand ! = " submit " & & strCommand ! = " count " & &
2017-06-26 15:56:29 +02:00
strCommand ! = " deserialize " & & strCommand ! = " get " & & strCommand ! = " getvotes " & & strCommand ! = " getcurrentvotes " & & strCommand ! = " list " & & strCommand ! = " diff " & &
strCommand ! = " check " ) )
2016-09-12 09:40:00 +02:00
throw std : : runtime_error (
2016-08-17 09:08:25 +02:00
" gobject \" command \" ... \n "
" Manage governance objects \n "
" \n Available commands: \n "
2017-06-26 15:56:29 +02:00
" check - Validate governance object data (proposal only) \n "
2016-09-12 09:40:00 +02:00
" prepare - Prepare governance object by signing and creating tx \n "
" submit - Submit governance object to network \n "
2016-12-12 02:44:46 +01:00
" deserialize - Deserialize governance object from hex string to JSON \n "
" count - Count governance objects and votes \n "
2016-09-12 09:40:00 +02:00
" get - Get governance object by hash \n "
2016-11-22 20:26:36 +01:00
" getvotes - Get all votes for a governance object hash (including old votes) \n "
" getcurrentvotes - Get only current (tallying) votes for a governance object hash (does not include old votes) \n "
2017-04-11 12:53:13 +02:00
" list - List governance objects (can be filtered by signal and/or object type) \n "
2016-08-17 09:08:25 +02:00
" diff - List differences since last diff \n "
2016-09-12 09:40:00 +02:00
" vote-alias - Vote on a governance object by masternode alias (using masternode.conf setup) \n "
2016-08-17 09:08:25 +02:00
" vote-conf - Vote on a governance object by masternode configured in dash.conf \n "
2016-09-12 09:40:00 +02:00
" vote-many - Vote on a governance object by all masternodes (using masternode.conf setup) \n "
2016-08-17 09:08:25 +02:00
) ;
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
2016-12-12 02:44:46 +01:00
if ( strCommand = = " count " )
return governance . ToString ( ) ;
2016-08-17 09:08:25 +02:00
/*
2016-09-12 09:40:00 +02:00
- - - - - - Example Governance Item - - - - - -
2016-08-17 09:08:25 +02:00
gobject submit 6e622 bb41bad1fb18e7f23ae96770aeb33129e18bd9efe790522488e580a0a03 0 1 1464292854 " beer-reimbursement " 5 b5b22636f6e7472616374222c207b2270726f6a6563745f6e616d65223a20225c22626565722d7265696d62757273656d656e745c22222c20227061796d656e745f61646472657373223a20225c225879324c4b4a4a64655178657948726e34744744514238626a6876464564615576375c22222c2022656e645f64617465223a202231343936333030343030222c20226465736372697074696f6e5f75726c223a20225c227777772e646173687768616c652e6f72672f702f626565722d7265696d62757273656d656e745c22222c2022636f6e74726163745f75726c223a20225c22626565722d7265696d62757273656d656e742e636f6d2f3030312e7064665c22222c20227061796d656e745f616d6f756e74223a20223233342e323334323232222c2022676f7665726e616e63655f6f626a6563745f6964223a2037342c202273746172745f64617465223a202231343833323534303030227d5d5d1
*/
// DEBUG : TEST DESERIALIZATION OF GOVERNANCE META DATA
if ( strCommand = = " deserialize " )
{
2016-12-12 02:44:46 +01:00
if ( params . size ( ) ! = 2 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject deserialize <data-hex>' " ) ;
}
2016-08-17 09:08:25 +02:00
std : : string strHex = params [ 1 ] . get_str ( ) ;
2016-09-12 09:40:00 +02:00
std : : vector < unsigned char > v = ParseHex ( strHex ) ;
std : : string s ( v . begin ( ) , v . end ( ) ) ;
2016-08-17 09:08:25 +02:00
UniValue u ( UniValue : : VOBJ ) ;
u . read ( s ) ;
return u . write ( ) . c_str ( ) ;
}
2017-06-26 15:56:29 +02:00
// VALIDATE A GOVERNANCE OBJECT PRIOR TO SUBMISSION
if ( strCommand = = " check " )
{
if ( params . size ( ) ! = 2 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject check <data-hex>' " ) ;
}
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
uint256 hashParent ;
int nRevision = 1 ;
2017-08-29 01:51:44 +02:00
int64_t nTime = GetAdjustedTime ( ) ;
2017-06-26 15:56:29 +02:00
std : : string strData = params [ 1 ] . get_str ( ) ;
CGovernanceObject govobj ( hashParent , nRevision , nTime , uint256 ( ) , strData ) ;
if ( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_PROPOSAL ) {
CProposalValidator validator ( strData ) ;
if ( ! validator . Validate ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid proposal data, error messages: " + validator . GetErrorMessages ( ) ) ;
}
}
else {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid object type, only proposals can be validated " ) ;
}
UniValue objResult ( UniValue : : VOBJ ) ;
objResult . push_back ( Pair ( " Object status " , " OK " ) ) ;
return objResult ;
}
2016-08-17 09:08:25 +02:00
// PREPARE THE GOVERNANCE OBJECT BY CREATING A COLLATERAL TRANSACTION
if ( strCommand = = " prepare " )
{
2016-09-17 21:37:48 +02:00
if ( params . size ( ) ! = 5 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject prepare <parent-hash> <revision> <time> <data-hex>' " ) ;
2016-09-15 08:49:24 +02:00
}
2016-08-17 09:08:25 +02:00
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
uint256 hashParent ;
// -- attach to root node (root node doesn't really exist, but has a hash of zero)
2016-09-12 09:40:00 +02:00
if ( params [ 1 ] . get_str ( ) = = " 0 " ) {
2016-08-17 09:08:25 +02:00
hashParent = uint256 ( ) ;
} else {
2016-09-12 09:40:00 +02:00
hashParent = ParseHashV ( params [ 1 ] , " fee-txid, parameter 1 " ) ;
2016-08-17 09:08:25 +02:00
}
std : : string strRevision = params [ 2 ] . get_str ( ) ;
std : : string strTime = params [ 3 ] . get_str ( ) ;
int nRevision = boost : : lexical_cast < int > ( strRevision ) ;
int nTime = boost : : lexical_cast < int > ( strTime ) ;
2016-09-17 21:37:48 +02:00
std : : string strData = params [ 4 ] . get_str ( ) ;
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
// CREATE A NEW COLLATERAL TRANSACTION FOR THIS SPECIFIC OBJECT
2016-09-17 21:37:48 +02:00
CGovernanceObject govobj ( hashParent , nRevision , nTime , uint256 ( ) , strData ) ;
2016-08-17 09:08:25 +02:00
2017-06-26 15:56:29 +02:00
if ( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_PROPOSAL ) {
CProposalValidator validator ( strData ) ;
if ( ! validator . Validate ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid proposal data, error messages: " + validator . GetErrorMessages ( ) ) ;
}
}
2016-10-17 20:54:28 +02:00
if ( ( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_TRIGGER ) | |
( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_WATCHDOG ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Trigger and watchdog objects need not be prepared (however only masternodes can create them) " ) ;
2016-09-15 08:49:24 +02:00
}
2017-07-13 11:38:00 +02:00
{
LOCK ( cs_main ) ;
std : : string strError = " " ;
if ( ! govobj . IsValidLocally ( strError , false ) )
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Governance object is not valid - " + govobj . GetHash ( ) . ToString ( ) + " - " + strError ) ;
}
2016-08-17 09:08:25 +02:00
CWalletTx wtx ;
2016-09-05 01:44:10 +02:00
if ( ! pwalletMain - > GetBudgetSystemCollateralTX ( wtx , govobj . GetHash ( ) , govobj . GetMinCollateralFee ( ) , false ) ) {
2016-09-12 09:40:00 +02:00
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Error making collateral transaction for governance object. Please check your wallet balance and make sure your wallet is unlocked. " ) ;
2016-08-17 09:08:25 +02:00
}
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
// -- make our change address
CReserveKey reservekey ( pwalletMain ) ;
// -- send the tx to the network
Backport Bitcoin PR#8085: p2p: Begin encapsulation (#1537)
* net: move CBanDB and CAddrDB out of net.h/cpp
This will eventually solve a circular dependency
* net: Create CConnman to encapsulate p2p connections
* net: Move socket binding into CConnman
* net: move OpenNetworkConnection into CConnman
* net: move ban and addrman functions into CConnman
* net: Add oneshot functions to CConnman
* net: move added node functions to CConnman
* net: Add most functions needed for vNodes to CConnman
* net: handle nodesignals in CConnman
* net: Pass CConnection to wallet rather than using the global
* net: Add rpc error for missing/disabled p2p functionality
* net: Pass CConnman around as needed
* gui: add NodeID to the peer table
* net: create generic functor accessors and move vNodes to CConnman
* net: move whitelist functions into CConnman
* net: move nLastNodeId to CConnman
* net: move nLocalHostNonce to CConnman
This behavior seems to have been quite racy and broken.
Move nLocalHostNonce into CNode, and check received nonces against all
non-fully-connected nodes. If there's a match, assume we've connected
to ourself.
* net: move messageHandlerCondition to CConnman
* net: move send/recv statistics to CConnman
* net: move SendBufferSize/ReceiveFloodSize to CConnman
* net: move nLocalServices/nRelevantServices to CConnman
These are in-turn passed to CNode at connection time. This allows us to offer
different services to different peers (or test the effects of doing so).
* net: move semOutbound and semMasternodeOutbound to CConnman
* net: SocketSendData returns written size
* net: move max/max-outbound to CConnman
* net: Pass best block known height into CConnman
CConnman then passes the current best height into CNode at creation time.
This way CConnman/CNode have no dependency on main for height, and the signals
only move in one direction.
This also helps to prevent identity leakage a tiny bit. Before this change, an
attacker could theoretically make 2 connections on different interfaces. They
would connect fully on one, and only establish the initial connection on the
other. Once they receive a new block, they would relay it to your first
connection, and immediately commence the version handshake on the second. Since
the new block height is reflected immediately, they could attempt to learn
whether the two connections were correlated.
This is, of course, incredibly unlikely to work due to the small timings
involved and receipt from other senders. But it doesn't hurt to lock-in
nBestHeight at the time of connection, rather than letting the remote choose
the time.
* net: pass CClientUIInterface into CConnman
* net: Drop StartNode/StopNode and use CConnman directly
* net: Introduce CConnection::Options to avoid passing so many params
* net: add nSendBufferMaxSize/nReceiveFloodSize to CConnection::Options
* net: move vNodesDisconnected into CConnman
* Made the ForEachNode* functions in src/net.cpp more pragmatic and self documenting
* Convert ForEachNode* functions to take a templated function argument rather than a std::function to eliminate std::function overhead
* net: move MAX_FEELER_CONNECTIONS into connman
2017-07-21 11:35:19 +02:00
pwalletMain - > CommitTransaction ( wtx , reservekey , g_connman . get ( ) , NetMsgType : : TX ) ;
2016-08-17 09:08:25 +02:00
2016-09-17 21:37:48 +02:00
DBG ( cout < < " gobject: prepare "
< < " strData = " < < govobj . GetDataAsString ( )
2016-08-17 09:08:25 +02:00
< < " , hash = " < < govobj . GetHash ( ) . GetHex ( )
2016-09-12 09:40:00 +02:00
< < " , txidFee = " < < wtx . GetHash ( ) . GetHex ( )
2016-08-17 09:08:25 +02:00
< < endl ; ) ;
return wtx . GetHash ( ) . ToString ( ) ;
}
// AFTER COLLATERAL TRANSACTION HAS MATURED USER CAN SUBMIT GOVERNANCE OBJECT TO PROPAGATE NETWORK
if ( strCommand = = " submit " )
{
2016-09-17 21:37:48 +02:00
if ( ( params . size ( ) < 5 ) | | ( params . size ( ) > 6 ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject submit <parent-hash> <revision> <time> <data-hex> <fee-txid>' " ) ;
2016-09-05 01:44:10 +02:00
}
2016-08-17 09:08:25 +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. " ) ;
}
2016-09-05 01:44:10 +02:00
CMasternode mn ;
2016-12-20 00:06:06 +01:00
bool fMnFound = mnodeman . Get ( activeMasternode . vin , mn ) ;
2016-09-05 01:44:10 +02:00
DBG ( cout < < " gobject: submit activeMasternode.pubKeyMasternode = " < < activeMasternode . pubKeyMasternode . GetHash ( ) . ToString ( )
2016-10-31 10:11:57 +01:00
< < " , vin = " < < activeMasternode . vin . prevout . ToStringShort ( )
2016-09-05 01:44:10 +02:00
< < " , params.size() = " < < params . size ( )
2016-12-20 00:06:06 +01:00
< < " , fMnFound = " < < fMnFound < < endl ; ) ;
2016-09-05 01:44:10 +02:00
2016-08-17 09:08:25 +02:00
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
2016-09-12 09:40:00 +02:00
uint256 txidFee ;
2016-08-17 09:08:25 +02:00
2016-09-17 21:37:48 +02:00
if ( params . size ( ) = = 6 ) {
txidFee = ParseHashV ( params [ 5 ] , " fee-txid, parameter 6 " ) ;
2016-09-05 01:44:10 +02:00
}
2016-08-17 09:08:25 +02:00
uint256 hashParent ;
2016-09-05 01:44:10 +02:00
if ( params [ 1 ] . get_str ( ) = = " 0 " ) { // attach to root node (root node doesn't really exist, but has a hash of zero)
2016-08-17 09:08:25 +02:00
hashParent = uint256 ( ) ;
} else {
2016-09-05 01:44:10 +02:00
hashParent = ParseHashV ( params [ 1 ] , " parent object hash, parameter 2 " ) ;
2016-08-17 09:08:25 +02:00
}
// GET THE PARAMETERS FROM USER
2016-09-05 01:44:10 +02:00
std : : string strRevision = params [ 2 ] . get_str ( ) ;
std : : string strTime = params [ 3 ] . get_str ( ) ;
2016-08-17 09:08:25 +02:00
int nRevision = boost : : lexical_cast < int > ( strRevision ) ;
int nTime = boost : : lexical_cast < int > ( strTime ) ;
2016-09-17 21:37:48 +02:00
std : : string strData = params [ 4 ] . get_str ( ) ;
2016-08-17 09:08:25 +02:00
2016-09-17 21:37:48 +02:00
CGovernanceObject govobj ( hashParent , nRevision , nTime , txidFee , strData ) ;
2016-08-17 09:08:25 +02:00
2016-09-17 21:37:48 +02:00
DBG ( cout < < " gobject: submit "
< < " strData = " < < govobj . GetDataAsString ( )
2016-08-17 09:08:25 +02:00
< < " , hash = " < < govobj . GetHash ( ) . GetHex ( )
2016-09-12 09:40:00 +02:00
< < " , txidFee = " < < txidFee . GetHex ( )
2016-08-17 09:08:25 +02:00
< < endl ; ) ;
2017-06-26 15:56:29 +02:00
if ( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_PROPOSAL ) {
CProposalValidator validator ( strData ) ;
if ( ! validator . Validate ( ) ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid proposal data, error messages: " + validator . GetErrorMessages ( ) ) ;
}
}
2016-09-05 01:44:10 +02:00
// Attempt to sign triggers if we are a MN
2016-10-17 20:54:28 +02:00
if ( ( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_TRIGGER ) | |
( govobj . GetObjectType ( ) = = GOVERNANCE_OBJECT_WATCHDOG ) ) {
2016-12-20 00:06:06 +01:00
if ( fMnFound ) {
2016-09-15 08:49:24 +02:00
govobj . SetMasternodeInfo ( mn . vin ) ;
govobj . Sign ( activeMasternode . keyMasternode , activeMasternode . pubKeyMasternode ) ;
2016-09-09 17:52:10 +02:00
}
else {
2017-01-03 15:17:29 +01:00
LogPrintf ( " gobject(submit) -- Object submission rejected because node is not a masternode \n " ) ;
2016-09-15 08:49:24 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Only valid masternodes can submit this type of object " ) ;
}
}
else {
2016-09-17 21:37:48 +02:00
if ( params . size ( ) ! = 6 ) {
2017-01-03 15:17:29 +01:00
LogPrintf ( " gobject(submit) -- Object submission rejected because fee tx not provided \n " ) ;
2016-09-15 08:49:24 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " The fee-txid parameter must be included to submit this type of object " ) ;
2016-09-09 17:52:10 +02:00
}
2016-09-05 01:44:10 +02:00
}
2017-01-03 15:17:29 +01:00
std : : string strHash = govobj . GetHash ( ) . ToString ( ) ;
2016-08-17 09:08:25 +02:00
std : : string strError = " " ;
2017-07-05 02:31:50 +02:00
bool fMissingMasternode ;
bool fMissingConfirmations ;
2017-07-13 11:38:00 +02:00
{
LOCK ( cs_main ) ;
if ( ! govobj . IsValidLocally ( strError , fMissingMasternode , fMissingConfirmations , true ) & & ! fMissingConfirmations ) {
LogPrintf ( " gobject(submit) -- Object submission rejected because object is not valid - hash = %s, strError = %s \n " , strHash , strError ) ;
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Governance object is not valid - " + strHash + " - " + strError ) ;
}
2016-08-17 09:08:25 +02:00
}
// RELAY THIS OBJECT
2017-01-03 15:17:29 +01:00
// Reject if rate check fails but don't update buffer
2016-12-08 21:00:49 +01:00
if ( ! governance . MasternodeRateCheck ( govobj ) ) {
2017-01-03 15:17:29 +01:00
LogPrintf ( " gobject(submit) -- Object submission rejected because of rate check failure - hash = %s \n " , strHash ) ;
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Object creation rate limit exceeded " ) ;
}
2017-07-05 02:31:50 +02:00
2017-01-03 15:17:29 +01:00
LogPrintf ( " gobject(submit) -- Adding locally created governance object - %s \n " , strHash ) ;
2017-07-05 02:31:50 +02:00
if ( fMissingConfirmations ) {
governance . AddPostponedObject ( govobj ) ;
govobj . Relay ( ) ;
} else {
governance . AddGovernanceObject ( govobj ) ;
}
2016-08-17 09:08:25 +02:00
return govobj . GetHash ( ) . ToString ( ) ;
}
if ( strCommand = = " vote-conf " )
{
if ( params . size ( ) ! = 4 )
2016-09-16 09:43:15 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject vote-conf <governance-hash> [funding|valid|delete] [yes|no|abstain]' " ) ;
2016-08-17 09:08:25 +02:00
uint256 hash ;
std : : string strVote ;
hash = ParseHashV ( params [ 1 ] , " Object hash " ) ;
2016-09-12 09:40:00 +02:00
std : : string strVoteSignal = params [ 2 ] . get_str ( ) ;
2016-08-17 09:08:25 +02:00
std : : string strVoteOutcome = params [ 3 ] . get_str ( ) ;
2016-09-12 09:40:00 +02:00
vote_signal_enum_t eVoteSignal = CGovernanceVoting : : ConvertVoteSignal ( strVoteSignal ) ;
2016-09-08 13:40:19 +02:00
if ( eVoteSignal = = VOTE_SIGNAL_NONE ) {
2016-09-12 09:40:00 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER ,
2016-09-08 13:40:19 +02:00
" Invalid vote signal. Please using one of the following: "
2016-09-12 09:40:00 +02:00
" (funding|valid|delete|endorsed) OR `custom sentinel code` " ) ;
2016-09-08 13:40:19 +02:00
}
2016-08-17 09:08:25 +02:00
2016-09-08 13:40:19 +02:00
vote_outcome_enum_t eVoteOutcome = CGovernanceVoting : : ConvertVoteOutcome ( strVoteOutcome ) ;
if ( eVoteOutcome = = VOTE_OUTCOME_NONE ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain' " ) ;
}
2016-08-17 09:08:25 +02:00
2016-12-20 00:06:06 +01:00
int nSuccessful = 0 ;
int nFailed = 0 ;
2016-08-17 09:08:25 +02:00
UniValue resultsObj ( UniValue : : VOBJ ) ;
std : : vector < unsigned char > vchMasterNodeSignature ;
std : : string strMasterNodeSignMessage ;
UniValue statusObj ( UniValue : : VOBJ ) ;
2016-09-12 03:17:41 +02:00
UniValue returnObj ( UniValue : : VOBJ ) ;
2016-08-17 09:08:25 +02:00
2016-09-18 23:11:03 +02:00
CMasternode mn ;
2016-12-20 00:06:06 +01:00
bool fMnFound = mnodeman . Get ( activeMasternode . vin , mn ) ;
2016-09-18 23:11:03 +02:00
2016-12-20 00:06:06 +01:00
if ( ! fMnFound ) {
nFailed + + ;
2016-08-17 09:08:25 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
2016-09-18 23:11:03 +02:00
statusObj . push_back ( Pair ( " errorMessage " , " Can't find masternode by collateral output " ) ) ;
2016-08-17 09:08:25 +02:00
resultsObj . push_back ( Pair ( " dash.conf " , statusObj ) ) ;
2016-12-20 00:06:06 +01:00
returnObj . push_back ( Pair ( " overall " , strprintf ( " Voted successfully %d time(s) and failed %d time(s). " , nSuccessful , nFailed ) ) ) ;
2016-09-12 03:17:41 +02:00
returnObj . push_back ( Pair ( " detail " , resultsObj ) ) ;
return returnObj ;
2016-08-17 09:08:25 +02:00
}
2016-09-18 23:11:03 +02:00
CGovernanceVote vote ( mn . vin , hash , eVoteSignal , eVoteOutcome ) ;
if ( ! vote . Sign ( activeMasternode . keyMasternode , activeMasternode . pubKeyMasternode ) ) {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-08-17 09:08:25 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
statusObj . push_back ( Pair ( " errorMessage " , " Failure to sign. " ) ) ;
resultsObj . push_back ( Pair ( " dash.conf " , statusObj ) ) ;
2016-12-20 00:06:06 +01:00
returnObj . push_back ( Pair ( " overall " , strprintf ( " Voted successfully %d time(s) and failed %d time(s). " , nSuccessful , nFailed ) ) ) ;
2016-09-12 03:17:41 +02:00
returnObj . push_back ( Pair ( " detail " , resultsObj ) ) ;
return returnObj ;
2016-08-17 09:08:25 +02:00
}
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2016-12-07 05:16:34 +01:00
if ( governance . ProcessVoteAndRelay ( vote , exception ) ) {
2016-12-20 00:06:06 +01:00
nSuccessful + + ;
2016-08-17 09:08:25 +02:00
statusObj . push_back ( Pair ( " result " , " success " ) ) ;
2016-11-13 18:52:34 +01:00
}
else {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-09-12 03:17:41 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
2016-11-13 18:52:34 +01:00
statusObj . push_back ( Pair ( " errorMessage " , exception . GetMessage ( ) ) ) ;
2016-08-17 09:08:25 +02:00
}
resultsObj . push_back ( Pair ( " dash.conf " , statusObj ) ) ;
2016-12-20 00:06:06 +01:00
returnObj . push_back ( Pair ( " overall " , strprintf ( " Voted successfully %d time(s) and failed %d time(s). " , nSuccessful , nFailed ) ) ) ;
2016-08-17 09:08:25 +02:00
returnObj . push_back ( Pair ( " detail " , resultsObj ) ) ;
2016-09-11 19:58:17 +02:00
return returnObj ;
}
if ( strCommand = = " vote-many " )
{
if ( params . size ( ) ! = 4 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject vote-many <governance-hash> [funding|valid|delete] [yes|no|abstain]' " ) ;
uint256 hash ;
std : : string strVote ;
hash = ParseHashV ( params [ 1 ] , " Object hash " ) ;
2016-09-12 09:40:00 +02:00
std : : string strVoteSignal = params [ 2 ] . get_str ( ) ;
2016-09-11 19:58:17 +02:00
std : : string strVoteOutcome = params [ 3 ] . get_str ( ) ;
2016-09-12 09:40:00 +02:00
vote_signal_enum_t eVoteSignal = CGovernanceVoting : : ConvertVoteSignal ( strVoteSignal ) ;
2016-09-11 19:58:17 +02:00
if ( eVoteSignal = = VOTE_SIGNAL_NONE ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER ,
" Invalid vote signal. Please using one of the following: "
" (funding|valid|delete|endorsed) OR `custom sentinel code` " ) ;
}
vote_outcome_enum_t eVoteOutcome = CGovernanceVoting : : ConvertVoteOutcome ( strVoteOutcome ) ;
if ( eVoteOutcome = = VOTE_OUTCOME_NONE ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain' " ) ;
}
2016-12-20 00:06:06 +01:00
int nSuccessful = 0 ;
int nFailed = 0 ;
2016-09-11 19:58:17 +02:00
std : : vector < CMasternodeConfig : : CMasternodeEntry > mnEntries ;
mnEntries = masternodeConfig . getEntries ( ) ;
UniValue resultsObj ( UniValue : : VOBJ ) ;
BOOST_FOREACH ( CMasternodeConfig : : CMasternodeEntry mne , masternodeConfig . getEntries ( ) ) {
2016-09-12 09:40:00 +02:00
std : : string strError ;
2016-09-11 19:58:17 +02:00
std : : vector < unsigned char > vchMasterNodeSignature ;
std : : string strMasterNodeSignMessage ;
CPubKey pubKeyCollateralAddress ;
CKey keyCollateralAddress ;
CPubKey pubKeyMasternode ;
CKey keyMasternode ;
UniValue statusObj ( UniValue : : VOBJ ) ;
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : GetKeysFromSecret ( mne . getPrivKey ( ) , keyMasternode , pubKeyMasternode ) ) {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-09-11 19:58:17 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
2016-09-12 09:40:00 +02:00
statusObj . push_back ( Pair ( " errorMessage " , " Masternode signing error, could not set key correctly " ) ) ;
2016-09-11 19:58:17 +02:00
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
continue ;
}
2016-09-18 23:11:03 +02:00
uint256 nTxHash ;
nTxHash . SetHex ( mne . getTxHash ( ) ) ;
int nOutputIndex = 0 ;
if ( ! ParseInt32 ( mne . getOutputIndex ( ) , & nOutputIndex ) ) {
continue ;
}
CTxIn vin ( COutPoint ( nTxHash , nOutputIndex ) ) ;
CMasternode mn ;
2016-12-20 00:06:06 +01:00
bool fMnFound = mnodeman . Get ( vin , mn ) ;
2016-09-18 23:11:03 +02:00
2016-12-20 00:06:06 +01:00
if ( ! fMnFound ) {
nFailed + + ;
2016-09-11 19:58:17 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
2016-09-18 23:11:03 +02:00
statusObj . push_back ( Pair ( " errorMessage " , " Can't find masternode by collateral output " ) ) ;
2016-09-11 19:58:17 +02:00
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
continue ;
}
2016-09-18 23:11:03 +02:00
CGovernanceVote vote ( mn . vin , hash , eVoteSignal , eVoteOutcome ) ;
2016-09-11 19:58:17 +02:00
if ( ! vote . Sign ( keyMasternode , pubKeyMasternode ) ) {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-09-11 19:58:17 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
statusObj . push_back ( Pair ( " errorMessage " , " Failure to sign. " ) ) ;
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
continue ;
}
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2016-12-07 05:16:34 +01:00
if ( governance . ProcessVoteAndRelay ( vote , exception ) ) {
2016-12-20 00:06:06 +01:00
nSuccessful + + ;
2016-09-11 19:58:17 +02:00
statusObj . push_back ( Pair ( " result " , " success " ) ) ;
2016-11-13 18:52:34 +01:00
}
else {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-09-11 19:58:17 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
2016-11-13 18:52:34 +01:00
statusObj . push_back ( Pair ( " errorMessage " , exception . GetMessage ( ) ) ) ;
2016-09-11 19:58:17 +02:00
}
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
}
UniValue returnObj ( UniValue : : VOBJ ) ;
2016-12-20 00:06:06 +01:00
returnObj . push_back ( Pair ( " overall " , strprintf ( " Voted successfully %d time(s) and failed %d time(s). " , nSuccessful , nFailed ) ) ) ;
2016-09-11 19:58:17 +02:00
returnObj . push_back ( Pair ( " detail " , resultsObj ) ) ;
2016-08-17 09:08:25 +02:00
return returnObj ;
}
// MASTERNODES CAN VOTE ON GOVERNANCE OBJECTS ON THE NETWORK FOR VARIOUS SIGNALS AND OUTCOMES
if ( strCommand = = " vote-alias " )
{
if ( params . size ( ) ! = 5 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject vote-alias <governance-hash> [funding|valid|delete] [yes|no|abstain] <alias-name>' " ) ;
uint256 hash ;
std : : string strVote ;
// COLLECT NEEDED PARAMETRS FROM USER
hash = ParseHashV ( params [ 1 ] , " Object hash " ) ;
2016-09-12 09:40:00 +02:00
std : : string strVoteSignal = params [ 2 ] . get_str ( ) ;
2016-08-17 09:08:25 +02:00
std : : string strVoteOutcome = params [ 3 ] . get_str ( ) ;
std : : string strAlias = params [ 4 ] . get_str ( ) ;
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
// CONVERT NAMED SIGNAL/ACTION AND CONVERT
2016-09-12 09:40:00 +02:00
vote_signal_enum_t eVoteSignal = CGovernanceVoting : : ConvertVoteSignal ( strVoteSignal ) ;
2016-09-08 13:40:19 +02:00
if ( eVoteSignal = = VOTE_SIGNAL_NONE ) {
2016-09-12 09:40:00 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER ,
2016-09-08 13:40:19 +02:00
" Invalid vote signal. Please using one of the following: "
2016-09-12 09:40:00 +02:00
" (funding|valid|delete|endorsed) OR `custom sentinel code` " ) ;
2016-09-08 13:40:19 +02:00
}
2016-08-17 09:08:25 +02:00
2016-09-08 13:40:19 +02:00
vote_outcome_enum_t eVoteOutcome = CGovernanceVoting : : ConvertVoteOutcome ( strVoteOutcome ) ;
if ( eVoteOutcome = = VOTE_OUTCOME_NONE ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain' " ) ;
}
2016-08-17 09:08:25 +02:00
// EXECUTE VOTE FOR EACH MASTERNODE, COUNT SUCCESSES VS FAILURES
2016-12-20 00:06:06 +01:00
int nSuccessful = 0 ;
int nFailed = 0 ;
2016-08-17 09:08:25 +02:00
std : : vector < CMasternodeConfig : : CMasternodeEntry > mnEntries ;
mnEntries = masternodeConfig . getEntries ( ) ;
UniValue resultsObj ( UniValue : : VOBJ ) ;
BOOST_FOREACH ( CMasternodeConfig : : CMasternodeEntry mne , masternodeConfig . getEntries ( ) )
{
// IF WE HAVE A SPECIFIC NODE REQUESTED TO VOTE, DO THAT
2016-09-18 23:11:03 +02:00
if ( strAlias ! = mne . getAlias ( ) ) continue ;
2016-08-17 09:08:25 +02:00
// INIT OUR NEEDED VARIABLES TO EXECUTE THE VOTE
2016-09-12 09:40:00 +02:00
std : : string strError ;
2016-08-17 09:08:25 +02:00
std : : vector < unsigned char > vchMasterNodeSignature ;
std : : string strMasterNodeSignMessage ;
CPubKey pubKeyCollateralAddress ;
CKey keyCollateralAddress ;
CPubKey pubKeyMasternode ;
CKey keyMasternode ;
// SETUP THE SIGNING KEY FROM MASTERNODE.CONF ENTRY
UniValue statusObj ( UniValue : : VOBJ ) ;
2017-04-12 09:04:06 +02:00
if ( ! CMessageSigner : : GetKeysFromSecret ( mne . getPrivKey ( ) , keyMasternode , pubKeyMasternode ) ) {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-08-17 09:08:25 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
2016-08-19 13:50:04 +02:00
statusObj . push_back ( Pair ( " errorMessage " , strprintf ( " Invalid masternode key %s. " , mne . getPrivKey ( ) ) ) ) ;
2016-08-17 09:08:25 +02:00
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
continue ;
}
// SEARCH FOR THIS MASTERNODE ON THE NETWORK, THE NODE MUST BE ACTIVE TO VOTE
2016-09-18 23:11:03 +02:00
uint256 nTxHash ;
nTxHash . SetHex ( mne . getTxHash ( ) ) ;
int nOutputIndex = 0 ;
if ( ! ParseInt32 ( mne . getOutputIndex ( ) , & nOutputIndex ) ) {
continue ;
}
CTxIn vin ( COutPoint ( nTxHash , nOutputIndex ) ) ;
CMasternode mn ;
2016-12-20 00:06:06 +01:00
bool fMnFound = mnodeman . Get ( vin , mn ) ;
2016-09-18 23:11:03 +02:00
2016-12-20 00:06:06 +01:00
if ( ! fMnFound ) {
nFailed + + ;
2016-08-17 09:08:25 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
statusObj . push_back ( Pair ( " errorMessage " , " Masternode must be publically available on network to vote. Masternode not found. " ) ) ;
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
continue ;
}
// CREATE NEW GOVERNANCE OBJECT VOTE WITH OUTCOME/SIGNAL
2016-09-18 23:11:03 +02:00
CGovernanceVote vote ( vin , hash , eVoteSignal , eVoteOutcome ) ;
if ( ! vote . Sign ( keyMasternode , pubKeyMasternode ) ) {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-08-17 09:08:25 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
statusObj . push_back ( Pair ( " errorMessage " , " Failure to sign. " ) ) ;
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
continue ;
}
// UPDATE LOCAL DATABASE WITH NEW OBJECT SETTINGS
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2016-12-07 05:16:34 +01:00
if ( governance . ProcessVoteAndRelay ( vote , exception ) ) {
2016-12-20 00:06:06 +01:00
nSuccessful + + ;
2016-08-17 09:08:25 +02:00
statusObj . push_back ( Pair ( " result " , " success " ) ) ;
2016-11-13 18:52:34 +01:00
}
else {
2016-12-20 00:06:06 +01:00
nFailed + + ;
2016-09-12 03:17:41 +02:00
statusObj . push_back ( Pair ( " result " , " failed " ) ) ;
2016-11-13 18:52:34 +01:00
statusObj . push_back ( Pair ( " errorMessage " , exception . GetMessage ( ) ) ) ;
2016-08-17 09:08:25 +02:00
}
resultsObj . push_back ( Pair ( mne . getAlias ( ) , statusObj ) ) ;
}
// REPORT STATS TO THE USER
UniValue returnObj ( UniValue : : VOBJ ) ;
2016-12-20 00:06:06 +01:00
returnObj . push_back ( Pair ( " overall " , strprintf ( " Voted successfully %d time(s) and failed %d time(s). " , nSuccessful , nFailed ) ) ) ;
2016-08-17 09:08:25 +02:00
returnObj . push_back ( Pair ( " detail " , resultsObj ) ) ;
return returnObj ;
}
// USERS CAN QUERY THE SYSTEM FOR A LIST OF VARIOUS GOVERNANCE ITEMS
if ( strCommand = = " list " | | strCommand = = " diff " )
{
2016-12-12 02:44:46 +01:00
if ( params . size ( ) > 3 )
2017-04-11 12:53:13 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject [list|diff] ( signal type ) ' " ) ;
2016-08-17 09:08:25 +02:00
// GET MAIN PARAMETER FOR THIS MODE, VALID OR ALL?
2017-04-11 12:53:13 +02:00
std : : string strCachedSignal = " valid " ;
if ( params . size ( ) > = 2 ) strCachedSignal = params [ 1 ] . get_str ( ) ;
if ( strCachedSignal ! = " valid " & & strCachedSignal ! = " funding " & & strCachedSignal ! = " delete " & & strCachedSignal ! = " endorsed " & & strCachedSignal ! = " all " )
return " Invalid signal, should be 'valid', 'funding', 'delete', 'endorsed' or 'all' " ;
2016-12-12 02:44:46 +01:00
std : : string strType = " all " ;
if ( params . size ( ) = = 3 ) strType = params [ 2 ] . get_str ( ) ;
if ( strType ! = " proposals " & & strType ! = " triggers " & & strType ! = " watchdogs " & & strType ! = " all " )
return " Invalid type, should be 'proposals', 'triggers', 'watchdogs' or 'all' " ;
2016-08-17 09:08:25 +02:00
// GET STARTING TIME TO QUERY SYSTEM WITH
int nStartTime = 0 ; //list
if ( strCommand = = " diff " ) nStartTime = governance . GetLastDiffTime ( ) ;
// SETUP BLOCK INDEX VARIABLE / RESULTS VARIABLE
UniValue objResult ( UniValue : : VOBJ ) ;
// GET MATCHING GOVERNANCE OBJECTS
2017-01-03 19:32:52 +01:00
LOCK2 ( cs_main , governance . cs ) ;
2016-08-17 09:08:25 +02:00
std : : vector < CGovernanceObject * > objs = governance . GetAllNewerThan ( nStartTime ) ;
governance . UpdateLastDiffTime ( GetTime ( ) ) ;
// CREATE RESULTS FOR USER
BOOST_FOREACH ( CGovernanceObject * pGovObj , objs )
{
2017-04-11 12:53:13 +02:00
if ( strCachedSignal = = " valid " & & ! pGovObj - > IsSetCachedValid ( ) ) continue ;
if ( strCachedSignal = = " funding " & & ! pGovObj - > IsSetCachedFunding ( ) ) continue ;
if ( strCachedSignal = = " delete " & & ! pGovObj - > IsSetCachedDelete ( ) ) continue ;
if ( strCachedSignal = = " endorsed " & & ! pGovObj - > IsSetCachedEndorsed ( ) ) continue ;
2016-08-17 09:08:25 +02:00
2016-12-12 02:44:46 +01:00
if ( strType = = " proposals " & & pGovObj - > GetObjectType ( ) ! = GOVERNANCE_OBJECT_PROPOSAL ) continue ;
if ( strType = = " triggers " & & pGovObj - > GetObjectType ( ) ! = GOVERNANCE_OBJECT_TRIGGER ) continue ;
if ( strType = = " watchdogs " & & pGovObj - > GetObjectType ( ) ! = GOVERNANCE_OBJECT_WATCHDOG ) continue ;
2016-08-17 09:08:25 +02:00
UniValue bObj ( UniValue : : VOBJ ) ;
bObj . push_back ( Pair ( " DataHex " , pGovObj - > GetDataAsHex ( ) ) ) ;
bObj . push_back ( Pair ( " DataString " , pGovObj - > GetDataAsString ( ) ) ) ;
bObj . push_back ( Pair ( " Hash " , pGovObj - > GetHash ( ) . ToString ( ) ) ) ;
2016-11-13 18:52:34 +01:00
bObj . push_back ( Pair ( " CollateralHash " , pGovObj - > GetCollateralHash ( ) . ToString ( ) ) ) ;
2017-02-19 17:55:52 +01:00
bObj . push_back ( Pair ( " ObjectType " , pGovObj - > GetObjectType ( ) ) ) ;
2016-12-22 04:20:05 +01:00
bObj . push_back ( Pair ( " CreationTime " , pGovObj - > GetCreationTime ( ) ) ) ;
const CTxIn & masternodeVin = pGovObj - > GetMasternodeVin ( ) ;
if ( masternodeVin ! = CTxIn ( ) ) {
bObj . push_back ( Pair ( " SigningMasternode " , masternodeVin . prevout . ToStringShort ( ) ) ) ;
}
2016-08-17 09:08:25 +02:00
2017-04-23 10:00:11 +02:00
// REPORT STATUS FOR FUNDING VOTES SPECIFICALLY
bObj . push_back ( Pair ( " AbsoluteYesCount " , pGovObj - > GetAbsoluteYesCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
bObj . push_back ( Pair ( " YesCount " , pGovObj - > GetYesCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
bObj . push_back ( Pair ( " NoCount " , pGovObj - > GetNoCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
bObj . push_back ( Pair ( " AbstainCount " , pGovObj - > GetAbstainCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
2016-08-17 09:08:25 +02:00
// REPORT VALIDITY AND CACHING FLAGS FOR VARIOUS SETTINGS
std : : string strError = " " ;
2017-01-03 19:32:52 +01:00
bObj . push_back ( Pair ( " fBlockchainValidity " , pGovObj - > IsValidLocally ( strError , false ) ) ) ;
2016-08-17 09:08:25 +02:00
bObj . push_back ( Pair ( " IsValidReason " , strError . c_str ( ) ) ) ;
2016-11-13 18:52:34 +01:00
bObj . push_back ( Pair ( " fCachedValid " , pGovObj - > IsSetCachedValid ( ) ) ) ;
bObj . push_back ( Pair ( " fCachedFunding " , pGovObj - > IsSetCachedFunding ( ) ) ) ;
bObj . push_back ( Pair ( " fCachedDelete " , pGovObj - > IsSetCachedDelete ( ) ) ) ;
bObj . push_back ( Pair ( " fCachedEndorsed " , pGovObj - > IsSetCachedEndorsed ( ) ) ) ;
2016-08-17 09:08:25 +02:00
2016-09-17 21:37:48 +02:00
objResult . push_back ( Pair ( pGovObj - > GetHash ( ) . ToString ( ) , bObj ) ) ;
2016-08-17 09:08:25 +02:00
}
return objResult ;
}
// GET SPECIFIC GOVERNANCE ENTRY
if ( strCommand = = " get " )
{
if ( params . size ( ) ! = 2 )
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Correct usage is 'gobject get <governance-hash>' " ) ;
// COLLECT VARIABLES FROM OUR USER
uint256 hash = ParseHashV ( params [ 1 ] , " GovObj hash " ) ;
LOCK2 ( cs_main , governance . cs ) ;
// FIND THE GOVERNANCE OBJECT THE USER IS LOOKING FOR
CGovernanceObject * pGovObj = governance . FindGovernanceObject ( hash ) ;
if ( pGovObj = = NULL )
2016-09-12 09:40:00 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Unknown governance object " ) ;
2016-08-17 09:08:25 +02:00
// REPORT BASIC OBJECT STATS
UniValue objResult ( UniValue : : VOBJ ) ;
2016-09-30 03:48:18 +02:00
objResult . push_back ( Pair ( " DataHex " , pGovObj - > GetDataAsHex ( ) ) ) ;
objResult . push_back ( Pair ( " DataString " , pGovObj - > GetDataAsString ( ) ) ) ;
2016-08-17 09:08:25 +02:00
objResult . push_back ( Pair ( " Hash " , pGovObj - > GetHash ( ) . ToString ( ) ) ) ;
2016-11-13 18:52:34 +01:00
objResult . push_back ( Pair ( " CollateralHash " , pGovObj - > GetCollateralHash ( ) . ToString ( ) ) ) ;
2017-02-19 17:55:52 +01:00
objResult . push_back ( Pair ( " ObjectType " , pGovObj - > GetObjectType ( ) ) ) ;
2016-12-22 04:20:05 +01:00
objResult . push_back ( Pair ( " CreationTime " , pGovObj - > GetCreationTime ( ) ) ) ;
const CTxIn & masternodeVin = pGovObj - > GetMasternodeVin ( ) ;
if ( masternodeVin ! = CTxIn ( ) ) {
objResult . push_back ( Pair ( " SigningMasternode " , masternodeVin . prevout . ToStringShort ( ) ) ) ;
}
2016-08-17 09:08:25 +02:00
// SHOW (MUCH MORE) INFORMATION ABOUT VOTES FOR GOVERNANCE OBJECT (THAN LIST/DIFF ABOVE)
// -- FUNDING VOTING RESULTS
UniValue objFundingResult ( UniValue : : VOBJ ) ;
2016-09-30 03:48:18 +02:00
objFundingResult . push_back ( Pair ( " AbsoluteYesCount " , pGovObj - > GetAbsoluteYesCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
objFundingResult . push_back ( Pair ( " YesCount " , pGovObj - > GetYesCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
objFundingResult . push_back ( Pair ( " NoCount " , pGovObj - > GetNoCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
objFundingResult . push_back ( Pair ( " AbstainCount " , pGovObj - > GetAbstainCount ( VOTE_SIGNAL_FUNDING ) ) ) ;
2016-08-17 09:08:25 +02:00
objResult . push_back ( Pair ( " FundingResult " , objFundingResult ) ) ;
// -- VALIDITY VOTING RESULTS
UniValue objValid ( UniValue : : VOBJ ) ;
2016-09-30 03:48:18 +02:00
objValid . push_back ( Pair ( " AbsoluteYesCount " , pGovObj - > GetAbsoluteYesCount ( VOTE_SIGNAL_VALID ) ) ) ;
objValid . push_back ( Pair ( " YesCount " , pGovObj - > GetYesCount ( VOTE_SIGNAL_VALID ) ) ) ;
objValid . push_back ( Pair ( " NoCount " , pGovObj - > GetNoCount ( VOTE_SIGNAL_VALID ) ) ) ;
objValid . push_back ( Pair ( " AbstainCount " , pGovObj - > GetAbstainCount ( VOTE_SIGNAL_VALID ) ) ) ;
2016-08-17 09:08:25 +02:00
objResult . push_back ( Pair ( " ValidResult " , objValid ) ) ;
// -- DELETION CRITERION VOTING RESULTS
UniValue objDelete ( UniValue : : VOBJ ) ;
2016-09-30 03:48:18 +02:00
objDelete . push_back ( Pair ( " AbsoluteYesCount " , pGovObj - > GetAbsoluteYesCount ( VOTE_SIGNAL_DELETE ) ) ) ;
objDelete . push_back ( Pair ( " YesCount " , pGovObj - > GetYesCount ( VOTE_SIGNAL_DELETE ) ) ) ;
objDelete . push_back ( Pair ( " NoCount " , pGovObj - > GetNoCount ( VOTE_SIGNAL_DELETE ) ) ) ;
objDelete . push_back ( Pair ( " AbstainCount " , pGovObj - > GetAbstainCount ( VOTE_SIGNAL_DELETE ) ) ) ;
2016-08-17 09:08:25 +02:00
objResult . push_back ( Pair ( " DeleteResult " , objDelete ) ) ;
2016-09-12 09:40:00 +02:00
// -- ENDORSED VIA MASTERNODE-ELECTED BOARD
2016-08-17 09:08:25 +02:00
UniValue objEndorsed ( UniValue : : VOBJ ) ;
2016-09-30 03:48:18 +02:00
objEndorsed . push_back ( Pair ( " AbsoluteYesCount " , pGovObj - > GetAbsoluteYesCount ( VOTE_SIGNAL_ENDORSED ) ) ) ;
objEndorsed . push_back ( Pair ( " YesCount " , pGovObj - > GetYesCount ( VOTE_SIGNAL_ENDORSED ) ) ) ;
objEndorsed . push_back ( Pair ( " NoCount " , pGovObj - > GetNoCount ( VOTE_SIGNAL_ENDORSED ) ) ) ;
objEndorsed . push_back ( Pair ( " AbstainCount " , pGovObj - > GetAbstainCount ( VOTE_SIGNAL_ENDORSED ) ) ) ;
2016-08-17 09:08:25 +02:00
objResult . push_back ( Pair ( " EndorsedResult " , objEndorsed ) ) ;
2016-09-12 09:40:00 +02:00
// --
2016-08-17 09:08:25 +02:00
std : : string strError = " " ;
2017-01-03 19:32:52 +01:00
objResult . push_back ( Pair ( " fLocalValidity " , pGovObj - > IsValidLocally ( strError , false ) ) ) ;
2016-09-30 03:48:18 +02:00
objResult . push_back ( Pair ( " IsValidReason " , strError . c_str ( ) ) ) ;
2016-11-13 18:52:34 +01:00
objResult . push_back ( Pair ( " fCachedValid " , pGovObj - > IsSetCachedValid ( ) ) ) ;
objResult . push_back ( Pair ( " fCachedFunding " , pGovObj - > IsSetCachedFunding ( ) ) ) ;
objResult . push_back ( Pair ( " fCachedDelete " , pGovObj - > IsSetCachedDelete ( ) ) ) ;
objResult . push_back ( Pair ( " fCachedEndorsed " , pGovObj - > IsSetCachedEndorsed ( ) ) ) ;
2016-08-17 09:08:25 +02:00
return objResult ;
}
// GETVOTES FOR SPECIFIC GOVERNANCE OBJECT
if ( strCommand = = " getvotes " )
{
2016-09-08 13:40:19 +02:00
if ( params . size ( ) ! = 2 )
2016-09-12 09:40:00 +02:00
throw std : : runtime_error (
2016-09-08 13:40:19 +02:00
" Correct usage is 'gobject getvotes <governance-hash>' "
2016-08-17 09:08:25 +02:00
) ;
// COLLECT PARAMETERS FROM USER
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
uint256 hash = ParseHashV ( params [ 1 ] , " Governance hash " ) ;
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
// FIND OBJECT USER IS LOOKING FOR
2016-09-12 09:40:00 +02:00
2016-08-17 09:08:25 +02:00
LOCK ( governance . cs ) ;
CGovernanceObject * pGovObj = governance . FindGovernanceObject ( hash ) ;
2016-09-08 13:40:19 +02:00
if ( pGovObj = = NULL ) {
2016-08-17 09:08:25 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Unknown governance-hash " ) ;
2016-09-08 13:40:19 +02:00
}
2016-08-17 09:08:25 +02:00
// REPORT RESULTS TO USER
UniValue bResult ( UniValue : : VOBJ ) ;
2016-09-12 09:40:00 +02:00
// GET MATCHING VOTES BY HASH, THEN SHOW USERS VOTE INFORMATION
2016-08-17 09:08:25 +02:00
2016-11-13 18:52:34 +01:00
std : : vector < CGovernanceVote > vecVotes = governance . GetMatchingVotes ( hash ) ;
BOOST_FOREACH ( CGovernanceVote vote , vecVotes ) {
2016-11-22 20:26:36 +01:00
bResult . push_back ( Pair ( vote . GetHash ( ) . ToString ( ) , vote . ToString ( ) ) ) ;
}
return bResult ;
}
// GETVOTES FOR SPECIFIC GOVERNANCE OBJECT
if ( strCommand = = " getcurrentvotes " )
{
2016-12-20 00:06:06 +01:00
if ( params . size ( ) ! = 2 & & params . size ( ) ! = 4 )
2016-11-22 20:26:36 +01:00
throw std : : runtime_error (
" Correct usage is 'gobject getcurrentvotes <governance-hash> [txid vout_index]' "
) ;
// COLLECT PARAMETERS FROM USER
uint256 hash = ParseHashV ( params [ 1 ] , " Governance hash " ) ;
CTxIn mnCollateralOutpoint ;
if ( params . size ( ) = = 4 ) {
uint256 txid = ParseHashV ( params [ 2 ] , " Masternode Collateral hash " ) ;
std : : string strVout = params [ 3 ] . get_str ( ) ;
uint32_t vout = boost : : lexical_cast < uint32_t > ( strVout ) ;
mnCollateralOutpoint = CTxIn ( txid , vout ) ;
}
// FIND OBJECT USER IS LOOKING FOR
LOCK ( governance . cs ) ;
CGovernanceObject * pGovObj = governance . FindGovernanceObject ( hash ) ;
if ( pGovObj = = NULL ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Unknown governance-hash " ) ;
}
// REPORT RESULTS TO USER
UniValue bResult ( UniValue : : VOBJ ) ;
// GET MATCHING VOTES BY HASH, THEN SHOW USERS VOTE INFORMATION
std : : vector < CGovernanceVote > vecVotes = governance . GetCurrentVotes ( hash , mnCollateralOutpoint ) ;
BOOST_FOREACH ( CGovernanceVote vote , vecVotes ) {
2016-11-13 18:52:34 +01:00
bResult . push_back ( Pair ( vote . GetHash ( ) . ToString ( ) , vote . ToString ( ) ) ) ;
2016-09-08 13:40:19 +02:00
}
2016-08-17 09:08:25 +02:00
return bResult ;
}
return NullUniValue ;
}
UniValue voteraw ( const UniValue & params , bool fHelp )
{
2017-01-04 18:47:16 +01:00
if ( fHelp | | params . size ( ) ! = 7 )
2016-09-12 09:40:00 +02:00
throw std : : runtime_error (
2016-09-08 13:40:19 +02:00
" voteraw <masternode-tx-hash> <masternode-tx-index> <governance-hash> <vote-signal> [yes|no|abstain] <time> <vote-sig> \n "
2016-08-17 09:08:25 +02:00
" Compile and relay a governance 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 hashGovObj = ParseHashV ( params [ 2 ] , " Governance hash " ) ;
2016-09-08 13:40:19 +02:00
std : : string strVoteSignal = params [ 3 ] . get_str ( ) ;
std : : string strVoteOutcome = params [ 4 ] . get_str ( ) ;
vote_signal_enum_t eVoteSignal = CGovernanceVoting : : ConvertVoteSignal ( strVoteSignal ) ;
if ( eVoteSignal = = VOTE_SIGNAL_NONE ) {
2016-09-12 09:40:00 +02:00
throw JSONRPCError ( RPC_INVALID_PARAMETER ,
2016-09-08 13:40:19 +02:00
" Invalid vote signal. Please using one of the following: "
2016-09-12 09:40:00 +02:00
" (funding|valid|delete|endorsed) OR `custom sentinel code` " ) ;
2016-09-08 13:40:19 +02:00
}
2016-08-17 09:08:25 +02:00
2016-09-08 13:40:19 +02:00
vote_outcome_enum_t eVoteOutcome = CGovernanceVoting : : ConvertVoteOutcome ( strVoteOutcome ) ;
if ( eVoteOutcome = = VOTE_OUTCOME_NONE ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Invalid vote outcome. Please use one of the following: 'yes', 'no' or 'abstain' " ) ;
}
2016-08-17 09:08:25 +02:00
2016-09-08 13:40:19 +02:00
int64_t nTime = params [ 5 ] . get_int64 ( ) ;
std : : string strSig = params [ 6 ] . get_str ( ) ;
2016-08-17 09:08:25 +02:00
bool fInvalid = false ;
2016-09-12 09:40:00 +02:00
std : : vector < unsigned char > vchSig = DecodeBase64 ( strSig . c_str ( ) , & fInvalid ) ;
2016-08-17 09:08:25 +02:00
2016-09-08 13:40:19 +02:00
if ( fInvalid ) {
2016-08-17 09:08:25 +02:00
throw JSONRPCError ( RPC_INVALID_ADDRESS_OR_KEY , " Malformed base64 encoding " ) ;
2016-09-08 13:40:19 +02:00
}
2016-08-17 09:08:25 +02:00
2016-09-18 23:11:03 +02:00
CMasternode mn ;
2016-12-20 00:06:06 +01:00
bool fMnFound = mnodeman . Get ( vin , mn ) ;
2016-09-18 23:11:03 +02:00
2016-12-20 00:06:06 +01:00
if ( ! fMnFound ) {
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Failure to find masternode in list : " + vin . prevout . ToStringShort ( ) ) ;
2016-08-17 09:08:25 +02:00
}
2016-09-08 13:40:19 +02:00
CGovernanceVote vote ( vin , hashGovObj , eVoteSignal , eVoteOutcome ) ;
vote . SetTime ( nTime ) ;
vote . SetSignature ( vchSig ) ;
2016-08-17 09:08:25 +02:00
2016-09-18 23:11:03 +02:00
if ( ! vote . IsValid ( true ) ) {
2016-08-17 09:08:25 +02:00
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Failure to verify vote. " ) ;
}
2016-11-13 18:52:34 +01:00
CGovernanceException exception ;
2016-12-07 05:16:34 +01:00
if ( governance . ProcessVoteAndRelay ( vote , exception ) ) {
2016-08-17 09:08:25 +02:00
return " Voted successfully " ;
2016-11-13 18:52:34 +01:00
}
else {
throw JSONRPCError ( RPC_INTERNAL_ERROR , " Error voting : " + exception . GetMessage ( ) ) ;
2016-08-17 09:08:25 +02:00
}
}
2016-08-28 21:15:48 +02:00
UniValue getgovernanceinfo ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 0 ) {
2016-09-12 09:40:00 +02:00
throw std : : runtime_error (
2016-08-28 21:15:48 +02:00
" getgovernanceinfo \n "
" Returns an object containing governance parameters. \n "
" \n Result: \n "
" { \n "
2016-10-17 20:54:28 +02:00
" \" governanceminquorum \" : xxxxx, (numeric) the absolute minimum number of votes needed to trigger a governance action \n "
" \" masternodewatchdogmaxseconds \" : xxxxx, (numeric) sentinel watchdog expiration time in seconds \n "
" \" proposalfee \" : xxx.xx, (numeric) the collateral transaction fee which must be paid to create a proposal in " + CURRENCY_UNIT + " \n "
" \" superblockcycle \" : xxxxx, (numeric) the number of blocks between superblocks \n "
" \" lastsuperblock \" : xxxxx, (numeric) the block number of the last superblock \n "
" \" nextsuperblock \" : xxxxx, (numeric) the block number of the next superblock \n "
2016-08-28 21:15:48 +02:00
" } \n "
" \n Examples: \n "
+ HelpExampleCli ( " getgovernanceinfo " , " " )
+ HelpExampleRpc ( " getgovernanceinfo " , " " )
) ;
}
2016-09-08 13:33:25 +02:00
// Compute last/next superblock
int nLastSuperblock , nNextSuperblock ;
// Get current block height
2016-09-18 23:11:03 +02:00
int nBlockHeight = 0 ;
{
LOCK ( cs_main ) ;
nBlockHeight = ( int ) chainActive . Height ( ) ;
}
2016-09-08 13:33:25 +02:00
// Get chain parameters
int nSuperblockStartBlock = Params ( ) . GetConsensus ( ) . nSuperblockStartBlock ;
int nSuperblockCycle = Params ( ) . GetConsensus ( ) . nSuperblockCycle ;
// Get first superblock
int nFirstSuperblockOffset = ( nSuperblockCycle - nSuperblockStartBlock % nSuperblockCycle ) % nSuperblockCycle ;
int nFirstSuperblock = nSuperblockStartBlock + nFirstSuperblockOffset ;
if ( nBlockHeight < nFirstSuperblock ) {
nLastSuperblock = 0 ;
nNextSuperblock = nFirstSuperblock ;
} else {
nLastSuperblock = nBlockHeight - nBlockHeight % nSuperblockCycle ;
nNextSuperblock = nLastSuperblock + nSuperblockCycle ;
}
2016-08-28 21:15:48 +02:00
UniValue obj ( UniValue : : VOBJ ) ;
obj . push_back ( Pair ( " governanceminquorum " , Params ( ) . GetConsensus ( ) . nGovernanceMinQuorum ) ) ;
2016-10-17 20:54:28 +02:00
obj . push_back ( Pair ( " masternodewatchdogmaxseconds " , MASTERNODE_WATCHDOG_MAX_SECONDS ) ) ;
2016-09-05 01:44:10 +02:00
obj . push_back ( Pair ( " proposalfee " , ValueFromAmount ( GOVERNANCE_PROPOSAL_FEE_TX ) ) ) ;
2016-08-28 21:15:48 +02:00
obj . push_back ( Pair ( " superblockcycle " , Params ( ) . GetConsensus ( ) . nSuperblockCycle ) ) ;
2016-09-08 13:33:25 +02:00
obj . push_back ( Pair ( " lastsuperblock " , nLastSuperblock ) ) ;
obj . push_back ( Pair ( " nextsuperblock " , nNextSuperblock ) ) ;
2016-08-28 21:15:48 +02:00
return obj ;
}
UniValue getsuperblockbudget ( const UniValue & params , bool fHelp )
{
if ( fHelp | | params . size ( ) ! = 1 ) {
2016-09-12 09:40:00 +02:00
throw std : : runtime_error (
2016-08-28 21:15:48 +02:00
" getsuperblockbudget index \n "
2016-12-20 00:06:06 +01:00
" \n Returns the absolute maximum sum of superblock payments allowed. \n "
2016-08-28 21:15:48 +02:00
" \n Arguments: \n "
" 1. index (numeric, required) The block index \n "
" \n Result: \n "
2016-12-20 00:06:06 +01:00
" n (numeric) The absolute maximum sum of superblock payments allowed, in " + CURRENCY_UNIT + " \n "
2016-08-28 21:15:48 +02:00
" \n Examples: \n "
+ HelpExampleCli ( " getsuperblockbudget " , " 1000 " )
+ HelpExampleRpc ( " getsuperblockbudget " , " 1000 " )
) ;
}
int nBlockHeight = params [ 0 ] . get_int ( ) ;
if ( nBlockHeight < 0 ) {
throw JSONRPCError ( RPC_INVALID_PARAMETER , " Block height out of range " ) ;
}
CAmount nBudget = CSuperblock : : GetPaymentsLimit ( nBlockHeight ) ;
std : : string strBudget = FormatMoney ( nBudget ) ;
return strBudget ;
}
2017-07-04 19:31:57 +02:00