diff options
Diffstat (limited to 'src')
42 files changed, 1290 insertions, 551 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 8dd0d31839..09daaebd23 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -95,6 +95,7 @@ endif BITCOIN_CORE_H = \ addrdb.h \ addrman.h \ + attributes.h \ base58.h \ bech32.h \ bloom.h \ diff --git a/src/attributes.h b/src/attributes.h new file mode 100644 index 0000000000..45099bd8b8 --- /dev/null +++ b/src/attributes.h @@ -0,0 +1,22 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2018 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_ATTRIBUTES_H +#define BITCOIN_ATTRIBUTES_H + +#if defined(__has_cpp_attribute) +# if __has_cpp_attribute(nodiscard) +# define NODISCARD [[nodiscard]] +# endif +#endif +#ifndef NODISCARD +# if defined(_MSC_VER) && _MSC_VER >= 1700 +# define NODISCARD _Check_return_ +# else +# define NODISCARD __attribute__((warn_unused_result)) +# endif +#endif + +#endif // BITCOIN_ATTRIBUTES_H diff --git a/src/base58.h b/src/base58.h index 9d3f90652e..d6e0299a1e 100644 --- a/src/base58.h +++ b/src/base58.h @@ -14,6 +14,8 @@ #ifndef BITCOIN_BASE58_H #define BITCOIN_BASE58_H +#include <attributes.h> + #include <string> #include <vector> @@ -33,13 +35,13 @@ std::string EncodeBase58(const std::vector<unsigned char>& vch); * return true if decoding is successful. * psz cannot be nullptr. */ -bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet); +NODISCARD bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet); /** * Decode a base58-encoded string (str) into a byte vector (vchRet). * return true if decoding is successful. */ -bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet); +NODISCARD bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet); /** * Encode a byte vector into a base58-encoded string, including checksum @@ -50,12 +52,12 @@ std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn); * Decode a base58-encoded string (psz) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet); +NODISCARD bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet); /** * Decode a base58-encoded string (str) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ -bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet); +NODISCARD bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet); #endif // BITCOIN_BASE58_H diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp index a555376e40..e7702ec461 100644 --- a/src/bench/base58.cpp +++ b/src/bench/base58.cpp @@ -49,7 +49,7 @@ static void Base58Decode(benchmark::State& state) const char* addr = "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem"; std::vector<unsigned char> vch; while (state.KeepRunning()) { - DecodeBase58(addr, vch); + (void) DecodeBase58(addr, vch); } } diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp index 8cc404b9e2..00e5d7e7a0 100644 --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -2,13 +2,21 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include <compat.h> #include <prevector.h> #include <serialize.h> #include <streams.h> +#include <type_traits> #include <bench/bench.h> +// GCC 4.8 is missing some C++11 type_traits, +// https://www.gnu.org/software/gcc/gcc-5/changes.html +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 +#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor +#else +#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible +#endif + struct nontrivial_t { int x; nontrivial_t() :x(-1) {} diff --git a/src/blockencodings.h b/src/blockencodings.h index fad1f56f54..0c2b83ebcf 100644 --- a/src/blockencodings.h +++ b/src/blockencodings.h @@ -52,12 +52,12 @@ public: } } - uint16_t offset = 0; + int32_t offset = 0; for (size_t j = 0; j < indexes.size(); j++) { - if (uint64_t(indexes[j]) + uint64_t(offset) > std::numeric_limits<uint16_t>::max()) + if (int32_t(indexes[j]) + offset > std::numeric_limits<uint16_t>::max()) throw std::ios_base::failure("indexes overflowed 16 bits"); indexes[j] = indexes[j] + offset; - offset = indexes[j] + 1; + offset = int32_t(indexes[j]) + 1; } } else { for (size_t i = 0; i < indexes.size(); i++) { @@ -186,6 +186,9 @@ public: READWRITE(prefilledtxn); + if (BlockTxCount() > std::numeric_limits<uint16_t>::max()) + throw std::ios_base::failure("indexes overflowed 16 bits"); + if (ser_action.ForRead()) FillShortTxIDSelector(); } diff --git a/src/compat.h b/src/compat.h index d228611160..049579c365 100644 --- a/src/compat.h +++ b/src/compat.h @@ -10,16 +10,6 @@ #include <config/bitcoin-config.h> #endif -#include <type_traits> - -// GCC 4.8 is missing some C++11 type_traits, -// https://www.gnu.org/software/gcc/gcc-5/changes.html -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 -#define IS_TRIVIALLY_CONSTRUCTIBLE std::has_trivial_default_constructor -#else -#define IS_TRIVIALLY_CONSTRUCTIBLE std::is_trivially_default_constructible -#endif - #ifdef WIN32 #ifdef _WIN32_WINNT #undef _WIN32_WINNT diff --git a/src/core_io.h b/src/core_io.h index 2c3b64d81e..6f87161f46 100644 --- a/src/core_io.h +++ b/src/core_io.h @@ -6,6 +6,7 @@ #define BITCOIN_CORE_IO_H #include <amount.h> +#include <attributes.h> #include <string> #include <vector> @@ -22,8 +23,8 @@ class UniValue; // core_read.cpp CScript ParseScript(const std::string& s); std::string ScriptToAsmStr(const CScript& script, const bool fAttemptSighashDecode = false); -bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true); -bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); +NODISCARD bool DecodeHexTx(CMutableTransaction& tx, const std::string& hex_tx, bool try_no_witness = false, bool try_witness = true); +NODISCARD bool DecodeHexBlk(CBlock&, const std::string& strHexBlk); bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); /** @@ -36,7 +37,7 @@ bool DecodeHexBlockHeader(CBlockHeader&, const std::string& hex_header); */ bool ParseHashStr(const std::string& strHex, uint256& result); std::vector<unsigned char> ParseHexUV(const UniValue& v, const std::string& strName); -bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error); +NODISCARD bool DecodePSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error); int ParseSighashString(const UniValue& sighash); // core_write.cpp diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 91ebc4680c..00434169cd 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -300,9 +300,12 @@ static bool HTTPBindAddresses(struct evhttp* http) std::vector<std::pair<std::string, uint16_t> > endpoints; // Determine what addresses to bind to - if (!gArgs.IsArgSet("-rpcallowip")) { // Default to loopback if not allowing external IPs + if (!(gArgs.IsArgSet("-rpcallowip") && gArgs.IsArgSet("-rpcbind"))) { // Default to loopback if not allowing external IPs endpoints.push_back(std::make_pair("::1", http_port)); endpoints.push_back(std::make_pair("127.0.0.1", http_port)); + if (gArgs.IsArgSet("-rpcallowip")) { + LogPrintf("WARNING: option -rpcallowip was specified without -rpcbind; this doesn't usually make sense\n"); + } if (gArgs.IsArgSet("-rpcbind")) { LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); } @@ -313,9 +316,6 @@ static bool HTTPBindAddresses(struct evhttp* http) SplitHostPort(strRPCBind, port, host); endpoints.push_back(std::make_pair(host, port)); } - } else { // No specific bind address specified, bind to any - endpoints.push_back(std::make_pair("::", http_port)); - endpoints.push_back(std::make_pair("0.0.0.0", http_port)); } // Bind addresses @@ -323,6 +323,10 @@ static bool HTTPBindAddresses(struct evhttp* http) LogPrint(BCLog::HTTP, "Binding RPC on address %s port %i\n", i->first, i->second); evhttp_bound_socket *bind_handle = evhttp_bind_socket_with_handle(http, i->first.empty() ? nullptr : i->first.c_str(), i->second); if (bind_handle) { + CNetAddr addr; + if (i->first.empty() || (LookupHost(i->first.c_str(), addr, false) && addr.IsBindAny())) { + LogPrintf("WARNING: the RPC server is not safe to expose to untrusted networks such as the public internet\n"); + } boundSockets.push_back(bind_handle); } else { LogPrintf("Binding RPC on address %s port %i failed.\n", i->first, i->second); diff --git a/src/init.cpp b/src/init.cpp index 3ab97be329..31212a355b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -500,7 +500,7 @@ void SetupServerArgs() gArgs.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), false, OptionsCategory::RPC); gArgs.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times", false, OptionsCategory::RPC); gArgs.AddArg("-rpcauth=<userpw>", "Username and hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcauth. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", false, OptionsCategory::RPC); - gArgs.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", false, OptionsCategory::RPC); + gArgs.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost)", false, OptionsCategory::RPC); gArgs.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", false, OptionsCategory::RPC); gArgs.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", false, OptionsCategory::RPC); gArgs.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), false, OptionsCategory::RPC); @@ -803,7 +803,15 @@ void InitParameterInteraction() // Warn if network-specific options (-addnode, -connect, etc) are // specified in default section of config file, but not overridden // on the command line or in this network's section of the config file. - gArgs.WarnForSectionOnlyArgs(); + std::string network = gArgs.GetChainName(); + for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) { + InitWarning(strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, network, network)); + } + + // Warn if unrecognized section name are present in the config file. + for (const auto& section : gArgs.GetUnrecognizedSections()) { + InitWarning(strprintf(_("Section [%s] is not recognized."), section)); + } } static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 1919e16a66..bd7e414ff3 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -35,7 +35,6 @@ #endif #include <atomic> -#include <boost/thread/thread.hpp> #include <univalue.h> class CWallet; diff --git a/src/miner.cpp b/src/miner.cpp index feb86cab66..96c9cd6d2a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -70,9 +70,8 @@ static BlockAssembler::Options DefaultOptions() // If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT BlockAssembler::Options options; options.nBlockMaxWeight = gArgs.GetArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT); - if (gArgs.IsArgSet("-blockmintxfee")) { - CAmount n = 0; - ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n); + CAmount n = 0; + if (gArgs.IsArgSet("-blockmintxfee") && ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) { options.blockMinFeeRate = CFeeRate(n); } else { options.blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE); diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 10e446392f..a0c7f8e3c2 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -82,6 +82,16 @@ unsigned int CNetAddr::GetByte(int n) const return ip[15-n]; } +bool CNetAddr::IsBindAny() const +{ + const int cmplen = IsIPv4() ? 4 : 16; + for (int i = 0; i < cmplen; ++i) { + if (GetByte(i)) return false; + } + + return true; +} + bool CNetAddr::IsIPv4() const { return (memcmp(ip, pchIPv4, sizeof(pchIPv4)) == 0); diff --git a/src/netaddress.h b/src/netaddress.h index dc55d8b1a8..ca435d17dc 100644 --- a/src/netaddress.h +++ b/src/netaddress.h @@ -55,6 +55,7 @@ class CNetAddr bool SetInternal(const std::string& name); bool SetSpecial(const std::string &strName); // for Tor addresses + bool IsBindAny() const; // INADDR_ANY equivalent bool IsIPv4() const; // IPv4 mapped address (::FFFF:0:0/96, 0.0.0.0/0) bool IsIPv6() const; // IPv6 address (not mapped IPv4, not Tor) bool IsRFC1918() const; // IPv4 private networks (10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12) diff --git a/src/outputtype.h b/src/outputtype.h index 4c4d93bc8b..6c30fd1950 100644 --- a/src/outputtype.h +++ b/src/outputtype.h @@ -6,6 +6,7 @@ #ifndef BITCOIN_OUTPUTTYPE_H #define BITCOIN_OUTPUTTYPE_H +#include <attributes.h> #include <keystore.h> #include <script/standard.h> @@ -26,7 +27,7 @@ enum class OutputType { CHANGE_AUTO, }; -bool ParseOutputType(const std::string& str, OutputType& output_type); +NODISCARD bool ParseOutputType(const std::string& str, OutputType& output_type); const std::string& FormatOutputType(OutputType type); /** diff --git a/src/prevector.h b/src/prevector.h index aa77573746..99e5751634 100644 --- a/src/prevector.h +++ b/src/prevector.h @@ -15,8 +15,6 @@ #include <iterator> #include <type_traits> -#include <compat.h> - #pragma pack(push, 1) /** Implements a drop-in replacement for std::vector<T> which stores up to N * elements directly (without heap allocation). The types Size and Diff are @@ -198,11 +196,7 @@ private: T* item_ptr(difference_type pos) { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } const T* item_ptr(difference_type pos) const { return is_direct() ? direct_ptr(pos) : indirect_ptr(pos); } - void fill(T* dst, ptrdiff_t count) { - std::fill_n(dst, count, T{}); - } - - void fill(T* dst, ptrdiff_t count, const T& value) { + void fill(T* dst, ptrdiff_t count, const T& value = T{}) { std::fill_n(dst, count, value); } diff --git a/src/rest.cpp b/src/rest.cpp index 6c7e0384cb..4988e6ed26 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -3,20 +3,21 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <attributes.h> #include <chain.h> #include <chainparams.h> #include <core_io.h> +#include <httpserver.h> #include <index/txindex.h> #include <primitives/block.h> #include <primitives/transaction.h> -#include <validation.h> -#include <httpserver.h> #include <rpc/blockchain.h> #include <rpc/server.h> #include <streams.h> #include <sync.h> #include <txmempool.h> #include <util/strencodings.h> +#include <validation.h> #include <version.h> #include <boost/algorithm/string.hpp> diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 95915b5488..e3d9357358 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -39,7 +39,6 @@ #include <univalue.h> -#include <boost/algorithm/string.hpp> #include <boost/thread/thread.hpp> // boost::thread::interrupt #include <memory> @@ -163,8 +162,9 @@ static UniValue getblockcount(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getblockcount\n" - "\nReturns the number of blocks in the longest blockchain.\n" + RPCHelpMan{"getblockcount", + "\nReturns the number of blocks in the longest blockchain.\n", {}} + .ToString() + "\nResult:\n" "n (numeric) The current block count\n" "\nExamples:\n" @@ -180,8 +180,9 @@ static UniValue getbestblockhash(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getbestblockhash\n" - "\nReturns the hash of the best (tip) block in the longest blockchain.\n" + RPCHelpMan{"getbestblockhash", + "\nReturns the hash of the best (tip) block in the longest blockchain.\n", {}} + .ToString() + "\nResult:\n" "\"hex\" (string) the block hash, hex-encoded\n" "\nExamples:\n" @@ -207,9 +208,13 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "waitfornewblock (timeout)\n" - "\nWaits for a specific new block and returns useful info about it.\n" - "\nReturns the current block on timeout or exit.\n" + RPCHelpMan{"waitfornewblock", + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n", + { + {"timeout", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" "\nResult:\n" @@ -245,9 +250,14 @@ static UniValue waitforblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "waitforblock <blockhash> (timeout)\n" - "\nWaits for a specific new block and returns useful info about it.\n" - "\nReturns the current block on timeout or exit.\n" + RPCHelpMan{"waitforblock", + "\nWaits for a specific new block and returns useful info about it.\n" + "\nReturns the current block on timeout or exit.\n", + { + {"blockhash", RPCArg::Type::STR, false}, + {"timeout", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\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" @@ -287,10 +297,15 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "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" + RPCHelpMan{"waitforblockheight", + "\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", + { + {"height", RPCArg::Type::NUM, false}, + {"timeout", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. height (int, required) Block height to wait for.\n" "2. timeout (int, optional, default=0) Time in milliseconds to wait for a response. 0 indicates no timeout.\n" @@ -329,8 +344,9 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 0) { throw std::runtime_error( - "syncwithvalidationinterfacequeue\n" - "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n" + RPCHelpMan{"syncwithvalidationinterfacequeue", + "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n", {}} + .ToString() + "\nExamples:\n" + HelpExampleCli("syncwithvalidationinterfacequeue","") + HelpExampleRpc("syncwithvalidationinterfacequeue","") @@ -344,8 +360,9 @@ static UniValue getdifficulty(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getdifficulty\n" - "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n" + RPCHelpMan{"getdifficulty", + "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", {}} + .ToString() + "\nResult:\n" "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n" "\nExamples:\n" @@ -478,8 +495,12 @@ static UniValue getrawmempool(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "getrawmempool ( verbose )\n" - "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" + RPCHelpMan{"getrawmempool", + "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n", + { + {"verbose", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n" "\nArguments:\n" "1. verbose (boolean, optional, default=false) True for a json object, false for array of transaction ids\n" @@ -510,8 +531,13 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "getmempoolancestors txid ( verbose )\n" - "\nIf txid is in the mempool, returns all in-mempool ancestors.\n" + RPCHelpMan{"getmempoolancestors", + "\nIf txid is in the mempool, returns all in-mempool ancestors.\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + {"verbose", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\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" @@ -574,8 +600,13 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "getmempooldescendants txid ( verbose )\n" - "\nIf txid is in the mempool, returns all in-mempool descendants.\n" + RPCHelpMan{"getmempooldescendants", + "\nIf txid is in the mempool, returns all in-mempool descendants.\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + {"verbose", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\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" @@ -638,8 +669,12 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "getmempoolentry txid\n" - "\nReturns mempool data for given transaction\n" + RPCHelpMan{"getmempoolentry", + "\nReturns mempool data for given transaction\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"txid\" (string, required) The transaction id (must be in mempool)\n" "\nResult:\n" @@ -671,8 +706,12 @@ static UniValue getblockhash(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "getblockhash height\n" - "\nReturns hash of block in best-block-chain at height provided.\n" + RPCHelpMan{"getblockhash", + "\nReturns hash of block in best-block-chain at height provided.\n", + { + {"height", RPCArg::Type::NUM, false}, + }} + .ToString() + "\nArguments:\n" "1. height (numeric, required) The height index\n" "\nResult:\n" @@ -696,9 +735,14 @@ static UniValue getblockheader(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "getblockheader \"blockhash\" ( verbose )\n" - "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n" - "If verbose is true, returns an Object with information about blockheader <hash>.\n" + RPCHelpMan{"getblockheader", + "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n" + "If verbose is true, returns an Object with information about blockheader <hash>.\n", + { + {"blockhash", RPCArg::Type::STR_HEX, false}, + {"verbose", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\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" @@ -774,10 +818,15 @@ static UniValue getblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "getblock \"blockhash\" ( verbosity ) \n" - "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n" - "If verbosity is 1, returns an Object with information about block <hash>.\n" - "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n" + RPCHelpMan{"getblock", + "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n" + "If verbosity is 1, returns an Object with information about block <hash>.\n" + "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction. \n", + { + {"blockhash", RPCArg::Type::STR_HEX, false}, + {"verbosity", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. \"blockhash\" (string, required) The block hash\n" "2. verbosity (numeric, optional, default=1) 0 for hex-encoded data, 1 for a json object, and 2 for json object with transaction data\n" @@ -926,7 +975,11 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "pruneblockchain height\n" + RPCHelpMan{"pruneblockchain", "", + { + {"height", RPCArg::Type::NUM, false}, + }} + .ToString() + "\nArguments:\n" "1. \"height\" (numeric, required) The block height to prune up to. May be set to a discrete height, or a unix timestamp\n" " to prune blocks whose block time is at least 2 hours older than the provided timestamp.\n" @@ -975,9 +1028,11 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "gettxoutsetinfo\n" - "\nReturns statistics about the unspent transaction output set.\n" - "Note this call may take some time.\n" + RPCHelpMan{"gettxoutsetinfo", + "\nReturns statistics about the unspent transaction output set.\n" + "Note this call may take some time.\n", + {}} + .ToString() + "\nResult:\n" "{\n" " \"height\":n, (numeric) The current block height (index)\n" @@ -1017,8 +1072,14 @@ UniValue gettxout(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) throw std::runtime_error( - "gettxout \"txid\" n ( include_mempool )\n" - "\nReturns details about an unspent transaction output.\n" + RPCHelpMan{"gettxout", + "\nReturns details about an unspent transaction output.\n", + { + {"txid", RPCArg::Type::STR, false}, + {"n", RPCArg::Type::NUM, false}, + {"include_mempool", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "2. \"n\" (numeric, required) vout number\n" @@ -1097,8 +1158,13 @@ static UniValue verifychain(const JSONRPCRequest& request) int nCheckDepth = gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS); if (request.fHelp || request.params.size() > 2) throw std::runtime_error( - "verifychain ( checklevel nblocks )\n" - "\nVerifies blockchain database.\n" + RPCHelpMan{"verifychain", + "\nVerifies blockchain database.\n", + { + {"checklevel", RPCArg::Type::NUM, true}, + {"nblocks", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. checklevel (numeric, optional, 0-4, default=" + strprintf("%d", nCheckLevel) + ") How thorough the block verification is.\n" "2. nblocks (numeric, optional, default=" + strprintf("%d", nCheckDepth) + ", 0=all) The number of blocks to check.\n" @@ -1194,8 +1260,9 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getblockchaininfo\n" - "Returns an object containing various state info regarding blockchain processing.\n" + RPCHelpMan{"getblockchaininfo", + "Returns an object containing various state info regarding blockchain processing.\n", {}} + .ToString() + "\nResult:\n" "{\n" " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" @@ -1311,9 +1378,11 @@ static UniValue getchaintips(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getchaintips\n" - "Return information about all known tips in the block tree," - " including the main chain as well as orphaned branches.\n" + RPCHelpMan{"getchaintips", + "Return information about all known tips in the block tree," + " including the main chain as well as orphaned branches.\n", + {}} + .ToString() + "\nResult:\n" "[\n" " {\n" @@ -1428,8 +1497,9 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getmempoolinfo\n" - "\nReturns details on the active state of the TX memory pool.\n" + RPCHelpMan{"getmempoolinfo", + "\nReturns details on the active state of the TX memory pool.\n", {}} + .ToString() + "\nResult:\n" "{\n" " \"size\": xxxxx, (numeric) Current tx count\n" @@ -1451,10 +1521,14 @@ static UniValue preciousblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "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" + RPCHelpMan{"preciousblock", + "\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", + { + {"blockhash", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"blockhash\" (string, required) the hash of the block to mark as precious\n" "\nResult:\n" @@ -1488,8 +1562,12 @@ static UniValue invalidateblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "invalidateblock \"blockhash\"\n" - "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" + RPCHelpMan{"invalidateblock", + "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n", + { + {"blockhash", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"blockhash\" (string, required) the hash of the block to mark as invalid\n" "\nResult:\n" @@ -1526,9 +1604,13 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "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" + RPCHelpMan{"reconsiderblock", + "\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", + { + {"blockhash", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"blockhash\" (string, required) the hash of the block to reconsider\n" "\nResult:\n" @@ -1563,8 +1645,13 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 2) throw std::runtime_error( - "getchaintxstats ( nblocks \"blockhash\" )\n" - "\nCompute statistics about the total number and rate of transactions in the chain.\n" + RPCHelpMan{"getchaintxstats", + "\nCompute statistics about the total number and rate of transactions in the chain.\n", + { + {"nblocks", RPCArg::Type::NUM, true}, + {"blockhash", RPCArg::Type::STR_HEX, true}, + }} + .ToString() + "\nArguments:\n" "1. nblocks (numeric, optional) Size of the window in number of blocks (default: one month).\n" "2. \"blockhash\" (string, optional) The hash of the block that ends the window.\n" @@ -1693,10 +1780,20 @@ static UniValue getblockstats(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) { throw std::runtime_error( - "getblockstats hash_or_height ( stats )\n" - "\nCompute per block statistics for a given window. All amounts are in satoshis.\n" - "It won't work for some heights with pruning.\n" - "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n" + RPCHelpMan{"getblockstats", + "\nCompute per block statistics for a given window. All amounts are in satoshis.\n" + "It won't work for some heights with pruning.\n" + "It won't work without -txindex for utxo_size_inc, *fee or *feerate stats.\n", + { + {"hash_or_height", RPCArg::Type::NUM, false}, + {"stats", RPCArg::Type::ARR, + { + {"height", RPCArg::Type::STR, true}, + {"time", RPCArg::Type::STR, true}, + }, + true, "stats"}, + }} + .ToString() + "\nArguments:\n" "1. \"hash_or_height\" (string or numeric, required) The block hash or height of the target block\n" "2. \"stats\" (array, optional) Values to plot, by default all values (see result below)\n" @@ -1957,8 +2054,9 @@ static UniValue savemempool(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( - "savemempool\n" - "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n" + RPCHelpMan{"savemempool", + "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", {}} + .ToString() + "\nExamples:\n" + HelpExampleCli("savemempool", "") + HelpExampleRpc("savemempool", "") @@ -2040,20 +2138,34 @@ UniValue scantxoutset(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "scantxoutset \"action\" [scanobjects,...]\n" - "\nEXPERIMENTAL warning: this call may be removed or changed in future releases.\n" - "\nScans the unspent transaction output set for entries that match certain output descriptors.\n" - "Examples of output descriptors are:\n" - " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n" - " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n" - " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n" - " pkh(<pubkey>) P2PKH outputs for the given pubkey\n" - " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n" - "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n" - "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n" - "unhardened or hardened child keys.\n" - "In the latter case, a range needs to be specified by below if different from 1000.\n" - "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n" + RPCHelpMan{"scantxoutset", + "\nEXPERIMENTAL warning: this call may be removed or changed in future releases.\n" + "\nScans the unspent transaction output set for entries that match certain output descriptors.\n" + "Examples of output descriptors are:\n" + " addr(<address>) Outputs whose scriptPubKey corresponds to the specified address (does not include P2PK)\n" + " raw(<hex script>) Outputs whose scriptPubKey equals the specified hex scripts\n" + " combo(<pubkey>) P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH outputs for the given pubkey\n" + " pkh(<pubkey>) P2PKH outputs for the given pubkey\n" + " sh(multi(<n>,<pubkey>,<pubkey>,...)) P2SH-multisig outputs for the given threshold and pubkeys\n" + "\nIn the above, <pubkey> either refers to a fixed public key in hexadecimal notation, or to an xpub/xprv optionally followed by one\n" + "or more path elements separated by \"/\", and optionally ending in \"/*\" (unhardened), or \"/*'\" or \"/*h\" (hardened) to specify all\n" + "unhardened or hardened child keys.\n" + "In the latter case, a range needs to be specified by below if different from 1000.\n" + "For more information on output descriptors, see the documentation in the doc/descriptors.md file.\n", + { + {"action", RPCArg::Type::STR, false}, + {"scanobjects", RPCArg::Type::ARR, + { + {"descriptor", RPCArg::Type::OBJ, + { + {"desc", RPCArg::Type::STR, false}, + {"range", RPCArg::Type::NUM, true}, + }, + false, "scanobjects"}, + }, + false}, + }} + .ToString() + "\nArguments:\n" "1. \"action\" (string, required) The action to execute\n" " \"start\" for starting a scan\n" diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 4f314ef215..c0287ec17f 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -87,10 +87,15 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 2) throw std::runtime_error( - "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" + RPCHelpMan{"getnetworkhashps", + "\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", + { + {"nblocks", RPCArg::Type::NUM, true}, + {"height", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\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" @@ -157,8 +162,14 @@ static UniValue generatetoaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 3) throw std::runtime_error( - "generatetoaddress nblocks address (maxtries)\n" - "\nMine blocks immediately to a specified address (before the RPC call returns)\n" + RPCHelpMan{"generatetoaddress", + "\nMine blocks immediately to a specified address (before the RPC call returns)\n", + { + {"nblocks", RPCArg::Type::NUM, false}, + {"address", RPCArg::Type::STR, false}, + {"maxtries", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\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" @@ -193,8 +204,9 @@ static UniValue getmininginfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getmininginfo\n" - "\nReturns a json object containing mining-related information." + RPCHelpMan{"getmininginfo", + "\nReturns a json object containing mining-related information.", {}} + .ToString() + "\nResult:\n" "{\n" " \"blocks\": nnn, (numeric) The current block\n" @@ -232,8 +244,14 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 3) throw std::runtime_error( - "prioritisetransaction \"txid\" dummy fee_delta\n" - "Accepts the transaction into mined blocks at a higher (or lower) priority\n" + RPCHelpMan{"prioritisetransaction", + "Accepts the transaction into mined blocks at a higher (or lower) priority\n", + { + {"txid", RPCArg::Type::STR, false}, + {"dummy", RPCArg::Type::NUM, false}, + {"fee_delta", RPCArg::Type::NUM, false}, + }} + .ToString() + "\nArguments:\n" "1. \"txid\" (string, required) The transaction id.\n" "2. dummy (numeric, optional) API-Compatibility for previous API. Must be zero or null.\n" @@ -295,15 +313,32 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "getblocktemplate ( \"template_request\" )\n" - "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" - "It returns data needed to construct a block to work on.\n" - "For full specification, see BIPs 22, 23, 9, and 145:\n" - " https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n" - " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n" - " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" - " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n" - + RPCHelpMan{"getblocktemplate", + "\nIf the request parameters include a 'mode' key, that is used to explicitly select between the default 'template' request or a 'proposal'.\n" + "It returns data needed to construct a block to work on.\n" + "For full specification, see BIPs 22, 23, 9, and 145:\n" + " https://github.com/bitcoin/bips/blob/master/bip-0022.mediawiki\n" + " https://github.com/bitcoin/bips/blob/master/bip-0023.mediawiki\n" + " https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki#getblocktemplate_changes\n" + " https://github.com/bitcoin/bips/blob/master/bip-0145.mediawiki\n", + { + {"template_request", RPCArg::Type::OBJ, + { + {"mode", RPCArg::Type::STR, true}, + {"capabilities", RPCArg::Type::ARR, + { + {"support", RPCArg::Type::STR, true}, + }, + true}, + {"rules", RPCArg::Type::ARR, + { + {"support", RPCArg::Type::STR, true}, + }, + true}, + }, + true, "\"template_request\""}, + }} + .ToString() + "\nArguments:\n" "1. template_request (json object, optional) A json object in the following spec\n" " {\n" @@ -703,10 +738,14 @@ static UniValue submitblock(const JSONRPCRequest& request) // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored. if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "submitblock \"hexdata\" ( \"dummy\" )\n" - "\nAttempts to submit new block to network.\n" - "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n" - + RPCHelpMan{"submitblock", + "\nAttempts to submit new block to network.\n" + "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n", + { + {"hexdata", RPCArg::Type::STR_HEX, false}, + {"dummy", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments\n" "1. \"hexdata\" (string, required) the hex-encoded block data to submit\n" "2. \"dummy\" (optional) dummy value, for compatibility with BIP22. This value is ignored.\n" @@ -767,9 +806,13 @@ static UniValue submitheader(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "submitheader \"hexdata\"\n" - "\nDecode the given hexdata as a header and submit it as a candidate chain tip if valid." - "\nThrows when the header is invalid.\n" + RPCHelpMan{"submitheader", + "\nDecode the given hexdata as a header and submit it as a candidate chain tip if valid." + "\nThrows when the header is invalid.\n", + { + {"hexdata", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments\n" "1. \"hexdata\" (string, required) the hex-encoded block header data\n" "\nResult:\n" @@ -803,11 +846,16 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "estimatesmartfee conf_target (\"estimate_mode\")\n" - "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within conf_target blocks if possible and return the number of blocks\n" - "for which the estimate is valid. Uses virtual transaction size as defined\n" - "in BIP 141 (witness data is discounted).\n" + RPCHelpMan{"estimatesmartfee", + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within conf_target blocks if possible and return the number of blocks\n" + "for which the estimate is valid. Uses virtual transaction size as defined\n" + "in BIP 141 (witness data is discounted).\n", + { + {"conf_target", RPCArg::Type::NUM, false}, + {"estimate_mode", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n" "2. \"estimate_mode\" (string, optional, default=CONSERVATIVE) The fee estimate mode.\n" @@ -864,14 +912,19 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "estimaterawfee conf_target (threshold)\n" - "\nWARNING: This interface is unstable and may disappear or change!\n" - "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n" - " implementation of fee estimation. The parameters it can be called with\n" - " and the results it returns will change if the internal implementation changes.\n" - "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" - "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n" - "defined in BIP 141 (witness data is discounted).\n" + RPCHelpMan{"estimaterawfee", + "\nWARNING: This interface is unstable and may disappear or change!\n" + "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n" + " implementation of fee estimation. The parameters it can be called with\n" + " and the results it returns will change if the internal implementation changes.\n" + "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n" + "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n" + "defined in BIP 141 (witness data is discounted).\n", + { + {"conf_target", RPCArg::Type::NUM, false}, + {"threshold", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. conf_target (numeric) Confirmation target in blocks (1 - 1008)\n" "2. threshold (numeric, optional) The proportion of transactions in a given feerate range that must have been\n" diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index cebf12bb34..5543035885 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -32,12 +32,16 @@ static UniValue validateaddress(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "validateaddress \"address\"\n" - "\nReturn information about the given bitcoin address.\n" - "DEPRECATION WARNING: Parts of this command have been deprecated and moved to getaddressinfo. Clients must\n" - "transition to using getaddressinfo to access this information before upgrading to v0.18. The following deprecated\n" - "fields have moved to getaddressinfo and will only be shown here with -deprecatedrpc=validateaddress: ismine, iswatchonly,\n" - "script, hex, pubkeys, sigsrequired, pubkey, addresses, embedded, iscompressed, account, timestamp, hdkeypath, kdmasterkeyid.\n" + RPCHelpMan{"validateaddress", + "\nReturn information about the given bitcoin address.\n" + "DEPRECATION WARNING: Parts of this command have been deprecated and moved to getaddressinfo. Clients must\n" + "transition to using getaddressinfo to access this information before upgrading to v0.18. The following deprecated\n" + "fields have moved to getaddressinfo and will only be shown here with -deprecatedrpc=validateaddress: ismine, iswatchonly,\n" + "script, hex, pubkeys, sigsrequired, pubkey, addresses, embedded, iscompressed, account, timestamp, hdkeypath, kdmasterkeyid.\n", + { + {"address", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to validate\n" "\nResult:\n" @@ -142,8 +146,14 @@ static UniValue verifymessage(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 3) throw std::runtime_error( - "verifymessage \"address\" \"signature\" \"message\"\n" - "\nVerify a signed message\n" + RPCHelpMan{"verifymessage", + "\nVerify a signed message\n", + { + {"address", RPCArg::Type::STR, false}, + {"signature", RPCArg::Type::STR, false}, + {"message", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\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" @@ -198,8 +208,13 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 2) throw std::runtime_error( - "signmessagewithprivkey \"privkey\" \"message\"\n" - "\nSign a message with the private key of an address\n" + RPCHelpMan{"signmessagewithprivkey", + "\nSign a message with the private key of an address\n", + { + {"privkey", RPCArg::Type::STR, false}, + {"message", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"privkey\" (string, required) The private key to sign the message with.\n" "2. \"message\" (string, required) The message to create a signature of.\n" @@ -237,8 +252,12 @@ static UniValue setmocktime(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "setmocktime timestamp\n" - "\nSet the local time to given timestamp (-regtest only)\n" + RPCHelpMan{"setmocktime", + "\nSet the local time to given timestamp (-regtest only)\n", + { + {"timestamp", RPCArg::Type::NUM, false}, + }} + .ToString() + "\nArguments:\n" "1. timestamp (integer, required) Unix seconds-since-epoch timestamp\n" " Pass 0 to go back to using the system time." @@ -299,8 +318,12 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request) */ if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "getmemoryinfo (\"mode\")\n" - "Returns an object containing information about memory usage.\n" + RPCHelpMan{"getmemoryinfo", + "Returns an object containing information about memory usage.\n", + { + {"mode", RPCArg::Type::STR, true}, + }} + .ToString() + "Arguments:\n" "1. \"mode\" determines what kind of information is returned. This argument is optional, the default mode is \"stats\".\n" " - \"stats\" returns general statistics about memory usage in the daemon.\n" @@ -361,7 +384,7 @@ UniValue logging(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 2) { throw std::runtime_error( - "logging ( <include> <exclude> )\n" + RPCHelpMan{"logging", "Gets and sets the logging configuration.\n" "When called without an argument, returns the list of categories with status that are currently being debug logged or not.\n" "When called with arguments, adds or removes categories from debug logging and return the lists above.\n" @@ -371,6 +394,12 @@ UniValue logging(const JSONRPCRequest& request) "In addition, the following are available as category names with special meanings:\n" " - \"all\", \"1\" : represent all logging categories.\n" " - \"none\", \"0\" : even if other logging categories are specified, ignore all of them.\n" + , + { + {"include", RPCArg::Type::STR, true}, + {"exclude", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. \"include\" (array of strings, optional) A json array of categories to add debug logging\n" " [\n" @@ -430,11 +459,13 @@ static UniValue echo(const JSONRPCRequest& request) { if (request.fHelp) throw std::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." - ); + RPCHelpMan{"echo|echojson ...", + "\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.", + {}} + .ToString() + + ""); return request.params; } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index fc1498a224..795b9b089b 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -28,8 +28,9 @@ static UniValue getconnectioncount(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getconnectioncount\n" - "\nReturns the number of connections to other nodes.\n" + RPCHelpMan{"getconnectioncount", + "\nReturns the number of connections to other nodes.\n", {}} + .ToString() + "\nResult:\n" "n (numeric) The connection count\n" "\nExamples:\n" @@ -47,10 +48,12 @@ static UniValue ping(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "ping\n" - "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" - "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" - "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n" + RPCHelpMan{"ping", + "\nRequests that a ping be sent to all other nodes, to measure ping time.\n" + "Results provided in getpeerinfo, pingtime and pingwait fields are decimal seconds.\n" + "Ping command is handled in queue with all other commands, so it measures processing backlog, not just network ping.\n", + {}} + .ToString() + "\nExamples:\n" + HelpExampleCli("ping", "") + HelpExampleRpc("ping", "") @@ -70,8 +73,9 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getpeerinfo\n" - "\nReturns data about each connected network node as a json array of objects.\n" + RPCHelpMan{"getpeerinfo", + "\nReturns data about each connected network node as a json array of objects.\n", {}} + .ToString() + "\nResult:\n" "[\n" " {\n" @@ -201,11 +205,16 @@ static UniValue addnode(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 2 || (strCommand != "onetry" && strCommand != "add" && strCommand != "remove")) throw std::runtime_error( - "addnode \"node\" \"command\"\n" - "\nAttempts to add or remove a node from the addnode list.\n" - "Or try a connection to a node once.\n" - "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n" - "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n" + RPCHelpMan{"addnode", + "\nAttempts to add or remove a node from the addnode list.\n" + "Or try a connection to a node once.\n" + "Nodes added using addnode (or -connect) are protected from DoS disconnection and are not required to be\n" + "full nodes/support SegWit as other outbound peers are (though such peers will not be synced from).\n", + { + {"node", RPCArg::Type::STR, false}, + {"command", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"node\" (string, required) The node (see getpeerinfo for nodes)\n" "2. \"command\" (string, required) 'add' to add a node to the list, 'remove' to remove a node from the list, 'onetry' to try a connection to the node once\n" @@ -244,10 +253,15 @@ static UniValue disconnectnode(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() == 0 || request.params.size() >= 3) throw std::runtime_error( - "disconnectnode ( \"address\" nodeid )\n" - "\nImmediately disconnects from the specified peer node.\n" - "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n" - "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n" + RPCHelpMan{"disconnectnode", + "\nImmediately disconnects from the specified peer node.\n" + "\nStrictly one out of 'address' and 'nodeid' can be provided to identify the node.\n" + "\nTo disconnect by nodeid, either set 'address' to the empty string, or call using the named 'nodeid' argument only.\n", + { + {"address", RPCArg::Type::STR, true}, + {"nodeid", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. \"address\" (string, optional) The IP address/port of the node\n" "2. nodeid (number, optional) The node ID (see getpeerinfo for node IDs)\n" @@ -287,9 +301,13 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "getaddednodeinfo ( \"node\" )\n" - "\nReturns information about the given added node, or all added nodes\n" - "(note that onetry addnodes are not listed here)\n" + RPCHelpMan{"getaddednodeinfo", + "\nReturns information about the given added node, or all added nodes\n" + "(note that onetry addnodes are not listed here)\n", + { + {"node", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. \"node\" (string, optional) If provided, return information about this specific node, otherwise all nodes are returned.\n" "\nResult:\n" @@ -354,9 +372,11 @@ static UniValue getnettotals(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 0) throw std::runtime_error( - "getnettotals\n" - "\nReturns information about network traffic, including bytes in, bytes out,\n" - "and current time.\n" + RPCHelpMan{"getnettotals", + "\nReturns information about network traffic, including bytes in, bytes out,\n" + "and current time.\n", + {}} + .ToString() + "\nResult:\n" "{\n" " \"totalbytesrecv\": n, (numeric) Total bytes received\n" @@ -420,8 +440,9 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getnetworkinfo\n" - "Returns an object containing various state info regarding P2P networking.\n" + RPCHelpMan{"getnetworkinfo", + "Returns an object containing various state info regarding P2P networking.\n", {}} + .ToString() + "\nResult:\n" "{\n" " \"version\": xxxxx, (numeric) the server version\n" @@ -500,8 +521,15 @@ static UniValue setban(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || (strCommand != "add" && strCommand != "remove")) throw std::runtime_error( - "setban \"subnet\" \"command\" ( bantime absolute )\n" - "\nAttempts to add or remove an IP/Subnet from the banned list.\n" + RPCHelpMan{"setban", + "\nAttempts to add or remove an IP/Subnet from the banned list.\n", + { + {"subnet", RPCArg::Type::STR, false}, + {"command", RPCArg::Type::STR, false}, + {"bantime", RPCArg::Type::NUM, true}, + {"absolute", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. \"subnet\" (string, required) The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)\n" "2. \"command\" (string, required) 'add' to add an IP/Subnet to the list, 'remove' to remove an IP/Subnet from the list\n" @@ -560,8 +588,9 @@ static UniValue listbanned(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "listbanned\n" - "\nList all banned IPs/Subnets.\n" + RPCHelpMan{"listbanned", + "\nList all banned IPs/Subnets.\n", {}} + .ToString() + "\nExamples:\n" + HelpExampleCli("listbanned", "") + HelpExampleRpc("listbanned", "") @@ -593,8 +622,9 @@ static UniValue clearbanned(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "clearbanned\n" - "\nClear all banned IPs.\n" + RPCHelpMan{"clearbanned", + "\nClear all banned IPs.\n", {}} + .ToString() + "\nExamples:\n" + HelpExampleCli("clearbanned", "") + HelpExampleRpc("clearbanned", "") @@ -611,8 +641,12 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "setnetworkactive state\n" - "\nDisable/enable all p2p network activity.\n" + RPCHelpMan{"setnetworkactive", + "\nDisable/enable all p2p network activity.\n", + { + {"state", RPCArg::Type::BOOL, false}, + }} + .ToString() + "\nArguments:\n" "1. \"state\" (boolean, required) true to enable networking, false to disable\n" ); @@ -631,8 +665,12 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) { throw std::runtime_error( - "getnodeaddresses ( count )\n" - "\nReturn known addresses which can potentially be used to find new nodes in the network\n" + RPCHelpMan{"getnodeaddresses", + "\nReturn known addresses which can potentially be used to find new nodes in the network\n", + { + {"count", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. \"count\" (numeric, optional) How many addresses to return. Limited to the smaller of " + std::to_string(ADDRMAN_GETADDR_MAX) + " or " + std::to_string(ADDRMAN_GETADDR_MAX_PCT) + "% of all known addresses. (default = 1)\n" diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 480cb0b9d2..a3ed4e86d9 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -66,13 +66,18 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "getrawtransaction \"txid\" ( verbose \"blockhash\" )\n" - - "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" - "enabled, it also works for blockchain transactions. If the block which contains the transaction\n" - "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n" - "provided, only that block will be searched and if the transaction is in the mempool or other\n" - "blocks, or if this node does not have the given block available, the transaction will not be found.\n" + RPCHelpMan{"getrawtransaction", + "\nNOTE: By default this function only works for mempool transactions. If the -txindex option is\n" + "enabled, it also works for blockchain transactions. If the block which contains the transaction\n" + "is known, its hash can be provided even for nodes without -txindex. Note that if a blockhash is\n" + "provided, only that block will be searched and if the transaction is in the mempool or other\n" + "blocks, or if this node does not have the given block available, the transaction will not be found.\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + {"verbose", RPCArg::Type::BOOL, true}, + {"blockhash", RPCArg::Type::STR_HEX, true}, + }} + .ToString() + "DEPRECATED: for now, it also works for transactions with unspent outputs.\n" "\nReturn the raw transaction data.\n" @@ -207,6 +212,11 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) if (request.fHelp || (request.params.size() != 1 && request.params.size() != 2)) throw std::runtime_error( RPCHelpMan{"gettxoutproof", + "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" + "\nNOTE: By default this function only works sometimes. This is when there is an\n" + "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 or\n" + "specify the block in which the transaction is included manually (by blockhash).\n", { {"txids", RPCArg::Type::ARR, { @@ -216,11 +226,6 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) {"blockhash", RPCArg::Type::STR_HEX, true}, }} .ToString() + - "\nReturns a hex-encoded proof that \"txid\" was included in a block.\n" - "\nNOTE: By default this function only works sometimes. This is when there is an\n" - "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 or\n" - "specify the block in which the transaction is included manually (by blockhash).\n" "\nArguments:\n" "1. \"txids\" (string) A json array of txids to filter\n" " [\n" @@ -307,9 +312,13 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "verifytxoutproof \"proof\"\n" - "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" - "and throwing an RPC error if the block is not in our best chain\n" + RPCHelpMan{"verifytxoutproof", + "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" + "and throwing an RPC error if the block is not in our best chain\n", + { + {"proof", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n" "\nResult:\n" @@ -514,9 +523,13 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "decoderawtransaction \"hexstring\" ( iswitness )\n" - "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" - + RPCHelpMan{"decoderawtransaction", + "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + {"iswitness", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string, required) The transaction hex string\n" "2. iswitness (boolean, optional) Whether the transaction hex is a serialized witness transaction\n" @@ -589,8 +602,12 @@ static UniValue decodescript(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "decodescript \"hexstring\"\n" - "\nDecode a hex-encoded script.\n" + RPCHelpMan{"decodescript", + "\nDecode a hex-encoded script.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string) the hex-encoded script\n" "\nResult:\n" @@ -685,6 +702,9 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( RPCHelpMan{"combinerawtransaction", + "\nCombine multiple partially signed transactions into one transaction.\n" + "The combined transaction may be another partially signed transaction or a \n" + "fully signed transaction.", { {"txs", RPCArg::Type::ARR, { @@ -693,10 +713,6 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) false}, }} .ToString() + - "\nCombine multiple partially signed transactions into one transaction.\n" - "The combined transaction may be another partially signed transaction or a \n" - "fully signed transaction." - "\nArguments:\n" "1. \"txs\" (string) A json array of hex strings of partially signed transactions\n" " [\n" @@ -916,6 +932,11 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) throw std::runtime_error( RPCHelpMan{"signrawtransactionwithkey", + "\nSign inputs for raw transaction (serialized, hex-encoded).\n" + "The second argument is an array of base58-encoded private\n" + "keys that will be the only keys used to sign the transaction.\n" + "The third optional argument (may be null) is an array of previous transaction outputs that\n" + "this transaction depends on but may not yet be in the block chain.\n", { {"hexstring", RPCArg::Type::STR, false}, {"privkyes", RPCArg::Type::ARR, @@ -939,12 +960,6 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) {"sighashtype", RPCArg::Type::STR, true}, }} .ToString() + - "\nSign inputs for raw transaction (serialized, hex-encoded).\n" - "The second argument is an array of base58-encoded private\n" - "keys that will be the only keys used to sign the transaction.\n" - "The third optional argument (may be null) is an array of previous transaction outputs that\n" - "this transaction depends on but may not yet be in the block chain.\n" - "\nArguments:\n" "1. \"hexstring\" (string, required) The transaction hex string\n" "2. \"privkeys\" (string, required) A json array of base58-encoded private keys for signing\n" @@ -1025,9 +1040,14 @@ static UniValue sendrawtransaction(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "sendrawtransaction \"hexstring\" ( allowhighfees )\n" - "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" - "\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n" + RPCHelpMan{"sendrawtransaction", + "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" + "\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + {"allowhighfees", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" @@ -1218,9 +1238,12 @@ UniValue decodepsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "decodepsbt \"psbt\"\n" - "\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n" - + RPCHelpMan{"decodepsbt", + "\nReturn a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.\n", + { + {"psbt", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"psbt\" (string, required) The PSBT base64 string\n" @@ -1494,6 +1517,8 @@ UniValue combinepsbt(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( RPCHelpMan{"combinepsbt", + "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n" + "Implements the Combiner role.\n", { {"txs", RPCArg::Type::ARR, { @@ -1502,8 +1527,6 @@ UniValue combinepsbt(const JSONRPCRequest& request) false}, }} .ToString() + - "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n" - "Implements the Combiner role.\n" "\nArguments:\n" "1. \"txs\" (string) A json array of base64 strings of partially signed transactions\n" " [\n" @@ -1554,11 +1577,16 @@ UniValue finalizepsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "finalizepsbt \"psbt\" ( extract )\n" - "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n" - "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n" - "created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n" - "Implements the Finalizer and Extractor roles.\n" + RPCHelpMan{"finalizepsbt", + "Finalize the inputs of a PSBT. If the transaction is fully signed, it will produce a\n" + "network serialized transaction which can be broadcast with sendrawtransaction. Otherwise a PSBT will be\n" + "created which has the final_scriptSig and final_scriptWitness fields filled for inputs that are complete.\n" + "Implements the Finalizer and Extractor roles.\n", + { + {"psbt", RPCArg::Type::STR, false}, + {"extract", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"psbt\" (string) A base64 string of a PSBT\n" "2. \"extract\" (boolean, optional, default=true) If true and the transaction is complete, \n" @@ -1619,6 +1647,8 @@ UniValue createpsbt(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) throw std::runtime_error( RPCHelpMan{"createpsbt", + "\nCreates a transaction in the Partially Signed Transaction format.\n" + "Implements the Creator role.\n", { {"inputs", RPCArg::Type::ARR, { @@ -1649,8 +1679,6 @@ UniValue createpsbt(const JSONRPCRequest& request) {"replaceable", RPCArg::Type::BOOL, true}, }} .ToString() + - "\nCreates a transaction in the Partially Signed Transaction format.\n" - "Implements the Creator role.\n" "\nArguments:\n" "1. \"inputs\" (array, required) A json array of json objects\n" " [\n" @@ -1713,9 +1741,15 @@ UniValue converttopsbt(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "converttopsbt \"hexstring\" ( permitsigdata iswitness )\n" - "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n" - "createpsbt and walletcreatefundedpsbt should be used for new applications.\n" + RPCHelpMan{"converttopsbt", + "\nConverts a network serialized transaction to a PSBT. This should be used only with createrawtransaction and fundrawtransaction\n" + "createpsbt and walletcreatefundedpsbt should be used for new applications.\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + {"permitsigdata", RPCArg::Type::BOOL, true}, + {"iswitness", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of a raw transaction\n" "2. permitsigdata (boolean, optional, default=false) If true, any signatures in the input will be discarded and conversion.\n" diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index f890baba51..c565094a10 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -204,8 +204,12 @@ UniValue help(const JSONRPCRequest& jsonRequest) { if (jsonRequest.fHelp || jsonRequest.params.size() > 1) throw std::runtime_error( - "help ( \"command\" )\n" - "\nList all commands, or get help for a specified command.\n" + RPCHelpMan{"help", + "\nList all commands, or get help for a specified command.\n", + { + {"command", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. \"command\" (string, optional) The command to get help on\n" "\nResult:\n" @@ -225,8 +229,9 @@ UniValue stop(const JSONRPCRequest& jsonRequest) // Accept the deprecated and ignored 'detach' boolean argument if (jsonRequest.fHelp || jsonRequest.params.size() > 1) throw std::runtime_error( - "stop\n" - "\nStop Bitcoin server."); + RPCHelpMan{"stop", + "\nStop Bitcoin server.", {}} + .ToString()); // Event loop will exit after current HTTP requests have been handled, so // this reply will get back to the client. StartShutdown(); @@ -237,8 +242,9 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest) { if (jsonRequest.fHelp || jsonRequest.params.size() > 0) throw std::runtime_error( - "uptime\n" - "\nReturns the total uptime of the server.\n" + RPCHelpMan{"uptime", + "\nReturns the total uptime of the server.\n", {}} + .ToString() + "\nResult:\n" "ttt (numeric) The number of seconds that the server has been running\n" "\nExamples:\n" diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 6f2450708a..0b6bbcb1dc 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -150,6 +150,8 @@ std::string RPCHelpMan::ToString() const if (is_optional) ret += " )"; ret += "\n"; + ret += m_description; + return ret; } @@ -185,6 +187,8 @@ std::string RPCArg::ToStringObj() const std::string RPCArg::ToString() const { + if (!m_oneline_description.empty()) return m_oneline_description; + switch (m_type) { case Type::STR_HEX: case Type::STR: { diff --git a/src/rpc/util.h b/src/rpc/util.h index 55ae2fa363..b1ab64247c 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -9,8 +9,6 @@ #include <script/standard.h> #include <univalue.h> -#include <boost/variant/static_visitor.hpp> - #include <string> #include <vector> @@ -45,15 +43,16 @@ struct RPCArg { const Type m_type; const std::vector<RPCArg> m_inner; //!< Only used for arrays or dicts const bool m_optional; + const std::string m_oneline_description; //!< Should be empty unless it is supposed to override the auto-generated summary line - RPCArg(const std::string& name, const Type& type, const bool optional) - : m_name{name}, m_type{type}, m_optional{optional} + RPCArg(const std::string& name, const Type& type, const bool optional, const std::string& oneline_description = "") + : m_name{name}, m_type{type}, m_optional{optional}, m_oneline_description{oneline_description} { assert(type != Type::ARR && type != Type::OBJ); } - RPCArg(const std::string& name, const Type& type, const std::vector<RPCArg>& inner, const bool optional) - : m_name{name}, m_type{type}, m_inner{inner}, m_optional{optional} + RPCArg(const std::string& name, const Type& type, const std::vector<RPCArg>& inner, const bool optional, const std::string& oneline_description = "") + : m_name{name}, m_type{type}, m_inner{inner}, m_optional{optional}, m_oneline_description{oneline_description} { assert(type == Type::ARR || type == Type::OBJ); } @@ -67,8 +66,8 @@ private: class RPCHelpMan { public: - RPCHelpMan(const std::string& name, const std::vector<RPCArg>& args) - : m_name{name}, m_args{args} + RPCHelpMan(const std::string& name, const std::string& description, const std::vector<RPCArg>& args) + : m_name{name}, m_description{description}, m_args{args} { } @@ -76,6 +75,7 @@ public: private: const std::string m_name; + const std::string m_description; const std::vector<RPCArg> m_args; }; diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index 90c4ddcc11..d343972c40 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -478,7 +478,7 @@ std::vector<Span<const char>> Split(const Span<const char>& sp, char sep) } /** Parse a key path, being passed a split list of elements (the first element is ignored). */ -bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out) +NODISCARD bool ParseKeyPath(const std::vector<Span<const char>>& split, KeyPath& out) { for (size_t i = 1; i < split.size(); ++i) { Span<const char> elem = split[i]; diff --git a/src/test/blockencodings_tests.cpp b/src/test/blockencodings_tests.cpp index 5131fe8235..309b8d2d06 100644 --- a/src/test/blockencodings_tests.cpp +++ b/src/test/blockencodings_tests.cpp @@ -344,4 +344,49 @@ BOOST_AUTO_TEST_CASE(TransactionsRequestSerializationTest) { BOOST_CHECK_EQUAL(req1.indexes[3], req2.indexes[3]); } +BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationMaxTest) { + // Check that the highest legal index is decoded correctly + BlockTransactionsRequest req0; + req0.blockhash = InsecureRand256(); + req0.indexes.resize(1); + req0.indexes[0] = 0xffff; + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << req0; + + BlockTransactionsRequest req1; + stream >> req1; + BOOST_CHECK_EQUAL(req0.indexes.size(), req1.indexes.size()); + BOOST_CHECK_EQUAL(req0.indexes[0], req1.indexes[0]); +} + +BOOST_AUTO_TEST_CASE(TransactionsRequestDeserializationOverflowTest) { + // Any set of index deltas that starts with N values that sum to (0x10000 - N) + // causes the edge-case overflow that was originally not checked for. Such + // a request cannot be created by serializing a real BlockTransactionsRequest + // due to the overflow, so here we'll serialize from raw deltas. + BlockTransactionsRequest req0; + req0.blockhash = InsecureRand256(); + req0.indexes.resize(3); + req0.indexes[0] = 0x7000; + req0.indexes[1] = 0x10000 - 0x7000 - 2; + req0.indexes[2] = 0; + CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); + stream << req0.blockhash; + WriteCompactSize(stream, req0.indexes.size()); + WriteCompactSize(stream, req0.indexes[0]); + WriteCompactSize(stream, req0.indexes[1]); + WriteCompactSize(stream, req0.indexes[2]); + + BlockTransactionsRequest req1; + try { + stream >> req1; + // before patch: deserialize above succeeds and this check fails, demonstrating the overflow + BOOST_CHECK(req1.indexes[1] < req1.indexes[2]); + // this shouldn't be reachable before or after patch + BOOST_CHECK(0); + } catch(std::ios_base::failure &) { + // deserialize should fail + } +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index 521312f1b7..d3cbaedf00 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -2,17 +2,18 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <attributes.h> #include <coins.h> +#include <consensus/validation.h> #include <script/standard.h> +#include <test/test_bitcoin.h> #include <uint256.h> #include <undo.h> #include <util/strencodings.h> -#include <test/test_bitcoin.h> #include <validation.h> -#include <consensus/validation.h> -#include <vector> #include <map> +#include <vector> #include <boost/test/unit_test.hpp> @@ -36,7 +37,7 @@ class CCoinsViewTest : public CCoinsView std::map<COutPoint, Coin> map_; public: - bool GetCoin(const COutPoint& outpoint, Coin& coin) const override + NODISCARD bool GetCoin(const COutPoint& outpoint, Coin& coin) const override { std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint); if (it == map_.end()) { diff --git a/src/test/dbwrapper_tests.cpp b/src/test/dbwrapper_tests.cpp index 9957ac074b..1034d4ade2 100644 --- a/src/test/dbwrapper_tests.cpp +++ b/src/test/dbwrapper_tests.cpp @@ -102,15 +102,15 @@ BOOST_AUTO_TEST_CASE(dbwrapper_iterator) char key_res; uint256 val_res; - it->GetKey(key_res); - it->GetValue(val_res); + BOOST_REQUIRE(it->GetKey(key_res)); + BOOST_REQUIRE(it->GetValue(val_res)); BOOST_CHECK_EQUAL(key_res, key); BOOST_CHECK_EQUAL(val_res.ToString(), in.ToString()); it->Next(); - it->GetKey(key_res); - it->GetValue(val_res); + BOOST_REQUIRE(it->GetKey(key_res)); + BOOST_REQUIRE(it->GetValue(val_res)); BOOST_CHECK_EQUAL(key_res, key2); BOOST_CHECK_EQUAL(val_res.ToString(), in2.ToString()); diff --git a/src/test/getarg_tests.cpp b/src/test/getarg_tests.cpp index 0432ede3e0..14ddf4d10e 100644 --- a/src/test/getarg_tests.cpp +++ b/src/test/getarg_tests.cpp @@ -28,7 +28,7 @@ static void ResetArgs(const std::string& strArg) vecChar.push_back(s.c_str()); std::string error; - gArgs.ParseParameters(vecChar.size(), vecChar.data(), error); + BOOST_CHECK(gArgs.ParseParameters(vecChar.size(), vecChar.data(), error)); } static void SetupArgs(const std::vector<std::string>& args) diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp index ff19b12a9c..9acebdd820 100644 --- a/src/test/util_tests.cpp +++ b/src/test/util_tests.cpp @@ -187,7 +187,7 @@ struct TestArgsManager : public ArgsManager m_config_args.clear(); } std::string error; - ReadConfigStream(streamConfig, error); + BOOST_REQUIRE(ReadConfigStream(streamConfig, error)); } void SetNetworkOnlyArg(const std::string arg) { @@ -210,13 +210,13 @@ BOOST_AUTO_TEST_CASE(util_ParseParameters) std::string error; testArgs.SetupArgs(4, avail_args); - testArgs.ParseParameters(0, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(0, (char**)argv_test, error)); BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty()); - testArgs.ParseParameters(1, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error)); BOOST_CHECK(testArgs.GetOverrideArgs().empty() && testArgs.GetConfigArgs().empty()); - testArgs.ParseParameters(7, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error)); // expectation: -ignored is ignored (program name argument), // -a, -b and -ccc end up in map, -d ignored because it is after // a non-option argument (non-GNU option parsing) @@ -242,7 +242,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArg) "ignored", "-a", "-nob", "-c=0", "-d=1", "-e=false", "-f=true"}; std::string error; testArgs.SetupArgs(6, avail_args); - testArgs.ParseParameters(7, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(7, (char**)argv_test, error)); // Each letter should be set. for (const char opt : "abcdef") @@ -278,7 +278,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases) const char *argv_test[] = {"ignored", "-nofoo", "-foo", "-nobar=0"}; testArgs.SetupArgs(2, avail_args); std::string error; - testArgs.ParseParameters(4, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(4, (char**)argv_test, error)); // This was passed twice, second one overrides the negative setting. BOOST_CHECK(!testArgs.IsArgNegated("-foo")); @@ -290,7 +290,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases) // Config test const char *conf_test = "nofoo=1\nfoo=1\nnobar=0\n"; - testArgs.ParseParameters(1, (char**)argv_test, error); + BOOST_CHECK(testArgs.ParseParameters(1, (char**)argv_test, error)); testArgs.ReadConfigString(conf_test); // This was passed twice, second one overrides the negative setting, @@ -305,7 +305,7 @@ BOOST_AUTO_TEST_CASE(util_GetBoolArgEdgeCases) // Combined test const char *combo_test_args[] = {"ignored", "-nofoo", "-bar"}; const char *combo_test_conf = "foo=1\nnobar=1\n"; - testArgs.ParseParameters(3, (char**)combo_test_args, error); + BOOST_CHECK(testArgs.ParseParameters(3, (char**)combo_test_args, error)); testArgs.ReadConfigString(combo_test_conf); // Command line overrides, but doesn't erase old setting @@ -557,38 +557,38 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) const char* testnetconf = "testnet=1\nregtest=0\n[test]\nregtest=1"; std::string error; - test_args.ParseParameters(0, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "main"); - test_args.ParseParameters(2, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_regtest, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "regtest"); - test_args.ParseParameters(3, (char**)argv_test_no_reg, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error)); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(3, (char**)argv_both, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error)); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); - test_args.ParseParameters(0, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_regtest, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); - test_args.ParseParameters(3, (char**)argv_test_no_reg, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_test_no_reg, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(3, (char**)argv_both, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); @@ -596,23 +596,23 @@ BOOST_AUTO_TEST_CASE(util_GetChainName) // [test] regtest=1 potentially relevant) doesn't break things test_args.SelectConfigNetwork("test"); - test_args.ParseParameters(0, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(0, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_testnet, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_testnet, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(2, (char**)argv_regtest, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_regtest, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); - test_args.ParseParameters(2, (char**)argv_test_no_reg, error); + BOOST_CHECK(test_args.ParseParameters(2, (char**)argv_test_no_reg, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_EQUAL(test_args.GetChainName(), "test"); - test_args.ParseParameters(3, (char**)argv_both, error); + BOOST_CHECK(test_args.ParseParameters(3, (char**)argv_both, error)); test_args.ReadConfigString(testnetconf); BOOST_CHECK_THROW(test_args.GetChainName(), std::runtime_error); } diff --git a/src/util/moneystr.h b/src/util/moneystr.h index 9133f46d5d..b8e2812a96 100644 --- a/src/util/moneystr.h +++ b/src/util/moneystr.h @@ -9,16 +9,17 @@ #ifndef BITCOIN_UTIL_MONEYSTR_H #define BITCOIN_UTIL_MONEYSTR_H -#include <stdint.h> -#include <string> - #include <amount.h> +#include <attributes.h> + +#include <cstdint> +#include <string> /* Do not use these functions to represent or parse monetary amounts to or from * JSON but use AmountFromValue and ValueFromAmount for that. */ std::string FormatMoney(const CAmount& n); -bool ParseMoney(const std::string& str, CAmount& nRet); -bool ParseMoney(const char* pszIn, CAmount& nRet); +NODISCARD bool ParseMoney(const std::string& str, CAmount& nRet); +NODISCARD bool ParseMoney(const char* pszIn, CAmount& nRet); #endif // BITCOIN_UTIL_MONEYSTR_H diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 2a2df43337..46146be66f 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -263,7 +263,7 @@ std::string DecodeBase32(const std::string& str) return std::string((const char*)vchRet.data(), vchRet.size()); } -static bool ParsePrechecks(const std::string& str) +NODISCARD static bool ParsePrechecks(const std::string& str) { if (str.empty()) // No empty string allowed return false; diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 87ccf40a1b..7d16d7dcfd 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -9,7 +9,9 @@ #ifndef BITCOIN_UTIL_STRENCODINGS_H #define BITCOIN_UTIL_STRENCODINGS_H -#include <stdint.h> +#include <attributes.h> + +#include <cstdint> #include <string> #include <vector> @@ -92,35 +94,35 @@ constexpr inline bool IsSpace(char c) noexcept { * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -bool ParseInt32(const std::string& str, int32_t *out); +NODISCARD bool ParseInt32(const std::string& str, int32_t *out); /** * Convert string to signed 64-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -bool ParseInt64(const std::string& str, int64_t *out); +NODISCARD bool ParseInt64(const std::string& str, int64_t *out); /** * Convert decimal string to unsigned 32-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -bool ParseUInt32(const std::string& str, uint32_t *out); +NODISCARD bool ParseUInt32(const std::string& str, uint32_t *out); /** * Convert decimal string to unsigned 64-bit integer with strict parse error feedback. * @returns true if the entire string could be parsed as valid integer, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -bool ParseUInt64(const std::string& str, uint64_t *out); +NODISCARD bool ParseUInt64(const std::string& str, uint64_t *out); /** * Convert string to double with strict parse error feedback. * @returns true if the entire string could be parsed as valid double, * false if not the entire string could be parsed or when overflow or underflow occurred. */ -bool ParseDouble(const std::string& str, double *out); +NODISCARD bool ParseDouble(const std::string& str, double *out); template<typename T> std::string HexStr(const T itbegin, const T itend, bool fSpaces=false) @@ -173,7 +175,7 @@ bool TimingResistantEqual(const T& a, const T& b) * @returns true on success, false on error. * @note The result must be in the range (-10^18,10^18), otherwise an overflow error will trigger. */ -bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); +NODISCARD bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out); /** Convert from one power-of-2 number base to another. */ template<int frombits, int tobits, bool pad, typename O, typename I> @@ -200,7 +202,7 @@ bool ConvertBits(const O& outfn, I it, I end) { } /** Parse an HD keypaths like "m/7/0'/2000". */ -bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); +NODISCARD bool ParseHDKeypath(const std::string& keypath_str, std::vector<uint32_t>& keypath); /** * Converts the given character to its lowercase equivalent. diff --git a/src/util/system.cpp b/src/util/system.cpp index f6f36c2238..8e201ec590 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -73,7 +73,6 @@ #include <malloc.h> #endif -#include <boost/thread.hpp> #include <openssl/crypto.h> #include <openssl/rand.h> #include <openssl/conf.h> @@ -372,15 +371,17 @@ ArgsManager::ArgsManager() : // nothing to do } -void ArgsManager::WarnForSectionOnlyArgs() +const std::set<std::string> ArgsManager::GetUnsuitableSectionOnlyArgs() const { + std::set<std::string> unsuitables; + LOCK(cs_args); // if there's no section selected, don't worry - if (m_network.empty()) return; + if (m_network.empty()) return std::set<std::string> {}; // if it's okay to use the default section for this network, don't worry - if (m_network == CBaseChainParams::MAIN) return; + if (m_network == CBaseChainParams::MAIN) return std::set<std::string> {}; for (const auto& arg : m_network_only_args) { std::pair<bool, std::string> found_result; @@ -398,8 +399,28 @@ void ArgsManager::WarnForSectionOnlyArgs() if (!found_result.first) continue; // otherwise, issue a warning - LogPrintf("Warning: Config setting for %s only applied on %s network when in [%s] section.\n", arg, m_network, m_network); + unsuitables.insert(arg); } + return unsuitables; +} + + +const std::set<std::string> ArgsManager::GetUnrecognizedSections() const +{ + // Section names to be recognized in the config file. + static const std::set<std::string> available_sections{ + CBaseChainParams::REGTEST, + CBaseChainParams::TESTNET, + CBaseChainParams::MAIN + }; + std::set<std::string> diff; + + LOCK(cs_args); + std::set_difference( + m_config_sections.begin(), m_config_sections.end(), + available_sections.begin(), available_sections.end(), + std::inserter(diff, diff.end())); + return diff; } void ArgsManager::SelectConfigNetwork(const std::string& network) @@ -820,7 +841,7 @@ static std::string TrimString(const std::string& str, const std::string& pattern return str.substr(front, end - front + 1); } -static bool GetConfigOptions(std::istream& stream, std::string& error, std::vector<std::pair<std::string, std::string>> &options) +static bool GetConfigOptions(std::istream& stream, std::string& error, std::vector<std::pair<std::string, std::string>>& options, std::set<std::string>& sections) { std::string str, prefix; std::string::size_type pos; @@ -835,7 +856,9 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect str = TrimString(str, pattern); if (!str.empty()) { if (*str.begin() == '[' && *str.rbegin() == ']') { - prefix = str.substr(1, str.size() - 2) + '.'; + const std::string section = str.substr(1, str.size() - 2); + sections.insert(section); + prefix = section + '.'; } else if (*str.begin() == '-') { error = strprintf("parse error on line %i: %s, options in configuration file must be specified without leading -", linenr, str); return false; @@ -847,6 +870,9 @@ static bool GetConfigOptions(std::istream& stream, std::string& error, std::vect return false; } options.emplace_back(name, value); + if ((pos = name.rfind('.')) != std::string::npos) { + sections.insert(name.substr(0, pos)); + } } else { error = strprintf("parse error on line %i: %s", linenr, str); if (str.size() >= 2 && str.substr(0, 2) == "no") { @@ -864,7 +890,8 @@ bool ArgsManager::ReadConfigStream(std::istream& stream, std::string& error, boo { LOCK(cs_args); std::vector<std::pair<std::string, std::string>> options; - if (!GetConfigOptions(stream, error, options)) { + m_config_sections.clear(); + if (!GetConfigOptions(stream, error, options, m_config_sections)) { return false; } for (const std::pair<std::string, std::string>& option : options) { diff --git a/src/util/system.h b/src/util/system.h index 5634b8dd61..dca32cc6fc 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -14,6 +14,7 @@ #include <config/bitcoin-config.h> #endif +#include <attributes.h> #include <compat.h> #include <fs.h> #include <logging.h> @@ -148,8 +149,9 @@ protected: std::string m_network GUARDED_BY(cs_args); std::set<std::string> m_network_only_args GUARDED_BY(cs_args); std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args); + std::set<std::string> m_config_sections GUARDED_BY(cs_args); - bool ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys = false); + NODISCARD bool ReadConfigStream(std::istream& stream, std::string& error, bool ignore_invalid_keys = false); public: ArgsManager(); @@ -159,8 +161,8 @@ public: */ void SelectConfigNetwork(const std::string& network); - bool ParseParameters(int argc, const char* const argv[], std::string& error); - bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false); + NODISCARD bool ParseParameters(int argc, const char* const argv[], std::string& error); + NODISCARD bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false); /** * Log warnings for options in m_section_only_args when @@ -168,7 +170,12 @@ public: * on the command line or in a network-specific section in the * config file. */ - void WarnForSectionOnlyArgs(); + const std::set<std::string> GetUnsuitableSectionOnlyArgs() const; + + /** + * Log warnings for unrecognized section names in the config file. + */ + const std::set<std::string> GetUnrecognizedSections() const; /** * Return a vector of strings of the given argument diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index 74787eb5d2..d75e30d336 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -56,9 +56,8 @@ bool WalletDatabaseFileId::operator==(const WalletDatabaseFileId& rhs) const return memcmp(value, &rhs.value, sizeof(value)) == 0; } -BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename) +static void SplitWalletPath(const fs::path& wallet_path, fs::path& env_directory, std::string& database_filename) { - fs::path env_directory; if (fs::is_regular_file(wallet_path)) { // Special case for backwards compatibility: if wallet path points to an // existing file, treat it as the path to a BDB data file in a parent @@ -71,6 +70,23 @@ BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& data env_directory = wallet_path; database_filename = "wallet.dat"; } +} + +bool IsWalletLoaded(const fs::path& wallet_path) +{ + fs::path env_directory; + std::string database_filename; + SplitWalletPath(wallet_path, env_directory, database_filename); + LOCK(cs_db); + auto env = g_dbenvs.find(env_directory.string()); + if (env == g_dbenvs.end()) return false; + return env->second.IsDatabaseLoaded(database_filename); +} + +BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename) +{ + fs::path env_directory; + SplitWalletPath(wallet_path, env_directory, database_filename); LOCK(cs_db); // Note: An unused temporary BerkeleyEnvironment object may be created inside the // emplace function if the key already exists. This is a little inefficient, @@ -90,13 +106,13 @@ void BerkeleyEnvironment::Close() fDbEnvInit = false; - for (auto& db : mapDb) { + for (auto& db : m_databases) { auto count = mapFileUseCount.find(db.first); assert(count == mapFileUseCount.end() || count->second == 0); - if (db.second) { - db.second->close(0); - delete db.second; - db.second = nullptr; + BerkeleyDatabase& database = db.second.get(); + if (database.m_db) { + database.m_db->close(0); + database.m_db.reset(); } } @@ -463,7 +479,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo if (!env->Open(false /* retry */)) throw std::runtime_error("BerkeleyBatch: Failed to open database environment."); - pdb = env->mapDb[strFilename]; + pdb = database.m_db.get(); if (pdb == nullptr) { int ret; std::unique_ptr<Db> pdb_temp = MakeUnique<Db>(env->dbenv.get(), 0); @@ -508,7 +524,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo } pdb = pdb_temp.release(); - env->mapDb[strFilename] = pdb; + database.m_db.reset(pdb); if (fCreate && !Exists(std::string("version"))) { bool fTmp = fReadOnly; @@ -563,12 +579,13 @@ void BerkeleyEnvironment::CloseDb(const std::string& strFile) { { LOCK(cs_db); - if (mapDb[strFile] != nullptr) { + auto it = m_databases.find(strFile); + assert(it != m_databases.end()); + BerkeleyDatabase& database = it->second.get(); + if (database.m_db) { // Close the database handle - Db* pdb = mapDb[strFile]; - pdb->close(0); - delete pdb; - mapDb[strFile] = nullptr; + database.m_db->close(0); + database.m_db.reset(); } } } @@ -586,7 +603,7 @@ void BerkeleyEnvironment::ReloadDbEnv() }); std::vector<std::string> filenames; - for (auto it : mapDb) { + for (auto it : m_databases) { filenames.push_back(it.first); } // Close the individual Db's diff --git a/src/wallet/db.h b/src/wallet/db.h index 8f96483a18..e453d441d7 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -31,6 +31,8 @@ struct WalletDatabaseFileId { bool operator==(const WalletDatabaseFileId& rhs) const; }; +class BerkeleyDatabase; + class BerkeleyEnvironment { private: @@ -43,7 +45,7 @@ private: public: std::unique_ptr<DbEnv> dbenv; std::map<std::string, int> mapFileUseCount; - std::map<std::string, Db*> mapDb; + std::map<std::string, std::reference_wrapper<BerkeleyDatabase>> m_databases; std::unordered_map<std::string, WalletDatabaseFileId> m_fileids; std::condition_variable_any m_db_in_use; @@ -54,6 +56,7 @@ public: void MakeMock(); bool IsMock() const { return fMockDb; } bool IsInitialized() const { return fDbEnvInit; } + bool IsDatabaseLoaded(const std::string& db_filename) const { return m_databases.find(db_filename) != m_databases.end(); } fs::path Directory() const { return strPath; } /** @@ -95,6 +98,9 @@ public: } }; +/** Return whether a wallet database is currently loaded. */ +bool IsWalletLoaded(const fs::path& wallet_path); + /** Get BerkeleyEnvironment and database filename given a wallet path. */ BerkeleyEnvironment* GetWalletEnv(const fs::path& wallet_path, std::string& database_filename); @@ -115,6 +121,8 @@ public: nUpdateCounter(0), nLastSeen(0), nLastFlushed(0), nLastWalletUpdate(0) { env = GetWalletEnv(wallet_path, strFile); + auto inserted = env->m_databases.emplace(strFile, std::ref(*this)); + assert(inserted.second); if (mock) { env->Close(); env->Reset(); @@ -122,6 +130,13 @@ public: } } + ~BerkeleyDatabase() { + if (env) { + size_t erased = env->m_databases.erase(strFile); + assert(erased == 1); + } + } + /** Return object for accessing database at specified path. */ static std::unique_ptr<BerkeleyDatabase> Create(const fs::path& path) { @@ -161,6 +176,9 @@ public: unsigned int nLastFlushed; int64_t nLastWalletUpdate; + /** Database pointer. This is initialized lazily and reset during flushes, so it can be null. */ + std::unique_ptr<Db> m_db; + private: /** BerkeleyDB specific */ BerkeleyEnvironment *env; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 6269bc9d3c..fa1e209bf2 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -109,8 +109,14 @@ UniValue importprivkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "importprivkey \"privkey\" ( \"label\" ) ( rescan )\n" - "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n" + RPCHelpMan{"importprivkey", + "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n", + { + {"privkey", RPCArg::Type::STR, false}, + {"label", RPCArg::Type::STR, true}, + {"rescan", RPCArg::Type::BOOL, true}, + }} + .ToString() + "Hint: use importmulti to import more than one private key.\n" "\nArguments:\n" "1. \"privkey\" (string, required) The private key (see dumpprivkey)\n" @@ -206,8 +212,9 @@ UniValue abortrescan(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 0) throw std::runtime_error( - "abortrescan\n" - "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n" + RPCHelpMan{"abortrescan", + "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n", {}} + .ToString() + "\nExamples:\n" "\nImport a private key\n" + HelpExampleCli("importprivkey", "\"mykey\"") + @@ -268,8 +275,15 @@ UniValue importaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) throw std::runtime_error( - "importaddress \"address\" ( \"label\" rescan p2sh )\n" - "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n" + RPCHelpMan{"importaddress", + "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n", + { + {"address", RPCArg::Type::STR, false}, + {"label", RPCArg::Type::STR, true}, + {"rescan", RPCArg::Type::BOOL, true}, + {"p2sh", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"address\" (string, required) The Bitcoin address (or hex-encoded script)\n" "2. \"label\" (string, optional, default=\"\") An optional label\n" @@ -348,8 +362,13 @@ UniValue importprunedfunds(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 2) throw std::runtime_error( - "importprunedfunds \"rawtransaction\" \"txoutproof\"\n" - "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n" + RPCHelpMan{"importprunedfunds", + "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n", + { + {"rawtransaction", RPCArg::Type::STR_HEX, false}, + {"txoutproof", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"rawtransaction\" (string, required) A raw transaction in hex funding an already-existing address in wallet\n" "2. \"txoutproof\" (string, required) The hex output from gettxoutproof that contains the transaction\n" @@ -412,8 +431,12 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "removeprunedfunds \"txid\"\n" - "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n" + RPCHelpMan{"removeprunedfunds", + "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"txid\" (string, required) The hex-encoded id of the transaction you are deleting\n" "\nExamples:\n" @@ -451,8 +474,14 @@ UniValue importpubkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "importpubkey \"pubkey\" ( \"label\" rescan )\n" - "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n" + RPCHelpMan{"importpubkey", + "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n", + { + {"pubkey", RPCArg::Type::STR, false}, + {"label", RPCArg::Type::STR, true}, + {"rescan", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"pubkey\" (string, required) The hex-encoded public key\n" "2. \"label\" (string, optional, default=\"\") An optional label\n" @@ -523,8 +552,12 @@ UniValue importwallet(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "importwallet \"filename\"\n" - "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n" + RPCHelpMan{"importwallet", + "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n", + { + {"filename", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"filename\" (string, required) The wallet file\n" "\nExamples:\n" @@ -653,9 +686,13 @@ UniValue dumpprivkey(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "dumpprivkey \"address\"\n" - "\nReveals the private key corresponding to 'address'.\n" - "Then the importprivkey can be used with this output\n" + RPCHelpMan{"dumpprivkey", + "\nReveals the private key corresponding to 'address'.\n" + "Then the importprivkey can be used with this output\n", + { + {"address", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address for the private key\n" "\nResult:\n" @@ -698,11 +735,15 @@ UniValue dumpwallet(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "dumpwallet \"filename\"\n" - "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n" - "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n" - "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n" - "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n" + RPCHelpMan{"dumpwallet", + "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n" + "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n" + "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n" + "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n", + { + {"filename", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n" "\nResult:\n" @@ -1083,11 +1124,35 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) return NullUniValue; } - // clang-format off if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) throw std::runtime_error( - "importmulti \"requests\" ( \"options\" )\n" - "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options). Requires a new wallet backup.\n\n" + RPCHelpMan{"importmulti", + "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options). Requires a new wallet backup.\n\n", + { + {"requests", RPCArg::Type::ARR, + { + {"", RPCArg::Type::OBJ, + { + { + {"scriptPubKey", RPCArg::Type::STR, false}, + {"timestamp", RPCArg::Type::NUM, false}, + {"redeemscript", RPCArg::Type::STR, true}, + {"witnessscript", RPCArg::Type::STR, true}, + {"internal", RPCArg::Type::BOOL, true}, + {"watchonly", RPCArg::Type::BOOL, true}, + {"label", RPCArg::Type::STR, true}, + }, + }, + false}, + }, + false, "\"requests\""}, + {"options", RPCArg::Type::OBJ, + { + {"rescan", RPCArg::Type::BOOL, true}, + }, + true, "\"options\""}, + }} + .ToString() + "Arguments:\n" "1. requests (array, required) Data to be imported\n" " [ (array of json objects)\n" @@ -1123,7 +1188,6 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) "\nResponse is an array with the same size as the input that has the execution result :\n" " [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n"); - // clang-format on RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0e2f8864b1..ecc8fa2643 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -149,10 +149,15 @@ static UniValue getnewaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 2) throw std::runtime_error( - "getnewaddress ( \"label\" \"address_type\" )\n" - "\nReturns a new Bitcoin address for receiving payments.\n" - "If 'label' is specified, it is added to the address book \n" - "so payments received with the address will be associated with 'label'.\n" + RPCHelpMan{"getnewaddress", + "\nReturns a new Bitcoin address for receiving payments.\n" + "If 'label' is specified, it is added to the address book \n" + "so payments received with the address will be associated with 'label'.\n", + { + {"label", RPCArg::Type::STR, true}, + {"address_type", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. \"label\" (string, optional) The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n" "2. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n" @@ -209,9 +214,13 @@ static UniValue getrawchangeaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "getrawchangeaddress ( \"address_type\" )\n" - "\nReturns a new Bitcoin address, for receiving change.\n" - "This is for use with raw transactions, NOT normal use.\n" + RPCHelpMan{"getrawchangeaddress", + "\nReturns a new Bitcoin address, for receiving change.\n" + "This is for use with raw transactions, NOT normal use.\n", + { + {"address_type", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -changetype.\n" "\nResult:\n" @@ -263,8 +272,13 @@ static UniValue setlabel(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 2) throw std::runtime_error( - "setlabel \"address\" \"label\"\n" - "\nSets the label associated with the given address.\n" + RPCHelpMan{"setlabel", + "\nSets the label associated with the given address.\n", + { + {"address", RPCArg::Type::STR, false}, + {"label", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to be associated with a label.\n" "2. \"label\" (string, required) The label to assign to the address.\n" @@ -343,9 +357,20 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) throw std::runtime_error( - "sendtoaddress \"address\" amount ( \"comment\" \"comment_to\" subtractfeefromamount replaceable conf_target \"estimate_mode\")\n" - "\nSend an amount to a given address.\n" - + HelpRequiringPassphrase(pwallet) + + RPCHelpMan{"sendtoaddress", + "\nSend an amount to a given address.\n", + { + {"address", RPCArg::Type::STR, false}, + {"amount", RPCArg::Type::AMOUNT, false}, + {"comment", RPCArg::Type::STR, true}, + {"comment_to", RPCArg::Type::STR, true}, + {"subtractfeefromamount", RPCArg::Type::BOOL, true}, + {"replaceable", RPCArg::Type::BOOL, true}, + {"conf_target", RPCArg::Type::NUM, true}, + {"estimate_mode", RPCArg::Type::STR, true}, + }} + .ToString() + + HelpRequiringPassphrase(pwallet) + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to send to.\n" "2. \"amount\" (numeric or string, required) The amount in " + CURRENCY_UNIT + " to send. eg 0.1\n" @@ -433,10 +458,12 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "listaddressgroupings\n" - "\nLists groups of addresses which have had their common ownership\n" - "made public by common use as inputs or as the resulting change\n" - "in past transactions\n" + RPCHelpMan{"listaddressgroupings", + "\nLists groups of addresses which have had their common ownership\n" + "made public by common use as inputs or as the resulting change\n" + "in past transactions\n", + {}} + .ToString() + "\nResult:\n" "[\n" " [\n" @@ -493,9 +520,14 @@ static UniValue signmessage(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 2) throw std::runtime_error( - "signmessage \"address\" \"message\"\n" - "\nSign a message with the private key of an address" - + HelpRequiringPassphrase(pwallet) + "\n" + RPCHelpMan{"signmessage", + "\nSign a message with the private key of an address", + { + {"address", RPCArg::Type::STR, false}, + {"message", RPCArg::Type::STR, false}, + }} + .ToString() + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to use for the private key.\n" "2. \"message\" (string, required) The message to create a signature of.\n" @@ -557,8 +589,13 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "getreceivedbyaddress \"address\" ( minconf )\n" - "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n" + RPCHelpMan{"getreceivedbyaddress", + "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n", + { + {"address", RPCArg::Type::STR, false}, + {"minconf", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address for transactions.\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" @@ -626,8 +663,13 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "getreceivedbylabel \"label\" ( minconf )\n" - "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n" + RPCHelpMan{"getreceivedbylabel", + "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n", + { + {"label", RPCArg::Type::STR, false}, + {"minconf", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. \"label\" (string, required) The selected label, may be the default label using \"\".\n" "2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n" @@ -693,10 +735,16 @@ static UniValue getbalance(const JSONRPCRequest& request) if (request.fHelp || (request.params.size() > 3 )) throw std::runtime_error( - "getbalance ( \"dummy\" minconf include_watchonly )\n" - "\nReturns the total available balance.\n" - "The available balance is what the wallet considers currently spendable, and is\n" - "thus affected by options which limit spendability such as -spendzeroconfchange.\n" + RPCHelpMan{"getbalance", + "\nReturns the total available balance.\n" + "The available balance is what the wallet considers currently spendable, and is\n" + "thus affected by options which limit spendability such as -spendzeroconfchange.\n", + { + {"dummy", RPCArg::Type::STR, true}, + {"minconf", RPCArg::Type::NUM, true}, + {"include_watchonly", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. (dummy) (string, optional) Remains for backward compatibility. Must be excluded or set to \"*\".\n" "2. minconf (numeric, optional, default=0) Only include transactions confirmed at least this many times.\n" @@ -748,8 +796,9 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request) if (request.fHelp || request.params.size() > 0) throw std::runtime_error( - "getunconfirmedbalance\n" - "Returns the server's total unconfirmed balance\n"); + RPCHelpMan{"getunconfirmedbalance", + "Returns the server's total unconfirmed balance\n", {}} + .ToString()); // 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 @@ -773,9 +822,28 @@ static UniValue sendmany(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || request.params.size() > 8) throw std::runtime_error( - "sendmany \"\" {\"address\":amount,...} ( minconf \"comment\" [\"address\",...] replaceable conf_target \"estimate_mode\")\n" - "\nSend multiple times. Amounts are double-precision floating point numbers.\n" - + HelpRequiringPassphrase(pwallet) + "\n" + RPCHelpMan{"sendmany", + "\nSend multiple times. Amounts are double-precision floating point numbers.\n", + { + {"dummy", RPCArg::Type::STR, false, "\"\""}, + {"amounts", RPCArg::Type::OBJ, + { + {"address", RPCArg::Type::AMOUNT, false}, + }, + false}, + {"minconf", RPCArg::Type::NUM, true}, + {"comment", RPCArg::Type::STR, true}, + {"subtractfeefrom", RPCArg::Type::ARR, + { + {"address", RPCArg::Type::STR, true}, + }, + true}, + {"replaceable", RPCArg::Type::BOOL, true}, + {"conf_target", RPCArg::Type::NUM, true}, + {"estimate_mode", RPCArg::Type::STR, true}, + }} + .ToString() + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"dummy\" (string, required) Must be set to \"\" for backwards compatibility.\n" "2. \"amounts\" (string, required) A json object with addresses and amounts\n" @@ -1166,8 +1234,15 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 4) throw std::runtime_error( - "listreceivedbyaddress ( minconf include_empty include_watchonly address_filter )\n" - "\nList balances by receiving address.\n" + RPCHelpMan{"listreceivedbyaddress", + "\nList balances by receiving address.\n", + { + {"minconf", RPCArg::Type::NUM, true}, + {"include_empty", RPCArg::Type::BOOL, true}, + {"include_watchonly", RPCArg::Type::BOOL, true}, + {"address_filter", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" "2. include_empty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n" @@ -1217,8 +1292,14 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 3) throw std::runtime_error( - "listreceivedbylabel ( minconf include_empty include_watchonly)\n" - "\nList received transactions by label.\n" + RPCHelpMan{"listreceivedbylabel", + "\nList received transactions by label.\n", + { + {"minconf", RPCArg::Type::NUM, true}, + {"include_empty", RPCArg::Type::BOOL, true}, + {"include_watchonly", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n" "2. include_empty (bool, optional, default=false) Whether to include labels that haven't received any payments.\n" @@ -1356,9 +1437,16 @@ UniValue listtransactions(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 4) throw std::runtime_error( - "listtransactions ( \"label\" count skip include_watchonly )\n" - "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n" - "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n" + RPCHelpMan{"listtransactions", + "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n" + "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n", + { + {"label", RPCArg::Type::STR, true}, + {"count", RPCArg::Type::NUM, true}, + {"skip", RPCArg::Type::NUM, true}, + {"include_watchonly", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"label\" (string, optional) If set, should be a valid label name to return only incoming transactions\n" " with the specified label, or \"*\" to disable filtering and return all transactions.\n" @@ -1483,10 +1571,17 @@ static UniValue listsinceblock(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 4) throw std::runtime_error( - "listsinceblock ( \"blockhash\" target_confirmations include_watchonly include_removed )\n" - "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n" - "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n" - "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n" + RPCHelpMan{"listsinceblock", + "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n" + "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n" + "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n", + { + {"blockhash", RPCArg::Type::STR, true}, + {"target_confirmations", RPCArg::Type::NUM, true}, + {"include_watchonly", RPCArg::Type::BOOL, true}, + {"include_removed", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"blockhash\" (string, optional) The block hash to list transactions since\n" "2. target_confirmations: (numeric, optional, default=1) Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value\n" @@ -1623,8 +1718,13 @@ static UniValue gettransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( - "gettransaction \"txid\" ( include_watchonly )\n" - "\nGet detailed information about in-wallet transaction <txid>\n" + RPCHelpMan{"gettransaction", + "\nGet detailed information about in-wallet transaction <txid>\n", + { + {"txid", RPCArg::Type::STR, false}, + {"include_watchonly", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "2. \"include_watchonly\" (bool, optional, default=false) Whether to include watch-only addresses in balance calculation and details[]\n" @@ -1718,12 +1818,16 @@ static UniValue abandontransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "abandontransaction \"txid\"\n" - "\nMark in-wallet transaction <txid> as abandoned\n" - "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n" - "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n" - "It only works on transactions which are not included in a block and are not currently in the mempool.\n" - "It has no effect on transactions which are already abandoned.\n" + RPCHelpMan{"abandontransaction", + "\nMark in-wallet transaction <txid> as abandoned\n" + "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n" + "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n" + "It only works on transactions which are not included in a block and are not currently in the mempool.\n" + "It has no effect on transactions which are already abandoned.\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + }} + .ToString() + "\nArguments:\n" "1. \"txid\" (string, required) The transaction id\n" "\nResult:\n" @@ -1764,8 +1868,12 @@ static UniValue backupwallet(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "backupwallet \"destination\"\n" - "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n" + RPCHelpMan{"backupwallet", + "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n", + { + {"destination", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"destination\" (string) The destination directory or file\n" "\nExamples:\n" @@ -1800,9 +1908,13 @@ static UniValue keypoolrefill(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "keypoolrefill ( newsize )\n" - "\nFills the keypool." - + HelpRequiringPassphrase(pwallet) + "\n" + RPCHelpMan{"keypoolrefill", + "\nFills the keypool.", + { + {"newsize", RPCArg::Type::NUM, true}, + }} + .ToString() + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments\n" "1. newsize (numeric, optional, default=100) The new keypool size\n" "\nExamples:\n" @@ -1847,9 +1959,14 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 2) { throw std::runtime_error( - "walletpassphrase \"passphrase\" timeout\n" - "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" - "This is needed prior to performing transactions related to private keys such as sending bitcoins\n" + RPCHelpMan{"walletpassphrase", + "\nStores the wallet decryption key in memory for 'timeout' seconds.\n" + "This is needed prior to performing transactions related to private keys such as sending bitcoins\n", + { + {"passphrase", RPCArg::Type::STR, false}, + {"timeout", RPCArg::Type::NUM, false}, + }} + .ToString() + "\nArguments:\n" "1. \"passphrase\" (string, required) The wallet passphrase\n" "2. timeout (numeric, required) The time to keep the decryption key in seconds; capped at 100000000 (~3 years).\n" @@ -1900,8 +2017,13 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) } else throw std::runtime_error( - "walletpassphrase <passphrase> <timeout>\n" - "Stores the wallet decryption key in memory for <timeout> seconds."); + RPCHelpMan{"walletpassphrase", + "Stores the wallet decryption key in memory for <timeout> seconds.", + { + {"passphrase", RPCArg::Type::STR, false}, + {"timeout", RPCArg::Type::NUM, false}, + }} + .ToString()); pwallet->TopUpKeyPool(); @@ -1934,8 +2056,13 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 2) { throw std::runtime_error( - "walletpassphrasechange \"oldpassphrase\" \"newpassphrase\"\n" - "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n" + RPCHelpMan{"walletpassphrasechange", + "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n", + { + {"oldpassphrase", RPCArg::Type::STR, false}, + {"newpassphrase", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"oldpassphrase\" (string) The current passphrase\n" "2. \"newpassphrase\" (string) The new passphrase\n" @@ -1964,8 +2091,13 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request) if (strOldWalletPass.length() < 1 || strNewWalletPass.length() < 1) throw std::runtime_error( - "walletpassphrasechange <oldpassphrase> <newpassphrase>\n" - "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>."); + RPCHelpMan{"walletpassphrasechange", + "Changes the wallet passphrase from <oldpassphrase> to <newpassphrase>.", + { + {"oldpassphrase", RPCArg::Type::STR, false}, + {"newpassphrase", RPCArg::Type::STR, false}, + }} + .ToString()); if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) { throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect."); @@ -1986,10 +2118,12 @@ static UniValue walletlock(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( - "walletlock\n" - "\nRemoves the wallet encryption key from memory, locking the wallet.\n" - "After calling this method, you will need to call walletpassphrase again\n" - "before being able to call any methods which require the wallet to be unlocked.\n" + RPCHelpMan{"walletlock", + "\nRemoves the wallet encryption key from memory, locking the wallet.\n" + "After calling this method, you will need to call walletpassphrase again\n" + "before being able to call any methods which require the wallet to be unlocked.\n", + {}} + .ToString() + "\nExamples:\n" "\nSet the passphrase for 2 minutes to perform a transaction\n" + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") + @@ -2027,12 +2161,16 @@ static UniValue encryptwallet(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "encryptwallet \"passphrase\"\n" - "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" - "After this, any calls that interact with private keys such as sending or signing \n" - "will require the passphrase to be set prior the making these calls.\n" - "Use the walletpassphrase call for this, and then walletlock call.\n" - "If the wallet is already encrypted, use the walletpassphrasechange call.\n" + RPCHelpMan{"encryptwallet", + "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n" + "After this, any calls that interact with private keys such as sending or signing \n" + "will require the passphrase to be set prior the making these calls.\n" + "Use the walletpassphrase call for this, and then walletlock call.\n" + "If the wallet is already encrypted, use the walletpassphrasechange call.\n", + { + {"passphrase", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"passphrase\" (string) The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long.\n" "\nExamples:\n" @@ -2064,8 +2202,12 @@ static UniValue encryptwallet(const JSONRPCRequest& request) if (strWalletPass.length() < 1) throw std::runtime_error( - "encryptwallet <passphrase>\n" - "Encrypts the wallet with <passphrase>."); + RPCHelpMan{"encryptwallet", + "Encrypts the wallet with <passphrase>.", + { + {"passphrase", RPCArg::Type::STR, false}, + }} + .ToString()); if (!pwallet->EncryptWallet(strWalletPass)) { throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet."); @@ -2086,6 +2228,13 @@ static UniValue lockunspent(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) throw std::runtime_error( RPCHelpMan{"lockunspent", + "\nUpdates list of temporarily unspendable outputs.\n" + "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" + "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n" + "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n" + "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" + "is always cleared (by virtue of process exit) when a node stops or fails.\n" + "Also see the listunspent call\n", { {"unlock", RPCArg::Type::BOOL, false}, {"transactions", RPCArg::Type::ARR, @@ -2100,13 +2249,6 @@ static UniValue lockunspent(const JSONRPCRequest& request) true}, }} .ToString() + - "\nUpdates list of temporarily unspendable outputs.\n" - "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" - "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n" - "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n" - "Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n" - "is always cleared (by virtue of process exit) when a node stops or fails.\n" - "Also see the listunspent call\n" "\nArguments:\n" "1. unlock (boolean, required) Whether to unlock (true) or lock (false) the specified transactions\n" "2. \"transactions\" (string, optional) A json array of objects. Each object the txid (string) vout (numeric)\n" @@ -2225,9 +2367,11 @@ static UniValue listlockunspent(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 0) throw std::runtime_error( - "listlockunspent\n" - "\nReturns list of temporarily unspendable outputs.\n" - "See the lockunspent call to lock and unlock transactions for spending.\n" + RPCHelpMan{"listlockunspent", + "\nReturns list of temporarily unspendable outputs.\n" + "See the lockunspent call to lock and unlock transactions for spending.\n", + {}} + .ToString() + "\nResult:\n" "[\n" " {\n" @@ -2279,8 +2423,12 @@ static UniValue settxfee(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 1) { throw std::runtime_error( - "settxfee amount\n" - "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n" + RPCHelpMan{"settxfee", + "\nSet the transaction fee per kB for this wallet. Overrides the global -paytxfee command line parameter.\n", + { + {"amount", RPCArg::Type::NUM, false}, + }} + .ToString() + "\nArguments:\n" "1. amount (numeric or string, required) The transaction fee in " + CURRENCY_UNIT + "/kB\n" "\nResult\n" @@ -2319,8 +2467,9 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "getwalletinfo\n" - "Returns an object containing various wallet state info.\n" + RPCHelpMan{"getwalletinfo", + "Returns an object containing various wallet state info.\n", {}} + .ToString() + "\nResult:\n" "{\n" " \"walletname\": xxxxx, (string) the wallet name\n" @@ -2381,8 +2530,9 @@ static UniValue listwalletdir(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( - "listwalletdir\n" - "Returns a list of wallets in the wallet directory.\n" + RPCHelpMan{"listwalletdir", + "Returns a list of wallets in the wallet directory.\n", {}} + .ToString() + "{\n" " \"wallets\" : [ (json array of objects)\n" " {\n" @@ -2413,9 +2563,11 @@ static UniValue listwallets(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "listwallets\n" - "Returns a list of currently loaded wallets.\n" - "For full information on the wallet, use \"getwalletinfo\"\n" + RPCHelpMan{"listwallets", + "Returns a list of currently loaded wallets.\n" + "For full information on the wallet, use \"getwalletinfo\"\n", + {}} + .ToString() + "\nResult:\n" "[ (json array of strings)\n" " \"walletname\" (string) the wallet name\n" @@ -2445,10 +2597,14 @@ static UniValue loadwallet(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "loadwallet \"filename\"\n" - "\nLoads a wallet from a wallet file or directory." - "\nNote that all wallet command-line options used when starting bitcoind will be" - "\napplied to the new wallet (eg -zapwallettxes, upgradewallet, rescan, etc).\n" + RPCHelpMan{"loadwallet", + "\nLoads a wallet from a wallet file or directory." + "\nNote that all wallet command-line options used when starting bitcoind will be" + "\napplied to the new wallet (eg -zapwallettxes, upgradewallet, rescan, etc).\n", + { + {"filename", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"filename\" (string, required) The wallet directory or .dat file.\n" "\nResult:\n" @@ -2498,8 +2654,13 @@ static UniValue createwallet(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "createwallet \"wallet_name\" ( disable_private_keys )\n" - "\nCreates and loads a new wallet.\n" + RPCHelpMan{"createwallet", + "\nCreates and loads a new wallet.\n", + { + {"wallet_name", RPCArg::Type::STR, false}, + {"disable_private_keys", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"wallet_name\" (string, required) The name for the new wallet. If this is a path, the wallet will be created at the path location.\n" "2. disable_private_keys (boolean, optional, default: false) Disable the possibility of private keys (only watchonlys are possible in this mode).\n" @@ -2550,9 +2711,13 @@ static UniValue unloadwallet(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() > 1) { throw std::runtime_error( - "unloadwallet ( \"wallet_name\" )\n" - "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n" - "Specifying the wallet name on a wallet endpoint is invalid." + RPCHelpMan{"unloadwallet", + "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n" + "Specifying the wallet name on a wallet endpoint is invalid.", + { + {"wallet_name", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. \"wallet_name\" (string, optional) The name of the wallet to unload.\n" "\nExamples:\n" @@ -2606,9 +2771,11 @@ static UniValue resendwallettransactions(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 0) throw std::runtime_error( - "resendwallettransactions\n" - "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n" - "Intended only for testing; the wallet code periodically re-broadcasts\n" + RPCHelpMan{"resendwallettransactions", + "Immediately re-broadcast unconfirmed wallet transactions to all peers.\n" + "Intended only for testing; the wallet code periodically re-broadcasts\n", + {}} + .ToString() + "automatically.\n" "Returns an RPC error if -walletbroadcast is set to false.\n" "Returns array of transaction ids that were re-broadcast.\n" @@ -2645,12 +2812,15 @@ static UniValue listunspent(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 5) throw std::runtime_error( RPCHelpMan{"listunspent", + "\nReturns array of unspent transaction outputs\n" + "with between minconf and maxconf (inclusive) confirmations.\n" + "Optionally filter to only include txouts paid to specified addresses.\n", { {"minconf", RPCArg::Type::NUM, true}, {"maxconf", RPCArg::Type::NUM, true}, {"addresses", RPCArg::Type::ARR, { - {"address", RPCArg::Type::STR_HEX, true}, + {"address", RPCArg::Type::STR, true}, }, true}, {"include_unsafe", RPCArg::Type::BOOL, true}, @@ -2661,12 +2831,9 @@ static UniValue listunspent(const JSONRPCRequest& request) {"maximumCount", RPCArg::Type::NUM, true}, {"minimumSumAmount", RPCArg::Type::AMOUNT, true}, }, - true}, + true, "query_options"}, }} .ToString() + - "\nReturns array of unspent transaction outputs\n" - "with between minconf and maxconf (inclusive) confirmations.\n" - "Optionally filter to only include txouts paid to specified addresses.\n" "\nArguments:\n" "1. minconf (numeric, optional, default=1) The minimum confirmations to filter\n" "2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter\n" @@ -2949,17 +3116,40 @@ static UniValue fundrawtransaction(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( - "fundrawtransaction \"hexstring\" ( options iswitness )\n" - "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n" - "This will not modify existing inputs, and will add at most one change output to the outputs.\n" - "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n" - "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n" - "The inputs added will not be signed, use signrawtransaction for that.\n" - "Note that all existing inputs must have their previous output transaction be in the wallet.\n" - "Note that all inputs selected must be of standard form and P2SH scripts must be\n" - "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n" - "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n" - "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n" + RPCHelpMan{"fundrawtransaction", + "\nAdd inputs to a transaction until it has enough in value to meet its out value.\n" + "This will not modify existing inputs, and will add at most one change output to the outputs.\n" + "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n" + "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n" + "The inputs added will not be signed, use signrawtransaction for that.\n" + "Note that all existing inputs must have their previous output transaction be in the wallet.\n" + "Note that all inputs selected must be of standard form and P2SH scripts must be\n" + "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n" + "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n" + "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n", + { + {"hexstring", RPCArg::Type::STR_HEX, false}, + {"options", RPCArg::Type::OBJ, + { + {"changeAddress", RPCArg::Type::STR, true}, + {"changePosition", RPCArg::Type::NUM, true}, + {"change_type", RPCArg::Type::STR, true}, + {"includeWatching", RPCArg::Type::BOOL, true}, + {"lockUnspents", RPCArg::Type::BOOL, true}, + {"feeRate", RPCArg::Type::AMOUNT, true}, + {"subtractFeeFromOutputs", RPCArg::Type::ARR, + { + {"vout_index", RPCArg::Type::NUM, true}, + }, + true}, + {"replaceable", RPCArg::Type::BOOL, true}, + {"conf_target", RPCArg::Type::NUM, true}, + {"estimate_mode", RPCArg::Type::STR, true}, + }, + true, "options"}, + {"iswitness", RPCArg::Type::BOOL, true}, + }} + .ToString() + "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of the raw transaction\n" "2. options (object, optional)\n" @@ -3039,6 +3229,9 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) throw std::runtime_error( RPCHelpMan{"signrawtransactionwithwallet", + "\nSign inputs for raw transaction (serialized, hex-encoded).\n" + "The second optional argument (may be null) is an array of previous transaction outputs that\n" + "this transaction depends on but may not yet be in the block chain.\n", { {"hexstring", RPCArg::Type::STR, false}, {"prevtxs", RPCArg::Type::ARR, @@ -3057,10 +3250,7 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) {"sighashtype", RPCArg::Type::STR, true}, }} .ToString() + - "\nSign inputs for raw transaction (serialized, hex-encoded).\n" - "The second optional argument (may be null) is an array of previous transaction outputs that\n" - "this transaction depends on but may not yet be in the block chain.\n" - + HelpRequiringPassphrase(pwallet) + "\n" + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"hexstring\" (string, required) The transaction hex string\n" @@ -3130,18 +3320,30 @@ static UniValue bumpfee(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "bumpfee \"txid\" ( options ) \n" - "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n" - "An opt-in RBF transaction with the given txid must be in the wallet.\n" - "The command will pay the additional fee by decreasing (or perhaps removing) its change output.\n" - "If the change output is not big enough to cover the increased fee, the command will currently fail\n" - "instead of adding new inputs to compensate. (A future implementation could improve this.)\n" - "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n" - "By default, the new fee will be calculated automatically using estimatesmartfee.\n" - "The user can specify a confirmation target for estimatesmartfee.\n" - "Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n" - "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" - "returned by getnetworkinfo) to enter the node's mempool.\n" + RPCHelpMan{"bumpfee", + "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n" + "An opt-in RBF transaction with the given txid must be in the wallet.\n" + "The command will pay the additional fee by decreasing (or perhaps removing) its change output.\n" + "If the change output is not big enough to cover the increased fee, the command will currently fail\n" + "instead of adding new inputs to compensate. (A future implementation could improve this.)\n" + "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n" + "By default, the new fee will be calculated automatically using estimatesmartfee.\n" + "The user can specify a confirmation target for estimatesmartfee.\n" + "Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n" + "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" + "returned by getnetworkinfo) to enter the node's mempool.\n", + { + {"txid", RPCArg::Type::STR_HEX, false}, + {"options", RPCArg::Type::OBJ, + { + {"confTarget", RPCArg::Type::NUM, true}, + {"totalFee", RPCArg::Type::AMOUNT, true}, + {"replaceable", RPCArg::Type::BOOL, true}, + {"estimate_mode", RPCArg::Type::STR, true}, + }, + true, "options"}, + }} + .ToString() + "\nArguments:\n" "1. txid (string, required) The txid to be bumped\n" "2. options (object, optional)\n" @@ -3282,8 +3484,13 @@ UniValue generate(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 2) { throw std::runtime_error( - "generate nblocks ( maxtries )\n" - "\nMine up to nblocks blocks immediately (before the RPC call returns) to an address in the wallet.\n" + RPCHelpMan{"generate", + "\nMine up to nblocks blocks immediately (before the RPC call returns) to an address in the wallet.\n", + { + {"nblocks", RPCArg::Type::NUM, false}, + {"maxtries", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. nblocks (numeric, required) How many blocks are generated immediately.\n" "2. maxtries (numeric, optional) How many iterations to try (default = 1000000).\n" @@ -3334,8 +3541,13 @@ UniValue rescanblockchain(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 2) { throw std::runtime_error( - "rescanblockchain (\"start_height\") (\"stop_height\")\n" - "\nRescan the local blockchain for wallet related transactions.\n" + RPCHelpMan{"rescanblockchain", + "\nRescan the local blockchain for wallet related transactions.\n", + { + {"start_height", RPCArg::Type::NUM, true}, + {"stop_height", RPCArg::Type::NUM, true}, + }} + .ToString() + "\nArguments:\n" "1. \"start_height\" (numeric, optional) block height where the rescan should start\n" "2. \"stop_height\" (numeric, optional) the last block height that should be scanned\n" @@ -3540,9 +3752,13 @@ UniValue getaddressinfo(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) { throw std::runtime_error( - "getaddressinfo \"address\"\n" - "\nReturn information about the given bitcoin address. Some information requires the address\n" - "to be in the wallet.\n" + RPCHelpMan{"getaddressinfo", + "\nReturn information about the given bitcoin address. Some information requires the address\n" + "to be in the wallet.\n", + { + {"address", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"address\" (string, required) The bitcoin address to get the information of.\n" "\nResult:\n" @@ -3660,8 +3876,12 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( - "getaddressesbylabel \"label\"\n" - "\nReturns the list of addresses assigned the specified label.\n" + RPCHelpMan{"getaddressesbylabel", + "\nReturns the list of addresses assigned the specified label.\n", + { + {"label", RPCArg::Type::STR, false}, + }} + .ToString() + "\nArguments:\n" "1. \"label\" (string, required) The label.\n" "\nResult:\n" @@ -3705,8 +3925,12 @@ static UniValue listlabels(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 1) throw std::runtime_error( - "listlabels ( \"purpose\" )\n" - "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n" + RPCHelpMan{"listlabels", + "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n", + { + {"purpose", RPCArg::Type::STR, true}, + }} + .ToString() + "\nArguments:\n" "1. \"purpose\" (string, optional) Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument.\n" "\nResult:\n" @@ -3759,10 +3983,15 @@ UniValue sethdseed(const JSONRPCRequest& request) if (request.fHelp || request.params.size() > 2) { throw std::runtime_error( - "sethdseed ( \"newkeypool\" \"seed\" )\n" - "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n" - "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n" - "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed.\n" + RPCHelpMan{"sethdseed", + "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n" + "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n" + "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed.\n", + { + {"newkeypool", RPCArg::Type::BOOL, true}, + {"seed", RPCArg::Type::STR, true}, + }} + .ToString() + HelpRequiringPassphrase(pwallet) + "\nArguments:\n" "1. \"newkeypool\" (boolean, optional, default=true) Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n" @@ -3898,10 +4127,17 @@ UniValue walletprocesspsbt(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) throw std::runtime_error( - "walletprocesspsbt \"psbt\" ( sign \"sighashtype\" bip32derivs )\n" - "\nUpdate a PSBT with input information from our wallet and then sign inputs\n" - "that we can sign for.\n" - + HelpRequiringPassphrase(pwallet) + "\n" + RPCHelpMan{"walletprocesspsbt", + "\nUpdate a PSBT with input information from our wallet and then sign inputs\n" + "that we can sign for.\n", + { + {"psbt", RPCArg::Type::STR, false}, + {"sign", RPCArg::Type::BOOL, true}, + {"sighashtype", RPCArg::Type::STR, true}, + {"bip32derivs", RPCArg::Type::BOOL, true}, + }} + .ToString() + + HelpRequiringPassphrase(pwallet) + "\n" "\nArguments:\n" "1. \"psbt\" (string, required) The transaction base64 string\n" @@ -3964,6 +4200,8 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) if (request.fHelp || request.params.size() < 2 || request.params.size() > 5) throw std::runtime_error( RPCHelpMan{"walletcreatefundedpsbt", + "\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n" + "Implements the Creator and Updater roles.\n", { {"inputs", RPCArg::Type::ARR, { @@ -3998,7 +4236,7 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) {"change_type", RPCArg::Type::STR, true}, {"includeWatching", RPCArg::Type::BOOL, true}, {"lockUnspents", RPCArg::Type::BOOL, true}, - {"feeRate", RPCArg::Type::NUM, true}, + {"feeRate", RPCArg::Type::AMOUNT, true}, {"subtractFeeFromOutputs", RPCArg::Type::ARR, { {"int", RPCArg::Type::NUM, true}, @@ -4008,12 +4246,10 @@ UniValue walletcreatefundedpsbt(const JSONRPCRequest& request) {"conf_target", RPCArg::Type::NUM, true}, {"estimate_mode", RPCArg::Type::STR, true}, }, - true}, + true, "options"}, {"bip32derivs", RPCArg::Type::BOOL, true}, }} .ToString() + - "\nCreates and funds a transaction in the Partially Signed Transaction format. Inputs will be added if supplied inputs are not enough\n" - "Implements the Creator and Updater roles.\n" "\nArguments:\n" "1. \"inputs\" (array, required) A json array of json objects\n" " [\n" diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8ea4c5c495..360d0f177c 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3872,11 +3872,9 @@ bool CWallet::Verify(interfaces::Chain& chain, const WalletLocation& location, b } // Make sure that the wallet path doesn't clash with an existing wallet path - for (auto wallet : GetWallets()) { - if (wallet->GetLocation().GetPath() == wallet_path) { - error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName()); - return false; - } + if (IsWalletLoaded(wallet_path)) { + error_string = strprintf("Error loading wallet %s. Duplicate -wallet filename specified.", location.GetName()); + return false; } try { diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp index 66b491427d..d3eab46e5f 100644 --- a/src/zmq/zmqrpc.cpp +++ b/src/zmq/zmqrpc.cpp @@ -17,8 +17,9 @@ UniValue getzmqnotifications(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 0) { throw std::runtime_error( - "getzmqnotifications\n" - "\nReturns information about the active ZeroMQ notifications.\n" + RPCHelpMan{"getzmqnotifications", + "\nReturns information about the active ZeroMQ notifications.\n", {}} + .ToString() + "\nResult:\n" "[\n" " { (json object)\n" |