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,74 @@ 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+ bool LikelyJSONType (std::string_view arg_value)
286+ {
287+ return arg_value.size () >= 2 && ((arg_value.front () == ' [' && arg_value.back () == ' ]' ) || (arg_value.front () == ' {' && arg_value.back () == ' }' ));
288+ }
264289
265290public:
266291 CRPCConvertTable ();
267292
268293 /* * Return arg_value as UniValue, and first parse it if it is a non-string parameter */
269294 UniValue ArgToUniValue (std::string_view arg_value, const std::string& method, int param_idx)
270295 {
271- return members.count ({method, param_idx}) > 0 ? ParseNonRFCJSONValue (arg_value) : arg_value;
296+ if (const auto it = members.find ({method, param_idx}); it != members.end () && (!it->second || (it->second && LikelyJSONType (arg_value)))) {
297+ return ParseNonRFCJSONValue (arg_value);
298+ }
299+ return arg_value;
272300 }
273301
274302 /* * Return arg_value as UniValue, and first parse it if it is a non-string parameter */
275303 UniValue ArgToUniValue (std::string_view arg_value, const std::string& method, const std::string& param_name)
276304 {
277- return membersByName.count ({method, param_name}) > 0 ? ParseNonRFCJSONValue (arg_value) : arg_value;
305+ if (const auto it = membersByName.find ({method, param_name}); it != membersByName.end () && (!it->second || (it->second && LikelyJSONType (arg_value)))) {
306+ return ParseNonRFCJSONValue (arg_value);
307+ }
308+ return arg_value;
309+ }
310+
311+ /* * Check if we have any conversion rules for this method */
312+ bool IsDefined (const std::string& method, bool named) const
313+ {
314+ return named ?
315+ std::find_if (membersByName.begin (), membersByName.end (), [&method](const auto & kv) { return kv.first .first == method; }) != membersByName.end ()
316+ : std::find_if (members.begin (), members.end (), [&method](const auto & kv) { return kv.first .first == method; }) != members.end ();
278317 }
279318};
280319
281320CRPCConvertTable::CRPCConvertTable ()
282321{
283322 for (const auto & cp : vRPCConvertParams) {
284- members.emplace ( cp.methodName , cp.paramIdx );
285- membersByName.emplace ( cp.methodName , cp.paramName );
323+ members.try_emplace ({ cp.methodName , cp.paramIdx }, cp. preserve_str );
324+ membersByName.try_emplace ({ cp.methodName , cp.paramName }, cp. preserve_str );
286325 }
287326}
288327
@@ -298,10 +337,19 @@ UniValue ParseNonRFCJSONValue(std::string_view raw)
298337 return parsed;
299338}
300339
301- UniValue RPCConvertValues (const std::string & strMethod, const std::vector<std::string> &strParams)
340+ UniValue RPCConvertValues (std::string strMethod, const std::vector<std::string> &strParams)
302341{
303342 UniValue params (UniValue::VARR);
304343
344+ // If we are using a subcommand that is in the table, update the method name
345+ strMethod = [&strMethod, &strParams]() {
346+ if (!strParams.empty () && strMethod.find (' ' ) == std::string::npos) {
347+ std::string candidate{strMethod + " " + strParams[0 ]};
348+ return rpcCvtTable.IsDefined (candidate, /* named=*/ false ) ? candidate : strMethod;
349+ }
350+ return strMethod;
351+ }();
352+
305353 for (unsigned int idx = 0 ; idx < strParams.size (); idx++) {
306354 std::string_view value{strParams[idx]};
307355 params.push_back (rpcCvtTable.ArgToUniValue (value, strMethod, idx));
@@ -310,11 +358,20 @@ UniValue RPCConvertValues(const std::string &strMethod, const std::vector<std::s
310358 return params;
311359}
312360
313- UniValue RPCConvertNamedValues (const std::string & strMethod, const std::vector<std::string> &strParams)
361+ UniValue RPCConvertNamedValues (std::string strMethod, const std::vector<std::string> &strParams)
314362{
315363 UniValue params (UniValue::VOBJ);
316364 UniValue positional_args{UniValue::VARR};
317365
366+ // If we are using a subcommand that is in the table, update the method name
367+ strMethod = [&strMethod, &strParams]() {
368+ if (strMethod.find (' ' ) == std::string::npos && !strParams.empty () && strParams[0 ].find (' =' ) == std::string::npos) {
369+ std::string candidate{strMethod + " " + strParams[0 ]};
370+ return rpcCvtTable.IsDefined (candidate, /* named=*/ true ) ? candidate : strMethod;
371+ }
372+ return strMethod;
373+ }();
374+
318375 for (std::string_view s: strParams) {
319376 size_t pos = s.find (' =' );
320377 if (pos == std::string::npos) {
0 commit comments