This commit is contained in:
2022-02-03 23:45:47 -08:00
parent 42c2062cc4
commit 184ece190c
1438 changed files with 404064 additions and 0 deletions
File diff suppressed because it is too large Load Diff
+952
View File
@@ -0,0 +1,952 @@
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "activemasternode.h"
#include "chainparams.h"
#include "db.h"
#include "init.h"
#include "main.h"
#include "masternode-budget.h"
#include "masternode-payments.h"
#include "masternodeconfig.h"
#include "masternodeman.h"
#include "rpc/server.h"
#include "utilmoneystr.h"
#include <univalue.h>
#include <fstream>
using namespace std;
void budgetToJSON(CBudgetProposal* pbudgetProposal, UniValue& bObj)
{
CTxDestination address1;
ExtractDestination(pbudgetProposal->GetPayee(), address1);
CBitcoinAddress address2(address1);
bObj.push_back(Pair("Name", pbudgetProposal->GetName()));
bObj.push_back(Pair("URL", pbudgetProposal->GetURL()));
bObj.push_back(Pair("Hash", pbudgetProposal->GetHash().ToString()));
bObj.push_back(Pair("FeeHash", pbudgetProposal->nFeeTXHash.ToString()));
bObj.push_back(Pair("BlockStart", (int64_t)pbudgetProposal->GetBlockStart()));
bObj.push_back(Pair("BlockEnd", (int64_t)pbudgetProposal->GetBlockEnd()));
bObj.push_back(Pair("TotalPaymentCount", (int64_t)pbudgetProposal->GetTotalPaymentCount()));
bObj.push_back(Pair("RemainingPaymentCount", (int64_t)pbudgetProposal->GetRemainingPaymentCount()));
bObj.push_back(Pair("PaymentAddress", address2.ToString()));
bObj.push_back(Pair("Ratio", pbudgetProposal->GetRatio()));
bObj.push_back(Pair("Yeas", (int64_t)pbudgetProposal->GetYeas()));
bObj.push_back(Pair("Nays", (int64_t)pbudgetProposal->GetNays()));
bObj.push_back(Pair("Abstains", (int64_t)pbudgetProposal->GetAbstains()));
bObj.push_back(Pair("TotalPayment", ValueFromAmount(pbudgetProposal->GetAmount() * pbudgetProposal->GetTotalPaymentCount())));
bObj.push_back(Pair("MonthlyPayment", ValueFromAmount(pbudgetProposal->GetAmount())));
bObj.push_back(Pair("IsEstablished", pbudgetProposal->IsEstablished()));
std::string strError = "";
bObj.push_back(Pair("IsValid", pbudgetProposal->IsValid(strError)));
bObj.push_back(Pair("IsValidReason", strError.c_str()));
bObj.push_back(Pair("fValid", pbudgetProposal->fValid));
}
UniValue preparebudget(const UniValue& params, bool fHelp)
{
int nBlockMin = 0;
CBlockIndex* pindexPrev = chainActive.Tip();
if (fHelp || params.size() != 6)
throw runtime_error(
"preparebudget \"proposal-name\" \"url\" payment-count block-start \"agrarian-address\" monthy-payment\n"
"\nPrepare proposal for network by signing and creating tx\n"
"\nArguments:\n"
"1. \"proposal-name\": (string, required) Desired proposal name (20 character limit)\n"
"2. \"url\": (string, required) URL of proposal details (64 character limit)\n"
"3. payment-count: (numeric, required) Total number of monthly payments\n"
"4. block-start: (numeric, required) Starting super block height\n"
"5. \"agrarian-address\": (string, required) Agrarian address to send payments to\n"
"6. monthly-payment: (numeric, required) Monthly payment amount\n"
"\nResult:\n"
"\"xxxx\" (string) proposal fee hash (if successful) or error message (if failed)\n"
"\nExamples:\n" +
HelpExampleCli("preparebudget", "\"test-proposal\" \"https://forum.agrarian.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") +
HelpExampleRpc("preparebudget", "\"test-proposal\" \"https://forum.agrarian.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500"));
LOCK2(cs_main, pwalletMain->cs_wallet);
EnsureWalletIsUnlocked();
std::string strProposalName = SanitizeString(params[0].get_str());
if (strProposalName.size() > 20)
throw runtime_error("Invalid proposal name, limit of 20 characters.");
std::string strURL = SanitizeString(params[1].get_str());
if (strURL.size() > 64)
throw runtime_error("Invalid url, limit of 64 characters.");
int nPaymentCount = params[2].get_int();
if (nPaymentCount < 1)
throw runtime_error("Invalid payment count, must be more than zero.");
// Start must be in the next budget cycle
if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks();
int nBlockStart = params[3].get_int();
if (nBlockStart % Params().GetBudgetCycleBlocks() != 0) {
int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks();
throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext));
}
int nBlockEnd = nBlockStart + Params().GetBudgetCycleBlocks() * nPaymentCount; // End must be AFTER current cycle
if (nBlockStart < nBlockMin)
throw runtime_error("Invalid block start, must be more than current height.");
if (nBlockEnd < pindexPrev->nHeight)
throw runtime_error("Invalid ending block, starting block + (payment_cycle*payments) must be more than current height.");
CBitcoinAddress address(params[4].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Agrarian address");
// Parse Agrarian address
CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(params[5]);
//*************************************************************************
// create transaction 15 minutes into the future, to allow for confirmation time
CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, 0);
std::string strError = "";
if (!budgetProposalBroadcast.IsValid(strError, false))
throw runtime_error("Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError);
bool useIX = false; //true;
// if (params.size() > 7) {
// if(params[7].get_str() != "false" && params[7].get_str() != "true")
// return "Invalid use_ix, must be true or false";
// useIX = params[7].get_str() == "true" ? true : false;
// }
CWalletTx wtx;
if (!pwalletMain->GetBudgetSystemCollateralTX(wtx, budgetProposalBroadcast.GetHash(), useIX)) { // 50 AGR collateral for proposal
throw runtime_error("Error making collateral transaction for proposal. Please check your wallet balance.");
}
// make our change address
CReserveKey reservekey(pwalletMain);
//send the tx to the network
pwalletMain->CommitTransaction(wtx, reservekey, useIX ? "ix" : "tx");
return wtx.GetHash().ToString();
}
UniValue submitbudget(const UniValue& params, bool fHelp)
{
int nBlockMin = 0;
CBlockIndex* pindexPrev = chainActive.Tip();
if (fHelp || params.size() != 7)
throw runtime_error(
"submitbudget \"proposal-name\" \"url\" payment-count block-start \"agrarian-address\" monthy-payment \"fee-tx\"\n"
"\nSubmit proposal to the network\n"
"\nArguments:\n"
"1. \"proposal-name\": (string, required) Desired proposal name (20 character limit)\n"
"2. \"url\": (string, required) URL of proposal details (64 character limit)\n"
"3. payment-count: (numeric, required) Total number of monthly payments\n"
"4. block-start: (numeric, required) Starting super block height\n"
"5. \"agrarian-address\": (string, required) Agrarian address to send payments to\n"
"6. monthly-payment: (numeric, required) Monthly payment amount\n"
"7. \"fee-tx\": (string, required) Transaction hash from preparebudget command\n"
"\nResult:\n"
"\"xxxx\" (string) proposal hash (if successful) or error message (if failed)\n"
"\nExamples:\n" +
HelpExampleCli("submitbudget", "\"test-proposal\" \"https://forum.agrarian.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500") +
HelpExampleRpc("submitbudget", "\"test-proposal\" \"https://forum.agrarian.org/t/test-proposal\" 2 820800 \"D9oc6C3dttUbv8zd7zGNq1qKBGf4ZQ1XEE\" 500"));
// Check these inputs the same way we check the vote commands:
// **********************************************************
std::string strProposalName = SanitizeString(params[0].get_str());
if (strProposalName.size() > 20)
throw runtime_error("Invalid proposal name, limit of 20 characters.");
std::string strURL = SanitizeString(params[1].get_str());
if (strURL.size() > 64)
throw runtime_error("Invalid url, limit of 64 characters.");
int nPaymentCount = params[2].get_int();
if (nPaymentCount < 1)
throw runtime_error("Invalid payment count, must be more than zero.");
// Start must be in the next budget cycle
if (pindexPrev != NULL) nBlockMin = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks();
int nBlockStart = params[3].get_int();
if (nBlockStart % Params().GetBudgetCycleBlocks() != 0) {
int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks();
throw runtime_error(strprintf("Invalid block start - must be a budget cycle block. Next valid block: %d", nNext));
}
int nBlockEnd = nBlockStart + (Params().GetBudgetCycleBlocks() * nPaymentCount); // End must be AFTER current cycle
if (nBlockStart < nBlockMin)
throw runtime_error("Invalid block start, must be more than current height.");
if (nBlockEnd < pindexPrev->nHeight)
throw runtime_error("Invalid ending block, starting block + (payment_cycle*payments) must be more than current height.");
CBitcoinAddress address(params[4].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Agrarian address");
// Parse Agrarian address
CScript scriptPubKey = GetScriptForDestination(address.Get());
CAmount nAmount = AmountFromValue(params[5]);
uint256 hash = ParseHashV(params[6], "parameter 1");
//create the proposal incase we're the first to make it
CBudgetProposalBroadcast budgetProposalBroadcast(strProposalName, strURL, nPaymentCount, scriptPubKey, nAmount, nBlockStart, hash);
std::string strError = "";
int nConf = 0;
if (!IsBudgetCollateralValid(hash, budgetProposalBroadcast.GetHash(), strError, budgetProposalBroadcast.nTime, nConf)) {
throw runtime_error("Proposal FeeTX is not valid - " + hash.ToString() + " - " + strError);
}
if (!masternodeSync.IsBlockchainSynced()) {
throw runtime_error("Must wait for client to sync with masternode network. Try again in a minute or so.");
}
// if(!budgetProposalBroadcast.IsValid(strError)){
// return "Proposal is not valid - " + budgetProposalBroadcast.GetHash().ToString() + " - " + strError;
// }
budget.mapSeenMasternodeBudgetProposals.insert(make_pair(budgetProposalBroadcast.GetHash(), budgetProposalBroadcast));
budgetProposalBroadcast.Relay();
if(budget.AddProposal(budgetProposalBroadcast)) {
return budgetProposalBroadcast.GetHash().ToString();
}
throw runtime_error("Invalid proposal, see debug.log for details.");
}
UniValue mnbudgetvote(const UniValue& params, bool fHelp)
{
std::string strCommand;
if (params.size() >= 1) {
strCommand = params[0].get_str();
// Backwards compatibility with legacy `mnbudget` command
if (strCommand == "vote") strCommand = "local";
if (strCommand == "vote-many") strCommand = "many";
if (strCommand == "vote-alias") strCommand = "alias";
}
if (fHelp || (params.size() == 3 && (strCommand != "local" && strCommand != "many")) || (params.size() == 4 && strCommand != "alias") ||
params.size() > 4 || params.size() < 3)
throw runtime_error(
"mnbudgetvote \"local|many|alias\" \"votehash\" \"yes|no\" ( \"alias\" )\n"
"\nVote on a budget proposal\n"
"\nArguments:\n"
"1. \"mode\" (string, required) The voting mode. 'local' for voting directly from a masternode, 'many' for voting with a MN controller and casting the same vote for each MN, 'alias' for voting with a MN controller and casting a vote for a single MN\n"
"2. \"votehash\" (string, required) The vote hash for the proposal\n"
"3. \"votecast\" (string, required) Your vote. 'yes' to vote for the proposal, 'no' to vote against\n"
"4. \"alias\" (string, required for 'alias' mode) The MN alias to cast a vote for.\n"
"\nResult:\n"
"{\n"
" \"overall\": \"xxxx\", (string) The overall status message for the vote cast\n"
" \"detail\": [\n"
" {\n"
" \"node\": \"xxxx\", (string) 'local' or the MN alias\n"
" \"result\": \"xxxx\", (string) Either 'Success' or 'Failed'\n"
" \"error\": \"xxxx\", (string) Error message, if vote failed\n"
" }\n"
" ,...\n"
" ]\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("mnbudgetvote", "\"local\" \"ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041\" \"yes\"") +
HelpExampleRpc("mnbudgetvote", "\"local\" \"ed2f83cedee59a91406f5f47ec4d60bf5a7f9ee6293913c82976bd2d3a658041\" \"yes\""));
uint256 hash = ParseHashV(params[1], "parameter 1");
std::string strVote = params[2].get_str();
if (strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
int nVote = VOTE_ABSTAIN;
if (strVote == "yes") nVote = VOTE_YES;
if (strVote == "no") nVote = VOTE_NO;
int success = 0;
int failed = 0;
UniValue resultsObj(UniValue::VARR);
if (strCommand == "local") {
CPubKey pubKeyMasternode;
CKey keyMasternode;
std::string errorMessage;
UniValue statusObj(UniValue::VOBJ);
while (true) {
if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode)) {
failed++;
statusObj.push_back(Pair("node", "local"));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Masternode signing error, could not set key correctly: " + errorMessage));
resultsObj.push_back(statusObj);
break;
}
CMasternode* pmn = mnodeman.Find(activeMasternode.vin);
if (pmn == NULL) {
failed++;
statusObj.push_back(Pair("node", "local"));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Failure to find masternode in list : " + activeMasternode.vin.ToString()));
resultsObj.push_back(statusObj);
break;
}
CBudgetVote vote(activeMasternode.vin, hash, nVote);
if (!vote.Sign(keyMasternode, pubKeyMasternode)) {
failed++;
statusObj.push_back(Pair("node", "local"));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Failure to sign."));
resultsObj.push_back(statusObj);
break;
}
std::string strError = "";
if (budget.UpdateProposal(vote, NULL, strError)) {
success++;
budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
statusObj.push_back(Pair("node", "local"));
statusObj.push_back(Pair("result", "success"));
statusObj.push_back(Pair("error", ""));
} else {
failed++;
statusObj.push_back(Pair("node", "local"));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Error voting : " + strError));
}
resultsObj.push_back(statusObj);
break;
}
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 == "many") {
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
std::string errorMessage;
std::vector<unsigned char> vchMasterNodeSignature;
std::string strMasterNodeSignMessage;
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
CPubKey pubKeyMasternode;
CKey keyMasternode;
UniValue statusObj(UniValue::VOBJ);
if (!obfuScationSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)) {
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Masternode signing error, could not set key correctly: " + errorMessage));
resultsObj.push_back(statusObj);
continue;
}
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
if (pmn == NULL) {
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Can't find masternode by pubkey"));
resultsObj.push_back(statusObj);
continue;
}
CBudgetVote vote(pmn->vin, hash, nVote);
if (!vote.Sign(keyMasternode, pubKeyMasternode)) {
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Failure to sign."));
resultsObj.push_back(statusObj);
continue;
}
std::string strError = "";
if (budget.UpdateProposal(vote, NULL, strError)) {
budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
success++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "success"));
statusObj.push_back(Pair("error", ""));
} else {
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", strError.c_str()));
}
resultsObj.push_back(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 == "alias") {
std::string strAlias = params[3].get_str();
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
for (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(!obfuScationSigner.SetKey(mne.getPrivKey(), errorMessage, keyMasternode, pubKeyMasternode)){
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Masternode signing error, could not set key correctly: " + errorMessage));
resultsObj.push_back(statusObj);
continue;
}
CMasternode* pmn = mnodeman.Find(pubKeyMasternode);
if(pmn == NULL)
{
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Can't find masternode by pubkey"));
resultsObj.push_back(statusObj);
continue;
}
CBudgetVote vote(pmn->vin, hash, nVote);
if(!vote.Sign(keyMasternode, pubKeyMasternode)){
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "Failure to sign."));
resultsObj.push_back(statusObj);
continue;
}
std::string strError = "";
if(budget.UpdateProposal(vote, NULL, strError)) {
budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
success++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "success"));
statusObj.push_back(Pair("error", ""));
} else {
failed++;
statusObj.push_back(Pair("node", mne.getAlias()));
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", strError.c_str()));
}
resultsObj.push_back(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;
}
return NullUniValue;
}
UniValue getbudgetvotes(const UniValue& params, bool fHelp)
{
if (params.size() != 1)
throw runtime_error(
"getbudgetvotes \"proposal-name\"\n"
"\nPrint vote information for a budget proposal\n"
"\nArguments:\n"
"1. \"proposal-name\": (string, required) Name of the proposal\n"
"\nResult:\n"
"[\n"
" {\n"
" \"mnId\": \"xxxx\", (string) Hash of the masternode's collateral transaction\n"
" \"nHash\": \"xxxx\", (string) Hash of the vote\n"
" \"Vote\": \"YES|NO\", (string) Vote cast ('YES' or 'NO')\n"
" \"nTime\": xxxx, (numeric) Time in seconds since epoch the vote was cast\n"
" \"fValid\": true|false, (boolean) 'true' if the vote is valid, 'false' otherwise\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("getbudgetvotes", "\"test-proposal\"") + HelpExampleRpc("getbudgetvotes", "\"test-proposal\""));
std::string strProposalName = SanitizeString(params[0].get_str());
UniValue ret(UniValue::VARR);
CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName);
if (pbudgetProposal == NULL) throw runtime_error("Unknown proposal name");
std::map<uint256, CBudgetVote>::iterator it = pbudgetProposal->mapVotes.begin();
while (it != pbudgetProposal->mapVotes.end()) {
UniValue bObj(UniValue::VOBJ);
bObj.push_back(Pair("mnId", (*it).second.vin.prevout.hash.ToString()));
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));
ret.push_back(bObj);
it++;
}
return ret;
}
UniValue getnextsuperblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getnextsuperblock\n"
"\nPrint the next super block height\n"
"\nResult:\n"
"n (numeric) Block height of the next super block\n"
"\nExamples:\n" +
HelpExampleCli("getnextsuperblock", "") + HelpExampleRpc("getnextsuperblock", ""));
CBlockIndex* pindexPrev = chainActive.Tip();
if (!pindexPrev) return "unknown";
int nNext = pindexPrev->nHeight - pindexPrev->nHeight % Params().GetBudgetCycleBlocks() + Params().GetBudgetCycleBlocks();
return nNext;
}
UniValue getbudgetprojection(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getbudgetprojection\n"
"\nShow the projection of which proposals will be paid the next cycle\n"
"\nResult:\n"
"[\n"
" {\n"
" \"Name\": \"xxxx\", (string) Proposal Name\n"
" \"URL\": \"xxxx\", (string) Proposal URL\n"
" \"Hash\": \"xxxx\", (string) Proposal vote hash\n"
" \"FeeHash\": \"xxxx\", (string) Proposal fee hash\n"
" \"BlockStart\": n, (numeric) Proposal starting block\n"
" \"BlockEnd\": n, (numeric) Proposal ending block\n"
" \"TotalPaymentCount\": n, (numeric) Number of payments\n"
" \"RemainingPaymentCount\": n, (numeric) Number of remaining payments\n"
" \"PaymentAddress\": \"xxxx\", (string) Agrarian address of payment\n"
" \"Ratio\": x.xxx, (numeric) Ratio of yeas vs nays\n"
" \"Yeas\": n, (numeric) Number of yea votes\n"
" \"Nays\": n, (numeric) Number of nay votes\n"
" \"Abstains\": n, (numeric) Number of abstains\n"
" \"TotalPayment\": xxx.xxx, (numeric) Total payment amount\n"
" \"MonthlyPayment\": xxx.xxx, (numeric) Monthly payment amount\n"
" \"IsEstablished\": true|false, (boolean) Established (true) or (false)\n"
" \"IsValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
" \"IsValidReason\": \"xxxx\", (string) Error message, if any\n"
" \"fValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
" \"Alloted\": xxx.xxx, (numeric) Amount alloted in current period\n"
" \"TotalBudgetAlloted\": xxx.xxx (numeric) Total alloted\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", ""));
UniValue ret(UniValue::VARR);
UniValue resultObj(UniValue::VOBJ);
CAmount nTotalAllotted = 0;
std::vector<CBudgetProposal*> winningProps = budget.GetBudget();
for (CBudgetProposal* pbudgetProposal : winningProps) {
nTotalAllotted += pbudgetProposal->GetAllotted();
CTxDestination address1;
ExtractDestination(pbudgetProposal->GetPayee(), address1);
CBitcoinAddress address2(address1);
UniValue bObj(UniValue::VOBJ);
budgetToJSON(pbudgetProposal, bObj);
bObj.push_back(Pair("Alloted", ValueFromAmount(pbudgetProposal->GetAllotted())));
bObj.push_back(Pair("TotalBudgetAlloted", ValueFromAmount(nTotalAllotted)));
ret.push_back(bObj);
}
return ret;
}
UniValue getbudgetinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getbudgetinfo ( \"proposal\" )\n"
"\nShow current masternode budgets\n"
"\nArguments:\n"
"1. \"proposal\" (string, optional) Proposal name\n"
"\nResult:\n"
"[\n"
" {\n"
" \"Name\": \"xxxx\", (string) Proposal Name\n"
" \"URL\": \"xxxx\", (string) Proposal URL\n"
" \"Hash\": \"xxxx\", (string) Proposal vote hash\n"
" \"FeeHash\": \"xxxx\", (string) Proposal fee hash\n"
" \"BlockStart\": n, (numeric) Proposal starting block\n"
" \"BlockEnd\": n, (numeric) Proposal ending block\n"
" \"TotalPaymentCount\": n, (numeric) Number of payments\n"
" \"RemainingPaymentCount\": n, (numeric) Number of remaining payments\n"
" \"PaymentAddress\": \"xxxx\", (string) Agrarian address of payment\n"
" \"Ratio\": x.xxx, (numeric) Ratio of yeas vs nays\n"
" \"Yeas\": n, (numeric) Number of yea votes\n"
" \"Nays\": n, (numeric) Number of nay votes\n"
" \"Abstains\": n, (numeric) Number of abstains\n"
" \"TotalPayment\": xxx.xxx, (numeric) Total payment amount\n"
" \"MonthlyPayment\": xxx.xxx, (numeric) Monthly payment amount\n"
" \"IsEstablished\": true|false, (boolean) Established (true) or (false)\n"
" \"IsValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
" \"IsValidReason\": \"xxxx\", (string) Error message, if any\n"
" \"fValid\": true|false, (boolean) Valid (true) or Invalid (false)\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("getbudgetprojection", "") + HelpExampleRpc("getbudgetprojection", ""));
UniValue ret(UniValue::VARR);
std::string strShow = "valid";
if (params.size() == 1) {
std::string strProposalName = SanitizeString(params[0].get_str());
CBudgetProposal* pbudgetProposal = budget.FindProposal(strProposalName);
if (pbudgetProposal == NULL) throw runtime_error("Unknown proposal name");
UniValue bObj(UniValue::VOBJ);
budgetToJSON(pbudgetProposal, bObj);
ret.push_back(bObj);
return ret;
}
std::vector<CBudgetProposal*> winningProps = budget.GetAllProposals();
for (CBudgetProposal* pbudgetProposal : winningProps) {
if (strShow == "valid" && !pbudgetProposal->fValid) continue;
UniValue bObj(UniValue::VOBJ);
budgetToJSON(pbudgetProposal, bObj);
ret.push_back(bObj);
}
return ret;
}
UniValue mnbudgetrawvote(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 6)
throw runtime_error(
"mnbudgetrawvote \"masternode-tx-hash\" masternode-tx-index \"proposal-hash\" yes|no time \"vote-sig\"\n"
"\nCompile and relay a proposal vote with provided external signature instead of signing vote internally\n"
"\nArguments:\n"
"1. \"masternode-tx-hash\" (string, required) Transaction hash for the masternode\n"
"2. masternode-tx-index (numeric, required) Output index for the masternode\n"
"3. \"proposal-hash\" (string, required) Proposal vote hash\n"
"4. yes|no (boolean, required) Vote to cast\n"
"5. time (numeric, required) Time since epoch in seconds\n"
"6. \"vote-sig\" (string, required) External signature\n"
"\nResult:\n"
"\"status\" (string) Vote status or error message\n"
"\nExamples:\n" +
HelpExampleCli("mnbudgetrawvote", "") + HelpExampleRpc("mnbudgetrawvote", ""));
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();
if (strVote != "yes" && strVote != "no") return "You can only vote 'yes' or 'no'";
int nVote = VOTE_ABSTAIN;
if (strVote == "yes") nVote = VOTE_YES;
if (strVote == "no") nVote = VOTE_NO;
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) {
return "Failure to find masternode in list : " + vin.ToString();
}
CBudgetVote vote(vin, hashProposal, nVote);
vote.nTime = nTime;
vote.vchSig = vchSig;
if (!vote.SignatureValid(true)) {
return "Failure to verify signature.";
}
std::string strError = "";
if (budget.UpdateProposal(vote, NULL, strError)) {
budget.mapSeenMasternodeBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
return "Voted successfully";
} else {
return "Error voting : " + strError;
}
}
UniValue mnfinalbudget(const UniValue& params, bool fHelp)
{
string strCommand;
if (params.size() >= 1)
strCommand = params[0].get_str();
if (fHelp ||
(strCommand != "suggest" && strCommand != "vote-many" && strCommand != "vote" && strCommand != "show" && strCommand != "getvotes"))
throw runtime_error(
"mnfinalbudget \"command\"... ( \"passphrase\" )\n"
"\nVote or show current budgets\n"
"\nAvailable commands:\n"
" vote-many - Vote on a finalized budget\n"
" vote - Vote on a finalized budget\n"
" show - Show existing finalized budgets\n"
" getvotes - Get vote information for each finalized budget\n");
if (strCommand == "vote-many") {
if (params.size() != 2)
throw runtime_error("Correct usage is 'mnfinalbudget vote-many BUDGET_HASH'");
std::string strHash = params[1].get_str();
uint256 hash(strHash);
int success = 0;
int failed = 0;
UniValue resultsObj(UniValue::VOBJ);
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
std::string errorMessage;
std::vector<unsigned char> vchMasterNodeSignature;
std::string strMasterNodeSignMessage;
CPubKey pubKeyCollateralAddress;
CKey keyCollateralAddress;
CPubKey pubKeyMasternode;
CKey keyMasternode;
UniValue statusObj(UniValue::VOBJ);
if (!obfuScationSigner.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;
}
CFinalizedBudgetVote vote(pmn->vin, hash);
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 (budget.UpdateFinalizedBudget(vote, NULL, strError)) {
budget.mapSeenFinalizedBudgetVotes.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 == "vote") {
if (params.size() != 2)
throw runtime_error("Correct usage is 'mnfinalbudget vote BUDGET_HASH'");
std::string strHash = params[1].get_str();
uint256 hash(strHash);
CPubKey pubKeyMasternode;
CKey keyMasternode;
std::string errorMessage;
if (!obfuScationSigner.SetKey(strMasterNodePrivKey, errorMessage, keyMasternode, pubKeyMasternode))
return "Error upon calling SetKey";
CMasternode* pmn = mnodeman.Find(activeMasternode.vin);
if (pmn == NULL) {
return "Failure to find masternode in list : " + activeMasternode.vin.ToString();
}
CFinalizedBudgetVote vote(activeMasternode.vin, hash);
if (!vote.Sign(keyMasternode, pubKeyMasternode)) {
return "Failure to sign.";
}
std::string strError = "";
if (budget.UpdateFinalizedBudget(vote, NULL, strError)) {
budget.mapSeenFinalizedBudgetVotes.insert(make_pair(vote.GetHash(), vote));
vote.Relay();
return "success";
} else {
return "Error voting : " + strError;
}
}
if (strCommand == "show") {
UniValue resultObj(UniValue::VOBJ);
std::vector<CFinalizedBudget*> winningFbs = budget.GetFinalizedBudgets();
for (CFinalizedBudget* finalizedBudget : winningFbs) {
UniValue bObj(UniValue::VOBJ);
bObj.push_back(Pair("FeeTX", finalizedBudget->nFeeTXHash.ToString()));
bObj.push_back(Pair("Hash", finalizedBudget->GetHash().ToString()));
bObj.push_back(Pair("BlockStart", (int64_t)finalizedBudget->GetBlockStart()));
bObj.push_back(Pair("BlockEnd", (int64_t)finalizedBudget->GetBlockEnd()));
bObj.push_back(Pair("Proposals", finalizedBudget->GetProposals()));
bObj.push_back(Pair("VoteCount", (int64_t)finalizedBudget->GetVoteCount()));
bObj.push_back(Pair("Status", finalizedBudget->GetStatus()));
std::string strError = "";
bObj.push_back(Pair("IsValid", finalizedBudget->IsValid(strError)));
bObj.push_back(Pair("IsValidReason", strError.c_str()));
resultObj.push_back(Pair(finalizedBudget->GetName(), bObj));
}
return resultObj;
}
if (strCommand == "getvotes") {
if (params.size() != 2)
throw runtime_error("Correct usage is 'mnbudget getvotes budget-hash'");
std::string strHash = params[1].get_str();
uint256 hash(strHash);
UniValue obj(UniValue::VOBJ);
CFinalizedBudget* pfinalBudget = budget.FindFinalizedBudget(hash);
if (pfinalBudget == NULL) return "Unknown budget hash";
std::map<uint256, CFinalizedBudgetVote>::iterator it = pfinalBudget->mapVotes.begin();
while (it != pfinalBudget->mapVotes.end()) {
UniValue bObj(UniValue::VOBJ);
bObj.push_back(Pair("nHash", (*it).first.ToString().c_str()));
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 checkbudgets(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"checkbudgets\n"
"\nInitiates a buddget check cycle manually\n"
"\nExamples:\n" +
HelpExampleCli("checkbudgets", "") + HelpExampleRpc("checkbudgets", ""));
budget.CheckAndRemove();
return NullUniValue;
}
+224
View File
@@ -0,0 +1,224 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "rpc/client.h"
#include "rpc/protocol.h"
#include "guiinterface.h"
#include "util.h"
#include <set>
#include <stdint.h>
#include <boost/algorithm/string/case_conv.hpp> // for to_lower()
#include <univalue.h>
using namespace std;
class CRPCConvertParam
{
public:
std::string methodName; //! method whose params want conversion
int paramIdx; //! 0-based idx of param to convert
};
// ***TODO***
static const CRPCConvertParam vRPCConvertParams[] =
{
{"stop", 0},
{"setmocktime", 0},
{"getaddednodeinfo", 0},
{"setgenerate", 0},
{"setgenerate", 1},
{"generate", 0},
{"getnetworkhashps", 0},
{"getnetworkhashps", 1},
{"sendtoaddress", 1},
{"sendtoaddressix", 1},
{"settxfee", 0},
{"getreceivedbyaddress", 1},
{"getreceivedbyaccount", 1},
{"listreceivedbyaddress", 0},
{"listreceivedbyaddress", 1},
{"listreceivedbyaddress", 2},
{"listreceivedbyaccount", 0},
{"listreceivedbyaccount", 1},
{"listreceivedbyaccount", 2},
{"getbalance", 1},
{"getbalance", 2},
{"getblockhash", 0},
{ "waitforblockheight", 0 },
{ "waitforblockheight", 1 },
{ "waitforblock", 1 },
{ "waitforblock", 2 },
{ "waitfornewblock", 0 },
{ "waitfornewblock", 1 },
{"move", 2},
{"move", 3},
{"sendfrom", 2},
{"sendfrom", 3},
{"listtransactions", 1},
{"listtransactions", 2},
{"listtransactions", 3},
{"listaccounts", 0},
{"listaccounts", 1},
{"walletpassphrase", 1},
{"walletpassphrase", 2},
{"getblocktemplate", 0},
{"listsinceblock", 1},
{"listsinceblock", 2},
{"sendmany", 1},
{"sendmany", 2},
{"addmultisigaddress", 0},
{"addmultisigaddress", 1},
{"createmultisig", 0},
{"createmultisig", 1},
{"listunspent", 0},
{"listunspent", 1},
{"listunspent", 2},
{"listunspent", 3},
{"getblock", 1},
{"getblockheader", 1},
{"gettransaction", 1},
{"getrawtransaction", 1},
{"createrawtransaction", 0},
{"createrawtransaction", 1},
{"createrawtransaction", 2},
{"signrawtransaction", 1},
{"signrawtransaction", 2},
{"sendrawtransaction", 1},
{"sendrawtransaction", 2},
{"gettxout", 1},
{"gettxout", 2},
{"lockunspent", 0},
{"lockunspent", 1},
{"importprivkey", 2},
{"importaddress", 2},
{"verifychain", 0},
{"verifychain", 1},
{"keypoolrefill", 0},
{"getrawmempool", 0},
{"estimatefee", 0},
{"estimatepriority", 0},
{"prioritisetransaction", 1},
{"prioritisetransaction", 2},
{"setban", 2},
{"setban", 3},
{"spork", 1},
{"preparebudget", 2},
{"preparebudget", 3},
{"preparebudget", 5},
{"submitbudget", 2},
{"submitbudget", 3},
{"submitbudget", 5},
{"submitbudget", 7},
// disabled until removal of the legacy 'masternode' command
//{"startmasternode", 1},
{"mnvoteraw", 1},
{"mnvoteraw", 4},
{"reservebalance", 0},
{"reservebalance", 1},
{"setstakesplitthreshold", 0},
{"autocombinerewards", 0},
{"autocombinerewards", 1},
{"getzerocoinbalance", 0},
{"listmintedzerocoins", 0},
{"listmintedzerocoins", 1},
{"listspentzerocoins", 0},
{"listzerocoinamounts", 0},
{"mintzerocoin", 0},
{"mintzerocoin", 1},
{"spendzerocoin", 0},
{"spendzerocoin", 1},
{"spendzerocoin", 2},
{"spendrawzerocoin", 2},
{"spendzerocoinmints", 0},
{"importzerocoins", 0},
{"exportzerocoins", 0},
{"exportzerocoins", 1},
{"resetmintzerocoin", 0},
{"getspentzerocoinamount", 1},
{"generatemintlist", 0},
{"generatemintlist", 1},
{"searchdzagr", 0},
{"searchdzagr", 1},
{"searchdzagr", 2},
{"getaccumulatorvalues", 0},
{"getaccumulatorwitness",2},
{"getmintsvalues", 2},
{"enableautomintaddress", 0},
{"getblockindexstats", 0},
{"getblockindexstats", 1},
{"getblockindexstats", 2},
{"getmintsinblocks", 0},
{"getmintsinblocks", 1},
{"getmintsinblocks", 2},
{"getserials", 0},
{"getserials", 1},
{"getserials", 2},
{"getfeeinfo", 0},
{"getchecksumblock", 1},
{"getchecksumblock", 2},
};
class CRPCConvertTable
{
private:
std::set<std::pair<std::string, int> > members;
public:
CRPCConvertTable();
bool convert(const std::string& method, int idx)
{
return (members.count(std::make_pair(method, idx)) > 0);
}
};
CRPCConvertTable::CRPCConvertTable()
{
const unsigned int n_elem =
(sizeof(vRPCConvertParams) / sizeof(vRPCConvertParams[0]));
for (unsigned int i = 0; i < n_elem; i++) {
members.insert(std::make_pair(vRPCConvertParams[i].methodName,
vRPCConvertParams[i].paramIdx));
}
}
static CRPCConvertTable rpcCvtTable;
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
* as well as objects and arrays.
*/
UniValue ParseNonRFCJSONValue(const std::string& strVal)
{
UniValue jVal;
if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
!jVal.isArray() || jVal.size()!=1)
throw runtime_error(string("Error parsing JSON:")+strVal);
return jVal[0];
}
/** Convert strings to command-specific RPC representation */
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
{
UniValue params(UniValue::VARR);
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
const std::string& strVal = strParams[idx];
if (!rpcCvtTable.convert(strMethod, idx)) {
// insert string value directly
params.push_back(strVal);
} else {
// parse string as JSON, insert bool/number/object/etc. value
params.push_back(ParseNonRFCJSONValue(strVal));
}
}
return params;
}
+18
View File
@@ -0,0 +1,18 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin developers
// Copyright (c) 2017-2018 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_RPCCLIENT_H
#define BITCOIN_RPCCLIENT_H
#include <univalue.h>
UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams);
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
* as well as objects and arrays.
*/
UniValue ParseNonRFCJSONValue(const std::string& strVal);
#endif // BITCOIN_RPCCLIENT_H
+962
View File
@@ -0,0 +1,962 @@
// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "activemasternode.h"
#include "db.h"
#include "init.h"
#include "main.h"
#include "masternode-budget.h"
#include "masternode-payments.h"
#include "masternodeconfig.h"
#include "masternodeman.h"
#include "rpc/server.h"
#include "utilmoneystr.h"
#include <univalue.h>
#include <boost/tokenizer.hpp>
#include <fstream>
UniValue getpoolinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getpoolinfo\n"
"\nReturns anonymous pool-related information\n"
"\nResult:\n"
"{\n"
" \"current\": \"addr\", (string) Agrarian address of current masternode\n"
" \"state\": xxxx, (string) unknown\n"
" \"entries\": xxxx, (numeric) Number of entries\n"
" \"accepted\": xxxx, (numeric) Number of entries accepted\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getpoolinfo", "") + HelpExampleRpc("getpoolinfo", ""));
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("current_masternode", mnodeman.GetCurrentMasterNode()->addr.ToString()));
obj.push_back(Pair("state", obfuScationPool.GetState()));
obj.push_back(Pair("entries", obfuScationPool.GetEntriesCount()));
obj.push_back(Pair("entries_accepted", obfuScationPool.GetCountEntriesAccepted()));
return obj;
}
UniValue listmasternodes(const UniValue& params, bool fHelp)
{
std::string strFilter = "";
if (params.size() == 1) strFilter = params[0].get_str();
if (fHelp || (params.size() > 1))
throw runtime_error(
"listmasternodes ( \"filter\" )\n"
"\nGet a ranked list of masternodes\n"
"\nArguments:\n"
"1. \"filter\" (string, optional) Filter search text. Partial match by txhash, status, or addr.\n"
"\nResult:\n"
"[\n"
" {\n"
" \"rank\": n, (numeric) Masternode Rank (or 0 if not enabled)\n"
" \"txhash\": \"hash\", (string) Collateral transaction hash\n"
" \"outidx\": n, (numeric) Collateral transaction output index\n"
" \"pubkey\": \"key\", (string) Masternode public key used for message broadcasting\n"
" \"status\": s, (string) Status (ENABLED/EXPIRED/REMOVE/etc)\n"
" \"addr\": \"addr\", (string) Masternode Agrarian address\n"
" \"version\": v, (numeric) Masternode protocol version\n"
" \"lastseen\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last seen\n"
" \"activetime\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) masternode has been active\n"
" \"lastpaid\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) masternode was last paid\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("listmasternodes", "") + HelpExampleRpc("listmasternodes", ""));
UniValue ret(UniValue::VARR);
int nHeight;
{
LOCK(cs_main);
CBlockIndex* pindex = chainActive.Tip();
if(!pindex) return 0;
nHeight = pindex->nHeight;
}
std::vector<pair<int, CMasternode> > vMasternodeRanks = mnodeman.GetMasternodeRanks(nHeight);
for (PAIRTYPE(int, CMasternode) & s : vMasternodeRanks) {
UniValue obj(UniValue::VOBJ);
std::string strVin = s.second.vin.prevout.ToStringShort();
std::string strTxHash = s.second.vin.prevout.hash.ToString();
uint32_t oIdx = s.second.vin.prevout.n;
CMasternode* mn = mnodeman.Find(s.second.vin);
if (mn != NULL) {
if (strFilter != "" && strTxHash.find(strFilter) == string::npos &&
mn->Status().find(strFilter) == string::npos &&
CBitcoinAddress(mn->pubKeyCollateralAddress.GetID()).ToString().find(strFilter) == string::npos) continue;
std::string strStatus = mn->Status();
std::string strHost;
int port;
SplitHostPort(mn->addr.ToString(), port, strHost);
CNetAddr node = CNetAddr(strHost, false);
std::string strNetwork = GetNetworkName(node.GetNetwork());
obj.push_back(Pair("rank", (strStatus == "ENABLED" ? s.first : 0)));
obj.push_back(Pair("network", strNetwork));
obj.push_back(Pair("txhash", strTxHash));
obj.push_back(Pair("outidx", (uint64_t)oIdx));
obj.push_back(Pair("pubkey", HexStr(mn->pubKeyMasternode)));
obj.push_back(Pair("status", strStatus));
obj.push_back(Pair("addr", CBitcoinAddress(mn->pubKeyCollateralAddress.GetID()).ToString()));
obj.push_back(Pair("version", mn->protocolVersion));
obj.push_back(Pair("lastseen", (int64_t)mn->lastPing.sigTime));
obj.push_back(Pair("activetime", (int64_t)(mn->lastPing.sigTime - mn->sigTime)));
obj.push_back(Pair("lastpaid", (int64_t)mn->GetLastPaid()));
ret.push_back(obj);
}
}
return ret;
}
UniValue masternodeconnect(const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 1))
throw runtime_error(
"masternodeconnect \"address\"\n"
"\nAttempts to connect to specified masternode address\n"
"\nArguments:\n"
"1. \"address\" (string, required) IP or net address to connect to\n"
"\nExamples:\n" +
HelpExampleCli("masternodeconnect", "\"192.168.0.6:51336\"") + HelpExampleRpc("masternodeconnect", "\"192.168.0.6:51336\""));
std::string strAddress = params[0].get_str();
CService addr = CService(strAddress);
CNode* pnode = ConnectNode((CAddress)addr, NULL, false);
if (pnode) {
pnode->Release();
return NullUniValue;
} else {
throw runtime_error("error connecting\n");
}
}
UniValue getmasternodecount (const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() > 0))
throw runtime_error(
"getmasternodecount\n"
"\nGet masternode count values\n"
"\nResult:\n"
"{\n"
" \"total\": n, (numeric) Total masternodes\n"
" \"stable\": n, (numeric) Stable count\n"
" \"obfcompat\": n, (numeric) Obfuscation Compatible\n"
" \"enabled\": n, (numeric) Enabled masternodes\n"
" \"inqueue\": n (numeric) Masternodes in queue\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getmasternodecount", "") + HelpExampleRpc("getmasternodecount", ""));
UniValue obj(UniValue::VOBJ);
int nCount = 0;
int ipv4 = 0, ipv6 = 0, onion = 0;
if (chainActive.Tip())
mnodeman.GetNextMasternodeInQueueForPayment(chainActive.Tip()->nHeight, true, nCount);
mnodeman.CountNetworks(ActiveProtocol(), ipv4, ipv6, onion);
obj.push_back(Pair("total", mnodeman.size()));
obj.push_back(Pair("stable", mnodeman.stable_size()));
obj.push_back(Pair("obfcompat", mnodeman.CountEnabled(ActiveProtocol())));
obj.push_back(Pair("enabled", mnodeman.CountEnabled()));
obj.push_back(Pair("inqueue", nCount));
obj.push_back(Pair("ipv4", ipv4));
obj.push_back(Pair("ipv6", ipv6));
obj.push_back(Pair("onion", onion));
return obj;
}
UniValue masternodecurrent (const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 0))
throw runtime_error(
"masternodecurrent\n"
"\nGet current masternode winner\n"
"\nResult:\n"
"{\n"
" \"protocol\": xxxx, (numeric) Protocol version\n"
" \"txhash\": \"xxxx\", (string) Collateral transaction hash\n"
" \"pubkey\": \"xxxx\", (string) MN Public key\n"
" \"lastseen\": xxx, (numeric) Time since epoch of last seen\n"
" \"activeseconds\": xxx, (numeric) Seconds MN has been active\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("masternodecurrent", "") + HelpExampleRpc("masternodecurrent", ""));
CMasternode* winner = mnodeman.GetCurrentMasterNode(1);
if (winner) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("protocol", (int64_t)winner->protocolVersion));
obj.push_back(Pair("txhash", winner->vin.prevout.hash.ToString()));
obj.push_back(Pair("pubkey", CBitcoinAddress(winner->pubKeyCollateralAddress.GetID()).ToString()));
obj.push_back(Pair("lastseen", (winner->lastPing == CMasternodePing()) ? winner->sigTime : (int64_t)winner->lastPing.sigTime));
obj.push_back(Pair("activeseconds", (winner->lastPing == CMasternodePing()) ? 0 : (int64_t)(winner->lastPing.sigTime - winner->sigTime)));
return obj;
}
throw runtime_error("unknown");
}
UniValue masternodedebug (const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 0))
throw runtime_error(
"masternodedebug\n"
"\nPrint masternode status\n"
"\nResult:\n"
"\"status\" (string) Masternode status message\n"
"\nExamples:\n" +
HelpExampleCli("masternodedebug", "") + HelpExampleRpc("masternodedebug", ""));
if (activeMasternode.status != ACTIVE_MASTERNODE_INITIAL || !masternodeSync.IsSynced())
return activeMasternode.GetStatus();
CTxIn vin = CTxIn();
CPubKey pubkey;
CKey key;
if (!activeMasternode.GetMasterNodeVin(vin, pubkey, key))
throw runtime_error("Missing masternode input, please look at the documentation for instructions on masternode creation\n");
else
return activeMasternode.GetStatus();
}
UniValue startmasternode (const UniValue& params, bool fHelp)
{
std::string strCommand;
if (params.size() >= 1) {
strCommand = params[0].get_str();
// Backwards compatibility with legacy 'masternode' super-command forwarder
if (strCommand == "start") strCommand = "local";
if (strCommand == "start-alias") strCommand = "alias";
if (strCommand == "start-all") strCommand = "all";
if (strCommand == "start-many") strCommand = "many";
if (strCommand == "start-missing") strCommand = "missing";
if (strCommand == "start-disabled") strCommand = "disabled";
}
if (fHelp || params.size() < 2 || params.size() > 3 ||
(params.size() == 2 && (strCommand != "local" && strCommand != "all" && strCommand != "many" && strCommand != "missing" && strCommand != "disabled")) ||
(params.size() == 3 && strCommand != "alias"))
throw runtime_error(
"startmasternode \"local|all|many|missing|disabled|alias\" lockwallet ( \"alias\" )\n"
"\nAttempts to start one or more masternode(s)\n"
"\nArguments:\n"
"1. set (string, required) Specify which set of masternode(s) to start.\n"
"2. lockwallet (boolean, required) Lock wallet after completion.\n"
"3. alias (string) Masternode alias. Required if using 'alias' as the set.\n"
"\nResult: (for 'local' set):\n"
"\"status\" (string) Masternode status message\n"
"\nResult: (for other sets):\n"
"{\n"
" \"overall\": \"xxxx\", (string) Overall status message\n"
" \"detail\": [\n"
" {\n"
" \"node\": \"xxxx\", (string) Node name or alias\n"
" \"result\": \"xxxx\", (string) 'success' or 'failed'\n"
" \"error\": \"xxxx\" (string) Error message, if failed\n"
" }\n"
" ,...\n"
" ]\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("startmasternode", "\"alias\" \"0\" \"my_mn\"") + HelpExampleRpc("startmasternode", "\"alias\" \"0\" \"my_mn\""));
bool fLock = (params[1].get_str() == "true" ? true : false);
EnsureWalletIsUnlocked();
if (strCommand == "local") {
if (!fMasterNode) throw runtime_error("you must set masternode=1 in the configuration\n");
if (activeMasternode.status != ACTIVE_MASTERNODE_STARTED) {
activeMasternode.status = ACTIVE_MASTERNODE_INITIAL; // TODO: consider better way
activeMasternode.ManageStatus();
if (fLock)
pwalletMain->Lock();
}
return activeMasternode.GetStatus();
}
if (strCommand == "all" || strCommand == "many" || strCommand == "missing" || strCommand == "disabled") {
if ((strCommand == "missing" || strCommand == "disabled") &&
(masternodeSync.RequestedMasternodeAssets <= MASTERNODE_SYNC_LIST ||
masternodeSync.RequestedMasternodeAssets == MASTERNODE_SYNC_FAILED)) {
throw runtime_error("You can't use this command until masternode list is synced\n");
}
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
int successful = 0;
int failed = 0;
UniValue resultsObj(UniValue::VARR);
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
std::string errorMessage;
int nIndex;
if(!mne.castOutputIndex(nIndex))
continue;
CTxIn vin = CTxIn(uint256(mne.getTxHash()), uint32_t(nIndex));
CMasternode* pmn = mnodeman.Find(vin);
CMasternodeBroadcast mnb;
if (pmn != NULL) {
if (strCommand == "missing") continue;
if (strCommand == "disabled" && pmn->IsEnabled()) continue;
}
bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb);
UniValue statusObj(UniValue::VOBJ);
statusObj.push_back(Pair("alias", mne.getAlias()));
statusObj.push_back(Pair("result", result ? "success" : "failed"));
if (result) {
successful++;
statusObj.push_back(Pair("error", ""));
} else {
failed++;
statusObj.push_back(Pair("error", errorMessage));
}
resultsObj.push_back(statusObj);
}
if (fLock)
pwalletMain->Lock();
UniValue returnObj(UniValue::VOBJ);
returnObj.push_back(Pair("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", successful, failed, successful + failed)));
returnObj.push_back(Pair("detail", resultsObj));
return returnObj;
}
if (strCommand == "alias") {
std::string alias = params[2].get_str();
bool found = false;
int successful = 0;
int failed = 0;
UniValue resultsObj(UniValue::VARR);
UniValue statusObj(UniValue::VOBJ);
statusObj.push_back(Pair("alias", alias));
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
if (mne.getAlias() == alias) {
found = true;
std::string errorMessage;
CMasternodeBroadcast mnb;
bool result = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb);
statusObj.push_back(Pair("result", result ? "successful" : "failed"));
if (result) {
successful++;
mnodeman.UpdateMasternodeList(mnb);
mnb.Relay();
} else {
failed++;
statusObj.push_back(Pair("errorMessage", errorMessage));
}
break;
}
}
if (!found) {
failed++;
statusObj.push_back(Pair("result", "failed"));
statusObj.push_back(Pair("error", "could not find alias in config. Verify with list-conf."));
}
resultsObj.push_back(statusObj);
if (fLock)
pwalletMain->Lock();
UniValue returnObj(UniValue::VOBJ);
returnObj.push_back(Pair("overall", strprintf("Successfully started %d masternodes, failed to start %d, total %d", successful, failed, successful + failed)));
returnObj.push_back(Pair("detail", resultsObj));
return returnObj;
}
return NullUniValue;
}
UniValue createmasternodekey (const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 0))
throw runtime_error(
"createmasternodekey\n"
"\nCreate a new masternode private key\n"
"\nResult:\n"
"\"key\" (string) Masternode private key\n"
"\nExamples:\n" +
HelpExampleCli("createmasternodekey", "") + HelpExampleRpc("createmasternodekey", ""));
CKey secret;
secret.MakeNewKey(false);
return CBitcoinSecret(secret).ToString();
}
UniValue getmasternodeoutputs (const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 0))
throw runtime_error(
"getmasternodeoutputs\n"
"\nPrint all masternode transaction outputs\n"
"\nResult:\n"
"[\n"
" {\n"
" \"txhash\": \"xxxx\", (string) output transaction hash\n"
" \"outputidx\": n (numeric) output index number\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("getmasternodeoutputs", "") + HelpExampleRpc("getmasternodeoutputs", ""));
// Find possible candidates
vector<COutput> possibleCoins = activeMasternode.SelectCoinsMasternode();
UniValue ret(UniValue::VARR);
for (COutput& out : possibleCoins) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("txhash", out.tx->GetHash().ToString()));
obj.push_back(Pair("outputidx", out.i));
ret.push_back(obj);
}
return ret;
}
UniValue listmasternodeconf (const UniValue& params, bool fHelp)
{
std::string strFilter = "";
if (params.size() == 1) strFilter = params[0].get_str();
if (fHelp || (params.size() > 1))
throw runtime_error(
"listmasternodeconf ( \"filter\" )\n"
"\nPrint masternode.conf in JSON format\n"
"\nArguments:\n"
"1. \"filter\" (string, optional) Filter search text. Partial match on alias, address, txHash, or status.\n"
"\nResult:\n"
"[\n"
" {\n"
" \"alias\": \"xxxx\", (string) masternode alias\n"
" \"address\": \"xxxx\", (string) masternode IP address\n"
" \"privateKey\": \"xxxx\", (string) masternode private key\n"
" \"txHash\": \"xxxx\", (string) transaction hash\n"
" \"outputIndex\": n, (numeric) transaction output index\n"
" \"status\": \"xxxx\" (string) masternode status\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("listmasternodeconf", "") + HelpExampleRpc("listmasternodeconf", ""));
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
UniValue ret(UniValue::VARR);
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
int nIndex;
if(!mne.castOutputIndex(nIndex))
continue;
CTxIn vin = CTxIn(uint256(mne.getTxHash()), uint32_t(nIndex));
CMasternode* pmn = mnodeman.Find(vin);
std::string strStatus = pmn ? pmn->Status() : "MISSING";
if (strFilter != "" && mne.getAlias().find(strFilter) == string::npos &&
mne.getIp().find(strFilter) == string::npos &&
mne.getTxHash().find(strFilter) == string::npos &&
strStatus.find(strFilter) == string::npos) continue;
UniValue mnObj(UniValue::VOBJ);
mnObj.push_back(Pair("alias", mne.getAlias()));
mnObj.push_back(Pair("address", mne.getIp()));
mnObj.push_back(Pair("privateKey", mne.getPrivKey()));
mnObj.push_back(Pair("txHash", mne.getTxHash()));
mnObj.push_back(Pair("outputIndex", mne.getOutputIndex()));
mnObj.push_back(Pair("status", strStatus));
ret.push_back(mnObj);
}
return ret;
}
UniValue getmasternodestatus (const UniValue& params, bool fHelp)
{
if (fHelp || (params.size() != 0))
throw runtime_error(
"getmasternodestatus\n"
"\nPrint masternode status\n"
"\nResult:\n"
"{\n"
" \"txhash\": \"xxxx\", (string) Collateral transaction hash\n"
" \"outputidx\": n, (numeric) Collateral transaction output index number\n"
" \"netaddr\": \"xxxx\", (string) Masternode network address\n"
" \"addr\": \"xxxx\", (string) Agrarian address for masternode payments\n"
" \"status\": \"xxxx\", (string) Masternode status\n"
" \"message\": \"xxxx\" (string) Masternode status message\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getmasternodestatus", "") + HelpExampleRpc("getmasternodestatus", ""));
if (!fMasterNode) throw runtime_error("This is not a masternode");
CMasternode* pmn = mnodeman.Find(activeMasternode.vin);
if (pmn) {
UniValue mnObj(UniValue::VOBJ);
mnObj.push_back(Pair("txhash", activeMasternode.vin.prevout.hash.ToString()));
mnObj.push_back(Pair("outputidx", (uint64_t)activeMasternode.vin.prevout.n));
mnObj.push_back(Pair("netaddr", activeMasternode.service.ToString()));
mnObj.push_back(Pair("addr", CBitcoinAddress(pmn->pubKeyCollateralAddress.GetID()).ToString()));
mnObj.push_back(Pair("status", activeMasternode.status));
mnObj.push_back(Pair("message", activeMasternode.GetStatus()));
return mnObj;
}
throw runtime_error("Masternode not found in the list of available masternodes. Current status: "
+ activeMasternode.GetStatus());
}
UniValue getmasternodewinners (const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 3)
throw runtime_error(
"getmasternodewinners ( blocks \"filter\" )\n"
"\nPrint the masternode winners for the last n blocks\n"
"\nArguments:\n"
"1. blocks (numeric, optional) Number of previous blocks to show (default: 10)\n"
"2. filter (string, optional) Search filter matching MN address\n"
"\nResult (single winner):\n"
"[\n"
" {\n"
" \"nHeight\": n, (numeric) block height\n"
" \"winner\": {\n"
" \"address\": \"xxxx\", (string) Agrarian MN Address\n"
" \"nVotes\": n, (numeric) Number of votes for winner\n"
" }\n"
" }\n"
" ,...\n"
"]\n"
"\nResult (multiple winners):\n"
"[\n"
" {\n"
" \"nHeight\": n, (numeric) block height\n"
" \"winner\": [\n"
" {\n"
" \"address\": \"xxxx\", (string) Agrarian MN Address\n"
" \"nVotes\": n, (numeric) Number of votes for winner\n"
" }\n"
" ,...\n"
" ]\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("getmasternodewinners", "") + HelpExampleRpc("getmasternodewinners", ""));
int nHeight;
{
LOCK(cs_main);
CBlockIndex* pindex = chainActive.Tip();
if(!pindex) return 0;
nHeight = pindex->nHeight;
}
int nLast = 10;
std::string strFilter = "";
if (params.size() >= 1)
nLast = atoi(params[0].get_str());
if (params.size() == 2)
strFilter = params[1].get_str();
UniValue ret(UniValue::VARR);
for (int i = nHeight - nLast; i < nHeight + 20; i++) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("nHeight", i));
std::string strPayment = GetRequiredPaymentsString(i);
if (strFilter != "" && strPayment.find(strFilter) == std::string::npos) continue;
if (strPayment.find(',') != std::string::npos) {
UniValue winner(UniValue::VARR);
boost::char_separator<char> sep(",");
boost::tokenizer< boost::char_separator<char> > tokens(strPayment, sep);
for (const string& t : tokens) {
UniValue addr(UniValue::VOBJ);
std::size_t pos = t.find(":");
std::string strAddress = t.substr(0,pos);
uint64_t nVotes = atoi(t.substr(pos+1));
addr.push_back(Pair("address", strAddress));
addr.push_back(Pair("nVotes", nVotes));
winner.push_back(addr);
}
obj.push_back(Pair("winner", winner));
} else if (strPayment.find("Unknown") == std::string::npos) {
UniValue winner(UniValue::VOBJ);
std::size_t pos = strPayment.find(":");
std::string strAddress = strPayment.substr(0,pos);
uint64_t nVotes = atoi(strPayment.substr(pos+1));
winner.push_back(Pair("address", strAddress));
winner.push_back(Pair("nVotes", nVotes));
obj.push_back(Pair("winner", winner));
} else {
UniValue winner(UniValue::VOBJ);
winner.push_back(Pair("address", strPayment));
winner.push_back(Pair("nVotes", 0));
obj.push_back(Pair("winner", winner));
}
ret.push_back(obj);
}
return ret;
}
UniValue getmasternodescores (const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getmasternodescores ( blocks )\n"
"\nPrint list of winning masternode by score\n"
"\nArguments:\n"
"1. blocks (numeric, optional) Show the last n blocks (default 10)\n"
"\nResult:\n"
"{\n"
" xxxx: \"xxxx\" (numeric : string) Block height : Masternode hash\n"
" ,...\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getmasternodescores", "") + HelpExampleRpc("getmasternodescores", ""));
int nLast = 10;
if (params.size() == 1) {
try {
nLast = std::stoi(params[0].get_str());
} catch (const std::invalid_argument&) {
throw runtime_error("Exception on param 2");
}
}
UniValue obj(UniValue::VOBJ);
std::vector<CMasternode> vMasternodes = mnodeman.GetFullMasternodeVector();
for (int nHeight = chainActive.Tip()->nHeight - nLast; nHeight < chainActive.Tip()->nHeight + 20; nHeight++) {
uint256 nHigh = 0;
CMasternode* pBestMasternode = NULL;
for (CMasternode& mn : vMasternodes) {
uint256 n = mn.CalculateScore(1, nHeight - 100);
if (n > nHigh) {
nHigh = n;
pBestMasternode = &mn;
}
}
if (pBestMasternode)
obj.push_back(Pair(strprintf("%d", nHeight), pBestMasternode->vin.prevout.hash.ToString().c_str()));
}
return obj;
}
bool DecodeHexMnb(CMasternodeBroadcast& mnb, std::string strHexMnb) {
if (!IsHex(strHexMnb))
return false;
vector<unsigned char> mnbData(ParseHex(strHexMnb));
CDataStream ssData(mnbData, SER_NETWORK, PROTOCOL_VERSION);
try {
ssData >> mnb;
}
catch (const std::exception&) {
return false;
}
return true;
}
UniValue createmasternodebroadcast(const UniValue& params, bool fHelp)
{
string strCommand;
if (params.size() >= 1)
strCommand = params[0].get_str();
if (fHelp || (strCommand != "alias" && strCommand != "all") || (strCommand == "alias" && params.size() < 2))
throw runtime_error(
"createmasternodebroadcast \"command\" ( \"alias\")\n"
"\nCreates a masternode broadcast message for one or all masternodes configured in masternode.conf\n" +
HelpRequiringPassphrase() + "\n"
"\nArguments:\n"
"1. \"command\" (string, required) \"alias\" for single masternode, \"all\" for all masternodes\n"
"2. \"alias\" (string, required if command is \"alias\") Alias of the masternode\n"
"\nResult (all):\n"
"{\n"
" \"overall\": \"xxx\", (string) Overall status message indicating number of successes.\n"
" \"detail\": [ (array) JSON array of broadcast objects.\n"
" {\n"
" \"alias\": \"xxx\", (string) Alias of the masternode.\n"
" \"success\": true|false, (boolean) Success status.\n"
" \"hex\": \"xxx\" (string, if success=true) Hex encoded broadcast message.\n"
" \"error_message\": \"xxx\" (string, if success=false) Error message, if any.\n"
" }\n"
" ,...\n"
" ]\n"
"}\n"
"\nResult (alias):\n"
"{\n"
" \"alias\": \"xxx\", (string) Alias of the masternode.\n"
" \"success\": true|false, (boolean) Success status.\n"
" \"hex\": \"xxx\" (string, if success=true) Hex encoded broadcast message.\n"
" \"error_message\": \"xxx\" (string, if success=false) Error message, if any.\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("createmasternodebroadcast", "alias mymn1") + HelpExampleRpc("createmasternodebroadcast", "alias mymn1"));
EnsureWalletIsUnlocked();
if (strCommand == "alias")
{
// wait for reindex and/or import to finish
if (fImporting || fReindex)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish");
std::string alias = params[1].get_str();
bool found = false;
UniValue statusObj(UniValue::VOBJ);
statusObj.push_back(Pair("alias", alias));
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
if(mne.getAlias() == alias) {
found = true;
std::string errorMessage;
CMasternodeBroadcast mnb;
bool success = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb, true);
statusObj.push_back(Pair("success", success));
if(success) {
CDataStream ssMnb(SER_NETWORK, PROTOCOL_VERSION);
ssMnb << mnb;
statusObj.push_back(Pair("hex", HexStr(ssMnb.begin(), ssMnb.end())));
} else {
statusObj.push_back(Pair("error_message", errorMessage));
}
break;
}
}
if(!found) {
statusObj.push_back(Pair("success", false));
statusObj.push_back(Pair("error_message", "Could not find alias in config. Verify with list-conf."));
}
return statusObj;
}
if (strCommand == "all")
{
// wait for reindex and/or import to finish
if (fImporting || fReindex)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Wait for reindex and/or import to finish");
std::vector<CMasternodeConfig::CMasternodeEntry> mnEntries;
mnEntries = masternodeConfig.getEntries();
int successful = 0;
int failed = 0;
UniValue resultsObj(UniValue::VARR);
for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) {
std::string errorMessage;
CTxIn vin = CTxIn(uint256S(mne.getTxHash()), uint32_t(atoi(mne.getOutputIndex().c_str())));
CMasternodeBroadcast mnb;
bool success = activeMasternode.CreateBroadcast(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), errorMessage, mnb, true);
UniValue statusObj(UniValue::VOBJ);
statusObj.push_back(Pair("alias", mne.getAlias()));
statusObj.push_back(Pair("success", success));
if(success) {
successful++;
CDataStream ssMnb(SER_NETWORK, PROTOCOL_VERSION);
ssMnb << mnb;
statusObj.push_back(Pair("hex", HexStr(ssMnb.begin(), ssMnb.end())));
} else {
failed++;
statusObj.push_back(Pair("error_message", errorMessage));
}
resultsObj.push_back(statusObj);
}
UniValue returnObj(UniValue::VOBJ);
returnObj.push_back(Pair("overall", strprintf("Successfully created broadcast messages for %d masternodes, failed to create %d, total %d", successful, failed, successful + failed)));
returnObj.push_back(Pair("detail", resultsObj));
return returnObj;
}
return NullUniValue;
}
UniValue decodemasternodebroadcast(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"decodemasternodebroadcast \"hexstring\"\n"
"\nCommand to decode masternode broadcast messages\n"
"\nArgument:\n"
"1. \"hexstring\" (string) The hex encoded masternode broadcast message\n"
"\nResult:\n"
"{\n"
" \"vin\": \"xxxx\" (string) The unspent output which is holding the masternode collateral\n"
" \"addr\": \"xxxx\" (string) IP address of the masternode\n"
" \"pubkeycollateral\": \"xxxx\" (string) Collateral address's public key\n"
" \"pubkeymasternode\": \"xxxx\" (string) Masternode's public key\n"
" \"vchsig\": \"xxxx\" (string) Base64-encoded signature of this message (verifiable via pubkeycollateral)\n"
" \"sigtime\": \"nnn\" (numeric) Signature timestamp\n"
" \"protocolversion\": \"nnn\" (numeric) Masternode's protocol version\n"
" \"nlastdsq\": \"nnn\" (numeric) The last time the masternode sent a DSQ message (for mixing) (DEPRECATED)\n"
" \"lastping\" : { (object) JSON object with information about the masternode's last ping\n"
" \"vin\": \"xxxx\" (string) The unspent output of the masternode which is signing the message\n"
" \"blockhash\": \"xxxx\" (string) Current chaintip blockhash minus 12\n"
" \"sigtime\": \"nnn\" (numeric) Signature time for this ping\n"
" \"vchsig\": \"xxxx\" (string) Base64-encoded signature of this ping (verifiable via pubkeymasternode)\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("decodemasternodebroadcast", "hexstring") + HelpExampleRpc("decodemasternodebroadcast", "hexstring"));
CMasternodeBroadcast mnb;
if (!DecodeHexMnb(mnb, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed");
if(!mnb.VerifySignature())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Masternode broadcast signature verification failed");
UniValue resultObj(UniValue::VOBJ);
resultObj.push_back(Pair("vin", mnb.vin.prevout.ToString()));
resultObj.push_back(Pair("addr", mnb.addr.ToString()));
resultObj.push_back(Pair("pubkeycollateral", CBitcoinAddress(mnb.pubKeyCollateralAddress.GetID()).ToString()));
resultObj.push_back(Pair("pubkeymasternode", CBitcoinAddress(mnb.pubKeyMasternode.GetID()).ToString()));
resultObj.push_back(Pair("vchsig", EncodeBase64(&mnb.sig[0], mnb.sig.size())));
resultObj.push_back(Pair("sigtime", mnb.sigTime));
resultObj.push_back(Pair("protocolversion", mnb.protocolVersion));
resultObj.push_back(Pair("nlastdsq", mnb.nLastDsq));
UniValue lastPingObj(UniValue::VOBJ);
lastPingObj.push_back(Pair("vin", mnb.lastPing.vin.prevout.ToString()));
lastPingObj.push_back(Pair("blockhash", mnb.lastPing.blockHash.ToString()));
lastPingObj.push_back(Pair("sigtime", mnb.lastPing.sigTime));
lastPingObj.push_back(Pair("vchsig", EncodeBase64(&mnb.lastPing.vchSig[0], mnb.lastPing.vchSig.size())));
resultObj.push_back(Pair("lastping", lastPingObj));
return resultObj;
}
UniValue relaymasternodebroadcast(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"relaymasternodebroadcast \"hexstring\"\n"
"\nCommand to relay masternode broadcast messages\n"
"\nArguments:\n"
"1. \"hexstring\" (string) The hex encoded masternode broadcast message\n"
"\nExamples:\n" +
HelpExampleCli("relaymasternodebroadcast", "hexstring") + HelpExampleRpc("relaymasternodebroadcast", "hexstring"));
CMasternodeBroadcast mnb;
if (!DecodeHexMnb(mnb, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Masternode broadcast message decode failed");
if(!mnb.VerifySignature())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Masternode broadcast signature verification failed");
mnodeman.UpdateMasternodeList(mnb);
mnb.Relay();
return strprintf("Masternode broadcast sent (service %s, vin %s)", mnb.addr.ToString(), mnb.vin.ToString());
}
+771
View File
@@ -0,0 +1,771 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amount.h"
#include "base58.h"
#include "chainparams.h"
#include "core_io.h"
#include "init.h"
#include "main.h"
#include "miner.h"
#include "net.h"
#include "pow.h"
#include "rpc/server.h"
#include "util.h"
#include "validationinterface.h"
#ifdef ENABLE_WALLET
#include "wallet/db.h"
#include "wallet/wallet.h"
#endif
#include <stdint.h>
#include <boost/assign/list_of.hpp>
#include <univalue.h>
using namespace std;
/**
* Return average network hashes per second based on the last 'lookup' blocks,
* or from the last difficulty change if 'lookup' is nonpositive.
* If 'height' is nonnegative, compute the estimate at the time when a given block was found.
*/
UniValue GetNetworkHashPS(int lookup, int height)
{
CBlockIndex *pb = chainActive.Tip();
if (height >= 0 && height < chainActive.Height())
pb = chainActive[height];
if (pb == NULL || !pb->nHeight)
return 0;
// If lookup is -1, then use blocks since last difficulty change.
if (lookup <= 0)
lookup = pb->nHeight % 2016 + 1;
// If lookup is larger than chain, then set it to chain length.
if (lookup > pb->nHeight)
lookup = pb->nHeight;
CBlockIndex* pb0 = pb;
int64_t minTime = pb0->GetBlockTime();
int64_t maxTime = minTime;
for (int i = 0; i < lookup; i++) {
pb0 = pb0->pprev;
int64_t time = pb0->GetBlockTime();
minTime = std::min(time, minTime);
maxTime = std::max(time, maxTime);
}
// In case there's a situation where minTime == maxTime, we don't want a divide by zero exception.
if (minTime == maxTime)
return 0;
uint256 workDiff = pb->nChainWork - pb0->nChainWork;
int64_t timeDiff = maxTime - minTime;
return (int64_t)(workDiff.getdouble() / timeDiff);
}
UniValue getnetworkhashps(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 2)
throw runtime_error(
"getnetworkhashps ( blocks height )\n"
"\nReturns the estimated network hashes per second based on the last n blocks.\n"
"Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n"
"Pass in [height] to estimate the network speed at the time when a certain block was found.\n"
"\nArguments:\n"
"1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n"
"2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n"
"\nResult:\n"
"x (numeric) Hashes per second estimated\n"
"\nExamples:\n" +
HelpExampleCli("getnetworkhashps", "") + HelpExampleRpc("getnetworkhashps", ""));
LOCK(cs_main);
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
}
#ifdef ENABLE_WALLET
UniValue getgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getgenerate\n"
"\nReturn if the server is set to generate coins or not. The default is false.\n"
"It is set with the command line argument -gen (or agrarian.conf setting gen)\n"
"It can also be set with the setgenerate call.\n"
"\nResult\n"
"true|false (boolean) If the server is set to generate coins or not\n"
"\nExamples:\n" +
HelpExampleCli("getgenerate", "") + HelpExampleRpc("getgenerate", ""));
LOCK(cs_main);
return GetBoolArg("-gen", false);
}
UniValue generate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 1)
throw runtime_error(
"generate numblocks\n"
"\nMine blocks immediately (before the RPC call returns)\n"
"\nNote: this function can only be used on the regtest network\n"
"\nArguments:\n"
"1. numblocks (numeric, required) How many blocks to generate.\n"
"\nResult\n"
"[ blockhashes ] (array) hashes of blocks generated\n"
"\nExamples:\n"
"\nGenerate 11 blocks\n"
+ HelpExampleCli("generate", "11")
);
if (!Params().MineBlocksOnDemand())
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "This method can only be used on regtest");
int nHeightStart = 0;
int nHeightEnd = 0;
int nHeight = 0;
int nGenerate = params[0].get_int();
CReserveKey reservekey(pwalletMain);
{ // Don't keep cs_main locked
LOCK(cs_main);
nHeightStart = chainActive.Height();
nHeight = nHeightStart;
nHeightEnd = nHeightStart+nGenerate;
}
unsigned int nExtraNonce = 0;
UniValue blockHashes(UniValue::VARR);
bool fPoS = nHeight >= Params().LAST_POW_BLOCK();
while (nHeight < nHeightEnd)
{
unique_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey, pwalletMain, fPoS));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
CBlock *pblock = &pblocktemplate->block;
if(!fPoS){
{
LOCK(cs_main);
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
}
}
while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits)) {
// Yes, there is a chance every nonce could fail to satisfy the -regtest
// target -- 1 in 2^(2^32). That ain't gonna happen.
++pblock->nNonce;
}
CValidationState state;
if (!ProcessNewBlock(state, NULL, pblock))
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
++nHeight;
fPoS = nHeight >= Params().LAST_POW_BLOCK();
blockHashes.push_back(pblock->GetHash().GetHex());
}
return blockHashes;
}
UniValue setgenerate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"setgenerate generate ( genproclimit )\n"
"\nSet 'generate' true or false to turn generation on or off.\n"
"Generation is limited to 'genproclimit' processors, -1 is unlimited.\n"
"See the getgenerate call for the current setting.\n"
"\nArguments:\n"
"1. generate (boolean, required) Set to true to turn on generation, false to turn off.\n"
"2. genproclimit (numeric, optional) Set the processor limit for when generation is on. Can be -1 for unlimited.\n"
"\nExamples:\n"
"\nSet the generation on with a limit of one processor\n" +
HelpExampleCli("setgenerate", "true 1") +
"\nCheck the setting\n" + HelpExampleCli("getgenerate", "") +
"\nTurn off generation\n" + HelpExampleCli("setgenerate", "false") +
"\nUsing json rpc\n" + HelpExampleRpc("setgenerate", "true, 1"));
if (pwalletMain == NULL)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
if (Params().MineBlocksOnDemand())
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Use the generate method instead of setgenerate on this network");
bool fGenerate = true;
if (params.size() > 0)
fGenerate = params[0].get_bool();
int nGenProcLimit = -1;
if (params.size() > 1) {
nGenProcLimit = params[1].get_int();
if (nGenProcLimit == 0)
fGenerate = false;
}
mapArgs["-gen"] = (fGenerate ? "1" : "0");
mapArgs["-genproclimit"] = itostr(nGenProcLimit);
GenerateBitcoins(fGenerate, pwalletMain, nGenProcLimit);
return NullUniValue;
}
UniValue gethashespersec(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"gethashespersec\n"
"\nReturns a recent hashes per second performance measurement while generating.\n"
"See the getgenerate and setgenerate calls to turn generation on and off.\n"
"\nResult:\n"
"n (numeric) The recent hashes per second when generation is on (will return 0 if generation is off)\n"
"\nExamples:\n" +
HelpExampleCli("gethashespersec", "") + HelpExampleRpc("gethashespersec", ""));
if (GetTimeMillis() - nHPSTimerStart > 8000)
return (int64_t)0;
return (int64_t)dHashesPerSec;
}
#endif
UniValue getmininginfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getmininginfo\n"
"\nReturns a json object containing mining-related information."
"\nResult:\n"
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
" \"currentblocksize\": nnn, (numeric) The last block size\n"
" \"currentblocktx\": nnn, (numeric) The last block transaction\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
" \"errors\": \"...\" (string) Current errors\n"
" \"generate\": true|false (boolean) If the generation is on or off (see getgenerate or setgenerate calls)\n"
" \"genproclimit\": n (numeric) The processor limit for generation. -1 if no generation. (see getgenerate or setgenerate calls)\n"
" \"hashespersec\": n (numeric) The hashes per second of the generation, or 0 if no generation.\n"
" \"pooledtx\": n (numeric) The size of the mem pool\n"
" \"testnet\": true|false (boolean) If using testnet or not\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getmininginfo", "") + HelpExampleRpc("getmininginfo", ""));
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
obj.push_back(Pair("currentblocktx", (uint64_t)nLastBlockTx));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
obj.push_back(Pair("genproclimit", (int)GetArg("-genproclimit", -1)));
obj.push_back(Pair("networkhashps", getnetworkhashps(params, false)));
obj.push_back(Pair("pooledtx", (uint64_t)mempool.size()));
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
obj.push_back(Pair("chain", Params().NetworkIDString()));
#ifdef ENABLE_WALLET
obj.push_back(Pair("generate", getgenerate(params, false)));
obj.push_back(Pair("hashespersec", gethashespersec(params, false)));
#endif
return obj;
}
// NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
UniValue prioritisetransaction(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
"prioritisetransaction <txid> <priority delta> <fee delta>\n"
"Accepts the transaction into mined blocks at a higher (or lower) priority\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id.\n"
"2. priority delta (numeric, required) The priority to add or subtract.\n"
" The transaction selection algorithm considers the tx as it would have a higher priority.\n"
" (priority of a transaction is calculated: coinage * value_in_uagr / txsize) \n"
"3. fee delta (numeric, required) The fee value (in uagr) to add (or subtract, if negative).\n"
" The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
" considers the transaction as it would have paid a higher (or lower) fee.\n"
"\nResult\n"
"true (boolean) Returns true\n"
"\nExamples:\n" +
HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000") + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000"));
LOCK(cs_main);
uint256 hash = ParseHashStr(params[0].get_str(), "txid");
CAmount nAmount = params[2].get_int64();
mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
return true;
}
// NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
static UniValue BIP22ValidationResult(const CValidationState& state)
{
if (state.IsValid())
return NullUniValue;
std::string strRejectReason = state.GetRejectReason();
if (state.IsError())
throw JSONRPCError(RPC_VERIFY_ERROR, strRejectReason);
if (state.IsInvalid()) {
if (strRejectReason.empty())
return "rejected";
return strRejectReason;
}
// Should be impossible
return "valid?";
}
UniValue getblocktemplate(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"getblocktemplate ( \"jsonrequestobject\" )\n"
"\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n"
"It returns data needed to construct a block to work on.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n"
"\nArguments:\n"
"1. \"jsonrequestobject\" (string, optional) A json object in the following spec\n"
" {\n"
" \"mode\":\"template\" (string, optional) This must be set to \"template\" or omitted\n"
" \"capabilities\":[ (array, optional) A list of strings\n"
" \"support\" (string) client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'\n"
" ,...\n"
" ]\n"
" }\n"
"\n"
"\nResult:\n"
"{\n"
" \"version\" : n, (numeric) The block version\n"
" \"previousblockhash\" : \"xxxx\", (string) The hash of current highest block\n"
" \"transactions\" : [ (array) contents of non-coinbase transactions that should be included in the next block\n"
" {\n"
" \"data\" : \"xxxx\", (string) transaction data encoded in hexadecimal (byte-for-byte)\n"
" \"hash\" : \"xxxx\", (string) hash/id encoded in little-endian hexadecimal\n"
" \"depends\" : [ (array) array of numbers \n"
" n (numeric) transactions before this one (by 1-based index in 'transactions' list) that must be present in the final block if this one is\n"
" ,...\n"
" ],\n"
" \"fee\": n, (numeric) difference in value between transaction inputs and outputs (in uagr); for coinbase transactions, this is a negative Number of the total collected block fees (ie, not including the block subsidy); if key is not present, fee is unknown and clients MUST NOT assume there isn't one\n"
" \"sigops\" : n, (numeric) total number of SigOps, as counted for purposes of block limits; if key is not present, sigop count is unknown and clients MUST NOT assume there aren't any\n"
" \"required\" : true|false (boolean) if provided and true, this transaction must be in the final block\n"
" }\n"
" ,...\n"
" ],\n"
" \"coinbaseaux\" : { (json object) data that should be included in the coinbase's scriptSig content\n"
" \"flags\" : \"flags\" (string) \n"
" },\n"
" \"coinbasevalue\" : n, (numeric) maximum allowable input to coinbase transaction, including the generation award and transaction fees (in uagr)\n"
" \"coinbasetxn\" : { ... }, (json object) information for coinbase transaction\n"
" \"target\" : \"xxxx\", (string) The hash target\n"
" \"mintime\" : xxx, (numeric) The minimum timestamp appropriate for next block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"mutable\" : [ (array of string) list of ways the block template may be changed \n"
" \"value\" (string) A way the block template may be changed, e.g. 'time', 'transactions', 'prevblock'\n"
" ,...\n"
" ],\n"
" \"noncerange\" : \"00000000ffffffff\", (string) A range of valid nonces\n"
" \"sigoplimit\" : n, (numeric) limit of sigops in blocks\n"
" \"sizelimit\" : n, (numeric) limit of block size\n"
" \"curtime\" : ttt, (numeric) current timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
" \"bits\" : \"xxx\", (string) compressed target of next block\n"
" \"height\" : n (numeric) The height of the next block\n"
" \"payee\" : \"xxx\", (string) required payee for the next block\n"
" \"payee_amount\" : n, (numeric) required amount to pay\n"
" \"votes\" : [\n (array) show vote candidates\n"
" { ... } (json object) vote candidate\n"
" ,...\n"
" ],\n"
" \"masternode_payments\" : true|false, (boolean) true, if masternode payments are enabled\n"
" \"enforce_masternode_payments\" : true|false (boolean) true, if masternode payments are enforced\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getblocktemplate", "") + HelpExampleRpc("getblocktemplate", ""));
LOCK(cs_main);
std::string strMode = "template";
UniValue lpval = NullUniValue;
if (params.size() > 0) {
const UniValue& oparam = params[0].get_obj();
const UniValue& modeval = find_value(oparam, "mode");
if (modeval.isStr())
strMode = modeval.get_str();
else if (modeval.isNull()) {
/* Do nothing */
} else
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
lpval = find_value(oparam, "longpollid");
if (strMode == "proposal") {
const UniValue& dataval = find_value(oparam, "data");
if (!dataval.isStr())
throw JSONRPCError(RPC_TYPE_ERROR, "Missing data String key for proposal");
CBlock block;
if (!DecodeHexBlk(block, dataval.get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
uint256 hash = block.GetHash();
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) {
CBlockIndex* pindex = mi->second;
if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
return "duplicate";
if (pindex->nStatus & BLOCK_FAILED_MASK)
return "duplicate-invalid";
return "duplicate-inconclusive";
}
CBlockIndex* const pindexPrev = chainActive.Tip();
// TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
return "inconclusive-not-best-prevblk";
CValidationState state;
TestBlockValidity(state, block, pindexPrev, false, true);
return BIP22ValidationResult(state);
}
}
if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
if (vNodes.empty())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Agrarian is not connected!");
if (IsInitialBlockDownload())
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Agrarian is downloading blocks...");
static unsigned int nTransactionsUpdatedLast;
if (!lpval.isNull()) {
// Wait to respond until either the best block changes, OR a minute has passed and there are more transactions
uint256 hashWatchedChain;
std::chrono::steady_clock::time_point checktxtime;
unsigned int nTransactionsUpdatedLastLP;
if (lpval.isStr()) {
// Format: <hashBestChain><nTransactionsUpdatedLast>
std::string lpstr = lpval.get_str();
hashWatchedChain.SetHex(lpstr.substr(0, 64));
nTransactionsUpdatedLastLP = atoi64(lpstr.substr(64));
} else {
// NOTE: Spec does not specify behaviour for non-string longpollid, but this makes testing easier
hashWatchedChain = chainActive.Tip()->GetBlockHash();
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}
// Release the wallet and main lock while waiting
LEAVE_CRITICAL_SECTION(cs_main);
{
checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1);
WaitableLock lock(csBestBlock);
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning()) {
if (cvBlockChange.wait_until(lock, checktxtime) == std::cv_status::timeout)
{
// Timeout: Check transactions for update
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
break;
checktxtime += std::chrono::seconds(10);
}
}
}
ENTER_CRITICAL_SECTION(cs_main);
if (!IsRPCRunning())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");
// TODO: Maybe recheck connections/IBD and (if something wrong) send an expires-immediately template to stop miners?
}
// Update block
static CBlockIndex* pindexPrev;
static int64_t nStart;
static CBlockTemplate* pblocktemplate;
if (pindexPrev != chainActive.Tip() ||
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - nStart > 5)) {
// Clear pindexPrev so future calls make a new block, despite any failures from here on
pindexPrev = NULL;
// Store the chainActive.Tip() used before CreateNewBlock, to avoid races
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrevNew = chainActive.Tip();
nStart = GetTime();
// Create new block
if (pblocktemplate) {
delete pblocktemplate;
pblocktemplate = NULL;
}
CScript scriptDummy = CScript() << OP_TRUE;
pblocktemplate = CreateNewBlock(scriptDummy, pwalletMain, false);
if (!pblocktemplate)
throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
// Need to update only after we know CreateNewBlock succeeded
pindexPrev = pindexPrevNew;
}
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
// Update nTime
UpdateTime(pblock, pindexPrev);
pblock->nNonce = 0;
UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
UniValue transactions(UniValue::VARR);
map<uint256, int64_t> setTxIndex;
int i = 0;
for (CTransaction& tx : pblock->vtx) {
uint256 txHash = tx.GetHash();
setTxIndex[txHash] = i++;
if (tx.IsCoinBase())
continue;
UniValue entry(UniValue::VOBJ);
entry.push_back(Pair("data", EncodeHexTx(tx)));
entry.push_back(Pair("hash", txHash.GetHex()));
UniValue deps(UniValue::VARR);
for (const CTxIn& in : tx.vin) {
if (setTxIndex.count(in.prevout.hash))
deps.push_back(setTxIndex[in.prevout.hash]);
}
entry.push_back(Pair("depends", deps));
int index_in_template = i - 1;
entry.push_back(Pair("fee", pblocktemplate->vTxFees[index_in_template]));
entry.push_back(Pair("sigops", pblocktemplate->vTxSigOps[index_in_template]));
transactions.push_back(entry);
}
UniValue aux(UniValue::VOBJ);
aux.push_back(Pair("flags", HexStr(COINBASE_FLAGS.begin(), COINBASE_FLAGS.end())));
uint256 hashTarget = uint256().SetCompact(pblock->nBits);
static UniValue aMutable(UniValue::VARR);
if (aMutable.empty()) {
aMutable.push_back("time");
aMutable.push_back("transactions");
aMutable.push_back("prevblock");
}
UniValue aVotes(UniValue::VARR);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("capabilities", aCaps));
result.push_back(Pair("version", pblock->nVersion));
result.push_back(Pair("previousblockhash", pblock->hashPrevBlock.GetHex()));
result.push_back(Pair("transactions", transactions));
result.push_back(Pair("coinbaseaux", aux));
result.push_back(Pair("coinbasevalue", (int64_t)pblock->vtx[0].GetValueOut()));
result.push_back(Pair("longpollid", chainActive.Tip()->GetBlockHash().GetHex() + i64tostr(nTransactionsUpdatedLast)));
result.push_back(Pair("target", hashTarget.GetHex()));
result.push_back(Pair("mintime", (int64_t)pindexPrev->GetMedianTimePast() + 1));
result.push_back(Pair("mutable", aMutable));
result.push_back(Pair("noncerange", "00000000ffffffff"));
// result.push_back(Pair("sigoplimit", (int64_t)MAX_BLOCK_SIGOPS));
// result.push_back(Pair("sizelimit", (int64_t)MAX_BLOCK_SIZE));
result.push_back(Pair("curtime", pblock->GetBlockTime()));
result.push_back(Pair("bits", strprintf("%08x", pblock->nBits)));
result.push_back(Pair("height", (int64_t)(pindexPrev->nHeight + 1)));
result.push_back(Pair("votes", aVotes));
if (pblock->payee != CScript()) {
CTxDestination address1;
ExtractDestination(pblock->payee, address1);
CBitcoinAddress address2(address1);
result.push_back(Pair("payee", address2.ToString().c_str()));
result.push_back(Pair("payee_amount", (int64_t)pblock->vtx[0].vout[1].nValue));
} else {
result.push_back(Pair("payee", ""));
result.push_back(Pair("payee_amount", ""));
}
result.push_back(Pair("masternode_payments", pblock->nTime > Params().StartMasternodePayments()));
result.push_back(Pair("enforce_masternode_payments", true));
return result;
}
class submitblock_StateCatcher : public CValidationInterface
{
public:
uint256 hash;
bool found;
CValidationState state;
submitblock_StateCatcher(const uint256& hashIn) : hash(hashIn), found(false), state(){};
protected:
virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn)
{
if (block.GetHash() != hash)
return;
found = true;
state = stateIn;
};
};
UniValue submitblock(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"submitblock \"hexdata\" ( \"jsonparametersobject\" )\n"
"\nAttempts to submit new block to network.\n"
"The 'jsonparametersobject' parameter is currently ignored.\n"
"See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n"
"\nArguments\n"
"1. \"hexdata\" (string, required) the hex-encoded block data to submit\n"
"2. \"jsonparametersobject\" (string, optional) object of optional parameters\n"
" {\n"
" \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n"
" }\n"
"\nResult:\n"
"\nExamples:\n" +
HelpExampleCli("submitblock", "\"mydata\"") + HelpExampleRpc("submitblock", "\"mydata\""));
CBlock block;
if (!DecodeHexBlk(block, params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block decode failed");
if (block.vtx.empty() || !block.vtx[0].IsCoinBase()) {
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block does not start with a coinbase");
}
uint256 hash = block.GetHash();
bool fBlockPresent = false;
{
LOCK(cs_main);
BlockMap::iterator mi = mapBlockIndex.find(hash);
if (mi != mapBlockIndex.end()) {
CBlockIndex* pindex = mi->second;
if (pindex->IsValid(BLOCK_VALID_SCRIPTS))
return "duplicate";
if (pindex->nStatus & BLOCK_FAILED_MASK)
return "duplicate-invalid";
// Otherwise, we might only have the header - process the block before returning
fBlockPresent = true;
}
}
CValidationState state;
submitblock_StateCatcher sc(block.GetHash());
RegisterValidationInterface(&sc);
bool fAccepted = ProcessNewBlock(state, NULL, &block);
UnregisterValidationInterface(&sc);
if (fBlockPresent) {
if (fAccepted && !sc.found)
return "duplicate-inconclusive";
return "duplicate";
}
if (fAccepted) {
if (!sc.found)
return "inconclusive";
state = sc.state;
}
return BIP22ValidationResult(state);
}
UniValue estimatefee(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatefee nblocks\n"
"\nEstimates the approximate fee per kilobyte\n"
"needed for a transaction to begin confirmation\n"
"within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
"n : (numeric) estimated fee-per-kilobyte\n"
"\n"
"-1.0 is returned if not enough transactions and\n"
"blocks have been observed to make an estimate.\n"
"\nExample:\n" +
HelpExampleCli("estimatefee", "6"));
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
CFeeRate feeRate = mempool.estimateFee(nBlocks);
if (feeRate == CFeeRate(0))
return -1.0;
return ValueFromAmount(feeRate.GetFeePerK());
}
UniValue estimatepriority(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"estimatepriority nblocks\n"
"\nEstimates the approximate priority\n"
"a zero-fee transaction needs to begin confirmation\n"
"within nblocks blocks.\n"
"\nArguments:\n"
"1. nblocks (numeric)\n"
"\nResult:\n"
"n : (numeric) estimated priority\n"
"\n"
"-1.0 is returned if not enough transactions and\n"
"blocks have been observed to make an estimate.\n"
"\nExample:\n" +
HelpExampleCli("estimatepriority", "6"));
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
int nBlocks = params[0].get_int();
if (nBlocks < 1)
nBlocks = 1;
return mempool.estimatePriority(nBlocks);
}
+637
View File
@@ -0,0 +1,637 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "base58.h"
#include "clientversion.h"
#include "init.h"
#include "main.h"
#include "masternode-sync.h"
#include "net.h"
#include "netbase.h"
#include "rpc/server.h"
#include "spork.h"
#include "timedata.h"
#include "util.h"
#ifdef ENABLE_WALLET
#include "wallet/wallet.h"
#include "wallet/walletdb.h"
#endif
#include <stdint.h>
#include <boost/assign/list_of.hpp>
#include <univalue.h>
using namespace boost;
using namespace boost::assign;
using namespace std;
/**
* @note Do not add or change anything in the information returned by this
* method. `getinfo` exists for backwards-compatibility only. It combines
* information from wildly different sources in the program, which is a mess,
* and is thus planned to be deprecated eventually.
*
* Based on the source of the information, new information should be added to:
* - `getblockchaininfo`,
* - `getnetworkinfo` or
* - `getwalletinfo`
*
* Or alternatively, create a specific query method for the information.
**/
UniValue getinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getinfo\n"
"\nReturns an object containing various state info.\n"
"\nResult:\n"
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"walletversion\": xxxxx, (numeric) the wallet version\n"
" \"balance\": xxxxxxx, (numeric) the total agrarian balance of the wallet (excluding zerocoins)\n"
" \"zerocoinbalance\": xxxxxxx, (numeric) the total zerocoin balance of the wallet\n"
" \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
" \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"testnet\": true|false, (boolean) if the server is using testnet or not\n"
" \"moneysupply\" : \"supply\" (numeric) The money supply when this block was added to the blockchain\n"
" \"zAGRsupply\" :\n"
" {\n"
" \"1\" : n, (numeric) supply of 1 zAGR denomination\n"
" \"5\" : n, (numeric) supply of 5 zAGR denomination\n"
" \"10\" : n, (numeric) supply of 10 zAGR denomination\n"
" \"50\" : n, (numeric) supply of 50 zAGR denomination\n"
" \"100\" : n, (numeric) supply of 100 zAGR denomination\n"
" \"500\" : n, (numeric) supply of 500 zAGR denomination\n"
" \"1000\" : n, (numeric) supply of 1000 zAGR denomination\n"
" \"5000\" : n, (numeric) supply of 5000 zAGR denomination\n"
" \"total\" : n, (numeric) The total supply of all zAGR denominations\n"
" }\n"
" \"keypoololdest\": xxxxxx, (numeric) the timestamp (seconds since GMT epoch) of the oldest pre-generated key in the key pool\n"
" \"keypoolsize\": xxxx, (numeric) how many new keys are pre-generated\n"
" \"unlocked_until\": ttt, (numeric) the timestamp in seconds since epoch (midnight Jan 1 1970 GMT) that the wallet is unlocked for transfers, or 0 if the wallet is locked\n"
" \"paytxfee\": x.xxxx, (numeric) the transaction fee set in agrarian/kb\n"
" \"relayfee\": x.xxxx, (numeric) minimum relay fee for non-free transactions in agrarian/kb\n"
" \"staking status\": true|false, (boolean) if the wallet is staking or not\n"
" \"errors\": \"...\" (string) any error messages\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getinfo", "") + HelpExampleRpc("getinfo", ""));
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
std::string services;
for (int i = 0; i < 8; i++) {
uint64_t check = 1 << i;
if (nLocalServices & check) {
switch (check) {
case NODE_NETWORK:
services+= "NETWORK/";
break;
case NODE_BLOOM:
services+= "BLOOM/";
break;
case NODE_BLOOM_WITHOUT_MN:
case NODE_BLOOM_LIGHT_ZC:
services+= "BLOOM_ZC/";
break;
default:
services+= "UNKNOWN/";
}
}
}
proxyType proxy;
GetProxy(NET_IPV4, proxy);
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
obj.push_back(Pair("services", services));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
obj.push_back(Pair("zerocoinbalance", ValueFromAmount(pwalletMain->GetZerocoinBalance(true))));
}
#endif
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string())));
obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC()));
// During inital block verification chainActive.Tip() might be not yet initialized
if (chainActive.Tip() == NULL) {
obj.push_back(Pair("status", "Blockchain information not yet available"));
return obj;
}
obj.push_back(Pair("moneysupply",ValueFromAmount(chainActive.Tip()->nMoneySupply)));
UniValue zagrObj(UniValue::VOBJ);
for (auto denom : libzerocoin::zerocoinDenomList) {
zagrObj.push_back(Pair(to_string(denom), ValueFromAmount(chainActive.Tip()->mapZerocoinSupply.at(denom) * (denom*COIN))));
}
zagrObj.push_back(Pair("total", ValueFromAmount(chainActive.Tip()->GetZerocoinSupply())));
obj.push_back(Pair("zAGRsupply", zagrObj));
#ifdef ENABLE_WALLET
if (pwalletMain) {
obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime()));
obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize()));
}
if (pwalletMain && pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
#endif
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
bool nStaking = false;
if (mapHashedBlocks.count(chainActive.Tip()->nHeight))
nStaking = true;
else if (mapHashedBlocks.count(chainActive.Tip()->nHeight - 1) && nLastCoinStakeSearchInterval)
nStaking = true;
obj.push_back(Pair("staking status", (nStaking ? "Staking Active" : "Staking Not Active")));
obj.push_back(Pair("errors", GetWarnings("statusbar")));
return obj;
}
UniValue mnsync(const UniValue& params, bool fHelp)
{
std::string strMode;
if (params.size() == 1)
strMode = params[0].get_str();
if (fHelp || params.size() != 1 || (strMode != "status" && strMode != "reset")) {
throw runtime_error(
"mnsync \"status|reset\"\n"
"\nReturns the sync status or resets sync.\n"
"\nArguments:\n"
"1. \"mode\" (string, required) either 'status' or 'reset'\n"
"\nResult ('status' mode):\n"
"{\n"
" \"IsBlockchainSynced\": true|false, (boolean) 'true' if blockchain is synced\n"
" \"lastMasternodeList\": xxxx, (numeric) Timestamp of last MN list message\n"
" \"lastMasternodeWinner\": xxxx, (numeric) Timestamp of last MN winner message\n"
" \"lastBudgetItem\": xxxx, (numeric) Timestamp of last MN budget message\n"
" \"lastFailure\": xxxx, (numeric) Timestamp of last failed sync\n"
" \"nCountFailures\": n, (numeric) Number of failed syncs (total)\n"
" \"sumMasternodeList\": n, (numeric) Number of MN list messages (total)\n"
" \"sumMasternodeWinner\": n, (numeric) Number of MN winner messages (total)\n"
" \"sumBudgetItemProp\": n, (numeric) Number of MN budget messages (total)\n"
" \"sumBudgetItemFin\": n, (numeric) Number of MN budget finalization messages (total)\n"
" \"countMasternodeList\": n, (numeric) Number of MN list messages (local)\n"
" \"countMasternodeWinner\": n, (numeric) Number of MN winner messages (local)\n"
" \"countBudgetItemProp\": n, (numeric) Number of MN budget messages (local)\n"
" \"countBudgetItemFin\": n, (numeric) Number of MN budget finalization messages (local)\n"
" \"RequestedMasternodeAssets\": n, (numeric) Status code of last sync phase\n"
" \"RequestedMasternodeAttempt\": n, (numeric) Status code of last sync attempt\n"
"}\n"
"\nResult ('reset' mode):\n"
"\"status\" (string) 'success'\n"
"\nExamples:\n" +
HelpExampleCli("mnsync", "\"status\"") + HelpExampleRpc("mnsync", "\"status\""));
}
if (strMode == "status") {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("IsBlockchainSynced", masternodeSync.IsBlockchainSynced()));
obj.push_back(Pair("lastMasternodeList", masternodeSync.lastMasternodeList));
obj.push_back(Pair("lastMasternodeWinner", masternodeSync.lastMasternodeWinner));
obj.push_back(Pair("lastBudgetItem", masternodeSync.lastBudgetItem));
obj.push_back(Pair("lastFailure", masternodeSync.lastFailure));
obj.push_back(Pair("nCountFailures", masternodeSync.nCountFailures));
obj.push_back(Pair("sumMasternodeList", masternodeSync.sumMasternodeList));
obj.push_back(Pair("sumMasternodeWinner", masternodeSync.sumMasternodeWinner));
obj.push_back(Pair("sumBudgetItemProp", masternodeSync.sumBudgetItemProp));
obj.push_back(Pair("sumBudgetItemFin", masternodeSync.sumBudgetItemFin));
obj.push_back(Pair("countMasternodeList", masternodeSync.countMasternodeList));
obj.push_back(Pair("countMasternodeWinner", masternodeSync.countMasternodeWinner));
obj.push_back(Pair("countBudgetItemProp", masternodeSync.countBudgetItemProp));
obj.push_back(Pair("countBudgetItemFin", masternodeSync.countBudgetItemFin));
obj.push_back(Pair("RequestedMasternodeAssets", masternodeSync.RequestedMasternodeAssets));
obj.push_back(Pair("RequestedMasternodeAttempt", masternodeSync.RequestedMasternodeAttempt));
return obj;
}
if (strMode == "reset") {
masternodeSync.Reset();
return "success";
}
return "failure";
}
#ifdef ENABLE_WALLET
class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{
private:
isminetype mine;
public:
DescribeAddressVisitor(isminetype mineIn) : mine(mineIn) {}
UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
UniValue operator()(const CKeyID &keyID) const {
UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey;
obj.push_back(Pair("isscript", false));
if (mine == ISMINE_SPENDABLE) {
pwalletMain->GetPubKey(keyID, vchPubKey);
obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
}
return obj;
}
UniValue operator()(const CScriptID &scriptID) const {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("isscript", true));
CScript subscript;
pwalletMain->GetCScript(scriptID, subscript);
std::vector<CTxDestination> addresses;
txnouttype whichType;
int nRequired;
ExtractDestinations(subscript, whichType, addresses, nRequired);
obj.push_back(Pair("script", GetTxnOutputType(whichType)));
obj.push_back(Pair("hex", HexStr(subscript.begin(), subscript.end())));
UniValue a(UniValue::VARR);
for (const CTxDestination& addr : addresses)
a.push_back(CBitcoinAddress(addr).ToString());
obj.push_back(Pair("addresses", a));
if (whichType == TX_MULTISIG)
obj.push_back(Pair("sigsrequired", nRequired));
return obj;
}
};
#endif
/*
Used for updating/reading spork settings on the network
*/
UniValue spork(const UniValue& params, bool fHelp)
{
if (params.size() == 1 && params[0].get_str() == "show") {
UniValue ret(UniValue::VOBJ);
for (int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++) {
if (sporkManager.GetSporkNameByID(nSporkID) != "Unknown")
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), GetSporkValue(nSporkID)));
}
return ret;
} else if (params.size() == 1 && params[0].get_str() == "active") {
UniValue ret(UniValue::VOBJ);
for (int nSporkID = SPORK_START; nSporkID <= SPORK_END; nSporkID++) {
if (sporkManager.GetSporkNameByID(nSporkID) != "Unknown")
ret.push_back(Pair(sporkManager.GetSporkNameByID(nSporkID), IsSporkActive(nSporkID)));
}
return ret;
} else if (params.size() == 2) {
int nSporkID = sporkManager.GetSporkIDByName(params[0].get_str());
if (nSporkID == -1) {
return "Invalid spork name";
}
// SPORK VALUE
int64_t nValue = params[1].get_int64();
//broadcast new spork
if (sporkManager.UpdateSpork(nSporkID, nValue)) {
return "success";
} else {
return "failure";
}
}
throw runtime_error(
"spork \"name\" ( value )\n"
"\nReturn spork values or their active state.\n"
"\nArguments:\n"
"1. \"name\" (string, required) \"show\" to show values, \"active\" to show active state.\n"
" When set up as a spork signer, the name of the spork can be used to update it's value.\n"
"2. value (numeric, required when updating a spork) The new value for the spork.\n"
"\nResult (show):\n"
"{\n"
" \"spork_name\": nnn (key/value) Key is the spork name, value is it's current value.\n"
" ,...\n"
"}\n"
"\nResult (active):\n"
"{\n"
" \"spork_name\": true|false (key/value) Key is the spork name, value is a boolean for it's active state.\n"
" ,...\n"
"}\n"
"\nResult (name):\n"
" \"success|failure\" (string) Wither or not the update succeeded.\n"
"\nExamples:\n" +
HelpExampleCli("spork", "show") + HelpExampleRpc("spork", "show"));
}
UniValue validateaddress(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"validateaddress \"agrarianaddress\"\n"
"\nReturn information about the given agrarian address.\n"
"\nArguments:\n"
"1. \"agrarianaddress\" (string, required) The agrarian address to validate\n"
"\nResult:\n"
"{\n"
" \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n"
" \"address\" : \"agrarianaddress\", (string) The agrarian address validated\n"
" \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
" \"ismine\" : true|false, (boolean) If the address is yours or not\n"
" \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
" \"isscript\" : true|false, (boolean) If the key is a script\n"
" \"hex\" : \"hex\", (string, optional) The redeemscript for the P2SH address\n"
" \"pubkey\" : \"publickeyhex\", (string) The hex value of the raw public key\n"
" \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
" \"account\" : \"account\" (string) The account associated with the address, \"\" is the default account\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\""));
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid();
UniValue ret(UniValue::VOBJ);
ret.push_back(Pair("isvalid", isValid));
if (isValid) {
CTxDestination dest = address.Get();
string currentAddress = address.ToString();
ret.push_back(Pair("address", currentAddress));
CScript scriptPubKey = GetScriptForDestination(dest);
ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
#ifdef ENABLE_WALLET
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO;
ret.push_back(Pair("ismine", bool(mine & ISMINE_SPENDABLE)));
ret.push_back(Pair("iswatchonly", bool(mine & ISMINE_WATCH_ONLY)));
UniValue detail = boost::apply_visitor(DescribeAddressVisitor(mine), dest);
ret.pushKVs(detail);
if (pwalletMain && pwalletMain->mapAddressBook.count(dest))
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name));
#endif
}
return ret;
}
/**
* Used by addmultisigaddress / createmultisig:
*/
CScript _createmultisig_redeemScript(const UniValue& params)
{
int nRequired = params[0].get_int();
const UniValue& keys = params[1].get_array();
// Gather public keys
if (nRequired < 1)
throw runtime_error("a multisignature address must require at least one key to redeem");
if ((int)keys.size() < nRequired)
throw runtime_error(
strprintf("not enough keys supplied "
"(got %u keys, but need at least %d to redeem)",
keys.size(), nRequired));
if (keys.size() > 16)
throw runtime_error("Number of addresses involved in the multisignature address creation > 16\nReduce the number");
std::vector<CPubKey> pubkeys;
pubkeys.resize(keys.size());
for (unsigned int i = 0; i < keys.size(); i++) {
const std::string& ks = keys[i].get_str();
#ifdef ENABLE_WALLET
// Case 1: Agrarian address and we have full public key:
CBitcoinAddress address(ks);
if (pwalletMain && address.IsValid()) {
CKeyID keyID;
if (!address.GetKeyID(keyID))
throw runtime_error(
strprintf("%s does not refer to a key", ks));
CPubKey vchPubKey;
if (!pwalletMain->GetPubKey(keyID, vchPubKey))
throw runtime_error(
strprintf("no full public key for address %s", ks));
if (!vchPubKey.IsFullyValid())
throw runtime_error(" Invalid public key: " + ks);
pubkeys[i] = vchPubKey;
}
// Case 2: hex public key
else
#endif
if (IsHex(ks)) {
CPubKey vchPubKey(ParseHex(ks));
if (!vchPubKey.IsFullyValid())
throw runtime_error(" Invalid public key: " + ks);
pubkeys[i] = vchPubKey;
} else {
throw runtime_error(" Invalid public key: " + ks);
}
}
CScript result = GetScriptForMultisig(nRequired, pubkeys);
if (result.size() > MAX_SCRIPT_ELEMENT_SIZE)
throw runtime_error(
strprintf("redeemScript exceeds size limit: %d > %d", result.size(), MAX_SCRIPT_ELEMENT_SIZE));
return result;
}
UniValue createmultisig(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 2 || params.size() > 2)
throw runtime_error(
"createmultisig nrequired [\"key\",...]\n"
"\nCreates a multi-signature address with n signature of m keys required.\n"
"It returns a json object with the address and redeemScript.\n"
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
"2. \"keys\" (string, required) A json array of keys which are agrarian addresses or hex-encoded public keys\n"
" [\n"
" \"key\" (string) agrarian address or hex-encoded public key\n"
" ,...\n"
" ]\n"
"\nResult:\n"
"{\n"
" \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
" \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
"}\n"
"\nExamples:\n"
"\nCreate a multisig address from 2 addresses\n" +
HelpExampleCli("createmultisig", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
"\nAs a json rpc call\n" +
HelpExampleRpc("createmultisig", "2, \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\""));
// Construct using pay-to-script-hash:
CScript inner = _createmultisig_redeemScript(params);
CScriptID innerID(inner);
CBitcoinAddress address(innerID);
UniValue result(UniValue::VOBJ);
result.push_back(Pair("address", address.ToString()));
result.push_back(Pair("redeemScript", HexStr(inner.begin(), inner.end())));
return result;
}
UniValue verifymessage(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 3)
throw runtime_error(
"verifymessage \"agrarianaddress\" \"signature\" \"message\"\n"
"\nVerify a signed message\n"
"\nArguments:\n"
"1. \"agrarianaddress\" (string, required) The agrarian address to use for the signature.\n"
"2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n"
"3. \"message\" (string, required) The message that was signed.\n"
"\nResult:\n"
"true|false (boolean) If the signature is verified or not.\n"
"\nExamples:\n"
"\nUnlock the wallet for 30 seconds\n" +
HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n" +
HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"my message\"") +
"\nVerify the signature\n" +
HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\" \"signature\" \"my message\"") +
"\nAs json rpc\n" +
HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\""));
LOCK(cs_main);
string strAddress = params[0].get_str();
string strSign = params[1].get_str();
string strMessage = params[2].get_str();
CBitcoinAddress addr(strAddress);
if (!addr.IsValid())
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
CKeyID keyID;
if (!addr.GetKeyID(keyID))
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
bool fInvalid = false;
vector<unsigned char> vchSig = DecodeBase64(strSign.c_str(), &fInvalid);
if (fInvalid)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
CHashWriter ss(SER_GETHASH, 0);
ss << strMessageMagic;
ss << strMessage;
CPubKey pubkey;
if (!pubkey.RecoverCompact(ss.GetHash(), vchSig))
return false;
return (pubkey.GetID() == keyID);
}
UniValue setmocktime(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"setmocktime timestamp\n"
"\nSet the local time to given timestamp (-regtest only)\n"
"\nArguments:\n"
"1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n"
" Pass 0 to go back to using the system time.");
if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only");
LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(UniValue::VNUM));
SetMockTime(params[0].get_int64());
return NullUniValue;
}
#ifdef ENABLE_WALLET
UniValue getstakingstatus(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getstakingstatus\n"
"\nReturns an object containing various staking information.\n"
"\nResult:\n"
"{\n"
" \"validtime\": true|false, (boolean) if the chain tip is within staking phases\n"
" \"haveconnections\": true|false, (boolean) if network connections are present\n"
" \"walletunlocked\": true|false, (boolean) if the wallet is unlocked\n"
" \"mintablecoins\": true|false, (boolean) if the wallet has mintable coins\n"
" \"enoughcoins\": true|false, (boolean) if available coins are greater than reserve balance\n"
" \"mnsync\": true|false, (boolean) if masternode data is synced\n"
" \"staking status\": true|false, (boolean) if the wallet is staking or not\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getstakingstatus", "") + HelpExampleRpc("getstakingstatus", ""));
#ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
#else
LOCK(cs_main);
#endif
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("validtime", chainActive.Tip()->nTime > 1471482000));
obj.push_back(Pair("haveconnections", !vNodes.empty()));
if (pwalletMain) {
obj.push_back(Pair("walletunlocked", !pwalletMain->IsLocked()));
obj.push_back(Pair("mintablecoins", pwalletMain->MintableCoins()));
obj.push_back(Pair("enoughcoins", nReserveBalance <= pwalletMain->GetBalance()));
}
obj.push_back(Pair("mnsync", masternodeSync.IsSynced()));
bool nStaking = false;
if (mapHashedBlocks.count(chainActive.Tip()->nHeight))
nStaking = true;
else if (mapHashedBlocks.count(chainActive.Tip()->nHeight - 1) && nLastCoinStakeSearchInterval)
nStaking = true;
obj.push_back(Pair("staking status", nStaking));
return obj;
}
#endif // ENABLE_WALLET
+578
View File
@@ -0,0 +1,578 @@
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "rpc/server.h"
#include "clientversion.h"
#include "main.h"
#include "net.h"
#include "netbase.h"
#include "protocol.h"
#include "sync.h"
#include "timedata.h"
#include "guiinterface.h"
#include "util.h"
#include "version.h"
#include <univalue.h>
using namespace std;
UniValue getconnectioncount(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getconnectioncount\n"
"\nReturns the number of connections to other nodes.\n"
"\nbResult:\n"
"n (numeric) The connection count\n"
"\nExamples:\n" +
HelpExampleCli("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", ""));
LOCK2(cs_main, cs_vNodes);
return (int)vNodes.size();
}
UniValue ping(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"ping\n"
"\nRequests that a ping be sent to all other nodes, to measure ping time.\n"
"Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n"
"Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n"
"\nExamples:\n" +
HelpExampleCli("ping", "") + HelpExampleRpc("ping", ""));
// Request that each node send a ping during next message processing pass
LOCK2(cs_main, cs_vNodes);
for (CNode* pNode : vNodes) {
pNode->fPingQueued = true;
}
return NullUniValue;
}
static void CopyNodeStats(std::vector<CNodeStats>& vstats)
{
vstats.clear();
LOCK(cs_vNodes);
vstats.reserve(vNodes.size());
for (CNode* pnode : vNodes) {
CNodeStats stats;
pnode->copyStats(stats);
vstats.push_back(stats);
}
}
UniValue getpeerinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getpeerinfo\n"
"\nReturns data about each connected network node as a json array of objects.\n"
"\nbResult:\n"
"[\n"
" {\n"
" \"id\": n, (numeric) Peer index\n"
" \"addr\":\"host:port\", (string) The ip address and port of the peer\n"
" \"addrlocal\":\"ip:port\", (string) local address\n"
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
" \"lastsend\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last send\n"
" \"lastrecv\": ttt, (numeric) The time in seconds since epoch (Jan 1 1970 GMT) of the last receive\n"
" \"bytessent\": n, (numeric) The total bytes sent\n"
" \"bytesrecv\": n, (numeric) The total bytes received\n"
" \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"timeoffset\": ttt, (numeric) The time offset in seconds\n"
" \"pingtime\": n, (numeric) ping time\n"
" \"pingwait\": n, (numeric) ping wait\n"
" \"version\": v, (numeric) The peer version, such as 7001\n"
" \"subver\": \"/Agrarian Core:x.x.x.x/\", (string) The string version\n"
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
" \"startingheight\": n, (numeric) The starting height (block) of the peer\n"
" \"banscore\": n, (numeric) The ban score\n"
" \"synced_headers\": n, (numeric) The last header we have in common with this peer\n"
" \"synced_blocks\": n, (numeric) The last block we have in common with this peer\n"
" \"inflight\": [\n"
" n, (numeric) The heights of blocks we're currently asking from this peer\n"
" ...\n"
" ]\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", ""));
LOCK(cs_main);
vector<CNodeStats> vstats;
CopyNodeStats(vstats);
UniValue ret(UniValue::VARR);
for (const CNodeStats& stats : vstats) {
UniValue obj(UniValue::VOBJ);
CNodeStateStats statestats;
bool fStateStats = GetNodeStateStats(stats.nodeid, statestats);
obj.push_back(Pair("id", stats.nodeid));
obj.push_back(Pair("addr", stats.addrName));
if (!(stats.addrLocal.empty()))
obj.push_back(Pair("addrlocal", stats.addrLocal));
obj.push_back(Pair("services", strprintf("%016x", stats.nServices)));
obj.push_back(Pair("lastsend", stats.nLastSend));
obj.push_back(Pair("lastrecv", stats.nLastRecv));
obj.push_back(Pair("bytessent", stats.nSendBytes));
obj.push_back(Pair("bytesrecv", stats.nRecvBytes));
obj.push_back(Pair("conntime", stats.nTimeConnected));
obj.push_back(Pair("timeoffset", stats.nTimeOffset));
obj.push_back(Pair("pingtime", stats.dPingTime));
if (stats.dPingWait > 0.0)
obj.push_back(Pair("pingwait", stats.dPingWait));
obj.push_back(Pair("version", stats.nVersion));
// Use the sanitized form of subver here, to avoid tricksy remote peers from
// corrupting or modifiying the JSON output by putting special characters in
// their ver message.
obj.push_back(Pair("subver", stats.cleanSubVer));
obj.push_back(Pair("inbound", stats.fInbound));
obj.push_back(Pair("startingheight", stats.nStartingHeight));
if (fStateStats) {
obj.push_back(Pair("banscore", statestats.nMisbehavior));
obj.push_back(Pair("synced_headers", statestats.nSyncHeight));
obj.push_back(Pair("synced_blocks", statestats.nCommonHeight));
UniValue heights(UniValue::VARR);
for (int height : statestats.vHeightInFlight) {
heights.push_back(height);
}
obj.push_back(Pair("inflight", heights));
}
obj.push_back(Pair("whitelisted", stats.fWhitelisted));
ret.push_back(obj);
}
return ret;
}
UniValue addnode(const UniValue& params, bool fHelp)
{
string strCommand;
if (params.size() == 2)
strCommand = params[1].get_str();
if (fHelp || params.size() != 2 ||
(strCommand != "onetry" && strCommand != "add" && strCommand != "remove"))
throw runtime_error(
"addnode \"node\" \"add|remove|onetry\"\n"
"\nAttempts add or remove a node from the addnode list.\n"
"Or try a connection to a node once.\n"
"\nArguments:\n"
"1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
"2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n"
"\nExamples:\n" +
HelpExampleCli("addnode", "\"192.168.0.6:51336\" \"onetry\"") + HelpExampleRpc("addnode", "\"192.168.0.6:51336\", \"onetry\""));
string strNode = params[0].get_str();
if (strCommand == "onetry") {
CAddress addr;
OpenNetworkConnection(addr, NULL, strNode.c_str());
return NullUniValue;
}
LOCK(cs_vAddedNodes);
vector<string>::iterator it = vAddedNodes.begin();
for (; it != vAddedNodes.end(); it++)
if (strNode == *it)
break;
if (strCommand == "add") {
if (it != vAddedNodes.end())
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Node already added");
vAddedNodes.push_back(strNode);
} else if (strCommand == "remove") {
if (it == vAddedNodes.end())
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
vAddedNodes.erase(it);
}
return NullUniValue;
}
UniValue disconnectnode(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 1)
throw runtime_error(
"disconnectnode \"node\" \n"
"\nImmediately disconnects from the specified node.\n"
"\nArguments:\n"
"1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n"
"\nExamples:\n"
+ HelpExampleCli("disconnectnode", "\"192.168.0.6:8333\"")
+ HelpExampleRpc("disconnectnode", "\"192.168.0.6:8333\"")
);
CNode* pNode = FindNode(params[0].get_str());
if (pNode == NULL)
throw JSONRPCError(RPC_CLIENT_NODE_NOT_CONNECTED, "Node not found in connected nodes");
pNode->CloseSocketDisconnect();
return NullUniValue;
}
UniValue getaddednodeinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() < 1 || params.size() > 2)
throw runtime_error(
"getaddednodeinfo dns ( \"node\" )\n"
"\nReturns information about the given added node, or all added nodes\n"
"(note that onetry addnodes are not listed here)\n"
"If dns is false, only a list of added nodes will be provided,\n"
"otherwise connected information will also be available.\n"
"\nArguments:\n"
"1. dns (boolean, required) If false, only a list of added nodes will be provided, otherwise connected information will also be available.\n"
"2. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n"
"\nResult:\n"
"[\n"
" {\n"
" \"addednode\" : \"192.168.0.201\", (string) The node ip address\n"
" \"connected\" : true|false, (boolean) If connected\n"
" \"addresses\" : [\n"
" {\n"
" \"address\" : \"192.168.0.201:51336\", (string) The agrarian server host and port\n"
" \"connected\" : \"outbound\" (string) connection, inbound or outbound\n"
" }\n"
" ,...\n"
" ]\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n" +
HelpExampleCli("getaddednodeinfo", "true") + HelpExampleCli("getaddednodeinfo", "true \"192.168.0.201\"") + HelpExampleRpc("getaddednodeinfo", "true, \"192.168.0.201\""));
bool fDns = params[0].get_bool();
list<string> laddedNodes(0);
if (params.size() == 1) {
LOCK(cs_vAddedNodes);
for (string& strAddNode : vAddedNodes)
laddedNodes.push_back(strAddNode);
} else {
string strNode = params[1].get_str();
LOCK(cs_vAddedNodes);
for (string& strAddNode : vAddedNodes)
if (strAddNode == strNode) {
laddedNodes.push_back(strAddNode);
break;
}
if (laddedNodes.size() == 0)
throw JSONRPCError(RPC_CLIENT_NODE_NOT_ADDED, "Error: Node has not been added.");
}
UniValue ret(UniValue::VARR);
if (!fDns) {
for (string& strAddNode : laddedNodes) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", strAddNode));
ret.push_back(obj);
}
return ret;
}
list<pair<string, vector<CService> > > laddedAddreses(0);
for (string& strAddNode : laddedNodes) {
vector<CService> vservNode(0);
if (Lookup(strAddNode.c_str(), vservNode, Params().GetDefaultPort(), fNameLookup, 0))
laddedAddreses.push_back(make_pair(strAddNode, vservNode));
else {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", strAddNode));
obj.push_back(Pair("connected", false));
UniValue addresses(UniValue::VARR);
obj.push_back(Pair("addresses", addresses));
}
}
LOCK(cs_vNodes);
for (list<pair<string, vector<CService> > >::iterator it = laddedAddreses.begin(); it != laddedAddreses.end(); it++) {
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("addednode", it->first));
UniValue addresses(UniValue::VARR);
bool fConnected = false;
for (CService& addrNode : it->second) {
bool fFound = false;
UniValue node(UniValue::VOBJ);
node.push_back(Pair("address", addrNode.ToString()));
for (CNode* pnode : vNodes)
if (pnode->addr == addrNode) {
fFound = true;
fConnected = true;
node.push_back(Pair("connected", pnode->fInbound ? "inbound" : "outbound"));
break;
}
if (!fFound)
node.push_back(Pair("connected", "false"));
addresses.push_back(node);
}
obj.push_back(Pair("connected", fConnected));
obj.push_back(Pair("addresses", addresses));
ret.push_back(obj);
}
return ret;
}
UniValue getnettotals(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 0)
throw runtime_error(
"getnettotals\n"
"\nReturns information about network traffic, including bytes in, bytes out,\n"
"and current time.\n"
"\nResult:\n"
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
" \"totalbytessent\": n, (numeric) Total bytes sent\n"
" \"timemillis\": t (numeric) Total cpu time\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", ""));
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("totalbytesrecv", CNode::GetTotalBytesRecv()));
obj.push_back(Pair("totalbytessent", CNode::GetTotalBytesSent()));
obj.push_back(Pair("timemillis", GetTimeMillis()));
return obj;
}
static UniValue GetNetworksInfo()
{
UniValue networks(UniValue::VARR);
for (int n = 0; n < NET_MAX; ++n) {
enum Network network = static_cast<enum Network>(n);
if (network == NET_UNROUTABLE)
continue;
proxyType proxy;
UniValue obj(UniValue::VOBJ);
GetProxy(network, proxy);
obj.push_back(Pair("name", GetNetworkName(network)));
obj.push_back(Pair("limited", IsLimited(network)));
obj.push_back(Pair("reachable", IsReachable(network)));
obj.push_back(Pair("proxy", proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()));
obj.push_back(Pair("proxy_randomize_credentials", proxy.randomize_credentials));
networks.push_back(obj);
}
return networks;
}
UniValue getnetworkinfo(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"getnetworkinfo\n"
"\nReturns an object containing various state info regarding P2P networking.\n"
"\nResult:\n"
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"subversion\": \"/Agrarian Core:x.x.x.x/\", (string) the server subversion string\n"
" \"protocolversion\": xxxxx, (numeric) the protocol version\n"
" \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
" \"networks\": [ (array) information per network\n"
" {\n"
" \"name\": \"xxx\", (string) network (ipv4, ipv6 or onion)\n"
" \"limited\": true|false, (boolean) is the network limited using -onlynet?\n"
" \"reachable\": true|false, (boolean) is the network reachable?\n"
" \"proxy\": \"host:port\" (string) the proxy that is used for this network, or empty if none\n"
" }\n"
" ,...\n"
" ],\n"
" \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for non-free transactions in agrarian/kb\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" {\n"
" \"address\": \"xxxx\", (string) network address\n"
" \"port\": xxx, (numeric) network port\n"
" \"score\": xxx (numeric) relative score\n"
" }\n"
" ,...\n"
" ]\n"
"}\n"
"\nExamples:\n" +
HelpExampleCli("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", ""));
LOCK(cs_main);
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion", strSubVersion));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices)));
obj.push_back(Pair("timeoffset", GetTimeOffset()));
obj.push_back(Pair("connections", (int)vNodes.size()));
obj.push_back(Pair("networks", GetNetworksInfo()));
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
UniValue localAddresses(UniValue::VARR);
{
LOCK(cs_mapLocalHost);
for (const std::pair<const CNetAddr, LocalServiceInfo> &item : mapLocalHost) {
UniValue rec(UniValue::VOBJ);
rec.push_back(Pair("address", item.first.ToString()));
rec.push_back(Pair("port", item.second.nPort));
rec.push_back(Pair("score", item.second.nScore));
localAddresses.push_back(rec);
}
}
obj.push_back(Pair("localaddresses", localAddresses));
return obj;
}
UniValue setban(const UniValue& params, bool fHelp)
{
string strCommand;
if (params.size() >= 2)
strCommand = params[1].get_str();
if (fHelp || params.size() < 2 ||
(strCommand != "add" && strCommand != "remove"))
throw runtime_error(
"setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n"
"\nAttempts add or remove a IP/Subnet from the banned list.\n"
"\nArguments:\n"
"1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n"
"2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n"
"3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n"
"4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n"
"\nExamples:\n"
+ HelpExampleCli("setban", "\"192.168.0.6\" \"add\" 86400")
+ HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"")
+ HelpExampleRpc("setban", "\"192.168.0.6\", \"add\" 86400"));
CSubNet subNet;
CNetAddr netAddr;
bool isSubnet = false;
if (params[0].get_str().find("/") != string::npos)
isSubnet = true;
if (!isSubnet)
netAddr = CNetAddr(params[0].get_str());
else
subNet = CSubNet(params[0].get_str());
if (! (isSubnet ? subNet.IsValid() : netAddr.IsValid()) )
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: Invalid IP/Subnet");
if (strCommand == "add")
{
if (isSubnet ? CNode::IsBanned(subNet) : CNode::IsBanned(netAddr))
throw JSONRPCError(RPC_CLIENT_NODE_ALREADY_ADDED, "Error: IP/Subnet already banned");
int64_t banTime = 0; //use standard bantime if not specified
if (params.size() >= 3 && !params[2].isNull())
banTime = params[2].get_int64();
bool absolute = false;
if (params.size() == 4)
absolute = params[3].get_bool();
isSubnet ? CNode::Ban(subNet, BanReasonManuallyAdded, banTime, absolute) : CNode::Ban(netAddr, BanReasonManuallyAdded, banTime, absolute);
//disconnect possible nodes
while(CNode *bannedNode = (isSubnet ? FindNode(subNet) : FindNode(netAddr)))
bannedNode->CloseSocketDisconnect();
}
else if(strCommand == "remove")
{
if (!( isSubnet ? CNode::Unban(subNet) : CNode::Unban(netAddr) ))
throw JSONRPCError(RPC_MISC_ERROR, "Error: Unban failed");
}
DumpBanlist(); //store banlist to disk
uiInterface.BannedListChanged();
return NullUniValue;
}
UniValue listbanned(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"listbanned\n"
"\nList all banned IPs/Subnets.\n"
"\nResult:\n"
"[\n"
" {\n"
" \"address\": \"xxx\", (string) Network address of banned client.\n"
" \"banned_until\": nnn, (numeric) Timestamp when the ban is lifted.\n"
" \"ban_created\": nnn, (numeric) Timestamp when the ban was created.\n"
" \"ban_reason\": \"xxx\" (string) Reason for banning.\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n"
+ HelpExampleCli("listbanned", "")
+ HelpExampleRpc("listbanned", ""));
banmap_t banMap;
CNode::GetBanned(banMap);
UniValue bannedAddresses(UniValue::VARR);
for (banmap_t::iterator it = banMap.begin(); it != banMap.end(); it++)
{
CBanEntry banEntry = (*it).second;
UniValue rec(UniValue::VOBJ);
rec.push_back(Pair("address", (*it).first.ToString()));
rec.push_back(Pair("banned_until", banEntry.nBanUntil));
rec.push_back(Pair("ban_created", banEntry.nCreateTime));
rec.push_back(Pair("ban_reason", banEntry.banReasonToString()));
bannedAddresses.push_back(rec);
}
return bannedAddresses;
}
UniValue clearbanned(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() != 0)
throw runtime_error(
"clearbanned\n"
"\nClear all banned IPs.\n"
"\nExamples:\n"
+ HelpExampleCli("clearbanned", "")
+ HelpExampleRpc("clearbanned", ""));
CNode::ClearBanned();
DumpBanlist(); //store banlist to disk
uiInterface.BannedListChanged();
return NullUniValue;
}
+129
View File
@@ -0,0 +1,129 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2018 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "rpc/protocol.h"
#include "random.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
#include "utiltime.h"
#include "version.h"
#include <stdint.h>
#include <fstream>
using namespace std;
/**
* JSON-RPC protocol. Agrarian speaks version 1.0 for maximum compatibility,
* but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
* unspecified (HTTP errors and contents of 'error').
*
* 1.0 spec: http://json-rpc.org/wiki/specification
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
* http://www.codeproject.com/KB/recipes/JSON_Spirit.aspx
*/
string JSONRPCRequest(const string& strMethod, const UniValue& params, const UniValue& id)
{
UniValue request(UniValue::VOBJ);
request.push_back(Pair("method", strMethod));
request.push_back(Pair("params", params));
request.push_back(Pair("id", id));
return request.write() + "\n";
}
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
{
UniValue reply(UniValue::VOBJ);
if (!error.isNull())
reply.push_back(Pair("result", NullUniValue));
else
reply.push_back(Pair("result", result));
reply.push_back(Pair("error", error));
reply.push_back(Pair("id", id));
return reply;
}
string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
{
UniValue reply = JSONRPCReplyObj(result, error, id);
return reply.write() + "\n";
}
UniValue JSONRPCError(int code, const string& message)
{
UniValue error(UniValue::VOBJ);
error.push_back(Pair("code", code));
error.push_back(Pair("message", message));
return error;
}
/** Username used when cookie authentication is in use (arbitrary, only for
* recognizability in debugging/logging purposes)
*/
static const std::string COOKIEAUTH_USER = "__cookie__";
/** Default name for auth cookie file */
static const std::string COOKIEAUTH_FILE = ".cookie";
boost::filesystem::path GetAuthCookieFile()
{
boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE));
if (!path.is_complete()) path = GetDataDir() / path;
return path;
}
bool GenerateAuthCookie(std::string *cookie_out)
{
unsigned char rand_pwd[32];
GetRandBytes(rand_pwd, 32);
std::string cookie = COOKIEAUTH_USER + ":" + EncodeBase64(&rand_pwd[0],32);
/** the umask determines what permissions are used to create this file -
* these are set to 077 in init.cpp unless overridden with -sysperms.
*/
std::ofstream file;
boost::filesystem::path filepath = GetAuthCookieFile();
file.open(filepath.string().c_str());
if (!file.is_open()) {
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string());
return false;
}
file << cookie;
file.close();
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string());
if (cookie_out)
*cookie_out = cookie;
return true;
}
bool GetAuthCookie(std::string *cookie_out)
{
std::ifstream file;
std::string cookie;
boost::filesystem::path filepath = GetAuthCookieFile();
file.open(filepath.string().c_str());
if (!file.is_open())
return false;
std::getline(file, cookie);
file.close();
if (cookie_out)
*cookie_out = cookie;
return true;
}
void DeleteAuthCookie()
{
try {
boost::filesystem::remove(GetAuthCookieFile());
} catch (const boost::filesystem::filesystem_error& e) {
LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what());
}
}
+92
View File
@@ -0,0 +1,92 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2017-2018 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_RPCPROTOCOL_H
#define BITCOIN_RPCPROTOCOL_H
#include <list>
#include <map>
#include <stdint.h>
#include <string>
#include <boost/filesystem.hpp>
#include <univalue.h>
//! HTTP status codes
enum HTTPStatusCode {
HTTP_OK = 200,
HTTP_BAD_REQUEST = 400,
HTTP_UNAUTHORIZED = 401,
HTTP_FORBIDDEN = 403,
HTTP_NOT_FOUND = 404,
HTTP_BAD_METHOD = 405,
HTTP_INTERNAL_SERVER_ERROR = 500,
HTTP_SERVICE_UNAVAILABLE = 503,
};
//! Agrarian RPC error codes
enum RPCErrorCode {
//! Standard JSON-RPC 2.0 errors
RPC_INVALID_REQUEST = -32600,
RPC_METHOD_NOT_FOUND = -32601,
RPC_INVALID_PARAMS = -32602,
RPC_INTERNAL_ERROR = -32603,
RPC_PARSE_ERROR = -32700,
//! General application defined errors
RPC_MISC_ERROR = -1, //! std::exception thrown in command handling
RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode
RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter
RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key
RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation
RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter
RPC_DATABASE_ERROR = -20, //! Database error
RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format
RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission
RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules
RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain
RPC_IN_WARMUP = -28, //! Client still warming up
//! Aliases for backward compatibility
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
RPC_TRANSACTION_REJECTED = RPC_VERIFY_REJECTED,
RPC_TRANSACTION_ALREADY_IN_CHAIN = RPC_VERIFY_ALREADY_IN_CHAIN,
//! P2P client errors
RPC_CLIENT_NOT_CONNECTED = -9, //! Agrarian is not connected
RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
//! Wallet errors
RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet
RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked
};
std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
UniValue JSONRPCError(int code, const std::string& message);
/** Get name of RPC authentication cookie file */
boost::filesystem::path GetAuthCookieFile();
/** Generate a new RPC authentication cookie and write it to disk */
bool GenerateAuthCookie(std::string *cookie_out);
/** Read the RPC authentication cookie from disk */
bool GetAuthCookie(std::string *cookie_out);
/** Delete RPC authentication cookie from disk */
void DeleteAuthCookie();
#endif // BITCOIN_RPCPROTOCOL_H
File diff suppressed because it is too large Load Diff
+671
View File
@@ -0,0 +1,671 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2014-2015 The Dash developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "rpc/server.h"
#include "base58.h"
#include "init.h"
#include "main.h"
#include "random.h"
#include "sync.h"
#include "guiinterface.h"
#include "util.h"
#include "utilstrencodings.h"
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include <boost/algorithm/string/case_conv.hpp> // for to_upper()
#include <univalue.h>
using namespace RPCServer;
using namespace std;
static bool fRPCRunning = false;
static bool fRPCInWarmup = true;
static std::string rpcWarmupStatus("RPC server started");
static CCriticalSection cs_rpcWarmup;
/* Timer-creating functions */
static RPCTimerInterface* timerInterface = NULL;
/* Map of name to timer.
* @note Can be changed to std::unique_ptr when C++11 */
static std::map<std::string, boost::shared_ptr<RPCTimerBase> > deadlineTimers;
static struct CRPCSignals
{
boost::signals2::signal<void ()> Started;
boost::signals2::signal<void ()> Stopped;
boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
boost::signals2::signal<void (const CRPCCommand&)> PostCommand;
} g_rpcSignals;
void RPCServer::OnStarted(boost::function<void ()> slot)
{
g_rpcSignals.Started.connect(slot);
}
void RPCServer::OnStopped(boost::function<void ()> slot)
{
g_rpcSignals.Stopped.connect(slot);
}
void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot)
{
g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
}
void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
{
g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
}
void RPCTypeCheck(const UniValue& params,
const list<UniValue::VType>& typesExpected,
bool fAllowNull)
{
unsigned int i = 0;
for (UniValue::VType t : typesExpected) {
if (params.size() <= i)
break;
const UniValue& v = params[i];
if (!((v.type() == t) || (fAllowNull && (v.isNull())))) {
string err = strprintf("Expected type %s, got %s",
uvTypeName(t), uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
i++;
}
}
void RPCTypeCheckObj(const UniValue& o,
const map<string, UniValue::VType>& typesExpected,
bool fAllowNull)
{
for (const PAIRTYPE(string, UniValue::VType)& t : typesExpected) {
const UniValue& v = find_value(o, t.first);
if (!fAllowNull && v.isNull())
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
if (!((v.type() == t.second) || (fAllowNull && (v.isNull())))) {
string err = strprintf("Expected type %s for %s, got %s",
uvTypeName(t.second), t.first, uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
}
}
static inline int64_t roundint64(double d)
{
return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
}
CAmount AmountFromValue(const UniValue& value)
{
if (!value.isNum())
throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number");
double dAmount = value.get_real();
if (dAmount <= 0.0 || dAmount > 21000000.0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
CAmount nAmount = roundint64(dAmount * COIN);
if (!MoneyRange(nAmount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
return nAmount;
}
UniValue ValueFromAmount(const CAmount& amount)
{
bool sign = amount < 0;
int64_t n_abs = (sign ? -amount : amount);
int64_t quotient = n_abs / COIN;
int64_t remainder = n_abs % COIN;
return UniValue(UniValue::VNUM,
strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
}
uint256 ParseHashV(const UniValue& v, std::string strName)
{
std::string strHex;
if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')");
if (64 != strHex.length())
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("%s must be of length %d (not %d)", strName, 64, strHex.length()));
uint256 result;
result.SetHex(strHex);
return result;
}
uint256 ParseHashO(const UniValue& o, string strKey)
{
return ParseHashV(find_value(o, strKey), strKey);
}
vector<unsigned char> ParseHexV(const UniValue& v, string strName)
{
string strHex;
if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex))
throw JSONRPCError(RPC_INVALID_PARAMETER, strName + " must be hexadecimal string (not '" + strHex + "')");
return ParseHex(strHex);
}
vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
{
return ParseHexV(find_value(o, strKey), strKey);
}
int ParseInt(const UniValue& o, string strKey)
{
const UniValue& v = find_value(o, strKey);
if (v.isNum())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, " + strKey + "is not an int");
return v.get_int();
}
bool ParseBool(const UniValue& o, string strKey)
{
const UniValue& v = find_value(o, strKey);
if (v.isBool())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, " + strKey + "is not a bool");
return v.get_bool();
}
/**
* Note: This interface may still be subject to change.
*/
string CRPCTable::help(string strCommand) const
{
string strRet;
string category;
set<rpcfn_type> setDone;
vector<pair<string, const CRPCCommand*> > vCommands;
for (map<string, const CRPCCommand*>::const_iterator mi = mapCommands.begin(); mi != mapCommands.end(); ++mi)
vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second));
sort(vCommands.begin(), vCommands.end());
for (const PAIRTYPE(string, const CRPCCommand*) & command : vCommands) {
const CRPCCommand* pcmd = command.second;
string strMethod = pcmd->name;
// We already filter duplicates, but these deprecated screw up the sort order
if (strMethod.find("label") != string::npos)
continue;
if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
continue;
#ifdef ENABLE_WALLET
if (pcmd->reqWallet && !pwalletMain)
continue;
#endif
try {
UniValue params;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
(*pfn)(params, true);
} catch (std::exception& e) {
// Help text is returned in an exception
string strHelp = string(e.what());
if (strCommand == "") {
if (strHelp.find('\n') != string::npos)
strHelp = strHelp.substr(0, strHelp.find('\n'));
if (category != pcmd->category) {
if (!category.empty())
strRet += "\n";
category = pcmd->category;
string firstLetter = category.substr(0, 1);
boost::to_upper(firstLetter);
strRet += "== " + firstLetter + category.substr(1) + " ==\n";
}
}
strRet += strHelp + "\n";
}
}
if (strRet == "")
strRet = strprintf("help: unknown command: %s\n", strCommand);
strRet = strRet.substr(0, strRet.size() - 1);
return strRet;
}
UniValue help(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
"help ( \"command\" )\n"
"\nList all commands, or get help for a specified command.\n"
"\nArguments:\n"
"1. \"command\" (string, optional) The command to get help on\n"
"\nResult:\n"
"\"text\" (string) The help text\n");
string strCommand;
if (params.size() > 0)
strCommand = params[0].get_str();
return tableRPC.help(strCommand);
}
UniValue stop(const UniValue& params, bool fHelp)
{
// Accept the deprecated and ignored 'detach' boolean argument
if (fHelp || params.size() > 1)
throw runtime_error(
"stop\n"
"\nStop Agrarian server.");
// Event loop will exit after current HTTP requests have been handled, so
// this reply will get back to the client.
StartShutdown();
return "Agrarian server stopping";
}
/**
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
{
// category name actor (function) okSafeMode threadSafe reqWallet
// --------------------- ------------------------ ----------------------- ---------- ---------- ---------
/* Overall control/query calls */
{"control", "getinfo", &getinfo, true, false, false}, /* uses wallet if enabled */
{"control", "help", &help, true, true, false},
{"control", "stop", &stop, true, true, false},
/* P2P networking */
{"network", "getnetworkinfo", &getnetworkinfo, true, false, false},
{"network", "addnode", &addnode, true, true, false},
{"network", "disconnectnode", &disconnectnode, true, true, false},
{"network", "getaddednodeinfo", &getaddednodeinfo, true, true, false},
{"network", "getconnectioncount", &getconnectioncount, true, false, false},
{"network", "getnettotals", &getnettotals, true, true, false},
{"network", "getpeerinfo", &getpeerinfo, true, false, false},
{"network", "ping", &ping, true, false, false},
{"network", "setban", &setban, true, false, false},
{"network", "listbanned", &listbanned, true, false, false},
{"network", "clearbanned", &clearbanned, true, false, false},
/* Block chain and UTXO */
{"blockchain", "findserial", &findserial, true, false, false},
{"blockchain", "getaccumulatorvalues", &getaccumulatorvalues, true, false, false},
{"blockchain", "getaccumulatorwitness", &getaccumulatorwitness, true, false, false},
{"blockchain", "getblockindexstats", &getblockindexstats, true, false, false},
{"blockchain", "getmintsinblocks", &getmintsinblocks, true, false, false},
{"blockchain", "getserials", &getserials, true, false, false},
{"blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false},
{"blockchain", "getbestblockhash", &getbestblockhash, true, false, false},
{"blockchain", "getblockcount", &getblockcount, true, false, false},
{"blockchain", "getblock", &getblock, true, false, false},
{"blockchain", "getblockhash", &getblockhash, true, false, false},
{"blockchain", "getblockheader", &getblockheader, false, false, false},
{"blockchain", "getchaintips", &getchaintips, true, false, false},
{"blockchain", "getchecksumblock", &getchecksumblock, false, false, false},
{"blockchain", "getdifficulty", &getdifficulty, true, false, false},
{"blockchain", "getfeeinfo", &getfeeinfo, true, false, false},
{"blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false},
{"blockchain", "getrawmempool", &getrawmempool, true, false, false},
{"blockchain", "gettxout", &gettxout, true, false, false},
{"blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false},
{"blockchain", "invalidateblock", &invalidateblock, true, true, false},
{"blockchain", "reconsiderblock", &reconsiderblock, true, true, false},
{"blockchain", "verifychain", &verifychain, true, false, false},
/* Mining */
{"mining", "getblocktemplate", &getblocktemplate, true, false, false},
{"mining", "getmininginfo", &getmininginfo, true, false, false},
{"mining", "getnetworkhashps", &getnetworkhashps, true, false, false},
{"mining", "prioritisetransaction", &prioritisetransaction, true, false, false},
{"mining", "submitblock", &submitblock, true, true, false},
{"mining", "reservebalance", &reservebalance, true, true, false},
#ifdef ENABLE_WALLET
/* Coin generation */
{"generating", "getgenerate", &getgenerate, true, false, false},
{"generating", "gethashespersec", &gethashespersec, true, false, false},
{"generating", "setgenerate", &setgenerate, true, true, false},
{"generating", "generate", &generate, true, true, false},
#endif
/* Raw transactions */
{"rawtransactions", "createrawtransaction", &createrawtransaction, true, false, false},
{"rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false, false},
{"rawtransactions", "decodescript", &decodescript, true, false, false},
{"rawtransactions", "getrawtransaction", &getrawtransaction, true, false, false},
{"rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false, false},
{"rawtransactions", "signrawtransaction", &signrawtransaction, false, false, false}, /* uses wallet if enabled */
/* Utility functions */
{"util", "createmultisig", &createmultisig, true, true, false},
{"util", "validateaddress", &validateaddress, true, false, false}, /* uses wallet if enabled */
{"util", "verifymessage", &verifymessage, true, false, false},
{"util", "estimatefee", &estimatefee, true, true, false},
{"util", "estimatepriority", &estimatepriority, true, true, false},
/* Not shown in help */
{"hidden", "invalidateblock", &invalidateblock, true, true, false},
{"hidden", "reconsiderblock", &reconsiderblock, true, true, false},
{"hidden", "setmocktime", &setmocktime, true, false, false},
{ "hidden", "waitfornewblock", &waitfornewblock, true, true, false },
{ "hidden", "waitforblock", &waitforblock, true, true, false },
{ "hidden", "waitforblockheight", &waitforblockheight, true, true, false },
/* Agrarian features */
{"agrarian", "listmasternodes", &listmasternodes, true, true, false},
{"agrarian", "getmasternodecount", &getmasternodecount, true, true, false},
{"agrarian", "masternodeconnect", &masternodeconnect, true, true, false},
{"agrarian", "createmasternodebroadcast", &createmasternodebroadcast, true, true, false},
{"agrarian", "decodemasternodebroadcast", &decodemasternodebroadcast, true, true, false},
{"agrarian", "relaymasternodebroadcast", &relaymasternodebroadcast, true, true, false},
{"agrarian", "masternodecurrent", &masternodecurrent, true, true, false},
{"agrarian", "masternodedebug", &masternodedebug, true, true, false},
{"agrarian", "startmasternode", &startmasternode, true, true, false},
{"agrarian", "createmasternodekey", &createmasternodekey, true, true, false},
{"agrarian", "getmasternodeoutputs", &getmasternodeoutputs, true, true, false},
{"agrarian", "listmasternodeconf", &listmasternodeconf, true, true, false},
{"agrarian", "getmasternodestatus", &getmasternodestatus, true, true, false},
{"agrarian", "getmasternodewinners", &getmasternodewinners, true, true, false},
{"agrarian", "getmasternodescores", &getmasternodescores, true, true, false},
{"agrarian", "preparebudget", &preparebudget, true, true, false},
{"agrarian", "submitbudget", &submitbudget, true, true, false},
{"agrarian", "mnbudgetvote", &mnbudgetvote, true, true, false},
{"agrarian", "getbudgetvotes", &getbudgetvotes, true, true, false},
{"agrarian", "getnextsuperblock", &getnextsuperblock, true, true, false},
{"agrarian", "getbudgetprojection", &getbudgetprojection, true, true, false},
{"agrarian", "getbudgetinfo", &getbudgetinfo, true, true, false},
{"agrarian", "mnbudgetrawvote", &mnbudgetrawvote, true, true, false},
{"agrarian", "mnfinalbudget", &mnfinalbudget, true, true, false},
{"agrarian", "checkbudgets", &checkbudgets, true, true, false},
{"agrarian", "mnsync", &mnsync, true, true, false},
{"agrarian", "spork", &spork, true, true, false},
{"agrarian", "getpoolinfo", &getpoolinfo, true, true, false},
#ifdef ENABLE_WALLET
/* Wallet */
{"wallet", "addmultisigaddress", &addmultisigaddress, true, false, true},
{"wallet", "autocombinerewards", &autocombinerewards, false, false, true},
{"wallet", "backupwallet", &backupwallet, true, false, true},
{"wallet", "enableautomintaddress", &enableautomintaddress, true, false, true},
{"wallet", "createautomintaddress", &createautomintaddress, true, false, true},
{"wallet", "dumpprivkey", &dumpprivkey, true, false, true},
{"wallet", "dumpwallet", &dumpwallet, true, false, true},
{"wallet", "bip38encrypt", &bip38encrypt, true, false, true},
{"wallet", "bip38decrypt", &bip38decrypt, true, false, true},
{"wallet", "encryptwallet", &encryptwallet, true, false, true},
{"wallet", "getaccountaddress", &getaccountaddress, true, false, true},
{"wallet", "getaccount", &getaccount, true, false, true},
{"wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, false, true},
{"wallet", "getbalance", &getbalance, false, false, true},
{"wallet", "getnewaddress", &getnewaddress, true, false, true},
{"wallet", "getrawchangeaddress", &getrawchangeaddress, true, false, true},
{"wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, false, true},
{"wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, false, true},
{"wallet", "getstakingstatus", &getstakingstatus, false, false, true},
{"wallet", "getstakesplitthreshold", &getstakesplitthreshold, false, false, true},
{"wallet", "gettransaction", &gettransaction, false, false, true},
{"wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, false, true},
{"wallet", "getwalletinfo", &getwalletinfo, false, false, true},
{"wallet", "importprivkey", &importprivkey, true, false, true},
{"wallet", "importwallet", &importwallet, true, false, true},
{"wallet", "importaddress", &importaddress, true, false, true},
{"wallet", "keypoolrefill", &keypoolrefill, true, false, true},
{"wallet", "listaccounts", &listaccounts, false, false, true},
{"wallet", "listaddressgroupings", &listaddressgroupings, false, false, true},
{"wallet", "listlockunspent", &listlockunspent, false, false, true},
{"wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, false, true},
{"wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, false, true},
{"wallet", "listsinceblock", &listsinceblock, false, false, true},
{"wallet", "listtransactions", &listtransactions, false, false, true},
{"wallet", "listunspent", &listunspent, false, false, true},
{"wallet", "lockunspent", &lockunspent, true, false, true},
{"wallet", "move", &movecmd, false, false, true},
{"wallet", "multisend", &multisend, false, false, true},
{"wallet", "sendfrom", &sendfrom, false, false, true},
{"wallet", "sendmany", &sendmany, false, false, true},
{"wallet", "sendtoaddress", &sendtoaddress, false, false, true},
{"wallet", "sendtoaddressix", &sendtoaddressix, false, false, true},
{"wallet", "setaccount", &setaccount, true, false, true},
{"wallet", "setstakesplitthreshold", &setstakesplitthreshold, false, false, true},
{"wallet", "settxfee", &settxfee, true, false, true},
{"wallet", "signmessage", &signmessage, true, false, true},
{"wallet", "walletlock", &walletlock, true, false, true},
{"wallet", "walletpassphrasechange", &walletpassphrasechange, true, false, true},
{"wallet", "walletpassphrase", &walletpassphrase, true, false, true},
{"zerocoin", "createrawzerocoinstake", &createrawzerocoinstake, false, false, true},
{"zerocoin", "createrawzerocoinpublicspend", &createrawzerocoinpublicspend, false, false, true},
{"zerocoin", "getzerocoinbalance", &getzerocoinbalance, false, false, true},
{"zerocoin", "listmintedzerocoins", &listmintedzerocoins, false, false, true},
{"zerocoin", "listspentzerocoins", &listspentzerocoins, false, false, true},
{"zerocoin", "listzerocoinamounts", &listzerocoinamounts, false, false, true},
{"zerocoin", "mintzerocoin", &mintzerocoin, false, false, true},
{"zerocoin", "spendzerocoin", &spendzerocoin, false, false, true},
{"zerocoin", "spendrawzerocoin", &spendrawzerocoin, true, false, false},
{"zerocoin", "spendzerocoinmints", &spendzerocoinmints, false, false, true},
{"zerocoin", "resetmintzerocoin", &resetmintzerocoin, false, false, true},
{"zerocoin", "resetspentzerocoin", &resetspentzerocoin, false, false, true},
{"zerocoin", "getarchivedzerocoin", &getarchivedzerocoin, false, false, true},
{"zerocoin", "importzerocoins", &importzerocoins, false, false, true},
{"zerocoin", "exportzerocoins", &exportzerocoins, false, false, true},
{"zerocoin", "reconsiderzerocoins", &reconsiderzerocoins, false, false, true},
{"zerocoin", "getspentzerocoinamount", &getspentzerocoinamount, false, false, false},
{"zerocoin", "getzagrseed", &getzagrseed, false, false, true},
{"zerocoin", "setzagrseed", &setzagrseed, false, false, true},
{"zerocoin", "generatemintlist", &generatemintlist, false, false, true},
{"zerocoin", "searchdzagr", &searchdzagr, false, false, true},
{"zerocoin", "dzagrstate", &dzagrstate, false, false, true},
{"zerocoin", "clearspendcache", &clearspendcache, false, false, true}
#endif // ENABLE_WALLET
};
CRPCTable::CRPCTable()
{
unsigned int vcidx;
for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++) {
const CRPCCommand* pcmd;
pcmd = &vRPCCommands[vcidx];
mapCommands[pcmd->name] = pcmd;
}
}
const CRPCCommand *CRPCTable::operator[](const std::string &name) const
{
map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it == mapCommands.end())
return NULL;
return (*it).second;
}
bool StartRPC()
{
LogPrint("rpc", "Starting RPC\n");
fRPCRunning = true;
g_rpcSignals.Started();
return true;
}
void InterruptRPC()
{
LogPrint("rpc", "Interrupting RPC\n");
// Interrupt e.g. running longpolls
fRPCRunning = false;
}
void StopRPC()
{
LogPrint("rpc", "Stopping RPC\n");
deadlineTimers.clear();
g_rpcSignals.Stopped();
}
bool IsRPCRunning()
{
return fRPCRunning;
}
void SetRPCWarmupStatus(const std::string& newStatus)
{
LOCK(cs_rpcWarmup);
rpcWarmupStatus = newStatus;
}
void SetRPCWarmupFinished()
{
LOCK(cs_rpcWarmup);
assert(fRPCInWarmup);
fRPCInWarmup = false;
}
bool RPCIsInWarmup(std::string* outStatus)
{
LOCK(cs_rpcWarmup);
if (outStatus)
*outStatus = rpcWarmupStatus;
return fRPCInWarmup;
}
void JSONRequest::parse(const UniValue& valRequest)
{
// Parse request
if (!valRequest.isObject())
throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
const UniValue& request = valRequest.get_obj();
// Parse id now so errors from here on will have the id
id = find_value(request, "id");
// Parse method
UniValue valMethod = find_value(request, "method");
if (valMethod.isNull())
throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
if (!valMethod.isStr())
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str();
if (strMethod != "getblocktemplate")
LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
// Parse params
UniValue valParams = find_value(request, "params");
if (valParams.isArray())
params = valParams.get_array();
else if (valParams.isNull())
params = UniValue(UniValue::VARR);
else
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
}
static UniValue JSONRPCExecOne(const UniValue& req)
{
UniValue rpc_result(UniValue::VOBJ);
JSONRequest jreq;
try {
jreq.parse(req);
UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
} catch (const UniValue& objError) {
rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
} catch (std::exception& e) {
rpc_result = JSONRPCReplyObj(NullUniValue,
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
}
return rpc_result;
}
std::string JSONRPCExecBatch(const UniValue& vReq)
{
UniValue ret(UniValue::VARR);
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
return ret.write() + "\n";
}
UniValue CRPCTable::execute(const std::string &strMethod, const UniValue &params) const
{
// Find method
const CRPCCommand* pcmd = tableRPC[strMethod];
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
g_rpcSignals.PreCommand(*pcmd);
try {
// Execute
return pcmd->actor(params, false);
} catch (std::exception& e) {
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
g_rpcSignals.PostCommand(*pcmd);
}
std::vector<std::string> CRPCTable::listCommands() const
{
std::vector<std::string> commandList;
typedef std::map<std::string, const CRPCCommand*> commandMap;
std::transform( mapCommands.begin(), mapCommands.end(),
std::back_inserter(commandList),
boost::bind(&commandMap::value_type::first,_1) );
return commandList;
}
std::string HelpExampleCli(string methodname, string args)
{
return "> agrarian-cli " + methodname + " " + args + "\n";
}
std::string HelpExampleRpc(string methodname, string args)
{
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
"\"method\": \"" +
methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:51335/\n";
}
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface)
{
if (!timerInterface)
timerInterface = iface;
}
void RPCSetTimerInterface(RPCTimerInterface *iface)
{
timerInterface = iface;
}
void RPCUnsetTimerInterface(RPCTimerInterface *iface)
{
if (timerInterface == iface)
timerInterface = NULL;
}
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds)
{
if (!timerInterface)
throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC");
deadlineTimers.erase(name);
LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
deadlineTimers.insert(std::make_pair(name, boost::shared_ptr<RPCTimerBase>(timerInterface->NewTimer(func, nSeconds*1000))));
}
const CRPCTable tableRPC;
+360
View File
@@ -0,0 +1,360 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Copyright (c) 2015-2019 The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_RPCSERVER_H
#define BITCOIN_RPCSERVER_H
#include "amount.h"
#include "zagr/zerocoin.h"
#include "rpc/protocol.h"
#include "uint256.h"
#include <list>
#include <map>
#include <stdint.h>
#include <string>
#include <boost/function.hpp>
#include <univalue.h>
class CRPCCommand;
namespace RPCServer
{
void OnStarted(boost::function<void ()> slot);
void OnStopped(boost::function<void ()> slot);
void OnPreCommand(boost::function<void (const CRPCCommand&)> slot);
void OnPostCommand(boost::function<void (const CRPCCommand&)> slot);
}
class CBlockIndex;
class CNetAddr;
class JSONRequest
{
public:
UniValue id;
std::string strMethod;
UniValue params;
JSONRequest() { id = NullUniValue; }
void parse(const UniValue& valRequest);
};
/** Query whether RPC is running */
bool IsRPCRunning();
/**
* Set the RPC warmup status. When this is done, all RPC calls will error out
* immediately with RPC_IN_WARMUP.
*/
void SetRPCWarmupStatus(const std::string& newStatus);
/* Mark warmup as done. RPC calls will be processed from now on. */
void SetRPCWarmupFinished();
/* returns the current warmup state. */
bool RPCIsInWarmup(std::string* statusOut);
/**
* Type-check arguments; throws JSONRPCError if wrong type given. Does not check that
* the right number of arguments are passed, just that any passed are the correct type.
* Use like: RPCTypeCheck(params, boost::assign::list_of(str_type)(int_type)(obj_type));
*/
void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
/**
* Check for expected keys/value types in an Object.
* Use like: RPCTypeCheckObj(object, boost::assign::map_list_of("name", str_type)("value", int_type));
*/
void RPCTypeCheckObj(const UniValue& o,
const std::map<std::string, UniValue::VType>& typesExpected, bool fAllowNull=false);
/** Opaque base class for timers returned by NewTimerFunc.
* This provides no methods at the moment, but makes sure that delete
* cleans up the whole state.
*/
class RPCTimerBase
{
public:
virtual ~RPCTimerBase() {}
};
/**
* RPC timer "driver".
*/
class RPCTimerInterface
{
public:
virtual ~RPCTimerInterface() {}
/** Implementation name */
virtual const char *Name() = 0;
/** Factory function for timers.
* RPC will call the function to create a timer that will call func in *millis* milliseconds.
* @note As the RPC mechanism is backend-neutral, it can use different implementations of timers.
* This is needed to cope with the case in which there is no HTTP server, but
* only GUI RPC console, and to break the dependency of pcserver on httprpc.
*/
virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0;
};
/** Set factory function for timers */
void RPCSetTimerInterface(RPCTimerInterface *iface);
/** Set factory function for timers, but only if unset */
void RPCSetTimerInterfaceIfUnset(RPCTimerInterface *iface);
/** Unset factory function for timers */
void RPCUnsetTimerInterface(RPCTimerInterface *iface);
/**
* Run func nSeconds from now.
* Overrides previous timer <name> (if any).
*/
void RPCRunLater(const std::string& name, boost::function<void(void)> func, int64_t nSeconds);
typedef UniValue(*rpcfn_type)(const UniValue& params, bool fHelp);
class CRPCCommand
{
public:
std::string category;
std::string name;
rpcfn_type actor;
bool okSafeMode;
bool threadSafe;
bool reqWallet;
};
/**
* Agrarian RPC command dispatcher.
*/
class CRPCTable
{
private:
std::map<std::string, const CRPCCommand*> mapCommands;
public:
CRPCTable();
const CRPCCommand* operator[](const std::string& name) const;
std::string help(std::string name) const;
/**
* Execute a method.
* @param method Method to execute
* @param params UniValue Array of arguments (JSON objects)
* @returns Result of the call.
* @throws an exception (UniValue) when an error happens.
*/
UniValue execute(const std::string &method, const UniValue &params) const;
/**
* Returns a list of registered commands
* @returns List of registered commands.
*/
std::vector<std::string> listCommands() const;
};
extern const CRPCTable tableRPC;
/**
* Utilities: convert hex-encoded Values
* (throws error if not hex).
*/
extern uint256 ParseHashV(const UniValue& v, std::string strName);
extern uint256 ParseHashO(const UniValue& o, std::string strKey);
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
extern int ParseInt(const UniValue& o, std::string strKey);
extern bool ParseBool(const UniValue& o, std::string strKey);
extern int64_t nWalletUnlockTime;
extern CAmount AmountFromValue(const UniValue& value);
extern UniValue ValueFromAmount(const CAmount& amount);
extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
extern std::string HelpRequiringPassphrase();
extern std::string HelpExampleCli(std::string methodname, std::string args);
extern std::string HelpExampleRpc(std::string methodname, std::string args);
extern void EnsureWalletIsUnlocked(bool fAllowAnonOnly = false);
extern UniValue DoZagrSpend(const CAmount nAmount, bool fMintChange, bool fMinimizeChange, vector<CZerocoinMint>& vMintsSelected, std::string address_str, bool isPublicSpend = true);
extern UniValue getconnectioncount(const UniValue& params, bool fHelp); // in rpc/net.cpp
extern UniValue getpeerinfo(const UniValue& params, bool fHelp);
extern UniValue ping(const UniValue& params, bool fHelp);
extern UniValue addnode(const UniValue& params, bool fHelp);
extern UniValue disconnectnode(const UniValue& params, bool fHelp);
extern UniValue getaddednodeinfo(const UniValue& params, bool fHelp);
extern UniValue getnettotals(const UniValue& params, bool fHelp);
extern UniValue setban(const UniValue& params, bool fHelp);
extern UniValue listbanned(const UniValue& params, bool fHelp);
extern UniValue clearbanned(const UniValue& params, bool fHelp);
extern UniValue dumpprivkey(const UniValue& params, bool fHelp); // in rpcdump.cpp
extern UniValue importprivkey(const UniValue& params, bool fHelp);
extern UniValue importaddress(const UniValue& params, bool fHelp);
extern UniValue dumpwallet(const UniValue& params, bool fHelp);
extern UniValue importwallet(const UniValue& params, bool fHelp);
extern UniValue bip38encrypt(const UniValue& params, bool fHelp);
extern UniValue bip38decrypt(const UniValue& params, bool fHelp);
extern UniValue getgenerate(const UniValue& params, bool fHelp); // in rpc/mining.cpp
extern UniValue setgenerate(const UniValue& params, bool fHelp);
extern UniValue generate(const UniValue& params, bool fHelp);
extern UniValue getnetworkhashps(const UniValue& params, bool fHelp);
extern UniValue gethashespersec(const UniValue& params, bool fHelp);
extern UniValue getmininginfo(const UniValue& params, bool fHelp);
extern UniValue prioritisetransaction(const UniValue& params, bool fHelp);
extern UniValue getblocktemplate(const UniValue& params, bool fHelp);
extern UniValue submitblock(const UniValue& params, bool fHelp);
extern UniValue estimatefee(const UniValue& params, bool fHelp);
extern UniValue estimatepriority(const UniValue& params, bool fHelp);
extern UniValue getnewaddress(const UniValue& params, bool fHelp); // in rpcwallet.cpp
extern UniValue getaccountaddress(const UniValue& params, bool fHelp);
extern UniValue getrawchangeaddress(const UniValue& params, bool fHelp);
extern UniValue setaccount(const UniValue& params, bool fHelp);
extern UniValue getaccount(const UniValue& params, bool fHelp);
extern UniValue getaddressesbyaccount(const UniValue& params, bool fHelp);
extern UniValue sendtoaddress(const UniValue& params, bool fHelp);
extern UniValue sendtoaddressix(const UniValue& params, bool fHelp);
extern UniValue signmessage(const UniValue& params, bool fHelp);
extern UniValue getreceivedbyaddress(const UniValue& params, bool fHelp);
extern UniValue getreceivedbyaccount(const UniValue& params, bool fHelp);
extern UniValue getbalance(const UniValue& params, bool fHelp);
extern UniValue getunconfirmedbalance(const UniValue& params, bool fHelp);
extern UniValue movecmd(const UniValue& params, bool fHelp);
extern UniValue sendfrom(const UniValue& params, bool fHelp);
extern UniValue sendmany(const UniValue& params, bool fHelp);
extern UniValue addmultisigaddress(const UniValue& params, bool fHelp);
extern UniValue listreceivedbyaddress(const UniValue& params, bool fHelp);
extern UniValue listreceivedbyaccount(const UniValue& params, bool fHelp);
extern UniValue listtransactions(const UniValue& params, bool fHelp);
extern UniValue listaddressgroupings(const UniValue& params, bool fHelp);
extern UniValue listaccounts(const UniValue& params, bool fHelp);
extern UniValue listsinceblock(const UniValue& params, bool fHelp);
extern UniValue gettransaction(const UniValue& params, bool fHelp);
extern UniValue backupwallet(const UniValue& params, bool fHelp);
extern UniValue keypoolrefill(const UniValue& params, bool fHelp);
extern UniValue walletpassphrase(const UniValue& params, bool fHelp);
extern UniValue walletpassphrasechange(const UniValue& params, bool fHelp);
extern UniValue walletlock(const UniValue& params, bool fHelp);
extern UniValue encryptwallet(const UniValue& params, bool fHelp);
extern UniValue getwalletinfo(const UniValue& params, bool fHelp);
extern UniValue getblockchaininfo(const UniValue& params, bool fHelp);
extern UniValue getnetworkinfo(const UniValue& params, bool fHelp);
extern UniValue reservebalance(const UniValue& params, bool fHelp);
extern UniValue setstakesplitthreshold(const UniValue& params, bool fHelp);
extern UniValue getstakesplitthreshold(const UniValue& params, bool fHelp);
extern UniValue multisend(const UniValue& params, bool fHelp);
extern UniValue autocombinerewards(const UniValue& params, bool fHelp);
extern UniValue getzerocoinbalance(const UniValue& params, bool fHelp);
extern UniValue listmintedzerocoins(const UniValue& params, bool fHelp);
extern UniValue listspentzerocoins(const UniValue& params, bool fHelp);
extern UniValue listzerocoinamounts(const UniValue& params, bool fHelp);
extern UniValue mintzerocoin(const UniValue& params, bool fHelp);
extern UniValue spendzerocoin(const UniValue& params, bool fHelp);
extern UniValue spendrawzerocoin(const UniValue& params, bool fHelp);
extern UniValue spendzerocoinmints(const UniValue& params, bool fHelp);
extern UniValue resetmintzerocoin(const UniValue& params, bool fHelp);
extern UniValue resetspentzerocoin(const UniValue& params, bool fHelp);
extern UniValue getarchivedzerocoin(const UniValue& params, bool fHelp);
extern UniValue importzerocoins(const UniValue& params, bool fHelp);
extern UniValue exportzerocoins(const UniValue& params, bool fHelp);
extern UniValue reconsiderzerocoins(const UniValue& params, bool fHelp);
extern UniValue getspentzerocoinamount(const UniValue& params, bool fHelp);
extern UniValue setzagrseed(const UniValue& params, bool fHelp);
extern UniValue getzagrseed(const UniValue& params, bool fHelp);
extern UniValue generatemintlist(const UniValue& params, bool fHelp);
extern UniValue searchdzagr(const UniValue& params, bool fHelp);
extern UniValue dzagrstate(const UniValue& params, bool fHelp);
extern UniValue clearspendcache(const UniValue& params, bool fHelp);
extern UniValue enableautomintaddress(const UniValue& params, bool fHelp);
extern UniValue createautomintaddress(const UniValue& params, bool fHelp);
extern UniValue getrawtransaction(const UniValue& params, bool fHelp); // in rpc/rawtransaction.cpp
extern UniValue listunspent(const UniValue& params, bool fHelp);
extern UniValue lockunspent(const UniValue& params, bool fHelp);
extern UniValue listlockunspent(const UniValue& params, bool fHelp);
extern UniValue createrawtransaction(const UniValue& params, bool fHelp);
extern UniValue decoderawtransaction(const UniValue& params, bool fHelp);
extern UniValue decodescript(const UniValue& params, bool fHelp);
extern UniValue signrawtransaction(const UniValue& params, bool fHelp);
extern UniValue sendrawtransaction(const UniValue& params, bool fHelp);
extern UniValue createrawzerocoinstake(const UniValue& params, bool fHelp);
extern UniValue createrawzerocoinpublicspend(const UniValue& params, bool fHelp);
extern UniValue findserial(const UniValue& params, bool fHelp); // in rpc/blockchain.cpp
extern UniValue getblockcount(const UniValue& params, bool fHelp);
extern UniValue getbestblockhash(const UniValue& params, bool fHelp);
extern UniValue waitfornewblock(const UniValue& params, bool fHelp);
extern UniValue waitforblock(const UniValue& params, bool fHelp);
extern UniValue waitforblockheight(const UniValue& params, bool fHelp);
extern UniValue getdifficulty(const UniValue& params, bool fHelp);
extern UniValue settxfee(const UniValue& params, bool fHelp);
extern UniValue getmempoolinfo(const UniValue& params, bool fHelp);
extern UniValue getrawmempool(const UniValue& params, bool fHelp);
extern UniValue getblockhash(const UniValue& params, bool fHelp);
extern UniValue getblock(const UniValue& params, bool fHelp);
extern UniValue getblockheader(const UniValue& params, bool fHelp);
extern UniValue getfeeinfo(const UniValue& params, bool fHelp);
extern UniValue gettxoutsetinfo(const UniValue& params, bool fHelp);
extern UniValue gettxout(const UniValue& params, bool fHelp);
extern UniValue verifychain(const UniValue& params, bool fHelp);
extern UniValue getchaintips(const UniValue& params, bool fHelp);
extern UniValue invalidateblock(const UniValue& params, bool fHelp);
extern UniValue reconsiderblock(const UniValue& params, bool fHelp);
extern UniValue getaccumulatorvalues(const UniValue& params, bool fHelp);
extern UniValue getaccumulatorwitness(const UniValue& params, bool fHelp);
extern UniValue getblockindexstats(const UniValue& params, bool fHelp);
extern UniValue getmintsinblocks(const UniValue& params, bool fHelp);
extern UniValue getserials(const UniValue& params, bool fHelp);
extern UniValue getchecksumblock(const UniValue& params, bool fHelp);
extern void validaterange(const UniValue& params, int& heightStart, int& heightEnd, int minHeightStart=1);
extern UniValue getpoolinfo(const UniValue& params, bool fHelp); // in rpc/masternode.cpp
extern UniValue listmasternodes(const UniValue& params, bool fHelp);
extern UniValue getmasternodecount(const UniValue& params, bool fHelp);
extern UniValue createmasternodebroadcast(const UniValue& params, bool fHelp);
extern UniValue decodemasternodebroadcast(const UniValue& params, bool fHelp);
extern UniValue relaymasternodebroadcast(const UniValue& params, bool fHelp);
extern UniValue masternodeconnect(const UniValue& params, bool fHelp);
extern UniValue masternodecurrent(const UniValue& params, bool fHelp);
extern UniValue masternodedebug(const UniValue& params, bool fHelp);
extern UniValue startmasternode(const UniValue& params, bool fHelp);
extern UniValue createmasternodekey(const UniValue& params, bool fHelp);
extern UniValue getmasternodeoutputs(const UniValue& params, bool fHelp);
extern UniValue listmasternodeconf(const UniValue& params, bool fHelp);
extern UniValue getmasternodestatus(const UniValue& params, bool fHelp);
extern UniValue getmasternodewinners(const UniValue& params, bool fHelp);
extern UniValue getmasternodescores(const UniValue& params, bool fHelp);
extern UniValue preparebudget(const UniValue& params, bool fHelp); // in rpc/budget.cpp
extern UniValue submitbudget(const UniValue& params, bool fHelp);
extern UniValue mnbudgetvote(const UniValue& params, bool fHelp);
extern UniValue getbudgetvotes(const UniValue& params, bool fHelp);
extern UniValue getnextsuperblock(const UniValue& params, bool fHelp);
extern UniValue getbudgetprojection(const UniValue& params, bool fHelp);
extern UniValue getbudgetinfo(const UniValue& params, bool fHelp);
extern UniValue mnbudgetrawvote(const UniValue& params, bool fHelp);
extern UniValue mnfinalbudget(const UniValue& params, bool fHelp);
extern UniValue checkbudgets(const UniValue& params, bool fHelp);
extern UniValue getinfo(const UniValue& params, bool fHelp); // in rpc/misc.cpp
extern UniValue mnsync(const UniValue& params, bool fHelp);
extern UniValue spork(const UniValue& params, bool fHelp);
extern UniValue validateaddress(const UniValue& params, bool fHelp);
extern UniValue createmultisig(const UniValue& params, bool fHelp);
extern UniValue verifymessage(const UniValue& params, bool fHelp);
extern UniValue setmocktime(const UniValue& params, bool fHelp);
extern UniValue getstakingstatus(const UniValue& params, bool fHelp);
bool StartRPC();
void InterruptRPC();
void StopRPC();
std::string JSONRPCExecBatch(const UniValue& vReq);
void RPCNotifyBlockChange(const uint256 nHeight);
#endif // BITCOIN_RPCSERVER_H