Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p2p, rpc: Manual block-relay-only connections with addnode #24170

Closed
wants to merge 7 commits into from
8 changes: 8 additions & 0 deletions doc/release-notes-24170.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
RPC
---

- The RPC `addnode` and the `-addnode` bitcoind startup option now
optionally support adding manual peers that are block-relay-only.
On these connections, the node doesn't participate in transaction or
address relay. See bitcoind and RPC help documentation for parameter
semantics. (#24170)
20 changes: 18 additions & 2 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ void SetupServerArgs(ArgsManager& argsman)
" If <type> is not supplied or if <type> = 1, indexes for all known types are enabled.",
ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);

argsman.AddArg("-addnode=<ip>", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
argsman.AddArg("-addnode=<ip>[=manual-block-relay]", strprintf("Add a node to connect to and attempt to keep the connection open (see the addnode RPC help for more info). This option can be specified multiple times to add multiple nodes; connections are limited to %u at a time and are counted separately from the -maxconnections limit. Append =manual-block-relay to disable transaction and address relay.", MAX_ADDNODE_CONNECTIONS), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer =blocksonly to be clearer and match the existing -blocksonly option.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-blocksonly mode is different from block relay peers.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How so? Maybe it needs better docs on the difference...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't contrast.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some differences:

  • -blocksonly is a global startup option (applying to all connections) -block-relay-only is connection-specific
  • A node in -blocksonly mode participates in address relay, we never send out addresses on -block-relay-only connections (and ignore incoming ones).
  • A node in -blocksonly signals not to receive any transactions (fRelay) and will disconnect if that is breached, but it may in special cases send out transactions itself (if submitted via RPC). We'll never send a tx over a block-relay-only connection.
  • A node in -blocksonly mode still has two of their outbound connections as -block-relay-only (for which then the block-relay-only rules apply).

argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), signetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
Expand Down Expand Up @@ -1722,7 +1722,23 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
connOptions.m_msgproc = node.peerman.get();
connOptions.nSendBufferMaxSize = 1000 * args.GetIntArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER);
connOptions.nReceiveFloodSize = 1000 * args.GetIntArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER);
connOptions.m_added_nodes = args.GetArgs("-addnode");

std::vector<AddedNodeParams> added_nodes;
for (auto added_node : args.GetArgs("-addnode")) {
ConnectionType conn_type{ConnectionType::MANUAL};
const size_t index{added_node.rfind('=')};
if (index != std::string::npos) {
const std::string conn_name{added_node.substr(index + 1)};
if (conn_name == ConnectionTypeAsString(ConnectionType::MANUAL_BLOCK_RELAY)) {
added_node = added_node.substr(0, index);
conn_type = ConnectionType::MANUAL_BLOCK_RELAY;
} else {
Comment on lines +1732 to +1735
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also add the case for ConnectionType::MANUAL?

./src/bitcoind -addnode='test.local=manual'

2023-01-16T16:04:19Z Error: Invalid -addnode connection type: manual
Error: Invalid -addnode connection type: manual

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about this: Currently, the help for "addnode" states that only =manual-block-relay is possible (manual is the default). Adding this to the help might only complicate things for the user, because there would be no difference between =manual and no argument at all?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer not having =manual, it would add more stuff to the code and I believe it might complicate for the user, it's the default behavior, not sure why someone would want to specify it.

return InitError(strprintf(_("Invalid -addnode connection type: %s"), conn_name));
}
}
added_nodes.push_back(AddedNodeParams{added_node, conn_type});
}
connOptions.m_added_nodes = added_nodes;
connOptions.nMaxOutboundLimit = *opt_max_upload;
connOptions.m_peer_connect_timeout = peer_connect_timeout;

Expand Down
55 changes: 29 additions & 26 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1079,11 +1079,12 @@ bool CConnman::AddConnection(const std::string& address, ConnectionType conn_typ
switch (conn_type) {
case ConnectionType::INBOUND:
case ConnectionType::MANUAL:
case ConnectionType::MANUAL_BLOCK_RELAY:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addconnection rpc should not support manual block relay, so seems here need not check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's true that it doesn't support this, just as it doesn't support INBOUND or MANUAL. But leaving it out her would result in a compiler warning for the switch, see comment below:
// no default case, so the compiler can warn about missing cases

return false;
case ConnectionType::OUTBOUND_FULL_RELAY:
max_connections = m_max_outbound_full_relay;
break;
case ConnectionType::BLOCK_RELAY:
case ConnectionType::AUTOMATIC_BLOCK_RELAY:
max_connections = m_max_outbound_block_relay;
break;
// no limit for ADDR_FETCH because -seednode has no limit either
Expand Down Expand Up @@ -1587,7 +1588,7 @@ int CConnman::GetExtraBlockRelayCount() const
{
LOCK(m_nodes_mutex);
for (const CNode* pnode : m_nodes) {
if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) {
if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsAutomaticBlockRelayConn()) {
++block_relay_peers;
}
}
Expand Down Expand Up @@ -1713,7 +1714,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
LOCK(m_nodes_mutex);
for (const CNode* pnode : m_nodes) {
if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;
if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;
if (pnode->IsAutomaticBlockRelayConn()) nOutboundBlockRelay++;

// Make sure our persistent outbound slots to ipv4/ipv6 peers belong to different netgroups.
switch (pnode->m_conn_type) {
Expand All @@ -1727,8 +1728,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
case ConnectionType::FEELER:
break;
case ConnectionType::MANUAL:
case ConnectionType::MANUAL_BLOCK_RELAY:
case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
case ConnectionType::AUTOMATIC_BLOCK_RELAY:
CAddress address{pnode->addr};
if (address.IsTor() || address.IsI2P() || address.IsCJDNS()) {
// Since our addrman-groups for these networks are
Expand All @@ -1752,9 +1754,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
bool fFeeler = false;

// Determine what type of connection to open. Opening
// BLOCK_RELAY connections to addresses from anchors.dat gets the highest
// AUTOMATIC_BLOCK_RELAY connections to addresses from anchors.dat gets the highest
// priority. Then we open OUTBOUND_FULL_RELAY priority until we
// meet our full-relay capacity. Then we open BLOCK_RELAY connection
// meet our full-relay capacity. Then we open AUTOMATIC_BLOCK_RELAY connection
// until we hit our block-relay-only peer limit.
// GetTryNewOutboundPeer() gets set when a stale tip is detected, so we
// try opening an additional OUTBOUND_FULL_RELAY connection. If none of
Expand All @@ -1763,12 +1765,12 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// timer to decide if we should open a FEELER.

if (!m_anchors.empty() && (nOutboundBlockRelay < m_max_outbound_block_relay)) {
conn_type = ConnectionType::BLOCK_RELAY;
conn_type = ConnectionType::AUTOMATIC_BLOCK_RELAY;
anchor = true;
} else if (nOutboundFullRelay < m_max_outbound_full_relay) {
// OUTBOUND_FULL_RELAY
} else if (nOutboundBlockRelay < m_max_outbound_block_relay) {
conn_type = ConnectionType::BLOCK_RELAY;
conn_type = ConnectionType::AUTOMATIC_BLOCK_RELAY;
} else if (GetTryNewOutboundPeer()) {
// OUTBOUND_FULL_RELAY
} else if (now > next_extra_block_relay && m_start_extra_block_relay_peers) {
Expand All @@ -1794,7 +1796,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// connections, they do not get their own ConnectionType enum
// (similar to how we deal with extra outbound peers).
next_extra_block_relay = GetExponentialRand(now, EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);
conn_type = ConnectionType::BLOCK_RELAY;
conn_type = ConnectionType::AUTOMATIC_BLOCK_RELAY;
} else if (now > next_feeler) {
next_feeler = GetExponentialRand(now, FEELER_INTERVAL);
conn_type = ConnectionType::FEELER;
Expand Down Expand Up @@ -1908,12 +1910,12 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
}
}

std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const
std::vector<CAddress> CConnman::GetCurrentAutomaticBlockRelayConns() const
{
std::vector<CAddress> ret;
LOCK(m_nodes_mutex);
for (const CNode* pnode : m_nodes) {
if (pnode->IsBlockOnlyConn()) {
if (pnode->IsAutomaticBlockRelayConn()) {
ret.push_back(pnode->addr);
}
}
Expand All @@ -1925,7 +1927,7 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
{
std::vector<AddedNodeInfo> ret;

std::list<std::string> lAddresses(0);
std::list<AddedNodeParams> lAddresses(0);
{
LOCK(m_added_nodes_mutex);
ret.reserve(m_added_nodes.size());
Expand All @@ -1949,20 +1951,20 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo() const
}
}

for (const std::string& strAddNode : lAddresses) {
CService service(LookupNumeric(strAddNode, Params().GetDefaultPort(strAddNode)));
AddedNodeInfo addedNode{strAddNode, CService(), false, false};
for (const auto& node_to_add : lAddresses) {
CService service(LookupNumeric(node_to_add.m_node_address, Params().GetDefaultPort(node_to_add.m_node_address)));
AddedNodeInfo addedNode{node_to_add, CService(), /*fConnected=*/false, /*fInbound=*/false};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
AddedNodeInfo addedNode{node_to_add, CService(), /*fConnected=*/false, /*fInbound=*/false};
AddedNodeInfo addedNode{
.m_params{node_to_add},
.resolvedAddress{CService()},
.fConnected{false},
.fInbound{false}};

Copy link
Contributor Author

@mzumsande mzumsande Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer the more concise version here, especially when most of the args are just defaults that are set to their actual values in the following lines. Also see below.

if (service.IsValid()) {
// strAddNode is an IP:port
// node address is an IP:port
auto it = mapConnected.find(service);
if (it != mapConnected.end()) {
addedNode.resolvedAddress = service;
addedNode.fConnected = true;
addedNode.fInbound = it->second;
}
} else {
// strAddNode is a name
auto it = mapConnectedByName.find(strAddNode);
// node address is a name
auto it = mapConnectedByName.find(node_to_add.m_node_address);
if (it != mapConnectedByName.end()) {
addedNode.resolvedAddress = it->second.second;
addedNode.fConnected = true;
Expand Down Expand Up @@ -1993,7 +1995,7 @@ void CConnman::ThreadOpenAddedConnections()
}
tried = true;
CAddress addr(CService(), NODE_NONE);
OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), ConnectionType::MANUAL);
OpenNetworkConnection(addr, false, &grant, info.m_params.m_node_address.c_str(), info.m_params.m_conn_type);
if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
return;
}
Expand Down Expand Up @@ -2482,7 +2484,7 @@ void CConnman::StopNodes()

if (m_use_addrman_outgoing) {
// Anchor connections are only dumped during clean shutdown.
std::vector<CAddress> anchors_to_dump = GetCurrentBlockRelayOnlyConns();
std::vector<CAddress> anchors_to_dump = GetCurrentAutomaticBlockRelayConns();
if (anchors_to_dump.size() > MAX_BLOCK_RELAY_ONLY_ANCHORS) {
anchors_to_dump.resize(MAX_BLOCK_RELAY_ONLY_ANCHORS);
}
Expand Down Expand Up @@ -2575,22 +2577,23 @@ std::vector<CAddress> CConnman::GetAddresses(CNode& requestor, size_t max_addres
return cache_entry.m_addrs_response_cache;
}

bool CConnman::AddNode(const std::string& strNode)
bool CConnman::AddNode(const std::string& strNode, ConnectionType conn_type)
mzumsande marked this conversation as resolved.
Show resolved Hide resolved
{
LOCK(m_added_nodes_mutex);
for (const std::string& it : m_added_nodes) {
if (strNode == it) return false;
assert(conn_type == ConnectionType::MANUAL || conn_type == ConnectionType::MANUAL_BLOCK_RELAY);
for (const auto& it : m_added_nodes) {
if (strNode == it.m_node_address) return false;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Supposed option modify case need not be handled?
If add node firstly with setting manual and then setting manual block relay.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, a modify option is not supported, especially since it is not possible to change the connection connection type of an existing connection. A user could instead use the 'remove' option and then re-add with another connection type (which would not change existing connections though).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be an option to use std::any_of here if using standard library algorithms is preferable, but personally I think it might end up a little less readable.

}

m_added_nodes.push_back(strNode);
m_added_nodes.push_back({strNode, conn_type});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
m_added_nodes.push_back({strNode, conn_type});
m_added_nodes.push_back(AddedNodeParams{
.m_node_address{strNode},
.m_conn_type{conn_type}});

Copy link
Contributor Author

@mzumsande mzumsande Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tried it, but the CI doesn't like it: designated initializers are C++20-only?

return true;
}

bool CConnman::RemoveAddedNode(const std::string& strNode)
{
LOCK(m_added_nodes_mutex);
for(std::vector<std::string>::iterator it = m_added_nodes.begin(); it != m_added_nodes.end(); ++it) {
if (strNode == *it) {
for (auto it = m_added_nodes.begin(); it != m_added_nodes.end(); ++it) {
if (strNode == it->m_node_address) {
m_added_nodes.erase(it);
return true;
}
Expand Down
54 changes: 35 additions & 19 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,14 +93,6 @@ static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;

typedef int64_t NodeId;

struct AddedNodeInfo
{
std::string strAddedNode;
CService resolvedAddress;
bool fConnected;
bool fInbound;
};

class CNodeStats;
class CClientUIInterface;

Expand All @@ -124,6 +116,18 @@ struct CSerializedNetMsg {
std::string m_type;
};

struct AddedNodeParams {
std::string m_node_address;
ConnectionType m_conn_type;
};

struct AddedNodeInfo {
AddedNodeParams m_params;
CService resolvedAddress;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would be the difference between resolvedAddress and m_node_address?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

m_node_address is a string, which is part of AddedNodeParams, which has just the unvalidated user input.

resolvedAddress is a CService built from m_node_address, which is generated in GetAddedNodeInfo and used in ThreadOpenConnection / rpc code.

bool fConnected;
bool fInbound;
};

/**
* Look up IP addresses from all interfaces on the machine and add them to the
* list of local addresses to self-advertise.
Expand Down Expand Up @@ -440,15 +444,16 @@ class CNode
mapSendBytesPerMsgType[msg_type] += sent_bytes;
}

bool IsOutboundOrBlockRelayConn() const {
bool IsAutomaticOutboundOrBlockRelayConn() const {
switch (m_conn_type) {
case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
case ConnectionType::AUTOMATIC_BLOCK_RELAY:
return true;
case ConnectionType::INBOUND:
case ConnectionType::MANUAL:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
case ConnectionType::MANUAL_BLOCK_RELAY:
return false;
Comment on lines +456 to 457
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be confused, but why don't we wanna consider MANUAL_BLOCK_RELAY as Outbound and BlockRelay?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used in net_processing in places suchas ConsiderEviction() where we wouldn't want to consider manual connections.
I think the name "IsOutboundOrBlockRelayConn" isn't ideal (even before this PR, because manual connections are also outbound connections), maybe the name "IsAutomaticOutboundOrBlockRelayConn" would be better. I added a commit to do that.

} // no default case, so the compiler can warn about missing cases

Expand All @@ -463,8 +468,8 @@ class CNode
return m_conn_type == ConnectionType::MANUAL;
}

bool IsBlockOnlyConn() const {
return m_conn_type == ConnectionType::BLOCK_RELAY;
bool IsAutomaticBlockRelayConn() const {
return m_conn_type == ConnectionType::AUTOMATIC_BLOCK_RELAY;
}

bool IsFeelerConn() const {
Expand All @@ -479,14 +484,25 @@ class CNode
return m_conn_type == ConnectionType::INBOUND;
}

bool IsManualBlockRelayConn() const
jnewbery marked this conversation as resolved.
Show resolved Hide resolved
{
return m_conn_type == ConnectionType::MANUAL_BLOCK_RELAY;
}

bool IsBlockRelayConn() const
{
return IsAutomaticBlockRelayConn() || IsManualBlockRelayConn();
}

bool ExpectServicesFromConn() const {
switch (m_conn_type) {
case ConnectionType::INBOUND:
case ConnectionType::MANUAL:
case ConnectionType::MANUAL_BLOCK_RELAY:
case ConnectionType::FEELER:
return false;
case ConnectionType::OUTBOUND_FULL_RELAY:
case ConnectionType::BLOCK_RELAY:
case ConnectionType::AUTOMATIC_BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
return true;
} // no default case, so the compiler can warn about missing cases
Expand Down Expand Up @@ -719,7 +735,7 @@ class CConnman
bool bind_on_any;
bool m_use_addrman_outgoing = true;
std::vector<std::string> m_specified_outgoing;
std::vector<std::string> m_added_nodes;
std::vector<AddedNodeParams> m_added_nodes;
bool m_i2p_accept_incoming;
};

Expand Down Expand Up @@ -832,15 +848,15 @@ class CConnman
// Count the number of block-relay-only peers we have over our limit.
int GetExtraBlockRelayCount() const;

bool AddNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
bool AddNode(const std::string& node, ConnectionType conn_type) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
bool RemoveAddedNode(const std::string& node) EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);
std::vector<AddedNodeInfo> GetAddedNodeInfo() const EXCLUSIVE_LOCKS_REQUIRED(!m_added_nodes_mutex);

/**
* 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, ConnectionType::BLOCK_RELAY,
* @param[in] conn_type ConnectionType::OUTBOUND, ConnectionType::AUTOMATIC_BLOCK_RELAY,
* ConnectionType::ADDR_FETCH or ConnectionType::FEELER
* @return bool Returns false if there are no available
* slots for this connection:
Expand Down Expand Up @@ -1004,9 +1020,9 @@ class CConnman
std::unordered_set<Network> GetReachableEmptyNetworks() const;

/**
* Return vector of current BLOCK_RELAY peers.
* Return vector of current AUTOMATIC_BLOCK_RELAY peers.
*/
std::vector<CAddress> GetCurrentBlockRelayOnlyConns() const;
std::vector<CAddress> GetCurrentAutomaticBlockRelayConns() const;

// Whether the node should be passed out in ForEach* callbacks
static bool NodeFullyConnected(const CNode* pnode);
Expand Down Expand Up @@ -1038,7 +1054,7 @@ class CConnman
const NetGroupManager& m_netgroupman;
std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
Mutex m_addr_fetches_mutex;
std::vector<std::string> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
std::vector<AddedNodeParams> m_added_nodes GUARDED_BY(m_added_nodes_mutex);
mutable Mutex m_added_nodes_mutex;
std::vector<CNode*> m_nodes GUARDED_BY(m_nodes_mutex);
std::list<CNode*> m_nodes_disconnected;
Expand Down
Loading