* Process named arguments into a vector of positional arguments, based on the * passed-in specification for the RPC call's arguments. */
| 366 | * passed-in specification for the RPC call's arguments. |
| 367 | */ |
| 368 | static inline JSONRPCRequest transformNamedArguments(const JSONRPCRequest& in, const std::vector<std::pair<std::string, bool>>& argNames) |
| 369 | { |
| 370 | JSONRPCRequest out = in; |
| 371 | out.params = UniValue(UniValue::VARR); |
| 372 | // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if |
| 373 | // there is an unknown one. |
| 374 | const std::vector<std::string>& keys = in.params.getKeys(); |
| 375 | const std::vector<UniValue>& values = in.params.getValues(); |
| 376 | std::unordered_map<std::string, const UniValue*> argsIn; |
| 377 | for (size_t i=0; i<keys.size(); ++i) { |
| 378 | auto [_, inserted] = argsIn.emplace(keys[i], &values[i]); |
| 379 | if (!inserted) { |
| 380 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + keys[i] + " specified multiple times"); |
| 381 | } |
| 382 | } |
| 383 | // Process expected parameters. If any parameters were left unspecified in |
| 384 | // the request before a parameter that was specified, null values need to be |
| 385 | // inserted at the unspecified parameter positions, and the "hole" variable |
| 386 | // below tracks the number of null values that need to be inserted. |
| 387 | // The "initial_hole_size" variable stores the size of the initial hole, |
| 388 | // i.e. how many initial positional arguments were left unspecified. This is |
| 389 | // used after the for-loop to add initial positional arguments from the |
| 390 | // "args" parameter, if present. |
| 391 | int hole = 0; |
| 392 | int initial_hole_size = 0; |
| 393 | const std::string* initial_param = nullptr; |
| 394 | UniValue options{UniValue::VOBJ}; |
| 395 | for (const auto& [argNamePattern, named_only]: argNames) { |
| 396 | std::vector<std::string> vargNames = SplitString(argNamePattern, '|'); |
| 397 | auto fr = argsIn.end(); |
| 398 | for (const std::string & argName : vargNames) { |
| 399 | fr = argsIn.find(argName); |
| 400 | if (fr != argsIn.end()) { |
| 401 | break; |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | // Handle named-only parameters by pushing them into a temporary options |
| 406 | // object, and then pushing the accumulated options as the next |
| 407 | // positional argument. |
| 408 | if (named_only) { |
| 409 | if (fr != argsIn.end()) { |
| 410 | if (options.exists(fr->first)) { |
| 411 | throw JSONRPCError(RPC_INVALID_PARAMETER, "Parameter " + fr->first + " specified multiple times"); |
| 412 | } |
| 413 | options.pushKVEnd(fr->first, *fr->second); |
| 414 | argsIn.erase(fr); |
| 415 | } |
| 416 | continue; |
| 417 | } |
| 418 | |
| 419 | if (!options.empty() || fr != argsIn.end()) { |
| 420 | for (int i = 0; i < hole; ++i) { |
| 421 | // Fill hole between specified parameters with JSON nulls, |
| 422 | // but not at the end (for backwards compatibility with calls |
| 423 | // that act based on number of specified parameters). |
| 424 | out.params.push_back(UniValue()); |
| 425 | } |
no test coverage detected