|
14 | 14 | #include <univalue.h> |
15 | 15 |
|
16 | 16 | namespace { |
| 17 | +bool IsNumeric(std::string_view input) { return input.find_first_not_of("0123456789") == std::string::npos; } |
| 18 | + |
17 | 19 | template <typename ProTx> |
18 | 20 | void ParseInput(ProTx& ptx, std::string_view field_name, const std::string& input_str, NetInfoPurpose purpose, |
19 | 21 | size_t idx, bool optional) |
@@ -65,19 +67,44 @@ void ProcessNetInfoPlatform(ProTx& ptx, const UniValue& input_p2p, const UniValu |
65 | 67 | { |
66 | 68 | CHECK_NONFATAL(ptx.netInfo); |
67 | 69 |
|
68 | | - auto process_field = [](uint16_t& target, const UniValue& input, const std::string& field_name) { |
| 70 | + auto process_field = [&](uint16_t& maybe_target, const UniValue& input, const NetInfoPurpose purpose, |
| 71 | + std::string_view field_name) { |
69 | 72 | if (!input.isNum() && !input.isStr()) { |
70 | | - throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid param for %s, must be number", field_name)); |
| 73 | + throw JSONRPCError(RPC_INVALID_PARAMETER, |
| 74 | + strprintf("Invalid param for %s, must be number or string", field_name)); |
71 | 75 | } |
72 | | - if (int32_t port{ParseInt32V(input, field_name)}; port >= 1 && port <= std::numeric_limits<uint16_t>::max()) { |
73 | | - target = static_cast<uint16_t>(port); |
| 76 | + |
| 77 | + const auto& input_str{input.getValStr()}; |
| 78 | + if (!IsNumeric(input_str)) { |
| 79 | + // Cannot be parsed as a number (port) so must be an addr:port string |
| 80 | + if (!ptx.netInfo->CanStorePlatform()) { |
| 81 | + throw JSONRPCError(RPC_INVALID_PARAMETER, |
| 82 | + strprintf("Invalid param for %s, ProTx version only supports ports", field_name)); |
| 83 | + } |
| 84 | + ParseInput(ptx, field_name, input.get_str(), purpose, /*idx=*/0, /*optional=*/false); |
74 | 85 | } else { |
75 | | - throw JSONRPCError(RPC_INVALID_PARAMETER, |
76 | | - strprintf("Invalid param for %s, must be a valid port [1-65535]", field_name)); |
| 86 | + if (int32_t port{0}; ParseInt32(input_str, &port) && port >= 1 && port <= std::numeric_limits<uint16_t>::max()) { |
| 87 | + // Valid port |
| 88 | + if (!ptx.netInfo->CanStorePlatform()) { |
| 89 | + maybe_target = static_cast<uint16_t>(port); |
| 90 | + return; // Parsing complete |
| 91 | + } |
| 92 | + // We cannot store *only* a port number in netInfo so we need to associate it with the primary service of CORE_P2P manually |
| 93 | + if (!ptx.netInfo->HasEntries(NetInfoPurpose::CORE_P2P)) { |
| 94 | + throw JSONRPCError(RPC_INVALID_PARAMETER, |
| 95 | + strprintf("Cannot set param for %s, must specify coreP2PAddrs first", field_name)); |
| 96 | + } |
| 97 | + const CService service{CNetAddr{ptx.netInfo->GetPrimary()}, static_cast<uint16_t>(port)}; |
| 98 | + CHECK_NONFATAL(service.IsValid()); |
| 99 | + ParseInput(ptx, field_name, service.ToStringAddrPort(), purpose, /*idx=*/0, /*optional=*/false); |
| 100 | + } else { |
| 101 | + throw JSONRPCError(RPC_INVALID_PARAMETER, |
| 102 | + strprintf("Invalid param for %s, must be a valid port [1-65535]", field_name)); |
| 103 | + } |
77 | 104 | } |
78 | 105 | }; |
79 | | - process_field(ptx.platformP2PPort, input_p2p, "platformP2PPort"); |
80 | | - process_field(ptx.platformHTTPPort, input_http, "platformHTTPPort"); |
| 106 | + process_field(ptx.platformP2PPort, input_p2p, NetInfoPurpose::PLATFORM_P2P, "platformP2PPort"); |
| 107 | + process_field(ptx.platformHTTPPort, input_http, NetInfoPurpose::PLATFORM_HTTPS, "platformHTTPPort"); |
81 | 108 | } |
82 | 109 | template void ProcessNetInfoPlatform(CProRegTx& ptx, const UniValue& input_p2p, const UniValue& input_http); |
83 | 110 | template void ProcessNetInfoPlatform(CProUpServTx& ptx, const UniValue& input_p2p, const UniValue& input_http); |
0 commit comments