diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/blockchain.cpp | 166 | ||||
-rw-r--r-- | src/rpc/client.cpp | 226 | ||||
-rw-r--r-- | src/rpc/client.h | 5 | ||||
-rw-r--r-- | src/rpc/mining.cpp | 68 | ||||
-rw-r--r-- | src/rpc/misc.cpp | 39 | ||||
-rw-r--r-- | src/rpc/net.cpp | 46 | ||||
-rw-r--r-- | src/rpc/rawtransaction.cpp | 62 | ||||
-rw-r--r-- | src/rpc/server.cpp | 65 | ||||
-rw-r--r-- | src/rpc/server.h | 1 |
9 files changed, 426 insertions, 252 deletions
diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 09671ea20e..bbcbde71cd 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -236,8 +236,8 @@ UniValue waitforblock(const JSONRPCRequest& request) "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n" "\nArguments:\n" - "1. blockhash to wait for (string)\n" - "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" + "1. \"blockhash\" (required, string) Block hash to wait for.\n" + "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" "\nResult:\n" "{ (json object)\n" " \"hash\" : { (string) The blockhash\n" @@ -274,12 +274,12 @@ UniValue waitforblockheight(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( - "waitforblockheight <blockheight> (timeout)\n" + "waitforblockheight <height> (timeout)\n" "\nWaits for (at least) block height and returns the height and hash\n" "of the current tip.\n" "\nReturns the current block on timeout or exit.\n" "\nArguments:\n" - "1. block height to wait for (int)\n" + "1. height (required, int) Block height to wait for (int)\n" "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" "\nResult:\n" "{ (json object)\n" @@ -331,18 +331,18 @@ UniValue getdifficulty(const JSONRPCRequest& request) std::string EntryDescriptionString() { - return " \"size\" : n, (numeric) transaction size in bytes\n" + return " \"size\" : n, (numeric) virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted.\n" " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" " \"modifiedfee\" : n, (numeric) transaction fee with fee deltas used for mining priority\n" " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" " \"height\" : n, (numeric) block height when transaction entered pool\n" - " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" - " \"currentpriority\" : n, (numeric) transaction priority now\n" + " \"startingpriority\" : n, (numeric) DEPRECATED. Priority when transaction entered pool\n" + " \"currentpriority\" : n, (numeric) DEPRECATED. Transaction priority now\n" " \"descendantcount\" : n, (numeric) number of in-mempool descendant transactions (including this one)\n" - " \"descendantsize\" : n, (numeric) size of in-mempool descendants (including this one)\n" + " \"descendantsize\" : n, (numeric) virtual transaction size of in-mempool descendants (including this one)\n" " \"descendantfees\" : n, (numeric) modified fees (see above) of in-mempool descendants (including this one)\n" " \"ancestorcount\" : n, (numeric) number of in-mempool ancestor transactions (including this one)\n" - " \"ancestorsize\" : n, (numeric) size of in-mempool ancestors (including this one)\n" + " \"ancestorsize\" : n, (numeric) virtual transaction size of in-mempool ancestors (including this one)\n" " \"ancestorfees\" : n, (numeric) modified fees (see above) of in-mempool ancestors (including this one)\n" " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" " \"transactionid\", (string) parent transaction id\n" @@ -418,7 +418,7 @@ UniValue getrawmempool(const JSONRPCRequest& request) "getrawmempool ( verbose )\n" "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" "\nArguments:\n" - "1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" "\nResult: (for verbose = false):\n" "[ (json array of string)\n" " \"transactionid\" (string) The transaction id\n" @@ -449,8 +449,8 @@ UniValue getmempoolancestors(const JSONRPCRequest& request) "getmempoolancestors txid (verbose)\n" "\nIf txid is in the mempool, returns all in-mempool ancestors.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" - "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" + "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" "\nResult (for verbose=false):\n" "[ (json array of strings)\n" " \"transactionid\" (string) The transaction id of an in-mempool ancestor transaction\n" @@ -513,8 +513,8 @@ UniValue getmempooldescendants(const JSONRPCRequest& request) "getmempooldescendants txid (verbose)\n" "\nIf txid is in the mempool, returns all in-mempool descendants.\n" "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" - "2. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" + "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" + "2. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" "\nResult (for verbose=false):\n" "[ (json array of strings)\n" " \"transactionid\" (string) The transaction id of an in-mempool descendant transaction\n" @@ -607,10 +607,10 @@ UniValue getblockhash(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "getblockhash index\n" - "\nReturns hash of block in best-block-chain at index provided.\n" + "getblockhash height\n" + "\nReturns hash of block in best-block-chain at height provided.\n" "\nArguments:\n" - "1. index (numeric, required) The block index\n" + "1. height (numeric, required) The height index\n" "\nResult:\n" "\"hash\" (string) The block hash\n" "\nExamples:\n" @@ -651,9 +651,9 @@ UniValue getblockheader(const JSONRPCRequest& request) " \"nonce\" : n, (numeric) The nonce\n" " \"bits\" : \"1d00ffff\", (string) The bits\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" " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" " \"nextblockhash\" : \"hash\", (string) The hash of the next block\n" - " \"chainwork\" : \"0000...1f3\" (string) Expected number of hashes required to produce the current chain (in hex)\n" "}\n" "\nResult (for verbose=false):\n" "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" @@ -691,19 +691,19 @@ UniValue getblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( - "getblock \"hash\" ( verbose )\n" + "getblock \"blockhash\" ( verbose )\n" "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash'.\n" "If verbose is true, returns an Object with information about block <hash>.\n" "\nArguments:\n" - "1. \"hash\" (string, required) The block hash\n" - "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" + "1. \"blockhash\" (string, required) The block hash\n" + "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" "\nResult (for verbose = true):\n" "{\n" " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" " \"size\" : n, (numeric) The block size\n" " \"strippedsize\" : n, (numeric) The block size excluding witness data\n" - " \"weight\" : n (numeric) The block weight (BIP 141)\n" + " \"weight\" : n (numeric) The block weight as defined in BIP 141\n" " \"height\" : n, (numeric) The block height or index\n" " \"version\" : n, (numeric) The block version\n" " \"versionHex\" : \"00000000\", (string) The block version formatted in hexadecimal\n" @@ -814,6 +814,53 @@ static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats) return true; } +UniValue pruneblockchain(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 1) + throw runtime_error( + "pruneblockchain\n" + "\nArguments:\n" + "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or to a unix timestamp to prune based on block time.\n" + "\nResult:\n" + "n (numeric) Height of the last block pruned.\n" + "\nExamples:\n" + + HelpExampleCli("pruneblockchain", "1000") + + HelpExampleRpc("pruneblockchain", "1000")); + + if (!fPruneMode) + throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Cannot prune blocks because node is not in prune mode."); + + LOCK(cs_main); + + int heightParam = request.params[0].get_int(); + if (heightParam < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height."); + + // Height value more than a billion is too high to be a block height, and + // too low to be a block time (corresponds to timestamp from Sep 2001). + if (heightParam > 1000000000) { + CBlockIndex* pindex = chainActive.FindLatestBefore(heightParam); + if (!pindex) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not find block before specified timestamp."); + } + heightParam = pindex->nHeight; + } + + unsigned int height = (unsigned int) heightParam; + unsigned int chainHeight = (unsigned int) chainActive.Height(); + if (chainHeight < Params().PruneAfterHeight()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Blockchain is too short for pruning."); + else if (height > chainHeight) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height."); + else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) { + LogPrint("rpc", "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks."); + height = chainHeight - MIN_BLOCKS_TO_KEEP; + } + + PruneBlockFilesManual(height); + return uint64_t(height); +} + UniValue gettxoutsetinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) @@ -858,12 +905,12 @@ UniValue gettxout(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) throw runtime_error( - "gettxout \"txid\" n ( includemempool )\n" + "gettxout \"txid\" n ( include_mempool )\n" "\nReturns details about an unspent transaction output.\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "2. n (numeric, required) vout number\n" - "3. includemempool (boolean, optional) Whether to include the mempool\n" + "3. include_mempool (boolean, optional) Whether to include the mempool\n" "\nResult:\n" "{\n" " \"bestblock\" : \"hash\", (string) the block hash\n" @@ -875,7 +922,7 @@ UniValue gettxout(const JSONRPCRequest& request) " \"reqSigs\" : n, (numeric) Number of required signatures\n" " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n" " \"addresses\" : [ (array of string) array of bitcoin addresses\n" - " \"bitcoinaddress\" (string) bitcoin address\n" + " \"address\" (string) bitcoin address\n" " ,...\n" " ]\n" " },\n" @@ -940,11 +987,11 @@ UniValue verifychain(const JSONRPCRequest& request) int nCheckDepth = GetArg("-checkblocks", DEFAULT_CHECKBLOCKS); if (request.fHelp || request.params.size() > 2) throw runtime_error( - "verifychain ( checklevel numblocks )\n" + "verifychain ( checklevel nblocks )\n" "\nVerifies blockchain database.\n" "\nArguments:\n" "1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n" - "2. numblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n" + "2. nblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n" "\nResult:\n" "true|false (boolean) Verified or not\n" "\nExamples:\n" @@ -1240,7 +1287,7 @@ UniValue getmempoolinfo(const JSONRPCRequest& request) "\nResult:\n" "{\n" " \"size\": xxxxx, (numeric) Current tx count\n" - " \"bytes\": xxxxx, (numeric) Sum of all tx sizes\n" + " \"bytes\": xxxxx, (numeric) Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted\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 for tx to be accepted\n" @@ -1257,12 +1304,12 @@ UniValue preciousblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "preciousblock \"hash\"\n" + "preciousblock \"blockhash\"\n" "\nTreats a block as if it were received before others with the same work.\n" "\nA later preciousblock call can override the effect of an earlier one.\n" "\nThe effects of preciousblock are not retained across restarts.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to mark as precious\n" + "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("preciousblock", "\"blockhash\"") @@ -1295,10 +1342,10 @@ UniValue invalidateblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "invalidateblock \"hash\"\n" + "invalidateblock \"blockhash\"\n" "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to mark as invalid\n" + "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("invalidateblock", "\"blockhash\"") @@ -1333,11 +1380,11 @@ UniValue reconsiderblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "reconsiderblock \"hash\"\n" + "reconsiderblock \"blockhash\"\n" "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n" "\nArguments:\n" - "1. hash (string, required) the hash of the block to reconsider\n" + "1. \"blockhash\" (string, required) the hash of the block to reconsider\n" "\nResult:\n" "\nExamples:\n" + HelpExampleCli("reconsiderblock", "\"blockhash\"") @@ -1367,33 +1414,34 @@ UniValue reconsiderblock(const JSONRPCRequest& request) } static const CRPCCommand commands[] = -{ // category name actor (function) okSafeMode - // --------------------- ------------------------ ----------------------- ---------- - { "blockchain", "getblockchaininfo", &getblockchaininfo, true }, - { "blockchain", "getbestblockhash", &getbestblockhash, true }, - { "blockchain", "getblockcount", &getblockcount, true }, - { "blockchain", "getblock", &getblock, true }, - { "blockchain", "getblockhash", &getblockhash, true }, - { "blockchain", "getblockheader", &getblockheader, true }, - { "blockchain", "getchaintips", &getchaintips, true }, - { "blockchain", "getdifficulty", &getdifficulty, true }, - { "blockchain", "getmempoolancestors", &getmempoolancestors, true }, - { "blockchain", "getmempooldescendants", &getmempooldescendants, true }, - { "blockchain", "getmempoolentry", &getmempoolentry, true }, - { "blockchain", "getmempoolinfo", &getmempoolinfo, true }, - { "blockchain", "getrawmempool", &getrawmempool, true }, - { "blockchain", "gettxout", &gettxout, true }, - { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true }, - { "blockchain", "verifychain", &verifychain, true }, - - { "blockchain", "preciousblock", &preciousblock, true }, +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ ---------- + { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} }, + { "blockchain", "getbestblockhash", &getbestblockhash, true, {} }, + { "blockchain", "getblockcount", &getblockcount, true, {} }, + { "blockchain", "getblock", &getblock, true, {"blockhash","verbose"} }, + { "blockchain", "getblockhash", &getblockhash, true, {"height"} }, + { "blockchain", "getblockheader", &getblockheader, true, {"blockhash","verbose"} }, + { "blockchain", "getchaintips", &getchaintips, true, {} }, + { "blockchain", "getdifficulty", &getdifficulty, true, {} }, + { "blockchain", "getmempoolancestors", &getmempoolancestors, true, {"txid","verbose"} }, + { "blockchain", "getmempooldescendants", &getmempooldescendants, true, {"txid","verbose"} }, + { "blockchain", "getmempoolentry", &getmempoolentry, true, {"txid"} }, + { "blockchain", "getmempoolinfo", &getmempoolinfo, true, {} }, + { "blockchain", "getrawmempool", &getrawmempool, true, {"verbose"} }, + { "blockchain", "gettxout", &gettxout, true, {"txid","n","include_mempool"} }, + { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, {} }, + { "blockchain", "pruneblockchain", &pruneblockchain, true, {"height"} }, + { "blockchain", "verifychain", &verifychain, true, {"checklevel","nblocks"} }, + + { "blockchain", "preciousblock", &preciousblock, true, {"blockhash"} }, /* Not shown in help */ - { "hidden", "invalidateblock", &invalidateblock, true }, - { "hidden", "reconsiderblock", &reconsiderblock, true }, - { "hidden", "waitfornewblock", &waitfornewblock, true }, - { "hidden", "waitforblock", &waitforblock, true }, - { "hidden", "waitforblockheight", &waitforblockheight, true }, + { "hidden", "invalidateblock", &invalidateblock, true, {"blockhash"} }, + { "hidden", "reconsiderblock", &reconsiderblock, true, {"blockhash"} }, + { "hidden", "waitfornewblock", &waitfornewblock, true, {"timeout"} }, + { "hidden", "waitforblock", &waitforblock, true, {"blockhash","timeout"} }, + { "hidden", "waitforblockheight", &waitforblockheight, true, {"height","timeout"} }, }; void RegisterBlockchainRPCCommands(CRPCTable &t) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index e094524bcb..5d3c458455 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -20,104 +20,121 @@ class CRPCConvertParam public: std::string methodName; //!< method whose params want conversion int paramIdx; //!< 0-based idx of param to convert + std::string paramName; //!< parameter name }; +/** + * Specifiy a (method, idx, name) here if the argument is a non-string RPC + * argument and needs to be converted from JSON. + * + * @note Parameter indexes start from 0. + */ static const CRPCConvertParam vRPCConvertParams[] = { - { "stop", 0 }, - { "setmocktime", 0 }, - { "generate", 0 }, - { "generate", 1 }, - { "generatetoaddress", 0 }, - { "generatetoaddress", 2 }, - { "getnetworkhashps", 0 }, - { "getnetworkhashps", 1 }, - { "sendtoaddress", 1 }, - { "sendtoaddress", 4 }, - { "settxfee", 0 }, - { "getreceivedbyaddress", 1 }, - { "getreceivedbyaccount", 1 }, - { "listreceivedbyaddress", 0 }, - { "listreceivedbyaddress", 1 }, - { "listreceivedbyaddress", 2 }, - { "listreceivedbyaccount", 0 }, - { "listreceivedbyaccount", 1 }, - { "listreceivedbyaccount", 2 }, - { "getbalance", 1 }, - { "getbalance", 2 }, - { "getblockhash", 0 }, - { "waitforblockheight", 0 }, - { "waitforblockheight", 1 }, - { "waitforblock", 1 }, - { "waitforblock", 2 }, - { "waitfornewblock", 0 }, - { "waitfornewblock", 1 }, - { "move", 2 }, - { "move", 3 }, - { "sendfrom", 2 }, - { "sendfrom", 3 }, - { "listtransactions", 1 }, - { "listtransactions", 2 }, - { "listtransactions", 3 }, - { "listaccounts", 0 }, - { "listaccounts", 1 }, - { "walletpassphrase", 1 }, - { "getblocktemplate", 0 }, - { "listsinceblock", 1 }, - { "listsinceblock", 2 }, - { "sendmany", 1 }, - { "sendmany", 2 }, - { "sendmany", 4 }, - { "addmultisigaddress", 0 }, - { "addmultisigaddress", 1 }, - { "createmultisig", 0 }, - { "createmultisig", 1 }, - { "listunspent", 0 }, - { "listunspent", 1 }, - { "listunspent", 2 }, - { "getblock", 1 }, - { "getblockheader", 1 }, - { "gettransaction", 1 }, - { "getrawtransaction", 1 }, - { "createrawtransaction", 0 }, - { "createrawtransaction", 1 }, - { "createrawtransaction", 2 }, - { "signrawtransaction", 1 }, - { "signrawtransaction", 2 }, - { "sendrawtransaction", 1 }, - { "fundrawtransaction", 1 }, - { "gettxout", 1 }, - { "gettxout", 2 }, - { "gettxoutproof", 0 }, - { "lockunspent", 0 }, - { "lockunspent", 1 }, - { "importprivkey", 2 }, - { "importaddress", 2 }, - { "importaddress", 3 }, - { "importpubkey", 2 }, - { "importmulti", 0 }, - { "importmulti", 1 }, - { "verifychain", 0 }, - { "verifychain", 1 }, - { "keypoolrefill", 0 }, - { "getrawmempool", 0 }, - { "estimatefee", 0 }, - { "estimatepriority", 0 }, - { "estimatesmartfee", 0 }, - { "estimatesmartpriority", 0 }, - { "prioritisetransaction", 1 }, - { "prioritisetransaction", 2 }, - { "setban", 2 }, - { "setban", 3 }, - { "setnetworkactive", 0 }, - { "getmempoolancestors", 1 }, - { "getmempooldescendants", 1 }, + { "setmocktime", 0, "timestamp" }, + { "generate", 0, "nblocks" }, + { "generate", 1, "maxtries" }, + { "generatetoaddress", 0, "nblocks" }, + { "generatetoaddress", 2, "maxtries" }, + { "getnetworkhashps", 0, "nblocks" }, + { "getnetworkhashps", 1, "height" }, + { "sendtoaddress", 1, "amount" }, + { "sendtoaddress", 4, "subtractfeefromamount" }, + { "settxfee", 0, "amount" }, + { "getreceivedbyaddress", 1, "minconf" }, + { "getreceivedbyaccount", 1, "minconf" }, + { "listreceivedbyaddress", 0, "minconf" }, + { "listreceivedbyaddress", 1, "include_empty" }, + { "listreceivedbyaddress", 2, "include_watchonly" }, + { "listreceivedbyaccount", 0, "minconf" }, + { "listreceivedbyaccount", 1, "include_empty" }, + { "listreceivedbyaccount", 2, "include_watchonly" }, + { "getbalance", 1, "minconf" }, + { "getbalance", 2, "include_watchonly" }, + { "getblockhash", 0, "height" }, + { "waitforblockheight", 0, "height" }, + { "waitforblockheight", 1, "timeout" }, + { "waitforblock", 1, "timeout" }, + { "waitfornewblock", 0, "timeout" }, + { "move", 2, "amount" }, + { "move", 3, "minconf" }, + { "sendfrom", 2, "amount" }, + { "sendfrom", 3, "minconf" }, + { "listtransactions", 1, "count" }, + { "listtransactions", 2, "skip" }, + { "listtransactions", 3, "include_watchonly" }, + { "listaccounts", 0, "minconf" }, + { "listaccounts", 1, "include_watchonly" }, + { "walletpassphrase", 1, "timeout" }, + { "getblocktemplate", 0, "template_request" }, + { "listsinceblock", 1, "target_confirmations" }, + { "listsinceblock", 2, "include_watchonly" }, + { "sendmany", 1, "amounts" }, + { "sendmany", 2, "minconf" }, + { "sendmany", 4, "subtractfeefrom" }, + { "addmultisigaddress", 0, "nrequired" }, + { "addmultisigaddress", 1, "keys" }, + { "createmultisig", 0, "nrequired" }, + { "createmultisig", 1, "keys" }, + { "listunspent", 0, "minconf" }, + { "listunspent", 1, "maxconf" }, + { "listunspent", 2, "addresses" }, + { "getblock", 1, "verbose" }, + { "getblockheader", 1, "verbose" }, + { "gettransaction", 1, "include_watchonly" }, + { "getrawtransaction", 1, "verbose" }, + { "createrawtransaction", 0, "transactions" }, + { "createrawtransaction", 1, "outputs" }, + { "createrawtransaction", 2, "locktime" }, + { "signrawtransaction", 1, "prevtxs" }, + { "signrawtransaction", 2, "privkeys" }, + { "sendrawtransaction", 1, "allowhighfees" }, + { "fundrawtransaction", 1, "options" }, + { "gettxout", 1, "n" }, + { "gettxout", 2, "include_mempool" }, + { "gettxoutproof", 0, "txids" }, + { "lockunspent", 0, "unlock" }, + { "lockunspent", 1, "transactions" }, + { "importprivkey", 2, "rescan" }, + { "importaddress", 2, "rescan" }, + { "importaddress", 3, "p2sh" }, + { "importpubkey", 2, "rescan" }, + { "importmulti", 0, "requests" }, + { "importmulti", 1, "options" }, + { "verifychain", 0, "checklevel" }, + { "verifychain", 1, "nblocks" }, + { "pruneblockchain", 0, "height" }, + { "keypoolrefill", 0, "newsize" }, + { "getrawmempool", 0, "verbose" }, + { "estimatefee", 0, "nblocks" }, + { "estimatepriority", 0, "nblocks" }, + { "estimatesmartfee", 0, "nblocks" }, + { "estimatesmartpriority", 0, "nblocks" }, + { "prioritisetransaction", 1, "priority_delta" }, + { "prioritisetransaction", 2, "fee_delta" }, + { "setban", 2, "bantime" }, + { "setban", 3, "absolute" }, + { "setnetworkactive", 0, "state" }, + { "getmempoolancestors", 1, "verbose" }, + { "getmempooldescendants", 1, "verbose" }, + // Echo with conversion (For testing only) + { "echojson", 0, "arg0" }, + { "echojson", 1, "arg1" }, + { "echojson", 2, "arg2" }, + { "echojson", 3, "arg3" }, + { "echojson", 4, "arg4" }, + { "echojson", 5, "arg5" }, + { "echojson", 6, "arg6" }, + { "echojson", 7, "arg7" }, + { "echojson", 8, "arg8" }, + { "echojson", 9, "arg9" }, }; class CRPCConvertTable { private: - std::set<std::pair<std::string, int> > members; + std::set<std::pair<std::string, int>> members; + std::set<std::pair<std::string, std::string>> membersByName; public: CRPCConvertTable(); @@ -125,6 +142,9 @@ public: bool convert(const std::string& method, int idx) { return (members.count(std::make_pair(method, idx)) > 0); } + bool convert(const std::string& method, const std::string& name) { + return (membersByName.count(std::make_pair(method, name)) > 0); + } }; CRPCConvertTable::CRPCConvertTable() @@ -135,6 +155,8 @@ CRPCConvertTable::CRPCConvertTable() for (unsigned int i = 0; i < n_elem; i++) { members.insert(std::make_pair(vRPCConvertParams[i].methodName, vRPCConvertParams[i].paramIdx)); + membersByName.insert(std::make_pair(vRPCConvertParams[i].methodName, + vRPCConvertParams[i].paramName)); } } @@ -152,7 +174,6 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal) return jVal[0]; } -/** Convert strings to command-specific RPC representation */ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams) { UniValue params(UniValue::VARR); @@ -171,3 +192,28 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s return params; } + +UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams) +{ + UniValue params(UniValue::VOBJ); + + for (const std::string &s: strParams) { + size_t pos = s.find("="); + if (pos == std::string::npos) { + throw(std::runtime_error("No '=' in named argument '"+s+"', this needs to be present for every argument (even if it is empty)")); + } + + std::string name = s.substr(0, pos); + std::string value = s.substr(pos+1); + + if (!rpcCvtTable.convert(strMethod, name)) { + // insert string value directly + params.pushKV(name, value); + } else { + // parse string as JSON, insert bool/number/object/etc. value + params.pushKV(name, ParseNonRFCJSONValue(value)); + } + } + + return params; +} diff --git a/src/rpc/client.h b/src/rpc/client.h index cb7c12b129..e7cf035d8f 100644 --- a/src/rpc/client.h +++ b/src/rpc/client.h @@ -8,7 +8,12 @@ #include <univalue.h> +/** Convert positional arguments to command-specific RPC representation */ UniValue RPCConvertValues(const std::string& strMethod, const std::vector<std::string>& strParams); + +/** Convert named arguments to command-specific RPC representation */ +UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector<std::string>& strParams); + /** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null) * as well as objects and arrays. */ diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index fa79d20734..e46f55a8aa 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -78,13 +78,13 @@ UniValue getnetworkhashps(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 2) throw runtime_error( - "getnetworkhashps ( blocks height )\n" + "getnetworkhashps ( nblocks height )\n" "\nReturns the estimated network hashes per second based on the last n blocks.\n" "Pass in [blocks] to override # of blocks, -1 specifies since last difficulty change.\n" "Pass in [height] to estimate the network speed at the time when a certain block was found.\n" "\nArguments:\n" - "1. blocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n" - "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" + "1. nblocks (numeric, optional, default=120) The number of blocks, or -1 for blocks since last difficulty change.\n" + "2. height (numeric, optional, default=-1) To estimate at the time of the given height.\n" "\nResult:\n" "x (numeric) Hashes per second estimated\n" "\nExamples:\n" @@ -150,10 +150,10 @@ UniValue generate(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( - "generate numblocks ( maxtries )\n" - "\nMine up to numblocks blocks immediately (before the RPC call returns)\n" + "generate nblocks ( maxtries )\n" + "\nMine up to nblocks blocks immediately (before the RPC call returns)\n" "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" + "1. nblocks (numeric, required) How many blocks are generated immediately.\n" "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" "\nResult:\n" "[ blockhashes ] (array) hashes of blocks generated\n" @@ -186,11 +186,11 @@ UniValue generatetoaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) throw runtime_error( - "generatetoaddress numblocks address (maxtries)\n" + "generatetoaddress nblocks address (maxtries)\n" "\nMine blocks immediately to a specified address (before the RPC call returns)\n" "\nArguments:\n" - "1. numblocks (numeric, required) How many blocks are generated immediately.\n" - "2. address (string, required) The address to send the newly generated bitcoin to.\n" + "1. nblocks (numeric, required) How many blocks are generated immediately.\n" + "2. address (string, required) The address to send the newly generated bitcoin to.\n" "3. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" "\nResult:\n" "[ blockhashes ] (array) hashes of blocks generated\n" @@ -264,10 +264,10 @@ UniValue prioritisetransaction(const JSONRPCRequest& request) "Accepts the transaction into mined blocks at a higher (or lower) priority\n" "\nArguments:\n" "1. \"txid\" (string, required) The transaction id.\n" - "2. priority delta (numeric, required) The priority to add or subtract.\n" + "2. priority_delta (numeric, required) The priority to add or subtract.\n" " The transaction selection algorithm considers the tx as it would have a higher priority.\n" " (priority of a transaction is calculated: coinage * value_in_satoshis / txsize) \n" - "3. fee delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n" + "3. fee_delta (numeric, required) The fee value (in satoshis) to add (or subtract, if negative).\n" " The fee is not actually paid, only the algorithm for selecting transactions into a block\n" " considers the transaction as it would have paid a higher (or lower) fee.\n" "\nResult:\n" @@ -329,7 +329,7 @@ UniValue getblocktemplate(const JSONRPCRequest& request) " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n" "\nArguments:\n" - "1. TemplateRequest (json object, optional) A json object in the following spec\n" + "1. template_request (json object, optional) A json object in the following spec\n" " {\n" " \"mode\":\"template\" (string, optional) This must be set to \"template\", \"proposal\" (see BIP 23), or omitted\n" " \"capabilities\":[ (array, optional) A list of strings\n" @@ -717,9 +717,9 @@ UniValue submitblock(const JSONRPCRequest& request) "The 'jsonparametersobject' parameter is currently ignored.\n" "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" - "\nArguments:\n" - "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" - "2. \"jsonparametersobject\" (string, optional) object of optional parameters\n" + "\nArguments\n" + "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" + "2. \"parameters\" (string, optional) object of optional parameters\n" " {\n" " \"workid\" : \"id\" (string, optional) if the server provided a workid, it MUST be included with submissions\n" " }\n" @@ -779,9 +779,10 @@ UniValue estimatefee(const JSONRPCRequest& request) throw runtime_error( "estimatefee nblocks\n" "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within nblocks blocks.\n" + "confirmation within nblocks blocks. Uses virtual transaction size of transaction\n" + "as defined in BIP 141 (witness data is discounted).\n" "\nArguments:\n" - "1. nblocks (numeric)\n" + "1. nblocks (numeric, required)\n" "\nResult:\n" "n (numeric) estimated fee-per-kilobyte\n" "\n" @@ -814,7 +815,7 @@ UniValue estimatepriority(const JSONRPCRequest& request) "\nDEPRECATED. Estimates the approximate priority a zero-fee transaction needs to begin\n" "confirmation within nblocks blocks.\n" "\nArguments:\n" - "1. nblocks (numeric)\n" + "1. nblocks (numeric, required)\n" "\nResult:\n" "n (numeric) estimated priority\n" "\n" @@ -841,7 +842,8 @@ UniValue estimatesmartfee(const JSONRPCRequest& request) "\nWARNING: This interface is unstable and may disappear or change!\n" "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" "confirmation within nblocks blocks if possible and return the number of blocks\n" - "for which the estimate is valid.\n" + "for which the estimate is valid. Uses virtual transaction size as defined\n" + "in BIP 141 (witness data is discounted).\n" "\nArguments:\n" "1. nblocks (numeric)\n" "\nResult:\n" @@ -879,7 +881,7 @@ UniValue estimatesmartpriority(const JSONRPCRequest& request) "confirmation within nblocks blocks if possible and return the number of blocks\n" "for which the estimate is valid.\n" "\nArguments:\n" - "1. nblocks (numeric)\n" + "1. nblocks (numeric, required)\n" "\nResult:\n" "{\n" " \"priority\" : x.x, (numeric) estimated priority\n" @@ -908,19 +910,19 @@ UniValue estimatesmartpriority(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "mining", "getnetworkhashps", &getnetworkhashps, true }, - { "mining", "getmininginfo", &getmininginfo, true }, - { "mining", "prioritisetransaction", &prioritisetransaction, true }, - { "mining", "getblocktemplate", &getblocktemplate, true }, - { "mining", "submitblock", &submitblock, true }, - - { "generating", "generate", &generate, true }, - { "generating", "generatetoaddress", &generatetoaddress, true }, - - { "util", "estimatefee", &estimatefee, true }, - { "util", "estimatepriority", &estimatepriority, true }, - { "util", "estimatesmartfee", &estimatesmartfee, true }, - { "util", "estimatesmartpriority", &estimatesmartpriority, true }, + { "mining", "getnetworkhashps", &getnetworkhashps, true, {"nblocks","height"} }, + { "mining", "getmininginfo", &getmininginfo, true, {} }, + { "mining", "prioritisetransaction", &prioritisetransaction, true, {"txid","priority_delta","fee_delta"} }, + { "mining", "getblocktemplate", &getblocktemplate, true, {"template_request"} }, + { "mining", "submitblock", &submitblock, true, {"hexdata","parameters"} }, + + { "generating", "generate", &generate, true, {"nblocks","maxtries"} }, + { "generating", "generatetoaddress", &generatetoaddress, true, {"nblocks","address","maxtries"} }, + + { "util", "estimatefee", &estimatefee, true, {"nblocks"} }, + { "util", "estimatepriority", &estimatepriority, true, {"nblocks"} }, + { "util", "estimatesmartfee", &estimatesmartfee, true, {"nblocks"} }, + { "util", "estimatesmartpriority", &estimatesmartpriority, true, {"nblocks"} }, }; void RegisterMiningRPCCommands(CRPCTable &t) diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index f7c4ecc20c..54d8c3e035 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -152,14 +152,14 @@ UniValue validateaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "validateaddress \"bitcoinaddress\"\n" + "validateaddress \"address\"\n" "\nReturn information about the given bitcoin address.\n" "\nArguments:\n" - "1. \"bitcoinaddress\" (string, required) The bitcoin address to validate\n" + "1. \"address\" (string, required) The bitcoin address to validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" - " \"address\" : \"bitcoinaddress\", (string) The bitcoin address validated\n" + " \"address\" : \"address\", (string) The bitcoin address validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n" @@ -325,10 +325,10 @@ UniValue verifymessage(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 3) throw runtime_error( - "verifymessage \"bitcoinaddress\" \"signature\" \"message\"\n" + "verifymessage \"address\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" - "1. \"bitcoinaddress\" (string, required) The bitcoin address to use for the signature.\n" + "1. \"address\" (string, required) The bitcoin address to use for the signature.\n" "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" "3. \"message\" (string, required) The message that was signed.\n" "\nResult:\n" @@ -492,18 +492,33 @@ UniValue getmemoryinfo(const JSONRPCRequest& request) return obj; } +UniValue echo(const JSONRPCRequest& request) +{ + if (request.fHelp) + throw runtime_error( + "echo|echojson \"message\" ...\n" + "\nSimply echo back the input arguments. This command is for testing.\n" + "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in" + "bitcoin-cli and the GUI. There is no server-side difference." + ); + + return request.params; +} + static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "control", "getinfo", &getinfo, true }, /* uses wallet if enabled */ - { "control", "getmemoryinfo", &getmemoryinfo, true }, - { "util", "validateaddress", &validateaddress, true }, /* uses wallet if enabled */ - { "util", "createmultisig", &createmultisig, true }, - { "util", "verifymessage", &verifymessage, true }, - { "util", "signmessagewithprivkey", &signmessagewithprivkey, true }, + { "control", "getinfo", &getinfo, true, {} }, /* uses wallet if enabled */ + { "control", "getmemoryinfo", &getmemoryinfo, true, {} }, + { "util", "validateaddress", &validateaddress, true, {"address"} }, /* uses wallet if enabled */ + { "util", "createmultisig", &createmultisig, true, {"nrequired","keys"} }, + { "util", "verifymessage", &verifymessage, true, {"address","signature","message"} }, + { "util", "signmessagewithprivkey", &signmessagewithprivkey, true, {"privkey","message"} }, /* Not shown in help */ - { "hidden", "setmocktime", &setmocktime, true }, + { "hidden", "setmocktime", &setmocktime, true, {"timestamp"}}, + { "hidden", "echo", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, + { "hidden", "echojson", &echo, true, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, }; void RegisterMiscRPCCommands(CRPCTable &t) diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 632514fc85..27b9963a10 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -92,6 +92,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) " \"version\": v, (numeric) The peer version, such as 7001\n" " \"subver\": \"/Satoshi:0.8.5/\", (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 and is using an addnode slot\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" @@ -99,13 +100,14 @@ UniValue getpeerinfo(const JSONRPCRequest& request) " \"inflight\": [\n" " n, (numeric) The heights of blocks we're currently asking from this peer\n" " ...\n" - " ]\n" + " ],\n" + " \"whitelisted\": true|false, (boolean) Whether the peer is whitelisted\n" " \"bytessent_per_msg\": {\n" - " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n" + " \"addr\": n, (numeric) The total bytes sent aggregated by message type\n" " ...\n" - " }\n" + " },\n" " \"bytesrecv_per_msg\": {\n" - " \"addr\": n, (numeric) The total bytes received aggregated by message type\n" + " \"addr\": n, (numeric) The total bytes received aggregated by message type\n" " ...\n" " }\n" " }\n" @@ -152,6 +154,7 @@ UniValue getpeerinfo(const JSONRPCRequest& request) // their ver message. obj.push_back(Pair("subver", stats.cleanSubVer)); obj.push_back(Pair("inbound", stats.fInbound)); + obj.push_back(Pair("addnode", stats.fAddnode)); obj.push_back(Pair("startingheight", stats.nStartingHeight)); if (fStateStats) { obj.push_back(Pair("banscore", statestats.nMisbehavior)); @@ -409,6 +412,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request) " \"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" @@ -421,7 +425,7 @@ UniValue getnetworkinfo(const JSONRPCRequest& request) " }\n" " ,...\n" " ]\n" - " \"warnings\": \"...\" (string) any network warnings (such as alert messages) \n" + " \"warnings\": \"...\" (string) any network warnings\n" "}\n" "\nExamples:\n" + HelpExampleCli("getnetworkinfo", "") @@ -468,10 +472,10 @@ UniValue setban(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || (strCommand != "add" && strCommand != "remove")) throw runtime_error( - "setban \"ip(/netmask)\" \"add|remove\" (bantime) (absolute)\n" + "setban \"subnet\" \"add|remove\" (bantime) (absolute)\n" "\nAttempts add or remove a IP/Subnet from the banned list.\n" "\nArguments:\n" - "1. \"ip(/netmask)\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n" + "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes ip) with a optional netmask (default is /32 = single ip)\n" "2. \"command\" (string, required) 'add' to add a IP/Subnet to the list, 'remove' to remove a IP/Subnet from the list\n" "3. \"bantime\" (numeric, optional) time in seconds how long (or until when if [absolute] is set) the ip is banned (0 or empty means using the default time of 24h which can also be overwritten by the -bantime startup argument)\n" "4. \"absolute\" (boolean, optional) If set, the bantime must be a absolute timestamp in seconds since epoch (Jan 1 1970 GMT)\n" @@ -580,7 +584,9 @@ UniValue setnetworkactive(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) { throw runtime_error( "setnetworkactive true|false\n" - "Disable/enable all p2p network activity." + "\nDisable/enable all p2p network activity.\n" + "\nArguments:\n" + "1. \"state\" (boolean, required) true to enable networking, false to disable\n" ); } @@ -596,18 +602,18 @@ UniValue setnetworkactive(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "network", "getconnectioncount", &getconnectioncount, true }, - { "network", "ping", &ping, true }, - { "network", "getpeerinfo", &getpeerinfo, true }, - { "network", "addnode", &addnode, true }, - { "network", "disconnectnode", &disconnectnode, true }, - { "network", "getaddednodeinfo", &getaddednodeinfo, true }, - { "network", "getnettotals", &getnettotals, true }, - { "network", "getnetworkinfo", &getnetworkinfo, true }, - { "network", "setban", &setban, true }, - { "network", "listbanned", &listbanned, true }, - { "network", "clearbanned", &clearbanned, true }, - { "network", "setnetworkactive", &setnetworkactive, true, }, + { "network", "getconnectioncount", &getconnectioncount, true, {} }, + { "network", "ping", &ping, true, {} }, + { "network", "getpeerinfo", &getpeerinfo, true, {} }, + { "network", "addnode", &addnode, true, {"node","command"} }, + { "network", "disconnectnode", &disconnectnode, true, {"node"} }, + { "network", "getaddednodeinfo", &getaddednodeinfo, true, {"node"} }, + { "network", "getnettotals", &getnettotals, true, {} }, + { "network", "getnetworkinfo", &getnetworkinfo, true, {} }, + { "network", "setban", &setban, true, {"subnet", "command", "bantime", "absolute"} }, + { "network", "listbanned", &listbanned, true, {} }, + { "network", "clearbanned", &clearbanned, true, {} }, + { "network", "setnetworkactive", &setnetworkactive, true, {"state"} }, }; void RegisterNetRPCCommands(CRPCTable &t) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 276ebfda26..f328543323 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -128,9 +128,11 @@ UniValue getrawtransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw runtime_error( "getrawtransaction \"txid\" ( verbose )\n" - "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n" - "or there is an unspent output in the utxo for this transaction. To make it always work,\n" - "you need to maintain a transaction index, using the -txindex command line option.\n" + + "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" + "enabled, it also works for blockchain transactions.\n" + "DEPRECATED: for now, it also works for transactions with unspent outputs.\n" + "\nReturn the raw transaction data.\n" "\nIf verbose is 'true', returns an Object with information about 'txid'.\n" "If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.\n" @@ -174,7 +176,7 @@ UniValue getrawtransaction(const JSONRPCRequest& request) " \"reqSigs\" : n, (numeric) The required sigs\n" " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" " \"addresses\" : [ (json array of string)\n" - " \"bitcoinaddress\" (string) bitcoin address\n" + " \"address\" (string) bitcoin address\n" " ,...\n" " ]\n" " }\n" @@ -218,7 +220,9 @@ UniValue getrawtransaction(const JSONRPCRequest& request) CTransactionRef tx; uint256 hashBlock; if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock, true)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string(fTxIndex ? "No such mempool or blockchain transaction" + : "No such mempool transaction. Use -txindex to enable blockchain transaction queries") + + ". Use gettransaction for wallet transactions."); string strHex = EncodeHexTx(*tx, RPCSerializationFlags()); @@ -248,7 +252,7 @@ UniValue gettxoutproof(const JSONRPCRequest& request) " \"txid\" (string) A transaction hash\n" " ,...\n" " ]\n" - "2. \"block hash\" (string, optional) If specified, looks for txid in the block with this hash\n" + "2. \"blockhash\" (string, optional) If specified, looks for txid in the block with this hash\n" "\nResult:\n" "\"data\" (string) A string that is a serialized, hex-encoded data for the proof.\n" ); @@ -358,24 +362,24 @@ UniValue createrawtransaction(const JSONRPCRequest& request) "it is not stored in the wallet or transmitted to the network.\n" "\nArguments:\n" - "1. \"transactions\" (string, required) A json array of json objects\n" + "1. \"inputs\" (string, required) A json array of json objects\n" " [\n" " {\n" " \"txid\":\"id\", (string, required) The transaction id\n" - " \"vout\":n (numeric, required) The output number\n" - " \"sequence\":n (numeric, optional) The sequence number\n" - " }\n" + " \"vout\":n, (numeric, required) The output number\n" + " \"sequence\":n (numeric, optional) The sequence number\n" + " } \n" " ,...\n" " ]\n" - "2. \"outputs\" (string, required) a json object with outputs\n" + "2. \"outputs\" (string, required) a json object with outputs\n" " {\n" - " \"address\": x.xxx (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" - " \"data\": \"hex\", (string, required) The key is \"data\", the value is hex encoded data\n" - " ...\n" + " \"address\": x.xxx, (numeric or string, required) The key is the bitcoin address, the numeric value (can be string) is the " + CURRENCY_UNIT + " amount\n" + " \"data\": \"hex\" (string, required) The key is \"data\", the value is hex encoded data\n" + " ,...\n" " }\n" - "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" + "3. locktime (numeric, optional, default=0) Raw locktime. Non-0 value also locktime-activates inputs\n" "\nResult:\n" - "\"transaction\" (string) hex string of the transaction\n" + "\"transaction\" (string) hex string of the transaction\n" "\nExamples:\n" + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") @@ -467,7 +471,7 @@ UniValue decoderawtransaction(const JSONRPCRequest& request) "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" "\nArguments:\n" - "1. \"hex\" (string, required) The transaction hex string\n" + "1. \"hexstring\" (string, required) The transaction hex string\n" "\nResult:\n" "{\n" @@ -532,10 +536,10 @@ UniValue decodescript(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw runtime_error( - "decodescript \"hex\"\n" + "decodescript \"hexstring\"\n" "\nDecode a hex-encoded script.\n" "\nArguments:\n" - "1. \"hex\" (string) the hex encoded script\n" + "1. \"hexstring\" (string) the hex encoded script\n" "\nResult:\n" "{\n" " \"asm\":\"asm\", (string) Script public key\n" @@ -616,7 +620,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request) " }\n" " ,...\n" " ]\n" - "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n" + "3. \"privkeys\" (string, optional) A json array of base58-encoded private keys for signing\n" " [ (json array of strings, or 'null' if none provided)\n" " \"privatekey\" (string) private key in base58-encoding\n" " ,...\n" @@ -926,15 +930,15 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) static const CRPCCommand commands[] = { // category name actor (function) okSafeMode // --------------------- ------------------------ ----------------------- ---------- - { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, - { "rawtransactions", "createrawtransaction", &createrawtransaction, true }, - { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true }, - { "rawtransactions", "decodescript", &decodescript, true }, - { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, - { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ - - { "blockchain", "gettxoutproof", &gettxoutproof, true }, - { "blockchain", "verifytxoutproof", &verifytxoutproof, true }, + { "rawtransactions", "getrawtransaction", &getrawtransaction, true, {"txid","verbose"} }, + { "rawtransactions", "createrawtransaction", &createrawtransaction, true, {"transactions","outputs","locktime"} }, + { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, {"hexstring"} }, + { "rawtransactions", "decodescript", &decodescript, true, {"hexstring"} }, + { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, {"hexstring","allowhighfees"} }, + { "rawtransactions", "signrawtransaction", &signrawtransaction, false, {"hexstring","prevtxs","privkeys","sighashtype"} }, /* uses wallet if enabled */ + + { "blockchain", "gettxoutproof", &gettxoutproof, true, {"txids", "blockhash"} }, + { "blockchain", "verifytxoutproof", &verifytxoutproof, true, {"proof"} }, }; void RegisterRawTransactionRPCCommands(CRPCTable &t) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 8a223d8aa8..1b94e10071 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -26,6 +26,7 @@ #include <boost/algorithm/string/case_conv.hpp> // for to_upper() #include <memory> // for unique_ptr +#include <unordered_map> using namespace RPCServer; using namespace std; @@ -268,11 +269,11 @@ UniValue stop(const JSONRPCRequest& jsonRequest) * Call Table */ static const CRPCCommand vRPCCommands[] = -{ // category name actor (function) okSafeMode - // --------------------- ------------------------ ----------------------- ---------- +{ // category name actor (function) okSafe argNames + // --------------------- ------------------------ ----------------------- ------ ---------- /* Overall control/query calls */ - { "control", "help", &help, true }, - { "control", "stop", &stop, true }, + { "control", "help", &help, true, {"command"} }, + { "control", "stop", &stop, true, {} }, }; CRPCTable::CRPCTable() @@ -379,12 +380,12 @@ void JSONRPCRequest::parse(const UniValue& valRequest) // Parse params UniValue valParams = find_value(request, "params"); - if (valParams.isArray()) - params = valParams.get_array(); + 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"); + throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object"); } static UniValue JSONRPCExecOne(const UniValue& req) @@ -420,6 +421,48 @@ std::string JSONRPCExecBatch(const UniValue& vReq) return ret.write() + "\n"; } +/** + * Process named arguments into a vector of positional arguments, based on the + * passed-in specification for the RPC call's arguments. + */ +static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::string>& argNames) +{ + JSONRPCRequest out = in; + out.params = UniValue(UniValue::VARR); + // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if + // there is an unknown one. + const std::vector<std::string>& keys = in.params.getKeys(); + const std::vector<UniValue>& values = in.params.getValues(); + std::unordered_map<std::string, const UniValue*> argsIn; + for (size_t i=0; i<keys.size(); ++i) { + argsIn[keys[i]] = &values[i]; + } + // Process expected parameters. + int hole = 0; + for (const std::string &argName: argNames) { + auto fr = argsIn.find(argName); + if (fr != argsIn.end()) { + for (int i = 0; i < hole; ++i) { + // Fill hole between specified parameters with JSON nulls, + // but not at the end (for backwards compatibility with calls + // that act based on number of specified parameters). + out.params.push_back(UniValue()); + } + hole = 0; + out.params.push_back(*fr->second); + argsIn.erase(fr); + } else { + hole += 1; + } + } + // If there are still arguments in the argsIn map, this is an error. + if (!argsIn.empty()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Unknown named parameter " + argsIn.begin()->first); + } + // Return request with named arguments transformed to positional arguments + return out; +} + UniValue CRPCTable::execute(const JSONRPCRequest &request) const { // Return immediately if in warmup @@ -438,8 +481,12 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const try { - // Execute - return pcmd->actor(request); + // Execute, convert arguments to array if necessary + if (request.params.isObject()) { + return pcmd->actor(transformNamedArguments(request, pcmd->argNames)); + } else { + return pcmd->actor(request); + } } catch (const std::exception& e) { diff --git a/src/rpc/server.h b/src/rpc/server.h index f3cdf3c602..fed3d8c90f 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -136,6 +136,7 @@ public: std::string name; rpcfn_type actor; bool okSafeMode; + std::vector<std::string> argNames; }; /** |