Merge pull request #4708 from kittywhiskers/json_cleanup

merge bitcoin 15746, 16240, 17192, 17318, 17809, 18098, 18444, 18607, 19100, 19386: rpc backports
This commit is contained in:
UdjinM6 2022-03-15 12:08:35 +03:00 committed by GitHub
commit f1a64744cd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 2215 additions and 2028 deletions

View File

@ -257,9 +257,10 @@ BITCOIN_CORE_H = \
rpc/client.h \
rpc/mining.h \
rpc/protocol.h \
rpc/server.h \
rpc/rawtransaction_util.h \
rpc/register.h \
rpc/request.h \
rpc/server.h \
rpc/util.h \
saltedhasher.h \
scheduler.h \
@ -292,6 +293,7 @@ BITCOIN_CORE_H = \
unordered_lru_cache.h \
util/bip32.h \
util/bytevectorhash.h \
util/check.h \
util/error.h \
util/fees.h \
util/spanparsing.h \
@ -678,7 +680,7 @@ libdash_util_a_SOURCES = \
interfaces/handler.cpp \
logging.cpp \
random.cpp \
rpc/protocol.cpp \
rpc/request.cpp \
stacktraces.cpp \
support/cleanse.cpp \
sync.cpp \

View File

@ -12,6 +12,7 @@
#include <clientversion.h>
#include <rpc/client.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <stacktraces.h>
#include <util/system.h>
#include <util/strencodings.h>

View File

@ -11,6 +11,7 @@
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <rpc/blockchain.h>
#include <rpc/protocol.h>
#include <rpc/server.h>
#include <streams.h>
#include <sync.h>

View File

@ -11,12 +11,12 @@
#include <chain.h>
#include <chainparams.h>
#include <coins.h>
#include <node/coinstats.h>
#include <core_io.h>
#include <consensus/validation.h>
#include <index/blockfilterindex.h>
#include <key_io.h>
#include <index/txindex.h>
#include <key_io.h>
#include <node/coinstats.h>
#include <policy/feerate.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
@ -40,7 +40,6 @@
#include <llmq/chainlocks.h>
#include <llmq/instantsend.h>
#include <assert.h>
#include <stdint.h>
#include <univalue.h>
@ -67,7 +66,7 @@ extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
*/
double GetDifficulty(const CBlockIndex* blockindex)
{
assert(blockindex);
CHECK_NONFATAL(blockindex);
int nShift = (blockindex->nBits >> 24) & 0xff;
double dDiff =
@ -190,8 +189,7 @@ static UniValue getblockcount(const JSONRPCRequest& request)
"The genesis block has height 0.\n",
{},
RPCResult{
"n (numeric) The current block count\n"
},
RPCResult::Type::NUM, "", "The current block count"},
RPCExamples{
HelpExampleCli("getblockcount", "")
+ HelpExampleRpc("getblockcount", "")
@ -210,8 +208,7 @@ static UniValue getbestblockhash(const JSONRPCRequest& request)
"\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n",
{},
RPCResult{
"\"hex\" (string) the block hash, hex-encoded\n"
},
RPCResult::Type::STR_HEX, "", "the block hash, hex-encoded"},
RPCExamples{
HelpExampleCli("getbestblockhash", "")
+ HelpExampleRpc("getbestblockhash", "")
@ -278,11 +275,11 @@ static UniValue waitfornewblock(const JSONRPCRequest& request)
{"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
},
RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
},
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "hash", "The blockhash"},
{RPCResult::Type::NUM, "height", "Block height"},
}},
RPCExamples{
HelpExampleCli("waitfornewblock", "1000")
+ HelpExampleRpc("waitfornewblock", "1000")
@ -320,11 +317,11 @@ static UniValue waitforblock(const JSONRPCRequest& request)
{"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
},
RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
},
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "hash", "The blockhash"},
{RPCResult::Type::NUM, "height", "Block height"},
}},
RPCExamples{
HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000")
+ HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000")
@ -366,11 +363,11 @@ static UniValue waitforblockheight(const JSONRPCRequest& request)
{"timeout", RPCArg::Type::NUM, /* default */ "0", "Time in milliseconds to wait for a response. 0 indicates no timeout."},
},
RPCResult{
"{ (json object)\n"
" \"hash\" : { (string) The blockhash\n"
" \"height\" : { (int) Block height\n"
"}\n"
},
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "hash", "The blockhash"},
{RPCResult::Type::NUM, "height", "Block height"},
}},
RPCExamples{
HelpExampleCli("waitforblockheight", "100 1000")
+ HelpExampleRpc("waitforblockheight", "100, 1000")
@ -425,8 +422,7 @@ static UniValue getdifficulty(const JSONRPCRequest& request)
"\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
{},
RPCResult{
"n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n"
},
RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
RPCExamples{
HelpExampleCli("getdifficulty", "")
+ HelpExampleRpc("getdifficulty", "")
@ -458,10 +454,10 @@ static std::string EntryDescriptionString()
" \"ancestor\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one) in " + CURRENCY_UNIT + "\n"
" \"descendant\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one) in " + CURRENCY_UNIT + "\n"
" }\n"
" \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n"
" \"depends\" : [ (json array) unconfirmed transactions used as inputs for this transaction\n"
" \"transactionid\", (string) parent transaction id\n"
" ... ],\n"
" \"spentby\" : [ (array) unconfirmed transactions spending outputs from this transaction\n"
" \"spentby\" : [ (json array) unconfirmed transactions spending outputs from this transaction\n"
" \"transactionid\", (string) child transaction id\n"
" ... ]\n"
" \"instantlock\" : true|false (boolean) True if this transaction was locked via InstantSend\n";
@ -802,8 +798,7 @@ static UniValue getblockhash(const JSONRPCRequest& request)
{"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"},
},
RPCResult{
"\"hash\" (string) The block hash\n"
},
RPCResult::Type::STR_HEX, "", "The block hash"},
RPCExamples{
HelpExampleCli("getblockhash", "1000")
+ HelpExampleRpc("getblockhash", "1000")
@ -1093,12 +1088,11 @@ static UniValue getblock(const JSONRPCRequest& request)
"If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n",
{
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
{"verbosity", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
{"verbosity|verbose", RPCArg::Type::NUM, /* default */ "1", "0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data"},
},
{
RPCResult{"for verbosity = 0",
"\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
},
RPCResult::Type::STR_HEX, "", "A string that is serialized, hex-encoded data for block 'hash'"},
RPCResult{"for verbosity = 1",
"{\n"
" \"hash\" : \"hash\", (string) the block hash (same as provided)\n"
@ -1186,8 +1180,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
" to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
},
RPCResult{
"n (numeric) Height of the last block pruned.\n"
},
RPCResult::Type::NUM, "", "Height of the last block pruned"},
RPCExamples{
HelpExampleCli("pruneblockchain", "1000")
+ HelpExampleRpc("pruneblockchain", "1000")
@ -1227,7 +1220,7 @@ static UniValue pruneblockchain(const JSONRPCRequest& request)
PruneBlockFilesManual(height);
const CBlockIndex* block = ::ChainActive().Tip();
assert(block);
CHECK_NONFATAL(block);
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
block = block->pprev;
}
@ -1243,17 +1236,17 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request)
"Note this call may take some time.\n",
{},
RPCResult{
"{\n"
" \"height\":n, (numeric) The current block height (index)\n"
" \"bestblock\": \"hex\", (string) The hash of the block at the tip of the chain\n"
" \"transactions\": n, (numeric) The number of transactions with unspent outputs\n"
" \"txouts\": n, (numeric) The number of unspent transaction outputs\n"
" \"bogosize\": n, (numeric) A meaningless metric for UTXO set size\n"
" \"hash_serialized_2\": \"hash\", (string) The serialized hash\n"
" \"disk_size\": n, (numeric) The estimated size of the chainstate on disk\n"
" \"total_amount\": x.xxx (numeric) The total amount\n"
"}\n"
},
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "height", "The current block height (index)"},
{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
{RPCResult::Type::NUM, "transactions", "The number of transactions with unspent outputs"},
{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs"},
{RPCResult::Type::NUM, "bogosize", "A meaningless metric for UTXO set size"},
{RPCResult::Type::STR_HEX, "hash_serialized_2", "The serialized hash"},
{RPCResult::Type::NUM, "disk_size", "The estimated size of the chainstate on disk"},
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount"},
}},
RPCExamples{
HelpExampleCli("gettxoutsetinfo", "")
+ HelpExampleRpc("gettxoutsetinfo", "")
@ -1294,7 +1287,7 @@ static UniValue gettxout(const JSONRPCRequest& request)
},
RPCResult{
"{\n"
" \"bestblock\": \"hash\", (string) The hash of the block at the tip of the chain\n"
" \"bestblock\" : \"hash\", (string) The hash of the block at the tip of the chain\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
" \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n"
" \"scriptPubKey\" : { (json object)\n"
@ -1376,8 +1369,7 @@ static UniValue verifychain(const JSONRPCRequest& request)
{"nblocks", RPCArg::Type::NUM, /* default */ strprintf("%d, 0=all", nCheckDepth), "The number of blocks to check."},
},
RPCResult{
"true|false (boolean) Verified or not\n"
},
RPCResult::Type::BOOL, "", "Verified or not"},
RPCExamples{
HelpExampleCli("verifychain", "")
+ HelpExampleRpc("verifychain", "")
@ -1475,43 +1467,43 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest) and\n"
" \"chain\" : \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest) and\n"
" devnet or devnet-<name> for \"-devnet\" and \"-devnet=<name>\" respectively\n"
" \"blocks\": xxxxxx, (numeric) the height of the most-work fully-validated chain. The genesis block has height 0\n"
" \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n"
" \"bestblockhash\": \"...\", (string) the hash of the currently best block\n"
" \"difficulty\": xxxxxx, (numeric) the current difficulty\n"
" \"mediantime\": xxxxxx, (numeric) median time for the current best block\n"
" \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"initialblockdownload\": xxxx, (bool) (debug information) estimate of whether this node is in Initial Block Download mode.\n"
" \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
" \"size_on_disk\": xxxxxx, (numeric) the estimated size of the block and undo files on disk\n"
" \"pruned\": xx, (boolean) if the blocks are subject to pruning\n"
" \"pruneheight\": xxxxxx, (numeric) lowest-height complete block stored (only present if pruning is enabled)\n"
" \"automatic_pruning\": xx, (boolean) whether automatic pruning is enabled (only present if pruning is enabled)\n"
" \"prune_target_size\": xxxxxx, (numeric) the target size used by pruning (only present if automatic pruning is enabled)\n"
" \"softforks\": [ (array) status of softforks in progress\n"
" \"blocks\" : xxxxxx, (numeric) the height of the most-work fully-validated chain. The genesis block has height 0\n"
" \"headers\" : xxxxxx, (numeric) the current number of headers we have validated\n"
" \"bestblockhash\" : \"...\", (string) the hash of the currently best block\n"
" \"difficulty\" : xxxxxx, (numeric) the current difficulty\n"
" \"mediantime\" : xxxxxx, (numeric) median time for the current best block\n"
" \"verificationprogress\" : xxxx, (numeric) estimate of verification progress [0..1]\n"
" \"initialblockdownload\" : xxxx, (boolean) (debug information) estimate of whether this node is in Initial Block Download mode.\n"
" \"chainwork\" : \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n"
" \"size_on_disk\" : xxxxxx, (numeric) the estimated size of the block and undo files on disk\n"
" \"pruned\" : xx, (boolean) if the blocks are subject to pruning\n"
" \"pruneheight\" : xxxxxx, (numeric) lowest-height complete block stored (only present if pruning is enabled)\n"
" \"automatic_pruning\" : xx, (boolean) whether automatic pruning is enabled (only present if pruning is enabled)\n"
" \"prune_target_size\" : xxxxxx, (numeric) the target size used by pruning (only present if automatic pruning is enabled)\n"
" \"softforks\" : [ (json array) status of softforks in progress\n"
" {\n"
" \"id\": \"xxxx\", (string) name of softfork\n"
" \"version\": xx, (numeric) block version\n"
" \"reject\": { (object) progress toward rejecting pre-softfork blocks\n"
" \"status\": xx, (boolean) true if threshold reached\n"
" \"id\" : \"xxxx\", (string) name of softfork\n"
" \"version\" : xx, (numeric) block version\n"
" \"reject\" : { (json object) progress toward rejecting pre-softfork blocks\n"
" \"status\" : xx, (boolean) true if threshold reached\n"
" },\n"
" }, ...\n"
" ],\n"
" \"bip9_softforks\": { (object) status of BIP9 softforks in progress\n"
" \"bip9_softforks\": { (json object) status of BIP9 softforks in progress\n"
" \"xxxx\" : { (string) name of the softfork\n"
" \"status\": \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
" \"bit\": xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
" \"start_time\": xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
" \"timeout\": xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
" \"since\": xx, (numeric) height of the first block to which the status applies\n"
" \"statistics\": { (object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
" \"period\": xx, (numeric) the length in blocks of the BIP9 signalling period \n"
" \"threshold\": xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
" \"elapsed\": xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
" \"count\": xx, (numeric) the number of blocks with the version bit set in the current period \n"
" \"possible\": xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
" \"status\" : \"xxxx\", (string) one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\"\n"
" \"bit\" : xx, (numeric) the bit (0-28) in the block version field used to signal this softfork (only for \"started\" status)\n"
" \"start_time\" : xx, (numeric) the minimum median time past of a block at which the bit gains its meaning\n"
" \"timeout\" : xx, (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in\n"
" \"since\" : xx, (numeric) height of the first block to which the status applies\n"
" \"statistics\" : { (json object) numeric statistics about BIP9 signalling for a softfork (only for \"started\" status)\n"
" \"period\" : xx, (numeric) the length in blocks of the BIP9 signalling period \n"
" \"threshold\" : xx, (numeric) the number of blocks with the version bit set required to activate the feature \n"
" \"elapsed\" : xx, (numeric) the number of blocks elapsed since the beginning of the current period \n"
" \"count\" : xx, (numeric) the number of blocks with the version bit set in the current period \n"
" \"possible\" : xx (boolean) returns false if there are not enough blocks left in this period to pass activation threshold \n"
" }\n"
" }\n"
" }\n"
@ -1543,7 +1535,7 @@ UniValue getblockchaininfo(const JSONRPCRequest& request)
obj.pushKV("pruned", fPruneMode);
if (fPruneMode) {
const CBlockIndex* block = tip;
assert(block);
CHECK_NONFATAL(block);
while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
block = block->pprev;
}
@ -1604,22 +1596,22 @@ static UniValue getchaintips(const JSONRPCRequest& request)
RPCResult{
"[\n"
" {\n"
" \"height\": xxxx, (numeric) height of the chain tip\n"
" \"hash\": \"xxxx\", (string) block hash of the tip\n"
" \"height\" : xxxx, (numeric) height of the chain tip\n"
" \"hash\" : \"xxxx\", (string) block hash of the tip\n"
" \"difficulty\" : x.xxx, (numeric) The difficulty\n"
" \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n"
" \"branchlen\": 0 (numeric) zero for main chain\n"
" \"forkpoint\": \"xxxx\", (string) same as \"hash\" for the main chain\n"
" \"status\": \"active\" (string) \"active\" for the main chain\n"
" \"branchlen\" : 0 (numeric) zero for main chain\n"
" \"forkpoint\" : \"xxxx\", (string) same as \"hash\" for the main chain\n"
" \"status\" : \"active\" (string) \"active\" for the main chain\n"
" },\n"
" {\n"
" \"height\": xxxx,\n"
" \"hash\": \"xxxx\",\n"
" \"height\" : xxxx,\n"
" \"hash\" : \"xxxx\",\n"
" \"difficulty\" : x.xxx,\n"
" \"chainwork\" : \"0000...1f3\"\n"
" \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n"
" \"forkpoint\": \"xxxx\", (string) block hash of the last common block between this tip and the main chain\n"
" \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
" \"branchlen\" : 1 (numeric) length of branch connecting the tip to the main chain\n"
" \"forkpoint\" : \"xxxx\", (string) block hash of the last common block between this tip and the main chain\n"
" \"status\" : \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n"
" }\n"
"]\n"
"Possible values for status:\n"
@ -1751,14 +1743,14 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
" \"loaded\": true|false (boolean) True if the mempool is fully loaded\n"
" \"size\": xxxxx, (numeric) Current tx count\n"
" \"bytes\": xxxxx, (numeric) Sum of all tx sizes\n"
" \"usage\": xxxxx, (numeric) Total memory usage for the mempool\n"
" \"maxmempool\": xxxxx, (numeric) Maximum memory usage for the mempool\n"
" \"mempoolminfee\": xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee\n"
" \"minrelaytxfee\": xxxxx (numeric) Current minimum relay fee for transactions\n"
" \"instantsendlocks\": xxxxx, (numeric) Number of unconfirmed instant send locks\n"
" \"loaded\" : true|false (boolean) True if the mempool is fully loaded\n"
" \"size\" : xxxxx, (numeric) Current tx count\n"
" \"bytes\" : xxxxx, (numeric) Sum of all tx sizes\n"
" \"usage\" : xxxxx, (numeric) Total memory usage for the mempool\n"
" \"maxmempool\" : xxxxx, (numeric) Maximum memory usage for the mempool\n"
" \"mempoolminfee\" : xxxxx (numeric) Minimum fee rate in " + CURRENCY_UNIT + "/kB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee\n"
" \"minrelaytxfee\" : xxxxx (numeric) Current minimum relay fee for transactions\n"
" \"instantsendlocks\" : xxxxx, (numeric) Number of unconfirmed instant send locks\n"
"}\n"
},
RPCExamples{
@ -1903,14 +1895,14 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
},
RPCResult{
"{\n"
" \"time\": xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
" \"txcount\": xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
" \"window_final_block_hash\": \"...\", (string) The hash of the final block in the window.\n"
" \"window_final_block_height\": xxxxx, (numeric) The height of the final block in the window.\n"
" \"window_block_count\": xxxxx, (numeric) Size of the window in number of blocks.\n"
" \"window_tx_count\": xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n"
" \"window_interval\": xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n"
" \"txrate\": x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n"
" \"time\" : xxxxx, (numeric) The timestamp for the final block in the window in UNIX format.\n"
" \"txcount\" : xxxxx, (numeric) The total number of transactions in the chain up to that point.\n"
" \"window_final_block_hash\" : \"...\", (string) The hash of the final block in the window.\n"
" \"window_final_block_height\" : xxxxx, (numeric) The height of the final block in the window.\n"
" \"window_block_count\" : xxxxx, (numeric) Size of the window in number of blocks.\n"
" \"window_tx_count\" : xxxxx, (numeric) The number of transactions in the window. Only returned if \"window_block_count\" is > 0.\n"
" \"window_interval\" : xxxxx, (numeric) The elapsed time in the window in seconds. Only returned if \"window_block_count\" is > 0.\n"
" \"txrate\" : x.xx, (numeric) The average rate of transactions per second in the window. Only returned if \"window_interval\" is > 0.\n"
"}\n"
},
RPCExamples{
@ -1937,7 +1929,7 @@ static UniValue getchaintxstats(const JSONRPCRequest& request)
}
}
assert(pindex != nullptr);
CHECK_NONFATAL(pindex != nullptr);
if (request.params[0].isNull()) {
blockcount = std::max(0, std::min(blockcount, pindex->nHeight - 1));
@ -2043,37 +2035,37 @@ static UniValue getblockstats(const JSONRPCRequest& request)
},
RPCResult{
"{ (json object)\n"
" \"avgfee\": xxxxx, (numeric) Average fee in the block\n"
" \"avgfeerate\": xxxxx, (numeric) Average feerate (in duffs per byte)\n"
" \"avgtxsize\": xxxxx, (numeric) Average transaction size\n"
" \"blockhash\": xxxxx, (string) The block hash (to check for potential reorgs)\n"
" \"feerate_percentiles\": [ (array of numeric) Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in duffs per byte)\n"
" \"avgfee\" : xxxxx, (numeric) Average fee in the block\n"
" \"avgfeerate\" : xxxxx, (numeric) Average feerate (in duffs per byte)\n"
" \"avgtxsize\" : xxxxx, (numeric) Average transaction size\n"
" \"blockhash\" : xxxxx, (string) The block hash (to check for potential reorgs)\n"
" \"feerate_percentiles\" : [ (array of numeric) Feerates at the 10th, 25th, 50th, 75th, and 90th percentile weight unit (in duffs per byte)\n"
" \"10th_percentile_feerate\", (numeric) The 10th percentile feerate\n"
" \"25th_percentile_feerate\", (numeric) The 25th percentile feerate\n"
" \"50th_percentile_feerate\", (numeric) The 50th percentile feerate\n"
" \"75th_percentile_feerate\", (numeric) The 75th percentile feerate\n"
" \"90th_percentile_feerate\", (numeric) The 90th percentile feerate\n"
" ],\n"
" \"height\": xxxxx, (numeric) The height of the block\n"
" \"ins\": xxxxx, (numeric) The number of inputs (excluding coinbase)\n"
" \"maxfee\": xxxxx, (numeric) Maximum fee in the block\n"
" \"maxfeerate\": xxxxx, (numeric) Maximum feerate (in duffs per byte)\n"
" \"maxtxsize\": xxxxx, (numeric) Maximum transaction size\n"
" \"medianfee\": xxxxx, (numeric) Truncated median fee in the block\n"
" \"mediantime\": xxxxx, (numeric) The block median time past\n"
" \"mediantxsize\": xxxxx, (numeric) Truncated median transaction size\n"
" \"minfee\": xxxxx, (numeric) Minimum fee in the block\n"
" \"minfeerate\": xxxxx, (numeric) Minimum feerate (in duffs per byte)\n"
" \"mintxsize\": xxxxx, (numeric) Minimum transaction size\n"
" \"outs\": xxxxx, (numeric) The number of outputs\n"
" \"subsidy\": xxxxx, (numeric) The block subsidy\n"
" \"time\": xxxxx, (numeric) The block time\n"
" \"total_out\": xxxxx, (numeric) Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])\n"
" \"total_size\": xxxxx, (numeric) Total size of all non-coinbase transactions\n"
" \"totalfee\": xxxxx, (numeric) The fee total\n"
" \"txs\": xxxxx, (numeric) The number of transactions (excluding coinbase)\n"
" \"utxo_increase\": xxxxx, (numeric) The increase/decrease in the number of unspent outputs\n"
" \"utxo_size_inc\": xxxxx, (numeric) The increase/decrease in size for the utxo index (not discounting op_return and similar)\n"
" \"height\" : xxxxx, (numeric) The height of the block\n"
" \"ins\" : xxxxx, (numeric) The number of inputs (excluding coinbase)\n"
" \"maxfee\" : xxxxx, (numeric) Maximum fee in the block\n"
" \"maxfeerate\" : xxxxx, (numeric) Maximum feerate (in duffs per byte)\n"
" \"maxtxsize\" : xxxxx, (numeric) Maximum transaction size\n"
" \"medianfee\" : xxxxx, (numeric) Truncated median fee in the block\n"
" \"mediantime\" : xxxxx, (numeric) The block median time past\n"
" \"mediantxsize\" : xxxxx, (numeric) Truncated median transaction size\n"
" \"minfee\" : xxxxx, (numeric) Minimum fee in the block\n"
" \"minfeerate\" : xxxxx, (numeric) Minimum feerate (in duffs per byte)\n"
" \"mintxsize\" : xxxxx, (numeric) Minimum transaction size\n"
" \"outs\" : xxxxx, (numeric) The number of outputs\n"
" \"subsidy\" : xxxxx, (numeric) The block subsidy\n"
" \"time\" : xxxxx, (numeric) The block time\n"
" \"total_out\" : xxxxx, (numeric) Total amount in all outputs (excluding coinbase and thus reward [ie subsidy + totalfee])\n"
" \"total_size\" : xxxxx, (numeric) Total size of all non-coinbase transactions\n"
" \"totalfee\" : xxxxx, (numeric) The fee total\n"
" \"txs\" : xxxxx, (numeric) The number of transactions (excluding coinbase)\n"
" \"utxo_increase\" : xxxxx, (numeric) The increase/decrease in the number of unspent outputs\n"
" \"utxo_size_inc\" : xxxxx, (numeric) The increase/decrease in size for the utxo index (not discounting op_return and similar)\n"
"}\n"
},
RPCExamples{
@ -2119,7 +2111,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
}
}
assert(pindex != nullptr);
CHECK_NONFATAL(pindex != nullptr);
std::set<std::string> stats;
if (!request.params[1].isNull()) {
@ -2208,7 +2200,7 @@ static UniValue getblockstats(const JSONRPCRequest& request)
}
CAmount txfee = tx_total_in - tx_total_out;
assert(MoneyRange(txfee));
CHECK_NONFATAL(MoneyRange(txfee));
if (do_medianfee) {
fee_array.push_back(txfee);
}
@ -2448,7 +2440,7 @@ public:
explicit CoinsViewScanReserver() : m_could_reserve(false) {}
bool reserve() {
assert (!m_could_reserve);
CHECK_NONFATAL(!m_could_reserve);
std::lock_guard<std::mutex> lock(g_utxosetscan);
if (g_scan_in_progress) {
return false;
@ -2503,24 +2495,26 @@ UniValue scantxoutset(const JSONRPCRequest& request)
"[scanobjects,...]"},
},
RPCResult{
"{\n"
" \"success\": true|false, (boolean) Whether the scan was completed\n"
" \"txouts\": n, (numeric) The number of unspent transaction outputs scanned\n"
" \"height\": n, (numeric) The current block height (index)\n"
" \"bestblock\": \"hex\", (string) The hash of the block at the tip of the chain\n"
" \"unspents\": [\n"
" {\n"
" \"txid\": \"hash\", (string) The transaction id\n"
" \"vout\": n, (numeric) The vout value\n"
" \"scriptPubKey\": \"script\", (string) The script key\n"
" \"desc\": \"descriptor\", (string) A specialized descriptor for the matched scriptPubKey\n"
" \"amount\": x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " of the unspent output\n"
" \"height\": n, (numeric) Height of the unspent transaction output\n"
" }\n"
" ,...],\n"
" \"total_amount\": x.xxx, (numeric) The total amount of all found unspent outputs in " + CURRENCY_UNIT + "\n"
"]\n"
},
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::BOOL, "success", "Whether the scan was completed"},
{RPCResult::Type::NUM, "txouts", "The number of unspent transaction outputs scanned"},
{RPCResult::Type::NUM, "height", "The current block height (index)"},
{RPCResult::Type::STR_HEX, "bestblock", "The hash of the block at the tip of the chain"},
{RPCResult::Type::ARR, "unspents", "",
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "txid", "The transaction id"},
{RPCResult::Type::NUM, "vout", "The vout value"},
{RPCResult::Type::STR_HEX, "scriptPubKey", "The script key"},
{RPCResult::Type::STR, "desc", "A specialized descriptor for the matched scriptPubKey"},
{RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " of the unspent output"},
{RPCResult::Type::NUM, "height", "Height of the unspent transaction output"},
}},
}},
{RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT},
}},
RPCExamples{""},
}.ToString()
);
@ -2613,9 +2607,9 @@ UniValue scantxoutset(const JSONRPCRequest& request)
LOCK(cs_main);
::ChainstateActive().ForceFlushStateToDisk();
pcursor = std::unique_ptr<CCoinsViewCursor>(::ChainstateActive().CoinsDB().Cursor());
assert(pcursor);
CHECK_NONFATAL(pcursor);
tip = ::ChainActive().Tip();
assert(tip);
CHECK_NONFATAL(tip);
}
bool res = FindScriptPubKey(g_scan_progress, g_should_abort_scan, count, pcursor.get(), needles, coins);
result.pushKV("success", res);

View File

@ -18,11 +18,6 @@
#ifdef ENABLE_WALLET
static UniValue coinjoin(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"coinjoin",
@ -37,6 +32,10 @@ static UniValue coinjoin(const JSONRPCRequest& request)
RPCExamples{""},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
if (fMasternodeMode)
throw JSONRPCError(RPC_INTERNAL_ERROR, "Client-side mixing is not supported on masternodes");
@ -103,36 +102,36 @@ static UniValue getcoinjoininfo(const JSONRPCRequest& request)
RPCResults{
{"for regular nodes",
"{\n"
" \"enabled\": true|false, (bool) Whether mixing functionality is enabled\n"
" \"multisession\": true|false, (bool) Whether CoinJoin Multisession option is enabled\n"
" \"max_sessions\": xxx, (numeric) How many parallel mixing sessions can there be at once\n"
" \"max_rounds\": xxx, (numeric) How many rounds to mix\n"
" \"max_amount\": xxx, (numeric) Target CoinJoin balance in " + CURRENCY_UNIT + "\n"
" \"denoms_goal\": xxx, (numeric) How many inputs of each denominated amount to target\n"
" \"denoms_hardcap\": xxx, (numeric) Maximum limit of how many inputs of each denominated amount to create\n"
" \"queue_size\": xxx, (numeric) How many queues there are currently on the network\n"
" \"running\": true|false, (bool) Whether mixing is currently running\n"
" \"sessions\": (array of json objects)\n"
" \"enabled\" : true|false, (boolean) Whether mixing functionality is enabled\n"
" \"multisession\" : true|false, (boolean) Whether CoinJoin Multisession option is enabled\n"
" \"max_sessions\" : xxx, (numeric) How many parallel mixing sessions can there be at once\n"
" \"max_rounds\" : xxx, (numeric) How many rounds to mix\n"
" \"max_amount\" : xxx, (numeric) Target CoinJoin balance in " + CURRENCY_UNIT + "\n"
" \"denoms_goal\" : xxx, (numeric) How many inputs of each denominated amount to target\n"
" \"denoms_hardcap\" : xxx, (numeric) Maximum limit of how many inputs of each denominated amount to create\n"
" \"queue_size\" : xxx, (numeric) How many queues there are currently on the network\n"
" \"running\" : true|false, (boolean) Whether mixing is currently running\n"
" \"sessions\" : (array of json objects)\n"
" [\n"
" {\n"
" \"protxhash\": \"...\", (string) The ProTxHash of the masternode\n"
" \"outpoint\": \"txid-index\", (string) The outpoint of the masternode\n"
" \"service\": \"host:port\", (string) The IP address and port of the masternode\n"
" \"denomination\": xxx, (numeric) The denomination of the mixing session in " + CURRENCY_UNIT + "\n"
" \"state\": \"...\", (string) Current state of the mixing session\n"
" \"entries_count\": xxx, (numeric) The number of entries in the mixing session\n"
" \"protxhash\" : \"...\", (string) The ProTxHash of the masternode\n"
" \"outpoint\" : \"txid-index\", (string) The outpoint of the masternode\n"
" \"service\" : \"host:port\", (string) The IP address and port of the masternode\n"
" \"denomination\" : xxx, (numeric) The denomination of the mixing session in " + CURRENCY_UNIT + "\n"
" \"state\" : \"...\", (string) Current state of the mixing session\n"
" \"entries_count\" : xxx, (numeric) The number of entries in the mixing session\n"
" }\n"
" ,...\n"
" ],\n"
" \"keys_left\": xxx, (numeric) How many new keys are left since last automatic backup\n"
" \"warnings\": \"...\" (string) Warnings if any\n"
" \"keys_left\" : xxx, (numeric) How many new keys are left since last automatic backup\n"
" \"warnings\" : \"...\" (string) Warnings if any\n"
"}\n"
}, {"for masternodes",
"{\n"
" \"queue_size\": xxx, (numeric) How many queues there are currently on the network\n"
" \"denomination\": xxx, (numeric) The denomination of the mixing session in " + CURRENCY_UNIT + "\n"
" \"state\": \"...\", (string) Current state of the mixing session\n"
" \"entries_count\": xxx, (numeric) The number of entries in the mixing session\n"
" \"queue_size\" : xxx, (numeric) How many queues there are currently on the network\n"
" \"denomination\" : xxx, (numeric) The denomination of the mixing session in " + CURRENCY_UNIT + "\n"
" \"state\" : \"...\", (string) Current state of the mixing session\n"
" \"entries_count\" : xxx, (numeric) The number of entries in the mixing session\n"
"}\n"
}},
RPCExamples{

View File

@ -24,9 +24,8 @@
#include <wallet/wallet.h>
#endif // ENABLE_WALLET
static void gobject_count_help()
static void gobject_count_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject count",
"Count governance objects and votes\n",
{
@ -34,13 +33,13 @@ static void gobject_count_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_count(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 2)
gobject_count_help();
gobject_count_help(request);
std::string strMode{"json"};
@ -49,14 +48,13 @@ static UniValue gobject_count(const JSONRPCRequest& request)
}
if (strMode != "json" && strMode != "all")
gobject_count_help();
gobject_count_help(request);
return strMode == "json" ? governance.ToJson() : governance.ToString();
}
static void gobject_deserialize_help()
static void gobject_deserialize_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan {"gobject deserialize",
"Deserialize governance object from hex string to JSON\n",
{
@ -64,13 +62,13 @@ static void gobject_deserialize_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_deserialize(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2)
gobject_deserialize_help();
gobject_deserialize_help(request);
std::string strHex = request.params[1].get_str();
@ -83,9 +81,8 @@ static UniValue gobject_deserialize(const JSONRPCRequest& request)
return u.write().c_str();
}
static void gobject_check_help()
static void gobject_check_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject check",
"Validate governance object data (proposal only)\n",
{
@ -93,13 +90,13 @@ static void gobject_check_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_check(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2)
gobject_check_help();
gobject_check_help(request);
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
@ -132,12 +129,11 @@ static UniValue gobject_check(const JSONRPCRequest& request)
}
#ifdef ENABLE_WALLET
static void gobject_prepare_help(CWallet* const pwallet)
static void gobject_prepare_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject prepare",
"Prepare governance object by signing and creating tx\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
{"parent-hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "hash of the parent object, \"0\" is root"},
{"revision", RPCArg::Type::NUM, RPCArg::Optional::NO, "object revision in the system"},
@ -149,18 +145,17 @@ static void gobject_prepare_help(CWallet* const pwallet)
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_prepare(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || (request.params.size() != 5 && request.params.size() != 6 && request.params.size() != 8))
gobject_prepare_help(pwallet);
gobject_prepare_help(request);
EnsureWalletIsUnlocked(pwallet);
@ -260,31 +255,29 @@ static UniValue gobject_prepare(const JSONRPCRequest& request)
return tx->GetHash().ToString();
}
static void gobject_list_prepared_help(CWallet* const pwallet)
static void gobject_list_prepared_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject list-prepared",
"Returns a list of governance objects prepared by this wallet with \"gobject prepare\" sorted by their creation time.\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
{"count", RPCArg::Type::NUM, /* default */ "10", "Maximum number of objects to return."},
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_list_prepared(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || (request.params.size() > 2)) {
gobject_list_prepared_help(pwallet);
gobject_list_prepared_help(request);
}
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
EnsureWalletIsUnlocked(pwallet);
int64_t nCount = request.params.size() > 1 ? ParseInt64V(request.params[1], "count") : 10;
@ -312,9 +305,8 @@ static UniValue gobject_list_prepared(const JSONRPCRequest& request)
}
#endif // ENABLE_WALLET
static void gobject_submit_help()
static void gobject_submit_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject submit",
"Submit governance object to network\n",
{
@ -326,13 +318,13 @@ static void gobject_submit_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_submit(const JSONRPCRequest& request)
{
if (request.fHelp || ((request.params.size() < 5) || (request.params.size() > 6)))
gobject_submit_help();
gobject_submit_help(request);
if(!masternodeSync.IsBlockchainSynced()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Must wait for client to sync with masternode network. Try again in a minute or so.");
@ -430,9 +422,8 @@ static UniValue gobject_submit(const JSONRPCRequest& request)
return govobj.GetHash().ToString();
}
static void gobject_vote_conf_help()
static void gobject_vote_conf_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject vote-conf",
"Vote on a governance object by masternode configured in dash.conf\n",
{
@ -442,13 +433,13 @@ static void gobject_vote_conf_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_vote_conf(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 4)
gobject_vote_conf_help();
gobject_vote_conf_help(request);
uint256 hash;
@ -604,12 +595,11 @@ static UniValue VoteWithMasternodes(const std::map<uint256, CKey>& keys,
}
#ifdef ENABLE_WALLET
static void gobject_vote_many_help(CWallet* const pwallet)
static void gobject_vote_many_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject vote-many",
"Vote on a governance object by all masternodes for which the voting key is present in the local wallet\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
{"governance-hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "hash of the governance object"},
{"vote", RPCArg::Type::STR, RPCArg::Optional::NO, "vote, possible values: [funding|valid|delete|endorsed]"},
@ -617,18 +607,17 @@ static void gobject_vote_many_help(CWallet* const pwallet)
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_vote_many(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size() != 4)
gobject_vote_many_help(pwallet);
gobject_vote_many_help(request);
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
uint256 hash = ParseHashV(request.params[1], "Object hash");
std::string strVoteSignal = request.params[2].get_str();
@ -661,12 +650,11 @@ static UniValue gobject_vote_many(const JSONRPCRequest& request)
return VoteWithMasternodes(votingKeys, hash, eVoteSignal, eVoteOutcome);
}
static void gobject_vote_alias_help(CWallet* const pwallet)
static void gobject_vote_alias_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject vote-alias",
"Vote on a governance object by masternode's voting key (if present in local wallet)\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
{"governance-hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "hash of the governance object"},
{"vote", RPCArg::Type::STR, RPCArg::Optional::NO, "vote, possible values: [funding|valid|delete|endorsed]"},
@ -675,18 +663,17 @@ static void gobject_vote_alias_help(CWallet* const pwallet)
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_vote_alias(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size() != 5)
gobject_vote_alias_help(pwallet);
gobject_vote_alias_help(request);
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
uint256 hash = ParseHashV(request.params[1], "Object hash");
std::string strVoteSignal = request.params[2].get_str();
@ -782,9 +769,8 @@ static UniValue ListObjects(const std::string& strCachedSignal, const std::strin
return objResult;
}
static void gobject_list_help()
static void gobject_list_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject list",
"List governance objects (can be filtered by signal and/or object type)\n",
{
@ -793,13 +779,13 @@ static void gobject_list_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_list(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 3)
gobject_list_help();
gobject_list_help(request);
std::string strCachedSignal = "valid";
if (!request.params[1].isNull()) {
@ -818,9 +804,8 @@ static UniValue gobject_list(const JSONRPCRequest& request)
return ListObjects(strCachedSignal, strType, 0);
}
static void gobject_diff_help()
static void gobject_diff_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject diff",
"List differences since last diff or list\n",
{
@ -829,13 +814,13 @@ static void gobject_diff_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_diff(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 3)
gobject_diff_help();
gobject_diff_help(request);
std::string strCachedSignal = "valid";
if (!request.params[1].isNull()) {
@ -854,9 +839,8 @@ static UniValue gobject_diff(const JSONRPCRequest& request)
return ListObjects(strCachedSignal, strType, governance.GetLastDiffTime());
}
static void gobject_get_help()
static void gobject_get_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject get",
"Get governance object by hash\n",
{
@ -864,13 +848,13 @@ static void gobject_get_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_get(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2)
gobject_get_help();
gobject_get_help(request);
// COLLECT VARIABLES FROM OUR USER
uint256 hash = ParseHashV(request.params[1], "GovObj hash");
@ -946,9 +930,8 @@ static UniValue gobject_get(const JSONRPCRequest& request)
return objResult;
}
static void gobject_getcurrentvotes_help()
static void gobject_getcurrentvotes_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"gobject getcurrentvotes",
"Get only current (tallying) votes for a governance object hash (does not include old votes)\n",
{
@ -958,13 +941,13 @@ static void gobject_getcurrentvotes_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue gobject_getcurrentvotes(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 2 && request.params.size() != 4))
gobject_getcurrentvotes_help();
gobject_getcurrentvotes_help(request);
// COLLECT PARAMETERS FROM USER
@ -1003,7 +986,6 @@ static UniValue gobject_getcurrentvotes(const JSONRPCRequest& request)
[[ noreturn ]] static void gobject_help()
{
throw std::runtime_error(
RPCHelpMan {"gobject",
"Set of commands to manage governance objects.\n"
"\nAvailable commands:\n"
@ -1030,7 +1012,7 @@ static UniValue gobject_getcurrentvotes(const JSONRPCRequest& request)
{},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Throw();
}
static UniValue gobject(const JSONRPCRequest& request)
@ -1181,11 +1163,11 @@ static UniValue getgovernanceinfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
" \"governanceminquorum\": xxxxx, (numeric) the absolute minimum number of votes needed to trigger a governance action\n"
" \"proposalfee\": xxx.xx, (numeric) the collateral transaction fee which must be paid to create a proposal in " + CURRENCY_UNIT + "\n"
" \"superblockcycle\": xxxxx, (numeric) the number of blocks between superblocks\n"
" \"lastsuperblock\": xxxxx, (numeric) the block number of the last superblock\n"
" \"nextsuperblock\": xxxxx, (numeric) the block number of the next superblock\n"
" \"governanceminquorum\" : xxxxx, (numeric) the absolute minimum number of votes needed to trigger a governance action\n"
" \"proposalfee\" : xxx.xx, (numeric) the collateral transaction fee which must be paid to create a proposal in " + CURRENCY_UNIT + "\n"
" \"superblockcycle\" : xxxxx, (numeric) the number of blocks between superblocks\n"
" \"lastsuperblock\" : xxxxx, (numeric) the block number of the last superblock\n"
" \"nextsuperblock\" : xxxxx, (numeric) the block number of the next superblock\n"
"}\n"
},
RPCExamples{

View File

@ -25,9 +25,8 @@
static UniValue masternodelist(const JSONRPCRequest& request);
static void masternode_list_help()
static void masternode_list_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"masternodelist",
"Get a list of masternodes in different modes. This call is identical to 'masternode list' call.\n"
"Available modes:\n"
@ -52,13 +51,13 @@ static void masternode_list_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue masternode_list(const JSONRPCRequest& request)
{
if (request.fHelp)
masternode_list_help();
masternode_list_help(request);
JSONRPCRequest newRequest = request;
newRequest.params.setArray();
// forward params but skip "list"
@ -68,9 +67,8 @@ static UniValue masternode_list(const JSONRPCRequest& request)
return masternodelist(newRequest);
}
static void masternode_connect_help()
static void masternode_connect_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"masternode connect",
"Connect to given masternode\n",
{
@ -78,13 +76,13 @@ static void masternode_connect_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_connect(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2)
masternode_connect_help();
masternode_connect_help(request);
std::string strAddress = request.params[1].get_str();
@ -100,21 +98,20 @@ static UniValue masternode_connect(const JSONRPCRequest& request)
return "successfully connected";
}
static void masternode_count_help()
static void masternode_count_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"masternode count",
"Get information about number of masternodes.\n",
{},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_count(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 1)
masternode_count_help();
masternode_count_help(request);
auto mnList = deterministicMNManager->GetListAtChainTip();
int total = mnList.GetAllMNsCount();
@ -148,74 +145,69 @@ static UniValue GetNextMasternodeForPayment(int heightShift)
return obj;
}
static void masternode_winner_help()
static void masternode_winner_help(const JSONRPCRequest& request)
{
if (!IsDeprecatedRPCEnabled("masternode_winner")) {
throw std::runtime_error("DEPRECATED: set -deprecatedrpc=masternode_winner to enable it");
}
throw std::runtime_error(
RPCHelpMan{"masternode winner",
"Print info on next masternode winner to vote for\n",
{},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_winner(const JSONRPCRequest& request)
{
if (request.fHelp || !IsDeprecatedRPCEnabled("masternode_winner"))
masternode_winner_help();
masternode_winner_help(request);
return GetNextMasternodeForPayment(10);
}
static void masternode_current_help()
static void masternode_current_help(const JSONRPCRequest& request)
{
if (!IsDeprecatedRPCEnabled("masternode_current")) {
throw std::runtime_error("DEPRECATED: set -deprecatedrpc=masternode_current to enable it");
}
throw std::runtime_error(
RPCHelpMan{"masternode current",
"Print info on current masternode winner to be paid the next block (calculated locally)\n",
{},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_current(const JSONRPCRequest& request)
{
if (request.fHelp || !IsDeprecatedRPCEnabled("masternode_current"))
masternode_current_help();
masternode_current_help(request);
return GetNextMasternodeForPayment(1);
}
#ifdef ENABLE_WALLET
static void masternode_outputs_help()
static void masternode_outputs_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"masternode outputs",
"Print masternode compatible outputs\n",
{},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_outputs(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp)
masternode_outputs_help();
masternode_outputs_help(request);
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
// Find possible candidates
std::vector<COutput> vPossibleCoins;
@ -236,21 +228,20 @@ static UniValue masternode_outputs(const JSONRPCRequest& request)
#endif // ENABLE_WALLET
static void masternode_status_help()
static void masternode_status_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"masternode status",
"Print masternode status information\n",
{},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_status(const JSONRPCRequest& request)
{
if (request.fHelp)
masternode_status_help();
masternode_status_help(request);
if (!fMasternodeMode)
throw JSONRPCError(RPC_INTERNAL_ERROR, "This is not a masternode");
@ -286,12 +277,12 @@ static std::string GetRequiredPaymentsString(int nBlockHeight, const CDeterminis
if (payee) {
CTxDestination dest;
if (!ExtractDestination(payee->pdmnState->scriptPayout, dest)) {
assert(false);
CHECK_NONFATAL(false);
}
strPayments = EncodeDestination(dest);
if (payee->nOperatorReward != 0 && payee->pdmnState->scriptOperatorPayout != CScript()) {
if (!ExtractDestination(payee->pdmnState->scriptOperatorPayout, dest)) {
assert(false);
CHECK_NONFATAL(false);
}
strPayments += ", " + EncodeDestination(dest);
}
@ -316,9 +307,8 @@ static std::string GetRequiredPaymentsString(int nBlockHeight, const CDeterminis
return strPayments;
}
static void masternode_winners_help()
static void masternode_winners_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"masternode winners",
"Print list of masternode winners\n",
{
@ -327,13 +317,13 @@ static void masternode_winners_help()
},
RPCResults{},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_winners(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 3)
masternode_winners_help();
masternode_winners_help(request);
const CBlockIndex* pindexTip{nullptr};
{
@ -375,9 +365,8 @@ static UniValue masternode_winners(const JSONRPCRequest& request)
return obj;
}
static void masternode_payments_help()
static void masternode_payments_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"masternode payments",
"\nReturns an array of deterministic masternodes and their payments for the specified block\n",
{
@ -385,20 +374,20 @@ static void masternode_payments_help()
{"count", RPCArg::Type::NUM, /* default */ "1", "The number of blocks to return. Will return <count> previous blocks if <count> is negative. Both 1 and -1 correspond to the chain tip."},
},
RPCResult {
" [ (array) Blocks\n"
" [ (json array) Blocks\n"
" {\n"
" \"height\" : n, (numeric) The height of the block\n"
" \"blockhash\" : \"hash\", (string) The hash of the block\n"
" \"amount\": n (numeric) Amount received in this block by all masternodes\n"
" \"masternodes\": [ (array) Masternodes that received payments in this block\n"
" \"amount\" : n (numeric) Amount received in this block by all masternodes\n"
" \"masternodes\" : [ (json array) Masternodes that received payments in this block\n"
" {\n"
" \"proTxHash\": \"xxxx\", (string) The hash of the corresponding ProRegTx\n"
" \"amount\": n (numeric) Amount received by this masternode\n"
" \"payees\": [ (array) Payees who received a share of this payment\n"
" \"proTxHash\" : \"xxxx\", (string) The hash of the corresponding ProRegTx\n"
" \"amount\" : n (numeric) Amount received by this masternode\n"
" \"payees\" : [ (json array) Payees who received a share of this payment\n"
" {\n"
" \"address\" : \"xxx\", (string) Payee address\n"
" \"script\" : \"xxx\", (string) Payee scriptPubKey\n"
" \"amount\": n (numeric) Amount received by this payee\n"
" \"amount\" : n (numeric) Amount received by this payee\n"
" },...\n"
" ]\n"
" },...\n"
@ -407,13 +396,13 @@ static void masternode_payments_help()
" ]"
},
RPCExamples{""}
}.ToString());
}.Check(request);
}
static UniValue masternode_payments(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() > 3) {
masternode_payments_help();
masternode_payments_help(request);
}
CBlockIndex* pindex{nullptr};
@ -522,7 +511,6 @@ static UniValue masternode_payments(const JSONRPCRequest& request)
[[ noreturn ]] static void masternode_help()
{
throw std::runtime_error(
RPCHelpMan{"masternode",
"Set of commands to execute masternode related actions\n"
"\nAvailable commands:\n"
@ -541,7 +529,7 @@ static UniValue masternode_payments(const JSONRPCRequest& request)
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Throw();
}
static UniValue masternode(const JSONRPCRequest& request)
@ -597,7 +585,7 @@ static UniValue masternodelist(const JSONRPCRequest& request)
strMode != "payee" && strMode != "pubkeyoperator" &&
strMode != "status"))
{
masternode_list_help();
masternode_list_help(request);
}
UniValue obj(UniValue::VOBJ);

View File

@ -93,8 +93,7 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request)
{"height", RPCArg::Type::NUM, /* default */ "-1", "To estimate at the time of the given height."},
},
RPCResult{
"x (numeric) Hashes per second estimated\n"
},
RPCResult::Type::NUM, "", "Hashes per second estimated"},
RPCExamples{
HelpExampleCli("getnetworkhashps", "")
+ HelpExampleRpc("getnetworkhashps", "")
@ -166,8 +165,10 @@ static UniValue generatetoaddress(const JSONRPCRequest& request)
{"maxtries", RPCArg::Type::NUM, /* default */ "1000000", "How many iterations to try."},
},
RPCResult{
"[ blockhashes ] (array) hashes of blocks generated\n"
},
RPCResult::Type::ARR, "", "hashes of blocks generated",
{
{RPCResult::Type::STR_HEX, "", "blockhash"},
}},
RPCExamples{
"\nGenerate 11 blocks to myaddress\n"
+ HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
@ -206,14 +207,14 @@ static UniValue getmininginfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
" \"blocks\": nnn, (numeric) The current block\n"
" \"currentblocksize\": nnn, (numeric, optional) The block size of the last assembled block (only present if a block was ever assembled)\n"
" \"currentblocktx\": nnn, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)\n"
" \"difficulty\": xxx.xxxxx (numeric) The current difficulty\n"
" \"networkhashps\": nnn, (numeric) The network hashes per second\n"
" \"pooledtx\": n (numeric) The size of the mempool\n"
" \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"warnings\": \"...\" (string) any network and blockchain warnings\n"
" \"blocks\" : nnn, (numeric) The current block\n"
" \"currentblocksize\" : nnn, (numeric, optional) The block size of the last assembled block (only present if a block was ever assembled)\n"
" \"currentblocktx\" : nnn, (numeric, optional) The number of block transactions of the last assembled block (only present if a block was ever assembled)\n"
" \"difficulty\" : xxx.xxxxx (numeric) The current difficulty\n"
" \"networkhashps\" : nnn, (numeric) The network hashes per second\n"
" \"pooledtx\" : n (numeric) The size of the mempool\n"
" \"chain\" : \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n"
" \"warnings\" : \"...\" (string) any network and blockchain warnings\n"
"}\n"
},
RPCExamples{
@ -253,8 +254,7 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request)
" considers the transaction as it would have paid a higher (or lower) fee."},
},
RPCResult{
"true (boolean) Returns true\n"
},
RPCResult::Type::BOOL, "", "Returns true"},
RPCExamples{
HelpExampleCli("prioritisetransaction", "\"txid\" 10000")
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 10000")
@ -338,15 +338,15 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
" },\n"
" \"vbrequired\" : n, (numeric) bit mask of versionbits the server requires set in submissions\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"
" \"transactions\" : [ (json 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"
" \"depends\" : [ (json 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 duffs); 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"
" \"fee\" : n, (numeric) difference in value between transaction inputs and outputs (in duffs); 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"
" }\n"
" ,...\n"
@ -367,20 +367,20 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
" \"bits\" : \"xxxxxxxx\", (string) compressed target of next block\n"
" \"previousbits\" : \"xxxxxxxx\", (string) compressed target of current highest block\n"
" \"height\" : n (numeric) The height of the next block\n"
" \"masternode\" : [ (array) required masternode payments that must be included in the next block\n"
" \"masternode\" : [ (json array) required masternode payments that must be included in the next block\n"
" {\n"
" \"payee\" : \"xxxx\", (string) payee address\n"
" \"script\" : \"xxxx\", (string) payee scriptPubKey\n"
" \"amount\": n (numeric) required amount to pay\n"
" \"amount\" : n (numeric) required amount to pay\n"
" }\n"
" },\n"
" \"masternode_payments_started\" : true|false, (boolean) true, if masternode payments started\n"
" \"masternode_payments_enforced\" : true|false, (boolean) true, if masternode payments are enforced\n"
" \"superblock\" : [ (array) required superblock payees that must be included in the next block\n"
" \"superblock\" : [ (json array) required superblock payees that must be included in the next block\n"
" {\n"
" \"payee\" : \"xxxx\", (string) payee address\n"
" \"script\" : \"xxxx\", (string) payee scriptPubKey\n"
" \"amount\": n (numeric) required amount to pay\n"
" \"amount\" : n (numeric) required amount to pay\n"
" }\n"
" ,...\n"
" ],\n"
@ -549,7 +549,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
// Need to update only after we know CreateNewBlock succeeded
pindexPrev = pindexPrevNew;
}
assert(pindexPrev);
CHECK_NONFATAL(pindexPrev);
CBlock* pblock = &pblocktemplate->block; // pointer for convenience
const Consensus::Params& consensusParams = Params().GetConsensus();
@ -798,8 +798,7 @@ static UniValue submitheader(const JSONRPCRequest& request)
{"hexdata", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded block header data"},
},
RPCResult{
"None"
},
RPCResult::Type::NONE, "", "None"},
RPCExamples{
HelpExampleCli("submitheader", "\"aabbcc\"") +
HelpExampleRpc("submitheader", "\"aabbcc\"")
@ -848,17 +847,19 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request)
" \"CONSERVATIVE\""},
},
RPCResult{
"{\n"
" \"feerate\" : x.x, (numeric, optional) estimate fee rate in " + CURRENCY_UNIT + "/kB\n"
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"blocks\" : n (numeric) block number where estimate was found\n"
"}\n"
"\n"
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "feerate", /* optional */ true, "estimate fee rate in " + CURRENCY_UNIT + "/kB (only present if no errors were encountered)"},
{RPCResult::Type::ARR, "errors", "Errors encountered during processing",
{
{RPCResult::Type::STR, "", "error"},
}},
{RPCResult::Type::NUM, "blocks", "block number where estimate was found\n"
"The request target will be clamped between 2 and the highest target\n"
"fee estimation is able to return based on how long it has been running.\n"
"An error is returned if not enough transactions and blocks\n"
"have been observed to make an estimate for any number of blocks.\n"
},
"have been observed to make an estimate for any number of blocks."},
}},
RPCExamples{
HelpExampleCli("estimatesmartfee", "6")
},
@ -923,7 +924,7 @@ static UniValue estimaterawfee(const JSONRPCRequest& request)
" \"leftmempool\" : x.x, (numeric) number of txs over history horizon in the feerate range that left mempool unconfirmed after target\n"
" },\n"
" \"fail\" : { ... }, (json object, optional) information about the highest range of feerates to fail to meet the threshold\n"
" \"errors\": [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" \"errors\" : [ str... ] (json array of strings, optional) Errors encountered during processing\n"
" },\n"
" \"medium\" : { ... }, (json object, optional) estimate for medium time horizon\n"
" \"long\" : { ... } (json object) estimate for long time horizon\n"

View File

@ -15,8 +15,9 @@
#include <rpc/util.h>
#include <script/descriptor.h>
#include <txmempool.h>
#include <util/system.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <validation.h>
#include <util/validation.h>
@ -254,8 +255,8 @@ static UniValue createmultisig(const JSONRPCRequest& request)
},
RPCResult{
"{\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"
" \"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"
},
RPCExamples{
@ -302,13 +303,14 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request)
{"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor"},
},
RPCResult{
"{\n"
" \"descriptor\" : \"desc\", (string) The descriptor in canonical form, without private keys\n"
" \"checksum\" : \"chksum\", (string) The checksum for the input descriptor\n"
" \"isrange\" : true|false, (boolean) Whether the descriptor is ranged\n"
" \"issolvable\" : true|false, (boolean) Whether the descriptor is solvable\n"
" \"hasprivatekeys\" : true|false, (boolean) Whether the input descriptor contained at least one private key\n"
"}\n"
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "descriptor", "The descriptor in canonical form, without private keys"},
{RPCResult::Type::STR, "checksum", "The checksum for the input descriptor"},
{RPCResult::Type::BOOL, "isrange", "Whether the descriptor is ranged"},
{RPCResult::Type::BOOL, "issolvable", "Whether the descriptor is solvable"},
{RPCResult::Type::BOOL, "hasprivatekeys", "Whether the input descriptor contained at least one private key"},
}
},
RPCExamples{
"\nAnalyse a descriptor\n"
@ -353,7 +355,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
{"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED_NAMED_ARG, "If a ranged descriptor is used, this specifies the end or the range (in [begin,end] notation) to derive."},
},
RPCResult{
"\"address\" (array) A json array of the derived addresses\n"
"\"address\" (json array) A json array of the derived addresses\n"
" [\n"
" ...\n"
" ]\n"
@ -429,7 +431,7 @@ static UniValue verifymessage(const JSONRPCRequest& request)
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."},
},
RPCResult{
"true|false (boolean) If the signature is verified or not.\n"
RPCResult::Type::BOOL, "", "If the signature is verified or not."
},
RPCExamples{
"\nUnlock the wallet for 30 seconds\n"
@ -487,7 +489,7 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request)
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
},
RPCResult{
"\"signature\" (string) The signature of the message encoded in base 64\n"
RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
},
RPCExamples{
"\nCreate the signature\n"
@ -899,10 +901,10 @@ static UniValue getaddressbalance(const JSONRPCRequest& request)
},
RPCResult{
"{\n"
" \"balance\": xxxxx, (numeric) The current total balance in duffs\n"
" \"balance_immature\": xxxxx, (numeric) The current immature balance in duffs\n"
" \"balance_spendable\": xxxxx, (numeric) The current spendable balance in duffs\n"
" \"received\": xxxxx (numeric) The total number of duffs received (including change)\n"
" \"balance\" : xxxxx, (numeric) The current total balance in duffs\n"
" \"balance_immature\" : xxxxx, (numeric) The current immature balance in duffs\n"
" \"balance_spendable\" : xxxxx, (numeric) The current spendable balance in duffs\n"
" \"received\" : xxxxx (numeric) The total number of duffs received (including change)\n"
"}\n"
},
RPCExamples{
@ -1136,19 +1138,21 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request)
},
{
RPCResult{"mode \"stats\"",
"{\n"
" \"locked\": { (json object) Information about locked memory manager\n"
" \"used\": xxxxx, (numeric) Number of bytes used\n"
" \"free\": xxxxx, (numeric) Number of bytes available in current arenas\n"
" \"total\": xxxxxxx, (numeric) Total number of bytes managed\n"
" \"locked\": xxxxxx, (numeric) Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk.\n"
" \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n"
" \"chunks_free\": xxxxx, (numeric) Number unused chunks\n"
" }\n"
"}\n"
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::OBJ, "locked", "Information about locked memory manager",
{
{RPCResult::Type::NUM, "used", "Number of bytes used"},
{RPCResult::Type::NUM, "free", "Number of bytes available in current arenas"},
{RPCResult::Type::NUM, "total", "Total number of bytes managed"},
{RPCResult::Type::NUM, "locked", "Amount of bytes that succeeded locking. If this number is smaller than total, locking pages failed at some point and key data could be swapped to disk."},
{RPCResult::Type::NUM, "chunks_used", "Number allocated chunks"},
{RPCResult::Type::NUM, "chunks_free", "Number unused chunks"},
}},
}
},
RPCResult{"mode \"mallocinfo\"",
"\"<malloc version=\"1\">...\"\n"
RPCResult::Type::STR, "", "\"<malloc version=\"1\">...\""
},
},
RPCExamples{
@ -1219,10 +1223,10 @@ static UniValue logging(const JSONRPCRequest& request)
}},
},
RPCResult{
"{ (json object where keys are the logging categories, and values indicates its status\n"
" \"category\": true|false, (bool) if being debug logged or not. false:inactive, true:active\n"
" ...\n"
"}\n"
RPCResult::Type::OBJ_DYN, "", "keys are the logging categories, and values indicates its status",
{
{RPCResult::Type::BOOL, "category", "if being debug logged or not. false:inactive, true:active"},
}
},
RPCExamples{
HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"")
@ -1270,6 +1274,7 @@ static UniValue echo(const JSONRPCRequest& request)
throw std::runtime_error(
RPCHelpMan{"echo|echojson ...",
"\nSimply echo back the input arguments. This command is for testing.\n"
"\nIt will return an internal bug report when exactly 100 arguments are passed.\n"
"\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
"dash-cli and the GUI. There is no server-side difference.",
{},
@ -1278,6 +1283,8 @@ static UniValue echo(const JSONRPCRequest& request)
}.ToString()
);
CHECK_NONFATAL(request.params.size() != 100);
return request.params;
}

View File

@ -34,7 +34,7 @@ static UniValue getconnectioncount(const JSONRPCRequest& request)
"\nReturns the number of connections to other nodes.\n",
{},
RPCResult{
"n (numeric) The connection count\n"
RPCResult::Type::NUM, "", "The connection count"
},
RPCExamples{
HelpExampleCli("getconnectioncount", "")
@ -84,54 +84,54 @@ static UniValue getpeerinfo(const JSONRPCRequest& request)
RPCResult{
"[\n"
" {\n"
" \"id\": n, (numeric) Peer index\n"
" \"addr\":\"host:port\", (string) The IP address and port of the peer\n"
" \"addrbind\":\"ip:port\", (string) Bind address of the connection to the peer\n"
" \"addrlocal\":\"ip:port\", (string) Local address as reported by the peer\n"
" \"mapped_as\":\"mapped_as\", (string) The AS in the BGP route to the peer used for diversifying peer selection\n"
" \"services\":\"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
" \"verified_proregtx_hash\": h, (hex) Only present when the peer is a masternode and successfully\n"
" \"id\" : n, (numeric) Peer index\n"
" \"addr\" : \"host:port\", (string) The IP address and port of the peer\n"
" \"addrbind\" : \"ip:port\", (string) Bind address of the connection to the peer\n"
" \"addrlocal\" : \"ip:port\", (string) Local address as reported by the peer\n"
" \"mapped_as\" : \"mapped_as\", (string) The AS in the BGP route to the peer used for diversifying peer selection\n"
" \"services\" : \"xxxxxxxxxxxxxxxx\", (string) The services offered\n"
" \"verified_proregtx_hash\" : h, (hex) Only present when the peer is a masternode and successfully\n"
" authenticated via MNAUTH. In this case, this field contains the\n"
" protx hash of the masternode\n"
" \"verified_pubkey_hash\": h, (hex) Only present when the peer is a masternode and successfully\n"
" \"verified_pubkey_hash\" : h, (hex) Only present when the peer is a masternode and successfully\n"
" authenticated via MNAUTH. In this case, this field contains the\n"
" hash of the masternode's operator public key\n"
" \"servicesnames\":[ (array) the services offered, in human-readable form\n"
" \"servicesnames\" : [ (json array) the services offered, in human-readable form\n"
" \"SERVICE_NAME\", (string) the service name if it is recognised\n"
" ...\n"
" ],\n"
" \"relaytxes\":true|false, (boolean) Whether peer has asked us to relay transactions to it\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 (if available)\n"
" \"minping\": n, (numeric) minimum observed ping time (if any at all)\n"
" \"pingwait\": n, (numeric) ping wait (if non-zero)\n"
" \"version\": v, (numeric) The peer version, such as 70001\n"
" \"subver\": \"/Dash Core:x.x.x/\", (string) The string version\n"
" \"inbound\": true|false, (boolean) Inbound (true) or Outbound (false)\n"
" \"addnode\": true|false, (boolean) Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n"
" \"masternode\": true|false, (boolean) Whether connection was due to masternode connection attempt\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"
" \"relaytxes\" : true|false, (boolean) Whether peer has asked us to relay transactions to it\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 (if available)\n"
" \"minping\" : n, (numeric) minimum observed ping time (if any at all)\n"
" \"pingwait\" : n, (numeric) ping wait (if non-zero)\n"
" \"version\" : v, (numeric) The peer version, such as 70001\n"
" \"subver\" : \"/Dash Core:x.x.x/\", (string) The string version\n"
" \"inbound\" : true|false, (boolean) Inbound (true) or Outbound (false)\n"
" \"addnode\" : true|false, (boolean) Whether connection was due to addnode/-connect or if it was an automatic/inbound connection\n"
" \"masternode\" : true|false, (boolean) Whether connection was due to masternode connection attempt\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"
" \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n"
" \"bytessent_per_msg\": {\n"
" \"msg\": n, (numeric) The total bytes sent aggregated by message type\n"
" \"whitelisted\" : true|false, (boolean) Whether the peer is whitelisted\n"
" \"bytessent_per_msg\" : {\n"
" \"msg\" : n, (numeric) The total bytes sent aggregated by message type\n"
" When a message type is not listed in this json object, the bytes sent are 0.\n"
" Only known message types can appear as keys in the object.\n"
" ...\n"
" },\n"
" \"bytesrecv_per_msg\": {\n"
" \"msg\": n, (numeric) The total bytes received aggregated by message type\n"
" \"bytesrecv_per_msg\" : {\n"
" \"msg\" : n, (numeric) The total bytes received aggregated by message type\n"
" When a message type is not listed in this json object, the bytes received are 0.\n"
" Only known message types can appear as keys in the object and all bytes received of unknown message types are listed under '"+NET_MESSAGE_COMMAND_OTHER+"'.\n"
" ...\n"
@ -413,20 +413,21 @@ static UniValue getnettotals(const JSONRPCRequest& request)
"and current time.\n",
{},
RPCResult{
"{\n"
" \"totalbytesrecv\": n, (numeric) Total bytes received\n"
" \"totalbytessent\": n, (numeric) Total bytes sent\n"
" \"timemillis\": t, (numeric) Current UNIX time in milliseconds\n"
" \"uploadtarget\":\n"
" {\n"
" \"timeframe\": n, (numeric) Length of the measuring timeframe in seconds\n"
" \"target\": n, (numeric) Target in bytes\n"
" \"target_reached\": true|false, (boolean) True if target is reached\n"
" \"serve_historical_blocks\": true|false, (boolean) True if serving historical blocks\n"
" \"bytes_left_in_cycle\": t, (numeric) Bytes left in current time cycle\n"
" \"time_left_in_cycle\": t (numeric) Seconds left in current time cycle\n"
" }\n"
"}\n"
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::NUM, "totalbytesrecv", "Total bytes received"},
{RPCResult::Type::NUM, "totalbytessent", "Total bytes sent"},
{RPCResult::Type::NUM_TIME, "timemillis", "Current UNIX time in milliseconds"},
{RPCResult::Type::OBJ, "uploadtarget", "",
{
{RPCResult::Type::NUM, "timeframe", "Length of the measuring timeframe in seconds"},
{RPCResult::Type::NUM, "target", "Target in bytes"},
{RPCResult::Type::BOOL, "target_reached", "True if target is reached"},
{RPCResult::Type::BOOL, "serve_historical_blocks", "True if serving historical blocks"},
{RPCResult::Type::NUM, "bytes_left_in_cycle", "Bytes left in current time cycle"},
{RPCResult::Type::NUM, "time_left_in_cycle", "Seconds left in current time cycle"},
}},
}
},
RPCExamples{
HelpExampleCli("getnettotals", "")
@ -482,41 +483,41 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
" \"version\": xxxxx, (numeric) the server version\n"
" \"buildversion\": \"x.x.x.x-xxx\", (string) the server build version including RC info or commit as relevant\n"
" \"subversion\": \"/Dash 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"
" \"localservicesnames\": [ (array) the services we offer to the network, in human-readable form\n"
" \"version\" : xxxxx, (numeric) the server version\n"
" \"buildversion\" : \"x.x.x.x-xxx\", (string) the server build version including RC info or commit as relevant\n"
" \"subversion\" : \"/Dash 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"
" \"localservicesnames\" : [ (json array) the services we offer to the network, in human-readable form\n"
" \"SERVICE_NAME\", (string) the service name\n"
" ...\n"
" ],\n"
" \"localrelay\": true|false, (bool) true if transaction relay is requested from peers\n"
" \"timeoffset\": xxxxx, (numeric) the time offset\n"
" \"connections\": xxxxx, (numeric) the number of connections\n"
" \"networkactive\": true|false, (bool) whether p2p networking is enabled\n"
" \"socketevents\": \"xxx/\", (string) the socket events mode, either kqueue, epoll, poll or select\n"
" \"networks\": [ (array) information per network\n"
" \"localrelay\" : true|false, (boolean) true if transaction relay is requested from peers\n"
" \"timeoffset\" : xxxxx, (numeric) the time offset\n"
" \"connections\" : xxxxx, (numeric) the number of connections\n"
" \"networkactive\" : true|false, (boolean) whether p2p networking is enabled\n"
" \"socketevents\" : \"xxx/\", (string) the socket events mode, either kqueue, epoll, poll or select\n"
" \"networks\" : [ (json 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"
" \"proxy_randomize_credentials\": true|false, (string) Whether randomized credentials are used\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"
" \"proxy_randomize_credentials\" : true|false, (string) Whether randomized credentials are used\n"
" }\n"
" ,...\n"
" ],\n"
" \"relayfee\": x.xxxxxxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"incrementalfee\": x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\": [ (array) list of local addresses\n"
" \"relayfee\" : x.xxxxxxxx, (numeric) minimum relay fee for transactions in " + CURRENCY_UNIT + "/kB\n"
" \"incrementalfee\" : x.xxxxxxxx, (numeric) minimum fee increment for mempool limiting in " + CURRENCY_UNIT + "/kB\n"
" \"localaddresses\" : [ (json 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"
" \"address\" : \"xxxx\", (string) network address\n"
" \"port\" : xxx, (numeric) network port\n"
" \"score\" : xxx (numeric) relative score\n"
" }\n"
" ,...\n"
" ]\n"
" \"warnings\": \"...\" (string) any network and blockchain warnings\n"
" \"warnings\" : \"...\" (string) any network and blockchain warnings\n"
"}\n"
},
RPCExamples{
@ -556,7 +557,7 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request)
strSocketEvents = "kqueue";
break;
default:
assert(false);
CHECK_NONFATAL(false);
}
obj.pushKV("socketevents", strSocketEvents);
}
@ -755,10 +756,10 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request)
RPCResult{
"[\n"
" {\n"
" \"time\": ttt, (numeric) Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen\n"
" \"services\": n, (numeric) The services offered\n"
" \"address\": \"host\", (string) The address of the node\n"
" \"port\": n (numeric) The port of the node\n"
" \"time\" : ttt, (numeric) Timestamp in seconds since epoch (Jan 1 1970 GMT) keeping track of when the node was last seen\n"
" \"services\" : n, (numeric) The services offered\n"
" \"address\" : \"host\", (string) The address of the node\n"
" \"port\" : n (numeric) The port of the node\n"
" }\n"
" ,....\n"
"]\n"

View File

@ -6,15 +6,6 @@
#ifndef BITCOIN_RPC_PROTOCOL_H
#define BITCOIN_RPC_PROTOCOL_H
#include <fs.h>
#include <list>
#include <map>
#include <stdint.h>
#include <string>
#include <univalue.h>
//! HTTP status codes
enum HTTPStatusCode
{
@ -93,18 +84,4 @@ enum RPCErrorCode
RPC_FORBIDDEN_BY_SAFE_MODE = -2, //!< Server is in safe mode, and command is not allowed in safe mode
};
UniValue JSONRPCRequestObj(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);
/** 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();
/** Parse JSON-RPC batch reply into a vector */
std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
#endif // BITCOIN_RPC_PROTOCOL_H

View File

@ -133,24 +133,24 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
},
{
RPCResult{"if verbose is not set or set to false",
"\"data\" (string) The serialized, hex-encoded data for 'txid'\n"
RPCResult::Type::STR, "data", "The serialized, hex-encoded data for 'txid'"
},
RPCResult{"if verbose is set to true",
"{\n"
" \"in_active_chain\": b, (bool) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n"
" \"in_active_chain\" : b, (boolean) Whether specified block is in the active chain or not (only present with explicit \"blockhash\" argument)\n"
" \"txid\" : \"id\", (string) The transaction id (same as provided)\n"
" \"size\" : n, (numeric) The transaction size\n"
" \"version\" : n, (numeric) The version\n"
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
" {\n"
" \"txid\": \"id\", (string) The transaction id\n"
" \"vout\": n, (numeric) \n"
" \"scriptSig\": { (json object) The script\n"
" \"asm\": \"asm\", (string) asm\n"
" \"hex\": \"hex\" (string) hex\n"
" \"txid\" : \"id\", (string) The transaction id\n"
" \"vout\" : n, (numeric) \n"
" \"scriptSig\" : { (json object) The script\n"
" \"asm\" : \"asm\", (string) asm\n"
" \"hex\" : \"hex\" (string) hex\n"
" },\n"
" \"sequence\": n (numeric) The script sequence number\n"
" \"sequence\" : n (numeric) The script sequence number\n"
" }\n"
" ,...\n"
" ],\n"
@ -179,9 +179,9 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
" \"confirmations\" : n, (numeric) The confirmations\n"
" \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
" \"time\" : ttt, (numeric) Same as \"blocktime\"\n"
" \"instantlock\" : true|false, (bool) Current transaction lock state\n"
" \"instantlock_internal\" : true|false, (bool) Current internal transaction lock state\n"
" \"chainlock\" : true|false, (bool) The state of the corresponding block chainlock\n"
" \"instantlock\" : true|false, (boolean) Current transaction lock state\n"
" \"instantlock_internal\" : true|false, (boolean) Current internal transaction lock state\n"
" \"chainlock\" : true|false, (boolean) The state of the corresponding block chainlock\n"
"}\n"
},
},
@ -273,7 +273,7 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
{"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED_NAMED_ARG, "If specified, looks for txid in the block with this hash"},
},
RPCResult{
"\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n"
RPCResult::Type::STR, "data", "A string that is a serialized, hex-encoded data for the proof."
},
RPCExamples{
HelpExampleCli("gettxoutproof", "'[\"mytxid\",...]'")
@ -367,7 +367,10 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request)
{"proof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded proof generated by gettxoutproof"},
},
RPCResult{
"[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof can not be validated.\n"
RPCResult::Type::ARR, "", "",
{
{RPCResult::Type::STR_HEX, "txid", "The txid(s) which the proof commits to, or empty array if the proof can not be validated."},
}
},
RPCExamples{
HelpExampleCli("verifytxoutproof", "\"proof\"")
@ -446,7 +449,7 @@ static UniValue createrawtransaction(const JSONRPCRequest& request)
{"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
},
RPCResult{
"\"transaction\" (string) hex string of the transaction\n"
RPCResult::Type::STR_HEX, "transaction", "hex string of the transaction"
},
RPCExamples{
HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"address\\\":0.01}]\"")
@ -487,13 +490,13 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request)
" \"locktime\" : ttt, (numeric) The lock time\n"
" \"vin\" : [ (array of json objects)\n"
" {\n"
" \"txid\": \"id\", (string) The transaction id\n"
" \"vout\": n, (numeric) The output number\n"
" \"scriptSig\": { (json object) The script\n"
" \"asm\": \"asm\", (string) asm\n"
" \"hex\": \"hex\" (string) hex\n"
" \"txid\" : \"id\", (string) The transaction id\n"
" \"vout\" : n, (numeric) The output number\n"
" \"scriptSig\" : { (json object) The script\n"
" \"asm\" : \"asm\", (string) asm\n"
" \"hex\" : \"hex\" (string) hex\n"
" },\n"
" \"sequence\": n (numeric) The script sequence number\n"
" \"sequence\" : n (numeric) The script sequence number\n"
" }\n"
" ,...\n"
" ],\n"
@ -556,10 +559,10 @@ static UniValue decodescript(const JSONRPCRequest& request)
},
RPCResult{
"{\n"
" \"asm\":\"asm\", (string) Script public key\n"
" \"type\":\"type\", (string) The output type (e.g. "+GetAllOutputTypes()+")\n"
" \"reqSigs\": n, (numeric) The required signatures\n"
" \"addresses\": [ (json array of string)\n"
" \"asm\" : \"asm\", (string) Script public key\n"
" \"type\" : \"type\", (string) The output type (e.g. "+GetAllOutputTypes()+")\n"
" \"reqSigs\" : n, (numeric) The required signatures\n"
" \"addresses\" : [ (json array of string)\n"
" \"address\" (string) dash address\n"
" ,...\n"
" ],\n"
@ -617,7 +620,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request)
},
},
RPCResult{
"\"hex\" (string) The hex-encoded raw transaction with signature(s)\n"
RPCResult::Type::STR, "", "The hex-encoded raw transaction with signature(s)"
},
RPCExamples{
HelpExampleCli("combinerawtransaction", "'[\"myhex1\", \"myhex2\", \"myhex3\"]'")
@ -725,20 +728,22 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request)
},
},
RPCResult{
"{\n"
" \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
" \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
" \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n"
" {\n"
" \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n"
" \"vout\" : n, (numeric) The index of the output to spent and used as input\n"
" \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n"
" \"sequence\" : n, (numeric) Script sequence number\n"
" \"error\" : \"text\" (string) Verification or signing error related to the input\n"
" }\n"
" ,...\n"
" ]\n"
"}\n"
RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"},
{RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
{RPCResult::Type::ARR, "errors", "Script verification errors (if there are any)",
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "txid", "The hash of the referenced, previous transaction"},
{RPCResult::Type::NUM, "vout", "The index of the output to spent and used as input"},
{RPCResult::Type::STR_HEX, "scriptSig", "The hex-encoded signature script"},
{RPCResult::Type::NUM, "sequence", "Script sequence number"},
{RPCResult::Type::STR, "error", "Verification or signing error related to the input"},
}},
}},
}
},
RPCExamples{
HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"")
@ -788,7 +793,7 @@ UniValue sendrawtransaction(const JSONRPCRequest& request)
{"bypasslimits", RPCArg::Type::BOOL, /* default_val */ "false", "Bypass transaction policy limits"},
},
RPCResult{
"\"hex\" (string) The transaction hash in hex\n"
RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
},
RPCExamples{
"\nCreate a transaction\n"
@ -856,14 +861,16 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request)
{"maxfeerate", RPCArg::Type::AMOUNT, /* default */ FormatMoney(DEFAULT_MAX_RAW_TX_FEE), "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kB\n"},
},
RPCResult{
"[ (array) The result of the mempool acceptance test for each raw transaction in the input array.\n"
" Length is exactly one for now.\n"
" {\n"
" \"txid\" (string) The transaction hash in hex\n"
" \"allowed\" (boolean) If the mempool allows this tx to be inserted\n"
" \"reject-reason\" (string) Rejection string (only present when 'allowed' is false)\n"
" }\n"
"]\n"
RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
"Length is exactly one for now.",
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
{RPCResult::Type::BOOL, "allowed", "If the mempool allows this tx to be inserted"},
{RPCResult::Type::STR, "reject-reason", "Rejection string (only present when 'allowed' is false)"},
}},
}
},
RPCExamples{
"\nCreate a transaction\n"
@ -1195,7 +1202,7 @@ UniValue combinepsbt(const JSONRPCRequest& request)
},
},
RPCResult{
" \"psbt\" (string) The base64-encoded partially signed transaction\n"
RPCResult::Type::STR, "", "The base64-encoded partially signed transaction"
},
RPCExamples{
HelpExampleCli("combinepsbt", "[\"mybase64_1\", \"mybase64_2\", \"mybase64_3\"]")
@ -1328,7 +1335,7 @@ UniValue createpsbt(const JSONRPCRequest& request)
{"locktime", RPCArg::Type::NUM, /* default */ "0", "Raw locktime. Non-0 value also locktime-activates inputs"},
},
RPCResult{
" \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n"
RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)"
},
RPCExamples{
HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
@ -1375,7 +1382,7 @@ UniValue converttopsbt(const JSONRPCRequest& request)
" will continue. If false, RPC will fail if any signatures are present."},
},
RPCResult{
" \"psbt\" (string) The resulting raw transaction (base64-encoded string)\n"
RPCResult::Type::STR, "", "The resulting raw transaction (base64-encoded string)"
},
RPCExamples{
"\nCreate a transaction\n"
@ -1430,7 +1437,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request)
{"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}
},
RPCResult {
" \"psbt\" (string) The base64-encoded partially signed transaction with inputs updated\n"
RPCResult::Type::STR, "", "The base64-encoded partially signed transaction with inputs updated"
},
RPCExamples {
HelpExampleCli("utxoupdatepsbt", "\"psbt\"")
@ -1495,7 +1502,7 @@ UniValue joinpsbts(const JSONRPCRequest& request)
}}
},
RPCResult {
" \"psbt\" (string) The base64-encoded partially signed transaction\n"
RPCResult::Type::STR, "", "The base64-encoded partially signed transaction"
},
RPCExamples {
HelpExampleCli("joinpsbts", "\"psbt\"")

View File

@ -12,7 +12,7 @@
#include <keystore.h>
#include <policy/policy.h>
#include <primitives/transaction.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <rpc/util.h>
#include <univalue.h>
#include <util/strencodings.h>

View File

@ -1,15 +1,16 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2014-2020 The Dash Core developers
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Copyright (c) 2014-2022 The Dash Core 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 <rpc/request.h>
#include <fs.h>
#include <random.h>
#include <rpc/protocol.h>
#include <util/system.h>
#include <util/strencodings.h>
#include <util/time.h>
/**
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
@ -148,3 +149,38 @@ std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num)
}
return batch;
}
void JSONRPCRequest::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") {
if (fLogIPs)
LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
this->authUser, this->peerAddr);
else
LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
}
// Parse params
UniValue valParams = find_value(request, "params");
if (valParams.isArray() || valParams.isObject())
params = valParams;
else if (valParams.isNull())
params = UniValue(UniValue::VARR);
else
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}

42
src/rpc/request.h Normal file
View File

@ -0,0 +1,42 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_RPC_REQUEST_H
#define BITCOIN_RPC_REQUEST_H
#include <string>
#include <univalue.h>
UniValue JSONRPCRequestObj(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);
/** 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();
/** Parse JSON-RPC batch reply into a vector */
std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue &in, size_t num);
class JSONRPCRequest
{
public:
UniValue id;
std::string strMethod;
UniValue params;
bool fHelp;
std::string URI;
std::string authUser;
std::string peerAddr;
JSONRPCRequest() : id(NullUniValue), params(NullUniValue), fHelp(false) {}
void parse(const UniValue& valRequest);
};
#endif // BITCOIN_RPC_REQUEST_H

View File

@ -175,7 +175,7 @@ static CBLSSecretKey ParseBLSSecretKey(const std::string& hexKey, const std::str
template<typename SpecialTxPayload>
static void FundSpecialTx(CWallet* pwallet, CMutableTransaction& tx, const SpecialTxPayload& payload, const CTxDestination& fundDest)
{
assert(pwallet != nullptr);
CHECK_NONFATAL(pwallet != nullptr);
// Make sure the results are valid at least up to the most recent block
// the user could have gotten from another RPC command prior to now
@ -242,7 +242,7 @@ static void FundSpecialTx(CWallet* pwallet, CMutableTransaction& tx, const Speci
// CreateTransaction added a change output, so we don't need the dummy txout anymore.
// Removing it results in slight overpayment of fees, but we ignore this for now (as it's a very low amount).
auto it = std::find(tx.vout.begin(), tx.vout.end(), dummyTxOut);
assert(it != tx.vout.end());
CHECK_NONFATAL(it != tx.vout.end());
tx.vout.erase(it);
}
}
@ -315,16 +315,15 @@ static std::string SignAndSendSpecialTx(const CMutableTransaction& tx, bool fSub
return sendrawtransaction(sendRequest).get_str();
}
static void protx_register_fund_help(CWallet* const pwallet)
static void protx_register_fund_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx register_fund",
"\nCreates, funds and sends a ProTx to the network. The resulting transaction will move 1000 Dash\n"
"to the address specified by collateralAddress and will then function as the collateral of your\n"
"masternode.\n"
"A few of the limitations you see in the arguments are temporary and might be lifted after DIP3\n"
"is fully deployed.\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
GetRpcArg("collateralAddress"),
GetRpcArg("ipAndPort"),
@ -345,17 +344,16 @@ static void protx_register_fund_help(CWallet* const pwallet)
RPCExamples{
HelpExampleCli("protx", "register_fund \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\" \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
},
}.ToString());
}.Check(request);
}
static void protx_register_help(CWallet* const pwallet)
static void protx_register_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx register",
"\nSame as \"protx register_fund\", but with an externally referenced collateral.\n"
"The collateral is specified through \"collateralHash\" and \"collateralIndex\" and must be an unspent\n"
"transaction output spendable by this wallet. It must also not be used by any other masternode.\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
GetRpcArg("collateralHash"),
GetRpcArg("collateralIndex"),
@ -377,12 +375,11 @@ static void protx_register_help(CWallet* const pwallet)
RPCExamples{
HelpExampleCli("protx", "register \"0123456701234567012345670123456701234567012345670123456701234567\" 0 \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
},
}.ToString());
}.Check(request);
}
static void protx_register_prepare_help()
static void protx_register_prepare_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx register_prepare",
"\nCreates an unsigned ProTx and a message that must be signed externally\n"
"with the private key that corresponds to collateralAddress to prove collateral ownership.\n"
@ -409,17 +406,16 @@ static void protx_register_prepare_help()
RPCExamples{
HelpExampleCli("protx", "register_prepare \"0123456701234567012345670123456701234567012345670123456701234567\" 0 \"1.2.3.4:1234\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" \"93746e8731c57f87f79b3620a7982924e2931717d49540a85864bd543de11c43fb868fd63e501a1db37e19ed59ae6db4\" \"Xt9AMWaYSz7tR7Uo7gzXA3m4QmeWgrR3rr\" 0 \"XrVhS9LogauRJGJu2sHuryjhpuex4RNPSb\"")
},
}.ToString());
}.Check(request);
}
static void protx_register_submit_help(CWallet* const pwallet)
static void protx_register_submit_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx register_submit",
"\nCombines the unsigned ProTx and a signature of the signMessage, signs all inputs\n"
"which were added to cover fees and submits the resulting transaction to the network.\n"
"Note: See \"help protx register_prepare\" for more info about creating a ProTx and a message to sign.\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
{"tx", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The serialized unsigned ProTx in hex format."},
{"sig", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature signed with the collateral key. Must be in base64 format."},
@ -430,29 +426,28 @@ static void protx_register_submit_help(CWallet* const pwallet)
RPCExamples{
HelpExampleCli("protx", "register_submit \"tx\" \"sig\"")
},
}.ToString());
}.Check(request);
}
// handles register, register_prepare and register_fund in one method
static UniValue protx_register(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
bool isExternalRegister = request.params[0].get_str() == "register";
bool isFundRegister = request.params[0].get_str() == "register_fund";
bool isPrepareRegister = request.params[0].get_str() == "register_prepare";
if (isFundRegister && (request.fHelp || (request.params.size() < 8 || request.params.size() > 10))) {
protx_register_fund_help(pwallet);
protx_register_fund_help(request);
} else if (isExternalRegister && (request.fHelp || (request.params.size() < 9 || request.params.size() > 11))) {
protx_register_help(pwallet);
protx_register_help(request);
} else if (isPrepareRegister && (request.fHelp || (request.params.size() != 9 && request.params.size() != 10))) {
protx_register_prepare_help();
protx_register_prepare_help(request);
}
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
if (isExternalRegister || isFundRegister) {
EnsureWalletIsUnlocked(pwallet);
}
@ -554,7 +549,7 @@ static UniValue protx_register(const JSONRPCRequest& request)
break;
}
}
assert(collateralIndex != (uint32_t) -1);
CHECK_NONFATAL(collateralIndex != (uint32_t) -1);
ptx.collateralOutpoint.n = collateralIndex;
SetTxPayload(tx, ptx);
@ -598,15 +593,14 @@ static UniValue protx_register(const JSONRPCRequest& request)
static UniValue protx_register_submit(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size() != 3) {
protx_register_submit_help(pwallet);
protx_register_submit_help(request);
}
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
EnsureWalletIsUnlocked(pwallet);
CMutableTransaction tx;
@ -630,14 +624,13 @@ static UniValue protx_register_submit(const JSONRPCRequest& request)
return SignAndSendSpecialTx(tx);
}
static void protx_update_service_help(CWallet* const pwallet)
static void protx_update_service_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx update_service",
"\nCreates and sends a ProUpServTx to the network. This will update the IP address\n"
"of a masternode.\n"
"If this is done for a masternode that got PoSe-banned, the ProUpServTx will also revive this masternode.\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
GetRpcArg("proTxHash"),
GetRpcArg("ipAndPort"),
@ -651,18 +644,17 @@ static void protx_update_service_help(CWallet* const pwallet)
RPCExamples{
HelpExampleCli("protx", "update_service \"0123456701234567012345670123456701234567012345670123456701234567\" \"1.2.3.4:1234\" 5a2e15982e62f1e0b7cf9783c64cf7e3af3f90a52d6c40f6f95d624c0b1621cd")
},
}.ToString());
}.Check(request);
}
static UniValue protx_update_service(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || (request.params.size() < 4 || request.params.size() > 6))
protx_update_service_help(pwallet);
protx_update_service_help(request);
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
EnsureWalletIsUnlocked(pwallet);
@ -729,14 +721,13 @@ static UniValue protx_update_service(const JSONRPCRequest& request)
return SignAndSendSpecialTx(tx);
}
static void protx_update_registrar_help(CWallet* const pwallet)
static void protx_update_registrar_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx update_registrar",
"\nCreates and sends a ProUpRegTx to the network. This will update the operator key, voting key and payout\n"
"address of the masternode specified by \"proTxHash\".\n"
"The owner key of the masternode must be known to your wallet.\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
GetRpcArg("proTxHash"),
GetRpcArg("operatorPubKey_update"),
@ -750,20 +741,19 @@ static void protx_update_registrar_help(CWallet* const pwallet)
RPCExamples{
HelpExampleCli("protx", "update_registrar \"0123456701234567012345670123456701234567012345670123456701234567\" \"982eb34b7c7f614f29e5c665bc3605f1beeef85e3395ca12d3be49d2868ecfea5566f11cedfad30c51b2403f2ad95b67\" \"XwnLY9Tf7Zsef8gMGL2fhWA9ZmMjt4KPwG\"")
},
}.ToString());
}.Check(request);
}
static UniValue protx_update_registrar(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || (request.params.size() != 5 && request.params.size() != 6)) {
protx_update_registrar_help(pwallet);
protx_update_registrar_help(request);
}
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
EnsureWalletIsUnlocked(pwallet);
CProUpRegTx ptx;
@ -821,15 +811,14 @@ static UniValue protx_update_registrar(const JSONRPCRequest& request)
return SignAndSendSpecialTx(tx);
}
static void protx_revoke_help(CWallet* const pwallet)
static void protx_revoke_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx revoke",
"\nCreates and sends a ProUpRevTx to the network. This will revoke the operator key of the masternode and\n"
"put it into the PoSe-banned state. It will also set the service field of the masternode\n"
"to zero. Use this in case your operator key got compromised or you want to stop providing your service\n"
"to the masternode owner.\n"
+ HelpRequiringPassphrase(pwallet) + "\n",
+ HelpRequiringPassphrase() + "\n",
{
GetRpcArg("proTxHash"),
GetRpcArg("operatorKey"),
@ -842,20 +831,19 @@ static void protx_revoke_help(CWallet* const pwallet)
RPCExamples{
HelpExampleCli("protx", "revoke \"0123456701234567012345670123456701234567012345670123456701234567\" \"072f36a77261cdd5d64c32d97bac417540eddca1d5612f416feb07ff75a8e240\"")
},
}.ToString());
}.Check(request);
}
static UniValue protx_revoke(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || (request.params.size() < 3 || request.params.size() > 5)) {
protx_revoke_help(pwallet);
protx_revoke_help(request);
}
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
EnsureWalletIsUnlocked(pwallet);
CProUpRevTx ptx;
@ -911,9 +899,8 @@ static UniValue protx_revoke(const JSONRPCRequest& request)
}
#endif//ENABLE_WALLET
static void protx_list_help()
static void protx_list_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx list",
"\nLists all ProTxs in your wallet or on-chain, depending on the given type.\n",
{
@ -932,7 +919,7 @@ static void protx_list_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
#ifdef ENABLE_WALLET
@ -1003,14 +990,19 @@ static UniValue BuildDMNListEntry(CWallet* pwallet, const CDeterministicMN& dmn,
static UniValue protx_list(const JSONRPCRequest& request)
{
if (request.fHelp) {
protx_list_help();
protx_list_help(request);
}
CWallet* pwallet;
#ifdef ENABLE_WALLET
try {
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
pwallet = wallet.get();
} catch (...) {
pwallet = nullptr;
}
#else
CWallet* const pwallet = nullptr;
pwallet = nullptr;
#endif
std::string type = "registered";
@ -1032,7 +1024,7 @@ static UniValue protx_list(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
if (request.params.size() > 4) {
protx_list_help();
protx_list_help(request);
}
bool detailed = !request.params[2].isNull() ? ParseBoolV(request.params[2], "detailed") : false;
@ -1062,7 +1054,7 @@ static UniValue protx_list(const JSONRPCRequest& request)
#endif
} else if (type == "valid" || type == "registered") {
if (request.params.size() > 4) {
protx_list_help();
protx_list_help(request);
}
LOCK(cs_main);
@ -1086,9 +1078,8 @@ static UniValue protx_list(const JSONRPCRequest& request)
return ret;
}
static void protx_info_help()
static void protx_info_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx info",
"\nReturns detailed information about a deterministic masternode.\n",
{
@ -1101,20 +1092,25 @@ static void protx_info_help()
RPCExamples{
HelpExampleCli("protx", "info \"0123456701234567012345670123456701234567012345670123456701234567\"")
},
}.ToString());
}.Check(request);
}
static UniValue protx_info(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2) {
protx_info_help();
protx_info_help(request);
}
CWallet* pwallet;
#ifdef ENABLE_WALLET
try {
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
pwallet = wallet.get();
} catch (...) {
pwallet = nullptr;
}
#else
CWallet* const pwallet = nullptr;
pwallet = nullptr;
#endif
if (g_txindex) {
@ -1130,9 +1126,8 @@ static UniValue protx_info(const JSONRPCRequest& request)
return BuildDMNListEntry(pwallet, *dmn, true);
}
static void protx_diff_help()
static void protx_diff_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"protx diff",
"\nCalculates a diff between two deterministic masternode lists. The result also contains proof data.\n",
{
@ -1141,7 +1136,7 @@ static void protx_diff_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static uint256 ParseBlock(const UniValue& v, std::string strName) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
@ -1161,7 +1156,7 @@ static uint256 ParseBlock(const UniValue& v, std::string strName) EXCLUSIVE_LOCK
static UniValue protx_diff(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 3) {
protx_diff_help();
protx_diff_help(request);
}
LOCK(cs_main);
@ -1181,7 +1176,6 @@ static UniValue protx_diff(const JSONRPCRequest& request)
[[ noreturn ]] static void protx_help()
{
throw std::runtime_error(
RPCHelpMan{"protx",
"Set of commands to execute ProTx related actions.\n"
"To get help on individual commands, use \"help protx command\".\n"
@ -1205,7 +1199,7 @@ static UniValue protx_diff(const JSONRPCRequest& request)
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Throw();
}
static UniValue protx(const JSONRPCRequest& request)
@ -1243,28 +1237,27 @@ static UniValue protx(const JSONRPCRequest& request)
}
}
static void bls_generate_help()
static void bls_generate_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"bls generate",
"\nReturns a BLS secret/public key pair.\n",
{},
RPCResult{
"{\n"
" \"secret\": \"xxxx\", (string) BLS secret key\n"
" \"public\": \"xxxx\", (string) BLS public key\n"
" \"secret\" : \"xxxx\", (string) BLS secret key\n"
" \"public\" : \"xxxx\", (string) BLS public key\n"
"}\n"
},
RPCExamples{
HelpExampleCli("bls generate", "")
},
}.ToString());
}.Check(request);
}
static UniValue bls_generate(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 1) {
bls_generate_help();
bls_generate_help(request);
}
CBLSSecretKey sk;
@ -1276,9 +1269,8 @@ static UniValue bls_generate(const JSONRPCRequest& request)
return ret;
}
static void bls_fromsecret_help()
static void bls_fromsecret_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"bls fromsecret",
"\nParses a BLS secret key and returns the secret/public key pair.\n",
{
@ -1286,20 +1278,20 @@ static void bls_fromsecret_help()
},
RPCResult{
"{\n"
" \"secret\": \"xxxx\", (string) BLS secret key\n"
" \"public\": \"xxxx\", (string) BLS public key\n"
" \"secret\" : \"xxxx\", (string) BLS secret key\n"
" \"public\" : \"xxxx\", (string) BLS public key\n"
"}\n"
},
RPCExamples{
HelpExampleCli("bls fromsecret", "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")
},
}.ToString());
}.Check(request);
}
static UniValue bls_fromsecret(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 2) {
bls_fromsecret_help();
bls_fromsecret_help(request);
}
CBLSSecretKey sk;
@ -1315,7 +1307,6 @@ static UniValue bls_fromsecret(const JSONRPCRequest& request)
[[ noreturn ]] static void bls_help()
{
throw std::runtime_error(
RPCHelpMan{"bls",
"Set of commands to execute BLS related actions.\n"
"To get help on individual commands, use \"help bls command\".\n"
@ -1327,7 +1318,7 @@ static UniValue bls_fromsecret(const JSONRPCRequest& request)
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Throw();
}
static UniValue _bls(const JSONRPCRequest& request)

View File

@ -23,9 +23,8 @@ namespace llmq {
extern const std::string CLSIG_REQUESTID_PREFIX;
}
static void quorum_list_help()
static void quorum_list_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum list",
"List of on-chain quorums\n",
{
@ -44,13 +43,13 @@ static void quorum_list_help()
+ HelpExampleCli("quorum", "list 10")
+ HelpExampleRpc("quorum", "list, 10")
},
}.ToString());
}.Check(request);
}
static UniValue quorum_list(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2))
quorum_list_help();
quorum_list_help(request);
int count = -1;
if (!request.params[1].isNull()) {
@ -80,9 +79,8 @@ static UniValue quorum_list(const JSONRPCRequest& request)
return ret;
}
static void quorum_info_help()
static void quorum_info_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum info",
"Return information about a quorum\n",
{
@ -92,7 +90,7 @@ static void quorum_info_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue BuildQuorumInfo(const llmq::CQuorumCPtr& quorum, bool includeMembers, bool includeSkShare)
@ -134,7 +132,7 @@ static UniValue BuildQuorumInfo(const llmq::CQuorumCPtr& quorum, bool includeMem
static UniValue quorum_info(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 3 && request.params.size() != 4))
quorum_info_help();
quorum_info_help(request);
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[1], "llmqType");
if (!Params().HasLLMQ(llmqType)) {
@ -155,9 +153,8 @@ static UniValue quorum_info(const JSONRPCRequest& request)
return BuildQuorumInfo(quorum, true, includeSkShare);
}
static void quorum_dkgstatus_help()
static void quorum_dkgstatus_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum dkgstatus",
"Return the status of the current DKG process.\n"
"Works only when SPORK_17_QUORUM_DKG_ENABLED spork is ON.\n",
@ -168,13 +165,13 @@ static void quorum_dkgstatus_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue quorum_dkgstatus(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() < 1 || request.params.size() > 2)) {
quorum_dkgstatus_help();
quorum_dkgstatus_help(request);
}
int detailLevel = 0;
@ -241,9 +238,8 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request)
return ret;
}
static void quorum_memberof_help()
static void quorum_memberof_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum memberof",
"Checks which quorums the given masternode is a member of.\n",
{
@ -254,13 +250,13 @@ static void quorum_memberof_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue quorum_memberof(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() < 2 || request.params.size() > 3)) {
quorum_memberof_help();
quorum_memberof_help(request);
}
uint256 protxHash = ParseHashV(request.params[1], "proTxHash");
@ -302,9 +298,8 @@ static UniValue quorum_memberof(const JSONRPCRequest& request)
return result;
}
static void quorum_sign_help()
static void quorum_sign_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum sign",
"Threshold-sign a message\n",
{
@ -318,12 +313,11 @@ static void quorum_sign_help()
"\nReturns an object containing the signature share if this is false.\n"
},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static void quorum_verify_help()
static void quorum_verify_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum verify",
"Test if a quorum signature is valid for a request id and a message hash\n",
{
@ -340,12 +334,11 @@ static void quorum_verify_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static void quorum_hasrecsig_help()
static void quorum_hasrecsig_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum hasrecsig",
"Test if a valid recovered signature is present\n",
{
@ -355,12 +348,11 @@ static void quorum_hasrecsig_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static void quorum_getrecsig_help()
static void quorum_getrecsig_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum getrecsig",
"Get a recovered signature\n",
{
@ -370,12 +362,11 @@ static void quorum_getrecsig_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static void quorum_isconflicting_help()
static void quorum_isconflicting_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum isconflicting",
"Test if a conflict exists\n",
{
@ -385,7 +376,7 @@ static void quorum_isconflicting_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
@ -394,18 +385,18 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
if (request.fHelp || (request.params.size() != 4)) {
if (cmd == "sign") {
if ((request.params.size() < 4) || (request.params.size() > 6)) {
quorum_sign_help();
quorum_sign_help(request);
}
} else if (cmd == "verify") {
if (request.params.size() < 5 || request.params.size() > 7) {
quorum_verify_help();
quorum_verify_help(request);
}
} else if (cmd == "hasrecsig") {
quorum_hasrecsig_help();
quorum_hasrecsig_help(request);
} else if (cmd == "getrecsig") {
quorum_getrecsig_help();
quorum_getrecsig_help(request);
} else if (cmd == "isconflicting") {
quorum_isconflicting_help();
quorum_isconflicting_help(request);
} else {
// shouldn't happen as it's already handled by the caller
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid cmd");
@ -507,9 +498,8 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
}
}
static void quorum_selectquorum_help()
static void quorum_selectquorum_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum selectquorum",
"Returns the quorum that would/should sign a request\n",
{
@ -518,13 +508,13 @@ static void quorum_selectquorum_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue quorum_selectquorum(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() != 3) {
quorum_selectquorum_help();
quorum_selectquorum_help(request);
}
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[1], "llmqType");
@ -552,9 +542,8 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
return ret;
}
static void quorum_dkgsimerror_help()
static void quorum_dkgsimerror_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum dkgsimerror",
"This enables simulation of errors and malicious behaviour in the DKG. Do NOT use this on mainnet\n"
"as you will get yourself very likely PoSe banned for this.\n",
@ -564,13 +553,13 @@ static void quorum_dkgsimerror_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue quorum_dkgsimerror(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() != 3)) {
quorum_dkgsimerror_help();
quorum_dkgsimerror_help(request);
}
std::string type = request.params[1].get_str();
@ -585,9 +574,8 @@ static UniValue quorum_dkgsimerror(const JSONRPCRequest& request)
return UniValue();
}
static void quorum_getdata_help()
static void quorum_getdata_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"quorum getdata",
"Send a QGETDATA message to the specified peer.\n",
{
@ -603,13 +591,13 @@ static void quorum_getdata_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue quorum_getdata(const JSONRPCRequest& request)
{
if (request.fHelp || (request.params.size() < 5 || request.params.size() > 6)) {
quorum_getdata_help();
quorum_getdata_help(request);
}
NodeId nodeId = ParseInt64V(request.params[1], "nodeId");
@ -639,7 +627,6 @@ static UniValue quorum_getdata(const JSONRPCRequest& request)
[[ noreturn ]] static void quorum_help()
{
throw std::runtime_error(
RPCHelpMan{"quorum",
"Set of commands for quorums/LLMQs.\n"
"To get help on individual commands, use \"help quorum command\".\n"
@ -661,7 +648,7 @@ static UniValue quorum_getdata(const JSONRPCRequest& request)
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Throw();
}
static UniValue _quorum(const JSONRPCRequest& request)
@ -696,9 +683,8 @@ static UniValue _quorum(const JSONRPCRequest& request)
}
}
static void verifychainlock_help()
static void verifychainlock_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"verifychainlock",
"Test if a quorum signature is valid for a ChainLock.\n",
{
@ -708,13 +694,13 @@ static void verifychainlock_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue verifychainlock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) {
verifychainlock_help();
verifychainlock_help(request);
}
const uint256 nBlockHash = ParseHashV(request.params[0], "blockHash");
@ -740,9 +726,8 @@ static UniValue verifychainlock(const JSONRPCRequest& request)
return llmq::CSigningManager::VerifyRecoveredSig(llmqType, nBlockHeight, nRequestId, nBlockHash, chainLockSig);
}
static void verifyislock_help()
static void verifyislock_help(const JSONRPCRequest& request)
{
throw std::runtime_error(
RPCHelpMan{"verifyislock",
"Test if a quorum signature is valid for an InstantSend Lock\n",
{
@ -753,13 +738,13 @@ static void verifyislock_help()
},
RPCResults{},
RPCExamples{""},
}.ToString());
}.Check(request);
}
static UniValue verifyislock(const JSONRPCRequest& request)
{
if (request.fHelp || request.params.size() < 3 || request.params.size() > 4) {
verifyislock_help();
verifyislock_help(request);
}
uint256 id = ParseHashV(request.params[0], "id");

View File

@ -161,7 +161,7 @@ UniValue help(const JSONRPCRequest& jsonRequest)
{"subcommand", RPCArg::Type::STR, /* default */ "all subcommands", "The subcommand to get help on. Please note that not all subcommands support this at the moment"},
},
RPCResult{
"\"text\" (string) The help text\n"
RPCResult::Type::STR, "", "The help text"
},
RPCExamples{""},
}.ToString()
@ -208,7 +208,7 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest)
"\nReturns the total uptime of the server.\n",
{},
RPCResult{
"ttt (numeric) The number of seconds that the server has been running\n"
RPCResult::Type::NUM, "", "The number of seconds that the server has been running"
},
RPCExamples{
HelpExampleCli("uptime", "")
@ -341,41 +341,6 @@ bool RPCIsInWarmup(std::string *outStatus)
return fRPCInWarmup;
}
void JSONRPCRequest::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") {
if (fLogIPs)
LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
this->authUser, this->peerAddr);
else
LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
}
// Parse params
UniValue valParams = find_value(request, "params");
if (valParams.isArray() || valParams.isObject())
params = valParams;
else if (valParams.isNull())
params = UniValue(UniValue::VARR);
else
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
}
bool IsDeprecatedRPCEnabled(const std::string& method)
{
const std::vector<std::string> enabled_methods = gArgs.GetArgs("-deprecatedrpc");

View File

@ -7,11 +7,13 @@
#define BITCOIN_RPC_SERVER_H
#include <amount.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <rpc/util.h>
#include <map>
#include <stdint.h>
#include <string>
#include <functional>
#include <univalue.h>
@ -23,21 +25,6 @@ namespace RPCServer
void OnStopped(std::function<void ()> slot);
}
class JSONRPCRequest
{
public:
UniValue id;
std::string strMethod;
UniValue params;
bool fHelp;
std::string URI;
std::string authUser;
std::string peerAddr;
JSONRPCRequest() : id(NullUniValue), params(NullUniValue), fHelp(false) {}
void parse(const UniValue& valRequest);
};
/** Query whether RPC is running */
bool IsRPCRunning();
@ -94,6 +81,7 @@ void RPCUnsetTimerInterface(RPCTimerInterface *iface);
void RPCRunLater(const std::string& name, std::function<void()> func, int64_t nSeconds);
typedef UniValue(*rpcfn_type)(const JSONRPCRequest& jsonRequest);
typedef RPCHelpMan (*RpcMethodFnType)();
class CRPCCommand
{
@ -110,6 +98,19 @@ public:
{
}
//! Simplified constructor taking plain RpcMethodFnType function pointer.
CRPCCommand(std::string category, std::string name_in, RpcMethodFnType fn, std::vector<std::string> args_in)
: CRPCCommand(
category,
fn().m_name,
[fn](const JSONRPCRequest& request, UniValue& result, bool) { result = fn().HandleRequest(request); return true; },
fn().GetArgNames(),
intptr_t(fn))
{
CHECK_NONFATAL(fn().m_name == name_in);
CHECK_NONFATAL(fn().GetArgNames() == args_in);
}
//! Simplified constructor taking plain rpcfn_type function pointer.
CRPCCommand(const char* category, const char* name, rpcfn_type fn, std::initializer_list<const char*> args)
: CRPCCommand(category, name,
@ -126,7 +127,7 @@ public:
};
/**
* Dash RPC command dispatcher.
* RPC command dispatcher.
*/
class CRPCTable
{

View File

@ -13,6 +13,9 @@
#include <tuple>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
InitInterfaces* g_rpc_interfaces = nullptr;
void RPCTypeCheck(const UniValue& params,
@ -263,13 +266,21 @@ unsigned int ParseConfirmTarget(const UniValue& value, unsigned int max_target)
return (unsigned int)target;
}
/**
* A pair of strings that can be aligned (through padding) with other Sections
* later on
*/
struct Section {
Section(const std::string& left, const std::string& right)
: m_left{left}, m_right{right} {}
const std::string m_left;
std::string m_left;
const std::string m_right;
};
/**
* Keeps track of RPCArgs by transforming them into sections for the purpose
* of serializing everything to a single string
*/
struct Sections {
std::vector<Section> m_sections;
size_t m_max_pad{0};
@ -280,16 +291,15 @@ struct Sections {
m_sections.push_back(s);
}
enum class OuterType {
ARR,
OBJ,
NAMED_ARG, // Only set on first recursion
};
void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NAMED_ARG)
/**
* Recursive helper to translate an RPCArg into sections
*/
void Push(const RPCArg& arg, const size_t current_indent = 5, const OuterType outer_type = OuterType::NONE)
{
const auto indent = std::string(current_indent, ' ');
const auto indent_next = std::string(current_indent + 2, ' ');
const bool push_name{outer_type == OuterType::OBJ}; // Dictionary keys must have a name
switch (arg.m_type) {
case RPCArg::Type::STR_HEX:
case RPCArg::Type::STR:
@ -297,12 +307,12 @@ struct Sections {
case RPCArg::Type::AMOUNT:
case RPCArg::Type::RANGE:
case RPCArg::Type::BOOL: {
if (outer_type == OuterType::NAMED_ARG) return; // Nothing more to do for non-recursive types on first recursion
if (outer_type == OuterType::NONE) return; // Nothing more to do for non-recursive types on first recursion
auto left = indent;
if (arg.m_type_str.size() != 0 && outer_type == OuterType::OBJ) {
left += "\"" + arg.m_name + "\": " + arg.m_type_str.at(0);
if (arg.m_type_str.size() != 0 && push_name) {
left += "\"" + arg.GetName() + "\": " + arg.m_type_str.at(0);
} else {
left += outer_type == OuterType::OBJ ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
left += push_name ? arg.ToStringObj(/* oneline */ false) : arg.ToString(/* oneline */ false);
}
left += ",";
PushSection({left, arg.ToDescriptionString()});
@ -310,40 +320,44 @@ struct Sections {
}
case RPCArg::Type::OBJ:
case RPCArg::Type::OBJ_USER_KEYS: {
const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString();
PushSection({indent + "{", right});
const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
PushSection({indent + (push_name ? "\"" + arg.GetName() + "\": " : "") + "{", right});
for (const auto& arg_inner : arg.m_inner) {
Push(arg_inner, current_indent + 2, OuterType::OBJ);
}
if (arg.m_type != RPCArg::Type::OBJ) {
PushSection({indent_next + "...", ""});
}
PushSection({indent + "}" + (outer_type != OuterType::NAMED_ARG ? "," : ""), ""});
PushSection({indent + "}" + (outer_type != OuterType::NONE ? "," : ""), ""});
break;
}
case RPCArg::Type::ARR: {
auto left = indent;
left += outer_type == OuterType::OBJ ? "\"" + arg.m_name + "\": " : "";
left += push_name ? "\"" + arg.GetName() + "\": " : "";
left += "[";
const auto right = outer_type == OuterType::NAMED_ARG ? "" : arg.ToDescriptionString();
const auto right = outer_type == OuterType::NONE ? "" : arg.ToDescriptionString();
PushSection({left, right});
for (const auto& arg_inner : arg.m_inner) {
Push(arg_inner, current_indent + 2, OuterType::ARR);
}
PushSection({indent_next + "...", ""});
PushSection({indent + "]" + (outer_type != OuterType::NAMED_ARG ? "," : ""), ""});
PushSection({indent + "]" + (outer_type != OuterType::NONE ? "," : ""), ""});
break;
}
// no default case, so the compiler can warn about missing cases
}
} // no default case, so the compiler can warn about missing cases
}
/**
* Concatenate all sections with proper padding
*/
std::string ToString() const
{
std::string ret;
const size_t pad = m_max_pad + 4;
for (const auto& s : m_sections) {
// The left part of a section is assumed to be a single line, usually it is the name of the JSON struct or a
// brace like {, }, [, or ]
CHECK_NONFATAL(s.m_left.find('\n') == std::string::npos);
if (s.m_right.empty()) {
ret += s.m_left;
ret += "\n";
@ -378,7 +392,11 @@ struct Sections {
};
RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples)
: RPCHelpMan{std::move(name), std::move(description), std::move(args), std::move(results), std::move(examples), nullptr} {}
RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun)
: m_name{std::move(name)},
m_fun{std::move(fun)},
m_description{std::move(description)},
m_args{std::move(args)},
m_results{std::move(results)},
@ -386,8 +404,12 @@ RPCHelpMan::RPCHelpMan(std::string name, std::string description, std::vector<RP
{
std::set<std::string> named_args;
for (const auto& arg : m_args) {
std::vector<std::string> names;
boost::split(names, arg.m_names, boost::is_any_of("|"));
// Should have unique named arguments
assert(named_args.insert(arg.m_name).second);
for (const std::string& name : names) {
CHECK_NONFATAL(named_args.insert(name).second);
}
}
}
@ -400,7 +422,13 @@ std::string RPCResults::ToDescriptionString() const
} else {
result += "\nResult (" + r.m_cond + "):\n";
}
if (r.m_legacy) {
result += r.m_result;
} else {
Sections sections;
r.ToSections(sections);
result += sections.ToString();
}
}
return result;
}
@ -421,6 +449,16 @@ bool RPCHelpMan::IsValidNumArgs(size_t num_args) const
}
return num_required_args <= num_args && num_args <= m_args.size();
}
std::vector<std::string> RPCHelpMan::GetArgNames() const
{
std::vector<std::string> ret;
for (const auto& arg : m_args) {
ret.emplace_back(arg.m_names);
}
return ret;
}
std::string RPCHelpMan::ToString() const
{
std::string ret;
@ -429,6 +467,7 @@ std::string RPCHelpMan::ToString() const
ret += m_name;
bool was_optional{false};
for (const auto& arg : m_args) {
if (arg.m_hidden) continue;
const bool optional = arg.IsOptional();
ret += " ";
if (optional) {
@ -450,11 +489,12 @@ std::string RPCHelpMan::ToString() const
Sections sections;
for (size_t i{0}; i < m_args.size(); ++i) {
const auto& arg = m_args.at(i);
if (arg.m_hidden) continue;
if (i == 0) ret += "\nArguments:\n";
// Push named argument name and description
sections.m_sections.emplace_back(std::to_string(i + 1) + ". " + arg.m_name, arg.ToDescriptionString());
sections.m_sections.emplace_back(std::to_string(i + 1) + ". " + arg.GetFirstName(), arg.ToDescriptionString());
sections.m_max_pad = std::max(sections.m_max_pad, sections.m_sections.back().m_left.size());
// Recursively push nested args
@ -471,6 +511,17 @@ std::string RPCHelpMan::ToString() const
return ret;
}
std::string RPCArg::GetFirstName() const
{
return m_names.substr(0, m_names.find("|"));
}
std::string RPCArg::GetName() const
{
CHECK_NONFATAL(std::string::npos == m_names.find("|"));
return m_names;
}
bool RPCArg::IsOptional() const
{
if (m_fallback.which() == 1) {
@ -518,9 +569,7 @@ std::string RPCArg::ToDescriptionString() const
ret += "json array";
break;
}
// no default case, so the compiler can warn about missing cases
}
} // no default case, so the compiler can warn about missing cases
}
if (m_fallback.which() == 1) {
ret += ", optional, default=" + boost::get<std::string>(m_fallback);
@ -538,20 +587,110 @@ std::string RPCArg::ToDescriptionString() const
ret += ", required";
break;
}
// no default case, so the compiler can warn about missing cases
}
} // no default case, so the compiler can warn about missing cases
}
ret += ")";
ret += m_description.empty() ? "" : " " + m_description;
return ret;
}
void RPCResult::ToSections(Sections& sections, const OuterType outer_type, const int current_indent) const
{
// Indentation
const std::string indent(current_indent, ' ');
const std::string indent_next(current_indent + 2, ' ');
// Elements in a JSON structure (dictionary or array) are separated by a comma
const std::string maybe_separator{outer_type != OuterType::NONE ? "," : ""};
// The key name if recursed into an dictionary
const std::string maybe_key{
outer_type == OuterType::OBJ ?
"\"" + this->m_key_name + "\" : " :
""};
// Format description with type
const auto Description = [&](const std::string& type) {
return "(" + type + (this->m_optional ? ", optional" : "") + ")" +
(this->m_description.empty() ? "" : " " + this->m_description);
};
switch (m_type) {
case Type::ELISION: {
// If the inner result is empty, use three dots for elision
sections.PushSection({indent_next + "...", m_description});
return;
}
case Type::NONE: {
sections.PushSection({indent + "None", Description("json null")});
return;
}
case Type::STR: {
sections.PushSection({indent + maybe_key + "\"str\"" + maybe_separator, Description("string")});
return;
}
case Type::STR_AMOUNT: {
sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
return;
}
case Type::STR_HEX: {
sections.PushSection({indent + maybe_key + "\"hex\"" + maybe_separator, Description("string")});
return;
}
case Type::NUM: {
sections.PushSection({indent + maybe_key + "n" + maybe_separator, Description("numeric")});
return;
}
case Type::NUM_TIME: {
sections.PushSection({indent + maybe_key + "xxx" + maybe_separator, Description("numeric")});
return;
}
case Type::BOOL: {
sections.PushSection({indent + maybe_key + "true|false" + maybe_separator, Description("boolean")});
return;
}
case Type::ARR_FIXED:
case Type::ARR: {
sections.PushSection({indent + maybe_key + "[", Description("json array")});
for (const auto& i : m_inner) {
i.ToSections(sections, OuterType::ARR, current_indent + 2);
}
if (m_type == Type::ARR) {
sections.PushSection({indent_next + "...", ""});
} else {
CHECK_NONFATAL(!m_inner.empty());
// Remove final comma, which would be invalid JSON
sections.m_sections.back().m_left.pop_back();
}
sections.PushSection({indent + "]" + maybe_separator, ""});
return;
}
case Type::OBJ_DYN:
case Type::OBJ: {
sections.PushSection({indent + maybe_key + "{", Description("json object")});
for (const auto& i : m_inner) {
i.ToSections(sections, OuterType::OBJ, current_indent + 2);
}
if (m_type == Type::OBJ_DYN) {
// If the dictionary keys are dynamic, use three dots for continuation
sections.PushSection({indent_next + "...", ""});
} else {
CHECK_NONFATAL(!m_inner.empty());
// Remove final comma, which would be invalid JSON
sections.m_sections.back().m_left.pop_back();
}
sections.PushSection({indent + "}" + maybe_separator, ""});
return;
}
} // no default case, so the compiler can warn about missing cases
CHECK_NONFATAL(false);
}
std::string RPCArg::ToStringObj(const bool oneline) const
{
std::string res;
res += "\"";
res += m_name;
res += GetFirstName();
if (oneline) {
res += "\":";
} else {
@ -579,11 +718,9 @@ std::string RPCArg::ToStringObj(const bool oneline) const
case Type::OBJ:
case Type::OBJ_USER_KEYS:
// Currently unused, so avoid writing dead code
assert(false);
// no default case, so the compiler can warn about missing cases
}
assert(false);
CHECK_NONFATAL(false);
} // no default case, so the compiler can warn about missing cases
CHECK_NONFATAL(false);
}
std::string RPCArg::ToString(const bool oneline) const
@ -593,13 +730,13 @@ std::string RPCArg::ToString(const bool oneline) const
switch (m_type) {
case Type::STR_HEX:
case Type::STR: {
return "\"" + m_name + "\"";
return "\"" + GetFirstName() + "\"";
}
case Type::NUM:
case Type::RANGE:
case Type::AMOUNT:
case Type::BOOL: {
return m_name;
return GetFirstName();
}
case Type::OBJ:
case Type::OBJ_USER_KEYS: {
@ -621,10 +758,8 @@ std::string RPCArg::ToString(const bool oneline) const
}
return "[" + res + "...]";
}
// no default case, so the compiler can warn about missing cases
}
assert(false);
} // no default case, so the compiler can warn about missing cases
CHECK_NONFATAL(false);
}
static std::pair<int64_t, int64_t> ParseRange(const UniValue& value)

View File

@ -6,11 +6,13 @@
#define BITCOIN_RPC_UTIL_H
#include <node/transaction.h>
#include <pubkey.h>
#include <protocol.h>
#include <pubkey.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <script/standard.h>
#include <univalue.h>
#include <util/check.h>
#include <util/strencodings.h>
#include <string>
@ -21,6 +23,7 @@
class CKeyStore;
class CPubKey;
class CScript;
struct Sections;
struct InitInterfaces;
//! Pointers to interfaces that need to be accessible from RPC methods. Due to
@ -90,6 +93,16 @@ UniValue GetServicesNames(ServiceFlags services);
//! Parse a JSON range specified as int64, or [int64, int64]
std::pair<int64_t, int64_t> ParseDescriptorRange(const UniValue& value);
/**
* Serializing JSON objects depends on the outer type. Only arrays and
* dictionaries can be nested in json. The top-level outer type is "NONE".
*/
enum class OuterType {
ARR,
OBJ,
NONE, // Only set on first recursion
};
struct RPCArg {
enum class Type {
OBJ,
@ -120,8 +133,9 @@ struct RPCArg {
OMITTED,
};
using Fallback = boost::variant<Optional, /* default value for optional args */ std::string>;
const std::string m_name; //!< The name of the arg (can be empty for inner args)
const std::string m_names; //!< The name of the arg (can be empty for inner args, can contain multiple aliases separated by | for named request arguments)
const Type m_type;
const bool m_hidden;
const std::vector<RPCArg> m_inner; //!< Only used for arrays or dicts
const Fallback m_fallback;
const std::string m_description;
@ -129,43 +143,52 @@ struct RPCArg {
const std::vector<std::string> m_type_str; //!< Should be empty unless it is supposed to override the auto-generated type strings. Vector length is either 0 or 2, m_type_str.at(0) will override the type of the value in a key-value pair, m_type_str.at(1) will override the type in the argument description.
RPCArg(
const std::string& name,
const Type& type,
const Fallback& fallback,
const std::string& description,
const std::string& oneline_description = "",
const std::vector<std::string>& type_str = {})
: m_name{name},
m_type{type},
m_fallback{fallback},
m_description{description},
m_oneline_description{oneline_description},
m_type_str{type_str}
const std::string name,
const Type type,
const Fallback fallback,
const std::string description,
const std::string oneline_description = "",
const std::vector<std::string> type_str = {},
const bool hidden = false)
: m_names{std::move(name)},
m_type{std::move(type)},
m_hidden{hidden},
m_fallback{std::move(fallback)},
m_description{std::move(description)},
m_oneline_description{std::move(oneline_description)},
m_type_str{std::move(type_str)}
{
assert(type != Type::ARR && type != Type::OBJ);
CHECK_NONFATAL(type != Type::ARR && type != Type::OBJ);
}
RPCArg(
const std::string& name,
const Type& type,
const Fallback& fallback,
const std::string& description,
const std::vector<RPCArg>& inner,
const std::string& oneline_description = "",
const std::vector<std::string>& type_str = {})
: m_name{name},
m_type{type},
m_inner{inner},
m_fallback{fallback},
m_description{description},
m_oneline_description{oneline_description},
m_type_str{type_str}
const std::string name,
const Type type,
const Fallback fallback,
const std::string description,
const std::vector<RPCArg> inner,
const std::string oneline_description = "",
const std::vector<std::string> type_str = {})
: m_names{std::move(name)},
m_type{std::move(type)},
m_hidden{false},
m_inner{std::move(inner)},
m_fallback{std::move(fallback)},
m_description{std::move(description)},
m_oneline_description{std::move(oneline_description)},
m_type_str{std::move(type_str)}
{
assert(type == Type::ARR || type == Type::OBJ);
CHECK_NONFATAL(type == Type::ARR || type == Type::OBJ);
}
bool IsOptional() const;
/** Return the first of all aliases */
std::string GetFirstName() const;
/** Return the name, throws when there are aliases */
std::string GetName() const;
/**
* Return the type string of the argument.
* Set oneline to allow it to be overridden by a custom oneline type string (m_oneline_description).
@ -184,21 +207,120 @@ struct RPCArg {
};
struct RPCResult {
enum class Type {
OBJ,
ARR,
STR,
NUM,
BOOL,
NONE,
STR_AMOUNT, //!< Special string to represent a floating point amount
STR_HEX, //!< Special string with only hex chars
OBJ_DYN, //!< Special dictionary with keys that are not literals
ARR_FIXED, //!< Special array that has a fixed number of entries
NUM_TIME, //!< Special numeric to denote unix epoch time
ELISION, //!< Special type to denote elision (...)
};
const Type m_type;
const std::string m_key_name; //!< Only used for dicts
const std::vector<RPCResult> m_inner; //!< Only used for arrays or dicts
const bool m_optional;
const std::string m_description;
const std::string m_cond;
const std::string m_result;
const bool m_legacy; //!< Used for legacy support
const std::string m_result; //!< Used for legacy support
explicit RPCResult(std::string result)
: m_cond{}, m_result{std::move(result)}
RPCResult(
const std::string cond,
const Type type,
const std::string m_key_name,
const bool optional,
const std::string description,
const std::vector<RPCResult> inner = {})
: m_type{std::move(type)},
m_key_name{std::move(m_key_name)},
m_inner{std::move(inner)},
m_optional{optional},
m_description{std::move(description)},
m_cond{std::move(cond)},
m_result{},
m_legacy{false}
{
assert(!m_result.empty());
CHECK_NONFATAL(!m_cond.empty());
const bool inner_needed{type == Type::ARR || type == Type::ARR_FIXED || type == Type::OBJ || type == Type::OBJ_DYN};
CHECK_NONFATAL(inner_needed != inner.empty());
}
// start legacy support logic
RPCResult(std::string cond, std::string result)
: m_cond{std::move(cond)}, m_result{std::move(result)}
: m_type{Type::NONE},
m_key_name{},
m_inner{},
m_optional{false},
m_description{},
m_cond{std::move(cond)},
m_result{std::move(result)},
m_legacy{true}
{
assert(!m_cond.empty());
assert(!m_result.empty());
CHECK_NONFATAL(!m_cond.empty());
CHECK_NONFATAL(!m_result.empty());
}
RPCResult(std::string result)
: m_type{Type::NONE},
m_key_name{},
m_inner{},
m_optional{false},
m_description{},
m_cond{},
m_result{std::move(result)},
m_legacy{true}
{
CHECK_NONFATAL(!m_result.empty());
}
// end legacy support logic
RPCResult(
const std::string cond,
const Type type,
const std::string m_key_name,
const std::string description,
const std::vector<RPCResult> inner = {})
: RPCResult{cond, type, m_key_name, false, description, inner} {}
RPCResult(
const Type type,
const std::string m_key_name,
const bool optional,
const std::string description,
const std::vector<RPCResult> inner = {})
: m_type{std::move(type)},
m_key_name{std::move(m_key_name)},
m_inner{std::move(inner)},
m_optional{optional},
m_description{std::move(description)},
m_cond{},
m_result{},
m_legacy{false}
{
const bool inner_needed{type == Type::ARR || type == Type::ARR_FIXED || type == Type::OBJ || type == Type::OBJ_DYN};
CHECK_NONFATAL(inner_needed != inner.empty());
}
RPCResult(
const Type type,
const std::string m_key_name,
const std::string description,
const std::vector<RPCResult> inner = {})
: RPCResult{type, m_key_name, false, description, inner} {}
/** Append the sections of the result. */
void ToSections(Sections& sections, OuterType outer_type = OuterType::NONE, const int current_indent = 0) const;
/** Return the type string of the result when it is in an object (dict). */
std::string ToStringObj() const;
/** Return the description string, including the result type. */
std::string ToDescriptionString() const;
};
struct RPCResults {
@ -239,13 +361,37 @@ class RPCHelpMan
{
public:
RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples);
using RPCMethodImpl = std::function<UniValue(const RPCHelpMan&, const JSONRPCRequest&)>;
RPCHelpMan(std::string name, std::string description, std::vector<RPCArg> args, RPCResults results, RPCExamples examples, RPCMethodImpl fun);
std::string ToString() const;
UniValue HandleRequest(const JSONRPCRequest& request)
{
Check(request);
return m_fun(*this, request);
}
/** If the supplied number of args is neither too small nor too high */
bool IsValidNumArgs(size_t num_args) const;
/**
* Check if the given request is valid according to this command or if
* the user is asking for help information, and throw help when appropriate.
*/
inline void Check(const JSONRPCRequest& request) const {
if (request.fHelp || !IsValidNumArgs(request.params.size())) {
throw std::runtime_error(ToString());
}
}
[[ noreturn ]] inline void Throw() const {
throw std::runtime_error(ToString());
}
std::vector<std::string> GetArgNames() const;
const std::string m_name;
private:
const std::string m_name;
const RPCMethodImpl m_fun;
const std::string m_description;
const std::vector<RPCArg> m_args;
const RPCResults m_results;

41
src/util/check.h Normal file
View File

@ -0,0 +1,41 @@
// Copyright (c) 2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UTIL_CHECK_H
#define BITCOIN_UTIL_CHECK_H
#include <tinyformat.h>
#include <stdexcept>
class NonFatalCheckError : public std::runtime_error
{
using std::runtime_error::runtime_error;
};
/**
* Throw a NonFatalCheckError when the condition evaluates to false
*
* This should only be used
* - where the condition is assumed to be true, not for error handling or validating user input
* - where a failure to fulfill the condition is recoverable and does not abort the program
*
* For example in RPC code, where it is undersirable to crash the whole program, this can be generally used to replace
* asserts or recoverable logic errors. A NonFatalCheckError in RPC code is caught and passed as a string to the RPC
* caller, which can then report the issue to the developers.
*/
#define CHECK_NONFATAL(condition) \
do { \
if (!(condition)) { \
throw NonFatalCheckError( \
strprintf("%s:%d (%s)\n" \
"Internal bug detected: '%s'\n" \
"You may report this issue here: %s\n", \
__FILE__, __LINE__, __func__, \
(#condition), \
PACKAGE_BUGREPORT)); \
} \
} while (false)
#endif // BITCOIN_UTIL_CHECK_H

View File

@ -83,12 +83,6 @@ static void RescanWallet(CWallet& wallet, const WalletRescanReserver& reserver,
UniValue importprivkey(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
RPCHelpMan{"importprivkey",
@ -116,6 +110,10 @@ UniValue importprivkey(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
}
@ -153,7 +151,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CHECK_NONFATAL(key.VerifyPubKey(pubkey));
CKeyID vchAddress = pubkey.GetID();
{
pwallet->MarkDirty();
@ -184,12 +182,6 @@ UniValue importprivkey(const JSONRPCRequest& request)
UniValue abortrescan(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() > 0)
throw std::runtime_error(
RPCHelpMan{"abortrescan",
@ -206,10 +198,14 @@ UniValue abortrescan(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
pwallet->AbortRescan();
return true;
}
}
static void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel);
static void ImportScript(CWallet * const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
@ -251,12 +247,6 @@ static void ImportAddress(CWallet * const pwallet, const CTxDestination& dest, c
UniValue importaddress(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw std::runtime_error(
RPCHelpMan{"importaddress",
@ -284,6 +274,9 @@ UniValue importaddress(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
std::string strLabel;
if (!request.params[1].isNull())
@ -343,12 +336,6 @@ UniValue importaddress(const JSONRPCRequest& request)
UniValue importprunedfunds(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 2)
throw std::runtime_error(
RPCHelpMan{"importprunedfunds",
@ -362,6 +349,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
}.ToString()
);
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
CMutableTransaction tx;
if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
@ -412,12 +403,6 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
UniValue removeprunedfunds(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"removeprunedfunds",
@ -433,6 +418,10 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@ -455,12 +444,6 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
UniValue importpubkey(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw std::runtime_error(
RPCHelpMan{"importpubkey",
@ -484,6 +467,9 @@ UniValue importpubkey(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
std::string strLabel;
if (!request.params[1].isNull())
@ -536,12 +522,6 @@ UniValue importpubkey(const JSONRPCRequest& request)
UniValue importwallet(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"importwallet",
@ -561,6 +541,10 @@ UniValue importwallet(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
if (pwallet->chain().havePruned()) {
// Exit early and print an error.
// If a block is pruned after this check, we will import the key(s),
@ -650,7 +634,7 @@ UniValue importwallet(const JSONRPCRequest& request)
std::string label = std::get<3>(key_tuple);
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CHECK_NONFATAL(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwallet->HaveKey(keyid)) {
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
@ -702,11 +686,6 @@ UniValue importwallet(const JSONRPCRequest& request)
UniValue importelectrumwallet(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
RPCHelpMan{"importselectrumwallet",
@ -726,6 +705,10 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
if (fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
@ -777,7 +760,7 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
continue;
}
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CHECK_NONFATAL(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwallet->HaveKey(keyid)) {
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
@ -809,7 +792,7 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
continue;
}
CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey));
CHECK_NONFATAL(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID();
if (pwallet->HaveKey(keyid)) {
pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
@ -853,12 +836,6 @@ UniValue importelectrumwallet(const JSONRPCRequest& request)
UniValue dumpprivkey(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"dumpprivkey",
@ -868,7 +845,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The dash address for the private key"},
},
RPCResult{
"\"key\" (string) The private key\n"
RPCResult::Type::STR, "key", "The private key"
},
RPCExamples{
HelpExampleCli("dumpprivkey", "\"myaddress\"")
@ -877,6 +854,10 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@ -900,11 +881,6 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
UniValue dumphdinfo(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
return NullUniValue;
if (request.fHelp || request.params.size() != 0)
throw std::runtime_error(
RPCHelpMan{"dumphdinfo",
@ -912,9 +888,9 @@ UniValue dumphdinfo(const JSONRPCRequest& request)
{},
RPCResult{
"{\n"
" \"hdseed\": \"seed\", (string) The HD seed (bip32, in hex)\n"
" \"mnemonic\": \"words\", (string) The mnemonic for this HD wallet (bip39, english words) \n"
" \"mnemonicpassphrase\": \"passphrase\", (string) The mnemonic passphrase for this HD wallet (bip39)\n"
" \"hdseed\" : \"seed\", (string) The HD seed (bip32, in hex)\n"
" \"mnemonic\" : \"words\", (string) The mnemonic for this HD wallet (bip39, english words) \n"
" \"mnemonicpassphrase\" : \"passphrase\", (string) The mnemonic passphrase for this HD wallet (bip39)\n"
"}\n"
},
RPCExamples{
@ -923,6 +899,10 @@ UniValue dumphdinfo(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
LOCK(pwallet->cs_wallet);
EnsureWalletIsUnlocked(pwallet);
@ -948,12 +928,6 @@ UniValue dumphdinfo(const JSONRPCRequest& request)
UniValue dumpwallet(const JSONRPCRequest& request)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
RPCHelpMan{"dumpwallet",
@ -966,7 +940,7 @@ UniValue dumpwallet(const JSONRPCRequest& request)
},
RPCResult{
"{ (json object)\n"
" \"keys\" : { (int) The number of keys contained in the wallet dump\n"
" \"keys\" : { (numeric) The number of keys contained in the wallet dump\n"
" \"filename\" : { (string) The filename with full absolute path\n"
" \"warning\" : { (string) A warning about not sharing the wallet dump with anyone\n"
"}\n"
@ -977,6 +951,10 @@ UniValue dumpwallet(const JSONRPCRequest& request)
},
}.ToString());
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
auto locked_chain = pwallet->chain().lock();
LockAnnotation lock(::cs_main);
LOCK(pwallet->cs_wallet);
@ -1153,7 +1131,7 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
}
case TX_SCRIPTHASH: {
if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH");
assert(script_ctx == ScriptContext::TOP);
CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
CScriptID id = CScriptID(uint160(solverdata[0]));
auto subscript = std::move(import_data.redeemscript); // Remove redeemscript from import_data to check for superfluous script later.
if (!subscript) return "missing redeemscript";
@ -1487,12 +1465,6 @@ static int64_t GetImportTimestamp(const UniValue& data, int64_t now)
UniValue importmulti(const JSONRPCRequest& mainRequest)
{
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
CWallet* const pwallet = wallet.get();
if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) {
return NullUniValue;
}
if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
throw std::runtime_error(
RPCHelpMan{"importmulti",
@ -1562,6 +1534,10 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
const UniValue& requests = mainRequest.params[0];
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
if (!wallet) return NullUniValue;
CWallet* const pwallet = wallet.get();
//Default options
bool fRescan = true;

File diff suppressed because it is too large Load Diff

View File

@ -31,9 +31,8 @@ void RegisterWalletRPCCommands(interfaces::Chain& chain, std::vector<std::unique
*/
std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request);
std::string HelpRequiringPassphrase(CWallet *);
std::string HelpRequiringPassphrase();
void EnsureWalletIsUnlocked(CWallet *);
bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
UniValue getaddressinfo(const JSONRPCRequest& request);
UniValue signrawtransactionwithwallet(const JSONRPCRequest& request);

View File

@ -21,14 +21,15 @@ UniValue getzmqnotifications(const JSONRPCRequest& request)
"\nReturns information about the active ZeroMQ notifications.\n",
{},
RPCResult{
"[\n"
" { (json object)\n"
" \"type\": \"pubhashtx\", (string) Type of notification\n"
" \"address\": \"...\", (string) Address of the publisher\n"
" \"hwm\": n (numeric) Outbound message high water mark\n"
" },\n"
" ...\n"
"]\n"
RPCResult::Type::ARR, "", "",
{
{RPCResult::Type::OBJ, "", "",
{
{RPCResult::Type::STR, "type", "Type of notification"},
{RPCResult::Type::STR, "address", "Address of the publisher"},
{RPCResult::Type::NUM, "hwm", "Outbound message high water mark"},
}},
}
},
RPCExamples{
HelpExampleCli("getzmqnotifications", "")

View File

@ -17,6 +17,8 @@ class HelpRpcTest(BitcoinTestFramework):
def run_test(self):
self.test_categories()
self.dump_help()
if self.is_wallet_compiled():
self.wallet_help()
def test_categories(self):
node = self.nodes[0]
@ -52,6 +54,11 @@ class HelpRpcTest(BitcoinTestFramework):
# Make sure the node can generate the help at runtime without crashing
f.write(self.nodes[0].help(call))
def wallet_help(self):
assert 'getnewaddress ( "label" )' in self.nodes[0].help('getnewaddress')
self.restart_node(0, extra_args=['-nowallet=1'])
assert 'getnewaddress ( "label" )' in self.nodes[0].help('getnewaddress')
if __name__ == '__main__':
HelpRpcTest().main()

View File

@ -23,6 +23,13 @@ class RpcMiscTest(BitcoinTestFramework):
def run_test(self):
node = self.nodes[0]
self.log.info("test CHECK_NONFATAL")
assert_raises_rpc_error(
-1,
"Internal bug detected: 'request.params.size() != 100'",
lambda: node.echo(*[0] * 100),
)
self.log.info("test getmemoryinfo")
memory = node.getmemoryinfo()['locked']
assert_greater_than(memory['used'], 0)

View File

@ -6,7 +6,7 @@
from decimal import Decimal
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_array_result
from test_framework.util import assert_array_result, assert_equal
class ListTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
@ -83,6 +83,8 @@ class ListTransactionsTest(BitcoinTestFramework):
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
self.nodes[1].generate(1)
self.sync_all()
assert_equal(len(self.nodes[0].listtransactions(label="watchonly", include_watchonly=True)), 1)
assert_equal(len(self.nodes[0].listtransactions(dummy="watchonly", include_watchonly=True)), 1)
assert len(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=False)) == 0
assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True),
{"category": "receive", "amount": Decimal("0.1")},

View File

@ -20,4 +20,15 @@ if [[ ${OUTPUT} != "" ]]; then
EXIT_CODE=1
fi
# Macro CHECK_NONFATAL(condition) should be used instead of assert for RPC code, where it
# is undesirable to crash the whole program. See: src/util/check.h
# src/rpc/server.cpp is excluded from this check since it's mostly meta-code.
OUTPUT=$(git grep -nE 'assert *\(.*\);' -- "src/rpc/" "src/wallet/rpc*" ":(exclude)src/rpc/server.cpp")
if [[ ${OUTPUT} != "" ]]; then
echo "CHECK_NONFATAL(condition) should be used instead of assert for RPC code."
echo
echo "${OUTPUT}"
EXIT_CODE=1
fi
exit ${EXIT_CODE}