mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
Merge bitcoin/bitcoin#26612: refactor: RPC: pass named argument value as string_view
545ff924ab
refactor: use string_view for RPC named argument values (stickies-v)7727603e44
refactor: reduce unnecessary complexity in ParseNonRFCJSONValue (stickies-v)1d02e59901
test: add cases to JSON parsing (stickies-v) Pull request description: Inspired by MarcoFalke's [comment](https://github.com/bitcoin/bitcoin/pull/26506#discussion_r1036149426). Main purpose of this PR is to minimize copying (potentially large) RPC named arguments when calling `.substr()` by using `std::string_view` instead of `std::string`. Furthermore, cleans up the code by removing unnecessary complexity in `ParseNonRFCJSONValue()` (done first to avoid refactoring required to concatenate `string` and `string_view`), updates some naming and adds a few test cases. Should not introduce any behaviour change. ## Questions - ~Was there actually any merit to `ParseNonRFCJSONValue()` surrounding the value with brackets and then parsing it as an array? I don't see it, and the new approach doesn't fail any tests. Still a bit suspicious about it though.~ - Cleared up by https://github.com/bitcoin/bitcoin/pull/26506#pullrequestreview-1211984059 - If there are no objections to7727603e44
, I think we should follow up with a PR to rename `ParseNonRFCJSONValue()` to a local `Parse()` helper function (that throws if invalid), remove it from `client.h` and merge the test coverage we currently have on `ParseNonRFCJSONValue()` with the coverage we have on `UniValue::read()`. ACKs for top commit: ryanofsky: Code review ACK545ff924ab
MarcoFalke: review ACK545ff924ab
📻 Tree-SHA512: b1c89fb010ac9c3054b023cac1acbba2a539a09cf39a7baffbd7f7571ee268d5a6d98701c7ac10d68a814526e8fd0fe96ac1d1fb072f272033e415b753f64a5c
This commit is contained in:
commit
3b88c85025
4 changed files with 31 additions and 19 deletions
|
@ -4,10 +4,13 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <rpc/client.h>
|
||||
#include <tinyformat.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
class CRPCConvertParam
|
||||
{
|
||||
|
@ -229,15 +232,15 @@ public:
|
|||
CRPCConvertTable();
|
||||
|
||||
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
|
||||
UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, int param_idx)
|
||||
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, int param_idx)
|
||||
{
|
||||
return members.count(std::make_pair(method, param_idx)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
|
||||
return members.count({method, param_idx}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
|
||||
}
|
||||
|
||||
/** Return arg_value as UniValue, and first parse it if it is a non-string parameter */
|
||||
UniValue ArgToUniValue(const std::string& arg_value, const std::string& method, const std::string& param_name)
|
||||
UniValue ArgToUniValue(std::string_view arg_value, const std::string& method, const std::string& param_name)
|
||||
{
|
||||
return membersByName.count(std::make_pair(method, param_name)) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
|
||||
return membersByName.count({method, param_name}) > 0 ? ParseNonRFCJSONValue(arg_value) : arg_value;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -254,13 +257,11 @@ static CRPCConvertTable rpcCvtTable;
|
|||
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
|
||||
* as well as objects and arrays.
|
||||
*/
|
||||
UniValue ParseNonRFCJSONValue(const std::string& strVal)
|
||||
UniValue ParseNonRFCJSONValue(std::string_view raw)
|
||||
{
|
||||
UniValue jVal;
|
||||
if (!jVal.read(std::string("[")+strVal+std::string("]")) ||
|
||||
!jVal.isArray() || jVal.size()!=1)
|
||||
throw std::runtime_error(std::string("Error parsing JSON: ") + strVal);
|
||||
return jVal[0];
|
||||
UniValue parsed;
|
||||
if (!parsed.read(raw)) throw std::runtime_error(tfm::format("Error parsing JSON: %s", raw));
|
||||
return parsed;
|
||||
}
|
||||
|
||||
UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::string> &strParams)
|
||||
|
@ -268,8 +269,8 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
|
|||
UniValue params(UniValue::VARR);
|
||||
|
||||
for (unsigned int idx = 0; idx < strParams.size(); idx++) {
|
||||
const std::string& strVal = strParams[idx];
|
||||
params.push_back(rpcCvtTable.ArgToUniValue(strVal, strMethod, idx));
|
||||
std::string_view value{strParams[idx]};
|
||||
params.push_back(rpcCvtTable.ArgToUniValue(value, strMethod, idx));
|
||||
}
|
||||
|
||||
return params;
|
||||
|
@ -280,15 +281,15 @@ UniValue RPCConvertNamedValues(const std::string &strMethod, const std::vector<s
|
|||
UniValue params(UniValue::VOBJ);
|
||||
UniValue positional_args{UniValue::VARR};
|
||||
|
||||
for (const std::string &s: strParams) {
|
||||
for (std::string_view s: strParams) {
|
||||
size_t pos = s.find('=');
|
||||
if (pos == std::string::npos) {
|
||||
positional_args.push_back(rpcCvtTable.ArgToUniValue(s, strMethod, positional_args.size()));
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string name = s.substr(0, pos);
|
||||
std::string value = s.substr(pos+1);
|
||||
std::string name{s.substr(0, pos)};
|
||||
std::string_view value{s.substr(pos+1)};
|
||||
|
||||
// Intentionally overwrite earlier named values with later ones as a
|
||||
// convenience for scripts and command line users that want to merge
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
#ifndef BITCOIN_RPC_CLIENT_H
|
||||
#define BITCOIN_RPC_CLIENT_H
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
/** Convert positional arguments to command-specific RPC representation */
|
||||
|
@ -17,6 +20,6 @@ UniValue RPCConvertNamedValues(const std::string& strMethod, const std::vector<s
|
|||
/** Non-RFC4627 JSON parser, accepts internal values (such as numbers, true, false, null)
|
||||
* as well as objects and arrays.
|
||||
*/
|
||||
UniValue ParseNonRFCJSONValue(const std::string& strVal);
|
||||
UniValue ParseNonRFCJSONValue(std::string_view raw);
|
||||
|
||||
#endif // BITCOIN_RPC_CLIENT_H
|
||||
|
|
|
@ -289,6 +289,10 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
|
|||
{
|
||||
// Valid
|
||||
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0").get_real(), 1.0);
|
||||
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("true").get_bool(), true);
|
||||
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("[false]")[0].get_bool(), false);
|
||||
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"a\": true}")["a"].get_bool(), true);
|
||||
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("{\"1\": \"true\"}")["1"].get_str(), "true");
|
||||
// Valid, with leading or trailing whitespace
|
||||
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue(" 1.0").get_real(), 1.0);
|
||||
BOOST_CHECK_EQUAL(ParseNonRFCJSONValue("1.0 ").get_real(), 1.0);
|
||||
|
@ -301,6 +305,11 @@ BOOST_AUTO_TEST_CASE(json_parse_errors)
|
|||
// Invalid, trailing garbage
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0sds"), std::runtime_error);
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("1.0]"), std::runtime_error);
|
||||
// Invalid, keys have to be names
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("{1: \"true\"}"), std::runtime_error);
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("{true: 1}"), std::runtime_error);
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("{[1]: 1}"), std::runtime_error);
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("{{\"a\": \"a\"}: 1}"), std::runtime_error);
|
||||
// BTC addresses should fail parsing
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("175tWpb8K1S7NmH4Zx6rewF9WQrcZv245W"), std::runtime_error);
|
||||
BOOST_CHECK_THROW(ParseNonRFCJSONValue("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNL"), std::runtime_error);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
|
@ -95,9 +96,7 @@ public:
|
|||
|
||||
bool read(const char *raw, size_t len);
|
||||
bool read(const char *raw) { return read(raw, strlen(raw)); }
|
||||
bool read(const std::string& rawStr) {
|
||||
return read(rawStr.data(), rawStr.size());
|
||||
}
|
||||
bool read(std::string_view raw) { return read(raw.data(), raw.size()); }
|
||||
|
||||
private:
|
||||
UniValue::VType typ;
|
||||
|
|
Loading…
Add table
Reference in a new issue