Inside Bitcoin
Opening the selected file…
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.
251if (node.IsInboundConn()) {252// For inbound connections, assume both the address and the port253// as seen from the peer.254addrLocal = CService{node.GetAddrLocal()};255} else {256// For outbound connections, assume just the address as seen from257// the peer and leave the port in `addrLocal` as returned by258// `GetLocalAddress()` above. The peer has no way to observe our259// listening port when we have initiated the connection.260addrLocal.SetIP(node.GetAddrLocal());261}262}263if (addrLocal.IsRoutable()) {264LogDebug(BCLog::NET, "Advertising address %s to peer=%d\n", addrLocal.ToStringAddrPort(), node.GetId());265return addrLocal;266}267// Address is unroutable. Don't advertise.268return std::nullopt;269}271void ClearLocal()272{273LOCK(g_maplocalhost_mutex);274return mapLocalHost.clear();275}277// learn a new local address278bool AddLocal(const CService& addr_, int nScore, bool add_even_if_unreachable)279{280CService addr{MaybeFlipIPv6toCJDNS(addr_)};282if (!addr.IsRoutable())283return false;285if (!fDiscover && nScore < LOCAL_MANUAL)286return false;288if (!g_reachable_nets.Contains(addr) && !add_even_if_unreachable)289return false;291if (fLogIPs) {292LogInfo("AddLocal(%s,%i)\n", addr.ToStringAddrPort(), nScore);293}295{296LOCK(g_maplocalhost_mutex);297const auto [it, is_newly_added] = mapLocalHost.emplace(addr, LocalServiceInfo());298LocalServiceInfo &info = it->second;299if (is_newly_added || nScore >= info.nScore) {300info.nScore = SaturatingAdd(nScore, is_newly_added ? 0 : 1);301info.nPort = addr.GetPort();302}303}305return true;306}308bool AddLocal(const CNetAddr& addr, int nScore, bool add_even_if_unreachable)309{310return AddLocal(CService(addr, GetListenPort()), nScore, add_even_if_unreachable);311}313void RemoveLocal(const CService& addr)314{315LOCK(g_maplocalhost_mutex);316if (fLogIPs) {317LogInfo("RemoveLocal(%s)\n", addr.ToStringAddrPort());318}320mapLocalHost.erase(addr);321}323/** vote for a local address */324bool SeenLocal(const CService& addr)325{326LOCK(g_maplocalhost_mutex);327const auto it = mapLocalHost.find(addr);328if (it == mapLocalHost.end()) return false;329it->second.nScore = SaturatingAdd(it->second.nScore, 1);330return true;331}334/** check whether a given address is potentially local */335bool IsLocal(const CService& addr)336{337LOCK(g_maplocalhost_mutex);338return mapLocalHost.contains(addr);339}341bool CConnman::AlreadyConnectedToHost(std::string_view host) const342{343LOCK(m_nodes_mutex);344return std::ranges::any_of(m_nodes, [&host](CNode* node) { return node->m_addr_name == host; });345}347bool CConnman::AlreadyConnectedToAddressPort(const CService& addr_port) const348{349LOCK(m_nodes_mutex);350return std::ranges::any_of(m_nodes, [&addr_port](CNode* node) { return node->addr == addr_port; });351}353bool CConnman::AlreadyConnectedToAddress(const CNetAddr& addr) const354{355LOCK(m_nodes_mutex);356return std::ranges::any_of(m_nodes, [&addr](CNode* node) { return node->addr == addr; });357}359bool CConnman::CheckIncomingNonce(uint64_t nonce)360{361LOCK(m_nodes_mutex);362for (const CNode* pnode : m_nodes) {363// Omit private broadcast connections from this check to prevent this privacy attack:364// - We connect to a peer in an attempt to privately broadcast a transaction. From our365// VERSION message the peer deducts that this is a short-lived connection for366// broadcasting a transaction, takes our nonce and delays their VERACK.367// - The peer starts connecting to (clearnet) nodes and sends them a VERSION message368// which contains our nonce. If the peer manages to connect to us we would disconnect.369// - Upon a disconnect, the peer knows our clearnet address. They go back to the short370// lived privacy broadcast connection and continue with VERACK.371if (!pnode->fSuccessfullyConnected && !pnode->IsInboundConn() && !pnode->IsPrivateBroadcastConn() &&372pnode->GetLocalNonce() == nonce)373return false;374}375return true;376}378CNode* CConnman::ConnectNode(CAddress addrConnect,379const char* pszDest,380bool fCountFailure,381ConnectionType conn_type,382bool use_v2transport,383const std::optional<Proxy>& proxy_override)384{385AssertLockNotHeld(m_nodes_mutex);386AssertLockNotHeld(m_unused_i2p_sessions_mutex);387assert(conn_type != ConnectionType::INBOUND);389if (pszDest == nullptr) {390if (IsLocal(addrConnect))391return nullptr;393// Look for an existing connection394if (AlreadyConnectedToAddressPort(addrConnect)) {395LogInfo("Failed to open new connection to %s, already connected", addrConnect.ToStringAddrPort());396return nullptr;397}398}400LogDebug(BCLog::NET, "trying %s connection (%s) to %s, lastseen=%.1fhrs\n",401use_v2transport ? "v2" : "v1",402ConnectionTypeAsString(conn_type),403pszDest ? pszDest : addrConnect.ToStringAddrPort(),404Ticks<HoursDouble>(pszDest ? 0h : Now<NodeSeconds>() - addrConnect.nTime));406// Resolve407const uint16_t default_port{pszDest != nullptr ? GetDefaultPort(pszDest) :408m_params.GetDefaultPort()};410// Collection of addresses to try to connect to: either all dns resolved addresses if a domain name (pszDest) is provided, or addrConnect otherwise.411std::vector<CAddress> connect_to{};412if (pszDest) {413std::vector<CService> resolved{Lookup(pszDest, default_port, fNameLookup && !HaveNameProxy(), 256)};414if (!resolved.empty()) {415std::shuffle(resolved.begin(), resolved.end(), FastRandomContext());416// If the connection is made by name, it can be the case that the name resolves to more than one address.417// We don't want to connect any more of them if we are already connected to one418for (const auto& r : resolved) {419addrConnect = CAddress{MaybeFlipIPv6toCJDNS(r), NODE_NONE};420if (!addrConnect.IsValid()) {421LogDebug(BCLog::NET, "Resolver returned invalid address %s for %s\n", addrConnect.ToStringAddrPort(), pszDest);422return nullptr;423}424// It is possible that we already have a connection to the IP/port pszDest resolved to.425// In that case, drop the connection that was just created.426if (AlreadyConnectedToAddressPort(addrConnect)) {427LogInfo("Not opening a connection to %s, already connected to %s\n", pszDest, addrConnect.ToStringAddrPort());428return nullptr;429}430// Add the address to the resolved addresses vector so we can try to connect to it later on431connect_to.push_back(addrConnect);432}433} else {434// For resolution via proxy435connect_to.push_back(addrConnect);436}437} else {438// Connect via addrConnect directly439connect_to.push_back(addrConnect);440}442// Connect443std::unique_ptr<Sock> sock;444CService addr_bind;445assert(!addr_bind.IsValid());446std::unique_ptr<i2p::sam::Session> i2p_transient_session;448for (auto& target_addr : connect_to) {449if (target_addr.IsValid()) {450const std::optional<Proxy> use_proxy{451proxy_override.has_value() ? proxy_override : GetProxy(target_addr.GetNetwork()),452};453bool proxyConnectionFailed = false;455if (target_addr.IsI2P() && use_proxy) {456i2p::Connection conn;457bool connected{false};459// If an I2P SAM session already exists, normally we would re-use it. But in the case of460// private broadcast we force a new transient session. A Connect() using m_i2p_sam_session461// would use our permanent I2P address as a source address.462if (m_i2p_sam_session && conn_type != ConnectionType::PRIVATE_BROADCAST) {463connected = m_i2p_sam_session->Connect(target_addr, conn, proxyConnectionFailed);464} else {465{466LOCK(m_unused_i2p_sessions_mutex);467if (m_unused_i2p_sessions.empty()) {468i2p_transient_session =469std::make_unique<i2p::sam::Session>(*use_proxy, m_interrupt_net);470} else {471i2p_transient_session.swap(m_unused_i2p_sessions.front());472m_unused_i2p_sessions.pop();473}474}475connected = i2p_transient_session->Connect(target_addr, conn, proxyConnectionFailed);476if (!connected) {477LOCK(m_unused_i2p_sessions_mutex);478if (m_unused_i2p_sessions.size() < MAX_UNUSED_I2P_SESSIONS_SIZE) {479m_unused_i2p_sessions.emplace(i2p_transient_session.release());480}481}482}484if (connected) {485sock = std::move(conn.sock);486addr_bind = conn.me;487}488} else if (use_proxy) {489LogDebug(BCLog::PROXY, "Using proxy: %s to connect to %s\n", use_proxy->ToString(), target_addr.ToStringAddrPort());490sock = ConnectThroughProxy(*use_proxy, target_addr.ToStringAddr(), target_addr.GetPort(), proxyConnectionFailed);491} else {492// No proxy needed (none set for target network). Private broadcast connections493// must always use a proxy, otherwise they would leak the originator's IP address.494if (Assume(conn_type != ConnectionType::PRIVATE_BROADCAST)) {495sock = ConnectDirectly(target_addr, conn_type == ConnectionType::MANUAL);496}497}498if (!proxyConnectionFailed) {499// If a connection to the node was attempted, and failure (if any) is not caused by a problem connecting to500// the proxy, mark this as an attempt.