Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
2751// We currently don't take inbound connections into account. Since they are2752// free to make, an attacker could make them to prevent us from connecting to2753// certain peers.2754case ConnectionType::INBOUND:2755// Short-lived outbound connections should not affect how we select outbound2756// peers from addrman.2757case ConnectionType::ADDR_FETCH:2758case ConnectionType::FEELER:2759case ConnectionType::PRIVATE_BROADCAST:2760break;2761case ConnectionType::MANUAL:2762case ConnectionType::OUTBOUND_FULL_RELAY:2763case ConnectionType::BLOCK_RELAY:2764const CAddress address{pnode->addr};2765if (address.IsTor() || address.IsI2P() || address.IsCJDNS()) {2766// Since our addrman-groups for these networks are2767// random, without relation to the route we2768// take to connect to these peers or to the2769// difficulty in obtaining addresses with diverse2770// groups, we don't worry about diversity with2771// respect to our addrman groups when connecting to2772// these networks.2773++outbound_privacy_network_peers;2774} else {2775outbound_ipv46_peer_netgroups.insert(m_netgroupman.GetGroup(address));2776}2777} // no default case, so the compiler can warn about missing cases2778}2779}2781if (!seed_nodes.empty() && nOutboundFullRelay < SEED_OUTBOUND_CONNECTION_THRESHOLD) {2782if (NodeClock::now() > seed_node_timer + ADD_NEXT_SEEDNODE) {2783seed_node_timer = NodeClock::now();2784add_addr_fetch = true;2785}2786}2788ConnectionType conn_type = ConnectionType::OUTBOUND_FULL_RELAY;2789auto now = GetTime<std::chrono::microseconds>();2790bool anchor = false;2791bool fFeeler = false;2792std::optional<Network> preferred_net;2794// Determine what type of connection to open. Opening2795// BLOCK_RELAY connections to addresses from anchors.dat gets the highest2796// priority. Then we open OUTBOUND_FULL_RELAY priority until we2797// meet our full-relay capacity. Then we open BLOCK_RELAY connection2798// until we hit our block-relay-only peer limit.2799// GetTryNewOutboundPeer() gets set when a stale tip is detected, so we2800// try opening an additional OUTBOUND_FULL_RELAY connection. If none of2801// these conditions are met, check to see if it's time to try an extra2802// block-relay-only peer (to confirm our tip is current, see below) or the next_feeler2803// timer to decide if we should open a FEELER.2805if (!m_anchors.empty() && (nOutboundBlockRelay < m_max_outbound_block_relay)) {2806conn_type = ConnectionType::BLOCK_RELAY;2807anchor = true;2808} else if (nOutboundFullRelay < m_max_outbound_full_relay) {2809// OUTBOUND_FULL_RELAY2810} else if (nOutboundBlockRelay < m_max_outbound_block_relay) {2811conn_type = ConnectionType::BLOCK_RELAY;2812} else if (GetTryNewOutboundPeer()) {2813// OUTBOUND_FULL_RELAY2814} else if (now > next_extra_block_relay && m_start_extra_block_relay_peers) {2815// Periodically connect to a peer (using regular outbound selection2816// methodology from addrman) and stay connected long enough to sync2817// headers, but not much else.2818//2819// Then disconnect the peer, if we haven't learned anything new.2820//2821// The idea is to make eclipse attacks very difficult to pull off,2822// because every few minutes we're finding a new peer to learn headers2823// from.2824//2825// This is similar to the logic for trying extra outbound (full-relay)2826// peers, except:2827// - we do this all the time on an exponential timer, rather than just when2828// our tip is stale2829// - we potentially disconnect our next-youngest block-relay-only peer, if our2830// newest block-relay-only peer delivers a block more recently.2831// See the eviction logic in net_processing.cpp.2832//2833// Because we can promote these connections to block-relay-only2834// connections, they do not get their own ConnectionType enum2835// (similar to how we deal with extra outbound peers).2836next_extra_block_relay = now + rng.rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);2837conn_type = ConnectionType::BLOCK_RELAY;2838} else if (now > next_feeler) {2839next_feeler = now + rng.rand_exp_duration(FEELER_INTERVAL);2840conn_type = ConnectionType::FEELER;2841fFeeler = true;2842} else if (nOutboundFullRelay == m_max_outbound_full_relay &&2843m_max_outbound_full_relay == MAX_OUTBOUND_FULL_RELAY_CONNECTIONS &&2844now > next_extra_network_peer &&2845MaybePickPreferredNetwork(preferred_net)) {2846// Full outbound connection management: Attempt to get at least one2847// outbound peer from each reachable network by making extra connections2848// and then protecting "only" peers from a network during outbound eviction.2849// This is not attempted if the user changed -maxconnections to a value2850// so low that less than MAX_OUTBOUND_FULL_RELAY_CONNECTIONS are made,2851// to prevent interactions with otherwise protected outbound peers.2852next_extra_network_peer = now + rng.rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL);2853} else {2854// skip to next iteration of while loop2855continue;2856}2858addrman.get().ResolveCollisions();2860const auto current_time{NodeClock::now()};2861int nTries = 0;2862const auto reachable_nets{g_reachable_nets.All()};2864while (!m_interrupt_net->interrupted()) {2865if (anchor && !m_anchors.empty()) {2866const CAddress addr = m_anchors.back();2867m_anchors.pop_back();2868if (!addr.IsValid() || IsLocal(addr) || !g_reachable_nets.Contains(addr) ||2869!m_msgproc->HasAllDesirableServiceFlags(addr.nServices) ||2870outbound_ipv46_peer_netgroups.contains(m_netgroupman.GetGroup(addr))) continue;2871addrConnect = addr;2872LogDebug(BCLog::NET, "Trying to make an anchor connection to %s\n", addrConnect.ToStringAddrPort());2873break;2874}2876// If we didn't find an appropriate destination after trying 100 addresses fetched from addrman,2877// stop this loop, and let the outer loop run again (which sleeps, adds seed nodes, recalculates2878// already-connected network ranges, ...) before trying new addrman addresses.2879nTries++;2880if (nTries > 100)2881break;2883CAddress addr;2884NodeSeconds addr_last_try{0s};2886if (fFeeler) {2887// First, try to get a tried table collision address. This returns2888// an empty (invalid) address if there are no collisions to try.2889std::tie(addr, addr_last_try) = addrman.get().SelectTriedCollision();2891if (!addr.IsValid()) {2892// No tried table collisions. Select a new table address2893// for our feeler.2894std::tie(addr, addr_last_try) = addrman.get().Select(true, reachable_nets);2895} else if (AlreadyConnectedToAddress(addr)) {2896// If test-before-evict logic would have us connect to a2897// peer that we're already connected to, just mark that2898// address as Good(). We won't be able to initiate the2899// connection anyway, so this avoids inadvertently evicting2900// a currently-connected peer.2901addrman.get().Good(addr);2902// Select a new table address for our feeler instead.2903std::tie(addr, addr_last_try) = addrman.get().Select(true, reachable_nets);2904}2905} else {2906// Not a feeler2907// If preferred_net has a value set, pick an extra outbound2908// peer from that network. The eviction logic in net_processing2909// ensures that a peer from another network will be evicted.2910std::tie(addr, addr_last_try) = preferred_net.has_value()2911? addrman.get().Select(false, {*preferred_net})2912: addrman.get().Select(false, reachable_nets);2913}2915// Require outbound IPv4/IPv6 connections, other than feelers, to be to distinct network groups2916if (!fFeeler && outbound_ipv46_peer_netgroups.contains(m_netgroupman.GetGroup(addr))) {2917continue;2918}2920// if we selected an invalid or local address, restart2921if (!addr.IsValid() || IsLocal(addr)) {2922break;2923}2925if (!g_reachable_nets.Contains(addr)) {2926continue;2927}2929// only consider very recently tried nodes after 30 failed attempts2930if (current_time - addr_last_try < 10min && nTries < 30) {2931continue;2932}2934// for non-feelers, require all the services we'll want,2935// for feelers, only require they be a full node (only because most2936// SPV clients don't have a good address DB available)2937if (!fFeeler && !m_msgproc->HasAllDesirableServiceFlags(addr.nServices)) {2938continue;2939} else if (fFeeler && !MayHaveUsefulAddressDB(addr.nServices)) {2940continue;2941}2943// Do not connect to bad ports, unless 50 invalid addresses have been selected already.2944if (nTries < 50 && (addr.IsIPv4() || addr.IsIPv6()) && IsBadPort(addr.GetPort())) {2945continue;2946}2948// Do not make automatic outbound connections to addnode peers, to2949// not use our limited outbound slots for them and to ensure2950// addnode connections benefit from their intended protections.2951if (AddedNodesContain(addr)) {2952LogDebug(BCLog::NET, "Not making automatic %s%s connection to %s peer selected for manual (addnode) connection%s\n",2953preferred_net.has_value() ? "network-specific " : "",2954ConnectionTypeAsString(conn_type), GetNetworkName(addr.GetNetwork()),2955fLogIPs ? strprintf(": %s", addr.ToStringAddrPort()) : "");2956continue;2957}2959addrConnect = addr;2960break;2961}2963if (addrConnect.IsValid()) {2964if (fFeeler) {2965// Add small amount of random noise before connection to avoid synchronization.2966if (!m_interrupt_net->sleep_for(rng.rand_uniform_duration<CThreadInterrupt::Clock>(FEELER_SLEEP_WINDOW))) {2967return;2968}2969LogDebug(BCLog::NET, "Making feeler connection to %s\n", addrConnect.ToStringAddrPort());2970}2972if (preferred_net != std::nullopt) LogDebug(BCLog::NET, "Making network specific connection to %s on %s.\n", addrConnect.ToStringAddrPort(), GetNetworkName(preferred_net.value()));2974// Record addrman failure attempts when node has at least 2 persistent outbound connections to peers with2975// different netgroups in ipv4/ipv6 networks + all peers in Tor/I2P/CJDNS networks.2976// Don't record addrman failure attempts when node is offline. This can be identified since all local2977// network connections (if any) belong in the same netgroup, and the size of `outbound_ipv46_peer_netgroups` would only be 1.2978const bool count_failures{((int)outbound_ipv46_peer_netgroups.size() + outbound_privacy_network_peers) >= std::min(m_max_automatic_connections - 1, 2)};2979// Use BIP324 transport when both us and them have NODE_V2_P2P set.2980const bool use_v2transport(addrConnect.nServices & GetLocalServices() & NODE_P2P_V2);2981OpenNetworkConnection(/*addrConnect=*/addrConnect,2982/*fCountFailure=*/count_failures,2983/*grant_outbound=*/std::move(grant),2984/*pszDest=*/nullptr,2985/*conn_type=*/conn_type,2986/*use_v2transport=*/use_v2transport,2987/*proxy_override=*/std::nullopt);2988}2989}2990}2992std::vector<CAddress> CConnman::GetCurrentBlockRelayOnlyConns() const2993{2994AssertLockNotHeld(m_nodes_mutex);2995std::vector<CAddress> ret;2996LOCK(m_nodes_mutex);2997for (const CNode* pnode : m_nodes) {2998if (pnode->IsBlockOnlyConn()) {2999ret.push_back(pnode->addr);3000}