Skip to content

Commit 5bc04e8

Browse files
committed
[rpc/net] Introduce addconnection to test outbounds & blockrelay
Add a new RPC endpoint to enable opening outbound connections from the tests. The functional test framework currently uses the addnode RPC, which has different behavior than general outbound peers. These changes enable creating both full-relay and block-relay-only connections. The new RPC endpoint calls through to a newly introduced AddConnection method on CConnman that ensures we stay within the allocated max.
1 parent b6a71b8 commit 5bc04e8

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

src/net.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,27 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
11321132
RandAddEvent((uint32_t)id);
11331133
}
11341134

1135+
bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
1136+
{
1137+
if (conn_type != ConnectionType::OUTBOUND_FULL_RELAY && conn_type != ConnectionType::BLOCK_RELAY) return false;
1138+
1139+
const int max_connections = conn_type == ConnectionType::OUTBOUND_FULL_RELAY ? m_max_outbound_full_relay : m_max_outbound_block_relay;
1140+
1141+
// Count existing connections
1142+
int existing_connections = WITH_LOCK(cs_vNodes,
1143+
return std::count_if(vNodes.begin(), vNodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
1144+
1145+
// Max connections of specified type already exist
1146+
if (existing_connections >= max_connections) return false;
1147+
1148+
// Max total outbound connections already exist
1149+
CSemaphoreGrant grant(*semOutbound, true);
1150+
if (!grant) return false;
1151+
1152+
OpenNetworkConnection(CAddress(), false, &grant, address.c_str(), conn_type);
1153+
return true;
1154+
}
1155+
11351156
void CConnman::DisconnectNodes()
11361157
{
11371158
{

src/net.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,19 @@ class CConnman
955955
bool RemoveAddedNode(const std::string& node);
956956
std::vector<AddedNodeInfo> GetAddedNodeInfo();
957957

958+
/**
959+
* Attempts to open a connection. Currently only used from tests.
960+
*
961+
* @param[in] address Address of node to try connecting to
962+
* @param[in] conn_type ConnectionType::OUTBOUND or ConnectionType::BLOCK_RELAY
963+
* @return bool Returns false if there are no available
964+
* slots for this connection:
965+
* - conn_type not a supported ConnectionType
966+
* - Max total outbound connection capacity filled
967+
* - Max connection capacity for type is filled
968+
*/
969+
bool AddConnection(const std::string& address, ConnectionType conn_type);
970+
958971
size_t GetNodeCount(NumConnections num);
959972
void GetNodeStats(std::vector<CNodeStats>& vstats);
960973
bool DisconnectNode(const std::string& node);

src/rpc/net.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <rpc/server.h>
66

77
#include <banman.h>
8+
#include <chainparams.h>
89
#include <clientversion.h>
910
#include <core_io.h>
1011
#include <net.h>
@@ -314,6 +315,61 @@ static RPCHelpMan addnode()
314315
};
315316
}
316317

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+
317373
static RPCHelpMan disconnectnode()
318374
{
319375
return RPCHelpMan{"disconnectnode",
@@ -900,6 +956,8 @@ static const CRPCCommand commands[] =
900956
{ "network", "clearbanned", &clearbanned, {} },
901957
{ "network", "setnetworkactive", &setnetworkactive, {"state"} },
902958
{ "network", "getnodeaddresses", &getnodeaddresses, {"count"} },
959+
960+
{ "hidden", "addconnection", &addconnection, {"address", "connection_type"} },
903961
{ "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} },
904962
};
905963
// clang-format on

src/rpc/protocol.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum RPCErrorCode
6262
RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
6363
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
6464
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
65+
RPC_CLIENT_NODE_CAPACITY_REACHED= -34, //!< Max number of outbound or block-relay connections already open
6566

6667
//! Chain errors
6768
RPC_CLIENT_MEMPOOL_DISABLED = -33, //!< No mempool instance found

0 commit comments

Comments
 (0)