2013-11-20 14:18:57 +01:00
|
|
|
// Copyright (c) 2010 Satoshi Nakamoto
|
2020-04-16 13:14:08 -04:00
|
|
|
// Copyright (c) 2009-2020 The Bitcoin Core developers
|
2014-11-20 10:19:29 +08:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
2013-11-20 14:18:57 +01:00
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
2017-11-10 13:57:53 +13:00
|
|
|
#include <rpc/client.h>
|
2018-10-22 15:51:11 -07:00
|
|
|
#include <util/system.h>
|
2013-11-20 14:18:57 +01:00
|
|
|
|
2014-09-14 12:43:56 +02:00
|
|
|
#include <set>
|
2013-11-20 14:18:57 +01:00
|
|
|
#include <stdint.h>
|
|
|
|
|
2014-06-26 22:12:36 -04:00
|
|
|
class CRPCConvertParam
|
2013-11-20 14:18:57 +01:00
|
|
|
{
|
2014-06-26 22:12:36 -04:00
|
|
|
public:
|
2016-04-03 11:49:36 +02:00
|
|
|
std::string methodName; //!< method whose params want conversion
|
|
|
|
int paramIdx; //!< 0-based idx of param to convert
|
2016-11-22 14:56:29 +01:00
|
|
|
std::string paramName; //!< parameter name
|
2014-06-26 22:12:36 -04:00
|
|
|
};
|
|
|
|
|
2018-08-20 14:19:43 +02:00
|
|
|
// clang-format off
|
2016-11-22 14:56:29 +01:00
|
|
|
/**
|
2017-02-06 15:16:18 +01:00
|
|
|
* Specify a (method, idx, name) here if the argument is a non-string RPC
|
2016-11-22 14:56:29 +01:00
|
|
|
* argument and needs to be converted from JSON.
|
|
|
|
*
|
|
|
|
* @note Parameter indexes start from 0.
|
|
|
|
*/
|
2014-06-26 22:12:36 -04:00
|
|
|
static const CRPCConvertParam vRPCConvertParams[] =
|
|
|
|
{
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "setmocktime", 0, "timestamp" },
|
2020-02-12 11:12:20 -08:00
|
|
|
{ "mockscheduler", 0, "delta_time" },
|
2019-07-02 18:34:18 +01:00
|
|
|
{ "utxoupdatepsbt", 1, "descriptors" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "generatetoaddress", 0, "nblocks" },
|
|
|
|
{ "generatetoaddress", 2, "maxtries" },
|
2019-09-23 14:27:23 -04:00
|
|
|
{ "generatetodescriptor", 0, "num_blocks" },
|
|
|
|
{ "generatetodescriptor", 2, "maxtries" },
|
2020-03-27 11:00:10 -04:00
|
|
|
{ "generateblock", 1, "transactions" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "getnetworkhashps", 0, "nblocks" },
|
|
|
|
{ "getnetworkhashps", 1, "height" },
|
|
|
|
{ "sendtoaddress", 1, "amount" },
|
|
|
|
{ "sendtoaddress", 4, "subtractfeefromamount" },
|
2017-06-14 15:15:40 -04:00
|
|
|
{ "sendtoaddress", 5 , "replaceable" },
|
|
|
|
{ "sendtoaddress", 6 , "conf_target" },
|
2018-09-11 15:53:36 +09:00
|
|
|
{ "sendtoaddress", 8, "avoid_reuse" },
|
2020-11-04 13:13:17 +01:00
|
|
|
{ "sendtoaddress", 9, "fee_rate"},
|
|
|
|
{ "sendtoaddress", 10, "verbose"},
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "settxfee", 0, "amount" },
|
2017-09-12 14:01:12 -07:00
|
|
|
{ "sethdseed", 0, "newkeypool" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "getreceivedbyaddress", 1, "minconf" },
|
2017-10-20 13:27:55 -04:00
|
|
|
{ "getreceivedbylabel", 1, "minconf" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "listreceivedbyaddress", 0, "minconf" },
|
|
|
|
{ "listreceivedbyaddress", 1, "include_empty" },
|
|
|
|
{ "listreceivedbyaddress", 2, "include_watchonly" },
|
2017-10-20 13:27:55 -04:00
|
|
|
{ "listreceivedbylabel", 0, "minconf" },
|
|
|
|
{ "listreceivedbylabel", 1, "include_empty" },
|
|
|
|
{ "listreceivedbylabel", 2, "include_watchonly" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "getbalance", 1, "minconf" },
|
|
|
|
{ "getbalance", 2, "include_watchonly" },
|
2018-09-11 15:53:36 +09:00
|
|
|
{ "getbalance", 3, "avoid_reuse" },
|
2016-12-09 17:06:42 +00:00
|
|
|
{ "getblockhash", 0, "height" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "waitforblockheight", 0, "height" },
|
|
|
|
{ "waitforblockheight", 1, "timeout" },
|
|
|
|
{ "waitforblock", 1, "timeout" },
|
|
|
|
{ "waitfornewblock", 0, "timeout" },
|
|
|
|
{ "listtransactions", 1, "count" },
|
2016-12-09 17:06:42 +00:00
|
|
|
{ "listtransactions", 2, "skip" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "listtransactions", 3, "include_watchonly" },
|
|
|
|
{ "walletpassphrase", 1, "timeout" },
|
|
|
|
{ "getblocktemplate", 0, "template_request" },
|
|
|
|
{ "listsinceblock", 1, "target_confirmations" },
|
|
|
|
{ "listsinceblock", 2, "include_watchonly" },
|
2017-01-24 14:27:22 +09:00
|
|
|
{ "listsinceblock", 3, "include_removed" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "sendmany", 1, "amounts" },
|
|
|
|
{ "sendmany", 2, "minconf" },
|
|
|
|
{ "sendmany", 4, "subtractfeefrom" },
|
2017-06-14 15:15:40 -04:00
|
|
|
{ "sendmany", 5 , "replaceable" },
|
|
|
|
{ "sendmany", 6 , "conf_target" },
|
2020-11-04 13:13:17 +01:00
|
|
|
{ "sendmany", 8, "fee_rate"},
|
|
|
|
{ "sendmany", 9, "verbose" },
|
2019-03-01 13:45:16 +01:00
|
|
|
{ "deriveaddresses", 1, "range" },
|
2018-01-15 20:33:59 -10:00
|
|
|
{ "scantxoutset", 1, "scanobjects" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "addmultisigaddress", 0, "nrequired" },
|
|
|
|
{ "addmultisigaddress", 1, "keys" },
|
|
|
|
{ "createmultisig", 0, "nrequired" },
|
|
|
|
{ "createmultisig", 1, "keys" },
|
|
|
|
{ "listunspent", 0, "minconf" },
|
|
|
|
{ "listunspent", 1, "maxconf" },
|
|
|
|
{ "listunspent", 2, "addresses" },
|
2017-06-19 11:48:57 +09:00
|
|
|
{ "listunspent", 3, "include_unsafe" },
|
2017-03-07 18:17:32 +00:00
|
|
|
{ "listunspent", 4, "query_options" },
|
2017-04-10 09:28:56 -04:00
|
|
|
{ "getblock", 1, "verbosity" },
|
2017-07-05 12:09:58 +01:00
|
|
|
{ "getblock", 1, "verbose" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "getblockheader", 1, "verbose" },
|
2017-02-09 17:24:30 -08:00
|
|
|
{ "getchaintxstats", 0, "nblocks" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "gettransaction", 1, "include_watchonly" },
|
2019-09-13 22:31:11 +03:00
|
|
|
{ "gettransaction", 2, "verbose" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "getrawtransaction", 1, "verbose" },
|
2017-03-26 12:08:44 +02:00
|
|
|
{ "createrawtransaction", 0, "inputs" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "createrawtransaction", 1, "outputs" },
|
|
|
|
{ "createrawtransaction", 2, "locktime" },
|
2017-06-28 17:49:04 -04:00
|
|
|
{ "createrawtransaction", 3, "replaceable" },
|
2017-08-28 18:00:21 +12:00
|
|
|
{ "decoderawtransaction", 1, "iswitness" },
|
2017-06-12 12:23:02 -07:00
|
|
|
{ "signrawtransactionwithkey", 1, "privkeys" },
|
|
|
|
{ "signrawtransactionwithkey", 2, "prevtxs" },
|
|
|
|
{ "signrawtransactionwithwallet", 1, "prevtxs" },
|
2018-06-27 17:21:07 +09:00
|
|
|
{ "sendrawtransaction", 1, "maxfeerate" },
|
2017-11-17 12:54:39 -05:00
|
|
|
{ "testmempoolaccept", 0, "rawtxs" },
|
2019-02-14 17:07:29 +09:00
|
|
|
{ "testmempoolaccept", 1, "maxfeerate" },
|
2017-06-09 22:38:06 -07:00
|
|
|
{ "combinerawtransaction", 0, "txs" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "fundrawtransaction", 1, "options" },
|
2017-08-28 18:00:21 +12:00
|
|
|
{ "fundrawtransaction", 2, "iswitness" },
|
2018-06-28 19:05:05 -07:00
|
|
|
{ "walletcreatefundedpsbt", 0, "inputs" },
|
|
|
|
{ "walletcreatefundedpsbt", 1, "outputs" },
|
|
|
|
{ "walletcreatefundedpsbt", 2, "locktime" },
|
2018-08-14 21:12:33 -04:00
|
|
|
{ "walletcreatefundedpsbt", 3, "options" },
|
|
|
|
{ "walletcreatefundedpsbt", 4, "bip32derivs" },
|
2018-06-28 19:05:05 -07:00
|
|
|
{ "walletprocesspsbt", 1, "sign" },
|
|
|
|
{ "walletprocesspsbt", 3, "bip32derivs" },
|
2018-06-28 19:04:40 -07:00
|
|
|
{ "createpsbt", 0, "inputs" },
|
|
|
|
{ "createpsbt", 1, "outputs" },
|
|
|
|
{ "createpsbt", 2, "locktime" },
|
|
|
|
{ "createpsbt", 3, "replaceable" },
|
|
|
|
{ "combinepsbt", 0, "txs"},
|
2018-07-20 18:24:16 -07:00
|
|
|
{ "joinpsbts", 0, "txs"},
|
2018-06-28 19:04:40 -07:00
|
|
|
{ "finalizepsbt", 1, "extract"},
|
|
|
|
{ "converttopsbt", 1, "permitsigdata"},
|
|
|
|
{ "converttopsbt", 2, "iswitness"},
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "gettxout", 1, "n" },
|
|
|
|
{ "gettxout", 2, "include_mempool" },
|
|
|
|
{ "gettxoutproof", 0, "txids" },
|
2020-08-22 20:21:20 +02:00
|
|
|
{ "gettxoutsetinfo", 1, "hash_or_height" },
|
2021-02-28 19:27:00 +01:00
|
|
|
{ "gettxoutsetinfo", 2, "use_index"},
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "lockunspent", 0, "unlock" },
|
|
|
|
{ "lockunspent", 1, "transactions" },
|
2020-08-07 17:36:36 +02:00
|
|
|
{ "send", 0, "outputs" },
|
|
|
|
{ "send", 1, "conf_target" },
|
2020-11-04 13:13:17 +01:00
|
|
|
{ "send", 3, "fee_rate"},
|
|
|
|
{ "send", 4, "options" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "importprivkey", 2, "rescan" },
|
|
|
|
{ "importaddress", 2, "rescan" },
|
|
|
|
{ "importaddress", 3, "p2sh" },
|
|
|
|
{ "importpubkey", 2, "rescan" },
|
|
|
|
{ "importmulti", 0, "requests" },
|
|
|
|
{ "importmulti", 1, "options" },
|
2019-08-01 15:08:47 -07:00
|
|
|
{ "importdescriptors", 0, "requests" },
|
2021-06-24 08:35:23 +02:00
|
|
|
{ "listdescriptors", 0, "private" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "verifychain", 0, "checklevel" },
|
|
|
|
{ "verifychain", 1, "nblocks" },
|
2017-06-04 00:25:55 +02:00
|
|
|
{ "getblockstats", 0, "hash_or_height" },
|
|
|
|
{ "getblockstats", 1, "stats" },
|
2016-11-29 12:39:19 -05:00
|
|
|
{ "pruneblockchain", 0, "height" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "keypoolrefill", 0, "newsize" },
|
|
|
|
{ "getrawmempool", 0, "verbose" },
|
Add 'sequence' zmq publisher to track all block (dis)connects, mempool deltas
Using the zmq notifications to avoid excessive mempool polling can be difficult
given the current notifications available. It announces all transactions
being added to mempool or included in blocks, but announces no evictions
and gives no indication if the transaction is in the mempool or a block.
Block notifications for zmq are also substandard, in that it only announces
block tips, while all block transactions are still announced.
This commit adds a unified stream which can be used to closely track mempool:
1) getrawmempool to fill out mempool knowledge
2) if txhash is announced, add or remove from set
based on add/remove flag
3) if blockhash is announced, get block txn list,
remove from those transactions local view of mempool
4) if we drop a sequence number, go to (1)
The mempool sequence number starts at the value 1, and
increments each time a transaction enters the mempool,
or is evicted from the mempool for any reason, including
block inclusion. The mempool sequence number is published
via ZMQ for any transaction-related notification.
These features allow for ZMQ/RPC consumer to track mempool
state in a more exacting way, without unnecesarily polling
getrawmempool. See interface_zmq.py::test_mempool_sync for
example usage.
2020-09-04 11:55:58 -04:00
|
|
|
{ "getrawmempool", 1, "mempool_sequence" },
|
2017-09-07 19:15:45 +02:00
|
|
|
{ "estimatesmartfee", 0, "conf_target" },
|
2017-09-07 18:16:34 +02:00
|
|
|
{ "estimaterawfee", 0, "conf_target" },
|
2017-01-24 16:30:03 -05:00
|
|
|
{ "estimaterawfee", 1, "threshold" },
|
2017-06-06 10:13:17 -04:00
|
|
|
{ "prioritisetransaction", 1, "dummy" },
|
2017-04-21 16:41:01 +00:00
|
|
|
{ "prioritisetransaction", 2, "fee_delta" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "setban", 2, "bantime" },
|
|
|
|
{ "setban", 3, "absolute" },
|
|
|
|
{ "setnetworkactive", 0, "state" },
|
2018-09-13 13:35:10 +09:00
|
|
|
{ "setwalletflag", 1, "value" },
|
2016-11-22 14:56:29 +01:00
|
|
|
{ "getmempoolancestors", 1, "verbose" },
|
|
|
|
{ "getmempooldescendants", 1, "verbose" },
|
2016-12-09 13:45:27 -05:00
|
|
|
{ "bumpfee", 1, "options" },
|
2020-04-13 14:48:03 -04:00
|
|
|
{ "psbtbumpfee", 1, "options" },
|
2017-04-03 13:39:11 -04:00
|
|
|
{ "logging", 0, "include" },
|
|
|
|
{ "logging", 1, "exclude" },
|
2017-04-03 10:03:00 -04:00
|
|
|
{ "disconnectnode", 1, "nodeid" },
|
2019-04-06 12:56:06 -04:00
|
|
|
{ "upgradewallet", 0, "version" },
|
2016-11-22 14:56:29 +01:00
|
|
|
// 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" },
|
2015-11-19 16:05:37 +01:00
|
|
|
{ "rescanblockchain", 0, "start_height"},
|
|
|
|
{ "rescanblockchain", 1, "stop_height"},
|
2018-06-13 20:35:41 +02:00
|
|
|
{ "createwallet", 1, "disable_private_keys"},
|
2019-02-06 21:26:55 -05:00
|
|
|
{ "createwallet", 2, "blank"},
|
2018-09-11 15:53:36 +09:00
|
|
|
{ "createwallet", 4, "avoid_reuse"},
|
2019-07-11 18:21:21 -04:00
|
|
|
{ "createwallet", 5, "descriptors"},
|
2019-05-01 15:12:44 -04:00
|
|
|
{ "createwallet", 6, "load_on_startup"},
|
2019-08-04 17:56:17 +02:00
|
|
|
{ "createwallet", 7, "external_signer"},
|
2021-07-27 14:28:23 -03:00
|
|
|
{ "restorewallet", 2, "load_on_startup"},
|
2019-05-01 15:12:44 -04:00
|
|
|
{ "loadwallet", 1, "load_on_startup"},
|
|
|
|
{ "unloadwallet", 1, "load_on_startup"},
|
2018-05-02 13:19:40 +01:00
|
|
|
{ "getnodeaddresses", 0, "count"},
|
2020-07-23 18:10:35 +01:00
|
|
|
{ "addpeeraddress", 1, "port"},
|
2021-09-14 12:14:43 +02:00
|
|
|
{ "addpeeraddress", 2, "tried"},
|
2018-11-20 17:52:15 +00:00
|
|
|
{ "stop", 0, "wait" },
|
2014-06-26 22:12:36 -04:00
|
|
|
};
|
2018-08-20 14:19:43 +02:00
|
|
|
// clang-format on
|
2014-06-26 22:12:36 -04:00
|
|
|
|
|
|
|
class CRPCConvertTable
|
|
|
|
{
|
|
|
|
private:
|
2016-11-22 14:56:29 +01:00
|
|
|
std::set<std::pair<std::string, int>> members;
|
|
|
|
std::set<std::pair<std::string, std::string>> membersByName;
|
2014-06-26 22:12:36 -04:00
|
|
|
|
|
|
|
public:
|
|
|
|
CRPCConvertTable();
|
|
|
|
|
|
|
|
bool convert(const std::string& method, int idx) {
|
|
|
|
return (members.count(std::make_pair(method, idx)) > 0);
|
2013-11-20 14:18:57 +01:00
|
|
|
}
|
2016-11-22 14:56:29 +01:00
|
|
|
bool convert(const std::string& method, const std::string& name) {
|
|
|
|
return (membersByName.count(std::make_pair(method, name)) > 0);
|
|
|
|
}
|
2014-06-26 22:12:36 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
CRPCConvertTable::CRPCConvertTable()
|
|
|
|
{
|
2021-01-12 06:27:29 +01:00
|
|
|
for (const auto& cp : vRPCConvertParams) {
|
|
|
|
members.emplace(cp.methodName, cp.paramIdx);
|
|
|
|
membersByName.emplace(cp.methodName, cp.paramName);
|
2013-11-20 14:18:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-26 22:12:36 -04:00
|
|
|
static CRPCConvertTable rpcCvtTable;
|
|
|
|
|
2015-06-04 10:31:22 +02:00
|
|
|
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
|
|
|
|
* as well as objects and arrays.
|
|
|
|
*/
|
|
|
|
UniValue ParseNonRFCJSONValue(const std::string& strVal)
|
|
|
|
{
|
|
|
|
UniValue jVal;
|
|
|
|
if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
|
|
|
|
!jVal.isArray() || jVal.size()!=1)
|
2020-06-01 10:35:07 +02:00
|
|
|
throw std::runtime_error(std::string("Error parsing JSON: ") + strVal);
|
2015-06-04 10:31:22 +02:00
|
|
|
return jVal[0];
|
|
|
|
}
|
|
|
|
|
2015-05-13 21:29:19 +02:00
|
|
|
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
|
2013-11-20 14:18:57 +01:00
|
|
|
{
|
2015-05-10 13:35:44 +02:00
|
|
|
UniValue params(UniValue::VARR);
|
2014-06-26 22:12:36 -04:00
|
|
|
|
|
|
|
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
|
|
|
|
const std::string& strVal = strParams[idx];
|
|
|
|
|
|
|
|
if (!rpcCvtTable.convert(strMethod, idx)) {
|
2015-06-04 10:31:22 +02:00
|
|
|
// insert string value directly
|
2014-06-26 22:12:36 -04:00
|
|
|
params.push_back(strVal);
|
2015-06-04 10:31:22 +02:00
|
|
|
} else {
|
|
|
|
// parse string as JSON, insert bool/number/object/etc. value
|
|
|
|
params.push_back(ParseNonRFCJSONValue(strVal));
|
2014-06-26 22:12:36 -04:00
|
|
|
}
|
|
|
|
}
|
2013-11-20 14:18:57 +01:00
|
|
|
|
|
|
|
return params;
|
|
|
|
}
|
2016-11-22 14:56:29 +01:00
|
|
|
|
|
|
|
UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<std::string> &strParams)
|
|
|
|
{
|
|
|
|
UniValue params(UniValue::VOBJ);
|
|
|
|
|
|
|
|
for (const std::string &s: strParams) {
|
2018-01-11 21:40:51 +01:00
|
|
|
size_t pos = s.find('=');
|
2016-11-22 14:56:29 +01:00
|
|
|
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;
|
|
|
|
}
|