0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-03-05 14:06:27 -05:00

Merge #19316: [net] Cleanup logic around connection types

01e283068b [net] Remove unnecessary default args on CNode constructor (Amiti Uttarwar)
bc5d65b3ca [refactor] Remove IsOutboundDisconnectionCandidate (Amiti Uttarwar)
2f2e13b6c2 [net/refactor] Simplify multiple-connection checks (Amiti Uttarwar)
7f7b83deb2 [net/refactor] Rework ThreadOpenConnections logic (Amiti Uttarwar)
35839e963b [net] Fix bug where AddrFetch connections would be counted as outbound full relay (Amiti Uttarwar)
4972c21b67 [net/refactor] Clarify logic for selecting connections in ThreadOpenConnections (Amiti Uttarwar)
60156f5fc4 [net/refactor] Remove fInbound flag from CNode (Amiti Uttarwar)
7b322df629 [net/refactor] Remove m_addr_fetch member var from CNode (Amiti Uttarwar)
14923422b0 [net/refactor] Remove fFeeler flag from CNode (Amiti Uttarwar)
49efac5cae [net/refactor] Remove m_manual_connection flag from CNode (Amiti Uttarwar)
d3698b5ee3 [net/refactor] Add connection type as a member var to CNode (Amiti Uttarwar)
46578c03e9 [doc] Describe different connection types (Amiti Uttarwar)
442abae2ba [net/refactor] Add AddrFetch connections to ConnectionType enum (Amiti Uttarwar)
af59feb052 [net/refactor] Extract m_addr_known logic from initializer list (Amiti Uttarwar)
e1bc29812d [net/refactor] Add block relay only connections to ConnectionType enum (Amiti Uttarwar)
0e52a659a2 [net/refactor] Add feeler connections to ConnectionType enum (Amiti Uttarwar)
1521c47438 [net/refactor] Add manual connections to ConnectionType enum (Amiti Uttarwar)
26304b4100 [net/refactor] Introduce an enum to distinguish type of connection (Amiti Uttarwar)
3f1b7140e9 scripted-diff: Rename OneShot to AddrFetch (Amiti Uttarwar)

Pull request description:

  **This is part 1 of #19315, which enables the ability to test `outbound` and `block-relay-only` connections from the functional tests.** Please see that PR for more information of overall functionality.

  **This PR simplifies how we manage different connection types.** It introduces an enum with the various types of connections so we can explicitly define the connection type. The existing system relies on a series of independent flags, then has asserts scattered around to ensure that conflicting flags are not enabled at the same time. I find this approach to be both brittle and confusing. While making these changes, I found a small bug due to the silent assumptions.

  This PR also proposes a rename from `OneShot` to `AddrFetch`. I find the name `OneShot` to be very confusing, especially when we also have `onetry` manual connections. Everyone I've talked to offline has agreed that the name is confusing, so I propose a potential alternative. I think this is a good opportunity for a rename since I'm creating an enum to explicitly define the connection types.
  (some context for the unfamiliar: `oneshot` or `addrfetch` connections are short-lived connections created on startup. They connect to the seed peers, send a `getaddr` to solicit addresses, then close the connection.)

  Overview of this PR:
  * rename `oneshot` to `addrfetch`
  * introduce `ConnectionType` enum
  * one by one, add different connection types to the enum
  * expose the `conn_type` on CNode, and use this to reduce reliance on flags (& asserts)
  * fix the bug in counting different type of connections
  * some additional cleanup to simplify logic and make expectations explicit/inclusive rather than implicit/exclusive.

ACKs for top commit:
  jnewbery:
    utACK 01e283068b
  laanwj:
    Code review ACK 01e283068b, the commits are pretty straightforward to follow, and I think this is a move in the right direction overall
  vasild:
    ACK 01e283068
  sdaftuar:
    ACK 01e283068b.
  fanquake:
    ACK 01e283068b - I don't have as much experience with the networking code but these changes look fairly straight forward, the new code seems more robust/understandable and the additional documentation is great. I'm glad that a followup branch is already underway. There might be some more review comments here later today, so keep an eye on the discussion, however I'm going to merge this now.
  jb55:
    wow this code was messy before... ACK 01e283068b

Tree-SHA512: 7bb644a6ed5849913d777ebc2ff89133ca0fbef680355a9a344e07496a979e6f9ff21a958e8eea93dcd7d5c343682b0c7174b1a3de380a4247eaae73da436e15
This commit is contained in:
fanquake 2020-08-12 09:41:24 +08:00
commit ce3bdd0ed1
No known key found for this signature in database
GPG key ID: 2EEB9F5CC09526C1
9 changed files with 186 additions and 140 deletions

View file

@ -110,7 +110,7 @@ public:
// Note that of those which support the service bits prefix, most only support a subset of // Note that of those which support the service bits prefix, most only support a subset of
// possible options. // possible options.
// This is fine at runtime as we'll fall back to using them as a oneshot if they don't support the // This is fine at runtime as we'll fall back to using them as an addrfetch if they don't support the
// service bits we want, but we should get them updated to support all service bits wanted by any // service bits we want, but we should get them updated to support all service bits wanted by any
// release ASAP to avoid it where possible. // release ASAP to avoid it where possible.
vSeeds.emplace_back("seed.bitcoin.sipa.be"); // Pieter Wuille, only supports x1, x5, x9, and xd vSeeds.emplace_back("seed.bitcoin.sipa.be"); // Pieter Wuille, only supports x1, x5, x9, and xd

View file

@ -105,10 +105,10 @@ std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(cs_mapLocalHost);
static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {}; static bool vfLimited[NET_MAX] GUARDED_BY(cs_mapLocalHost) = {};
std::string strSubVersion; std::string strSubVersion;
void CConnman::AddOneShot(const std::string& strDest) void CConnman::AddAddrFetch(const std::string& strDest)
{ {
LOCK(cs_vOneShots); LOCK(m_addr_fetches_mutex);
vOneShots.push_back(strDest); m_addr_fetches.push_back(strDest);
} }
uint16_t GetListenPort() uint16_t GetListenPort()
@ -346,7 +346,7 @@ bool CConnman::CheckIncomingNonce(uint64_t nonce)
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) { for (const CNode* pnode : vNodes) {
if (!pnode->fSuccessfullyConnected && !pnode->fInbound && pnode->GetLocalNonce() == nonce) if (!pnode->fSuccessfullyConnected && !pnode->IsInboundConn() && pnode->GetLocalNonce() == nonce)
return false; return false;
} }
return true; return true;
@ -368,8 +368,10 @@ static CAddress GetBindAddress(SOCKET sock)
return addr_bind; return addr_bind;
} }
CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection, bool block_relay_only) CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type)
{ {
assert(conn_type != ConnectionType::INBOUND);
if (pszDest == nullptr) { if (pszDest == nullptr) {
if (IsLocal(addrConnect)) if (IsLocal(addrConnect))
return nullptr; return nullptr;
@ -432,7 +434,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
if (hSocket == INVALID_SOCKET) { if (hSocket == INVALID_SOCKET) {
return nullptr; return nullptr;
} }
connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout, manual_connection); connected = ConnectSocketDirectly(addrConnect, hSocket, nConnectTimeout, conn_type == ConnectionType::MANUAL);
} }
if (!proxyConnectionFailed) { if (!proxyConnectionFailed) {
// If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to // If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to
@ -459,7 +461,7 @@ CNode* CConnman::ConnectNode(CAddress addrConnect, const char *pszDest, bool fCo
NodeId id = GetNewNodeId(); NodeId id = GetNewNodeId();
uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize(); uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();
CAddress addr_bind = GetBindAddress(hSocket); CAddress addr_bind = GetBindAddress(hSocket);
CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", false, block_relay_only); CNode* pnode = new CNode(id, nLocalServices, GetBestHeight(), hSocket, addrConnect, CalculateKeyedNetGroup(addrConnect), nonce, addr_bind, pszDest ? pszDest : "", conn_type);
pnode->AddRef(); pnode->AddRef();
// We're making a new connection, harvest entropy from the time (and our peer count) // We're making a new connection, harvest entropy from the time (and our peer count)
@ -536,8 +538,8 @@ void CNode::copyStats(CNodeStats &stats, const std::vector<bool> &m_asmap)
LOCK(cs_SubVer); LOCK(cs_SubVer);
X(cleanSubVer); X(cleanSubVer);
} }
X(fInbound); stats.fInbound = IsInboundConn();
X(m_manual_connection); stats.m_manual_connection = IsManualConn();
X(nStartingHeight); X(nStartingHeight);
{ {
LOCK(cs_vSend); LOCK(cs_vSend);
@ -872,7 +874,7 @@ bool CConnman::AttemptToEvictConnection()
for (const CNode* node : vNodes) { for (const CNode* node : vNodes) {
if (node->HasPermission(PF_NOBAN)) if (node->HasPermission(PF_NOBAN))
continue; continue;
if (!node->fInbound) if (!node->IsInboundConn())
continue; continue;
if (node->fDisconnect) if (node->fDisconnect)
continue; continue;
@ -983,7 +985,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) { for (const CNode* pnode : vNodes) {
if (pnode->fInbound) nInbound++; if (pnode->IsInboundConn()) nInbound++;
} }
} }
@ -1048,7 +1050,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
if (NetPermissions::HasFlag(permissionFlags, PF_BLOOMFILTER)) { if (NetPermissions::HasFlag(permissionFlags, PF_BLOOMFILTER)) {
nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM); nodeServices = static_cast<ServiceFlags>(nodeServices | NODE_BLOOM);
} }
CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", true); CNode* pnode = new CNode(id, nodeServices, GetBestHeight(), hSocket, addr, CalculateKeyedNetGroup(addr), nonce, addr_bind, "", ConnectionType::INBOUND);
pnode->AddRef(); pnode->AddRef();
pnode->m_permissionFlags = permissionFlags; pnode->m_permissionFlags = permissionFlags;
// If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility) // If this flag is present, the user probably expect that RPC and QT report it as whitelisted (backward compatibility)
@ -1646,7 +1648,7 @@ void CConnman::ThreadDNSAddressSeed()
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) { for (const CNode* pnode : vNodes) {
nRelevant += pnode->fSuccessfullyConnected && !pnode->fFeeler && !pnode->fOneShot && !pnode->m_manual_connection && !pnode->fInbound; if (pnode->fSuccessfullyConnected && pnode->IsOutboundOrBlockRelayConn()) ++nRelevant;
} }
} }
if (nRelevant >= 2) { if (nRelevant >= 2) {
@ -1674,7 +1676,7 @@ void CConnman::ThreadDNSAddressSeed()
LogPrintf("Loading addresses from DNS seed %s\n", seed); LogPrintf("Loading addresses from DNS seed %s\n", seed);
if (HaveNameProxy()) { if (HaveNameProxy()) {
AddOneShot(seed); AddAddrFetch(seed);
} else { } else {
std::vector<CNetAddr> vIPs; std::vector<CNetAddr> vIPs;
std::vector<CAddress> vAdd; std::vector<CAddress> vAdd;
@ -1696,8 +1698,8 @@ void CConnman::ThreadDNSAddressSeed()
addrman.Add(vAdd, resolveSource); addrman.Add(vAdd, resolveSource);
} else { } else {
// We now avoid directly using results from DNS Seeds which do not support service bit filtering, // We now avoid directly using results from DNS Seeds which do not support service bit filtering,
// instead using them as a oneshot to get nodes with our desired service bits. // instead using them as a addrfetch to get nodes with our desired service bits.
AddOneShot(seed); AddAddrFetch(seed);
} }
} }
--seeds_right_now; --seeds_right_now;
@ -1705,17 +1707,6 @@ void CConnman::ThreadDNSAddressSeed()
LogPrintf("%d addresses found from DNS seeds\n", found); LogPrintf("%d addresses found from DNS seeds\n", found);
} }
void CConnman::DumpAddresses() void CConnman::DumpAddresses()
{ {
int64_t nStart = GetTimeMillis(); int64_t nStart = GetTimeMillis();
@ -1727,20 +1718,20 @@ void CConnman::DumpAddresses()
addrman.size(), GetTimeMillis() - nStart); addrman.size(), GetTimeMillis() - nStart);
} }
void CConnman::ProcessOneShot() void CConnman::ProcessAddrFetch()
{ {
std::string strDest; std::string strDest;
{ {
LOCK(cs_vOneShots); LOCK(m_addr_fetches_mutex);
if (vOneShots.empty()) if (m_addr_fetches.empty())
return; return;
strDest = vOneShots.front(); strDest = m_addr_fetches.front();
vOneShots.pop_front(); m_addr_fetches.pop_front();
} }
CAddress addr; CAddress addr;
CSemaphoreGrant grant(*semOutbound, true); CSemaphoreGrant grant(*semOutbound, true);
if (grant) { if (grant) {
OpenNetworkConnection(addr, false, &grant, strDest.c_str(), true); OpenNetworkConnection(addr, false, &grant, strDest.c_str(), ConnectionType::ADDR_FETCH);
} }
} }
@ -1767,7 +1758,7 @@ int CConnman::GetExtraOutboundCount()
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) { for (const CNode* pnode : vNodes) {
if (!pnode->fInbound && !pnode->m_manual_connection && !pnode->fFeeler && !pnode->fDisconnect && !pnode->fOneShot && pnode->fSuccessfullyConnected) { if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsOutboundOrBlockRelayConn()) {
++nOutbound; ++nOutbound;
} }
} }
@ -1782,11 +1773,11 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{ {
for (int64_t nLoop = 0;; nLoop++) for (int64_t nLoop = 0;; nLoop++)
{ {
ProcessOneShot(); ProcessAddrFetch();
for (const std::string& strAddr : connect) for (const std::string& strAddr : connect)
{ {
CAddress addr(CService(), NODE_NONE); CAddress addr(CService(), NODE_NONE);
OpenNetworkConnection(addr, false, nullptr, strAddr.c_str(), false, false, true); OpenNetworkConnection(addr, false, nullptr, strAddr.c_str(), ConnectionType::MANUAL);
for (int i = 0; i < 10 && i < nLoop; i++) for (int i = 0; i < 10 && i < nLoop; i++)
{ {
if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
@ -1805,7 +1796,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL); int64_t nNextFeeler = PoissonNextSend(nStart*1000*1000, FEELER_INTERVAL);
while (!interruptNet) while (!interruptNet)
{ {
ProcessOneShot(); ProcessAddrFetch();
if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
return; return;
@ -1838,21 +1829,27 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
int nOutboundFullRelay = 0; int nOutboundFullRelay = 0;
int nOutboundBlockRelay = 0; int nOutboundBlockRelay = 0;
std::set<std::vector<unsigned char> > setConnected; std::set<std::vector<unsigned char> > setConnected;
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) { for (const CNode* pnode : vNodes) {
if (!pnode->fInbound && !pnode->m_manual_connection) { if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;
// Netgroups for inbound and addnode peers are not excluded because our goal here if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;
// is to not use multiple of our limited outbound slots on a single netgroup
// but inbound and addnode peers do not use our outbound slots. Inbound peers // Netgroups for inbound and manual peers are not excluded because our goal here
// also have the added issue that they're attacker controlled and could be used // is to not use multiple of our limited outbound slots on a single netgroup
// to prevent us from connecting to particular hosts if we used them here. // but inbound and manual peers do not use our outbound slots. Inbound peers
setConnected.insert(pnode->addr.GetGroup(addrman.m_asmap)); // also have the added issue that they could be attacker controlled and used
if (pnode->m_tx_relay == nullptr) { // to prevent us from connecting to particular hosts if we used them here.
nOutboundBlockRelay++; switch(pnode->m_conn_type){
} else if (!pnode->fFeeler) { case ConnectionType::INBOUND:
nOutboundFullRelay++; case ConnectionType::MANUAL:
} break;
case ConnectionType::OUTBOUND:
case ConnectionType::BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
setConnected.insert(pnode->addr.GetGroup(addrman.m_asmap));
} }
} }
} }
@ -1945,14 +1942,24 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString()); LogPrint(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToString());
} }
// Open this connection as block-relay-only if we're already at our ConnectionType conn_type;
// full-relay capacity, but not yet at our block-relay peer limit. // Determine what type of connection to open. If fFeeler is not
// (It should not be possible for fFeeler to be set if we're not // set, open OUTBOUND connections until we meet our full-relay
// also at our block-relay peer limit, but check against that as // capacity. Then open BLOCK_RELAY connections until we hit our
// well for sanity.) // block-relay peer limit. Otherwise, default to opening an
bool block_relay_only = nOutboundBlockRelay < m_max_outbound_block_relay && !fFeeler && nOutboundFullRelay >= m_max_outbound_full_relay; // OUTBOUND connection.
if (fFeeler) {
conn_type = ConnectionType::FEELER;
} else if (nOutboundFullRelay < m_max_outbound_full_relay) {
conn_type = ConnectionType::OUTBOUND;
} else if (nOutboundBlockRelay < m_max_outbound_block_relay) {
conn_type = ConnectionType::BLOCK_RELAY;
} else {
// GetTryNewOutboundPeer() is true
conn_type = ConnectionType::OUTBOUND;
}
OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, false, fFeeler, false, block_relay_only); OpenNetworkConnection(addrConnect, (int)setConnected.size() >= std::min(nMaxConnections - 1, 2), &grant, nullptr, conn_type);
} }
} }
} }
@ -1976,11 +1983,11 @@ std::vector<AddedNodeInfo> CConnman::GetAddedNodeInfo()
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (const CNode* pnode : vNodes) { for (const CNode* pnode : vNodes) {
if (pnode->addr.IsValid()) { if (pnode->addr.IsValid()) {
mapConnected[pnode->addr] = pnode->fInbound; mapConnected[pnode->addr] = pnode->IsInboundConn();
} }
std::string addrName = pnode->GetAddrName(); std::string addrName = pnode->GetAddrName();
if (!addrName.empty()) { if (!addrName.empty()) {
mapConnectedByName[std::move(addrName)] = std::make_pair(pnode->fInbound, static_cast<const CService&>(pnode->addr)); mapConnectedByName[std::move(addrName)] = std::make_pair(pnode->IsInboundConn(), static_cast<const CService&>(pnode->addr));
} }
} }
} }
@ -2027,7 +2034,7 @@ void CConnman::ThreadOpenAddedConnections()
} }
tried = true; tried = true;
CAddress addr(CService(), NODE_NONE); CAddress addr(CService(), NODE_NONE);
OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), false, false, true); OpenNetworkConnection(addr, false, &grant, info.strAddedNode.c_str(), ConnectionType::MANUAL);
if (!interruptNet.sleep_for(std::chrono::milliseconds(500))) if (!interruptNet.sleep_for(std::chrono::milliseconds(500)))
return; return;
} }
@ -2039,8 +2046,10 @@ void CConnman::ThreadOpenAddedConnections()
} }
// if successful, this moves the passed grant to the constructed node // if successful, this moves the passed grant to the constructed node
void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, bool fOneShot, bool fFeeler, bool manual_connection, bool block_relay_only) void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound, const char *pszDest, ConnectionType conn_type)
{ {
assert(conn_type != ConnectionType::INBOUND);
// //
// Initiate outbound network connection // Initiate outbound network connection
// //
@ -2058,18 +2067,12 @@ void CConnman::OpenNetworkConnection(const CAddress& addrConnect, bool fCountFai
} else if (FindNode(std::string(pszDest))) } else if (FindNode(std::string(pszDest)))
return; return;
CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, manual_connection, block_relay_only); CNode* pnode = ConnectNode(addrConnect, pszDest, fCountFailure, conn_type);
if (!pnode) if (!pnode)
return; return;
if (grantOutbound) if (grantOutbound)
grantOutbound->MoveTo(pnode->grantOutbound); grantOutbound->MoveTo(pnode->grantOutbound);
if (fOneShot)
pnode->fOneShot = true;
if (fFeeler)
pnode->fFeeler = true;
if (manual_connection)
pnode->m_manual_connection = true;
m_msgproc->InitializeNode(pnode); m_msgproc->InitializeNode(pnode);
{ {
@ -2127,11 +2130,6 @@ void CConnman::ThreadMessageHandler()
} }
} }
bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, NetPermissionFlags permissions) bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError, NetPermissionFlags permissions)
{ {
int nOne = 1; int nOne = 1;
@ -2337,7 +2335,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
} }
for (const auto& strDest : connOptions.vSeedNodes) { for (const auto& strDest : connOptions.vSeedNodes) {
AddOneShot(strDest); AddAddrFetch(strDest);
} }
if (clientInterface) { if (clientInterface) {
@ -2390,7 +2388,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
else else
threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this))); threadDNSAddressSeed = std::thread(&TraceThread<std::function<void()> >, "dnsseed", std::function<void()>(std::bind(&CConnman::ThreadDNSAddressSeed, this)));
// Initiate outbound connections from -addnode // Initiate manual connections
threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this))); threadOpenAddedConnections = std::thread(&TraceThread<std::function<void()> >, "addcon", std::function<void()>(std::bind(&CConnman::ThreadOpenAddedConnections, this)));
if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) { if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) {
@ -2581,7 +2579,7 @@ size_t CConnman::GetNodeCount(NumConnections flags)
int nNum = 0; int nNum = 0;
for (const auto& pnode : vNodes) { for (const auto& pnode : vNodes) {
if (flags & (pnode->fInbound ? CONNECTIONS_IN : CONNECTIONS_OUT)) { if (flags & (pnode->IsInboundConn() ? CONNECTIONS_IN : CONNECTIONS_OUT)) {
nNum++; nNum++;
} }
} }
@ -2765,26 +2763,26 @@ int CConnman::GetBestHeight() const
unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; } unsigned int CConnman::GetReceiveFloodSize() const { return nReceiveFloodSize; }
CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, bool fInboundIn, bool block_relay_only) CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in)
: nTimeConnected(GetSystemTimeInSeconds()), : nTimeConnected(GetSystemTimeInSeconds()),
addr(addrIn), addr(addrIn),
addrBind(addrBindIn), addrBind(addrBindIn),
fInbound(fInboundIn),
nKeyedNetGroup(nKeyedNetGroupIn), nKeyedNetGroup(nKeyedNetGroupIn),
// Don't relay addr messages to peers that we connect to as block-relay-only // Don't relay addr messages to peers that we connect to as block-relay-only
// peers (to prevent adversaries from inferring these links from addr // peers (to prevent adversaries from inferring these links from addr
// traffic). // traffic).
m_addr_known{block_relay_only ? nullptr : MakeUnique<CRollingBloomFilter>(5000, 0.001)},
id(idIn), id(idIn),
nLocalHostNonce(nLocalHostNonceIn), nLocalHostNonce(nLocalHostNonceIn),
m_conn_type(conn_type_in),
nLocalServices(nLocalServicesIn), nLocalServices(nLocalServicesIn),
nMyStartingHeight(nMyStartingHeightIn) nMyStartingHeight(nMyStartingHeightIn)
{ {
hSocket = hSocketIn; hSocket = hSocketIn;
addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn; addrName = addrNameIn == "" ? addr.ToStringIPPort() : addrNameIn;
hashContinue = uint256(); hashContinue = uint256();
if (!block_relay_only) { if (conn_type_in != ConnectionType::BLOCK_RELAY) {
m_tx_relay = MakeUnique<TxRelay>(); m_tx_relay = MakeUnique<TxRelay>();
m_addr_known = MakeUnique<CRollingBloomFilter>(5000, 0.001);
} }
for (const std::string &msg : getAllNetMessageTypes()) for (const std::string &msg : getAllNetMessageTypes())

View file

@ -117,6 +117,17 @@ struct CSerializedNetMsg
std::string m_type; std::string m_type;
}; };
/** Different types of connections to a peer. This enum encapsulates the
* information we have available at the time of opening or accepting the
* connection. Aside from INBOUND, all types are initiated by us. */
enum class ConnectionType {
INBOUND, /**< peer initiated connections */
OUTBOUND, /**< full relay connections (blocks, addrs, txns) made automatically. Addresses selected from AddrMan. */
MANUAL, /**< connections to addresses added via addnode or the connect command line argument */
FEELER, /**< short lived connections used to test address validity */
BLOCK_RELAY, /**< only relay blocks to these automatic outbound connections. Addresses selected from AddrMan. */
ADDR_FETCH, /**< short lived connections used to solicit addrs when starting the node without a populated AddrMan */
};
class NetEventsInterface; class NetEventsInterface;
class CConnman class CConnman
@ -201,7 +212,7 @@ public:
bool GetNetworkActive() const { return fNetworkActive; }; bool GetNetworkActive() const { return fNetworkActive; };
bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; }; bool GetUseAddrmanOutgoing() const { return m_use_addrman_outgoing; };
void SetNetworkActive(bool active); void SetNetworkActive(bool active);
void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, bool fOneShot = false, bool fFeeler = false, bool manual_connection = false, bool block_relay_only = false); void OpenNetworkConnection(const CAddress& addrConnect, bool fCountFailure, CSemaphoreGrant *grantOutbound = nullptr, const char *strDest = nullptr, ConnectionType conn_type = ConnectionType::OUTBOUND);
bool CheckIncomingNonce(uint64_t nonce); bool CheckIncomingNonce(uint64_t nonce);
bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func); bool ForNode(NodeId id, std::function<bool(CNode* pnode)> func);
@ -351,8 +362,8 @@ private:
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions); bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds); bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds);
void ThreadOpenAddedConnections(); void ThreadOpenAddedConnections();
void AddOneShot(const std::string& strDest); void AddAddrFetch(const std::string& strDest);
void ProcessOneShot(); void ProcessAddrFetch();
void ThreadOpenConnections(std::vector<std::string> connect); void ThreadOpenConnections(std::vector<std::string> connect);
void ThreadMessageHandler(); void ThreadMessageHandler();
void AcceptConnection(const ListenSocket& hListenSocket); void AcceptConnection(const ListenSocket& hListenSocket);
@ -373,7 +384,7 @@ private:
CNode* FindNode(const CService& addr); CNode* FindNode(const CService& addr);
bool AttemptToEvictConnection(); bool AttemptToEvictConnection();
CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, bool manual_connection, bool block_relay_only); CNode* ConnectNode(CAddress addrConnect, const char *pszDest, bool fCountFailure, ConnectionType conn_type);
void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const; void AddWhitelistPermissionFlags(NetPermissionFlags& flags, const CNetAddr &addr) const;
void DeleteNode(CNode* pnode); void DeleteNode(CNode* pnode);
@ -416,8 +427,8 @@ private:
std::atomic<bool> fNetworkActive{true}; std::atomic<bool> fNetworkActive{true};
bool fAddressesInitialized{false}; bool fAddressesInitialized{false};
CAddrMan addrman; CAddrMan addrman;
std::deque<std::string> vOneShots GUARDED_BY(cs_vOneShots); std::deque<std::string> m_addr_fetches GUARDED_BY(m_addr_fetches_mutex);
RecursiveMutex cs_vOneShots; RecursiveMutex m_addr_fetches_mutex;
std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes); std::vector<std::string> vAddedNodes GUARDED_BY(cs_vAddedNodes);
RecursiveMutex cs_vAddedNodes; RecursiveMutex cs_vAddedNodes;
std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes); std::vector<CNode*> vNodes GUARDED_BY(cs_vNodes);
@ -798,12 +809,8 @@ public:
} }
// This boolean is unusued in actual processing, only present for backward compatibility at RPC/QT level // This boolean is unusued in actual processing, only present for backward compatibility at RPC/QT level
bool m_legacyWhitelisted{false}; bool m_legacyWhitelisted{false};
bool fFeeler{false}; // If true this node is being used as a short lived feeler.
bool fOneShot{false};
bool m_manual_connection{false};
bool fClient{false}; // set by version message bool fClient{false}; // set by version message
bool m_limited_node{false}; //after BIP159, set by version message bool m_limited_node{false}; //after BIP159, set by version message
const bool fInbound;
std::atomic_bool fSuccessfullyConnected{false}; std::atomic_bool fSuccessfullyConnected{false};
// Setting fDisconnect to true will cause the node to be disconnected the // Setting fDisconnect to true will cause the node to be disconnected the
// next time DisconnectNodes() runs // next time DisconnectNodes() runs
@ -816,6 +823,60 @@ public:
std::atomic_bool fPauseRecv{false}; std::atomic_bool fPauseRecv{false};
std::atomic_bool fPauseSend{false}; std::atomic_bool fPauseSend{false};
bool IsOutboundOrBlockRelayConn() const {
switch(m_conn_type) {
case ConnectionType::OUTBOUND:
case ConnectionType::BLOCK_RELAY:
return true;
case ConnectionType::INBOUND:
case ConnectionType::MANUAL:
case ConnectionType::ADDR_FETCH:
case ConnectionType::FEELER:
return false;
}
assert(false);
}
bool IsFullOutboundConn() const {
return m_conn_type == ConnectionType::OUTBOUND;
}
bool IsManualConn() const {
return m_conn_type == ConnectionType::MANUAL;
}
bool IsBlockOnlyConn() const {
return m_conn_type == ConnectionType::BLOCK_RELAY;
}
bool IsFeelerConn() const {
return m_conn_type == ConnectionType::FEELER;
}
bool IsAddrFetchConn() const {
return m_conn_type == ConnectionType::ADDR_FETCH;
}
bool IsInboundConn() const {
return m_conn_type == ConnectionType::INBOUND;
}
bool ExpectServicesFromConn() const {
switch(m_conn_type) {
case ConnectionType::INBOUND:
case ConnectionType::MANUAL:
case ConnectionType::FEELER:
return false;
case ConnectionType::OUTBOUND:
case ConnectionType::BLOCK_RELAY:
case ConnectionType::ADDR_FETCH:
return true;
}
assert(false);
}
protected: protected:
mapMsgCmdSize mapSendBytesPerMsgCmd; mapMsgCmdSize mapSendBytesPerMsgCmd;
mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv); mapMsgCmdSize mapRecvBytesPerMsgCmd GUARDED_BY(cs_vRecv);
@ -826,7 +887,7 @@ public:
// flood relay // flood relay
std::vector<CAddress> vAddrToSend; std::vector<CAddress> vAddrToSend;
const std::unique_ptr<CRollingBloomFilter> m_addr_known; std::unique_ptr<CRollingBloomFilter> m_addr_known = nullptr;
bool fGetAddr{false}; bool fGetAddr{false};
std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0}; std::chrono::microseconds m_next_addr_send GUARDED_BY(cs_sendProcessing){0};
std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0}; std::chrono::microseconds m_next_local_addr_send GUARDED_BY(cs_sendProcessing){0};
@ -890,7 +951,7 @@ public:
std::set<uint256> orphan_work_set; std::set<uint256> orphan_work_set;
CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn = "", bool fInboundIn = false, bool block_relay_only = false); CNode(NodeId id, ServiceFlags nLocalServicesIn, int nMyStartingHeightIn, SOCKET hSocketIn, const CAddress &addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress &addrBindIn, const std::string &addrNameIn, ConnectionType conn_type_in);
~CNode(); ~CNode();
CNode(const CNode&) = delete; CNode(const CNode&) = delete;
CNode& operator=(const CNode&) = delete; CNode& operator=(const CNode&) = delete;
@ -898,6 +959,7 @@ public:
private: private:
const NodeId id; const NodeId id;
const uint64_t nLocalHostNonce; const uint64_t nLocalHostNonce;
const ConnectionType m_conn_type;
//! Services offered to this peer. //! Services offered to this peer.
//! //!

View file

@ -479,7 +479,7 @@ static void UpdatePreferredDownload(const CNode& node, CNodeState* state) EXCLUS
nPreferredDownload -= state->fPreferredDownload; nPreferredDownload -= state->fPreferredDownload;
// Whether this node should be marked as a preferred download node. // Whether this node should be marked as a preferred download node.
state->fPreferredDownload = (!node.fInbound || node.HasPermission(PF_NOBAN)) && !node.fOneShot && !node.fClient; state->fPreferredDownload = (!node.IsInboundConn() || node.HasPermission(PF_NOBAN)) && !node.IsAddrFetchConn() && !node.fClient;
nPreferredDownload += state->fPreferredDownload; nPreferredDownload += state->fPreferredDownload;
} }
@ -833,22 +833,15 @@ void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)
if (state) state->m_last_block_announcement = time_in_seconds; if (state) state->m_last_block_announcement = time_in_seconds;
} }
// Returns true for outbound peers, excluding manual connections, feelers, and
// one-shots.
static bool IsOutboundDisconnectionCandidate(const CNode& node)
{
return !(node.fInbound || node.m_manual_connection || node.fFeeler || node.fOneShot);
}
void PeerLogicValidation::InitializeNode(CNode *pnode) { void PeerLogicValidation::InitializeNode(CNode *pnode) {
CAddress addr = pnode->addr; CAddress addr = pnode->addr;
std::string addrName = pnode->GetAddrName(); std::string addrName = pnode->GetAddrName();
NodeId nodeid = pnode->GetId(); NodeId nodeid = pnode->GetId();
{ {
LOCK(cs_main); LOCK(cs_main);
mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName), pnode->fInbound, pnode->m_manual_connection)); mapNodeState.emplace_hint(mapNodeState.end(), std::piecewise_construct, std::forward_as_tuple(nodeid), std::forward_as_tuple(addr, std::move(addrName), pnode->IsInboundConn(), pnode->IsManualConn()));
} }
if(!pnode->fInbound) if(!pnode->IsInboundConn())
PushNodeVersion(*pnode, *connman, GetTime()); PushNodeVersion(*pnode, *connman, GetTime());
} }
@ -1982,14 +1975,14 @@ static void ProcessHeadersMessage(CNode& pfrom, CConnman& connman, ChainstateMan
// until we have a headers chain that has at least // until we have a headers chain that has at least
// nMinimumChainWork, even if a peer has a chain past our tip, // nMinimumChainWork, even if a peer has a chain past our tip,
// as an anti-DoS measure. // as an anti-DoS measure.
if (IsOutboundDisconnectionCandidate(pfrom)) { if (pfrom.IsOutboundOrBlockRelayConn()) {
LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom.GetId()); LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom.GetId());
pfrom.fDisconnect = true; pfrom.fDisconnect = true;
} }
} }
} }
if (!pfrom.fDisconnect && IsOutboundDisconnectionCandidate(pfrom) && nodestate->pindexBestKnownBlock != nullptr && pfrom.m_tx_relay != nullptr) { if (!pfrom.fDisconnect && pfrom.IsOutboundOrBlockRelayConn() && nodestate->pindexBestKnownBlock != nullptr && pfrom.m_tx_relay != nullptr) {
// If this is an outbound full-relay peer, check to see if we should protect // If this is an outbound full-relay peer, check to see if we should protect
// it from the bad/lagging chain logic. // it from the bad/lagging chain logic.
// Note that block-relay-only peers are already implicitly protected, so we // Note that block-relay-only peers are already implicitly protected, so we
@ -2352,11 +2345,11 @@ void ProcessMessage(
vRecv >> nVersion >> nServiceInt >> nTime >> addrMe; vRecv >> nVersion >> nServiceInt >> nTime >> addrMe;
nSendVersion = std::min(nVersion, PROTOCOL_VERSION); nSendVersion = std::min(nVersion, PROTOCOL_VERSION);
nServices = ServiceFlags(nServiceInt); nServices = ServiceFlags(nServiceInt);
if (!pfrom.fInbound) if (!pfrom.IsInboundConn())
{ {
connman.SetServices(pfrom.addr, nServices); connman.SetServices(pfrom.addr, nServices);
} }
if (!pfrom.fInbound && !pfrom.fFeeler && !pfrom.m_manual_connection && !HasAllDesirableServiceFlags(nServices)) if (pfrom.ExpectServicesFromConn() && !HasAllDesirableServiceFlags(nServices))
{ {
LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom.GetId(), nServices, GetDesirableServiceFlags(nServices)); LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom.GetId(), nServices, GetDesirableServiceFlags(nServices));
pfrom.fDisconnect = true; pfrom.fDisconnect = true;
@ -2383,20 +2376,20 @@ void ProcessMessage(
if (!vRecv.empty()) if (!vRecv.empty())
vRecv >> fRelay; vRecv >> fRelay;
// Disconnect if we connected to ourself // Disconnect if we connected to ourself
if (pfrom.fInbound && !connman.CheckIncomingNonce(nNonce)) if (pfrom.IsInboundConn() && !connman.CheckIncomingNonce(nNonce))
{ {
LogPrintf("connected to self at %s, disconnecting\n", pfrom.addr.ToString()); LogPrintf("connected to self at %s, disconnecting\n", pfrom.addr.ToString());
pfrom.fDisconnect = true; pfrom.fDisconnect = true;
return; return;
} }
if (pfrom.fInbound && addrMe.IsRoutable()) if (pfrom.IsInboundConn() && addrMe.IsRoutable())
{ {
SeenLocal(addrMe); SeenLocal(addrMe);
} }
// Be shy and don't send version until we hear // Be shy and don't send version until we hear
if (pfrom.fInbound) if (pfrom.IsInboundConn())
PushNodeVersion(pfrom, connman, GetAdjustedTime()); PushNodeVersion(pfrom, connman, GetAdjustedTime());
if (nVersion >= WTXID_RELAY_VERSION) { if (nVersion >= WTXID_RELAY_VERSION) {
@ -2440,7 +2433,7 @@ void ProcessMessage(
UpdatePreferredDownload(pfrom, State(pfrom.GetId())); UpdatePreferredDownload(pfrom, State(pfrom.GetId()));
} }
if (!pfrom.fInbound && pfrom.IsAddrRelayPeer()) if (!pfrom.IsInboundConn() && pfrom.IsAddrRelayPeer())
{ {
// Advertise our address // Advertise our address
if (fListen && !::ChainstateActive().IsInitialBlockDownload()) if (fListen && !::ChainstateActive().IsInitialBlockDownload())
@ -2484,8 +2477,7 @@ void ProcessMessage(
} }
// Feeler connections exist only to verify if address is online. // Feeler connections exist only to verify if address is online.
if (pfrom.fFeeler) { if (pfrom.IsFeelerConn()) {
assert(pfrom.fInbound == false);
pfrom.fDisconnect = true; pfrom.fDisconnect = true;
} }
return; return;
@ -2505,7 +2497,7 @@ void ProcessMessage(
{ {
pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION)); pfrom.SetRecvVersion(std::min(pfrom.nVersion.load(), PROTOCOL_VERSION));
if (!pfrom.fInbound) { if (!pfrom.IsInboundConn()) {
// Mark this node as currently connected, so we update its timestamp later. // Mark this node as currently connected, so we update its timestamp later.
LOCK(cs_main); LOCK(cs_main);
State(pfrom.GetId())->fCurrentlyConnected = true; State(pfrom.GetId())->fCurrentlyConnected = true;
@ -2614,7 +2606,7 @@ void ProcessMessage(
connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60); connman.AddNewAddresses(vAddrOk, pfrom.addr, 2 * 60 * 60);
if (vAddr.size() < 1000) if (vAddr.size() < 1000)
pfrom.fGetAddr = false; pfrom.fGetAddr = false;
if (pfrom.fOneShot) if (pfrom.IsAddrFetchConn())
pfrom.fDisconnect = true; pfrom.fDisconnect = true;
return; return;
} }
@ -3509,7 +3501,7 @@ void ProcessMessage(
// to users' AddrMan and later request them by sending getaddr messages. // to users' AddrMan and later request them by sending getaddr messages.
// Making nodes which are behind NAT and can only make outgoing connections ignore // Making nodes which are behind NAT and can only make outgoing connections ignore
// the getaddr message mitigates the attack. // the getaddr message mitigates the attack.
if (!pfrom.fInbound) { if (!pfrom.IsInboundConn()) {
LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom.GetId()); LogPrint(BCLog::NET, "Ignoring \"getaddr\" from outbound connection. peer=%d\n", pfrom.GetId());
return; return;
} }
@ -3792,7 +3784,7 @@ bool PeerLogicValidation::MaybeDiscourageAndDisconnect(CNode& pnode)
return false; return false;
} }
if (pnode.m_manual_connection) { if (pnode.IsManualConn()) {
// We never disconnect or discourage manual peers for bad behavior // We never disconnect or discourage manual peers for bad behavior
LogPrintf("Warning: not punishing manually connected peer %d!\n", peer_id); LogPrintf("Warning: not punishing manually connected peer %d!\n", peer_id);
return false; return false;
@ -3913,7 +3905,7 @@ void PeerLogicValidation::ConsiderEviction(CNode& pto, int64_t time_in_seconds)
CNodeState &state = *State(pto.GetId()); CNodeState &state = *State(pto.GetId());
const CNetMsgMaker msgMaker(pto.GetSendVersion()); const CNetMsgMaker msgMaker(pto.GetSendVersion());
if (!state.m_chain_sync.m_protect && IsOutboundDisconnectionCandidate(pto) && state.fSyncStarted) { if (!state.m_chain_sync.m_protect && pto.IsOutboundOrBlockRelayConn() && state.fSyncStarted) {
// This is an outbound peer subject to disconnection if they don't // This is an outbound peer subject to disconnection if they don't
// announce a block with as much work as the current tip within // announce a block with as much work as the current tip within
// CHAIN_SYNC_TIMEOUT + HEADERS_RESPONSE_TIME seconds (note: if // CHAIN_SYNC_TIMEOUT + HEADERS_RESPONSE_TIME seconds (note: if
@ -3975,7 +3967,7 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds)
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Ignore non-outbound peers, or nodes marked for disconnect already // Ignore non-outbound peers, or nodes marked for disconnect already
if (!IsOutboundDisconnectionCandidate(*pnode) || pnode->fDisconnect) return; if (!pnode->IsOutboundOrBlockRelayConn() || pnode->fDisconnect) return;
CNodeState *state = State(pnode->GetId()); CNodeState *state = State(pnode->GetId());
if (state == nullptr) return; // shouldn't be possible, but just in case if (state == nullptr) return; // shouldn't be possible, but just in case
// Don't evict our protected peers // Don't evict our protected peers
@ -4153,7 +4145,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
// Start block sync // Start block sync
if (pindexBestHeader == nullptr) if (pindexBestHeader == nullptr)
pindexBestHeader = ::ChainActive().Tip(); pindexBestHeader = ::ChainActive().Tip();
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do.
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
// Only actively request headers from a single peer, unless we're close to today. // Only actively request headers from a single peer, unless we're close to today.
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
@ -4338,7 +4330,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
bool fSendTrickle = pto->HasPermission(PF_NOBAN); bool fSendTrickle = pto->HasPermission(PF_NOBAN);
if (pto->m_tx_relay->nNextInvSend < current_time) { if (pto->m_tx_relay->nNextInvSend < current_time) {
fSendTrickle = true; fSendTrickle = true;
if (pto->fInbound) { if (pto->IsInboundConn()) {
pto->m_tx_relay->nNextInvSend = std::chrono::microseconds{connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL)}; pto->m_tx_relay->nNextInvSend = std::chrono::microseconds{connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL)};
} else { } else {
// Use half the delay for outbound peers, as there is less privacy concern for them. // Use half the delay for outbound peers, as there is less privacy concern for them.

View file

@ -264,7 +264,7 @@ static UniValue addnode(const JSONRPCRequest& request)
if (strCommand == "onetry") if (strCommand == "onetry")
{ {
CAddress addr; CAddress addr;
node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), false, false, true); node.connman->OpenNetworkConnection(addr, false, nullptr, strNode.c_str(), ConnectionType::MANUAL);
return NullUniValue; return NullUniValue;
} }

View file

@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
// Mock an outbound peer // Mock an outbound peer
CAddress addr1(ip(0xa0b0c001), NODE_NONE); CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", /*fInboundIn=*/ false); CNode dummyNode1(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::OUTBOUND);
dummyNode1.SetSendVersion(PROTOCOL_VERSION); dummyNode1.SetSendVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1); peerLogic->InitializeNode(&dummyNode1);
@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman) static void AddRandomOutboundPeer(std::vector<CNode *> &vNodes, PeerLogicValidation &peerLogic, CConnmanTest* connman)
{ {
CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE); CAddress addr(ip(g_insecure_rand_ctx.randbits(32)), NODE_NONE);
vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", /*fInboundIn=*/ false)); vNodes.emplace_back(new CNode(id++, ServiceFlags(NODE_NETWORK|NODE_WITNESS), 0, INVALID_SOCKET, addr, 0, 0, CAddress(), "", ConnectionType::OUTBOUND));
CNode &node = *vNodes.back(); CNode &node = *vNodes.back();
node.SetSendVersion(PROTOCOL_VERSION); node.SetSendVersion(PROTOCOL_VERSION);
@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
banman->ClearBanned(); banman->ClearBanned();
CAddress addr1(ip(0xa0b0c001), NODE_NONE); CAddress addr1(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", true); CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, CAddress(), "", ConnectionType::INBOUND);
dummyNode1.SetSendVersion(PROTOCOL_VERSION); dummyNode1.SetSendVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode1); peerLogic->InitializeNode(&dummyNode1);
dummyNode1.nVersion = 1; dummyNode1.nVersion = 1;
@ -244,7 +244,7 @@ BOOST_AUTO_TEST_CASE(peer_discouragement)
BOOST_CHECK(!banman->IsDiscouraged(ip(0xa0b0c001|0x0000ff00))); // Different IP, not discouraged BOOST_CHECK(!banman->IsDiscouraged(ip(0xa0b0c001|0x0000ff00))); // Different IP, not discouraged
CAddress addr2(ip(0xa0b0c002), NODE_NONE); CAddress addr2(ip(0xa0b0c002), NODE_NONE);
CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", true); CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, CAddress(), "", ConnectionType::INBOUND);
dummyNode2.SetSendVersion(PROTOCOL_VERSION); dummyNode2.SetSendVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode2); peerLogic->InitializeNode(&dummyNode2);
dummyNode2.nVersion = 1; dummyNode2.nVersion = 1;
@ -286,7 +286,7 @@ BOOST_AUTO_TEST_CASE(DoS_bantime)
SetMockTime(nStartTime); // Overrides future calls to GetTime() SetMockTime(nStartTime); // Overrides future calls to GetTime()
CAddress addr(ip(0xa0b0c001), NODE_NONE); CAddress addr(ip(0xa0b0c001), NODE_NONE);
CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", true); CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, CAddress(), "", ConnectionType::INBOUND);
dummyNode.SetSendVersion(PROTOCOL_VERSION); dummyNode.SetSendVersion(PROTOCOL_VERSION);
peerLogic->InitializeNode(&dummyNode); peerLogic->InitializeNode(&dummyNode);
dummyNode.nVersion = 1; dummyNode.nVersion = 1;

View file

@ -80,7 +80,7 @@ void test_one_input(const std::vector<uint8_t>& buffer)
return; return;
} }
CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION}; CDataStream random_bytes_data_stream{fuzzed_data_provider.ConsumeRemainingBytes<unsigned char>(), SER_NETWORK, PROTOCOL_VERSION};
CNode& p2p_node = *MakeUnique<CNode>(0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, false).release(); CNode& p2p_node = *MakeUnique<CNode>(0, ServiceFlags(NODE_NETWORK | NODE_WITNESS | NODE_BLOOM), 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND).release();
p2p_node.fSuccessfullyConnected = true; p2p_node.fSuccessfullyConnected = true;
p2p_node.nVersion = PROTOCOL_VERSION; p2p_node.nVersion = PROTOCOL_VERSION;
p2p_node.SetSendVersion(PROTOCOL_VERSION); p2p_node.SetSendVersion(PROTOCOL_VERSION);

View file

@ -44,9 +44,8 @@ void test_one_input(const std::vector<uint8_t>& buffer)
const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3); const auto num_peers_to_add = fuzzed_data_provider.ConsumeIntegralInRange(1, 3);
for (int i = 0; i < num_peers_to_add; ++i) { for (int i = 0; i < num_peers_to_add; ++i) {
const ServiceFlags service_flags = ServiceFlags(fuzzed_data_provider.ConsumeIntegral<uint64_t>()); const ServiceFlags service_flags = ServiceFlags(fuzzed_data_provider.ConsumeIntegral<uint64_t>());
const bool inbound{fuzzed_data_provider.ConsumeBool()}; const ConnectionType conn_type = fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH});
const bool block_relay_only{fuzzed_data_provider.ConsumeBool()}; peers.push_back(MakeUnique<CNode>(i, service_flags, 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, conn_type).release());
peers.push_back(MakeUnique<CNode>(i, service_flags, 0, INVALID_SOCKET, CAddress{CService{in_addr{0x0100007f}, 7777}, NODE_NETWORK}, 0, 0, CAddress{}, std::string{}, inbound, block_relay_only).release());
CNode& p2p_node = *peers.back(); CNode& p2p_node = *peers.back();
p2p_node.fSuccessfullyConnected = true; p2p_node.fSuccessfullyConnected = true;

View file

@ -180,17 +180,12 @@ BOOST_AUTO_TEST_CASE(cnode_simple_test)
CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK); CAddress addr = CAddress(CService(ipv4Addr, 7777), NODE_NETWORK);
std::string pszDest; std::string pszDest;
bool fInboundIn = false;
// Test that fFeeler is false by default. std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, ConnectionType::OUTBOUND);
std::unique_ptr<CNode> pnode1 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 0, 0, CAddress(), pszDest, fInboundIn); BOOST_CHECK(pnode1->IsInboundConn() == false);
BOOST_CHECK(pnode1->fInbound == false);
BOOST_CHECK(pnode1->fFeeler == false);
fInboundIn = true; std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, ConnectionType::INBOUND);
std::unique_ptr<CNode> pnode2 = MakeUnique<CNode>(id++, NODE_NETWORK, height, hSocket, addr, 1, 1, CAddress(), pszDest, fInboundIn); BOOST_CHECK(pnode2->IsInboundConn() == true);
BOOST_CHECK(pnode2->fInbound == true);
BOOST_CHECK(pnode2->fFeeler == false);
} }
// prior to PR #14728, this test triggers an undefined behavior // prior to PR #14728, this test triggers an undefined behavior
@ -214,7 +209,7 @@ BOOST_AUTO_TEST_CASE(ipv4_peer_with_ipv6_addrMe_test)
in_addr ipv4AddrPeer; in_addr ipv4AddrPeer;
ipv4AddrPeer.s_addr = 0xa0b0c001; ipv4AddrPeer.s_addr = 0xa0b0c001;
CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK); CAddress addr = CAddress(CService(ipv4AddrPeer, 7777), NODE_NETWORK);
std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, false); std::unique_ptr<CNode> pnode = MakeUnique<CNode>(0, NODE_NETWORK, 0, INVALID_SOCKET, addr, 0, 0, CAddress{}, std::string{}, ConnectionType::OUTBOUND);
pnode->fSuccessfullyConnected.store(true); pnode->fSuccessfullyConnected.store(true);
// the peer claims to be reaching us via IPv6 // the peer claims to be reaching us via IPv6