rpc: Make it an error server-side to specify same named parameter multiple times

Specifying same named parameter multiple times is still allowed by bitcoin-cli.
The client implementation overwrites earlier option values with later ones
before sending to server. This is tested by interface_bitcoin_cli.py

Rationale for allowing client parameters to be specified multiple times in
bitcoin-cli is that this behavior has been supported for a long time, and that
when using the command line interactively, it can be convenient to override
earlier option values with new values without having to go back and remove the
old value.

But for the RPC server, there isn't really a good use-case for earlier values
to be discarded if multiple values are specified. JSON keys are generally
supposed to be unique and if they aren't it's probably an indication of some
problem generating the RPC request.
This commit is contained in:
Ryan Ofsky 2022-12-02 17:53:16 -05:00
parent e2c3b18e67
commit 6bd1d20b8c
3 changed files with 11 additions and 3 deletions

View file

@ -0,0 +1,4 @@
JSON-RPC
---
The JSON-RPC server now rejects requests where a parameter is specified multiple times with the same name, instead of silently overwriting earlier parameter values with later ones. (#26628)

View file

@ -399,7 +399,10 @@ static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, c
const std::vector<UniValue>& values = in.params.getValues();
std::unordered_map<std::string, const UniValue*> argsIn;
for (size_t i=0; i<keys.size(); ++i) {
argsIn[keys[i]] = &values[i];
auto [_, inserted] = argsIn.emplace(keys[i], &values[i]);
if (!inserted) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times");
}
}
// Process expected parameters. If any parameters were left unspecified in
// the request before a parameter that was specified, null values need to be

View file

@ -89,8 +89,9 @@ BOOST_AUTO_TEST_CASE(rpc_namedparams)
// Make sure named arguments are transformed into positional arguments in correct places separated by nulls
BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg2": 2, "arg4": 4})"), arg_names).write(), "[null,2,null,4]");
// Make sure later named argument value silently overwrites earlier values
BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg2": 2, "arg2": 4})"), arg_names).write(), "[null,4]");
// Make sure named argument specified multiple times raises an exception
BOOST_CHECK_EXCEPTION(TransformParams(JSON(R"({"arg2": 2, "arg2": 4})"), arg_names), UniValue,
HasJSON(R"({"code":-8,"message":"Parameter arg2 specified multiple times"})"));
// Make sure named and positional arguments can be combined.
BOOST_CHECK_EQUAL(TransformParams(JSON(R"({"arg5": 5, "args": [1, 2], "arg4": 4})"), arg_names).write(), "[1,2,null,4,5]");