From 58d923cd5b731e7806b7956746daf2d7d9420253 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Fri, 14 Aug 2020 09:24:42 +0200 Subject: [PATCH 01/12] Merge #19528: rpc: Assert that RPCArg names are equal to CRPCCommand ones (misc) fa77de2baa40ee828c850ef4068c76cc3619e87b rpc: Assert that RPCArg names are equal to CRPCCommand ones (misc) (MarcoFalke) fa50bdc755489b2e291ea5ba0e39e44a20c6c6de rpc: Limit echo to 10 args (MarcoFalke) fa89ca9b5bd334813fd7e7edb202c56b35076e8d refactor: Use C++11 range based for loops to simplify rpc code (MarcoFalke) fa459bdc87bbb050ca1c8d469023a96ed798540e rpc: Treat all args after a hidden arg as hidden as well (MarcoFalke) Pull request description: This is split out from #18531 to just touch the RPC methods in misc. Description from the main pr: ### Motivation RPCArg names in the rpc help are currently only used for documentation. However, in the future they could be used to teach the server the named arguments. Named arguments are currently registered by the `CRPCCommand`s and duplicate the RPCArg names from the documentation. This redundancy is fragile, and has lead to errors in the past (despite having linters to catch those kind of errors). See section "bugs found" for a list of bugs that have been found as a result of the changes here. ### Changes The changes here add an assert in the `CRPCCommand` constructor that the RPCArg names are identical to the ones in the `CRPCCommand`. ### Future work > Here or follow up, makes sense to also assert type of returned UniValue? Sure, but let's not get ahead of ourselves. I am going to submit any further works as follow-ups, including: * Removing the CRPCCommand arguments, now that they are asserted to be equal and thus redundant * Removing all python regex linters on the args, now that RPCMan can be used to generate any output, including the cli.cpp table * Auto-formatting and sanity checking the RPCExamples with RPCMan * Checking passed-in json in self-check. Removing redundant checks * Checking returned json against documentation to avoid regressions or false documentation * Compile the RPC documentation at compile-time to ensure it doesn't change at runtime and is completely static ### Bugs found * The assert identified issue #18607 * The changes itself fixed bug #19250 ACKs for top commit: laanwj: Code review ACK fa77de2baa40ee828c850ef4068c76cc3619e87b fjahr: tested ACK fa77de2baa40ee828c850ef4068c76cc3619e87b theStack: ACK https://github.com/bitcoin/bitcoin/pull/19528/commits/fa77de2baa40ee828c850ef4068c76cc3619e87b ryanofsky: Code review ACK fa77de2baa40ee828c850ef4068c76cc3619e87b. Pretty straightfoward changes Tree-SHA512: badae1606518c0b55ce2c0bb9025d14f05556532375eb20fd6f3bfadae1e5e6568860bff8599d037e655bf1d23f1f464ca17f4db10a6ab3d502b6e9e61c7b3d3 --- src/rpc/blockchain.cpp | 5 +- src/rpc/mining.cpp | 5 +- src/rpc/misc.cpp | 241 ++++++++++++++++++++++++------------ src/rpc/net.cpp | 5 +- src/rpc/rawtransaction.cpp | 5 +- src/rpc/server.cpp | 9 +- src/rpc/util.cpp | 4 +- test/functional/rpc_misc.py | 4 +- 8 files changed, 173 insertions(+), 105 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 68b245daff0b6..242731b3bbe01 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -2986,8 +2986,7 @@ static const CRPCCommand commands[] = { "hidden", "dumptxoutset", &dumptxoutset, {"path"} }, }; // clang-format on - - for (const auto& command : commands) { - t.appendCommand(command.name, &command); + for (const auto& c : commands) { + t.appendCommand(c.name, &c); } } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 43f4f687195c4..afbf18b229ea0 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -1281,8 +1281,7 @@ static const CRPCCommand commands[] = { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} }, }; // clang-format on - - for (const auto& command : commands) { - t.appendCommand(command.name, &command); + for (const auto& c : commands) { + t.appendCommand(c.name, &c); } } diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 0d11f930202d7..aba1f252e4db8 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -40,9 +40,9 @@ #include -static UniValue debug(const JSONRPCRequest& request) +static RPCHelpMan debug() { - RPCHelpMan{"debug", + return RPCHelpMan{"debug", "Change debug category on the fly. Specify single category or use '+' to specify many.\n" "The valid logging categories are: " + LogInstance().LogCategoriesString() + ".\n" "libevent logging is configured on startup and cannot be modified by this RPC during runtime.\n" @@ -60,7 +60,9 @@ static UniValue debug(const JSONRPCRequest& request) RPCExamples { HelpExampleCli("debug", "dash") + HelpExampleRpc("debug", "dash+net") - }}.Check(request); + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::string strMode = request.params[0].get_str(); LogInstance().DisableCategory(BCLog::ALL); @@ -73,11 +75,13 @@ static UniValue debug(const JSONRPCRequest& request) } return "Debug mode: " + LogInstance().LogCategoriesString(/*enabled_only=*/true); +}, + }; } -static UniValue mnsync(const JSONRPCRequest& request) +static RPCHelpMan mnsync() { - RPCHelpMan{"mnsync", + return RPCHelpMan{"mnsync", "Returns the sync status, updates to the next step or resets it entirely.\n", { {"mode", RPCArg::Type::STR, RPCArg::Optional::NO, "[status|next|reset]"}, @@ -97,7 +101,8 @@ static UniValue mnsync(const JSONRPCRequest& request) RPCResult::Type::STR, "", ""}, }, RPCExamples{""}, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::string strMode = request.params[0].get_str(); @@ -127,15 +132,17 @@ static UniValue mnsync(const JSONRPCRequest& request) return "success"; } return "failure"; +}, + }; } /* Used for updating/reading spork settings on the network */ -static UniValue spork(const JSONRPCRequest& request) +static RPCHelpMan spork() { // default help, for basic mode - RPCHelpMan{"spork", + return RPCHelpMan{"spork", "\nShows information about current state of sporks\n", { {"command", RPCArg::Type::STR, RPCArg::Optional::NO, "'show' to show all current spork values, 'active' to show which sporks are active"}, @@ -155,8 +162,9 @@ static UniValue spork(const JSONRPCRequest& request) RPCExamples { HelpExampleCli("spork", "show") + HelpExampleRpc("spork", "\"show\"") - } - }.Check(request); + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ // basic mode, show info std:: string strCommand = request.params[0].get_str(); @@ -176,11 +184,13 @@ static UniValue spork(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue sporkupdate(const JSONRPCRequest& request) +static RPCHelpMan sporkupdate() { - RPCHelpMan{"sporkupdate", + return RPCHelpMan{"sporkupdate", "\nUpdate the value of the specific spork. Requires \"-sporkkey\" to be set to sign the message.\n", { {"name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the spork to update"}, @@ -193,7 +203,8 @@ static UniValue sporkupdate(const JSONRPCRequest& request) HelpExampleCli("sporkupdate", "SPORK_2_INSTANTSEND_ENABLED 4070908800") + HelpExampleRpc("sporkupdate", "\"SPORK_2_INSTANTSEND_ENABLED\", 4070908800") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ // advanced mode, update spork values SporkId nSporkID = CSporkManager::GetSporkIDByName(request.params[0].get_str()); @@ -215,11 +226,13 @@ static UniValue sporkupdate(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue validateaddress(const JSONRPCRequest& request) +static RPCHelpMan validateaddress() { - RPCHelpMan{"validateaddress", + return RPCHelpMan{"validateaddress", "\nReturn information about the given Dash address.\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Dash address to validate"}, @@ -238,8 +251,8 @@ static UniValue validateaddress(const JSONRPCRequest& request) HelpExampleCli("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") + HelpExampleRpc("validateaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::string error_msg; CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg); const bool isValid = IsValidDestination(dest); @@ -261,11 +274,13 @@ static UniValue validateaddress(const JSONRPCRequest& request) } return ret; +}, + }; } -static UniValue createmultisig(const JSONRPCRequest& request) +static RPCHelpMan createmultisig() { - RPCHelpMan{"createmultisig", + return RPCHelpMan{"createmultisig", "\nCreates a multi-signature address with n signature of m keys required.\n" "It returns a json object with the address and redeemScript.\n", { @@ -289,8 +304,8 @@ static UniValue createmultisig(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("createmultisig", "2, \"[\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd342cf11ae157a7ace5fd\\\",\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e17e107ef3f6aa5a61626\\\"]\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ int required = request.params[0].get_int(); // Get the public keys @@ -318,11 +333,13 @@ static UniValue createmultisig(const JSONRPCRequest& request) result.pushKV("descriptor", descriptor->ToString()); return result; +}, + }; } -UniValue getdescriptorinfo(const JSONRPCRequest& request) +static RPCHelpMan getdescriptorinfo() { - RPCHelpMan{"getdescriptorinfo", + return RPCHelpMan{"getdescriptorinfo", {"\nAnalyses a descriptor.\n"}, { {"descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The descriptor"}, @@ -340,8 +357,9 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request) RPCExamples{ "\nAnalyse a descriptor\n" + HelpExampleCli("getdescriptorinfo", "\"pkh([d34db33f/84h/0h/0h]0279be667ef9dcbbac55a06295Ce870b07029Bfcdb2dce28d959f2815b16f81798)\"") - } - }.Check(request); + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); @@ -359,11 +377,13 @@ UniValue getdescriptorinfo(const JSONRPCRequest& request) result.pushKV("issolvable", desc->IsSolvable()); result.pushKV("hasprivatekeys", provider.keys.size() > 0); return result; +}, + }; } -UniValue deriveaddresses(const JSONRPCRequest& request) +static RPCHelpMan deriveaddresses() { - RPCHelpMan{"deriveaddresses", + return RPCHelpMan{"deriveaddresses", "\nDerives one or more addresses corresponding to an output descriptor.\n" "Examples of output descriptors are:\n" " pkh() P2PKH outputs for the given pubkey\n" @@ -385,8 +405,9 @@ UniValue deriveaddresses(const JSONRPCRequest& request) RPCExamples{ "\nFirst three receive addresses\n" + HelpExampleCli("deriveaddresses", "\"pkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#cjjspncu\" \"[0,2]\"") - } - }.Check(request); + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()}); // Range argument is checked later const std::string desc_str = request.params[0].get_str(); @@ -438,11 +459,13 @@ UniValue deriveaddresses(const JSONRPCRequest& request) } return addresses; +}, + }; } -static UniValue verifymessage(const JSONRPCRequest& request) +static RPCHelpMan verifymessage() { - RPCHelpMan{"verifymessage", + return RPCHelpMan{"verifymessage", "\nVerify a signed message\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Dash address to use for the signature."}, @@ -462,7 +485,8 @@ static UniValue verifymessage(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("verifymessage", "\"" + EXAMPLE_ADDRESS[0] + "\", \"signature\", \"my message\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ LOCK(cs_main); @@ -485,11 +509,13 @@ static UniValue verifymessage(const JSONRPCRequest& request) } return false; +}, + }; } -static UniValue signmessagewithprivkey(const JSONRPCRequest& request) +static RPCHelpMan signmessagewithprivkey() { - RPCHelpMan{"signmessagewithprivkey", + return RPCHelpMan{"signmessagewithprivkey", "\nSign a message with the private key of an address\n", { {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."}, @@ -506,7 +532,8 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::string strPrivkey = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); @@ -523,11 +550,13 @@ static UniValue signmessagewithprivkey(const JSONRPCRequest& request) } return signature; +}, + }; } -static UniValue setmocktime(const JSONRPCRequest& request) +static RPCHelpMan setmocktime() { - RPCHelpMan{"setmocktime", + return RPCHelpMan{"setmocktime", "\nSet the local time to given timestamp (-regtest only)\n", { {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, UNIX_EPOCH_TIME + "\n" @@ -535,7 +564,8 @@ static UniValue setmocktime(const JSONRPCRequest& request) }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ if (!Params().IsMockableChain()) { throw std::runtime_error("setmocktime is for regression testing (-regtest mode) only"); @@ -561,11 +591,13 @@ static UniValue setmocktime(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue mnauth(const JSONRPCRequest& request) +static RPCHelpMan mnauth() { - RPCHelpMan{"mnauth", + return RPCHelpMan{"mnauth", "\nOverride MNAUTH processing results for the specified node with a user provided data (-regtest only).\n", { {"nodeId", RPCArg::Type::NUM, RPCArg::Optional::NO, "Internal peer id of the node the mock data gets added to."}, @@ -576,7 +608,8 @@ static UniValue mnauth(const JSONRPCRequest& request) RPCResult::Type::BOOL, "result", "true, if the node was updated" }, RPCExamples{""}, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ if (!Params().MineBlocksOnDemand()) throw std::runtime_error("mnauth for regression testing (-regtest mode) only"); @@ -604,6 +637,8 @@ static UniValue mnauth(const JSONRPCRequest& request) }); return fSuccess; +}, + }; } static bool getAddressFromIndex(const AddressType& type, const uint160 &hash, std::string &address) @@ -673,9 +708,9 @@ static bool timestampSort(std::pair UniValue +{ std::vector > addresses; @@ -741,11 +777,13 @@ static UniValue getaddressmempool(const JSONRPCRequest& request) } return result; +}, + }; } -static UniValue getaddressutxos(const JSONRPCRequest& request) +static RPCHelpMan getaddressutxos() { - RPCHelpMan{"getaddressutxos", + return RPCHelpMan{"getaddressutxos", "\nReturns all unspent outputs for an address (requires addressindex to be enabled).\n", { {"addresses", RPCArg::Type::ARR, /* default */ "", "", @@ -771,7 +809,8 @@ static UniValue getaddressutxos(const JSONRPCRequest& request) HelpExampleCli("getaddressutxos", "'{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}'") + HelpExampleRpc("getaddressutxos", "{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::vector > addresses; @@ -808,11 +847,13 @@ static UniValue getaddressutxos(const JSONRPCRequest& request) } return result; +}, + }; } -static UniValue getaddressdeltas(const JSONRPCRequest& request) +static RPCHelpMan getaddressdeltas() { - RPCHelpMan{"getaddressdeltas", + return RPCHelpMan{"getaddressdeltas", "\nReturns all changes for an address (requires addressindex to be enabled).\n", { {"addresses", RPCArg::Type::ARR, /* default */ "", "", @@ -838,7 +879,8 @@ static UniValue getaddressdeltas(const JSONRPCRequest& request) HelpExampleCli("getaddressdeltas", "'{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}'") + HelpExampleRpc("getaddressdeltas", "{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ UniValue startValue = find_value(request.params[0].get_obj(), "start"); @@ -894,11 +936,13 @@ static UniValue getaddressdeltas(const JSONRPCRequest& request) } return result; +}, + }; } -static UniValue getaddressbalance(const JSONRPCRequest& request) +static RPCHelpMan getaddressbalance() { - RPCHelpMan{"getaddressbalance", + return RPCHelpMan{"getaddressbalance", "\nReturns the balance for an address(es) (requires addressindex to be enabled).\n", { {"addresses", RPCArg::Type::ARR, /* default */ "", "", @@ -919,7 +963,8 @@ static UniValue getaddressbalance(const JSONRPCRequest& request) HelpExampleCli("getaddressbalance", "'{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}'") + HelpExampleRpc("getaddressbalance", "{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::vector > addresses; @@ -963,11 +1008,13 @@ static UniValue getaddressbalance(const JSONRPCRequest& request) return result; +}, + }; } -static UniValue getaddresstxids(const JSONRPCRequest& request) +static RPCHelpMan getaddresstxids() { - RPCHelpMan{"getaddresstxids", + return RPCHelpMan{"getaddresstxids", "\nReturns the txids for an address(es) (requires addressindex to be enabled).\n", { {"addresses", RPCArg::Type::ARR, /* default */ "", "", @@ -984,7 +1031,8 @@ static UniValue getaddresstxids(const JSONRPCRequest& request) HelpExampleCli("getaddresstxids", "'{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}'") + HelpExampleRpc("getaddresstxids", "{\"addresses\": [\"" + EXAMPLE_ADDRESS[0] + "\"]}") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::vector > addresses; @@ -1041,11 +1089,13 @@ static UniValue getaddresstxids(const JSONRPCRequest& request) return result; +}, + }; } -static UniValue getspentinfo(const JSONRPCRequest& request) +static RPCHelpMan getspentinfo() { - RPCHelpMan{"getspentinfo", + return RPCHelpMan{"getspentinfo", "\nReturns the txid and index where an output is spent.\n", { {"request", RPCArg::Type::OBJ, /* default */ "", "", @@ -1065,7 +1115,8 @@ static UniValue getspentinfo(const JSONRPCRequest& request) HelpExampleCli("getspentinfo", "'{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}'") + HelpExampleRpc("getspentinfo", "{\"txid\": \"0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9\", \"index\": 0}") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ UniValue txidValue = find_value(request.params[0].get_obj(), "txid"); UniValue indexValue = find_value(request.params[0].get_obj(), "index"); @@ -1091,19 +1142,21 @@ static UniValue getspentinfo(const JSONRPCRequest& request) obj.pushKV("height", value.m_block_height); return obj; +}, + }; } -static UniValue mockscheduler(const JSONRPCRequest& request) +static RPCHelpMan mockscheduler() { - RPCHelpMan{"mockscheduler", + return RPCHelpMan{"mockscheduler", "\nBump the scheduler into the future (-regtest only)\n", { {"delta_time", RPCArg::Type::NUM, RPCArg::Optional::NO, "Number of seconds to forward the scheduler into the future." }, }, RPCResults{}, RPCExamples{""}, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ if (!Params().IsMockableChain()) { throw std::runtime_error("mockscheduler is for regression testing (-regtest mode) only"); } @@ -1122,6 +1175,8 @@ static UniValue mockscheduler(const JSONRPCRequest& request) node_context->scheduler->MockForward(std::chrono::seconds(delta_seconds)); return NullUniValue; +}, + }; } static UniValue RPCLockedMemoryInfo() @@ -1156,12 +1211,12 @@ static std::string RPCMallocInfo() } #endif -static UniValue getmemoryinfo(const JSONRPCRequest& request) +static RPCHelpMan getmemoryinfo() { /* Please, avoid using the word "pool" here in the RPC interface or help, * as users will undoubtedly confuse it with the other "memory pool" */ - RPCHelpMan{"getmemoryinfo", + return RPCHelpMan{"getmemoryinfo", "Returns an object containing information about memory usage.\n", { {"mode", RPCArg::Type::STR, /* default */ "\"stats\"", "determines what kind of information is returned.\n" @@ -1191,7 +1246,8 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request) HelpExampleCli("getmemoryinfo", "") + HelpExampleRpc("getmemoryinfo", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str(); if (mode == "stats") { @@ -1207,6 +1263,8 @@ static UniValue getmemoryinfo(const JSONRPCRequest& request) } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode); } +}, + }; } static void EnableOrDisableLogCategories(UniValue cats, bool enable) { @@ -1227,9 +1285,9 @@ static void EnableOrDisableLogCategories(UniValue cats, bool enable) { } } -static UniValue logging(const JSONRPCRequest& request) +static RPCHelpMan logging() { - RPCHelpMan{"logging", + return 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" @@ -1262,7 +1320,8 @@ static UniValue logging(const JSONRPCRequest& request) HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"") + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint64_t original_log_categories = LogInstance().GetCategoryMask(); if (request.params[0].isArray()) { @@ -1294,25 +1353,41 @@ static UniValue logging(const JSONRPCRequest& request) } return result; +}, + }; } -static UniValue echo(const JSONRPCRequest& request) +static RPCHelpMan echo(const std::string& name) { - if (request.fHelp) - throw std::runtime_error( - RPCHelpMan{"echo|echojson ...", + return RPCHelpMan{name, "\nSimply echo back the input arguments. This command is for testing.\n" - "\nIt will return an internal bug report when exactly 100 arguments are passed.\n" + "\nIt will return an internal bug report when arg9='trigger_internal_bug' is passed.\n" "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in " "dash-cli and the GUI. There is no server-side difference.", - {}, + { + {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg2", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg3", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg4", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg5", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg6", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg7", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg8", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + {"arg9", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""}, + }, RPCResult{RPCResult::Type::NONE, "", "Returns whatever was passed in"}, RPCExamples{""}, - }.ToString() - ); - CHECK_NONFATAL(request.params.size() != 100); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + if (request.fHelp) throw std::runtime_error(self.ToString()); + if (request.params[9].isStr()) { + CHECK_NONFATAL(request.params[9].get_str() != "trigger_internal_bug"); + } return request.params; +}, + }; } static UniValue SummaryToJSON(const IndexSummary&& summary, std::string index_name) @@ -1373,6 +1448,9 @@ static RPCHelpMan getindexinfo() }; } +static RPCHelpMan echo() { return echo("echo"); } +static RPCHelpMan echojson() { return echo("echojson"); } + void RegisterMiscRPCCommands(CRPCTable &t) { static const CRPCCommand commands[] = @@ -1406,12 +1484,11 @@ static const CRPCCommand commands[] = { "hidden", "setmocktime", &setmocktime, {"timestamp"}}, { "hidden", "mockscheduler", &mockscheduler, {"delta_time"}}, { "hidden", "echo", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, - { "hidden", "echojson", &echo, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, + { "hidden", "echojson", &echojson, {"arg0","arg1","arg2","arg3","arg4","arg5","arg6","arg7","arg8","arg9"}}, { "hidden", "mnauth", &mnauth, {"nodeId", "proTxHash", "publicKey"}}, }; // clang-format on - - for (const auto& command : commands) { - t.appendCommand(command.name, &command); + for (const auto& c : commands) { + t.appendCommand(c.name, &c); } } diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 1a0710ec9323c..0e101cdca5af6 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -923,8 +923,7 @@ static const CRPCCommand commands[] = { "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} }, }; // clang-format on - - for (const auto& command : commands) { - t.appendCommand(command.name, &command); + for (const auto& c : commands) { + t.appendCommand(c.name, &c); } } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index a36d8511d0606..ba2ccebc52798 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -2059,8 +2059,7 @@ static const CRPCCommand commands[] = { "blockchain", "verifytxoutproof", &verifytxoutproof, {"proof"} }, }; // clang-format on - - for (const auto& command : commands) { - t.appendCommand(command.name, &command); + for (const auto& c : commands) { + t.appendCommand(c.name, &c); } } diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 1376219bd6ae9..6c0f1295fc4a2 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -286,13 +286,8 @@ static const CRPCCommand vRPCCommands[] = CRPCTable::CRPCTable() { - unsigned int vcidx; - for (vcidx = 0; vcidx < (sizeof(vRPCCommands) / sizeof(vRPCCommands[0])); vcidx++) - { - const CRPCCommand *pcmd; - - pcmd = &vRPCCommands[vcidx]; - mapCommands[pcmd->name].push_back(pcmd); + for (const auto& c : vRPCCommands) { + appendCommand(c.name, &c); } } diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index ad0894954c0e6..e850a17879f1d 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -459,7 +459,7 @@ std::string RPCHelpMan::ToString() const ret += m_name; bool was_optional{false}; for (const auto& arg : m_args) { - if (arg.m_hidden) continue; + if (arg.m_hidden) break; // Any arg that follows is also hidden const bool optional = arg.IsOptional(); ret += " "; if (optional) { @@ -481,7 +481,7 @@ std::string RPCHelpMan::ToString() const Sections sections; for (size_t i{0}; i < m_args.size(); ++i) { const auto& arg = m_args.at(i); - if (arg.m_hidden) continue; + if (arg.m_hidden) break; // Any arg that follows is also hidden if (i == 0) ret += "\nArguments:\n"; diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py index e348cfd935aea..80dc56bee7ff0 100755 --- a/test/functional/rpc_misc.py +++ b/test/functional/rpc_misc.py @@ -27,8 +27,8 @@ def run_test(self): self.log.info("test CHECK_NONFATAL") assert_raises_rpc_error( -1, - "Internal bug detected: 'request.params.size() != 100'", - lambda: node.echo(*[0] * 100), + 'Internal bug detected: \'request.params[9].get_str() != "trigger_internal_bug"\'', + lambda: node.echo(arg9='trigger_internal_bug'), ) self.log.info("test getmemoryinfo") From 41c35fd8dc348f659a1bccbdb5b5845bf3dba737 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sat, 24 Feb 2024 14:16:14 +0700 Subject: [PATCH 02/12] fix: adjust missing arguments and help for misc rpc: debug, echo, mnsync --- src/rpc/client.cpp | 2 +- src/rpc/misc.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index d787647bb64da..c2c9479dee9db 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -183,7 +183,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "voteraw", 5, "time" }, { "getblockhashes", 0, "high"}, { "getblockhashes", 1, "low" }, - { "getspentinfo", 0, "json" }, + { "getspentinfo", 0, "request" }, { "getaddresstxids", 0, "addresses" }, { "getaddressbalance", 0, "addresses" }, { "getaddressdeltas", 0, "addresses" }, diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index aba1f252e4db8..dfb463eb3aa70 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -1456,7 +1456,7 @@ void RegisterMiscRPCCommands(CRPCTable &t) static const CRPCCommand commands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- - { "control", "debug", &debug, {} }, + { "control", "debug", &debug, {"category"} }, { "control", "getmemoryinfo", &getmemoryinfo, {"mode"} }, { "control", "logging", &logging, {"include", "exclude"}}, { "util", "validateaddress", &validateaddress, {"address"} }, @@ -1466,7 +1466,7 @@ static const CRPCCommand commands[] = { "util", "verifymessage", &verifymessage, {"address","signature","message"} }, { "util", "signmessagewithprivkey", &signmessagewithprivkey, {"privkey","message"} }, { "util", "getindexinfo", &getindexinfo, {"index_name"} }, - { "blockchain", "getspentinfo", &getspentinfo, {"json"} }, + { "blockchain", "getspentinfo", &getspentinfo, {"request"} }, /* Address index */ { "addressindex", "getaddressmempool", &getaddressmempool, {"addresses"} }, @@ -1476,7 +1476,7 @@ static const CRPCCommand commands[] = { "addressindex", "getaddressbalance", &getaddressbalance, {"addresses"} }, /* Dash features */ - { "dash", "mnsync", &mnsync, {} }, + { "dash", "mnsync", &mnsync, {"mode"} }, { "dash", "spork", &spork, {"command"} }, { "dash", "sporkupdate", &sporkupdate, {"name","value"} }, From 860d31f5048ddabfb869ae02f80e11272b74e2d7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 14 Aug 2020 11:03:36 +0200 Subject: [PATCH 03/12] Merge #19455: rpc generate: print useful help and error message f0aa8aeea5a183ea44a877255d12db7732f2e0a8 test: add rpc_generate functional test (Jon Atack) 92d94ffb8d07cc0d2665c901de5903a3a90d5fd0 rpc: print useful help and error message for generate (Jon Atack) 8d32d2011d3f4e1d9e587d6f80dfa4a3e9f9393d test: consider generate covered in _get_uncovered_rpc_commands() (Jon Atack) Pull request description: This was a requested follow-up to #19133 and #17700 to alleviate confusion and head-scratching by people following tutorials that use `generate`. See https://github.com/bitcoin/bitcoin/pull/19455#issuecomment-668172916 below, https://github.com/bitcoin/bitcoin/pull/19133#issuecomment-636860943 and https://github.com/bitcoin/bitcoin/pull/17700#issuecomment-566159096. before ``` $ bitcoin-cli help generate help: unknown command: generate $ bitcoin-cli generate error code: -32601 error message: Method not found ``` after ``` $ bitcoin-cli help generate generate ( nblocks maxtries ) has been replaced by the -generate cli option. Refer to -help for more information. $ bitcoin-cli generate error code: -32601 error message: generate ( nblocks maxtries ) has been replaced by the -generate cli option. Refer to -help for more information. ``` In the general help it remains hidden, as requested by laanwj. ``` $ bitcoin-cli help == Generating == generateblock "output" ["rawtx/txid",...] generatetoaddress nblocks "address" ( maxtries ) generatetodescriptor num_blocks "descriptor" ( maxtries ) ``` ACKs for top commit: adamjonas: utACK f0aa8aeea5a183ea44a877255d12db7732f2e0a8 pinheadmz: ACK f0aa8aeea5a183ea44a877255d12db7732f2e0a8 Tree-SHA512: d083652589ad3e8228c733455245001db22397559c3946e7e573cf9bd01c46e9e88b72d934728ec7f4361436ae4c74adb8f579670b09f479011924357e729af5 --- src/rpc/mining.cpp | 13 ++++++++++++ test/functional/rpc_generate.py | 35 +++++++++++++++++++++++++++++++++ test/functional/test_runner.py | 7 +++++-- 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100755 test/functional/rpc_generate.py diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index afbf18b229ea0..bb6e61a17f8ff 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -421,6 +421,18 @@ static UniValue generateblock(const JSONRPCRequest& request) } #endif // ENABLE_MINER +static UniValue generate(const JSONRPCRequest& request) +{ + return RPCHelpMan{"generate", "has been replaced by the -generate cli option. Refer to -help for more information.", {}, {}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { + + if (request.fHelp) { + throw std::runtime_error(self.ToString()); + } else { + throw JSONRPCError(RPC_METHOD_NOT_FOUND, self.ToString()); + } + }}; +} + static UniValue getmininginfo(const JSONRPCRequest& request) { RPCHelpMan{"getmininginfo", @@ -1279,6 +1291,7 @@ static const CRPCCommand commands[] = { "util", "estimatesmartfee", &estimatesmartfee, {"conf_target", "estimate_mode"} }, { "hidden", "estimaterawfee", &estimaterawfee, {"conf_target", "threshold"} }, + { "hidden", "generate", &generate, {} }, }; // clang-format on for (const auto& c : commands) { diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py new file mode 100755 index 0000000000000..9404f1e25ef2e --- /dev/null +++ b/test/functional/rpc_generate.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# Copyright (c) 2020 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. +"""Test generate RPC.""" + +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, +) + + +class RPCGenerateTest(BitcoinTestFramework): + def set_test_params(self): + self.num_nodes = 1 + + def run_test(self): + message = ( + "generate ( nblocks maxtries ) has been replaced by the -generate " + "cli option. Refer to -help for more information." + ) + + self.log.info("Test rpc generate raises with message to use cli option") + assert_raises_rpc_error(-32601, message, self.nodes[0].rpc.generate) + + self.log.info("Test rpc generate help prints message to use cli option") + assert_equal(message, self.nodes[0].help("generate")) + + self.log.info("Test rpc generate is a hidden command not discoverable in general help") + assert message not in self.nodes[0].help() + + +if __name__ == "__main__": + RPCGenerateTest().main() diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index 0a4b232713544..5273b1e36f7c3 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -243,6 +243,7 @@ 'p2p_eviction.py', 'rpc_signmessage.py', 'rpc_generateblock.py', + 'rpc_generate.py', 'wallet_balance.py', 'wallet_balance.py --descriptors', 'feature_nulldummy.py', @@ -816,14 +817,16 @@ def _get_uncovered_rpc_commands(self): Return a set of currently untested RPC commands. """ - # This is shared from `test/functional/test-framework/coverage.py` + # This is shared from `test/functional/test_framework/coverage.py` reference_filename = 'rpc_interface.txt' coverage_file_prefix = 'coverage.' coverage_ref_filename = os.path.join(self.dir, reference_filename) coverage_filenames = set() all_cmds = set() - covered_cmds = set() + # Consider RPC generate covered, because it is overloaded in + # test_framework/test_node.py and not seen by the coverage check. + covered_cmds = set({'generate'}) if not os.path.isfile(coverage_ref_filename): raise RuntimeError("No coverage reference found") From 7ac1ee0fb43552c46ab608647a8b067480327fe9 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Mon, 31 Aug 2020 17:42:32 +0200 Subject: [PATCH 04/12] Merge #19717: rpc: Assert that RPCArg names are equal to CRPCCommand ones (mining,zmq,rpcdump) fa3d9ce3254882c545d700990fe8e9a678f31eed rpc: Assert that RPCArg names are equal to CRPCCommand ones (rpcdump) (MarcoFalke) fa32c1d5ec25bc53bf989a8ae68e688593d2859d rpc: Assert that RPCArg names are equal to CRPCCommand ones (zmq) (MarcoFalke) faaa46dc204d6d714f71dbc6f0bf02215dba0f0f rpc: Assert that RPCArg names are equal to CRPCCommand ones (mining) (MarcoFalke) fa93bc14c7411a108dd024d391344fabf0f76369 rpc: Remove unused return type from appendCommand (MarcoFalke) Pull request description: This is split out from #18531 to just touch the RPC methods in misc. Description from the main pr: ### Motivation RPCArg names in the rpc help are currently only used for documentation. However, in the future they could be used to teach the server the named arguments. Named arguments are currently registered by the `CRPCCommand`s and duplicate the RPCArg names from the documentation. This redundancy is fragile, and has lead to errors in the past (despite having linters to catch those kind of errors). See section "bugs found" for a list of bugs that have been found as a result of the changes here. ### Changes The changes here add an assert in the `CRPCCommand` constructor that the RPCArg names are identical to the ones in the `CRPCCommand`. ### Future work > Here or follow up, makes sense to also assert type of returned UniValue? Sure, but let's not get ahead of ourselves. I am going to submit any further works as follow-ups, including: * Removing the CRPCCommand arguments, now that they are asserted to be equal and thus redundant * Removing all python regex linters on the args, now that RPCMan can be used to generate any output, including the cli.cpp table * Auto-formatting and sanity checking the RPCExamples with RPCMan * Checking passed-in json in self-check. Removing redundant checks * Checking returned json against documentation to avoid regressions or false documentation * Compile the RPC documentation at compile-time to ensure it doesn't change at runtime and is completely static ### Bugs found * The assert identified issue #18607 * The changes itself fixed bug #19250 ACKs for top commit: fjahr: tested ACK fa3d9ce3254882c545d700990fe8e9a678f31eed promag: Code review ACK fa3d9ce3254882c545d700990fe8e9a678f31eed. Tree-SHA512: 068ade4b55cc195868d53b7f9a27151d45b440857bb069e261a49d102a49a38fdba5d68868516a1d66a54a73ba34681362f934ded7349e894042bde873b75719 --- src/rpc/mining.cpp | 112 ++++++++++++++++---------- src/rpc/server.cpp | 6 +- src/rpc/server.h | 4 +- src/wallet/rpcdump.cpp | 133 +++++++++++++++++++------------ src/wallet/rpcwallet.cpp | 26 +++--- src/wallet/test/wallet_tests.cpp | 12 +-- src/zmq/zmqrpc.cpp | 10 ++- test/functional/rpc_generate.py | 3 +- 8 files changed, 180 insertions(+), 126 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index bb6e61a17f8ff..de6c78616c741 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -94,9 +94,9 @@ static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_ch return workDiff.getdouble() / timeDiff; } -static UniValue getnetworkhashps(const JSONRPCRequest& request) +static RPCHelpMan getnetworkhashps() { - RPCHelpMan{"getnetworkhashps", + return 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", @@ -110,11 +110,14 @@ static UniValue getnetworkhashps(const JSONRPCRequest& request) HelpExampleCli("getnetworkhashps", "") + HelpExampleRpc("getnetworkhashps", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); return GetNetworkHashPS(!request.params[0].isNull() ? request.params[0].get_int() : 120, !request.params[1].isNull() ? request.params[1].get_int() : -1, chainman.ActiveChain()); +}, + }; } #if ENABLE_MINER @@ -218,9 +221,9 @@ static bool getScriptFromDescriptor(const std::string& descriptor, CScript& scri } } -static UniValue generatetodescriptor(const JSONRPCRequest& request) +static RPCHelpMan generatetodescriptor() { - RPCHelpMan{ + return RPCHelpMan{ "generatetodescriptor", "\nMine blocks immediately to a specified descriptor (before the RPC call returns)\n", { @@ -236,9 +239,8 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request) }, RPCExamples{ "\nGenerate 11 blocks to mydesc\n" + HelpExampleCli("generatetodescriptor", "11 \"mydesc\"")}, - } - .Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const int num_blocks{request.params[0].get_int()}; const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()}; @@ -254,11 +256,13 @@ static UniValue generatetodescriptor(const JSONRPCRequest& request) LLMQContext& llmq_ctx = EnsureLLMQContext(node); return generateBlocks(chainman, *node.evodb, *node.chain_helper, llmq_ctx, mempool, coinbase_script, num_blocks, max_tries); +}, + }; } -static UniValue generatetoaddress(const JSONRPCRequest& request) +static RPCHelpMan generatetoaddress() { - RPCHelpMan{"generatetoaddress", + return RPCHelpMan{"generatetoaddress", "\nMine blocks immediately to a specified address (before the RPC call returns)\n", { {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated immediately."}, @@ -275,8 +279,8 @@ static UniValue generatetoaddress(const JSONRPCRequest& request) + HelpExampleCli("generatetoaddress", "11 \"myaddress\"") + "If you are using the " PACKAGE_NAME " wallet, you can get a new address to send the newly generated coins to with:\n" + HelpExampleCli("getnewaddress", "")}, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const int num_blocks{request.params[0].get_int()}; const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()}; @@ -293,11 +297,13 @@ static UniValue generatetoaddress(const JSONRPCRequest& request) CScript coinbase_script = GetScriptForDestination(destination); return generateBlocks(chainman, *node.evodb, *node.chain_helper, llmq_ctx, mempool, coinbase_script, num_blocks, max_tries); +}, + }; } -static UniValue generateblock(const JSONRPCRequest& request) +static RPCHelpMan generateblock() { - RPCHelpMan{"generateblock", + return RPCHelpMan{"generateblock", "\nMine a block with a set of ordered transactions immediately to a specified address or descriptor (before the RPC call returns)\n", { {"address/descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor to send the newly generated coins to."}, @@ -319,8 +325,8 @@ static UniValue generateblock(const JSONRPCRequest& request) "\nGenerate a block to myaddress, with txs rawtx and mempool_txid\n" + HelpExampleCli("generateblock", R"("myaddress" '["rawtx", "mempool_txid"]')") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const auto address_or_descriptor = request.params[0].get_str(); CScript coinbase_script; std::string error; @@ -405,6 +411,8 @@ static UniValue generateblock(const JSONRPCRequest& request) UniValue obj(UniValue::VOBJ); obj.pushKV("hash", block_hash.GetHex()); return obj; +}, + }; } #else static UniValue generatetoaddress(const JSONRPCRequest& request) @@ -421,7 +429,7 @@ static UniValue generateblock(const JSONRPCRequest& request) } #endif // ENABLE_MINER -static UniValue generate(const JSONRPCRequest& request) +static RPCHelpMan generate() { return RPCHelpMan{"generate", "has been replaced by the -generate cli option. Refer to -help for more information.", {}, {}, RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { @@ -433,9 +441,9 @@ static UniValue generate(const JSONRPCRequest& request) }}; } -static UniValue getmininginfo(const JSONRPCRequest& request) +static RPCHelpMan getmininginfo() { - RPCHelpMan{"getmininginfo", + return RPCHelpMan{"getmininginfo", "\nReturns a json object containing mining-related information.", {}, RPCResult{ @@ -454,7 +462,8 @@ static UniValue getmininginfo(const JSONRPCRequest& request) HelpExampleCli("getmininginfo", "") + HelpExampleRpc("getmininginfo", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -469,18 +478,20 @@ static UniValue getmininginfo(const JSONRPCRequest& request) if (BlockAssembler::m_last_block_size) obj.pushKV("currentblocksize", *BlockAssembler::m_last_block_size); if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs); obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip())); - obj.pushKV("networkhashps", getnetworkhashps(request)); + obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request)); obj.pushKV("pooledtx", (uint64_t)mempool.size()); obj.pushKV("chain", Params().NetworkIDString()); obj.pushKV("warnings", GetWarnings(false).original); return obj; +}, + }; } // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts -static UniValue prioritisetransaction(const JSONRPCRequest& request) +static RPCHelpMan prioritisetransaction() { - RPCHelpMan{"prioritisetransaction", + return RPCHelpMan{"prioritisetransaction", "Accepts the transaction into mined blocks at a higher (or lower) priority\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id."}, @@ -495,8 +506,9 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) HelpExampleCli("prioritisetransaction", "\"txid\" 10000") + HelpExampleRpc("prioritisetransaction", "\"txid\", 10000") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ LOCK(cs_main); uint256 hash(ParseHashV(request.params[0].get_str(), "txid")); @@ -504,6 +516,8 @@ static UniValue prioritisetransaction(const JSONRPCRequest& request) EnsureAnyMemPool(request.context).PrioritiseTransaction(hash, nAmount); return true; +}, + }; } @@ -535,9 +549,9 @@ static std::string gbt_vb_name(const Consensus::DeploymentPos pos) { return s; } -static UniValue getblocktemplate(const JSONRPCRequest& request) +static RPCHelpMan getblocktemplate() { - RPCHelpMan{"getblocktemplate", + return 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, and 9:\n" @@ -641,8 +655,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) HelpExampleCli("getblocktemplate", "") + HelpExampleRpc("getblocktemplate", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); @@ -969,6 +983,8 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) result.pushKV("coinbase_payload", HexStr(pblock->vtx[0]->vExtraPayload)); return result; +}, + }; } class submitblock_StateCatcher final : public CValidationInterface @@ -989,10 +1005,10 @@ class submitblock_StateCatcher final : public CValidationInterface } }; -static UniValue submitblock(const JSONRPCRequest& request) +static RPCHelpMan submitblock() { // We allow 2 arguments for compliance with BIP22. Argument 2 is ignored. - RPCHelpMan{"submitblock", + return RPCHelpMan{"submitblock", "\nAttempts to submit new block to network.\n" "See https://en.bitcoin.it/wiki/BIP_0022 for full specification.\n", { @@ -1004,8 +1020,8 @@ static UniValue submitblock(const JSONRPCRequest& request) HelpExampleCli("submitblock", "\"mydata\"") + HelpExampleRpc("submitblock", "\"mydata\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr blockptr = std::make_shared(); CBlock& block = *blockptr; if (!DecodeHexBlk(block, request.params[0].get_str())) { @@ -1043,11 +1059,13 @@ static UniValue submitblock(const JSONRPCRequest& request) return "inconclusive"; } return BIP22ValidationResult(sc->state); +}, + }; } -static UniValue submitheader(const JSONRPCRequest& request) +static RPCHelpMan submitheader() { - RPCHelpMan{"submitheader", + return 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", { @@ -1059,8 +1077,8 @@ static UniValue submitheader(const JSONRPCRequest& request) HelpExampleCli("submitheader", "\"aabbcc\"") + HelpExampleRpc("submitheader", "\"aabbcc\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ CBlockHeader h; if (!DecodeHexBlockHeader(h, request.params[0].get_str())) { throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Block header decode failed"); @@ -1080,11 +1098,13 @@ static UniValue submitheader(const JSONRPCRequest& request) throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString()); } throw JSONRPCError(RPC_VERIFY_ERROR, state.GetRejectReason()); +}, + }; } -static UniValue estimatesmartfee(const JSONRPCRequest& request) +static RPCHelpMan estimatesmartfee() { - RPCHelpMan{"estimatesmartfee", + return 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.\n", @@ -1115,8 +1135,8 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("estimatesmartfee", "6") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR}); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); @@ -1145,11 +1165,13 @@ static UniValue estimatesmartfee(const JSONRPCRequest& request) } result.pushKV("blocks", feeCalc.returnedTarget); return result; +}, + }; } -static UniValue estimaterawfee(const JSONRPCRequest& request) +static RPCHelpMan estimaterawfee() { - RPCHelpMan{"estimaterawfee", + return 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" @@ -1200,8 +1222,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("estimaterawfee", "6 0.9") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true); RPCTypeCheckArgument(request.params[0], UniValue::VNUM); @@ -1263,6 +1285,8 @@ static UniValue estimaterawfee(const JSONRPCRequest& request) result.pushKV(StringForFeeEstimateHorizon(horizon), horizon_result); } return result; +}, + }; } void RegisterMiningRPCCommands(CRPCTable &t) diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 6c0f1295fc4a2..c93e55126e42d 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -291,13 +291,11 @@ CRPCTable::CRPCTable() } } -bool CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd) +void CRPCTable::appendCommand(const std::string& name, const CRPCCommand* pcmd) { - if (IsRPCRunning()) - return false; + CHECK_NONFATAL(!IsRPCRunning()); // Only add commands before rpc is running mapCommands[name].push_back(pcmd); - return true; } bool CRPCTable::removeCommand(const std::string& name, const CRPCCommand* pcmd) diff --git a/src/rpc/server.h b/src/rpc/server.h index afad349845854..d4a7ba60eb24a 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -160,7 +160,7 @@ class CRPCTable /** * Appends a CRPCCommand to the dispatch table. * - * Returns false if RPC server is already running (dump concurrency protection). + * Precondition: RPC server is not running * * Commands with different method names but the same unique_id will * be considered aliases, and only the first registered method name will @@ -169,7 +169,7 @@ class CRPCTable * between calls based on method name, and aliased commands can also * register different names, types, and numbers of parameters. */ - bool appendCommand(const std::string& name, const CRPCCommand* pcmd); + void appendCommand(const std::string& name, const CRPCCommand* pcmd); bool removeCommand(const std::string& name, const CRPCCommand* pcmd); }; diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index dfb1ec1139d8c..69ebc9459e7dd 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -68,9 +68,9 @@ static void RescanWallet(CWallet& wallet, const WalletRescanReserver& reserver, } } -UniValue importprivkey(const JSONRPCRequest& request) +RPCHelpMan importprivkey() { - RPCHelpMan{"importprivkey", + return RPCHelpMan{"importprivkey", "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n" "Hint: use importmulti to import more than one private key.\n" "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" @@ -93,8 +93,8 @@ UniValue importprivkey(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -156,11 +156,13 @@ UniValue importprivkey(const JSONRPCRequest& request) RescanWallet(*pwallet, reserver); } return NullUniValue; +}, + }; } -UniValue abortrescan(const JSONRPCRequest& request) +RPCHelpMan abortrescan() { - RPCHelpMan{"abortrescan", + return RPCHelpMan{"abortrescan", "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n", {}, RPCResult{RPCResult::Type::BOOL, "", "Whether the abort was successful"}, @@ -172,20 +174,22 @@ UniValue abortrescan(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("abortrescan", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false; - pwallet->AbortRescan(); - return true; - } + pwallet->AbortRescan(); + return true; +}, + }; +} -UniValue importaddress(const JSONRPCRequest& request) +RPCHelpMan importaddress() { - RPCHelpMan{"importaddress", + return 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" "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" "may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n" @@ -208,8 +212,8 @@ UniValue importaddress(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -279,11 +283,13 @@ UniValue importaddress(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -UniValue importprunedfunds(const JSONRPCRequest& request) +RPCHelpMan importprunedfunds() { - RPCHelpMan{"importprunedfunds", + return 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, RPCArg::Optional::NO, "A raw transaction in hex funding an already-existing address in wallet"}, @@ -291,8 +297,8 @@ UniValue importprunedfunds(const JSONRPCRequest& request) }, RPCResult{RPCResult::Type::NONE, "", ""}, RPCExamples{""}, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -336,11 +342,13 @@ UniValue importprunedfunds(const JSONRPCRequest& request) } throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction"); +}, + }; } -UniValue removeprunedfunds(const JSONRPCRequest& request) +RPCHelpMan removeprunedfunds() { - RPCHelpMan{"removeprunedfunds", + return 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, RPCArg::Optional::NO, "The hex-encoded id of the transaction you are deleting"}, @@ -351,8 +359,8 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -373,11 +381,13 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -UniValue importpubkey(const JSONRPCRequest& request) +RPCHelpMan importpubkey() { - RPCHelpMan{"importpubkey", + return 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" "Hint: use importmulti to import more than one public key.\n" "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" @@ -396,8 +406,8 @@ UniValue importpubkey(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -453,12 +463,14 @@ UniValue importpubkey(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -UniValue importwallet(const JSONRPCRequest& request) +RPCHelpMan importwallet() { - RPCHelpMan{"importwallet", + return RPCHelpMan{"importwallet", "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n" "Note: Use \"getwalletinfo\" to query the scanning progress.\n", { @@ -473,8 +485,8 @@ UniValue importwallet(const JSONRPCRequest& request) "\nImport using the json rpc call\n" + HelpExampleRpc("importwallet", "\"test\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -613,11 +625,13 @@ UniValue importwallet(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys/scripts to wallet"); return NullUniValue; +}, + }; } -UniValue importelectrumwallet(const JSONRPCRequest& request) +RPCHelpMan importelectrumwallet() { - RPCHelpMan{"importelectrumwallet", + return RPCHelpMan{"importelectrumwallet", "\nImports keys from an Electrum wallet export file (.csv or .json)\n", { {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The Electrum wallet export file, should be in csv or json format"}, @@ -632,7 +646,8 @@ UniValue importelectrumwallet(const JSONRPCRequest& request) + HelpExampleRpc("importelectrumwallet", "\"test.csv\"") + HelpExampleRpc("importelectrumwallet", "\"test.json\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; @@ -790,11 +805,13 @@ UniValue importelectrumwallet(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); return NullUniValue; +}, + }; } -UniValue dumpprivkey(const JSONRPCRequest& request) +RPCHelpMan dumpprivkey() { - RPCHelpMan{"dumpprivkey", + return RPCHelpMan{"dumpprivkey", "\nReveals the private key corresponding to 'address'.\n" "Then the importprivkey can be used with this output\n", { @@ -808,8 +825,8 @@ UniValue dumpprivkey(const JSONRPCRequest& request) + HelpExampleCli("importprivkey", "\"mykey\"") + HelpExampleRpc("dumpprivkey", "\"myaddress\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; const CWallet* const pwallet = wallet.get(); @@ -834,11 +851,13 @@ UniValue dumpprivkey(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); } return EncodeSecret(vchSecret); +}, + }; } -UniValue dumphdinfo(const JSONRPCRequest& request) +RPCHelpMan dumphdinfo() { - RPCHelpMan{"dumphdinfo", + return RPCHelpMan{"dumphdinfo", "Returns an object containing sensitive private info about this HD wallet.\n", {}, RPCResult{ @@ -853,8 +872,8 @@ UniValue dumphdinfo(const JSONRPCRequest& request) HelpExampleCli("dumphdinfo", "") + HelpExampleRpc("dumphdinfo", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; const CWallet* const pwallet = wallet.get(); @@ -881,11 +900,13 @@ UniValue dumphdinfo(const JSONRPCRequest& request) obj.pushKV("mnemonicpassphrase", ssMnemonicPassphrase.c_str()); return obj; +}, + }; } -UniValue dumpwallet(const JSONRPCRequest& request) +RPCHelpMan dumpwallet() { - RPCHelpMan{"dumpwallet", + return 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 too, their corresponding addresses will 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" @@ -905,8 +926,8 @@ UniValue dumpwallet(const JSONRPCRequest& request) HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return NullUniValue; @@ -1056,6 +1077,8 @@ UniValue dumpwallet(const JSONRPCRequest& request) obj.pushKV("warning", strWarning); return obj; +}, + }; } struct ImportData @@ -1430,9 +1453,9 @@ static int64_t GetImportTimestamp(const UniValue& data, int64_t now) throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key"); } -UniValue importmulti(const JSONRPCRequest& mainRequest) +RPCHelpMan importmulti() { - RPCHelpMan{"importmulti", + return RPCHelpMan{"importmulti", "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), optionally rescanning the blockchain from the earliest creation time of the imported scripts. Requires a new wallet backup.\n" "If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n" "Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n" @@ -1504,7 +1527,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) "{ \"scriptPubKey\": { \"address\": \"\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") + HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") }, - }.Check(mainRequest); + [&](const RPCHelpMan& self, const JSONRPCRequest& mainRequest) -> UniValue +{ RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); @@ -1614,6 +1638,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) } return response; +}, + }; } static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) @@ -1757,8 +1783,8 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue& return result; } -UniValue importdescriptors(const JSONRPCRequest& main_request) { - RPCHelpMan{"importdescriptors", +RPCHelpMan importdescriptors() { + return RPCHelpMan{"importdescriptors", "\nImport descriptors. This will trigger a rescan of the blockchain based on the earliest timestamp of all descriptors being imported. Requires a new wallet backup.\n" "\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n" "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n", @@ -1807,7 +1833,8 @@ UniValue importdescriptors(const JSONRPCRequest& main_request) { "{ \"desc\": \"\", \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") + HelpExampleCli("importdescriptors", "'[{ \"desc\": \"\", \"timestamp\":1455191478, \"active\": true, \"range\": [0,100], \"label\": \"\" }]'") }, - }.Check(main_request); + [&](const RPCHelpMan& self, const JSONRPCRequest& main_request) -> UniValue +{ // Acquire the wallet std::shared_ptr const wallet = GetWalletForJSONRPCRequest(main_request); @@ -1907,6 +1934,8 @@ UniValue importdescriptors(const JSONRPCRequest& main_request) { } return response; +}, + }; } RPCHelpMan listdescriptors() diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a7a52ea0a0726..24ab61710fe59 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4153,20 +4153,20 @@ static UniValue send(const JSONRPCRequest& request) return result; } -UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp -UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp -UniValue importprivkey(const JSONRPCRequest& request); -UniValue importaddress(const JSONRPCRequest& request); -UniValue importpubkey(const JSONRPCRequest& request); -UniValue dumpwallet(const JSONRPCRequest& request); -UniValue importwallet(const JSONRPCRequest& request); -UniValue importprunedfunds(const JSONRPCRequest& request); -UniValue removeprunedfunds(const JSONRPCRequest& request); -UniValue importmulti(const JSONRPCRequest& request); -UniValue importdescriptors(const JSONRPCRequest& request); +RPCHelpMan abortrescan(); +RPCHelpMan dumpprivkey(); +RPCHelpMan importprivkey(); +RPCHelpMan importaddress(); +RPCHelpMan importpubkey(); +RPCHelpMan dumpwallet(); +RPCHelpMan importwallet(); +RPCHelpMan importprunedfunds(); +RPCHelpMan removeprunedfunds(); +RPCHelpMan importmulti(); +RPCHelpMan importdescriptors(); RPCHelpMan listdescriptors(); -UniValue dumphdinfo(const JSONRPCRequest& request); -UniValue importelectrumwallet(const JSONRPCRequest& request); +RPCHelpMan dumphdinfo(); +RPCHelpMan importelectrumwallet(); UniValue walletprocesspsbt(const JSONRPCRequest& request) { diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index 282cad393bcf9..f24c591c89420 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -29,9 +29,9 @@ #include #include -extern UniValue importmulti(const JSONRPCRequest& request); -extern UniValue dumpwallet(const JSONRPCRequest& request); -extern UniValue importwallet(const JSONRPCRequest& request); +RPCHelpMan importmulti(); +RPCHelpMan dumpwallet(); +RPCHelpMan importwallet(); extern UniValue getnewaddress(const JSONRPCRequest& request); extern UniValue getrawchangeaddress(const JSONRPCRequest& request); extern UniValue getaddressinfo(const JSONRPCRequest& request); @@ -234,7 +234,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup) request.params.setArray(); request.params.push_back(keys); - UniValue response = importmulti(request); + UniValue response = importmulti().HandleRequest(request); BOOST_CHECK_EQUAL(response.write(), strprintf("[{\"success\":false,\"error\":{\"code\":-1,\"message\":\"Rescan failed for key with creation " "timestamp %d. There was an error reading a block from time %d, which is after or within %d " @@ -287,7 +287,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) request.params.setArray(); request.params.push_back(backup_file); - ::dumpwallet(request); + ::dumpwallet().HandleRequest(request); RemoveWallet(wallet, std::nullopt); } @@ -304,7 +304,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) request.params.push_back(backup_file); AddWallet(wallet); wallet->SetLastBlockProcessed(::ChainActive().Height(), ::ChainActive().Tip()->GetBlockHash()); - ::importwallet(request); + ::importwallet().HandleRequest(request); RemoveWallet(wallet, std::nullopt); BOOST_CHECK_EQUAL(wallet->mapWallet.size(), 3U); diff --git a/src/zmq/zmqrpc.cpp b/src/zmq/zmqrpc.cpp index 4cf2c585c1c8a..5abb2d0304ff9 100644 --- a/src/zmq/zmqrpc.cpp +++ b/src/zmq/zmqrpc.cpp @@ -13,9 +13,9 @@ namespace { -UniValue getzmqnotifications(const JSONRPCRequest& request) +static RPCHelpMan getzmqnotifications() { - RPCHelpMan{"getzmqnotifications", + return RPCHelpMan{"getzmqnotifications", "\nReturns information about the active ZeroMQ notifications.\n", {}, RPCResult{ @@ -33,8 +33,8 @@ UniValue getzmqnotifications(const JSONRPCRequest& request) HelpExampleCli("getzmqnotifications", "") + HelpExampleRpc("getzmqnotifications", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ UniValue result(UniValue::VARR); if (g_zmq_notification_interface != nullptr) { for (const auto* n : g_zmq_notification_interface->GetActiveNotifiers()) { @@ -47,6 +47,8 @@ UniValue getzmqnotifications(const JSONRPCRequest& request) } return result; +}, + }; } const CRPCCommand commands[] = diff --git a/test/functional/rpc_generate.py b/test/functional/rpc_generate.py index 9404f1e25ef2e..e55f2e6d12084 100755 --- a/test/functional/rpc_generate.py +++ b/test/functional/rpc_generate.py @@ -17,7 +17,8 @@ def set_test_params(self): def run_test(self): message = ( - "generate ( nblocks maxtries ) has been replaced by the -generate " + "generate\n" + "has been replaced by the -generate " "cli option. Refer to -help for more information." ) From f525f574b08a17debbd8fd0e8247e0007cb7dd3a Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 26 Feb 2024 01:19:02 +0700 Subject: [PATCH 05/12] fix: follow-up missing changes from Merge #18607: rpc: Fix named arguments in documentation --- src/rpc/mining.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index de6c78616c741..6b707a777a726 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -306,19 +306,19 @@ static RPCHelpMan generateblock() return RPCHelpMan{"generateblock", "\nMine a block with a set of ordered transactions immediately to a specified address or descriptor (before the RPC call returns)\n", { - {"address/descriptor", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor to send the newly generated coins to."}, + {"output", RPCArg::Type::STR, RPCArg::Optional::NO, "The address or descriptor to send the newly generated coins to."}, {"transactions", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings which are either txids or raw transactions.\n" "Txids must reference transactions currently in the mempool.\n" "All transactions must be valid and in valid order, otherwise the block will be rejected.", { {"rawtx/txid", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""}, }, - } + }, }, RPCResult{ RPCResult::Type::OBJ, "", "", { - {RPCResult::Type::STR_HEX, "hash", "hash of generated block"} + {RPCResult::Type::STR_HEX, "hash", "hash of generated block"}, } }, RPCExamples{ @@ -1305,7 +1305,7 @@ static const CRPCCommand commands[] = #if ENABLE_MINER { "generating", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} }, { "generating", "generatetodescriptor", &generatetodescriptor, {"num_blocks","descriptor","maxtries"} }, - { "generating", "generateblock", &generateblock, {"address","transactions"} }, + { "generating", "generateblock", &generateblock, {"output","transactions"} }, #else { "hidden", "generatetoaddress", &generatetoaddress, {"nblocks","address","maxtries"} }, // Hidden as it isn't functional, just an error to let people know if miner isn't compiled { "hidden", "generatetodescriptor", &generatetodescriptor, {"num_blocks","descriptor","maxtries"} }, From c30c8f22dd3a551000e3c23c9ba56d25beb6cb96 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Tue, 22 Sep 2020 17:08:00 +0200 Subject: [PATCH 06/12] Merge #19849: Assert that RPCArg names are equal to CRPCCommand ones (blockchain,rawtransaction) fa6bb0ce5dba33970e2c1e47ea4d0d2c0718eccb Assert that RPCArg names are equal to CRPCCommand ones (rawtransaction) (MarcoFalke) fa80c814874a2893e4323ba5148fba21d7f421cd Assert that RPCArg names are equal to CRPCCommand ones (blockchain) (MarcoFalke) Pull request description: This is split out from #18531 to just touch some RPC methods. Description from the main pr: ### Motivation RPCArg names in the rpc help are currently only used for documentation. However, in the future they could be used to teach the server the named arguments. Named arguments are currently registered by the `CRPCCommand`s and duplicate the RPCArg names from the documentation. This redundancy is fragile, and has lead to errors in the past (despite having linters to catch those kind of errors). See section "bugs found" for a list of bugs that have been found as a result of the changes here. ### Changes The changes here add an assert in the `CRPCCommand` constructor that the RPCArg names are identical to the ones in the `CRPCCommand`. ### Future work > Here or follow up, makes sense to also assert type of returned UniValue? Sure, but let's not get ahead of ourselves. I am going to submit any further works as follow-ups, including: * Removing the CRPCCommand arguments, now that they are asserted to be equal and thus redundant * Removing all python regex linters on the args, now that RPCMan can be used to generate any output, including the cli.cpp table * Auto-formatting and sanity checking the RPCExamples with RPCMan * Checking passed-in json in self-check. Removing redundant checks * Checking returned json against documentation to avoid regressions or false documentation * Compile the RPC documentation at compile-time to ensure it doesn't change at runtime and is completely static ### Bugs found * The assert identified issue #18607 * The changes itself fixed bug #19250 ACKs for top commit: fjahr: utACK fa6bb0ce5dba33970e2c1e47ea4d0d2c0718eccb tryphe: utACK fa6bb0ce5dba33970e2c1e47ea4d0d2c0718eccb. Reducing data duplication is nice. Code changes are minimal and concise. Tree-SHA512: deb0edc3f999baf055526eaa199b98c500635e12502dece7aa3cad5319db330eb5ee7459a5c8f040a83671a7f20c560c19a2026fb76c8416f138aa332727cbce --- src/rest.cpp | 4 +- src/rpc/blockchain.cpp | 342 +++++++++++++++++++++++-------------- src/rpc/evo.cpp | 6 +- src/rpc/rawtransaction.cpp | 217 +++++++++++++---------- 4 files changed, 344 insertions(+), 225 deletions(-) diff --git a/src/rest.cpp b/src/rest.cpp index 25308263e3cfc..0c83b3cef1523 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -334,7 +334,7 @@ static bool rest_block_notxdetails(const CoreContext& context, HTTPRequest* req, } // A bit of a hack - dependency on a function defined in rpc/blockchain.cpp -UniValue getblockchaininfo(const JSONRPCRequest& request); +RPCHelpMan getblockchaininfo(); static bool rest_chaininfo(const CoreContext& context, HTTPRequest* req, const std::string& strURIPart) { @@ -347,7 +347,7 @@ static bool rest_chaininfo(const CoreContext& context, HTTPRequest* req, const s case RetFormat::JSON: { JSONRPCRequest jsonRequest(context); jsonRequest.params = UniValue(UniValue::VARR); - UniValue chainInfoObject = getblockchaininfo(jsonRequest); + UniValue chainInfoObject = getblockchaininfo().HandleRequest(jsonRequest); std::string strJSON = chainInfoObject.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 242731b3bbe01..d457baf923a2c 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -242,9 +242,9 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn return result; } -static UniValue getblockcount(const JSONRPCRequest& request) +static RPCHelpMan getblockcount() { - RPCHelpMan{"getblockcount", + return RPCHelpMan{"getblockcount", "\nReturns the height of the most-work fully-validated chain.\n" "The genesis block has height 0.\n", {}, @@ -254,16 +254,18 @@ static UniValue getblockcount(const JSONRPCRequest& request) HelpExampleCli("getblockcount", "") + HelpExampleRpc("getblockcount", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); return chainman.ActiveChain().Height(); +}, + }; } -static UniValue getbestblockhash(const JSONRPCRequest& request) +static RPCHelpMan getbestblockhash() { - RPCHelpMan{"getbestblockhash", + return RPCHelpMan{"getbestblockhash", "\nReturns the hash of the best (tip) block in the most-work fully-validated chain.\n", {}, RPCResult{ @@ -272,16 +274,18 @@ static UniValue getbestblockhash(const JSONRPCRequest& request) HelpExampleCli("getbestblockhash", "") + HelpExampleRpc("getbestblockhash", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); return chainman.ActiveChain().Tip()->GetBlockHash().GetHex(); +}, + }; } -static UniValue getbestchainlock(const JSONRPCRequest& request) +static RPCHelpMan getbestchainlock() { - RPCHelpMan{"getbestchainlock", + return RPCHelpMan{"getbestchainlock", "\nReturns information about the best ChainLock. Throws an error if there is no known ChainLock yet.", {}, RPCResult{ @@ -296,7 +300,8 @@ static UniValue getbestchainlock(const JSONRPCRequest& request) HelpExampleCli("getbestchainlock", "") + HelpExampleRpc("getbestchainlock", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ UniValue result(UniValue::VOBJ); const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -314,6 +319,8 @@ static UniValue getbestchainlock(const JSONRPCRequest& request) LOCK(cs_main); result.pushKV("known_block", chainman.m_blockman.LookupBlockIndex(clsig.getBlockHash()) != nullptr); return result; +}, + }; } void RPCNotifyBlockChange(const CBlockIndex* pindex) @@ -326,9 +333,9 @@ void RPCNotifyBlockChange(const CBlockIndex* pindex) cond_blockchange.notify_all(); } -static UniValue waitfornewblock(const JSONRPCRequest& request) +static RPCHelpMan waitfornewblock() { - RPCHelpMan{"waitfornewblock", + return RPCHelpMan{"waitfornewblock", "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n", { @@ -344,7 +351,8 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) HelpExampleCli("waitfornewblock", "1000") + HelpExampleRpc("waitfornewblock", "1000") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ int timeout = 0; if (!request.params[0].isNull()) timeout = request.params[0].get_int(); @@ -363,11 +371,13 @@ static UniValue waitfornewblock(const JSONRPCRequest& request) ret.pushKV("hash", block.hash.GetHex()); ret.pushKV("height", block.height); return ret; +}, + }; } -static UniValue waitforblock(const JSONRPCRequest& request) +static RPCHelpMan waitforblock() { - RPCHelpMan{"waitforblock", + return RPCHelpMan{"waitforblock", "\nWaits for a specific new block and returns useful info about it.\n" "\nReturns the current block on timeout or exit.\n", { @@ -384,7 +394,8 @@ static UniValue waitforblock(const JSONRPCRequest& request) HelpExampleCli("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\" 1000") + HelpExampleRpc("waitforblock", "\"0000000000079f8ef3d2c688c244eb7a4570b24c9ed7b4a8c619eb02596f8862\", 1000") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ int timeout = 0; uint256 hash(ParseHashV(request.params[0], "blockhash")); @@ -406,11 +417,13 @@ static UniValue waitforblock(const JSONRPCRequest& request) ret.pushKV("hash", block.hash.GetHex()); ret.pushKV("height", block.height); return ret; +}, + }; } -static UniValue waitforblockheight(const JSONRPCRequest& request) +static RPCHelpMan waitforblockheight() { - RPCHelpMan{"waitforblockheight", + return 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", @@ -428,7 +441,8 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) HelpExampleCli("waitforblockheight", "100 1000") + HelpExampleRpc("waitforblockheight", "100, 1000") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ int timeout = 0; int height = request.params[0].get_int(); @@ -449,11 +463,13 @@ static UniValue waitforblockheight(const JSONRPCRequest& request) ret.pushKV("hash", block.hash.GetHex()); ret.pushKV("height", block.height); return ret; +}, + }; } -static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request) +static RPCHelpMan syncwithvalidationinterfacequeue() { - RPCHelpMan{"syncwithvalidationinterfacequeue", + return RPCHelpMan{"syncwithvalidationinterfacequeue", "\nWaits for the validation interface queue to catch up on everything that was there when we entered this function.\n", {}, RPCResult{RPCResult::Type::NONE, "", ""}, @@ -461,14 +477,17 @@ static UniValue syncwithvalidationinterfacequeue(const JSONRPCRequest& request) HelpExampleCli("syncwithvalidationinterfacequeue","") + HelpExampleRpc("syncwithvalidationinterfacequeue","") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ SyncWithValidationInterfaceQueue(); return NullUniValue; +}, + }; } -static UniValue getdifficulty(const JSONRPCRequest& request) +static RPCHelpMan getdifficulty() { - RPCHelpMan{"getdifficulty", + return RPCHelpMan{"getdifficulty", "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n", {}, RPCResult{ @@ -477,11 +496,14 @@ static UniValue getdifficulty(const JSONRPCRequest& request) HelpExampleCli("getdifficulty", "") + HelpExampleRpc("getdifficulty", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); return GetDifficulty(chainman.ActiveChain().Tip()); +}, + }; } static std::vector MempoolEntryDescription() { return { @@ -588,9 +610,9 @@ UniValue MempoolToJSON(const CTxMemPool& pool, llmq::CInstantSendManager* isman, } } -static UniValue getrawmempool(const JSONRPCRequest& request) +static RPCHelpMan getrawmempool() { - RPCHelpMan{"getrawmempool", + return RPCHelpMan{"getrawmempool", "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n", { @@ -612,8 +634,8 @@ static UniValue getrawmempool(const JSONRPCRequest& request) HelpExampleCli("getrawmempool", "true") + HelpExampleRpc("getrawmempool", "true") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ bool fVerbose = false; if (!request.params[0].isNull()) fVerbose = request.params[0].get_bool(); @@ -622,11 +644,13 @@ static UniValue getrawmempool(const JSONRPCRequest& request) const CTxMemPool& mempool = EnsureMemPool(node); LLMQContext& llmq_ctx = EnsureLLMQContext(node); return MempoolToJSON(mempool, llmq_ctx.isman, fVerbose); +}, + }; } -static UniValue getmempoolancestors(const JSONRPCRequest& request) +static RPCHelpMan getmempoolancestors() { - RPCHelpMan{"getmempoolancestors", + return RPCHelpMan{"getmempoolancestors", "\nIf txid is in the mempool, returns all in-mempool ancestors.\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, @@ -646,8 +670,8 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) HelpExampleCli("getmempoolancestors", "\"mytxid\"") + HelpExampleRpc("getmempoolancestors", "\"mytxid\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ bool fVerbose = false; if (!request.params[1].isNull()) fVerbose = request.params[1].get_bool(); @@ -687,11 +711,13 @@ static UniValue getmempoolancestors(const JSONRPCRequest& request) } return o; } +}, + }; } -static UniValue getmempooldescendants(const JSONRPCRequest& request) +static RPCHelpMan getmempooldescendants() { - RPCHelpMan{"getmempooldescendants", + return RPCHelpMan{"getmempooldescendants", "\nIf txid is in the mempool, returns all in-mempool descendants.\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, @@ -711,8 +737,8 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) HelpExampleCli("getmempooldescendants", "\"mytxid\"") + HelpExampleRpc("getmempooldescendants", "\"mytxid\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ bool fVerbose = false; if (!request.params[1].isNull()) fVerbose = request.params[1].get_bool(); @@ -753,11 +779,13 @@ static UniValue getmempooldescendants(const JSONRPCRequest& request) } return o; } +}, + }; } -static UniValue getmempoolentry(const JSONRPCRequest& request) +static RPCHelpMan getmempoolentry() { - RPCHelpMan{"getmempoolentry", + return RPCHelpMan{"getmempoolentry", "\nReturns mempool data for given transaction\n", { {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"}, @@ -768,7 +796,8 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) HelpExampleCli("getmempoolentry", "\"mytxid\"") + HelpExampleRpc("getmempoolentry", "\"mytxid\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint256 hash(ParseHashV(request.params[0], "parameter 1")); @@ -787,11 +816,13 @@ static UniValue getmempoolentry(const JSONRPCRequest& request) LLMQContext& llmq_ctx = EnsureLLMQContext(node); entryToJSON(mempool, info, e, llmq_ctx.isman); return info; +}, + }; } -static UniValue getblockhashes(const JSONRPCRequest& request) +static RPCHelpMan getblockhashes() { - RPCHelpMan{"getblockhashes", + return RPCHelpMan{"getblockhashes", "\nReturns array of hashes of blocks within the timestamp range provided.\n", { {"high", RPCArg::Type::NUM, RPCArg::Optional::NO, "The newer block timestamp"}, @@ -804,8 +835,8 @@ static UniValue getblockhashes(const JSONRPCRequest& request) HelpExampleCli("getblockhashes", "1231614698 1231024505") + HelpExampleRpc("getblockhashes", "1231614698, 1231024505") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ unsigned int high = request.params[0].get_int(); unsigned int low = request.params[1].get_int(); std::vector blockHashes; @@ -820,11 +851,13 @@ static UniValue getblockhashes(const JSONRPCRequest& request) } return result; +}, + }; } -static UniValue getblockhash(const JSONRPCRequest& request) +static RPCHelpMan getblockhash() { - RPCHelpMan{"getblockhash", + return RPCHelpMan{"getblockhash", "\nReturns hash of block in best-block-chain at height provided.\n", { {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The height index"}, @@ -835,8 +868,8 @@ static UniValue getblockhash(const JSONRPCRequest& request) HelpExampleCli("getblockhash", "1000") + HelpExampleRpc("getblockhash", "1000") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); const CChain& active_chain = chainman.ActiveChain(); @@ -847,11 +880,13 @@ static UniValue getblockhash(const JSONRPCRequest& request) CBlockIndex* pblockindex = active_chain[nHeight]; return pblockindex->GetBlockHash().GetHex(); +}, + }; } -static UniValue getblockheader(const JSONRPCRequest& request) +static RPCHelpMan getblockheader() { - RPCHelpMan{"getblockheader", + return 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 .\n", { @@ -886,8 +921,8 @@ static UniValue getblockheader(const JSONRPCRequest& request) HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint256 hash(ParseHashV(request.params[0], "hash")); const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -918,11 +953,13 @@ static UniValue getblockheader(const JSONRPCRequest& request) LLMQContext& llmq_ctx = EnsureLLMQContext(node); return blockheaderToJSON(tip, pblockindex, *llmq_ctx.clhandler, *llmq_ctx.isman); +}, + }; } -static UniValue getblockheaders(const JSONRPCRequest& request) +static RPCHelpMan getblockheaders() { - RPCHelpMan{"getblockheaders", + return RPCHelpMan{"getblockheaders", "\nReturns an array of items with information about blockheaders starting from .\n" "\nIf verbose is false, each item is a string that is serialized, hex-encoded data for a single blockheader.\n" "If verbose is true, each item is an Object with information about a single blockheader.\n", @@ -962,7 +999,8 @@ static UniValue getblockheaders(const JSONRPCRequest& request) HelpExampleCli("getblockheaders", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 2000") + HelpExampleRpc("getblockheaders", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" 2000") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint256 hash(ParseHashV(request.params[0], "blockhash")); @@ -1021,6 +1059,8 @@ static UniValue getblockheaders(const JSONRPCRequest& request) } return arrHeaders; +}, + }; } static CBlock GetBlockChecked(const CBlockIndex* pblockindex) @@ -1054,9 +1094,9 @@ static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) return blockUndo; } -static UniValue getmerkleblocks(const JSONRPCRequest& request) +static RPCHelpMan getmerkleblocks() { - RPCHelpMan{"getmerkleblocks", + return RPCHelpMan{"getmerkleblocks", "\nReturns an array of hex-encoded merkleblocks for blocks starting from which match .\n", { {"filter", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded bloom filter"}, @@ -1070,8 +1110,8 @@ static UniValue getmerkleblocks(const JSONRPCRequest& request) HelpExampleCli("getmerkleblocks", "\"2303028005802040100040000008008400048141010000f8400420800080025004000004130000000000000001\" \"00000000007e1432d2af52e8463278bf556b55cf5049262f25634557e2e91202\" 2000") + HelpExampleRpc("getmerkleblocks", "\"2303028005802040100040000008008400048141010000f8400420800080025004000004130000000000000001\" \"00000000007e1432d2af52e8463278bf556b55cf5049262f25634557e2e91202\" 2000") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); @@ -1125,11 +1165,13 @@ static UniValue getmerkleblocks(const JSONRPCRequest& request) arrMerkleBlocks.push_back(strHex); } return arrMerkleBlocks; +}, + }; } -static UniValue getblock(const JSONRPCRequest& request) +static RPCHelpMan getblock() { - RPCHelpMan{"getblock", + return 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 .\n" "If verbosity is 2, returns an Object with information about block and information about each transaction. \n", @@ -1187,8 +1229,8 @@ static UniValue getblock(const JSONRPCRequest& request) HelpExampleCli("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + HelpExampleRpc("getblock", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint256 hash(ParseHashV(request.params[0], "blockhash")); int verbosity = 1; @@ -1227,11 +1269,13 @@ static UniValue getblock(const JSONRPCRequest& request) LLMQContext& llmq_ctx = EnsureLLMQContext(node); return blockToJSON(block, tip, pblockindex, *llmq_ctx.clhandler, *llmq_ctx.isman, verbosity >= 2); +}, + }; } -static UniValue pruneblockchain(const JSONRPCRequest& request) +static RPCHelpMan pruneblockchain() { - RPCHelpMan{"pruneblockchain", "", + return RPCHelpMan{"pruneblockchain", "", { {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or to a " + UNIX_EPOCH_TIME + "\n" " to prune blocks whose block time is at least 2 hours older than the provided timestamp."}, @@ -1242,8 +1286,8 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) HelpExampleCli("pruneblockchain", "1000") + HelpExampleRpc("pruneblockchain", "1000") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ if (!fPruneMode) throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode."); @@ -1285,6 +1329,8 @@ static UniValue pruneblockchain(const JSONRPCRequest& request) block = block->pprev; } return uint64_t(block->nHeight); +}, + }; } CoinStatsHashType ParseHashType(const std::string& hash_type_input) @@ -1300,9 +1346,9 @@ CoinStatsHashType ParseHashType(const std::string& hash_type_input) } } -static UniValue gettxoutsetinfo(const JSONRPCRequest& request) +static RPCHelpMan gettxoutsetinfo() { - RPCHelpMan{"gettxoutsetinfo", + return RPCHelpMan{"gettxoutsetinfo", "\nReturns statistics about the unspent transaction output set.\n" "Note this call may take some time if you are not using coinstatsindex.\n", { @@ -1348,8 +1394,8 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request) HelpExampleRpc("gettxoutsetinfo", R"("none", 1000)") + HelpExampleRpc("gettxoutsetinfo", R"("none", "00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09")") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ UniValue ret(UniValue::VOBJ); CBlockIndex* pindex{nullptr}; @@ -1439,11 +1485,13 @@ static UniValue gettxoutsetinfo(const JSONRPCRequest& request) throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); } return ret; +}, + }; } -static UniValue gettxout(const JSONRPCRequest& request) +static RPCHelpMan gettxout() { - RPCHelpMan{"gettxout", + return RPCHelpMan{"gettxout", "\nReturns details about an unspent transaction output.\n", { {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"}, @@ -1475,7 +1523,8 @@ static UniValue gettxout(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("gettxout", "\"txid\", 1") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); @@ -1523,11 +1572,13 @@ static UniValue gettxout(const JSONRPCRequest& request) ret.pushKV("coinbase", (bool)coin.fCoinBase); return ret; +}, + }; } -static UniValue verifychain(const JSONRPCRequest& request) +static RPCHelpMan verifychain() { - RPCHelpMan{"verifychain", + return RPCHelpMan{"verifychain", "\nVerifies blockchain database.\n", { {"checklevel", RPCArg::Type::NUM, /* default */ strprintf("%d, range=0-4", DEFAULT_CHECKLEVEL), @@ -1540,8 +1591,8 @@ static UniValue verifychain(const JSONRPCRequest& request) HelpExampleCli("verifychain", "") + HelpExampleRpc("verifychain", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const int check_level(request.params[0].isNull() ? DEFAULT_CHECKLEVEL : request.params[0].get_int()); const int check_depth{request.params[1].isNull() ? DEFAULT_CHECKBLOCKS : request.params[1].get_int()}; @@ -1553,6 +1604,8 @@ static UniValue verifychain(const JSONRPCRequest& request) CChainState& active_chainstate = chainman.ActiveChainstate(); return CVerifyDB().VerifyDB( active_chainstate, Params(), active_chainstate.CoinsTip(), *node.evodb, check_level, check_depth); +}, + }; } static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep) @@ -1628,9 +1681,9 @@ static void SoftForkDescPushBack(const CBlockIndex* active_chain_tip, const std: softforks.pushKV(DeploymentName(id), rv); } -UniValue getblockchaininfo(const JSONRPCRequest& request) +RPCHelpMan getblockchaininfo() { - RPCHelpMan{"getblockchaininfo", + return RPCHelpMan{"getblockchaininfo", "Returns an object containing various state info regarding blockchain processing.\n", {}, RPCResult{ @@ -1683,7 +1736,8 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) HelpExampleCli("getblockchaininfo", "") + HelpExampleRpc("getblockchaininfo", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); @@ -1748,6 +1802,8 @@ UniValue getblockchaininfo(const JSONRPCRequest& request) obj.pushKV("warnings", GetWarnings(false).original); return obj; +}, + }; } /** Comparison function for sorting the getchaintips heads. */ @@ -1765,9 +1821,9 @@ struct CompareBlocksByHeight } }; -static UniValue getchaintips(const JSONRPCRequest& request) +static RPCHelpMan getchaintips() { - RPCHelpMan{"getchaintips", + return RPCHelpMan{"getchaintips", "Return information about all known tips in the block tree," " including the main chain as well as orphaned branches.\n", { @@ -1797,7 +1853,8 @@ static UniValue getchaintips(const JSONRPCRequest& request) HelpExampleCli("getchaintips", "") + HelpExampleRpc("getchaintips", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); LOCK(cs_main); @@ -1886,6 +1943,8 @@ static UniValue getchaintips(const JSONRPCRequest& request) } return res; +}, + }; } UniValue MempoolInfoToJSON(const CTxMemPool& pool, llmq::CInstantSendManager& isman) @@ -1907,9 +1966,9 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool, llmq::CInstantSendManager& is return ret; } -static UniValue getmempoolinfo(const JSONRPCRequest& request) +static RPCHelpMan getmempoolinfo() { - RPCHelpMan{"getmempoolinfo", + return RPCHelpMan{"getmempoolinfo", "\nReturns details on the active state of the TX memory pool.\n", {}, RPCResult{ @@ -1930,17 +1989,19 @@ static UniValue getmempoolinfo(const JSONRPCRequest& request) HelpExampleCli("getmempoolinfo", "") + HelpExampleRpc("getmempoolinfo", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); const CTxMemPool& mempool = EnsureMemPool(node); LLMQContext& llmq_ctx = EnsureLLMQContext(node); return MempoolInfoToJSON(mempool, *llmq_ctx.isman); +}, + }; } -static UniValue preciousblock(const JSONRPCRequest& request) +static RPCHelpMan preciousblock() { - RPCHelpMan{"preciousblock", + return 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", @@ -1952,8 +2013,8 @@ static UniValue preciousblock(const JSONRPCRequest& request) HelpExampleCli("preciousblock", "\"blockhash\"") + HelpExampleRpc("preciousblock", "\"blockhash\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint256 hash(ParseHashV(request.params[0], "blockhash")); CBlockIndex* pblockindex; @@ -1974,11 +2035,13 @@ static UniValue preciousblock(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue invalidateblock(const JSONRPCRequest& request) +static RPCHelpMan invalidateblock() { - RPCHelpMan{"invalidateblock", + return RPCHelpMan{"invalidateblock", "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n", { {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hash of the block to mark as invalid"}, @@ -1988,8 +2051,8 @@ static UniValue invalidateblock(const JSONRPCRequest& request) HelpExampleCli("invalidateblock", "\"blockhash\"") + HelpExampleRpc("invalidateblock", "\"blockhash\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint256 hash(ParseHashV(request.params[0], "blockhash")); BlockValidationState state; @@ -2015,11 +2078,13 @@ static UniValue invalidateblock(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue reconsiderblock(const JSONRPCRequest& request) +static RPCHelpMan reconsiderblock() { - RPCHelpMan{"reconsiderblock", + return RPCHelpMan{"reconsiderblock", "\nRemoves invalidity status of a block, its ancestors and its descendants, reconsider them for activation.\n" "This can be used to undo the effects of invalidateblock.\n", { @@ -2030,8 +2095,8 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) HelpExampleCli("reconsiderblock", "\"blockhash\"") + HelpExampleRpc("reconsiderblock", "\"blockhash\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); CChainState& active_chainstate = chainman.ActiveChainstate(); @@ -2055,11 +2120,13 @@ static UniValue reconsiderblock(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue getchaintxstats(const JSONRPCRequest& request) +static RPCHelpMan getchaintxstats() { - RPCHelpMan{"getchaintxstats", + return RPCHelpMan{"getchaintxstats", "\nCompute statistics about the total number and rate of transactions in the chain.\n", { {"nblocks", RPCArg::Type::NUM, /* default */ "one month", "Size of the window in number of blocks"}, @@ -2081,8 +2148,8 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) HelpExampleCli("getchaintxstats", "") + HelpExampleRpc("getchaintxstats", "2016") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ ChainstateManager& chainman = EnsureAnyChainman(request.context); CChain& active_chain = chainman.ActiveChain(); @@ -2135,6 +2202,8 @@ static UniValue getchaintxstats(const JSONRPCRequest& request) } return ret; +}, + }; } template @@ -2193,9 +2262,9 @@ static inline bool SetHasKeys(const std::set& set, const Tk& key, const Args& // outpoint (needed for the utxo index) + nHeight + fCoinBase static constexpr size_t PER_UTXO_OVERHEAD = sizeof(COutPoint) + sizeof(uint32_t) + sizeof(bool); -static UniValue getblockstats(const JSONRPCRequest& request) +static RPCHelpMan getblockstats() { - RPCHelpMan{"getblockstats", + return RPCHelpMan{"getblockstats", "\nCompute per block statistics for a given window. All amounts are in duffs.\n" "It won't work for some heights with pruning.\n", { @@ -2249,8 +2318,8 @@ static UniValue getblockstats(const JSONRPCRequest& request) HelpExampleRpc("getblockstats", R"("00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09", ["minfeerate","avgfeerate"])") + HelpExampleRpc("getblockstats", R"(1000, ["minfeerate","avgfeerate"])") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ if (g_txindex) { g_txindex->BlockUntilSyncedToCurrentChain(); } @@ -2405,11 +2474,13 @@ static UniValue getblockstats(const JSONRPCRequest& request) ret.pushKV(stat, value); } return ret; +}, + }; } -static UniValue getspecialtxes(const JSONRPCRequest& request) +static RPCHelpMan getspecialtxes() { - RPCHelpMan{"getspecialtxes", + return RPCHelpMan{"getspecialtxes", "Returns an array of special transactions found in the specified block\n" "\nIf verbosity is 0, returns tx hash for each transaction.\n" "If verbosity is 1, returns hex-encoded data for each transaction.\n" @@ -2436,8 +2507,8 @@ static UniValue getspecialtxes(const JSONRPCRequest& request) HelpExampleCli("getspecialtxes", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") + HelpExampleRpc("getspecialtxes", "\"00000000000fd08c2fb661d2fcb0d49abb3a91e5f27082ce64feed3b4dede2e2\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); @@ -2510,13 +2581,14 @@ static UniValue getspecialtxes(const JSONRPCRequest& request) default : throw JSONRPCError(RPC_INTERNAL_ERROR, "Unsupported verbosity"); } } - return result; +}, + }; } -static UniValue savemempool(const JSONRPCRequest& request) +static RPCHelpMan savemempool() { - RPCHelpMan{"savemempool", + return RPCHelpMan{"savemempool", "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n", {}, RPCResult{RPCResult::Type::NONE, "", ""}, @@ -2524,8 +2596,8 @@ static UniValue savemempool(const JSONRPCRequest& request) HelpExampleCli("savemempool", "") + HelpExampleRpc("savemempool", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const CTxMemPool& mempool = EnsureAnyMemPool(request.context); if (!mempool.IsLoaded()) { @@ -2537,6 +2609,8 @@ static UniValue savemempool(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } namespace { @@ -2600,9 +2674,9 @@ class CoinsViewScanReserver } }; -UniValue scantxoutset(const JSONRPCRequest& request) +static RPCHelpMan scantxoutset() { - RPCHelpMan{"scantxoutset", + return 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" @@ -2656,8 +2730,8 @@ UniValue scantxoutset(const JSONRPCRequest& request) {RPCResult::Type::STR_AMOUNT, "total_amount", "The total amount of all found unspent outputs in " + CURRENCY_UNIT}, }}, RPCExamples{""}, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}); UniValue result(UniValue::VOBJ); @@ -2751,11 +2825,13 @@ UniValue scantxoutset(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid command"); } return result; +}, + }; } -static UniValue getblockfilter(const JSONRPCRequest& request) +static RPCHelpMan getblockfilter() { - RPCHelpMan{"getblockfilter", + return RPCHelpMan{"getblockfilter", "\nRetrieve a BIP 157 content filter for a particular block.\n", { {"blockhash", RPCArg::Type::STR, RPCArg::Optional::NO, "The hash of the block"}, @@ -2771,8 +2847,8 @@ static UniValue getblockfilter(const JSONRPCRequest& request) HelpExampleCli("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\" \"basic\"")+ HelpExampleRpc("getblockfilter", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\", \"basic\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ uint256 block_hash(ParseHashV(request.params[0], "blockhash")); std::string filtertype_name = "basic"; if (!request.params[1].isNull()) { @@ -2828,6 +2904,8 @@ static UniValue getblockfilter(const JSONRPCRequest& request) ret.pushKV("filter", HexStr(filter.GetEncodedFilter())); ret.pushKV("header", filter_header.GetHex()); return ret; +}, + }; } /** @@ -2835,9 +2913,9 @@ static UniValue getblockfilter(const JSONRPCRequest& request) * * @see SnapshotMetadata */ -UniValue dumptxoutset(const JSONRPCRequest& request) +static RPCHelpMan dumptxoutset() { - RPCHelpMan{ + return RPCHelpMan{ "dumptxoutset", "Write the serialized UTXO set to disk.", { @@ -2854,9 +2932,9 @@ UniValue dumptxoutset(const JSONRPCRequest& request) }, RPCExamples{ HelpExampleCli("dumptxoutset", "utxo.dat") - } - }.Check(request); - + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const fs::path path = fsbridge::AbsPathJoin(GetDataDir(), request.params[0].get_str()); // Write to a temporary path and then move into `path` on completion // to avoid confusion due to an interruption. @@ -2877,6 +2955,8 @@ UniValue dumptxoutset(const JSONRPCRequest& request) result.pushKV("path", path.string()); return result; +}, + }; } UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFile& afile) diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index c5a4a75b12660..c82e2d1b0e2b4 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -35,8 +35,8 @@ #endif//ENABLE_WALLET #ifdef ENABLE_WALLET -extern UniValue signrawtransaction(const JSONRPCRequest& request); -extern UniValue sendrawtransaction(const JSONRPCRequest& request); +extern RPCHelpMan signrawtransaction(); +extern RPCHelpMan sendrawtransaction(); #else class CWallet; #endif//ENABLE_WALLET @@ -350,7 +350,7 @@ static std::string SignAndSendSpecialTx(const JSONRPCRequest& request, const Cha JSONRPCRequest sendRequest(request); sendRequest.params.setArray(); sendRequest.params.push_back(signResult["hex"].get_str()); - return sendrawtransaction(sendRequest).get_str(); + return sendrawtransaction().HandleRequest(sendRequest).get_str(); } static void protx_register_fund_help(const JSONRPCRequest& request, bool legacy) diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index ba2ccebc52798..142d89677a6c1 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -112,9 +112,9 @@ void TxToJSON(const CTransaction& tx, const uint256 hashBlock, CTxMemPool& mempo entry.pushKV("chainlock", chainLock); } -static UniValue getrawtransaction(const JSONRPCRequest& request) +static RPCHelpMan getrawtransaction() { - RPCHelpMan{ + return RPCHelpMan{ "getrawtransaction", "\nReturn the raw transaction data.\n" @@ -198,8 +198,8 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) + HelpExampleCli("getrawtransaction", "\"mytxid\" false \"myblockhash\"") + HelpExampleCli("getrawtransaction", "\"mytxid\" true \"myblockhash\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); ChainstateManager& chainman = EnsureChainman(node); @@ -264,10 +264,12 @@ static UniValue getrawtransaction(const JSONRPCRequest& request) if (blockindex) result.pushKV("in_active_chain", in_active_chain); TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *llmq_ctx.clhandler, *llmq_ctx.isman, result); return result; +}, + }; } -static UniValue getrawtransactionmulti(const JSONRPCRequest& request) { - RPCHelpMan{ +static RPCHelpMan getrawtransactionmulti() { + return RPCHelpMan{ "getrawtransactionmulti", "\nReturns the raw transaction data for multiple transactions.\n" "\nThis call is an extension of getrawtransaction that supports multiple transactions.\n" @@ -293,8 +295,8 @@ static UniValue getrawtransactionmulti(const JSONRPCRequest& request) { + HelpExampleRpc("getrawtransactionmulti", R"('{"blockhash1":["txid1","txid2"], "0":["txid3"]})") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ // Parse arguments UniValue transactions{request.params[0].get_obj()}; // Accept either a bool (true) or a num (>=1) to indicate verbose output. @@ -347,13 +349,14 @@ static UniValue getrawtransactionmulti(const JSONRPCRequest& request) { } } } - return result; +}, + }; } -static UniValue gettxchainlocks(const JSONRPCRequest& request) +static RPCHelpMan gettxchainlocks() { - RPCHelpMan{ + return RPCHelpMan{ "gettxchainlocks", "\nReturns the block height at which each transaction was mined, and indicates whether it is in the mempool, ChainLocked, or neither.\n", { @@ -378,8 +381,8 @@ static UniValue gettxchainlocks(const JSONRPCRequest& request) HelpExampleCli("gettxchainlocks", "'[\"mytxid\",...]'") + HelpExampleRpc("gettxchainlocks", "[\"mytxid\",...]") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); const ChainstateManager& chainman = EnsureChainman(node); @@ -433,11 +436,13 @@ static UniValue gettxchainlocks(const JSONRPCRequest& request) result_arr.push_back(result); } return result_arr; +}, + }; } -static void getassetunlockstatuses_help(const JSONRPCRequest& request) +static RPCHelpMan getassetunlockstatuses() { - RPCHelpMan{ + return RPCHelpMan{ "getassetunlockstatuses", "\nReturns the status of given Asset Unlock indexes at the tip of the chain or at a specific block height if specified.\n", { @@ -462,13 +467,8 @@ static void getassetunlockstatuses_help(const JSONRPCRequest& request) HelpExampleCli("getassetunlockstatuses", "'[\"myindex\",...]'") + HelpExampleRpc("getassetunlockstatuses", "[\"myindex\",...]") }, - }.Check(request); -} - -static UniValue getassetunlockstatuses(const JSONRPCRequest& request) + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - getassetunlockstatuses_help(request); - const NodeContext& node = EnsureAnyNodeContext(request.context); const CTxMemPool& mempool = EnsureMemPool(node); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); @@ -562,11 +562,13 @@ static UniValue getassetunlockstatuses(const JSONRPCRequest& request) } return result_arr; +}, + }; } -static UniValue gettxoutproof(const JSONRPCRequest& request) +static RPCHelpMan gettxoutproof() { - RPCHelpMan{"gettxoutproof", + return 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" @@ -588,8 +590,8 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) + HelpExampleCli("gettxoutproof", "'[\"mytxid\",...]' \"blockhash\"") + HelpExampleRpc("gettxoutproof", "[\"mytxid\",...], \"blockhash\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::set setTxids; UniValue txids = request.params[0].get_array(); if (txids.empty()) { @@ -665,11 +667,13 @@ static UniValue gettxoutproof(const JSONRPCRequest& request) ssMB << mb; std::string strHex = HexStr(ssMB); return strHex; +}, + }; } -static UniValue verifytxoutproof(const JSONRPCRequest& request) +static RPCHelpMan verifytxoutproof() { - RPCHelpMan{"verifytxoutproof", + return 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", { @@ -685,8 +689,8 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) HelpExampleCli("verifytxoutproof", "\"proof\"") + HelpExampleRpc("gettxoutproof", "\"proof\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ CDataStream ssMB(ParseHexV(request.params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION); CMerkleBlock merkleBlock; ssMB >> merkleBlock; @@ -714,11 +718,13 @@ static UniValue verifytxoutproof(const JSONRPCRequest& request) } return res; +}, + }; } -static UniValue createrawtransaction(const JSONRPCRequest& request) +static RPCHelpMan createrawtransaction() { - RPCHelpMan{"createrawtransaction", + return RPCHelpMan{"createrawtransaction", "\nCreate a transaction spending the given inputs and creating new outputs.\n" "Outputs can be addresses or data.\n" "Returns hex-encoded raw transaction.\n" @@ -764,8 +770,8 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"address\\\":0.01}]\"") + HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"[{\\\"data\\\":\\\"00010203\\\"}]\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VARR, UniValueType(), // ARR or OBJ, checked later @@ -776,11 +782,13 @@ static UniValue createrawtransaction(const JSONRPCRequest& request) CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2]); return EncodeHexTx(CTransaction(rawTx)); +}, + }; } -static UniValue decoderawtransaction(const JSONRPCRequest& request) +static RPCHelpMan decoderawtransaction() { - RPCHelpMan{"decoderawtransaction", + return RPCHelpMan{"decoderawtransaction", "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction hex string"}, @@ -834,8 +842,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) HelpExampleCli("decoderawtransaction", "\"hexstring\"") + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); CMutableTransaction mtx; @@ -847,6 +855,8 @@ static UniValue decoderawtransaction(const JSONRPCRequest& request) TxToUniv(CTransaction(std::move(mtx)), uint256(), result, false); return result; +}, + }; } static std::string GetAllOutputTypes() @@ -859,9 +869,9 @@ static std::string GetAllOutputTypes() return Join(ret, ", "); } -static UniValue decodescript(const JSONRPCRequest& request) +static RPCHelpMan decodescript() { - RPCHelpMan{"decodescript", + return RPCHelpMan{"decodescript", "\nDecode a hex-encoded script.\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "the hex-encoded script"}, @@ -883,8 +893,8 @@ static UniValue decodescript(const JSONRPCRequest& request) HelpExampleCli("decodescript", "\"hexstring\"") + HelpExampleRpc("decodescript", "\"hexstring\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); UniValue r(UniValue::VOBJ); @@ -908,11 +918,13 @@ static UniValue decodescript(const JSONRPCRequest& request) } return r; +}, + }; } -static UniValue combinerawtransaction(const JSONRPCRequest& request) +static RPCHelpMan combinerawtransaction() { - RPCHelpMan{"combinerawtransaction", + return 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.", @@ -929,8 +941,8 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("combinerawtransaction", R"('["myhex1", "myhex2", "myhex3"]')") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ UniValue txs = request.params[0].get_array(); std::vector txVariants(txs.size()); @@ -992,11 +1004,13 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) } return EncodeHexTx(CTransaction(mergedTx)); +}, + }; } -static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) +static RPCHelpMan signrawtransactionwithkey() { - RPCHelpMan{"signrawtransactionwithkey", + return 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" @@ -1053,8 +1067,8 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) HelpExampleCli("signrawtransactionwithkey", "\"myhex\" \"[\\\"key1\\\",\\\"key2\\\"]\"") + HelpExampleRpc("signrawtransactionwithkey", "\"myhex\", \"[\\\"key1\\\",\\\"key2\\\"]\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VARR, UniValue::VSTR}, true); CMutableTransaction mtx; @@ -1087,11 +1101,13 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) UniValue result(UniValue::VOBJ); SignTransaction(mtx, &keystore, coins, request.params[3], result); return result; +}, + }; } -UniValue sendrawtransaction(const JSONRPCRequest& request) +RPCHelpMan sendrawtransaction() { - RPCHelpMan{"sendrawtransaction", "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n" + return RPCHelpMan{"sendrawtransaction", "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n" "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n" "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n" "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n" @@ -1118,8 +1134,8 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VSTR, UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() @@ -1150,11 +1166,13 @@ UniValue sendrawtransaction(const JSONRPCRequest& request) } return tx->GetHash().GetHex(); +}, + }; } -static UniValue testmempoolaccept(const JSONRPCRequest& request) +static RPCHelpMan testmempoolaccept() { - RPCHelpMan{"testmempoolaccept", + return RPCHelpMan{"testmempoolaccept", "\nReturns result of mempool acceptance tests indicating if raw transaction (serialized, hex-encoded) would be accepted by mempool.\n" "\nIf multiple transactions are passed in, parents must come before children and package policies apply: the transactions cannot conflict with any mempool transactions or each other.\n" "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n" @@ -1200,8 +1218,8 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VARR, UniValueType(), // VNUM or VSTR, checked inside AmountFromValue() @@ -1286,11 +1304,13 @@ static UniValue testmempoolaccept(const JSONRPCRequest& request) rpc_result.push_back(result_inner); } return rpc_result; +}, + }; } -UniValue decodepsbt(const JSONRPCRequest& request) +static RPCHelpMan decodepsbt() { - RPCHelpMan{"decodepsbt", + return RPCHelpMan{"decodepsbt", "\nReturn a JSON object representing the serialized, base64-encoded partially signed Dash transaction.\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"}, @@ -1375,8 +1395,8 @@ UniValue decodepsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("decodepsbt", "\"psbt\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); // Unserialize the transactions @@ -1537,11 +1557,13 @@ UniValue decodepsbt(const JSONRPCRequest& request) } return result; +}, + }; } -UniValue combinepsbt(const JSONRPCRequest& request) +static RPCHelpMan combinepsbt() { - RPCHelpMan{"combinepsbt", + return RPCHelpMan{"combinepsbt", "\nCombine multiple partially signed Dash transactions into one transaction.\n" "Implements the Combiner role.\n", { @@ -1557,8 +1579,8 @@ UniValue combinepsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("combinepsbt", R"('["mybase64_1", "mybase64_2", "mybase64_3"]')") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VARR}, true); // Unserialize the transactions @@ -1585,11 +1607,13 @@ UniValue combinepsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << merged_psbt; return EncodeBase64(ssTx); +}, + }; } -UniValue finalizepsbt(const JSONRPCRequest& request) +static RPCHelpMan finalizepsbt() { - RPCHelpMan{"finalizepsbt", + return 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 field filled for inputs that are complete.\n" @@ -1610,8 +1634,8 @@ UniValue finalizepsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("finalizepsbt", "\"psbt\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL}, true); // Unserialize the transactions @@ -1642,11 +1666,13 @@ UniValue finalizepsbt(const JSONRPCRequest& request) result.pushKV("complete", complete); return result; +}, + }; } -UniValue createpsbt(const JSONRPCRequest& request) +static RPCHelpMan createpsbt() { - RPCHelpMan{"createpsbt", + return RPCHelpMan{"createpsbt", "\nCreates a transaction in the Partially Signed Transaction format.\n" "Implements the Creator role.\n", { @@ -1686,8 +1712,8 @@ UniValue createpsbt(const JSONRPCRequest& request) RPCExamples{ HelpExampleCli("createpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, { UniValue::VARR, @@ -1713,11 +1739,13 @@ UniValue createpsbt(const JSONRPCRequest& request) ssTx << psbtx; return EncodeBase64(ssTx); +}, + }; } -UniValue converttopsbt(const JSONRPCRequest& request) +static RPCHelpMan converttopsbt() { - RPCHelpMan{"converttopsbt", + return 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", { @@ -1734,8 +1762,8 @@ UniValue converttopsbt(const JSONRPCRequest& request) "\nConvert the transaction to a PSBT\n" + HelpExampleCli("converttopsbt", "\"rawtransaction\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VBOOL}, true); // parse hex string from parameter @@ -1768,12 +1796,13 @@ UniValue converttopsbt(const JSONRPCRequest& request) ssTx << psbtx; return EncodeBase64(ssTx); +}, + }; } -UniValue utxoupdatepsbt(const JSONRPCRequest& request) +static RPCHelpMan utxoupdatepsbt() { - - RPCHelpMan{"utxoupdatepsbt", + return RPCHelpMan{"utxoupdatepsbt", "\nUpdates a PSBT with data from output descriptors, UTXOs retrieved from the UTXO set or the mempool.\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"}, @@ -1790,7 +1819,9 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) }, RPCExamples { HelpExampleCli("utxoupdatepsbt", "\"psbt\"") - }}.Check(request); + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR}, true); // Unserialize the transactions @@ -1852,11 +1883,13 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; return EncodeBase64(ssTx); +}, + }; } -UniValue joinpsbts(const JSONRPCRequest& request) +static RPCHelpMan joinpsbts() { - RPCHelpMan{"joinpsbts", + return RPCHelpMan{"joinpsbts", "\nJoins multiple distinct PSBTs with different inputs and outputs into one PSBT with inputs and outputs from all of the PSBTs\n" "No input in any of the PSBTs can be in more than one of the PSBTs.\n", { @@ -1870,8 +1903,9 @@ UniValue joinpsbts(const JSONRPCRequest& request) }, RPCExamples { HelpExampleCli("joinpsbts", "\"psbt\"") - }}.Check(request); - + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VARR}, true); // Unserialize the transactions @@ -1923,11 +1957,13 @@ UniValue joinpsbts(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << merged_psbt; return EncodeBase64(ssTx); +}, + }; } -UniValue analyzepsbt(const JSONRPCRequest& request) +static RPCHelpMan analyzepsbt() { - RPCHelpMan{"analyzepsbt", + return RPCHelpMan{"analyzepsbt", "\nAnalyzes and provides information about the current status of a PSBT and its inputs\n", { {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "A base64 string of a PSBT"} @@ -1965,8 +2001,9 @@ UniValue analyzepsbt(const JSONRPCRequest& request) }, RPCExamples { HelpExampleCli("analyzepsbt", "\"psbt\"") - }}.Check(request); - + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ RPCTypeCheck(request.params, {UniValue::VSTR}); // Unserialize the transaction @@ -2027,6 +2064,8 @@ UniValue analyzepsbt(const JSONRPCRequest& request) } return result; +}, + }; } void RegisterRawTransactionRPCCommands(CRPCTable &t) From af9eb81e56b2dfaa991ca7ab01bd37ef0e1394ac Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 26 Feb 2024 22:38:48 +0700 Subject: [PATCH 07/12] fix: wrong name of arguments for RPC --- src/rpc/blockchain.cpp | 4 ++-- src/rpc/client.cpp | 2 +- src/rpc/rawtransaction.cpp | 2 +- test/functional/rpc_rawtransaction.py | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index d457baf923a2c..e4a37197bff74 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -964,7 +964,7 @@ static RPCHelpMan getblockheaders() "\nIf verbose is false, each item is a string that is serialized, hex-encoded data for a single blockheader.\n" "If verbose is true, each item is an Object with information about a single blockheader.\n", { - {"hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, {"count", RPCArg::Type::NUM, /* default */ strprintf("%s", MAX_HEADERS_RESULTS), ""}, {"verbose", RPCArg::Type::BOOL, /* default */ "true", "true for a json object, false for the hex-encoded data"}, }, @@ -1100,7 +1100,7 @@ static RPCHelpMan getmerkleblocks() "\nReturns an array of hex-encoded merkleblocks for blocks starting from which match .\n", { {"filter", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded bloom filter"}, - {"hash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, + {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"}, {"count", RPCArg::Type::NUM, /* default */ strprintf("%s", MAX_HEADERS_RESULTS), ""}, }, RPCResult{ diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index c2c9479dee9db..3e0f501574585 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -109,7 +109,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "gettransaction", 1, "include_watchonly" }, { "gettransaction", 2, "verbose" }, { "getrawtransaction", 1, "verbose" }, - { "getrawtransactionmulti", 0, "txid_map" }, + { "getrawtransactionmulti", 0, "transactions" }, { "getrawtransactionmulti", 1, "verbose" }, { "gettxchainlocks", 0, "txids" }, { "createrawtransaction", 0, "inputs" }, diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 142d89677a6c1..08f759ca98ffd 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -2076,7 +2076,7 @@ static const CRPCCommand commands[] = // --------------------- ------------------------ ----------------------- ---------- { "rawtransactions", "getassetunlockstatuses", &getassetunlockstatuses, {"indexes","height"} }, { "rawtransactions", "getrawtransaction", &getrawtransaction, {"txid","verbose","blockhash"} }, - { "rawtransactions", "getrawtransactionmulti", &getrawtransactionmulti, {"txid_map","verbose"} }, + { "rawtransactions", "getrawtransactionmulti", &getrawtransactionmulti, {"transactions","verbose"} }, { "rawtransactions", "gettxchainlocks", &gettxchainlocks, {"txids"} }, { "rawtransactions", "createrawtransaction", &createrawtransaction, {"inputs","outputs","locktime"} }, { "rawtransactions", "decoderawtransaction", &decoderawtransaction, {"hexstring"} }, diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index c32a0c2e010ff..2e3edf3b5ef2f 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -339,7 +339,7 @@ def run_test(self): # 5. valid parameters - supply txid and True for non-verbose assert_equal(self.nodes[0].getrawtransaction(txId, True)["hex"], rawTxSigned['hex']) - assert_equal(self.nodes[0].getrawtransactionmulti({"0":[txId]}, True)[txId]['hex'], rawTxSigned['hex']) + assert_equal(self.nodes[0].getrawtransactionmulti(verbose=True, transactions={"0":[txId]})[txId]['hex'], rawTxSigned['hex']) # 6. invalid parameters - supply txid and string "Flase" assert_raises_rpc_error(-1, "not a boolean", self.nodes[0].getrawtransaction, txId, "Flase") From 0e1a31159f20de60bd8849759eee2eb24e916468 Mon Sep 17 00:00:00 2001 From: MarcoFalke Date: Wed, 23 Sep 2020 20:10:35 +0200 Subject: [PATCH 08/12] Merge #19994: Assert that RPCArg names are equal to CRPCCommand ones (net, rpcwallet) fa14f57fbc3c1fa2b9eea5df687f0fb36d452bd5 Assert that RPCArg names are equal to CRPCCommand ones (net, rpcwallet) (MarcoFalke) Pull request description: This is the last part split out from #18531 to just touch some RPC methods. Description from the main pr: ### Motivation RPCArg names in the rpc help are currently only used for documentation. However, in the future they could be used to teach the server the named arguments. Named arguments are currently registered by the `CRPCCommand`s and duplicate the RPCArg names from the documentation. This redundancy is fragile, and has lead to errors in the past (despite having linters to catch those kind of errors). See section "bugs found" for a list of bugs that have been found as a result of the changes here. ### Changes The changes here add an assert in the `CRPCCommand` constructor that the RPCArg names are identical to the ones in the `CRPCCommand`. ### Future work > Here or follow up, makes sense to also assert type of returned UniValue? Sure, but let's not get ahead of ourselves. I am going to submit any further works as follow-ups, including: * Removing the CRPCCommand arguments, now that they are asserted to be equal and thus redundant * Removing all python regex linters on the args, now that RPCMan can be used to generate any output, including the cli.cpp table * Auto-formatting and sanity checking the RPCExamples with RPCMan * Checking passed-in json in self-check. Removing redundant checks * Checking returned json against documentation to avoid regressions or false documentation * Compile the RPC documentation at compile-time to ensure it doesn't change at runtime and is completely static ### Bugs found * The assert identified issue #18607 * The changes itself fixed bug #19250 ACKs for top commit: fjahr: tACK fa14f57fbc3c1fa2b9eea5df687f0fb36d452bd5 ryanofsky: Code review ACK fa14f57fbc3c1fa2b9eea5df687f0fb36d452bd5. Just straightforward replacements except code moved in `addnode`, and displatching updated in `bumpfee_helper` Tree-SHA512: e07af150f1d95a88e558256ce197a6b7dc6cd722a6d6c13c75d944c49c2e2441f8b8237e9f94b03db69fa18f9bda627b0781d5e1da70bf5415e09b38728a8cb1 --- src/rpc/evo.cpp | 2 +- src/rpc/net.cpp | 145 +++++--- src/wallet/rpcdump.cpp | 1 - src/wallet/rpcwallet.cpp | 556 +++++++++++++++++++------------ src/wallet/rpcwallet.h | 8 +- src/wallet/test/wallet_tests.cpp | 22 +- 6 files changed, 444 insertions(+), 290 deletions(-) diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index c82e2d1b0e2b4..69b19c9c6524d 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -341,7 +341,7 @@ static std::string SignAndSendSpecialTx(const JSONRPCRequest& request, const Cha JSONRPCRequest signRequest(request); signRequest.params.setArray(); signRequest.params.push_back(HexStr(ds)); - UniValue signResult = signrawtransactionwithwallet(signRequest); + UniValue signResult = signrawtransactionwithwallet().HandleRequest(signRequest); if (!fSubmit) { return signResult["hex"].get_str(); diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 0e101cdca5af6..6de82e6a7c444 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -39,9 +39,9 @@ const std::vector CONNECTION_TYPE_DOC{ "feeler (short-lived automatic connection for testing addresses)" }; -static UniValue getconnectioncount(const JSONRPCRequest& request) +static RPCHelpMan getconnectioncount() { - RPCHelpMan{"getconnectioncount", + return RPCHelpMan{"getconnectioncount", "\nReturns the number of connections to other nodes.\n", {}, RPCResult{ @@ -51,18 +51,20 @@ static UniValue getconnectioncount(const JSONRPCRequest& request) HelpExampleCli("getconnectioncount", "") + HelpExampleRpc("getconnectioncount", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); return (int)node.connman->GetNodeCount(CConnman::CONNECTIONS_ALL); +}, + }; } -static UniValue ping(const JSONRPCRequest& request) +static RPCHelpMan ping() { - RPCHelpMan{"ping", + return 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", @@ -72,8 +74,8 @@ static UniValue ping(const JSONRPCRequest& request) HelpExampleCli("ping", "") + HelpExampleRpc("ping", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -83,11 +85,13 @@ static UniValue ping(const JSONRPCRequest& request) pnode->fPingQueued = true; }); return NullUniValue; +}, + }; } -static UniValue getpeerinfo(const JSONRPCRequest& request) +static RPCHelpMan getpeerinfo() { - RPCHelpMan{"getpeerinfo", + return RPCHelpMan{"getpeerinfo", "\nReturns data about each connected network node as a json array of objects.\n", {}, RPCResult{ @@ -160,8 +164,8 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) HelpExampleCli("getpeerinfo", "") + HelpExampleRpc("getpeerinfo", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.connman || !node.peerman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -259,14 +263,13 @@ static UniValue getpeerinfo(const JSONRPCRequest& request) } return ret; +}, + }; } -static UniValue addnode(const JSONRPCRequest& request) +static RPCHelpMan addnode() { - std::string strCommand; - if (!request.params[1].isNull()) - strCommand = request.params[1].get_str(); - RPCHelpMan{"addnode", + return 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" @@ -280,7 +283,11 @@ static UniValue addnode(const JSONRPCRequest& request) HelpExampleCli("addnode", "\"192.168.0.6:9999\" \"onetry\"") + HelpExampleRpc("addnode", "\"192.168.0.6:9999\", \"onetry\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + std::string strCommand; + if (!request.params[1].isNull()) + strCommand = request.params[1].get_str(); const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.connman) @@ -307,11 +314,13 @@ static UniValue addnode(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue disconnectnode(const JSONRPCRequest& request) +static RPCHelpMan disconnectnode() { - RPCHelpMan{"disconnectnode", + return 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", @@ -326,7 +335,8 @@ static UniValue disconnectnode(const JSONRPCRequest& request) + HelpExampleRpc("disconnectnode", "\"192.168.0.6:9999\"") + HelpExampleRpc("disconnectnode", "\"\", 1") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.connman) @@ -352,11 +362,13 @@ static UniValue disconnectnode(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } -static UniValue getaddednodeinfo(const JSONRPCRequest& request) +static RPCHelpMan getaddednodeinfo() { - RPCHelpMan{"getaddednodeinfo", + return RPCHelpMan{"getaddednodeinfo", "\nReturns information about the given added node, or all added nodes\n" "(note that onetry addnodes are not listed here)\n", { @@ -384,7 +396,8 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) HelpExampleCli("getaddednodeinfo", "\"192.168.0.201\"") + HelpExampleRpc("getaddednodeinfo", "\"192.168.0.201\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.connman) @@ -424,11 +437,13 @@ static UniValue getaddednodeinfo(const JSONRPCRequest& request) } return ret; +}, + }; } -static UniValue getnettotals(const JSONRPCRequest& request) +static RPCHelpMan getnettotals() { - RPCHelpMan{"getnettotals", + return RPCHelpMan{"getnettotals", "\nReturns information about network traffic, including bytes in, bytes out,\n" "and current time.\n", {}, @@ -453,7 +468,8 @@ static UniValue getnettotals(const JSONRPCRequest& request) HelpExampleCli("getnettotals", "") + HelpExampleRpc("getnettotals", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.connman) throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -472,6 +488,8 @@ static UniValue getnettotals(const JSONRPCRequest& request) outboundLimit.pushKV("time_left_in_cycle", count_seconds(node.connman->GetMaxOutboundTimeLeftInCycle())); obj.pushKV("uploadtarget", outboundLimit); return obj; +}, + }; } static UniValue GetNetworksInfo() @@ -493,9 +511,9 @@ static UniValue GetNetworksInfo() return networks; } -static UniValue getnetworkinfo(const JSONRPCRequest& request) +static RPCHelpMan getnetworkinfo() { - RPCHelpMan{"getnetworkinfo", + return RPCHelpMan{"getnetworkinfo", "Returns an object containing various state info regarding P2P networking.\n", {}, RPCResult{ @@ -549,8 +567,8 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) HelpExampleCli("getnetworkinfo", "") + HelpExampleRpc("getnetworkinfo", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ LOCK(cs_main); UniValue obj(UniValue::VOBJ); obj.pushKV("version", CLIENT_VERSION); @@ -612,11 +630,13 @@ static UniValue getnetworkinfo(const JSONRPCRequest& request) obj.pushKV("localaddresses", localAddresses); obj.pushKV("warnings", GetWarnings(false).original); return obj; +}, + }; } -static UniValue setban(const JSONRPCRequest& request) +static RPCHelpMan setban() { - const RPCHelpMan help{"setban", + return RPCHelpMan{"setban", "\nAttempts to add or remove an IP/Subnet from the banned list.\n", { {"subnet", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP/Subnet (see getpeerinfo for nodes IP) with an optional netmask (default is /32 = single IP)"}, @@ -630,7 +650,8 @@ static UniValue setban(const JSONRPCRequest& request) + HelpExampleCli("setban", "\"192.168.0.0/24\" \"add\"") + HelpExampleRpc("setban", "\"192.168.0.6\", \"add\", 86400") }, - }; + [&](const RPCHelpMan& help, const JSONRPCRequest& request) -> UniValue +{ std::string strCommand; if (!request.params[1].isNull()) strCommand = request.params[1].get_str(); @@ -693,11 +714,13 @@ static UniValue setban(const JSONRPCRequest& request) } } return NullUniValue; +}, + }; } -static UniValue listbanned(const JSONRPCRequest& request) +static RPCHelpMan listbanned() { - RPCHelpMan{"listbanned", + return RPCHelpMan{"listbanned", "\nList all manually banned IPs/Subnets.\n", {}, RPCResult{RPCResult::Type::ARR, "", "", @@ -713,7 +736,8 @@ static UniValue listbanned(const JSONRPCRequest& request) HelpExampleCli("listbanned", "") + HelpExampleRpc("listbanned", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if(!node.banman) { @@ -736,11 +760,13 @@ static UniValue listbanned(const JSONRPCRequest& request) } return bannedAddresses; +}, + }; } -static UniValue clearbanned(const JSONRPCRequest& request) +static RPCHelpMan clearbanned() { - RPCHelpMan{"clearbanned", + return RPCHelpMan{"clearbanned", "\nClear all banned IPs.\n", {}, RPCResult{RPCResult::Type::NONE, "", ""}, @@ -748,7 +774,8 @@ static UniValue clearbanned(const JSONRPCRequest& request) HelpExampleCli("clearbanned", "") + HelpExampleRpc("clearbanned", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); @@ -757,11 +784,13 @@ static UniValue clearbanned(const JSONRPCRequest& request) node.banman->ClearBanned(); return NullUniValue; +}, + }; } -static UniValue cleardiscouraged(const JSONRPCRequest& request) +static RPCHelpMan cleardiscouraged() { - RPCHelpMan{"cleardiscouraged", + return RPCHelpMan{"cleardiscouraged", "\nClear all discouraged nodes.\n", {}, RPCResult{RPCResult::Type::NONE, "", ""}, @@ -769,7 +798,8 @@ static UniValue cleardiscouraged(const JSONRPCRequest& request) HelpExampleCli("cleardiscouraged", "") + HelpExampleRpc("cleardiscouraged", "") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.banman) { throw JSONRPCError(RPC_DATABASE_ERROR, "Error: Ban database not loaded"); @@ -778,18 +808,21 @@ static UniValue cleardiscouraged(const JSONRPCRequest& request) node.banman->ClearDiscouraged(); return NullUniValue; +}, + }; } -static UniValue setnetworkactive(const JSONRPCRequest& request) +static RPCHelpMan setnetworkactive() { - RPCHelpMan{"setnetworkactive", + return RPCHelpMan{"setnetworkactive", "\nDisable/enable all p2p network activity.\n", { {"state", RPCArg::Type::BOOL, RPCArg::Optional::NO, "true to enable networking, false to disable"}, }, RPCResult{RPCResult::Type::BOOL, "", "The value that was passed in"}, RPCExamples{""}, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.connman) { @@ -799,11 +832,13 @@ static UniValue setnetworkactive(const JSONRPCRequest& request) node.connman->SetNetworkActive(request.params[0].get_bool()); return node.connman->GetNetworkActive(); +}, + }; } -static UniValue getnodeaddresses(const JSONRPCRequest& request) +static RPCHelpMan getnodeaddresses() { - RPCHelpMan{"getnodeaddresses", + return RPCHelpMan{"getnodeaddresses", "\nReturn known addresses which can potentially be used to find new nodes in the network\n", { {"count", RPCArg::Type::NUM, /* default */ "1", "The maximum number of addresses to return. Specify 0 to return all known addresses."}, @@ -824,7 +859,8 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) HelpExampleCli("getnodeaddresses", "8") + HelpExampleRpc("getnodeaddresses", "8") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.connman) { throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled"); @@ -850,11 +886,13 @@ static UniValue getnodeaddresses(const JSONRPCRequest& request) ret.push_back(obj); } return ret; +}, + }; } -static UniValue addpeeraddress(const JSONRPCRequest& request) +static RPCHelpMan addpeeraddress() { - RPCHelpMan{"addpeeraddress", + return RPCHelpMan{"addpeeraddress", "\nAdd the address of a potential peer to the address manager. This RPC is for testing only.\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address of the peer"}, @@ -870,7 +908,8 @@ static UniValue addpeeraddress(const JSONRPCRequest& request) HelpExampleCli("addpeeraddress", "\"1.2.3.4\" 9999") + HelpExampleRpc("addpeeraddress", "\"1.2.3.4\", 9999") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ const NodeContext& node = EnsureAnyNodeContext(request.context); if (!node.addrman) { @@ -898,6 +937,8 @@ static UniValue addpeeraddress(const JSONRPCRequest& request) obj.pushKV("success", true); return obj; +}, + }; } void RegisterNetRPCCommands(CRPCTable &t) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 69ebc9459e7dd..9ca319641b5f4 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -1835,7 +1835,6 @@ RPCHelpMan importdescriptors() { }, [&](const RPCHelpMan& self, const JSONRPCRequest& main_request) -> UniValue { - // Acquire the wallet std::shared_ptr const wallet = GetWalletForJSONRPCRequest(main_request); if (!wallet) return NullUniValue; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 24ab61710fe59..fd134fc7894f3 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -236,9 +236,9 @@ static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const U } } -UniValue getnewaddress(const JSONRPCRequest& request) +RPCHelpMan getnewaddress() { - RPCHelpMan{"getnewaddress", + return RPCHelpMan{"getnewaddress", "\nReturns a new Dash 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", @@ -252,8 +252,8 @@ UniValue getnewaddress(const JSONRPCRequest& request) HelpExampleCli("getnewaddress", "") + HelpExampleRpc("getnewaddress", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -275,11 +275,13 @@ UniValue getnewaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error); } return EncodeDestination(dest); +}, + }; } -UniValue getrawchangeaddress(const JSONRPCRequest& request) +RPCHelpMan getrawchangeaddress() { - RPCHelpMan{"getrawchangeaddress", + return RPCHelpMan{"getrawchangeaddress", "\nReturns a new Dash address, for receiving change.\n" "This is for use with raw transactions, NOT normal use.\n", {}, @@ -290,8 +292,8 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) HelpExampleCli("getrawchangeaddress", "") + HelpExampleRpc("getrawchangeaddress", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -308,12 +310,14 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request) throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, error); } return EncodeDestination(dest); +}, + }; } -static UniValue setlabel(const JSONRPCRequest& request) +static RPCHelpMan setlabel() { - RPCHelpMan{"setlabel", + return RPCHelpMan{"setlabel", "\nSets the label associated with the given address.\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Dash address to be associated with a label."}, @@ -324,8 +328,8 @@ static UniValue setlabel(const JSONRPCRequest& request) HelpExampleCli("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\" \"tabby\"") + HelpExampleRpc("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\", \"tabby\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -346,6 +350,8 @@ static UniValue setlabel(const JSONRPCRequest& request) } return NullUniValue; +}, + }; } @@ -384,13 +390,9 @@ static CTransactionRef SendMoney(CWallet* const pwallet, const CTxDestination& a return tx; } -static UniValue sendtoaddress(const JSONRPCRequest& request) +static RPCHelpMan sendtoaddress() { - std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); - if (!wallet) return NullUniValue; - CWallet* const pwallet = wallet.get(); - - RPCHelpMan{"sendtoaddress", + return RPCHelpMan{"sendtoaddress", "\nSend an amount to a given address." + HELP_REQUIRING_PASSPHRASE, { @@ -422,7 +424,11 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"\" \"\" false true 2 " + (CURRENCY_ATOM + "/B")) + HelpExampleRpc("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 0.1, \"donation\", \"seans outpost\"") }, - }.Check(request); + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ + std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); + if (!wallet) return NullUniValue; + CWallet* const pwallet = wallet.get(); // 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 @@ -469,21 +475,31 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue)); return tx->GetHash().GetHex(); +}, + }; } // DEPRECATED -static UniValue instantsendtoaddress(const JSONRPCRequest& request) +static RPCHelpMan instantsendtoaddress() +{ + return RPCHelpMan{"instantsendtoaddress", + "instantsendtoaddress is deprecated and sendtoaddress should be used instead", + {}, + RPCResult{ + RPCResult::Type::STR_HEX, "txid", "The transaction id." + }, + RPCExamples{""}, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - if (request.fHelp) { - throw std::runtime_error("instantsendtoaddress is deprecated and sendtoaddress should be used instead"); - } LogPrintf("WARNING: Used deprecated RPC method 'instantsendtoaddress'! Please use 'sendtoaddress' instead\n"); - return sendtoaddress(request); + return sendtoaddress().HandleRequest(request); +}, + }; } -static UniValue listaddressgroupings(const JSONRPCRequest& request) +static RPCHelpMan listaddressgroupings() { - RPCHelpMan{"listaddressgroupings", + return 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", @@ -505,8 +521,8 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) HelpExampleCli("listaddressgroupings", "") + HelpExampleRpc("listaddressgroupings", "") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; const CWallet* const pwallet = wallet.get(); @@ -537,11 +553,13 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) jsonGroupings.push_back(jsonGrouping); } return jsonGroupings; +}, + }; } -static UniValue listaddressbalances(const JSONRPCRequest& request) +static RPCHelpMan listaddressbalances() { - RPCHelpMan{"listaddressbalances", + return RPCHelpMan{"listaddressbalances", "\nLists addresses of this wallet and their balances\n", { {"minamount", RPCArg::Type::NUM, /* default */ "0", "Minimum balance in " + CURRENCY_UNIT + " an address should have to be shown in the list"}, @@ -557,9 +575,9 @@ static UniValue listaddressbalances(const JSONRPCRequest& request) + HelpExampleCli("listaddressbalances", "10") + HelpExampleRpc("listaddressbalances", "") + HelpExampleRpc("listaddressbalances", "10") - } - }.Check(request); - + }, + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; const CWallet* const pwallet = wallet.get(); @@ -580,11 +598,13 @@ static UniValue listaddressbalances(const JSONRPCRequest& request) jsonBalances.pushKV(EncodeDestination(balance.first), ValueFromAmount(balance.second)); return jsonBalances; +}, + }; } -static UniValue signmessage(const JSONRPCRequest& request) +static RPCHelpMan signmessage() { - RPCHelpMan{"signmessage", + return RPCHelpMan{"signmessage", "\nSign a message with the private key of an address" + HELP_REQUIRING_PASSPHRASE, { @@ -604,8 +624,8 @@ static UniValue signmessage(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("signmessage", "\"" + EXAMPLE_ADDRESS[0] + "\", \"my message\"") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; CWallet* const pwallet = wallet.get(); @@ -636,6 +656,8 @@ static UniValue signmessage(const JSONRPCRequest& request) } return signature; +}, + }; } static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) @@ -686,9 +708,9 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b } -static UniValue getreceivedbyaddress(const JSONRPCRequest& request) +static RPCHelpMan getreceivedbyaddress() { - RPCHelpMan{"getreceivedbyaddress", + return RPCHelpMan{"getreceivedbyaddress", "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Dash address for transactions."}, @@ -708,8 +730,8 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) "\nAs a JSON-RPC call\n" + HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6") }, - }.Check(request); - + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue +{ std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); if (!wallet) return NullUniValue; const CWallet* const pwallet = wallet.get(); @@ -721,12 +743,14 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) LOCK(pwallet->cs_wallet); return ValueFromAmount(GetReceived(*pwallet, request.params, /* by_label */ false)); +}, + }; } -static UniValue getreceivedbylabel(const JSONRPCRequest& request) +static RPCHelpMan getreceivedbylabel() { - RPCHelpMan{"getreceivedbylabel", + return RPCHelpMan{"getreceivedbylabel", "\nReturns the total amount received by addresses with