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.
2501// Return the number of outbound connections that are full relay (not blocks only)2502int CConnman::GetFullOutboundConnCount() const2503{2504AssertLockNotHeld(m_nodes_mutex);2506int nRelevant = 0;2507{2508LOCK(m_nodes_mutex);2509for (const CNode* pnode : m_nodes) {2510if (pnode->fSuccessfullyConnected && pnode->IsFullOutboundConn()) ++nRelevant;2511}2512}2513return nRelevant;2514}2516// Return the number of peers we have over our outbound connection limit2517// Exclude peers that are marked for disconnect, or are going to be2518// disconnected soon (eg ADDR_FETCH and FEELER)2519// Also exclude peers that haven't finished initial connection handshake yet2520// (so that we don't decide we're over our desired connection limit, and then2521// evict some peer that has finished the handshake)2522int CConnman::GetExtraFullOutboundCount() const2523{2524AssertLockNotHeld(m_nodes_mutex);2526int full_outbound_peers = 0;2527{2528LOCK(m_nodes_mutex);2529for (const CNode* pnode : m_nodes) {2530if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsFullOutboundConn()) {2531++full_outbound_peers;2532}2533}2534}2535return std::max(full_outbound_peers - m_max_outbound_full_relay, 0);2536}2538int CConnman::GetExtraBlockRelayCount() const2539{2540AssertLockNotHeld(m_nodes_mutex);2542int block_relay_peers = 0;2543{2544LOCK(m_nodes_mutex);2545for (const CNode* pnode : m_nodes) {2546if (pnode->fSuccessfullyConnected && !pnode->fDisconnect && pnode->IsBlockOnlyConn()) {2547++block_relay_peers;2548}2549}2550}2551return std::max(block_relay_peers - m_max_outbound_block_relay, 0);2552}2554bool CConnman::EvictTxPeerIfFull(std::optional<NodeId> protect_peer)2555{2556int tx_inbound_peers{0};2557{2558LOCK(m_nodes_mutex);2559for (const CNode* pnode : m_nodes) {2560if (!pnode->fDisconnect && pnode->IsInboundConn() && pnode->m_relays_txs) {2561++tx_inbound_peers;2562}2563}2564}2565if (tx_inbound_peers > m_max_inbound_full_relay) {2566return AttemptToEvictConnection(/*evict_tx_relay_peer_only=*/true, protect_peer);2567}2568return true;2569}2571std::unordered_set<Network> CConnman::GetReachableEmptyNetworks() const2572{2573std::unordered_set<Network> networks{};2574for (int n = 0; n < NET_MAX; n++) {2575enum Network net = (enum Network)n;2576if (net == NET_UNROUTABLE || net == NET_INTERNAL) continue;2577if (g_reachable_nets.Contains(net) && addrman.get().Size(net, std::nullopt) == 0) {2578networks.insert(net);2579}2580}2581return networks;2582}2584bool CConnman::MultipleManualOrFullOutboundConns(Network net) const2585{2586AssertLockHeld(m_nodes_mutex);2587return m_network_conn_counts[net] > 1;2588}2590bool CConnman::MaybePickPreferredNetwork(std::optional<Network>& network)2591{2592AssertLockNotHeld(m_nodes_mutex);2594std::array<Network, 5> nets{NET_IPV4, NET_IPV6, NET_ONION, NET_I2P, NET_CJDNS};2595std::shuffle(nets.begin(), nets.end(), FastRandomContext());2597LOCK(m_nodes_mutex);2598for (const auto net : nets) {2599if (g_reachable_nets.Contains(net) && m_network_conn_counts[net] == 0 && addrman.get().Size(net) != 0) {2600network = net;2601return true;2602}2603}2605return false;2606}2608void CConnman::ThreadOpenConnections(const std::vector<std::string> connect, std::span<const std::string> seed_nodes)2609{2610AssertLockNotHeld(m_nodes_mutex);2611AssertLockNotHeld(m_reconnections_mutex);2612AssertLockNotHeld(m_unused_i2p_sessions_mutex);2614FastRandomContext rng;2615// Connect to specific addresses2616if (!connect.empty())2617{2618// Attempt v2 connection if we support v2 - we'll reconnect with v1 if our2619// peer doesn't support it or immediately disconnects us for another reason.2620const bool use_v2transport(GetLocalServices() & NODE_P2P_V2);2621for (int64_t nLoop = 0;; nLoop++)2622{2623for (const std::string& strAddr : connect)2624{2625OpenNetworkConnection(/*addrConnect=*/CAddress{CService{}, NODE_NONE},2626/*fCountFailure=*/false,2627/*grant_outbound=*/{},2628/*pszDest=*/strAddr.c_str(),2629/*conn_type=*/ConnectionType::MANUAL,2630/*use_v2transport=*/use_v2transport,2631/*proxy_override=*/std::nullopt);2632for (int i = 0; i < 10 && i < nLoop; i++)2633{2634if (!m_interrupt_net->sleep_for(500ms)) {2635return;2636}2637}2638}2639if (!m_interrupt_net->sleep_for(500ms)) {2640return;2641}2642PerformReconnections();2643}2644}2646// Initiate network connections2647auto start = GetTime<std::chrono::microseconds>();2649// Minimum time before next feeler connection (in microseconds).2650auto next_feeler = start + rng.rand_exp_duration(FEELER_INTERVAL);2651auto next_extra_block_relay = start + rng.rand_exp_duration(EXTRA_BLOCK_RELAY_ONLY_PEER_INTERVAL);2652auto next_extra_network_peer{start + rng.rand_exp_duration(EXTRA_NETWORK_PEER_INTERVAL)};2653const bool dnsseed = gArgs.GetBoolArg("-dnsseed", DEFAULT_DNSSEED);2654bool add_fixed_seeds = gArgs.GetBoolArg("-fixedseeds", DEFAULT_FIXEDSEEDS);2655const bool use_seednodes{!gArgs.GetArgs("-seednode").empty()};2657auto seed_node_timer = NodeClock::now();2658bool add_addr_fetch{addrman.get().Size() == 0 && !seed_nodes.empty()};2659constexpr std::chrono::seconds ADD_NEXT_SEEDNODE = 10s;2661if (!add_fixed_seeds) {2662LogInfo("Fixed seeds are disabled\n");2663}2665while (!m_interrupt_net->interrupted()) {2666if (add_addr_fetch) {2667add_addr_fetch = false;2668const auto& seed{SpanPopBack(seed_nodes)};2669AddAddrFetch(seed);2671if (addrman.get().Size() == 0) {2672LogInfo("Empty addrman, adding seednode (%s) to addrfetch\n", seed);2673} else {2674LogInfo("Couldn't connect to peers from addrman after %d seconds. Adding seednode (%s) to addrfetch\n", ADD_NEXT_SEEDNODE.count(), seed);2675}2676}2678ProcessAddrFetch();2680if (!m_interrupt_net->sleep_for(500ms)) {2681return;2682}2684PerformReconnections();2686CountingSemaphoreGrant<> grant(*semOutbound);2687if (m_interrupt_net->interrupted()) {2688return;2689}2691const std::unordered_set<Network> fixed_seed_networks{GetReachableEmptyNetworks()};2692if (add_fixed_seeds && !fixed_seed_networks.empty()) {2693// When the node starts with an empty peers.dat, there are a few other sources of peers before2694// we fallback on to fixed seeds: -dnsseed, -seednode, -addnode2695// If none of those are available, we fallback on to fixed seeds immediately, else we allow2696// 60 seconds for any of those sources to populate addrman.2697bool add_fixed_seeds_now = false;2698// It is cheapest to check if enough time has passed first.2699if (GetTime<std::chrono::seconds>() > start + std::chrono::minutes{1}) {2700add_fixed_seeds_now = true;2701LogInfo("Adding fixed seeds as 60 seconds have passed and addrman is empty for at least one reachable network\n");2702}2704// Perform cheap checks before locking a mutex.2705else if (!dnsseed && !use_seednodes) {2706LOCK(m_added_nodes_mutex);2707if (m_added_node_params.empty()) {2708add_fixed_seeds_now = true;2709LogInfo("Adding fixed seeds as -dnsseed=0 (or IPv4/IPv6 connections are disabled via -onlynet) and neither -addnode nor -seednode are provided\n");2710}2711}2713if (add_fixed_seeds_now) {2714std::vector<CAddress> seed_addrs{ConvertSeeds(m_params.FixedSeeds())};2715// We will not make outgoing connections to peers that are unreachable2716// (e.g. because of -onlynet configuration).2717// Therefore, we do not add them to addrman in the first place.2718// In case previously unreachable networks become reachable2719// (e.g. in case of -onlynet changes by the user), fixed seeds will2720// be loaded only for networks for which we have no addresses.2721seed_addrs.erase(std::remove_if(seed_addrs.begin(), seed_addrs.end(),2722[&fixed_seed_networks](const CAddress& addr) { return !fixed_seed_networks.contains(addr.GetNetwork()); }),2723seed_addrs.end());2724CNetAddr local;2725local.SetInternal("fixedseeds");2726addrman.get().Add(seed_addrs, local);2727add_fixed_seeds = false;2728LogInfo("Added %d fixed seeds from reachable networks.\n", seed_addrs.size());2729}2730}2732//2733// Choose an address to connect to based on most recently seen2734//2735CAddress addrConnect;2737// Only connect out to one peer per ipv4/ipv6 network group (/16 for IPv4).2738int nOutboundFullRelay = 0;2739int nOutboundBlockRelay = 0;2740int outbound_privacy_network_peers = 0;2741std::set<std::vector<unsigned char>> outbound_ipv46_peer_netgroups;2743{2744LOCK(m_nodes_mutex);2745for (const CNode* pnode : m_nodes) {2746if (pnode->IsFullOutboundConn()) nOutboundFullRelay++;2747if (pnode->IsBlockOnlyConn()) nOutboundBlockRelay++;2749// Make sure our persistent outbound slots to ipv4/ipv6 peers belong to different netgroups.2750switch (pnode->m_conn_type) {