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.
1751for (const auto& stale_tx : stale_txs) {1752// Only hold lock per single submission1753LOCK(cs_main);1754auto mempool_acceptable = m_chainman.ProcessTransaction(stale_tx, /*test_accept=*/true);1755if (mempool_acceptable.m_result_type == MempoolAcceptResult::ResultType::VALID) {1756if (!m_tx_for_private_broadcast.TryGrantRetry(stale_tx)) continue;1757LogDebug(BCLog::PRIVBROADCAST,1758"Reattempting broadcast of stale txid=%s wtxid=%s",1759stale_tx->GetHash().ToString(), stale_tx->GetWitnessHash().ToString());1760++num_for_rebroadcast;1761} else {1762LogDebug(BCLog::PRIVBROADCAST, "Giving up broadcast attempts for txid=%s wtxid=%s: %s",1763stale_tx->GetHash().ToString(), stale_tx->GetWitnessHash().ToString(),1764mempool_acceptable.m_state.ToString());1765m_tx_for_private_broadcast.MarkResolved(stale_tx);1766}1767}1769// This could overshoot, but that is ok - we will open some private connections in vain.1770m_connman.m_private_broadcast.NumToOpenAdd(num_for_rebroadcast);1771}1773const auto delta{2min + FastRandomContext().randrange<std::chrono::milliseconds>(1min)};1774scheduler.scheduleFromNow([&] { ReattemptPrivateBroadcast(scheduler); }, delta);1775}1777void PeerManagerImpl::FinalizeNode(const CNode& node)1778{1779NodeId nodeid = node.GetId();1780{1781LOCK(cs_main);1782{1783// We remove the PeerRef from g_peer_map here, but we don't always1784// destruct the Peer. Sometimes another thread is still holding a1785// PeerRef, so the refcount is >= 1. Be careful not to do any1786// processing here that assumes Peer won't be changed before it's1787// destructed.1788PeerRef peer = RemovePeer(nodeid);1789assert(peer != nullptr);1790m_wtxid_relay_peers -= peer->m_wtxid_relay;1791assert(m_wtxid_relay_peers >= 0);1792}1793CNodeState *state = State(nodeid);1794assert(state != nullptr);1796if (state->fSyncStarted)1797nSyncStarted--;1799for (const QueuedBlock& entry : state->vBlocksInFlight) {1800auto range = mapBlocksInFlight.equal_range(entry.pindex->GetBlockHash());1801while (range.first != range.second) {1802auto [node_id, list_it] = range.first->second;1803if (node_id != nodeid) {1804range.first++;1805} else {1806range.first = mapBlocksInFlight.erase(range.first);1807}1808}1809}1810{1811LOCK(m_tx_download_mutex);1812m_txdownloadman.DisconnectedPeer(nodeid);1813}1814if (m_txreconciliation) m_txreconciliation->ForgetPeer(nodeid);1815m_num_preferred_download_peers -= state->fPreferredDownload;1816m_peers_downloading_from -= (!state->vBlocksInFlight.empty());1817assert(m_peers_downloading_from >= 0);1818m_outbound_peers_with_protect_from_disconnect -= state->m_chain_sync.m_protect;1819assert(m_outbound_peers_with_protect_from_disconnect >= 0);1821m_node_states.erase(nodeid);1823if (m_node_states.empty()) {1824// Do a consistency check after the last peer is removed.1825assert(mapBlocksInFlight.empty());1826assert(m_num_preferred_download_peers == 0);1827assert(m_peers_downloading_from == 0);1828assert(m_outbound_peers_with_protect_from_disconnect == 0);1829assert(m_wtxid_relay_peers == 0);1830WITH_LOCK(m_tx_download_mutex, m_txdownloadman.CheckIsEmpty());1831}1832} // cs_main1833if (node.fSuccessfullyConnected &&1834!node.IsBlockOnlyConn() && !node.IsPrivateBroadcastConn() && !node.IsInboundConn()) {1835// Only change visible addrman state for full outbound peers. We don't1836// call Connected() for feeler connections since they don't have1837// fSuccessfullyConnected set. Also don't call Connected() for private broadcast1838// connections since they could leak information in addrman.1839m_addrman.Connected(node.addr);1840}1841{1842LOCK(m_headers_presync_mutex);1843m_headers_presync_stats.erase(nodeid);1844}1845if (node.IsPrivateBroadcastConn()) {1846m_tx_for_private_broadcast.NodeDisconnected(nodeid);1847// We consider a transaction sent to a peer if we sent them an INV.1848// Normally they should request the transaction with GETDATA, but this may1849// not happen if they are already aware of the transaction.1850// If we didn't send them an INV, schedule a new connection to compensate1851// for this send failure. Whether we sent them an INV is not readily1852// available here, so use fSuccessfullyConnected because INV is sent right1853// after a successful handshake when there is a pending transaction.1854if (!node.fSuccessfullyConnected && m_tx_for_private_broadcast.HavePendingTransactions()) {1855m_connman.m_private_broadcast.NumToOpenAdd(1);1856}1857}1858LogDebug(BCLog::NET, "Cleared nodestate for peer=%d\n", nodeid);1859}1861bool PeerManagerImpl::HasAllDesirableServiceFlags(ServiceFlags services) const1862{1863// Shortcut for (services & GetDesirableServiceFlags(services)) == GetDesirableServiceFlags(services)1864return !(GetDesirableServiceFlags(services) & (~services));1865}1867ServiceFlags PeerManagerImpl::GetDesirableServiceFlags(ServiceFlags services) const1868{1869if (services & NODE_NETWORK_LIMITED) {1870// Limited peers are desirable when we are close to the tip.1871if (ApproximateBestBlockDepth() < NODE_NETWORK_LIMITED_ALLOW_CONN_BLOCKS) {1872return ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS);1873}1874}1875return ServiceFlags(NODE_NETWORK | NODE_WITNESS);1876}1878PeerRef PeerManagerImpl::GetPeerRef(NodeId id) const1879{1880LOCK(m_peer_mutex);1881auto it = m_peer_map.find(id);1882return it != m_peer_map.end() ? it->second : nullptr;1883}1885PeerRef PeerManagerImpl::RemovePeer(NodeId id)1886{1887PeerRef ret;1888LOCK(m_peer_mutex);1889auto it = m_peer_map.find(id);1890if (it != m_peer_map.end()) {1891ret = std::move(it->second);1892m_peer_map.erase(it);1893}1894return ret;1895}1897std::vector<PeerRef> PeerManagerImpl::GetAllPeers() const1898{1899std::vector<PeerRef> peers;1900LOCK(m_peer_mutex);1901peers.reserve(m_peer_map.size());1902for (const auto& [_, peer] : m_peer_map) {1903peers.push_back(peer);1904}1905return peers;1906}1908bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const1909{1910{1911LOCK(cs_main);1912const CNodeState* state = State(nodeid);1913if (state == nullptr)1914return false;1915stats.nSyncHeight = state->pindexBestKnownBlock ? state->pindexBestKnownBlock->nHeight : -1;1916stats.nCommonHeight = state->pindexLastCommonBlock ? state->pindexLastCommonBlock->nHeight : -1;1917for (const QueuedBlock& queue : state->vBlocksInFlight) {1918if (queue.pindex)1919stats.vHeightInFlight.push_back(queue.pindex->nHeight);1920}1921}1923PeerRef peer = GetPeerRef(nodeid);1924if (peer == nullptr) return false;1925stats.their_services = peer->m_their_services;1926// It is common for nodes with good ping times to suddenly become lagged,1927// due to a new block arriving or other large transfer.1928// Merely reporting pingtime might fool the caller into thinking the node was still responsive,1929// since pingtime does not update until the ping is complete, which might take a while.1930// So, if a ping is taking an unusually long time in flight,1931// the caller can immediately detect that this is happening.1932NodeClock::duration ping_wait{0us};1933if ((0 != peer->m_ping_nonce_sent) && (peer->m_ping_start.load() > NodeClock::epoch)) {1934ping_wait = NodeClock::now() - peer->m_ping_start.load();1935}1937if (auto tx_relay = peer->GetTxRelay(); tx_relay != nullptr) {1938stats.m_relay_txs = WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs);1939stats.m_fee_filter_received = tx_relay->m_fee_filter_received.load();1940LOCK(tx_relay->m_tx_inventory_mutex);1941stats.m_last_inv_seq = tx_relay->m_last_inv_sequence;1942stats.m_inv_to_send = tx_relay->m_tx_inventory_to_send.size();1943} else {1944stats.m_relay_txs = false;1945stats.m_fee_filter_received = 0;1946stats.m_inv_to_send = 0;1947}1949stats.m_ping_wait = ping_wait;1950stats.m_addr_processed = peer->m_addr_processed.load();1951stats.m_addr_rate_limited = peer->m_addr_rate_limited.load();1952stats.m_addr_relay_enabled = peer->m_addr_relay_enabled.load();1953{1954LOCK(peer->m_headers_sync_mutex);1955if (peer->m_headers_sync) {1956stats.presync_height = peer->m_headers_sync->GetPresyncHeight();1957}1958}1959stats.time_offset = peer->m_time_offset;1961return true;1962}1964std::vector<node::TxOrphanage::OrphanInfo> PeerManagerImpl::GetOrphanTransactions()1965{1966LOCK(m_tx_download_mutex);1967return m_txdownloadman.GetOrphanTransactions();1968}1970PeerManagerInfo PeerManagerImpl::GetInfo() const1971{1972LOCK(m_inv_to_send_mutex);1973return PeerManagerInfo{1974.median_outbound_time_offset = m_outbound_time_offsets.Median(),1975.ignores_incoming_txs = m_opts.ignore_incoming_txs,1976.private_broadcast = m_opts.private_broadcast,1977.tx_send_rate = m_opts.tx_send_rate,1978.inbound_bucket = m_inbound_inv_bucket.info(),1979.outbound_bucket = m_outbound_inv_bucket.info(),1980};1981}1983std::vector<PrivateBroadcast::TxBroadcastInfo> PeerManagerImpl::GetPrivateBroadcastInfo() const1984{1985return m_tx_for_private_broadcast.GetBroadcastInfo();1986}1988std::vector<CTransactionRef> PeerManagerImpl::AbortPrivateBroadcast(const uint256& id)1989{1990const auto snapshot{m_tx_for_private_broadcast.GetBroadcastInfo()};1991std::vector<CTransactionRef> removed_txs;1993size_t connections_cancelled{0};1994for (const auto& tx_info : snapshot) {1995const CTransactionRef& tx{tx_info.tx};1996if (tx->GetHash().ToUint256() != id && tx->GetWitnessHash().ToUint256() != id) continue;1997if (const auto remaining_sends{m_tx_for_private_broadcast.Remove(tx)}) {1998removed_txs.push_back(tx);1999connections_cancelled += *remaining_sends;2000}