diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 1fbe62d3d38..e462a26d97e 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -18,6 +18,7 @@ public: std::string methodName; //!< method whose params want conversion int paramIdx; //!< 0-based idx of param to convert std::string paramName; //!< parameter name + bool also_string{false}; //!< The parameter is also a string }; // clang-format off @@ -188,10 +189,10 @@ static const CRPCConvertParam vRPCConvertParams[] = { "gettxout", 1, "n" }, { "gettxout", 2, "include_mempool" }, { "gettxoutproof", 0, "txids" }, - { "gettxoutsetinfo", 1, "hash_or_height" }, + { "gettxoutsetinfo", 1, "hash_or_height", /*also_string=*/true }, { "gettxoutsetinfo", 2, "use_index"}, { "dumptxoutset", 2, "options" }, - { "dumptxoutset", 2, "rollback" }, + { "dumptxoutset", 2, "rollback", /*also_string=*/true }, { "lockunspent", 0, "unlock" }, { "lockunspent", 1, "transactions" }, { "lockunspent", 2, "persistent" }, @@ -246,7 +247,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "listdescriptors", 0, "private" }, { "verifychain", 0, "checklevel" }, { "verifychain", 1, "nblocks" }, - { "getblockstats", 0, "hash_or_height" }, + { "getblockstats", 0, "hash_or_height", /*also_string=*/true }, { "getblockstats", 1, "stats" }, { "pruneblockchain", 0, "height" }, { "keypoolrefill", 0, "newsize" }, @@ -318,18 +319,21 @@ static const CRPCConvertParam vRPCConvertParams[] = // clang-format on /** Parse string to UniValue or throw runtime_error if string contains invalid JSON */ -static UniValue Parse(std::string_view raw) +static UniValue Parse(std::string_view raw, bool also_string) { UniValue parsed; - if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw)); + if (!parsed.read(raw)) { + if (!also_string) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw)); + return raw; + } return parsed; } class CRPCConvertTable { private: - std::set> members; - std::set> membersByName; + std::map, bool> members; + std::map, bool> membersByName; public: CRPCConvertTable(); @@ -337,21 +341,29 @@ public: /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx) { - return members.count({method, param_idx}) > 0 ? Parse(arg_value) : arg_value; + const auto& it = members.find({method, param_idx}); + if (it != members.end()) { + return Parse(arg_value, it->second); + } + return arg_value; } /** Return arg_value as UniValue, and first parse it if it is a non-string parameter */ UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name) { - return membersByName.count({method, param_name}) > 0 ? Parse(arg_value) : arg_value; + const auto& it = membersByName.find({method, param_name}); + if (it != membersByName.end()) { + return Parse(arg_value, it->second); + } + return arg_value; } }; CRPCConvertTable::CRPCConvertTable() { for (const auto& cp : vRPCConvertParams) { - members.emplace(cp.methodName, cp.paramIdx); - membersByName.emplace(cp.methodName, cp.paramName); + members.emplace(std::make_pair(cp.methodName, cp.paramIdx), cp.also_string); + membersByName.emplace(std::make_pair(cp.methodName, cp.paramName), cp.also_string); } } diff --git a/test/functional/rpc_help.py b/test/functional/rpc_help.py index 802a55492f2..02279ad2f7f 100755 --- a/test/functional/rpc_help.py +++ b/test/functional/rpc_help.py @@ -32,7 +32,7 @@ def process_mapping(fname): if line.startswith('};'): in_rpcs = False elif '{' in line and '"' in line: - m = re.search(r'{ *("[^"]*"), *([0-9]+) *, *("[^"]*") *},', line) + m = re.search(r'{ *("[^"]*"), *([0-9]+) *, *("[^"]*") *(, \/\*also_string=\*\/true *)?},', line) assert m, 'No match to table expression: %s' % line name = parse_string(m.group(1)) idx = int(m.group(2))