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.
6001const bool rate_limited = !pfrom.HasPermission(NetPermissionFlags::Addr);6002uint64_t num_proc = 0;6003uint64_t num_rate_limit = 0;6004std::shuffle(vAddr.begin(), vAddr.end(), m_rng);6005for (CAddress& addr : vAddr)6006{6007if (interruptMsgProc)6008return;6010// Apply rate limiting.6011if (peer.m_addr_token_bucket < 1.0) {6012if (rate_limited) {6013++num_rate_limit;6014continue;6015}6016} else {6017peer.m_addr_token_bucket -= 1.0;6018}6019// We only bother storing full nodes, though this may include6020// things which we would not make an outbound connection to, in6021// part because we may make feeler connections to them.6022if (!MayHaveUsefulAddressDB(addr.nServices) && !HasAllDesirableServiceFlags(addr.nServices))6023continue;6025if (addr.nTime <= NodeSeconds{100000000s} || addr.nTime > current_time + 10min) {6026addr.nTime = std::chrono::time_point_cast<std::chrono::seconds>(current_time - 5 * 24h);6027}6028AddAddressKnown(peer, addr);6029if (m_banman && (m_banman->IsDiscouraged(addr) || m_banman->IsBanned(addr))) {6030// Do not process banned/discouraged addresses beyond remembering we received them6031continue;6032}6033++num_proc;6034const bool reachable{g_reachable_nets.Contains(addr)};6035if (addr.nTime > current_time - 10min && !peer.m_getaddr_sent && vAddr.size() <= 10 && addr.IsRoutable()) {6036// Relay to a limited number of other nodes6037RelayAddress(pfrom.GetId(), addr, reachable);6038}6039// Do not store addresses outside our network6040if (reachable) {6041vAddrOk.push_back(addr);6042}6043}6044peer.m_addr_processed += num_proc;6045peer.m_addr_rate_limited += num_rate_limit;6046LogDebug(BCLog::NET, "Received addr: %u addresses (%u processed, %u rate-limited) from peer=%d\n",6047vAddr.size(), num_proc, num_rate_limit, pfrom.GetId());6049m_addrman.Add(vAddrOk, pfrom.addr, /*time_penalty=*/2h);6050if (vAddr.size() < 1000) peer.m_getaddr_sent = false;6052// AddrFetch: Require multiple addresses to avoid disconnecting on self-announcements6053if (pfrom.IsAddrFetchConn() && vAddr.size() > 1) {6054LogDebug(BCLog::NET, "addrfetch connection completed, %s", pfrom.DisconnectMsg());6055pfrom.fDisconnect = true;6056}6057}6059bool PeerManagerImpl::SendMessages(CNode& node)6060{6061AssertLockNotHeld(m_tx_download_mutex);6062AssertLockHeld(g_msgproc_mutex);6064PeerRef maybe_peer{GetPeerRef(node.GetId())};6065if (!maybe_peer) return false;6066Peer& peer{*maybe_peer};6067const Consensus::Params& consensusParams = m_chainparams.GetConsensus();6069// We must call MaybeDiscourageAndDisconnect first, to ensure that we'll6070// disconnect misbehaving peers even before the version handshake is complete.6071if (MaybeDiscourageAndDisconnect(node, peer)) return true;6073// Initiate version handshake for outbound connections6074if (!node.IsInboundConn() && !peer.m_outbound_version_message_sent) {6075PushNodeVersion(node, peer);6076peer.m_outbound_version_message_sent = true;6077}6079// Don't send anything until the version handshake is complete6080if (!node.fSuccessfullyConnected || node.fDisconnect)6081return true;6083const auto now{NodeClock::now()};6084const auto current_time{GetTime<std::chrono::microseconds>()};6086// The logic below does not apply to private broadcast peers, so skip it.6087// Also in CConnman::PushMessage() we make sure that unwanted messages are6088// not sent. This here is just an optimization.6089if (node.IsPrivateBroadcastConn()) {6090if (node.m_connected + PRIVATE_BROADCAST_MAX_CONNECTION_LIFETIME < now) {6091LogDebug(BCLog::PRIVBROADCAST, "Disconnecting: did not complete the transaction send within %d seconds, %s",6092count_seconds(PRIVATE_BROADCAST_MAX_CONNECTION_LIFETIME), node.LogPeer());6093node.fDisconnect = true;6094}6095return true;6096}6098if (node.IsAddrFetchConn() && now - node.m_connected > 10 * AVG_ADDRESS_BROADCAST_INTERVAL) {6099LogDebug(BCLog::NET, "addrfetch connection timeout, %s", node.DisconnectMsg());6100node.fDisconnect = true;6101return true;6102}6104MaybeSendPing(node, peer, now);6106// MaybeSendPing may have marked peer for disconnection6107if (node.fDisconnect) return true;6109MaybeSendAddr(node, peer, current_time);6111MaybeSendSendHeaders(node, peer);6113ProcessInvBacklog(now);6115{6116LOCK(cs_main);6118CNodeState &state = *State(node.GetId());6120// Start block sync6121if (m_chainman.m_best_header == nullptr) {6122m_chainman.m_best_header = m_chainman.ActiveChain().Tip();6123}6125// Determine whether we might try initial headers sync or parallel6126// block download from this peer -- this mostly affects behavior while6127// in IBD (once out of IBD, we sync from all peers).6128bool sync_blocks_and_headers_from_peer = false;6129if (state.fPreferredDownload) {6130sync_blocks_and_headers_from_peer = true;6131} else if (CanServeBlocks(peer) && !node.IsAddrFetchConn()) {6132// Typically this is an inbound peer. If we don't have any outbound6133// peers, or if we aren't downloading any blocks from such peers,6134// then allow block downloads from this peer, too.6135// We prefer downloading blocks from outbound peers to avoid6136// putting undue load on (say) some home user who is just making6137// outbound connections to the network, but if our only source of6138// the latest blocks is from an inbound peer, we have to be sure to6139// eventually download it (and not just wait indefinitely for an6140// outbound peer to have it).6141if (m_num_preferred_download_peers == 0 || mapBlocksInFlight.empty()) {6142sync_blocks_and_headers_from_peer = true;6143}6144}6146if (!state.fSyncStarted && CanServeBlocks(peer) && !m_chainman.m_blockman.LoadingBlocks()) {6147// Only actively request headers from a single peer, unless we're close to today.6148if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->Time() > NodeClock::now() - 24h) {6149const CBlockIndex* pindexStart = m_chainman.m_best_header;6150/* If possible, start at the block preceding the currently6151best known header. This ensures that we always get a6152non-empty list of headers back as long as the peer6153is up-to-date. With a non-empty response, we can initialise6154the peer's known best block. This wouldn't be possible6155if we requested starting at m_chainman.m_best_header and6156got back an empty response. */6157if (pindexStart->pprev)6158pindexStart = pindexStart->pprev;6159if (MaybeSendGetHeaders(node, GetLocator(pindexStart), peer)) {6160LogDebug(BCLog::NET, "initial getheaders (%d) to peer=%d", pindexStart->nHeight, node.GetId());6162state.fSyncStarted = true;6163peer.m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE +6164(6165// Convert HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER to microseconds before scaling6166// to maintain precision6167std::chrono::microseconds{HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER} *6168Ticks<std::chrono::seconds>(NodeClock::now() - m_chainman.m_best_header->Time()) / consensusParams.nPowTargetSpacing6169);6170nSyncStarted++;6171}6172}6173}6175//6176// Try sending block announcements via headers6177//6178{6179// If we have no more than MAX_BLOCKS_TO_ANNOUNCE in our6180// list of block hashes we're relaying, and our peer wants6181// headers announcements, then find the first header6182// not yet known to our peer but would connect, and send.6183// If no header would connect, or if we have too many6184// blocks, or if the peer doesn't want headers, just6185// add all to the inv queue.6186LOCK(peer.m_block_inv_mutex);6187std::vector<CBlock> vHeaders;6188bool fRevertToInv = ((!peer.m_prefers_headers &&6189(!state.m_requested_hb_cmpctblocks || peer.m_blocks_for_headers_relay.size() > 1)) ||6190peer.m_blocks_for_headers_relay.size() > MAX_BLOCKS_TO_ANNOUNCE);6191const CBlockIndex *pBestIndex = nullptr; // last header queued for delivery6192ProcessBlockAvailability(node.GetId()); // ensure pindexBestKnownBlock is up-to-date6194if (!fRevertToInv) {6195bool fFoundStartingHeader = false;6196// Try to find first header that our peer doesn't have, and6197// then send all headers past that one. If we come across any6198// headers that aren't on m_chainman.ActiveChain(), give up.6199for (const uint256& hash : peer.m_blocks_for_headers_relay) {6200const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);6201assert(pindex);6202if (m_chainman.ActiveChain()[pindex->nHeight] != pindex) {6203// Bail out if we reorged away from this block6204fRevertToInv = true;6205break;6206}6207if (pBestIndex != nullptr && pindex->pprev != pBestIndex) {6208// This means that the list of blocks to announce don't6209// connect to each other.6210// This shouldn't really be possible to hit during6211// regular operation (because reorgs should take us to6212// a chain that has some block not on the prior chain,6213// which should be caught by the prior check), but one6214// way this could happen is by using invalidateblock /6215// reconsiderblock repeatedly on the tip, causing it to6216// be added multiple times to m_blocks_for_headers_relay.6217// Robustly deal with this rare situation by reverting6218// to an inv.6219fRevertToInv = true;6220break;6221}6222pBestIndex = pindex;6223if (fFoundStartingHeader) {6224// add this to the headers message6225vHeaders.emplace_back(pindex->GetBlockHeader());6226} else if (PeerHasHeader(&state, pindex)) {6227continue; // keep looking for the first new block6228} else if (pindex->pprev == nullptr || PeerHasHeader(&state, pindex->pprev)) {6229// Peer doesn't have this header but they do have the prior one.6230// Start sending headers.6231fFoundStartingHeader = true;6232vHeaders.emplace_back(pindex->GetBlockHeader());6233} else {6234// Peer doesn't have this header or the prior one -- nothing will6235// connect, so bail out.6236fRevertToInv = true;6237break;6238}6239}6240}6241if (!fRevertToInv && !vHeaders.empty()) {6242if (vHeaders.size() == 1 && state.m_requested_hb_cmpctblocks) {6243// We only send up to 1 block as header-and-ids, as otherwise6244// probably means we're doing an initial-ish-sync or they're slow6245LogDebug(BCLog::NET, "%s sending header-and-ids %s to peer=%d\n", __func__,6246vHeaders.front().GetHash().ToString(), node.GetId());6248std::optional<CSerializedNetMsg> cached_cmpctblock_msg;6249{6250LOCK(m_most_recent_block_mutex);