diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 3784d09754..383dc6f8e2 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -1,588 +1,593 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_MALLOC_INFO #include #endif static UniValue validateaddress(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 1) { - throw std::runtime_error( - RPCHelpMan{ - "validateaddress", - "\nReturn information about the given bitcoin address.\n", - { - {"address", RPCArg::Type::STR, /* opt */ false, - /* default_val */ "", "The bitcoin address to validate"}, - }} - .ToString() + - "\nResult:\n" - "{\n" - " \"isvalid\" : true|false, (boolean) If the address is " - "valid or not. If not, this is the only property returned.\n" - " \"address\" : \"address\", (string) The bitcoin address " - "validated\n" - " \"scriptPubKey\" : \"hex\", (string) The hex-encoded " - "scriptPubKey generated by the address\n" - " \"isscript\" : true|false, (boolean) If the key is a " - "script\n" - "}\n" - "\nExamples:\n" + - HelpExampleCli("validateaddress", - "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + - HelpExampleRpc("validateaddress", - "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")); + throw std::runtime_error(RPCHelpMan{ + "validateaddress", + "\nReturn information about the given bitcoin address.\n", + { + {"address", RPCArg::Type::STR, /* opt */ false, + /* default_val */ "", "The bitcoin address to validate"}, + }, + RPCResult{ + "{\n" + " \"isvalid\" : true|false, (boolean) If the address is " + "valid or not. If not, this is the only property returned.\n" + " \"address\" : \"address\", (string) The bitcoin " + "address validated\n" + " \"scriptPubKey\" : \"hex\", (string) The hex-encoded " + "scriptPubKey generated by the address\n" + " \"isscript\" : true|false, (boolean) If the key is a " + "script\n" + "}\n"}, + RPCExamples{ + HelpExampleCli("validateaddress", + "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"") + + HelpExampleRpc("validateaddress", + "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")}, + } + .ToStringWithResultsAndExamples()); } CTxDestination dest = DecodeDestination(request.params[0].get_str(), config.GetChainParams()); bool isValid = IsValidDestination(dest); UniValue ret(UniValue::VOBJ); ret.pushKV("isvalid", isValid); if (isValid) { if (ret["address"].isNull()) { std::string currentAddress = EncodeDestination(dest, config); ret.pushKV("address", currentAddress); CScript scriptPubKey = GetScriptForDestination(dest); ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())); UniValue detail = DescribeAddress(dest); ret.pushKVs(detail); } } return ret; } static UniValue createmultisig(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() < 2 || request.params.size() > 2) { std::string msg = 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", { {"nrequired", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "The number of required signatures out of the n keys."}, {"keys", RPCArg::Type::ARR, /* opt */ false, /* default_val */ "", "A json array of hex-encoded public keys.", { {"key", RPCArg::Type::STR_HEX, /* opt */ false, /* default_val */ "", "The hex-encoded public key"}, }}, - }} - .ToString() + - "\nResult:\n" - "{\n" - " \"address\":\"multisigaddress\", (string) The value of the new " - "multisig address.\n" - " \"redeemScript\":\"script\" (string) The string value of " - "the hex-encoded redemption script.\n" - "}\n" - - "\nExamples:\n" - "\nCreate a multisig address from 2 public keys\n" + - HelpExampleCli("createmultisig", - "2 " - "\"[" - "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" - "42cf11ae157a7ace5fd\\\"," - "\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" - "7e107ef3f6aa5a61626\\\"]\"") + - "\nAs a JSON-RPC call\n" + - HelpExampleRpc("createmultisig", - "2, " - "\"[" - "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" - "42cf11ae157a7ace5fd\\\"," - "\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" - "7e107ef3f6aa5a61626\\\"]\""); + }, + RPCResult{"{\n" + " \"address\":\"multisigaddress\", (string) The " + "value of the new multisig address.\n" + " \"redeemScript\":\"script\" (string) The " + "string value of the hex-encoded redemption script.\n" + "}\n"}, + RPCExamples{ + "\nCreate a multisig address from 2 public keys\n" + + HelpExampleCli( + "createmultisig", + "2 " + "\"[" + "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" + "42cf11ae157a7ace5fd\\\"," + "\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" + "7e107ef3f6aa5a61626\\\"]\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc( + "createmultisig", + "2, " + "\"[" + "\\\"03789ed0bb717d88f7d321a368d905e7430207ebbd82bd3" + "42cf11ae157a7ace5fd\\\"," + "\\\"03dbc6764b8884a92e871274b87583e6d5c2a58819473e1" + "7e107ef3f6aa5a61626\\\"]\"")}, + } + .ToStringWithResultsAndExamples(); throw std::runtime_error(msg); } int required = request.params[0].get_int(); // Get the public keys const UniValue &keys = request.params[1].get_array(); std::vector pubkeys; for (size_t i = 0; i < keys.size(); ++i) { if ((keys[i].get_str().length() == 2 * CPubKey::COMPRESSED_PUBLIC_KEY_SIZE || keys[i].get_str().length() == 2 * CPubKey::PUBLIC_KEY_SIZE) && IsHex(keys[i].get_str())) { pubkeys.push_back(HexToPubKey(keys[i].get_str())); } else { throw JSONRPCError( RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid public key: %s\n", keys[i].get_str())); } } // Get the output type OutputType output_type = OutputType::LEGACY; // Construct using pay-to-script-hash: const CScript inner = CreateMultisigRedeemscript(required, pubkeys); CBasicKeyStore keystore; const CTxDestination dest = AddAndGetDestinationForScript(keystore, inner, output_type); UniValue result(UniValue::VOBJ); result.pushKV("address", EncodeDestination(dest, config)); result.pushKV("redeemScript", HexStr(inner.begin(), inner.end())); return result; } static UniValue verifymessage(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 3) { - throw std::runtime_error( - RPCHelpMan{ - "verifymessage", - "\nVerify a signed message\n", - { - {"address", RPCArg::Type::STR, /* opt */ false, - /* default_val */ "", - "The bitcoin address to use for the signature."}, - {"signature", RPCArg::Type::STR, /* opt */ false, - /* default_val */ "", - "The signature provided by the signer in base 64 encoding " - "(see signmessage)."}, - {"message", RPCArg::Type::STR, /* opt */ false, - /* default_val */ "", "The message that was signed."}, - }} - .ToString() + - "\nResult:\n" - "true|false (boolean) If the signature is verified or not.\n" - "\nExamples:\n" - "\nUnlock the wallet for 30 seconds\n" + - HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + - "\nCreate the signature\n" + - HelpExampleCli( - "signmessage", - "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + - "\nVerify the signature\n" + - HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" - "XX\" \"signature\" \"my " - "message\"") + - "\nAs a JSON-RPC call\n" + - HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" - "XX\", \"signature\", \"my " - "message\"")); + throw std::runtime_error(RPCHelpMan{ + "verifymessage", + "\nVerify a signed message\n", + { + {"address", RPCArg::Type::STR, /* opt */ false, + /* default_val */ "", + "The bitcoin address to use for the signature."}, + {"signature", RPCArg::Type::STR, /* opt */ false, + /* default_val */ "", + "The signature provided by the signer in base 64 encoding " + "(see signmessage)."}, + {"message", RPCArg::Type::STR, /* opt */ false, + /* default_val */ "", "The message that was signed."}, + }, + RPCResult{"true|false (boolean) If the signature is verified or " + "not.\n"}, + RPCExamples{ + "\nUnlock the wallet for 30 seconds\n" + + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") + + "\nCreate the signature\n" + + HelpExampleCli( + "signmessage", + "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") + + "\nVerify the signature\n" + + HelpExampleCli("verifymessage", + "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" + "XX\" \"signature\" \"my " + "message\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("verifymessage", + "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" + "XX\", \"signature\", \"my " + "message\"")}, + } + .ToStringWithResultsAndExamples()); } LOCK(cs_main); std::string strAddress = request.params[0].get_str(); std::string strSign = request.params[1].get_str(); std::string strMessage = request.params[2].get_str(); CTxDestination destination = DecodeDestination(strAddress, config.GetChainParams()); if (!IsValidDestination(destination)) { throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address"); } const CKeyID *keyID = boost::get(&destination); if (!keyID) { throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key"); } bool fInvalid = false; std::vector vchSig = DecodeBase64(strSign.c_str(), &fInvalid); if (fInvalid) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding"); } CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; CPubKey pubkey; if (!pubkey.RecoverCompact(ss.GetHash(), vchSig)) { return false; } return (pubkey.GetID() == *keyID); } static UniValue signmessagewithprivkey(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 2) { - throw std::runtime_error( - RPCHelpMan{"signmessagewithprivkey", - "\nSign a message with the private key of an address\n", - { - {"privkey", RPCArg::Type::STR, /* opt */ false, - /* default_val */ "", - "The private key to sign the message with."}, - {"message", RPCArg::Type::STR, /* opt */ false, - /* default_val */ "", - "The message to create a signature of."}, - }} - .ToString() + - "\nResult:\n" - "\"signature\" (string) The signature of the message " - "encoded in base 64\n" - "\nExamples:\n" - "\nCreate the signature\n" + - HelpExampleCli("signmessagewithprivkey", - "\"privkey\" \"my message\"") + - "\nVerify the signature\n" + - HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" - "XX\" \"signature\" \"my " - "message\"") + - "\nAs a JSON-RPC call\n" + - HelpExampleRpc("signmessagewithprivkey", - "\"privkey\", \"my message\"")); + throw std::runtime_error(RPCHelpMan{ + "signmessagewithprivkey", + "\nSign a message with the private key of an address\n", + { + {"privkey", RPCArg::Type::STR, /* opt */ false, + /* default_val */ "", + "The private key to sign the message with."}, + {"message", RPCArg::Type::STR, /* opt */ false, + /* default_val */ "", "The message to create a signature of."}, + }, + RPCResult{"\"signature\" (string) The signature of the " + "message encoded in base 64\n"}, + RPCExamples{"\nCreate the signature\n" + + HelpExampleCli("signmessagewithprivkey", + "\"privkey\" \"my message\"") + + "\nVerify the signature\n" + + HelpExampleCli("verifymessage", + "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4" + "XX\" \"signature\" \"my " + "message\"") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("signmessagewithprivkey", + "\"privkey\", \"my message\"")}, + } + .ToStringWithResultsAndExamples()); } std::string strPrivkey = request.params[0].get_str(); std::string strMessage = request.params[1].get_str(); CKey key = DecodeSecret(strPrivkey); if (!key.IsValid()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); } CHashWriter ss(SER_GETHASH, 0); ss << strMessageMagic; ss << strMessage; std::vector vchSig; if (!key.SignCompact(ss.GetHash(), vchSig)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed"); } return EncodeBase64(vchSig.data(), vchSig.size()); } static UniValue setmocktime(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() != 1) { throw std::runtime_error(RPCHelpMan{ "setmocktime", "\nSet the local time to given timestamp (-regtest only)\n", { {"timestamp", RPCArg::Type::NUM, /* opt */ false, /* default_val */ "", "Unix seconds-since-epoch timestamp\n" " Pass 0 to go back to using the system time."}, - }}.ToString()); + }, + RPCResults{}, + RPCExamples{""}, + } + .ToStringWithResultsAndExamples()); } if (!config.GetChainParams().MineBlocksOnDemand()) { throw std::runtime_error( "setmocktime for regression testing (-regtest mode) only"); } // For now, don't change mocktime if we're in the middle of validation, as // this could have an effect on mempool time-based eviction, as well as // IsInitialBlockDownload(). // TODO: figure out the right way to synchronize around mocktime, and // ensure all call sites of GetTime() are accessing this safely. LOCK(cs_main); RPCTypeCheck(request.params, {UniValue::VNUM}); SetMockTime(request.params[0].get_int64()); return NullUniValue; } static UniValue RPCLockedMemoryInfo() { LockedPool::Stats stats = LockedPoolManager::Instance().stats(); UniValue obj(UniValue::VOBJ); obj.pushKV("used", uint64_t(stats.used)); obj.pushKV("free", uint64_t(stats.free)); obj.pushKV("total", uint64_t(stats.total)); obj.pushKV("locked", uint64_t(stats.locked)); obj.pushKV("chunks_used", uint64_t(stats.chunks_used)); obj.pushKV("chunks_free", uint64_t(stats.chunks_free)); return obj; } #ifdef HAVE_MALLOC_INFO static std::string RPCMallocInfo() { char *ptr = nullptr; size_t size = 0; FILE *f = open_memstream(&ptr, &size); if (f) { malloc_info(0, f); fclose(f); if (ptr) { std::string rv(ptr, size); free(ptr); return rv; } } return ""; } #endif static UniValue getmemoryinfo(const Config &config, const JSONRPCRequest &request) { /* Please, avoid using the word "pool" here in the RPC interface or help, * as users will undoubtedly confuse it with the other "memory pool" */ if (request.fHelp || request.params.size() > 1) { - throw std::runtime_error( - RPCHelpMan{ - "getmemoryinfo", - "Returns an object containing information about memory " - "usage.\n", - { - {"mode", RPCArg::Type::STR, /* opt */ true, - /* default_val */ "", - "determines what kind of information is returned. This " - "argument is optional, the default mode is \"stats\".\n" - " - \"stats\" returns general statistics about memory " - "usage in the daemon.\n" - " - \"mallocinfo\" returns an XML string describing " - "low-level heap state (only available if compiled with " - "glibc 2.10+)."}, - }} - .ToString() + - "\nResult (mode \"stats\"):\n" - "{\n" - " \"locked\": { (json object) Information about " - "locked memory manager\n" - " \"used\": xxxxx, (numeric) Number of bytes used\n" - " \"free\": xxxxx, (numeric) Number of bytes available " - "in current arenas\n" - " \"total\": xxxxxxx, (numeric) Total number of bytes " - "managed\n" - " \"locked\": xxxxxx, (numeric) Amount of bytes that " - "succeeded locking. If this number is smaller than total, locking " - "pages failed at some point and key data could be swapped to " - "disk.\n" - " \"chunks_used\": xxxxx, (numeric) Number allocated chunks\n" - " \"chunks_free\": xxxxx, (numeric) Number unused chunks\n" - " }\n" - "}\n" - "\nResult (mode \"mallocinfo\"):\n" - "\"...\"\n" - "\nExamples:\n" + - HelpExampleCli("getmemoryinfo", "") + - HelpExampleRpc("getmemoryinfo", "")); + throw std::runtime_error(RPCHelpMan{ + "getmemoryinfo", + "Returns an object containing information about memory usage.\n", + { + {"mode", RPCArg::Type::STR, /* opt */ true, + /* default_val */ "", + "determines what kind of information is returned. This " + "argument is optional, the default mode is \"stats\".\n" + " - \"stats\" returns general statistics about memory usage " + "in the daemon.\n" + " - \"mallocinfo\" returns an XML string describing " + "low-level heap state (only available if compiled with glibc " + "2.10+)."}, + }, + { + RPCResult{"mode \"stats\"", + "{\n" + " \"locked\": { (json object) " + "Information about locked memory manager\n" + " \"used\": xxxxx, (numeric) Number of " + "bytes used\n" + " \"free\": xxxxx, (numeric) Number of " + "bytes available in current arenas\n" + " \"total\": xxxxxxx, (numeric) Total " + "number of bytes managed\n" + " \"locked\": xxxxxx, (numeric) Amount of " + "bytes that succeeded locking. If this number is " + "smaller than total, locking pages failed at some " + "point and key data could be swapped to disk.\n" + " \"chunks_used\": xxxxx, (numeric) Number " + "allocated chunks\n" + " \"chunks_free\": xxxxx, (numeric) Number " + "unused chunks\n" + " }\n" + "}\n"}, + RPCResult{"mode \"mallocinfo\"", + "\"...\"\n"}, + }, + RPCExamples{HelpExampleCli("getmemoryinfo", "") + + HelpExampleRpc("getmemoryinfo", "")}, + } + .ToStringWithResultsAndExamples()); } std::string mode = request.params[0].isNull() ? "stats" : request.params[0].get_str(); if (mode == "stats") { UniValue obj(UniValue::VOBJ); obj.pushKV("locked", RPCLockedMemoryInfo()); return obj; } else if (mode == "mallocinfo") { #ifdef HAVE_MALLOC_INFO return RPCMallocInfo(); #else throw JSONRPCError( RPC_INVALID_PARAMETER, "mallocinfo is only available when compiled with glibc 2.10+"); #endif } else { throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown mode " + mode); } } static void EnableOrDisableLogCategories(UniValue cats, bool enable) { cats = cats.get_array(); for (size_t i = 0; i < cats.size(); ++i) { std::string cat = cats[i].get_str(); bool success; if (enable) { success = LogInstance().EnableCategory(cat); } else { success = LogInstance().DisableCategory(cat); } if (!success) { throw JSONRPCError(RPC_INVALID_PARAMETER, "unknown logging category " + cat); } } } static UniValue logging(const Config &config, const JSONRPCRequest &request) { if (request.fHelp || request.params.size() > 2) { - throw std::runtime_error( - 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" - "The arguments are evaluated in order \"include\", " - "\"exclude\".\n" - "If an item is both included and excluded, it will thus end up " - "being excluded.\n" - "The valid logging categories are: " + - ListLogCategories() + - "\n" - "In addition, the following are available as category " - "names with special meanings:\n" - " - \"all\", \"1\" : represent all logging categories.\n" - " - \"none\", \"0\" : even if other logging categories " - "are specified, ignore all of them.\n", - { - {"include", - RPCArg::Type::ARR, - /* opt */ true, - /* default_val */ "", - "A json array of categories to add debug logging", - { - {"include_category", RPCArg::Type::STR, - /* opt */ false, /* default_val */ "", - "the valid logging category"}, - }}, - {"exclude", - RPCArg::Type::ARR, - /* opt */ true, - /* default_val */ "", - "A json array of categories to remove debug logging", - { - {"exclude_category", RPCArg::Type::STR, - /* opt */ false, /* default_val */ "", - "the valid logging category"}, - }}, - }} - .ToString() + - "\nResult:\n" - "{ (json object where keys are the logging " - "categories, and values indicates its status\n" - " \"category\": 0|1, (numeric) if being debug logged or not. " - "0:inactive, 1:active\n" - " ...\n" - "}\n" - "\nExamples:\n" + - HelpExampleCli("logging", "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"") + - HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")); + throw std::runtime_error(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" + "The arguments are evaluated in order \"include\", \"exclude\".\n" + "If an item is both included and excluded, it will thus end up " + "being excluded.\n" + "The valid logging categories are: " + + ListLogCategories() + + "\n" + "In addition, the following are available as category names " + "with special meanings:\n" + " - \"all\", \"1\" : represent all logging categories.\n" + " - \"none\", \"0\" : even if other logging categories are " + "specified, ignore all of them.\n", + { + {"include", + RPCArg::Type::ARR, + /* opt */ true, + /* default_val */ "", + "A json array of categories to add debug logging", + { + {"include_category", RPCArg::Type::STR, + /* opt */ false, /* default_val */ "", + "the valid logging category"}, + }}, + {"exclude", + RPCArg::Type::ARR, + /* opt */ true, + /* default_val */ "", + "A json array of categories to remove debug logging", + { + {"exclude_category", RPCArg::Type::STR, + /* opt */ false, /* default_val */ "", + "the valid logging category"}, + }}, + }, + RPCResult{"{ (json object where keys are the " + "logging categories, and values indicates its status\n" + " \"category\": 0|1, (numeric) if being debug logged " + "or not. 0:inactive, 1:active\n" + " ...\n" + "}\n"}, + RPCExamples{HelpExampleCli("logging", + "\"[\\\"all\\\"]\" \"[\\\"http\\\"]\"") + + HelpExampleRpc("logging", "[\"all\"], \"[libevent]\"")}, + } + .ToStringWithResultsAndExamples()); } uint32_t original_log_categories = LogInstance().GetCategoryMask(); if (request.params[0].isArray()) { EnableOrDisableLogCategories(request.params[0], true); } if (request.params[1].isArray()) { EnableOrDisableLogCategories(request.params[1], false); } uint32_t updated_log_categories = LogInstance().GetCategoryMask(); uint32_t changed_log_categories = original_log_categories ^ updated_log_categories; /** * Update libevent logging if BCLog::LIBEVENT has changed. * If the library version doesn't allow it, UpdateHTTPServerLogging() * returns false, in which case we should clear the BCLog::LIBEVENT flag. * Throw an error if the user has explicitly asked to change only the * libevent flag and it failed. */ if (changed_log_categories & BCLog::LIBEVENT) { if (!UpdateHTTPServerLogging( LogInstance().WillLogCategory(BCLog::LIBEVENT))) { LogInstance().DisableCategory(BCLog::LIBEVENT); if (changed_log_categories == BCLog::LIBEVENT) { throw JSONRPCError(RPC_INVALID_PARAMETER, "libevent logging cannot be updated when " "using libevent before v2.1.1."); } } } UniValue result(UniValue::VOBJ); std::vector vLogCatActive = ListActiveLogCategories(); for (const auto &logCatActive : vLogCatActive) { result.pushKV(logCatActive.category, logCatActive.active); } return result; } static UniValue echo(const Config &config, const JSONRPCRequest &request) { if (request.fHelp) { - throw std::runtime_error( - RPCHelpMan{ - "echo|echojson ...", - "\nSimply echo back the input arguments. This command is for " - "testing.\n" - "\nIt will return an internal bug report when exactly 100 " - "arguments are passed.\n" - "\nThe difference between echo and echojson is that echojson " - "has argument conversion enabled in the client-side table in " - "bitcoin-cli and the GUI. There is no server-side difference.", - {}} - .ToString() + - ""); + throw std::runtime_error(RPCHelpMan{ + "echo|echojson ...", + "\nSimply echo back the input arguments. This command is for " + "testing.\n" + "\nThe difference between echo and echojson is that echojson has " + "argument conversion enabled in the client-side table in " + "bitcoin-cli and the GUI. There is no server-side difference.", + {}, + RPCResults{}, + RPCExamples{""}, + } + .ToStringWithResultsAndExamples()); } CHECK_NONFATAL(request.params.size() != 100); return request.params; } // clang-format off static const CRPCCommand commands[] = { // category name actor (function) argNames // ------------------- ------------------------ ---------------------- ---------- { "control", "getmemoryinfo", getmemoryinfo, {"mode"} }, { "control", "logging", logging, {"include", "exclude"} }, { "util", "validateaddress", validateaddress, {"address"} }, { "util", "createmultisig", createmultisig, {"nrequired","keys"} }, { "util", "verifymessage", verifymessage, {"address","signature","message"} }, { "util", "signmessagewithprivkey", signmessagewithprivkey, {"privkey","message"} }, /* Not shown in help */ { "hidden", "setmocktime", setmocktime, {"timestamp"}}, { "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"}}, }; // clang-format on void RegisterMiscRPCCommands(CRPCTable &t) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { t.appendCommand(commands[vcidx].name, &commands[vcidx]); } }