aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAmiti Uttarwar <amiti@uttarwar.org>2020-06-02 09:46:41 -0700
committerAmiti Uttarwar <amiti@uttarwar.org>2021-01-07 10:15:56 -0800
commit5bc04e8837c0452923cebd1b823a85e5c4dcdfa6 (patch)
tree53e4946c569cd17b054d7dc57854001f3630f569 /src
parentb6a71b80d28c79796b557cdb6bae05abb34d1225 (diff)
downloadbitcoin-5bc04e8837c0452923cebd1b823a85e5c4dcdfa6.tar.xz
[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.
Diffstat (limited to 'src')
-rw-r--r--src/net.cpp21
-rw-r--r--src/net.h13
-rw-r--r--src/rpc/net.cpp58
-rw-r--r--src/rpc/protocol.h1
4 files changed, 93 insertions, 0 deletions
diff --git a/src/net.cpp b/src/net.cpp
index ad4af4abb2..6050e1354c 100644
--- a/src/net.cpp
+++ b/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()
{
{
diff --git a/src/net.h b/src/net.h
index acc1da49a5..2973ddd0b9 100644
--- a/src/net.h
+++ b/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);
diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp
index 89ddfb35cb..a96d9d774b 100644
--- a/src/rpc/net.cpp
+++ b/src/rpc/net.cpp
@@ -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
diff --git a/src/rpc/protocol.h b/src/rpc/protocol.h
index d1475f452d..c8ceb2c186 100644
--- a/src/rpc/protocol.h
+++ b/src/rpc/protocol.h
@@ -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