r1
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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 ¶ms) 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;
|
||||
@@ -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 ¶ms) 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
|
||||
Reference in New Issue
Block a user