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.
1251/** Whether this peer can serve us blocks. */1252static bool CanServeBlocks(const Peer& peer)1253{1254return peer.m_their_services & (NODE_NETWORK|NODE_NETWORK_LIMITED);1255}1257/** Whether this peer can only serve limited recent blocks (e.g. because1258* it prunes old blocks) */1259static bool IsLimitedPeer(const Peer& peer)1260{1261return (!(peer.m_their_services & NODE_NETWORK) &&1262(peer.m_their_services & NODE_NETWORK_LIMITED));1263}1265/** Whether this peer can serve us witness data */1266static bool CanServeWitnesses(const Peer& peer)1267{1268return peer.m_their_services & NODE_WITNESS;1269}1271std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,1272std::chrono::seconds average_interval,1273uint64_t network_key)1274{1275auto [it, inserted] = m_next_inv_to_inbounds_per_network_key.try_emplace(network_key, 0us);1276auto& timer{it->second};1277if (timer < now) {1278timer = now + m_rng.rand_exp_duration(average_interval);1279}1280return timer;1281}1283bool PeerManagerImpl::IsBlockRequested(const uint256& hash)1284{1285return mapBlocksInFlight.contains(hash);1286}1288bool PeerManagerImpl::IsBlockRequestedFromOutbound(const uint256& hash)1289{1290for (auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {1291auto [nodeid, block_it] = range.first->second;1292PeerRef peer{GetPeerRef(nodeid)};1293if (peer && !peer->m_is_inbound) return true;1294}1296return false;1297}1299void PeerManagerImpl::RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer)1300{1301auto range = mapBlocksInFlight.equal_range(hash);1302if (range.first == range.second) {1303// Block was not requested from any peer1304return;1305}1307// We should not have requested too many of this block1308Assume(mapBlocksInFlight.count(hash) <= MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK);1310while (range.first != range.second) {1311const auto& [node_id, list_it]{range.first->second};1313if (from_peer && *from_peer != node_id) {1314range.first++;1315continue;1316}1318CNodeState& state = *Assert(State(node_id));1320if (state.vBlocksInFlight.begin() == list_it) {1321// First block on the queue was received, update the start download time for the next one1322state.m_downloading_since = std::max(state.m_downloading_since, GetTime<std::chrono::microseconds>());1323}1324state.vBlocksInFlight.erase(list_it);1326if (state.vBlocksInFlight.empty()) {1327// Last validated block on the queue for this peer was received.1328m_peers_downloading_from--;1329}1330state.m_stalling_since = 0us;1332range.first = mapBlocksInFlight.erase(range.first);1333}1334}1336bool PeerManagerImpl::BlockRequested(NodeId nodeid, const CBlockIndex& block, std::list<QueuedBlock>::iterator** pit)1337{1338const uint256& hash{block.GetBlockHash()};1340CNodeState *state = State(nodeid);1341assert(state != nullptr);1343Assume(mapBlocksInFlight.count(hash) <= MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK);1345// Short-circuit most stuff in case it is from the same node1346for (auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {1347if (range.first->second.first == nodeid) {1348if (pit) {1349*pit = &range.first->second.second;1350}1351return false;1352}1353}1355// Make sure it's not being fetched already from same peer.1356RemoveBlockRequest(hash, nodeid);1358std::list<QueuedBlock>::iterator it = state->vBlocksInFlight.insert(state->vBlocksInFlight.end(),1359{&block, std::unique_ptr<PartiallyDownloadedBlock>(pit ? new PartiallyDownloadedBlock(&m_mempool) : nullptr)});1360if (state->vBlocksInFlight.size() == 1) {1361// We're starting a block download (batch) from this peer.1362state->m_downloading_since = GetTime<std::chrono::microseconds>();1363m_peers_downloading_from++;1364}1365auto itInFlight = mapBlocksInFlight.insert(std::make_pair(hash, std::make_pair(nodeid, it)));1366if (pit) {1367*pit = &itInFlight->second.second;1368}1369return true;1370}1372void PeerManagerImpl::MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid)1373{1374AssertLockHeld(cs_main);1376// When in -blocksonly mode, never request high-bandwidth mode from peers. Our1377// mempool will not contain the transactions necessary to reconstruct the1378// compact block.1379if (m_opts.ignore_incoming_txs) return;1381CNodeState* nodestate = State(nodeid);1382PeerRef peer{GetPeerRef(nodeid)};1383if (!nodestate || !nodestate->m_provides_cmpctblocks) {1384// Don't request compact blocks if the peer has not signalled support1385return;1386}1388int num_outbound_hb_peers = 0;1389for (std::list<NodeId>::iterator it = lNodesAnnouncingHeaderAndIDs.begin(); it != lNodesAnnouncingHeaderAndIDs.end(); it++) {1390if (*it == nodeid) {1391lNodesAnnouncingHeaderAndIDs.erase(it);1392lNodesAnnouncingHeaderAndIDs.push_back(nodeid);1393return;1394}1395PeerRef peer_ref{GetPeerRef(*it)};1396if (peer_ref && !peer_ref->m_is_inbound) ++num_outbound_hb_peers;1397}1398if (peer && peer->m_is_inbound) {1399// If we're adding an inbound HB peer, make sure we're not removing1400// our last outbound HB peer in the process.1401if (lNodesAnnouncingHeaderAndIDs.size() >= 3 && num_outbound_hb_peers == 1) {1402PeerRef remove_peer{GetPeerRef(lNodesAnnouncingHeaderAndIDs.front())};1403if (remove_peer && !remove_peer->m_is_inbound) {1404// Put the HB outbound peer in the second slot, so that it1405// doesn't get removed.1406std::swap(lNodesAnnouncingHeaderAndIDs.front(), *std::next(lNodesAnnouncingHeaderAndIDs.begin()));1407}1408}1409}1410const bool nodeid_was_appended{m_connman.ForNode(nodeid, [this](CNode* pfrom) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {1411AssertLockHeld(::cs_main);1412MakeAndPushMessage(*pfrom, NetMsgType::SENDCMPCT, /*high_bandwidth=*/true, /*version=*/CMPCTBLOCKS_VERSION);1413// save BIP152 bandwidth state: we select peer to be high-bandwidth1414pfrom->m_bip152_highbandwidth_to = true;1415lNodesAnnouncingHeaderAndIDs.push_back(pfrom->GetId());1416return true;1417})};1418if (nodeid_was_appended && lNodesAnnouncingHeaderAndIDs.size() > 3) {1419// As per BIP152, we only get 3 of our peers to announce1420// blocks using compact encodings.1421m_connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [this](CNode* pnodeStop) {1422MakeAndPushMessage(*pnodeStop, NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION);1423// save BIP152 bandwidth state: we select peer to be low-bandwidth1424pnodeStop->m_bip152_highbandwidth_to = false;1425return true;1426});1427lNodesAnnouncingHeaderAndIDs.pop_front();1428}1429}1431bool PeerManagerImpl::TipMayBeStale()1432{1433AssertLockHeld(cs_main);1434const Consensus::Params& consensusParams = m_chainparams.GetConsensus();1435if (m_last_tip_update.load() == 0s) {1436m_last_tip_update = GetTime<std::chrono::seconds>();1437}1438return m_last_tip_update.load() < GetTime<std::chrono::seconds>() - std::chrono::seconds{consensusParams.nPowTargetSpacing * 3} && mapBlocksInFlight.empty();1439}1441int64_t PeerManagerImpl::ApproximateBestBlockDepth() const1442{1443return (GetTime<std::chrono::seconds>() - m_best_block_time.load()).count() / m_chainparams.GetConsensus().nPowTargetSpacing;1444}1446bool PeerManagerImpl::CanDirectFetch()1447{1448return m_chainman.ActiveChain().Tip()->Time() > NodeClock::now() - m_chainparams.GetConsensus().PowTargetSpacing() * 20;1449}1451static bool PeerHasHeader(CNodeState *state, const CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)1452{1453if (state->pindexBestKnownBlock && pindex == state->pindexBestKnownBlock->GetAncestor(pindex->nHeight))1454return true;1455if (state->pindexBestHeaderSent && pindex == state->pindexBestHeaderSent->GetAncestor(pindex->nHeight))1456return true;1457return false;1458}1460void PeerManagerImpl::ProcessBlockAvailability(NodeId nodeid) {1461CNodeState *state = State(nodeid);1462assert(state != nullptr);1464if (!state->hashLastUnknownBlock.IsNull()) {1465const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock);1466if (pindex && pindex->nChainWork > 0) {1467if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {1468state->pindexBestKnownBlock = pindex;1469}1470state->hashLastUnknownBlock.SetNull();1471}1472}1473}1475void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {1476CNodeState *state = State(nodeid);1477assert(state != nullptr);1479ProcessBlockAvailability(nodeid);1481const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);1482if (pindex && pindex->nChainWork > 0) {1483// An actually better block was announced.1484if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {1485state->pindexBestKnownBlock = pindex;1486}1487} else {1488// An unknown block was announced; just assume that the latest one is the best one.1489state->hashLastUnknownBlock = hash;1490}1491}1493// Logic for calculating which blocks to download from a given peer, given our current tip.1494void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int count, std::vector<const CBlockIndex*>& vBlocks, NodeId& nodeStaller)1495{1496if (count == 0)1497return;1499vBlocks.reserve(vBlocks.size() + count);1500CNodeState *state = State(peer.m_id);