mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-12 20:12:36 +02:00
[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.
This commit is contained in:
21
src/net.cpp
21
src/net.cpp
@ -1132,6 +1132,27 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
|
||||
RandAddEvent((uint32_t)id);
|
||||
}
|
||||
|
||||
bool CConnman::AddConnection(const std::string& address, ConnectionType conn_type)
|
||||
{
|
||||
if (conn_type != ConnectionType::OUTBOUND_FULL_RELAY && conn_type != ConnectionType::BLOCK_RELAY) return false;
|
||||
|
||||
const int max_connections = conn_type == ConnectionType::OUTBOUND_FULL_RELAY ? m_max_outbound_full_relay : m_max_outbound_block_relay;
|
||||
|
||||
// Count existing connections
|
||||
int existing_connections = WITH_LOCK(cs_vNodes,
|
||||
return std::count_if(vNodes.begin(), vNodes.end(), [conn_type](CNode* node) { return node->m_conn_type == conn_type; }););
|
||||
|
||||
// Max connections of specified type already exist
|
||||
if (existing_connections >= max_connections) return false;
|
||||
|
||||
// Max total outbound connections already exist
|
||||
CSemaphoreGrant grant(*semOutbound, true);
|
||||
if (!grant) return false;
|
||||
|
||||
OpenNetworkConnection(CAddress(), false, &grant, address.c_str(), conn_type);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CConnman::DisconnectNodes()
|
||||
{
|
||||
{
|
||||
|
13
src/net.h
13
src/net.h
@ -955,6 +955,19 @@ public:
|
||||
bool RemoveAddedNode(const std::string& node);
|
||||
std::vector<AddedNodeInfo> GetAddedNodeInfo();
|
||||
|
||||
/**
|
||||
* Attempts to open a connection. Currently only used from tests.
|
||||
*
|
||||
* @param[in] address Address of node to try connecting to
|
||||
* @param[in] conn_type ConnectionType::OUTBOUND or ConnectionType::BLOCK_RELAY
|
||||
* @return bool Returns false if there are no available
|
||||
* slots for this connection:
|
||||
* - conn_type not a supported ConnectionType
|
||||
* - Max total outbound connection capacity filled
|
||||
* - Max connection capacity for type is filled
|
||||
*/
|
||||
bool AddConnection(const std::string& address, ConnectionType conn_type);
|
||||
|
||||
size_t GetNodeCount(NumConnections num);
|
||||
void GetNodeStats(std::vector<CNodeStats>& vstats);
|
||||
bool DisconnectNode(const std::string& node);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <rpc/server.h>
|
||||
|
||||
#include <banman.h>
|
||||
#include <chainparams.h>
|
||||
#include <clientversion.h>
|
||||
#include <core_io.h>
|
||||
#include <net.h>
|
||||
@ -314,6 +315,61 @@ static RPCHelpMan addnode()
|
||||
};
|
||||
}
|
||||
|
||||
static RPCHelpMan addconnection()
|
||||
{
|
||||
return RPCHelpMan{"addconnection",
|
||||
"\nOpen an outbound connection to a specified node. This RPC is for testing only.\n",
|
||||
{
|
||||
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The IP address and port to attempt connecting to."},
|
||||
{"connection_type", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of connection to open, either \"outbound-full-relay\" or \"block-relay-only\"."},
|
||||
},
|
||||
RPCResult{
|
||||
RPCResult::Type::OBJ, "", "",
|
||||
{
|
||||
{ RPCResult::Type::STR, "address", "Address of newly added connection." },
|
||||
{ RPCResult::Type::STR, "connection_type", "Type of connection opened." },
|
||||
}},
|
||||
RPCExamples{
|
||||
HelpExampleCli("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"")
|
||||
+ HelpExampleRpc("addconnection", "\"192.168.0.6:8333\" \"outbound-full-relay\"")
|
||||
},
|
||||
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||
{
|
||||
if (Params().NetworkIDString() != CBaseChainParams::REGTEST) {
|
||||
throw std::runtime_error("addconnection is for regression testing (-regtest mode) only.");
|
||||
}
|
||||
|
||||
RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VSTR});
|
||||
const std::string address = request.params[0].get_str();
|
||||
const std::string conn_type_in{TrimString(request.params[1].get_str())};
|
||||
ConnectionType conn_type{};
|
||||
if (conn_type_in == "outbound-full-relay") {
|
||||
conn_type = ConnectionType::OUTBOUND_FULL_RELAY;
|
||||
} else if (conn_type_in == "block-relay-only") {
|
||||
conn_type = ConnectionType::BLOCK_RELAY;
|
||||
} else {
|
||||
throw JSONRPCError(RPC_INVALID_PARAMETER, self.ToString());
|
||||
}
|
||||
|
||||
NodeContext& node = EnsureNodeContext(request.context);
|
||||
if (!node.connman) {
|
||||
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled.");
|
||||
}
|
||||
|
||||
const bool success = node.connman->AddConnection(address, conn_type);
|
||||
if (!success) {
|
||||
throw JSONRPCError(RPC_CLIENT_NODE_CAPACITY_REACHED, "Error: Already at capacity for specified connection type.");
|
||||
}
|
||||
|
||||
UniValue info(UniValue::VOBJ);
|
||||
info.pushKV("address", address);
|
||||
info.pushKV("connection_type", conn_type_in);
|
||||
|
||||
return info;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static RPCHelpMan disconnectnode()
|
||||
{
|
||||
return RPCHelpMan{"disconnectnode",
|
||||
@ -900,6 +956,8 @@ static const CRPCCommand commands[] =
|
||||
{ "network", "clearbanned", &clearbanned, {} },
|
||||
{ "network", "setnetworkactive", &setnetworkactive, {"state"} },
|
||||
{ "network", "getnodeaddresses", &getnodeaddresses, {"count"} },
|
||||
|
||||
{ "hidden", "addconnection", &addconnection, {"address", "connection_type"} },
|
||||
{ "hidden", "addpeeraddress", &addpeeraddress, {"address", "port"} },
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -62,6 +62,7 @@ enum RPCErrorCode
|
||||
RPC_CLIENT_NODE_NOT_CONNECTED = -29, //!< Node to disconnect not found in connected nodes
|
||||
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //!< Invalid IP/Subnet
|
||||
RPC_CLIENT_P2P_DISABLED = -31, //!< No valid connection manager instance found
|
||||
RPC_CLIENT_NODE_CAPACITY_REACHED= -34, //!< Max number of outbound or block-relay connections already open
|
||||
|
||||
//! Chain errors
|
||||
RPC_CLIENT_MEMPOOL_DISABLED = -33, //!< No mempool instance found
|
||||
|
Reference in New Issue
Block a user