Skip to content

Commit d519eea

Browse files
kwvgknst
andcommitted
rpc: allow multiple entries in platform{HTTP,P2P}Port
Co-Authored-By: Konstantin Akimov <[email protected]>
1 parent 01ee293 commit d519eea

File tree

3 files changed

+64
-37
lines changed

3 files changed

+64
-37
lines changed

src/rpc/evo.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -184,24 +184,36 @@ static RPCArg GetRpcArg(const std::string& strParamName)
184184
"Platform P2P node ID, derived from P2P public key."}
185185
},
186186
{"platformP2PPort",
187-
{"platformP2PPort", RPCArg::Type::STR, RPCArg::Optional::NO,
188-
"Address in the form \"ADDR:PORT\" used by Platform for peer-to-peer connection.\n"
189-
"Must be unique on the network. Can be set to an empty string, which will require a ProUpServTx afterwards."}
187+
{"platformP2PPort", RPCArg::Type::ARR, RPCArg::Optional::NO,
188+
"Array of addresses in the form \"ADDR:PORT\" used by Platform for peer-to-peer connection.\n"
189+
"Must be unique on the network. Can be set to an empty string, which will require a ProUpServTx afterwards.",
190+
{
191+
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, ""},
192+
}}
190193
},
191194
{"platformP2PPort_update",
192-
{"platformP2PPort", RPCArg::Type::STR, RPCArg::Optional::NO,
193-
"Address in the form \"ADDR:PORT\" used by Platform for peer-to-peer connection.\n"
194-
"Must be unique on the network."}
195+
{"platformP2PPort", RPCArg::Type::ARR, RPCArg::Optional::NO,
196+
"Array of addresses in the form \"ADDR:PORT\" used by Platform for peer-to-peer connection.\n"
197+
"Must be unique on the network.",
198+
{
199+
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, ""},
200+
}}
195201
},
196202
{"platformHTTPPort",
197-
{"platformHTTPPort", RPCArg::Type::STR, RPCArg::Optional::NO,
198-
"Address in the form \"ADDR:PORT\" used by Platform for their HTTPS API.\n"
199-
"Must be unique on the network. Can be set to an empty string, which will require a ProUpServTx afterwards."}
203+
{"platformHTTPPort", RPCArg::Type::ARR, RPCArg::Optional::NO,
204+
"Array of addresses in the form \"ADDR:PORT\" used by Platform for their HTTPS API.\n"
205+
"Must be unique on the network. Can be set to an empty string, which will require a ProUpServTx afterwards.",
206+
{
207+
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, ""},
208+
}}
200209
},
201210
{"platformHTTPPort_update",
202-
{"platformHTTPPort", RPCArg::Type::STR, RPCArg::Optional::NO,
203-
"Address in the form \"ADDR:PORT\" used by Platform for their HTTPS API.\n"
204-
"Must be unique on the network."}
211+
{"platformHTTPPort", RPCArg::Type::ARR, RPCArg::Optional::NO,
212+
"Array of addresses in the form \"ADDR:PORT\" used by Platform for their HTTPS API.\n"
213+
"Must be unique on the network.",
214+
{
215+
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, ""},
216+
}}
205217
},
206218
};
207219

src/rpc/evo_util.cpp

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,37 +69,52 @@ void ProcessNetInfoPlatform(ProTx& ptx, const UniValue& input_p2p, const UniValu
6969

7070
auto process_field = [&](uint16_t& maybe_target, const UniValue& input, const NetInfoPurpose purpose,
7171
std::string_view field_name) {
72-
if (!input.isNum() && !input.isStr()) {
72+
if (!input.isArray() && !input.isNum() && !input.isStr()) {
7373
throw JSONRPCError(RPC_INVALID_PARAMETER,
74-
strprintf("Invalid param for %s, must be number or string", field_name));
74+
strprintf("Invalid param for %s, must be array, number or string", field_name));
7575
}
7676

77-
const auto& input_str{input.getValStr()};
78-
if (input_str.empty()) {
79-
if (!optional) {
80-
// Mandatory field, cannot specify blank value
81-
throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid param for %s, cannot be empty", field_name));
77+
bool is_empty{input.isArray() ? input.get_array().empty() : input.getValStr().empty()};
78+
bool is_nonnumeric_str{input.isStr() && !IsNumeric(input.getValStr())};
79+
if (is_empty || is_nonnumeric_str || input.isArray()) {
80+
if (is_empty) {
81+
if (!optional) {
82+
// Mandatory field, cannot specify blank value
83+
throw JSONRPCError(RPC_INVALID_PARAMETER,
84+
strprintf("Invalid param for %s, cannot be empty", field_name));
85+
}
86+
if (!ptx.netInfo->IsEmpty()) {
87+
// Blank values are tolerable so long as no other field has been populated.
88+
throw JSONRPCError(RPC_INVALID_PARAMETER,
89+
strprintf("Invalid param for %s, cannot be empty if other fields populated",
90+
field_name));
91+
}
8292
}
8393
if (!ptx.netInfo->CanStorePlatform()) {
84-
// We can tolerate blank values if netInfo can store platform fields, if it cannot, we are relying
85-
// on platform{HTTP,P2P}Port, where it is mandatory even if their netInfo counterpart is optional.
94+
// Arrays: Expected to be address strings, if relying on platform{HTTP,P2P}Port, bail out.
95+
// Empty Input: We can tolerate blank values if netInfo can store platform fields, if it cannot, we are relying
96+
// on platform{HTTP,P2P}Port, where it is mandatory even if their netInfo counterpart is optional.
97+
// String: If not parsable as port and relying on platform{HTTP,P2P}Port, bail out.
8698
throw JSONRPCError(RPC_INVALID_PARAMETER,
8799
strprintf("Invalid param for %s, ProTx version only supports ports", field_name));
88100
}
89-
if (!ptx.netInfo->IsEmpty()) {
90-
// Blank values are tolerable so long as no other field has been populated.
91-
throw JSONRPCError(RPC_INVALID_PARAMETER,
92-
strprintf("Invalid param for %s, cannot be empty if other fields populated", field_name));
93-
}
94-
} else if (!IsNumeric(input_str)) {
95-
// Cannot be parsed as a number (port) so must be an addr:port string
96-
if (!ptx.netInfo->CanStorePlatform()) {
97-
throw JSONRPCError(RPC_INVALID_PARAMETER,
98-
strprintf("Invalid param for %s, ProTx version only supports ports", field_name));
101+
if (input.isArray()) {
102+
const UniValue& entries = input.get_array();
103+
for (size_t idx{0}; idx < entries.size(); idx++) {
104+
const UniValue& entry{entries[idx]};
105+
if (!entry.isStr() || IsNumeric(entry.get_str())) {
106+
throw JSONRPCError(RPC_INVALID_PARAMETER,
107+
strprintf("Invalid param for %s[%zu], must be string", field_name, idx));
108+
}
109+
ParseInput(ptx, field_name, entry.get_str(), purpose, idx, /*optional=*/false);
110+
}
111+
} else {
112+
CHECK_NONFATAL(is_empty || is_nonnumeric_str);
113+
ParseInput(ptx, field_name, input.get_str(), purpose, /*idx=*/0, /*optional=*/true);
99114
}
100-
ParseInput(ptx, field_name, input.get_str(), purpose, /*idx=*/0, /*optional=*/false);
101115
} else {
102-
if (int32_t port{0}; ParseInt32(input_str, &port) && port >= 1 && port <= std::numeric_limits<uint16_t>::max()) {
116+
if (int32_t port{0};
117+
ParseInt32(input.getValStr(), &port) && port >= 1 && port <= std::numeric_limits<uint16_t>::max()) {
103118
// Valid port
104119
if (!ptx.netInfo->CanStorePlatform()) {
105120
maybe_target = static_cast<uint16_t>(port);
@@ -122,5 +137,5 @@ void ProcessNetInfoPlatform(ProTx& ptx, const UniValue& input_p2p, const UniValu
122137
process_field(ptx.platformP2PPort, input_p2p, NetInfoPurpose::PLATFORM_P2P, "platformP2PPort");
123138
process_field(ptx.platformHTTPPort, input_http, NetInfoPurpose::PLATFORM_HTTPS, "platformHTTPPort");
124139
}
125-
template void ProcessNetInfoPlatform(CProRegTx& ptx, const UniValue& input_p2p, const UniValue& input_http);
126-
template void ProcessNetInfoPlatform(CProUpServTx& ptx, const UniValue& input_p2p, const UniValue& input_http);
140+
template void ProcessNetInfoPlatform(CProRegTx& ptx, const UniValue& input_p2p, const UniValue& input_http, const bool optional);
141+
template void ProcessNetInfoPlatform(CProUpServTx& ptx, const UniValue& input_p2p, const UniValue& input_http, const bool optional);

test/functional/rpc_netinfo.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,11 @@ def test_validation_legacy(self):
206206
self.node_evo.register_mn(self, False, f"127.0.0.1:{self.node_evo.mn.nodePort}", f"127.0.0.1:{DEFAULT_PORT_PLATFORM_P2P}", DEFAULT_PORT_PLATFORM_HTTP,
207207
-8, "Invalid param for platformP2PPort, ProTx version only supports ports")
208208
self.node_evo.register_mn(self, False, f"127.0.0.1:{self.node_evo.mn.nodePort}", [f"127.0.0.1:{DEFAULT_PORT_PLATFORM_P2P}"], DEFAULT_PORT_PLATFORM_HTTP,
209-
-8, "Invalid param for platformP2PPort, must be number")
209+
-8, "Invalid param for platformP2PPort, ProTx version only supports ports")
210210
self.node_evo.register_mn(self, False, f"127.0.0.1:{self.node_evo.mn.nodePort}", DEFAULT_PORT_PLATFORM_P2P, f"127.0.0.1:{DEFAULT_PORT_PLATFORM_HTTP}",
211211
-8, "Invalid param for platformHTTPPort, ProTx version only supports ports")
212212
self.node_evo.register_mn(self, False, f"127.0.0.1:{self.node_evo.mn.nodePort}", DEFAULT_PORT_PLATFORM_P2P, [f"127.0.0.1:{DEFAULT_PORT_PLATFORM_HTTP}"],
213-
-8, "Invalid param for platformHTTPPort, must be number")
213+
-8, "Invalid param for platformHTTPPort, ProTx version only supports ports")
214214

215215
def test_deprecation(self):
216216
# netInfo is represented with JSON in CProRegTx, CProUpServTx, CDeterministicMNState and CSimplifiedMNListEntry,

0 commit comments

Comments
 (0)