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.
501addrman.get().Attempt(target_addr, fCountFailure);502}503} else if (pszDest) {504if (const auto name_proxy = GetNameProxy()) {505std::string host;506uint16_t port{default_port};507SplitHostPort(pszDest, port, host);508bool proxyConnectionFailed;509sock = ConnectThroughProxy(*name_proxy, host, port, proxyConnectionFailed);510}511}512// Check any other resolved address (if any) if we fail to connect513if (!sock) {514continue;515}517NetPermissionFlags permission_flags = NetPermissionFlags::None;518std::vector<NetWhitelistPermissions> whitelist_permissions = conn_type == ConnectionType::MANUAL ? vWhitelistedRangeOutgoing : std::vector<NetWhitelistPermissions>{};519AddWhitelistPermissionFlags(permission_flags, target_addr, whitelist_permissions);521// Add node522NodeId id = GetNewNodeId();523uint64_t nonce = GetDeterministicRandomizer(RANDOMIZER_ID_LOCALHOSTNONCE).Write(id).Finalize();524if (!addr_bind.IsValid()) {525addr_bind = GetBindAddress(*sock);526}527uint64_t network_id = GetDeterministicRandomizer(RANDOMIZER_ID_NETWORKKEY)528.Write(target_addr.GetNetClass())529.Write(addr_bind.GetAddrBytes())530// For outbound connections, the port of the bound address is randomly531// assigned by the OS and would therefore not be useful for seeding.532.Write(0)533.Finalize();534CNode* pnode = new CNode(id,535std::move(sock),536target_addr,537CalculateKeyedNetGroup(target_addr),538nonce,539addr_bind,540pszDest ? pszDest : "",541conn_type,542/*inbound_onion=*/false,543network_id,544CNodeOptions{545.permission_flags = permission_flags,546.proxy_override = proxy_override,547.i2p_sam_session = std::move(i2p_transient_session),548.recv_flood_size = nReceiveFloodSize,549.use_v2transport = use_v2transport,550});551pnode->AddRef();553// We're making a new connection, harvest entropy from the time (and our peer count)554RandAddEvent((uint32_t)id);556return pnode;557}559return nullptr;560}562void CNode::CloseSocketDisconnect()563{564fDisconnect = true;565LOCK(m_sock_mutex);566if (m_sock) {567LogDebug(BCLog::NET, "Resetting socket for %s", LogPeer());568m_sock.reset();570TRACEPOINT(net, closed_connection,571GetId(),572m_addr_name.c_str(),573ConnectionTypeAsString().c_str(),574ConnectedThroughNetwork(),575TicksSinceEpoch<std::chrono::seconds>(m_connected));576}577m_i2p_sam_session.reset();578}580void CConnman::AddWhitelistPermissionFlags(NetPermissionFlags& flags, std::optional<CNetAddr> addr, const std::vector<NetWhitelistPermissions>& ranges) const {581for (const auto& subnet : ranges) {582if (addr.has_value() && subnet.m_subnet.Match(addr.value())) {583NetPermissions::AddFlag(flags, subnet.m_flags);584}585}586if (NetPermissions::HasFlag(flags, NetPermissionFlags::Implicit)) {587NetPermissions::ClearFlag(flags, NetPermissionFlags::Implicit);588if (whitelist_forcerelay) NetPermissions::AddFlag(flags, NetPermissionFlags::ForceRelay);589if (whitelist_relay) NetPermissions::AddFlag(flags, NetPermissionFlags::Relay);590NetPermissions::AddFlag(flags, NetPermissionFlags::Mempool);591NetPermissions::AddFlag(flags, NetPermissionFlags::NoBan);592}593}595CService CNode::GetAddrLocal() const596{597AssertLockNotHeld(m_addr_local_mutex);598LOCK(m_addr_local_mutex);599return m_addr_local;600}602void CNode::SetAddrLocal(const CService& addrLocalIn) {603AssertLockNotHeld(m_addr_local_mutex);604LOCK(m_addr_local_mutex);605if (Assume(!m_addr_local.IsValid())) { // Addr local can only be set once during version msg processing606m_addr_local = addrLocalIn;607}608}610Network CNode::ConnectedThroughNetwork() const611{612return m_inbound_onion ? NET_ONION : addr.GetNetClass();613}615bool CNode::IsConnectedThroughPrivacyNet() const616{617return m_inbound_onion || addr.IsPrivacyNet();618}620#undef X621#define X(name) stats.name = name622void CNode::CopyStats(CNodeStats& stats)623{624stats.nodeid = this->GetId();625X(addr);626X(addrBind);627stats.m_network = ConnectedThroughNetwork();628X(m_last_send);629X(m_last_recv);630X(m_last_tx_time);631X(m_last_block_time);632X(m_connected);633X(m_addr_name);634X(nVersion);635{636LOCK(m_subver_mutex);637X(cleanSubVer);638}639stats.fInbound = IsInboundConn();640X(m_bip152_highbandwidth_to);641X(m_bip152_highbandwidth_from);642{643LOCK(cs_vSend);644X(mapSendBytesPerMsgType);645X(nSendBytes);646}647{648LOCK(cs_vRecv);649X(mapRecvBytesPerMsgType);650X(nRecvBytes);651Transport::Info info = m_transport->GetInfo();652stats.m_transport_type = info.transport_type;653if (info.session_id) stats.m_session_id = HexStr(*info.session_id);654}655X(m_permission_flags);657X(m_last_ping_time);658X(m_min_ping_time);660// Leave string empty if addrLocal invalid (not filled in yet)661CService addrLocalUnlocked = GetAddrLocal();662stats.addrLocal = addrLocalUnlocked.IsValid() ? addrLocalUnlocked.ToStringAddrPort() : "";664X(m_conn_type);665}666#undef X668bool CNode::ReceiveMsgBytes(std::span<const uint8_t> msg_bytes, bool& complete)669{670complete = false;671const auto time{NodeClock::now()};672LOCK(cs_vRecv);673m_last_recv = time;674nRecvBytes += msg_bytes.size();675while (msg_bytes.size() > 0) {676// absorb network data677if (!m_transport->ReceivedBytes(msg_bytes)) {678// Serious transport problem, disconnect from the peer.679return false;680}682if (m_transport->ReceivedMessageComplete()) {683// decompose a transport agnostic CNetMessage from the deserializer684bool reject_message{false};685CNetMessage msg = m_transport->GetReceivedMessage(time, reject_message);686if (reject_message) {687// Message deserialization failed. Drop the message but don't disconnect the peer.688// store the size of the corrupt message689mapRecvBytesPerMsgType.at(NET_MESSAGE_TYPE_OTHER) += msg.m_raw_message_size;690continue;691}693// Store received bytes per message type.694// To prevent a memory DOS, only allow known message types.695auto i = mapRecvBytesPerMsgType.find(msg.m_type);696if (i == mapRecvBytesPerMsgType.end()) {697i = mapRecvBytesPerMsgType.find(NET_MESSAGE_TYPE_OTHER);698}699assert(i != mapRecvBytesPerMsgType.end());700i->second += msg.m_raw_message_size;702// push the message to the process queue,703vRecvMsg.push_back(std::move(msg));705complete = true;706}707}709return true;710}712std::string CNode::LogPeer() const713{714auto peer_info{strprintf("peer=%d", GetId())};715if (fLogIPs) {716return strprintf("%s, peeraddr=%s", peer_info, addr.ToStringAddrPort());717} else {718return peer_info;719}720}722std::string CNode::DisconnectMsg() const723{724return strprintf("disconnecting %s", LogPeer());725}727V1Transport::V1Transport(const NodeId node_id) noexcept728: m_magic_bytes{Params().MessageStart()}, m_node_id{node_id}729{730LOCK(m_recv_mutex);731Reset();732}734Transport::Info V1Transport::GetInfo() const noexcept735{736return {.transport_type = TransportProtocolType::V1, .session_id = {}};737}739int V1Transport::readHeader(std::span<const uint8_t> msg_bytes)740{741AssertLockHeld(m_recv_mutex);742// copy data to temporary parsing buffer743unsigned int nRemaining = CMessageHeader::HEADER_SIZE - nHdrPos;744unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size());746memcpy(&hdrbuf[nHdrPos], msg_bytes.data(), nCopy);747nHdrPos += nCopy;749// if header incomplete, exit750if (nHdrPos < CMessageHeader::HEADER_SIZE)