Merge bitcoin/bitcoin#35842: rpc: Properly make RPCResult::Type::ANY non-test-only
What changed, and why it matters
This is a small cleanup and documentation fix for Bitcoin Core's RPC help system. It removes a comment that incorrectly said a certain output type was 'for testing only' and makes the help text properly display those outputs. There is no direct security vulnerability here; the change is about making generated API documentation accurate and consistent.
No security action required. Treat as a normal code-quality/documentation merge. Reviewers may verify that OpenRPC output for the 'help' command now includes the previously elided ANY result as intended.
Security signals we found
No memory safety, cryptography, consensus, or authorization changes observed
Change is confined to RPC help/schema metadata generation
Comment-only/type-label change from 'for testing only' to general use
Refactoring of std::get_if to std::visit with exhaustive variant handlers
Evidence from the diff
The commit completes an earlier incomplete change (6a1a66c) so that RPCResult::Type::ANY is rendered correctly in help output and OpenRPC schema generation instead of being silently skipped. It updates the ‘help’ command’s result description, removes the ‘for testing only’ comment on the ANY type, refactors ApplyArgFallback to use std::visit, and makes minor cleanups (CLIENT_NAME macro, self.Arg
Changed components
src/rpc/server.cppsrc/rpc/util.cppsrc/rpc/util.hsrc/wallet/rpc/addresses.cppInspect captured patch +42 / −36
### src/rpc/server.cpp
@@ -15,6 +15,7 @@
#include <rpc/server_util.h>
#include <rpc/util.h>
#include <sync.h>
+#include <util/overloaded.h>
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/string.h>
@@ -28,8 +29,8 @@
#include <mutex>
#include <span>
#include <string_view>
-#include <unordered_set>
#include <unordered_map>
+#include <unordered_set>
#include <variant>
using util::SplitString;
@@ -124,24 +125,27 @@ static RPCMethod help()
return RPCMethod{
"help",
"List all commands, or get help for a specified command.\n",
- {
- {"command", RPCArg::Type::STR, RPCArg::DefaultHint{"all commands"}, "The command to get help on"},
- },
- {
- RPCResult{RPCResult::Type::STR, "", "The help text"},
- RPCResult{RPCResult::Type::ANY, "", ""},
- },
- RPCExamples{""},
+ {
+ {"command", RPCArg::Type::STR, RPCArg::DefaultHint{"all commands"}, "The command to get help on"},
+ },
+ {
+ RPCResult{RPCResult::Type::STR, "", "The help text"},
+ RPCResult{RPCResult::Type::ANY, "", "The command conversions. (Hidden in dump_all_command_conversions)", /*inner=*/{},
+ RPCResultOptions{
+ .print_elision = HelpElisionSkip{},
+ }},
+ },
+ RPCExamples{""},
[](const RPCMethod& self, const JSONRPCRequest& jsonRequest) -> UniValue
-{
- auto command{self.MaybeArg<std::string_view>("command")};
- if (command == "dump_all_command_conversions") {
- // Used for testing only, undocumented
- return tableRPC.dumpArgMap(jsonRequest);
- }
+ {
+ auto command{self.MaybeArg<std::string_view>("command")};
+ if (command == "dump_all_command_conversions") {
+ // Used for testing only, undocumented
+ return tableRPC.dumpArgMap(jsonRequest);
+ }
- return tableRPC.help(command.value_or(""), jsonRequest);
-},
+ return tableRPC.help(command.value_or(""), jsonRequest);
+ },
};
}
@@ -318,11 +322,12 @@ void ApplyTypeStrOverride(UniValue& schema, const RPCArg& arg)
void ApplyArgFallback(UniValue& schema, const RPCArg& arg)
{
- if (const auto* def = std::get_if<RPCArg::Default>(&arg.m_fallback)) {
- schema.pushKV("default", *def);
- } else if (const auto* hint = std::get_if<RPCArg::DefaultHint>(&arg.m_fallback)) {
- schema.pushKV("x-bitcoin-default-hint", *hint);
- }
+ std::visit(util::Overloaded{
+ [&](const RPCArg::Default& def) { schema.pushKV("default", def); },
+ [&](const RPCArg::DefaultHint& hint) { schema.pushKV("x-bitcoin-default-hint", hint); },
+ [](const RPCArg::Optional&) {},
+ },
+ arg.m_fallback);
}
// NOLINTNEXTLINE(misc-no-recursion)
@@ -565,10 +570,10 @@ static RPCMethod getopenrpcinfo()
+ HelpExampleRpc("getopenrpcinfo", "")
},
[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
-{
- const bool include_hidden{!request.params[0].isNull() && request.params[0].get_bool()};
- return tableRPC.buildOpenRPCDoc(include_hidden);
-},
+ {
+ const bool include_hidden{self.Arg<bool>("show_hidden")};
+ return tableRPC.buildOpenRPCDoc(include_hidden);
+ },
};
}
@@ -584,9 +589,9 @@ static RPCMethod rpc_discover()
+ HelpExampleRpc("rpc.discover", "")
},
[](const RPCMethod&, const JSONRPCRequest&) -> UniValue
-{
- return tableRPC.buildOpenRPCDoc(/*include_hidden=*/false);
-},
+ {
+ return tableRPC.buildOpenRPCDoc(/*include_hidden=*/false);
+ },
};
}
@@ -955,9 +960,9 @@ UniValue CRPCTable::buildOpenRPCDoc(bool include_hidden) const
if (!CLIENT_VERSION_IS_RELEASE) version += "-dev";
UniValue info{UniValue::VOBJ};
- info.pushKV("title", "Bitcoin Core JSON-RPC");
+ info.pushKV("title", CLIENT_NAME " JSON-RPC");
info.pushKV("version", version);
- info.pushKV("description", "Autogenerated from Bitcoin Core RPC metadata.");
+ info.pushKV("description", "Autogenerated from " CLIENT_NAME " RPC metadata.");
UniValue doc{UniValue::VOBJ};
doc.pushKV("openrpc", "1.4.1");
### src/rpc/util.cpp
@@ -616,14 +616,16 @@ std::string RPCResults::ToDescriptionString() const
{
std::string result;
for (const auto& r : m_results) {
- if (r.m_type == RPCResult::Type::ANY) continue; // for testing only
+ Sections sections;
+ r.ToSections(sections);
+ // A result can be empty via HelpElisionSkip
+ if (sections.m_sections.empty()) continue;
+
if (r.m_cond.empty()) {
result += "\nResult:\n";
} else {
result += "\nResult (" + r.m_cond + "):\n";
}
- Sections sections;
- r.ToSections(sections);
result += sections.ToString();
}
return result;
### src/rpc/util.h
@@ -313,7 +313,7 @@ struct RPCResult {
NUM,
BOOL,
NONE,
- ANY, //!< Special type to disable type checks (for testing only)
+ ANY, //!< Special type to disable type checks
STR_AMOUNT, //!< Special string to represent a floating point amount
STR_HEX, //!< Special string with only hex chars
OBJ_DYN, //!< Special dictionary with keys that are not literals
### src/wallet/rpc/addresses.cpp
@@ -365,7 +365,6 @@ static UniValue DescribeWalletAddress(const CWallet& wallet, const CTxDestinatio
return ret;
}
-// NOLINTNEXTLINE(misc-no-recursion)
static std::vector<RPCResult> GetAddressInfoBaseFields()
{
return {Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.