|
5 | 5 | #include <rpc/server.h>
|
6 | 6 |
|
7 | 7 | #include <banman.h>
|
| 8 | +#include <chainparams.h> |
8 | 9 | #include <clientversion.h>
|
9 | 10 | #include <core_io.h>
|
10 | 11 | #include <net.h>
|
@@ -314,6 +315,61 @@ static RPCHelpMan addnode()
|
314 | 315 | };
|
315 | 316 | }
|
316 | 317 |
|
| 318 | +static RPCHelpMan addconnection() |
| 319 | +{ |
| 320 | + return RPCHelpMan{"addconnection", |
| 321 | + "\nOpen an outbound connection to a specified node. This RPC is for testing only.\n", |
| 322 | + { |
| 323 | + {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."}, |
| 324 | + {"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open, either \"outbound-full-relay\" or \"block-relay-only\"."}, |
| 325 | + }, |
| 326 | + RPCResult{ |
| 327 | + RPCResult::Type::OBJ, "", "", |
| 328 | + { |
| 329 | + { RPCResult::Type::STR, "address", "Address of newly added connection." }, |
| 330 | + { RPCResult::Type::STR, "connection_type", "Type of connection opened." }, |
| 331 | + }}, |
| 332 | + RPCExamples{ |
| 333 | + HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"") |
| 334 | + + HelpExampleRpc("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"") |
| 335 | + }, |
| 336 | + [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue |
| 337 | +{ |
| 338 | + if (Params().NetworkIDString() != CBaseChainParams::REGTEST) { |
| 339 | + throw std::runtime_error("addconnection is for regression testing (-regtest mode) only."); |
| 340 | + } |
| 341 | + |
| 342 | + RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR}); |
| 343 | + const std::string address = request.params[0].get_str(); |
| 344 | + const std::string conn_type_in{TrimString(request.params[1].get_str())}; |
| 345 | + ConnectionType conn_type{}; |
| 346 | + if (conn_type_in == "outbound-full-relay") { |
| 347 | + conn_type = ConnectionType::OUTBOUND_FULL_RELAY; |
| 348 | + } else if (conn_type_in == "block-relay-only") { |
| 349 | + conn_type = ConnectionType::BLOCK_RELAY; |
| 350 | + } else { |
| 351 | + throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString()); |
| 352 | + } |
| 353 | + |
| 354 | + NodeContext& node = EnsureNodeContext(request.context); |
| 355 | + if (!node.connman) { |
| 356 | + throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled."); |
| 357 | + } |
| 358 | + |
| 359 | + const bool success = node.connman->AddConnection(address, conn_type); |
| 360 | + if (!success) { |
| 361 | + throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type."); |
| 362 | + } |
| 363 | + |
| 364 | + UniValue info(UniValue::VOBJ); |
| 365 | + info.pushKV("address", address); |
| 366 | + info.pushKV("connection_type", conn_type_in); |
| 367 | + |
| 368 | + return info; |
| 369 | +}, |
| 370 | + }; |
| 371 | +} |
| 372 | + |
317 | 373 | static RPCHelpMan disconnectnode()
|
318 | 374 | {
|
319 | 375 | return RPCHelpMan{"disconnectnode",
|
@@ -900,6 +956,8 @@ static const CRPCCommand commands[] =
|
900 | 956 | { "network", "clearbanned", &clearbanned, {} },
|
901 | 957 | { "network", "setnetworkactive", &setnetworkactive, {"state"} },
|
902 | 958 | { "network", "getnodeaddresses", &getnodeaddresses, {"count"} },
|
| 959 | + |
| 960 | + { "hidden", "addconnection", &addconnection, {"address", "connection_type"} }, |
903 | 961 | { "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} },
|
904 | 962 | };
|
905 | 963 | // clang-format on
|
|
0 commit comments