88#include < tinyformat.h>
99#include < util/system.h>
1010
11- #include < set >
11+ #include < map >
1212#include < string>
1313#include < string_view>
1414
1515class CRPCConvertParam
1616{
1717public:
18- std::string methodName; // !< method whose params want conversion
19- int paramIdx; // !< 0-based idx of param to convert
20- std::string paramName; // !< parameter name
18+ std::string methodName; // !< method whose params want conversion
19+ int paramIdx; // !< 0-based idx of param to convert
20+ std::string paramName; // !< parameter name
21+ bool preserve_str{false }; // !< only parse if array or object
2122};
2223
2324// clang-format off
@@ -253,36 +254,83 @@ static const CRPCConvertParam vRPCConvertParams[] =
253254 { " verifyislock" , 3 , " maxHeight" },
254255 { " submitchainlock" , 2 , " blockHeight" },
255256 { " mnauth" , 0 , " nodeId" },
257+ { " protx register" , 3 , " coreP2PAddrs" , true },
258+ { " protx register_legacy" , 3 , " coreP2PAddrs" , true },
259+ { " protx register_evo" , 3 , " coreP2PAddrs" , true },
260+ { " protx register_evo" , 10 , " platformP2PAddrs" , true },
261+ { " protx register_evo" , 11 , " platformHTTPSAddrs" , true },
262+ { " protx register_fund" , 2 , " coreP2PAddrs" , true },
263+ { " protx register_fund_legacy" , 2 , " coreP2PAddrs" , true },
264+ { " protx register_fund_evo" , 2 , " coreP2PAddrs" , true },
265+ { " protx register_fund_evo" , 9 , " platformP2PAddrs" , true },
266+ { " protx register_fund_evo" , 10 , " platformHTTPSAddrs" , true },
267+ { " protx register_prepare" , 3 , " coreP2PAddrs" , true },
268+ { " protx register_prepare_legacy" , 3 , " coreP2PAddrs" , true },
269+ { " protx register_prepare_evo" , 3 , " coreP2PAddrs" , true },
270+ { " protx register_prepare_evo" , 10 , " platformP2PAddrs" , true },
271+ { " protx register_prepare_evo" , 11 , " platformHTTPSAddrs" , true },
272+ { " protx update_service" , 2 , " coreP2PAddrs" , true },
273+ { " protx update_service_evo" , 2 , " coreP2PAddrs" , true },
274+ { " protx update_service_evo" , 5 , " platformP2PAddrs" , true },
275+ { " protx update_service_evo" , 6 , " platformHTTPSAddrs" , true },
256276};
257277// clang-format on
258278
259279class CRPCConvertTable
260280{
261281private:
262- std::set<std::pair<std::string, int >> members;
263- std::set<std::pair<std::string, std::string>> membersByName;
282+ std::map<std::pair<std::string, int >, bool > members;
283+ std::map<std::pair<std::string, std::string>, bool > membersByName;
284+
285+ std::string_view MaybeUnquoteString (std::string_view arg_value)
286+ {
287+ if (arg_value.size () >= 2 && ((arg_value.front () == ' \' ' && arg_value.back () == ' \' ' ) || (arg_value.front () == ' \" ' && arg_value.back () == ' \" ' ))) {
288+ return arg_value.substr (1 , arg_value.size () - 2 );
289+ }
290+ return arg_value;
291+ }
292+
293+ bool LikelyJSONType (std::string_view arg_value)
294+ {
295+ arg_value = MaybeUnquoteString (arg_value);
296+ return arg_value.size () >= 2 && ((arg_value.front () == ' [' && arg_value.back () == ' ]' ) || (arg_value.front () == ' {' && arg_value.back () == ' }' ));
297+ }
264298
265299public:
266300 CRPCConvertTable ();
267301
268302 /* * Return arg_value as UniValue, and first parse it if it is a non-string parameter */
269303 UniValue ArgToUniValue (std::string_view arg_value, const std::string& method, int param_idx)
270304 {
271- return members.count ({method, param_idx}) > 0 ? ParseNonRFCJSONValue (arg_value) : arg_value;
305+ if (const auto it = members.find ({method, param_idx}); it != members.end () && (!it->second || (it->second && LikelyJSONType (arg_value)))) {
306+ return ParseNonRFCJSONValue (MaybeUnquoteString (arg_value));
307+ }
308+ return arg_value;
272309 }
273310
274311 /* * Return arg_value as UniValue, and first parse it if it is a non-string parameter */
275312 UniValue ArgToUniValue (std::string_view arg_value, const std::string& method, const std::string& param_name)
276313 {
277- return membersByName.count ({method, param_name}) > 0 ? ParseNonRFCJSONValue (arg_value) : arg_value;
314+ if (const auto it = membersByName.find ({method, param_name}); it != membersByName.end () && (!it->second || (it->second && LikelyJSONType (arg_value)))) {
315+ return ParseNonRFCJSONValue (MaybeUnquoteString (arg_value));
316+ }
317+ return arg_value;
318+ }
319+
320+ /* * Check if we have any conversion rules for this method */
321+ bool IsDefined (const std::string& method, bool named) const
322+ {
323+ return named ?
324+ std::find_if (membersByName.begin (), membersByName.end (), [&method](const auto & kv) { return kv.first .first == method; }) != membersByName.end ()
325+ : std::find_if (members.begin (), members.end (), [&method](const auto & kv) { return kv.first .first == method; }) != members.end ();
278326 }
279327};
280328
281329CRPCConvertTable::CRPCConvertTable ()
282330{
283331 for (const auto & cp : vRPCConvertParams) {
284- members.emplace ( cp.methodName , cp.paramIdx );
285- membersByName.emplace ( cp.methodName , cp.paramName );
332+ members.try_emplace ({ cp.methodName , cp.paramIdx }, cp. preserve_str );
333+ membersByName.try_emplace ({ cp.methodName , cp.paramName }, cp. preserve_str );
286334 }
287335}
288336
@@ -298,10 +346,19 @@ UniValue ParseNonRFCJSONValue(std::string_view raw)
298346 return parsed;
299347}
300348
301- UniValue RPCConvertValues (const std::string & strMethod, const std::vector<std::string> &strParams)
349+ UniValue RPCConvertValues (std::string strMethod, const std::vector<std::string> &strParams)
302350{
303351 UniValue params (UniValue::VARR);
304352
353+ // If we are using a subcommand that is in the table, update the method name
354+ strMethod = [&strMethod, &strParams]() {
355+ if (!strParams.empty () && strMethod.find (' ' ) == std::string::npos) {
356+ std::string candidate{strMethod + " " + strParams[0 ]};
357+ return rpcCvtTable.IsDefined (candidate, /* named=*/ false ) ? candidate : strMethod;
358+ }
359+ return strMethod;
360+ }();
361+
305362 for (unsigned int idx = 0 ; idx < strParams.size (); idx++) {
306363 std::string_view value{strParams[idx]};
307364 params.push_back (rpcCvtTable.ArgToUniValue (value, strMethod, idx));
@@ -310,11 +367,20 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
310367 return params;
311368}
312369
313- UniValue RPCConvertNamedValues (const std::string & strMethod, const std::vector<std::string> &strParams)
370+ UniValue RPCConvertNamedValues (std::string strMethod, const std::vector<std::string> &strParams)
314371{
315372 UniValue params (UniValue::VOBJ);
316373 UniValue positional_args{UniValue::VARR};
317374
375+ // If we are using a subcommand that is in the table, update the method name
376+ strMethod = [&strMethod, &strParams]() {
377+ if (strMethod.find (' ' ) == std::string::npos && !strParams.empty () && strParams[0 ].find (' =' ) == std::string::npos) {
378+ std::string candidate{strMethod + " " + strParams[0 ]};
379+ return rpcCvtTable.IsDefined (candidate, /* named=*/ true ) ? candidate : strMethod;
380+ }
381+ return strMethod;
382+ }();
383+
318384 for (std::string_view s: strParams) {
319385 size_t pos = s.find (' =' );
320386 if (pos == std::string::npos) {
0 commit comments