2323#include < boost/signals2/signal.hpp>
2424#include < boost/thread.hpp>
2525
26- #include < univalue.h>
27-
2826#include < memory> // for unique_ptr
27+ #include < univalue.h>
28+ #include < unordered_map>
2929
3030static bool fRPCRunning = false ;
3131static bool fRPCInWarmup = true ;
@@ -274,12 +274,11 @@ UniValue stop(const JSONRPCRequest& jsonRequest)
274274 */
275275static const CRPCCommand vRPCCommands[] =
276276 {
277- // category name actor (function) okSafeMode
278- // --------------------- ------------------------ ----------------------- ----------
279- /* Overall control/query calls */
280-
281- {" control" , " help" , &help, true },
282- {" control" , " stop" , &stop, true },
277+ // category name actor (function) okSafe argNames
278+ // --------------------- ------------------------ ----------------------- ------ ----------
279+ /* Overall control/query calls */
280+ { " control" , " help" , &help, true , {" command" } },
281+ { " control" , " stop" , &stop, true , {} },
283282};
284283
285284CRPCTable::CRPCTable ()
@@ -385,12 +384,12 @@ void JSONRPCRequest::parse(const UniValue& valRequest)
385384
386385 // Parse params
387386 UniValue valParams = find_value (request, " params" );
388- if (valParams.isArray ())
389- params = valParams. get_array () ;
387+ if (valParams.isArray () || valParams. isObject () )
388+ params = valParams;
390389 else if (valParams.isNull ())
391390 params = UniValue (UniValue::VARR);
392391 else
393- throw JSONRPCError (RPC_INVALID_REQUEST, " Params must be an array" );
392+ throw JSONRPCError (RPC_INVALID_REQUEST, " Params must be an array or object " );
394393}
395394
396395bool IsDeprecatedRPCEnabled (const std::string& method)
@@ -429,6 +428,48 @@ std::string JSONRPCExecBatch(const UniValue& vReq)
429428 return ret.write () + " \n " ;
430429}
431430
431+ /* *
432+ * Process named arguments into a vector of positional arguments, based on the
433+ * passed-in specification for the RPC call's arguments.
434+ */
435+ static inline JSONRPCRequest transformNamedArguments (const JSONRPCRequest& in, const std::vector<std::string>& argNames)
436+ {
437+ JSONRPCRequest out = in;
438+ out.params = UniValue (UniValue::VARR);
439+ // Build a map of parameters, and remove ones that have been processed, so that we can throw a focused error if
440+ // there is an unknown one.
441+ const std::vector<std::string>& keys = in.params .getKeys ();
442+ const std::vector<UniValue>& values = in.params .getValues ();
443+ std::unordered_map<std::string, const UniValue*> argsIn;
444+ for (size_t i=0 ; i<keys.size (); ++i) {
445+ argsIn[keys[i]] = &values[i];
446+ }
447+ // Process expected parameters.
448+ int hole = 0 ;
449+ for (const std::string &argName: argNames) {
450+ auto fr = argsIn.find (argName);
451+ if (fr != argsIn.end ()) {
452+ for (int i = 0 ; i < hole; ++i) {
453+ // Fill hole between specified parameters with JSON nulls,
454+ // but not at the end (for backwards compatibility with calls
455+ // that act based on number of specified parameters).
456+ out.params .push_back (UniValue ());
457+ }
458+ hole = 0 ;
459+ out.params .push_back (*fr->second );
460+ argsIn.erase (fr);
461+ } else {
462+ hole += 1 ;
463+ }
464+ }
465+ // If there are still arguments in the argsIn map, this is an error.
466+ if (!argsIn.empty ()) {
467+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Unknown named parameter " + argsIn.begin ()->first );
468+ }
469+ // Return request with named arguments transformed to positional arguments
470+ return out;
471+ }
472+
432473UniValue CRPCTable::execute (const JSONRPCRequest &request) const
433474{
434475 // Return immediately if in warmup
@@ -445,8 +486,12 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const
445486 g_rpcSignals.PreCommand (*pcmd);
446487
447488 try {
448- // Execute
449- return pcmd->actor (request);
489+ // Execute, convert arguments to array if necessary
490+ if (request.params .isObject ()) {
491+ return pcmd->actor (transformNamedArguments (request, pcmd->argNames ));
492+ } else {
493+ return pcmd->actor (request);
494+ }
450495 } catch (const std::exception& e) {
451496 throw JSONRPCError (RPC_MISC_ERROR, e.what ());
452497 }
0 commit comments