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.
1501assert(state != nullptr);1503// Make sure pindexBestKnownBlock is up to date, we'll need it.1504ProcessBlockAvailability(peer.m_id);1506if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < m_chainman.MinimumChainWork()) {1507// This peer has nothing interesting.1508return;1509}1511// When syncing with AssumeUtxo and the snapshot has not yet been validated,1512// abort downloading blocks from peers that don't have the snapshot block in their best chain.1513// We can't reorg to this chain due to missing undo data until validation completes,1514// so downloading blocks from it would be futile.1515const CBlockIndex* snap_base{m_chainman.CurrentChainstate().SnapshotBase()};1516if (snap_base && m_chainman.CurrentChainstate().m_assumeutxo == Assumeutxo::UNVALIDATED &&1517state->pindexBestKnownBlock->GetAncestor(snap_base->nHeight) != snap_base) {1518LogDebug(BCLog::NET, "Not downloading blocks from peer=%d, which doesn't have the snapshot block in its best chain.\n", peer.m_id);1519return;1520}1522// Determine the forking point between the peer's chain and our chain:1523// pindexLastCommonBlock is required to be an ancestor of pindexBestKnownBlock, and will be used as a starting point.1524// It is being set to the fork point between the peer's best known block and the current tip, unless it is already set to1525// an ancestor with more work than the fork point.1526auto fork_point = LastCommonAncestor(state->pindexBestKnownBlock, m_chainman.ActiveTip());1527if (state->pindexLastCommonBlock == nullptr ||1528fork_point->nChainWork > state->pindexLastCommonBlock->nChainWork ||1529state->pindexBestKnownBlock->GetAncestor(state->pindexLastCommonBlock->nHeight) != state->pindexLastCommonBlock) {1530state->pindexLastCommonBlock = fork_point;1531}1532if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)1533return;1535const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;1536// Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last1537// linked block we have in common with this peer. The +1 is so we can detect stalling, namely if we would be able to1538// download that next block if the window were 1 larger.1539int nWindowEnd = state->pindexLastCommonBlock->nHeight + BLOCK_DOWNLOAD_WINDOW;1541FindNextBlocks(vBlocks, peer, state, pindexWalk, count, nWindowEnd, &m_chainman.ActiveChain(), &nodeStaller);1542}1544void PeerManagerImpl::TryDownloadingHistoricalBlocks(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, const CBlockIndex *from_tip, const CBlockIndex* target_block)1545{1546Assert(from_tip);1547Assert(target_block);1549if (vBlocks.size() >= count) {1550return;1551}1553vBlocks.reserve(count);1554CNodeState *state = Assert(State(peer.m_id));1556if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->GetAncestor(target_block->nHeight) != target_block) {1557// This peer can't provide us the complete series of blocks leading up to the1558// assumeutxo snapshot base.1559//1560// Presumably this peer's chain has less work than our ActiveChain()'s tip, or else we1561// will eventually crash when we try to reorg to it. Let other logic1562// deal with whether we disconnect this peer.1563//1564// TODO at some point in the future, we might choose to request what blocks1565// this peer does have from the historical chain, despite it not having a1566// complete history beneath the snapshot base.1567return;1568}1570FindNextBlocks(vBlocks, peer, state, from_tip, count, std::min<int>(from_tip->nHeight + BLOCK_DOWNLOAD_WINDOW, target_block->nHeight));1571}1573void PeerManagerImpl::FindNextBlocks(std::vector<const CBlockIndex*>& vBlocks, const Peer& peer, CNodeState *state, const CBlockIndex *pindexWalk, unsigned int count, int nWindowEnd, const CChain* activeChain, NodeId* nodeStaller)1574{1575std::vector<const CBlockIndex*> vToFetch;1576int nMaxHeight = std::min<int>(state->pindexBestKnownBlock->nHeight, nWindowEnd + 1);1577bool is_limited_peer = IsLimitedPeer(peer);1578NodeId waitingfor = -1;1579while (pindexWalk->nHeight < nMaxHeight) {1580// Read up to 128 (or more, if more blocks than that are needed) successors of pindexWalk (towards1581// pindexBestKnownBlock) into vToFetch. We fetch 128, because CBlockIndex::GetAncestor may be as expensive1582// as iterating over ~100 CBlockIndex* entries anyway.1583int nToFetch = std::min(nMaxHeight - pindexWalk->nHeight, std::max<int>(count - vBlocks.size(), 128));1584vToFetch.resize(nToFetch);1585pindexWalk = state->pindexBestKnownBlock->GetAncestor(pindexWalk->nHeight + nToFetch);1586vToFetch[nToFetch - 1] = pindexWalk;1587for (unsigned int i = nToFetch - 1; i > 0; i--) {1588vToFetch[i - 1] = vToFetch[i]->pprev;1589}1591// Iterate over those blocks in vToFetch (in forward direction), adding the ones that1592// are not yet downloaded and not in flight to vBlocks. In the meantime, update1593// pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's1594// already part of our chain (and therefore don't need it even if pruned).1595for (const CBlockIndex* pindex : vToFetch) {1596if (!pindex->IsValid(BLOCK_VALID_TREE)) {1597// We consider the chain that this peer is on invalid.1598return;1599}1601if (!CanServeWitnesses(peer) && DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) {1602// We wouldn't download this block or its descendants from this peer.1603return;1604}1606if (pindex->nStatus & BLOCK_HAVE_DATA || (activeChain && activeChain->Contains(*pindex))) {1607if (activeChain && pindex->HaveNumChainTxs()) {1608state->pindexLastCommonBlock = pindex;1609}1610continue;1611}1613// Is block in-flight?1614if (IsBlockRequested(pindex->GetBlockHash())) {1615if (waitingfor == -1) {1616// This is the first already-in-flight block.1617waitingfor = mapBlocksInFlight.lower_bound(pindex->GetBlockHash())->second.first;1618}1619continue;1620}1622// The block is not already downloaded, and not yet in flight.1623if (pindex->nHeight > nWindowEnd) {1624// We reached the end of the window.1625if (vBlocks.size() == 0 && waitingfor != peer.m_id) {1626// We aren't able to fetch anything, but we would be if the download window was one larger.1627if (nodeStaller) *nodeStaller = waitingfor;1628}1629return;1630}1632// Don't request blocks that go further than what limited peers can provide1633if (is_limited_peer && (state->pindexBestKnownBlock->nHeight - pindex->nHeight >= static_cast<int>(NODE_NETWORK_LIMITED_MIN_BLOCKS) - 2 /* two blocks buffer for possible races */)) {1634continue;1635}1637vBlocks.push_back(pindex);1638if (vBlocks.size() == count) {1639return;1640}1641}1642}1643}1645} // namespace1647void PeerManagerImpl::PushNodeVersion(CNode& pnode, const Peer& peer)1648{1649uint64_t my_services;1650int64_t my_time;1651uint64_t your_services;1652CService your_addr;1653std::string my_user_agent;1654int my_height;1655bool my_tx_relay;1656if (pnode.IsPrivateBroadcastConn()) {1657my_services = NODE_NONE;1658my_time = 0;1659your_services = NODE_NONE;1660your_addr = CService{};1661my_user_agent = "/pynode:0.0.1/"; // Use a constant other than the default (or user-configured). See https://github.com/bitcoin/bitcoin/pull/27509#discussion_r12146719171662my_height = 0;1663my_tx_relay = false;1664} else {1665const CAddress& addr{pnode.addr};1666my_services = peer.m_our_services;1667my_time = TicksSinceEpoch<std::chrono::seconds>(NodeClock::now());1668your_services = addr.nServices;1669your_addr = addr.IsRoutable() && !IsProxy(addr) && addr.IsAddrV1Compatible() ? CService{addr} : CService{};1670my_user_agent = strSubVersion;1671my_height = m_best_height;1672my_tx_relay = !RejectIncomingTxs(pnode);1673}1675MakeAndPushMessage(1676pnode,1677NetMsgType::VERSION,1678pnode.AdvertisedVersion(),1679my_services,1680my_time,1681// your_services + CNetAddr::V1(your_addr) is the pre-version-31402 serialization of your_addr (without nTime)1682your_services, CNetAddr::V1(your_addr),1683// same, for a dummy address1684my_services, CNetAddr::V1(CService{}),1685pnode.GetLocalNonce(),1686my_user_agent,1687my_height,1688my_tx_relay);1690LogDebug(1691BCLog::NET, "send version message: version=%d, blocks=%d%s, txrelay=%d, peer=%d\n",1692pnode.AdvertisedVersion(), my_height,1693fLogIPs ? strprintf(", them=%s", your_addr.ToStringAddrPort()) : "",1694my_tx_relay, pnode.GetId());1695}1697void PeerManagerImpl::UpdateLastBlockAnnounceTime(NodeId node, int64_t time_in_seconds)1698{1699LOCK(cs_main);1700CNodeState *state = State(node);1701if (state) state->m_last_block_announcement = time_in_seconds;1702}1704void PeerManagerImpl::InitializeNode(const CNode& node, ServiceFlags our_services)1705{1706NodeId nodeid = node.GetId();1707{1708LOCK(cs_main); // For m_node_states1709m_node_states.try_emplace(m_node_states.end(), nodeid);1710}1711WITH_LOCK(m_tx_download_mutex, m_txdownloadman.CheckIsEmpty(nodeid));1713if (NetPermissions::HasFlag(node.m_permission_flags, NetPermissionFlags::BloomFilter)) {1714our_services = static_cast<ServiceFlags>(our_services | NODE_BLOOM);1715}1717PeerRef peer = std::make_shared<Peer>(nodeid, our_services, node.IsInboundConn());1718{1719LOCK(m_peer_mutex);1720m_peer_map.emplace_hint(m_peer_map.end(), nodeid, peer);1721}1722}1724void PeerManagerImpl::ReattemptInitialBroadcast(CScheduler& scheduler)1725{1726std::set<Txid> unbroadcast_txids = m_mempool.GetUnbroadcastTxs();1728for (const auto& txid : unbroadcast_txids) {1729CTransactionRef tx = m_mempool.get(txid);1731if (tx != nullptr) {1732InitiateTxBroadcastToAll(tx->GetWitnessHash());1733} else {1734m_mempool.RemoveUnbroadcastTx(txid, true);1735}1736}1738// Schedule next run for 10-15 minutes in the future.1739// We add randomness on every cycle to avoid the possibility of P2P fingerprinting.1740const auto delta = 10min + FastRandomContext().randrange<std::chrono::milliseconds>(5min);1741scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);1742}1744void PeerManagerImpl::ReattemptPrivateBroadcast(CScheduler& scheduler)1745{1746// Resolve stale transactions that are no longer relevant (e.g. already in1747// the mempool or mined) and count the remaining ones.1748size_t num_for_rebroadcast{0};1749const auto stale_txs = m_tx_for_private_broadcast.GetStale();1750if (!stale_txs.empty()) {