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: adaptive connections services flags #28170

Merged
merged 6 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/net.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2637,7 +2637,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
const CAddress addr = m_anchors.back();
m_anchors.pop_back();
if (!addr.IsValid() || IsLocal(addr) || !g_reachable_nets.Contains(addr) ||
!HasAllDesirableServiceFlags(addr.nServices) ||
!m_msgproc->HasAllDesirableServiceFlags(addr.nServices) ||
outbound_ipv46_peer_netgroups.count(m_netgroupman.GetGroup(addr))) continue;
addrConnect = addr;
LogPrint(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort());
Expand Down Expand Up @@ -2703,7 +2703,7 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
// for non-feelers, require all the services we'll want,
// for feelers, only require they be a full node (only because most
// SPV clients don't have a good address DB available)
if (!fFeeler && !HasAllDesirableServiceFlags(addr.nServices)) {
if (!fFeeler && !m_msgproc->HasAllDesirableServiceFlags(addr.nServices)) {
continue;
} else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) {
continue;
Expand Down
6 changes: 6 additions & 0 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,12 @@ class NetEventsInterface
/** Handle removal of a peer (clear state) */
virtual void FinalizeNode(const CNode& node) = 0;

/**
* Callback to determine whether the given set of service flags are sufficient
* for a peer to be "relevant".
*/
virtual bool HasAllDesirableServiceFlags(ServiceFlags services) const = 0;

/**
* Process protocol messages received from a given node
*
Expand Down
16 changes: 16 additions & 0 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ class PeerManagerImpl final : public PeerManager
/** Implement NetEventsInterface */
void InitializeNode(CNode& node, ServiceFlags our_services) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
void FinalizeNode(const CNode& node) override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_headers_presync_mutex);
bool HasAllDesirableServiceFlags(ServiceFlags services) const override;
bool ProcessMessages(CNode* pfrom, std::atomic<bool>& interrupt) override
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
bool SendMessages(CNode* pto) override
Expand All @@ -523,6 +524,7 @@ class PeerManagerImpl final : public PeerManager
const std::chrono::microseconds time_received, const std::atomic<bool>& interruptMsgProc) override
EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex, !m_recent_confirmed_transactions_mutex, !m_most_recent_block_mutex, !m_headers_presync_mutex, g_msgproc_mutex);
void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) override;
ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const override;

private:
/** Consider evicting an outbound peer based on the amount of time they've been behind our tip */
Expand Down Expand Up @@ -1668,6 +1670,20 @@ void PeerManagerImpl::FinalizeNode(const CNode& node)
LogPrint(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);
}

bool PeerManagerImpl::HasAllDesirableServiceFlags(ServiceFlags services) const
{
// Shortcut for (services & GetDesirableServiceFlags(services)) == GetDesirableServiceFlags(services)
return !(GetDesirableServiceFlags(services) & (~services));
}

ServiceFlags PeerManagerImpl::GetDesirableServiceFlags(ServiceFlags services) const
{
if (services & NODE_NETWORK_LIMITED && GetServicesFlagsIBDCache()) {
return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
}
return ServiceFlags(NODE_NETWORK | NODE_WITNESS);
furszy marked this conversation as resolved.
Show resolved Hide resolved
}

PeerRef PeerManagerImpl::GetPeerRef(NodeId id) const
{
LOCK(m_peer_mutex);
Expand Down
23 changes: 23 additions & 0 deletions src/net_processing.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,29 @@ class PeerManager : public CValidationInterface, public NetEventsInterface

/** This function is used for testing the stale tip eviction logic, see denialofservice_tests.cpp */
virtual void UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds) = 0;

/**
* Gets the set of service flags which are "desirable" for a given peer.
*
* These are the flags which are required for a peer to support for them
* to be "interesting" to us, ie for us to wish to use one of our few
* outbound connection slots for or for us to wish to prioritize keeping
furszy marked this conversation as resolved.
Show resolved Hide resolved
* their connection around.
*
* Relevant service flags may be peer- and state-specific in that the
* version of the peer may determine which flags are required (eg in the
* case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers
* unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which
* case NODE_NETWORK_LIMITED suffices).
furszy marked this conversation as resolved.
Show resolved Hide resolved
*
* Thus, generally, avoid calling with 'services' == NODE_NONE, unless
furszy marked this conversation as resolved.
Show resolved Hide resolved
* state-specific flags must absolutely be avoided. When called with
* 'services' == NODE_NONE, the returned desirable service flags are
* guaranteed to not change dependent on state - ie they are suitable for
* use when describing peers which we know to be desirable, but for which
* we do not have a confirmed set of service flags.
*/
virtual ServiceFlags GetDesirableServiceFlags(ServiceFlags services) const = 0;
};

#endif // BITCOIN_NET_PROCESSING_H
10 changes: 2 additions & 8 deletions src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,18 +125,12 @@ bool CMessageHeader::IsCommandValid() const
return true;
}


ServiceFlags GetDesirableServiceFlags(ServiceFlags services) {
if ((services & NODE_NETWORK_LIMITED) && g_initial_block_download_completed) {
furszy marked this conversation as resolved.
Show resolved Hide resolved
return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);
}
return ServiceFlags(NODE_NETWORK | NODE_WITNESS);
}

void SetServiceFlagsIBDCache(bool state) {
g_initial_block_download_completed = state;
}

bool GetServicesFlagsIBDCache() { return g_initial_block_download_completed; }

CInv::CInv()
{
type = 0;
Expand Down
34 changes: 1 addition & 33 deletions src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,29 +310,6 @@ enum ServiceFlags : uint64_t {
*/
std::vector<std::string> serviceFlagsToStr(uint64_t flags);

/**
* Gets the set of service flags which are "desirable" for a given peer.
*
* These are the flags which are required for a peer to support for them
* to be "interesting" to us, ie for us to wish to use one of our few
* outbound connection slots for or for us to wish to prioritize keeping
* their connection around.
*
* Relevant service flags may be peer- and state-specific in that the
* version of the peer may determine which flags are required (eg in the
* case of NODE_NETWORK_LIMITED where we seek out NODE_NETWORK peers
* unless they set NODE_NETWORK_LIMITED and we are out of IBD, in which
* case NODE_NETWORK_LIMITED suffices).
*
* Thus, generally, avoid calling with peerServices == NODE_NONE, unless
* state-specific flags must absolutely be avoided. When called with
* peerServices == NODE_NONE, the returned desirable service flags are
* guaranteed to not change dependent on state - ie they are suitable for
* use when describing peers which we know to be desirable, but for which
* we do not have a confirmed set of service flags.
*/
ServiceFlags GetDesirableServiceFlags(ServiceFlags services);

/**
* State independent service flags.
* If the return value is changed, contrib/seeds/makeseeds.py
Expand All @@ -343,16 +320,7 @@ constexpr ServiceFlags SeedsServiceFlags() { return ServiceFlags(NODE_NETWORK |

/** Set the current IBD status in order to figure out the desirable service flags */
void SetServiceFlagsIBDCache(bool status);

/**
* A shortcut for (services & GetDesirableServiceFlags(services))
* == GetDesirableServiceFlags(services), ie determines whether the given
* set of service flags are sufficient for a peer to be "relevant".
*/
static inline bool HasAllDesirableServiceFlags(ServiceFlags services)
{
return !(GetDesirableServiceFlags(services) & (~services));
}
bool GetServicesFlagsIBDCache();

/**
* Checks if a peer with the given service flags may be capable of having a
Expand Down
1 change: 0 additions & 1 deletion src/test/fuzz/integer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,6 @@ FUZZ_TARGET(integer, .init = initialize_integer)

{
const ServiceFlags service_flags = (ServiceFlags)u64;
(void)HasAllDesirableServiceFlags(service_flags);
(void)MayHaveUsefulAddressDB(service_flags);
}

Expand Down