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.
2001}2002m_connman.m_private_broadcast.NumToOpenSub(connections_cancelled);2004return removed_txs;2005}2007void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx)2008{2009if (m_opts.max_extra_txs == 0) return;2010if (vExtraTxnForCompact.size() < m_opts.max_extra_txs) {2011if (vExtraTxnForCompact.empty()) vExtraTxnForCompact.reserve(m_opts.max_extra_txs);2012vExtraTxnForCompact.emplace_back(tx->GetWitnessHash(), tx);2013} else {2014vExtraTxnForCompact[vExtraTxnForCompactIt] = std::make_pair(tx->GetWitnessHash(), tx);2015}2016vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;2017}2019void PeerManagerImpl::Misbehaving(Peer& peer, const std::string& message)2020{2021LOCK(peer.m_misbehavior_mutex);2023const std::string message_prefixed = message.empty() ? "" : (": " + message);2024peer.m_should_discourage = true;2025LogDebug(BCLog::NET, "Misbehaving: peer=%d%s\n", peer.m_id, message_prefixed);2026TRACEPOINT(net, misbehaving_connection,2027peer.m_id,2028message.c_str()2029);2030}2032void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,2033bool via_compact_block, const std::string& message)2034{2035PeerRef peer{GetPeerRef(nodeid)};2036switch (state.GetResult()) {2037case BlockValidationResult::BLOCK_RESULT_UNSET:2038break;2039case BlockValidationResult::BLOCK_HEADER_LOW_WORK:2040// We didn't try to process the block because the header chain may have2041// too little work.2042break;2043// The node is providing invalid data:2044case BlockValidationResult::BLOCK_CONSENSUS:2045case BlockValidationResult::BLOCK_MUTATED:2046if (!via_compact_block) {2047if (peer) Misbehaving(*peer, message);2048return;2049}2050break;2051case BlockValidationResult::BLOCK_CACHED_INVALID:2052{2053// Discourage outbound (but not inbound) peers if on an invalid chain.2054// Exempt HB compact block peers. Manual connections are always protected from discouragement.2055if (peer && !via_compact_block && !peer->m_is_inbound) {2056if (peer) Misbehaving(*peer, message);2057return;2058}2059break;2060}2061case BlockValidationResult::BLOCK_INVALID_HEADER:2062case BlockValidationResult::BLOCK_INVALID_PREV:2063if (peer) Misbehaving(*peer, message);2064return;2065// Conflicting (but not necessarily invalid) data or different policy:2066case BlockValidationResult::BLOCK_MISSING_PREV:2067if (peer) Misbehaving(*peer, message);2068return;2069case BlockValidationResult::BLOCK_TIME_FUTURE:2070break;2071}2072if (message != "") {2073LogDebug(BCLog::NET, "peer=%d: %s\n", nodeid, message);2074}2075}2077bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex& block_index)2078{2079AssertLockHeld(cs_main);2080if (m_chainman.ActiveChain().Contains(block_index)) return true;2081return block_index.IsValid(BLOCK_VALID_SCRIPTS) && (m_chainman.m_best_header != nullptr) &&2082(m_chainman.m_best_header->GetBlockTime() - block_index.GetBlockTime() < STALE_RELAY_AGE_LIMIT) &&2083(GetBlockProofEquivalentTime(*m_chainman.m_best_header, block_index, *m_chainman.m_best_header, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);2084}2086util::Expected<void, std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index)2087{2088if (m_chainman.m_blockman.LoadingBlocks()) return util::Unexpected{"Loading blocks ..."};2090// The lock must be taken here before fetching Peer so another thread does2091// not delete the CNodeState from under the current thread, causing an2092// assertion failure in BlockRequested. This lock can be replaced with a2093// net-specific lock when more of CNodeState is moved into Peer.2094LOCK(cs_main);2096// Ensure this peer exists and hasn't been disconnected2097PeerRef peer = GetPeerRef(peer_id);2098if (peer == nullptr) return util::Unexpected{"Peer does not exist"};2100// Ignore pre-segwit peers2101if (!CanServeWitnesses(*peer)) return util::Unexpected{"Pre-SegWit peer"};2103// Forget about all prior requests2104RemoveBlockRequest(block_index.GetBlockHash(), std::nullopt);2106// Mark block as in-flight2107if (!BlockRequested(peer_id, block_index)) return util::Unexpected{"Already requested from this peer"};2109// Construct message to request the block2110const uint256& hash{block_index.GetBlockHash()};2111std::vector<CInv> invs{CInv(MSG_BLOCK | MSG_WITNESS_FLAG, hash)};2113// Send block request message to the peer2114bool success = m_connman.ForNode(peer_id, [this, &invs](CNode* node) {2115this->MakeAndPushMessage(*node, NetMsgType::GETDATA, invs);2116return true;2117});2119if (!success) return util::Unexpected{"Peer not fully connected"};2121LogDebug(BCLog::NET, "Requesting block %s from peer=%d\n",2122hash.ToString(), peer_id);2123return {};2124}2126std::unique_ptr<PeerManager> PeerManager::make(CConnman& connman, AddrMan& addrman,2127BanMan* banman, ChainstateManager& chainman,2128CTxMemPool& pool, node::Warnings& warnings, Options opts)2129{2130return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, warnings, opts);2131}2133PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman,2134BanMan* banman, ChainstateManager& chainman,2135CTxMemPool& pool, node::Warnings& warnings, Options opts)2136: m_rng{opts.deterministic_rng},2137m_fee_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}, m_rng},2138m_chainparams(chainman.GetParams()),2139m_connman(connman),2140m_addrman(addrman),2141m_banman(banman),2142m_chainman(chainman),2143m_mempool(pool),2144m_txdownloadman{node::TxDownloadOptions{pool, opts.deterministic_rng}},2145m_warnings{warnings},2146m_opts{opts},2147m_inbound_inv_bucket(/*rate=*/m_opts.tx_send_rate, /*mult=*/1.0),2148m_outbound_inv_bucket(/*rate=*/m_opts.tx_send_rate, /*mult=*/OUTBOUND_INVENTORY_BUCKET_MULTIPLIER)2149{2150// While Erlay support is incomplete, it must be enabled explicitly via -txreconciliation.2151// This argument can go away after Erlay support is complete.2152if (opts.reconcile_txs) {2153m_txreconciliation = std::make_unique<TxReconciliationTracker>(TXRECONCILIATION_VERSION);2154}2155}2157void PeerManagerImpl::StartScheduledTasks(CScheduler& scheduler)2158{2159// Stale tip checking and peer eviction are on two different timers, but we2160// don't want them to get out of sync due to drift in the scheduler, so we2161// combine them in one function and schedule at the quicker (peer-eviction)2162// timer.2163static_assert(EXTRA_PEER_CHECK_INTERVAL < STALE_CHECK_INTERVAL, "peer eviction timer should be less than stale tip check timer");2164scheduler.scheduleEvery([this] { this->CheckForStaleTipAndEvictPeers(); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL});2166// schedule next run for 10-15 minutes in the future2167const auto delta = 10min + FastRandomContext().randrange<std::chrono::milliseconds>(5min);2168scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);2170if (m_opts.private_broadcast) {2171scheduler.scheduleFromNow([&] { ReattemptPrivateBroadcast(scheduler); }, 0min);2172}2173}2175void PeerManagerImpl::ActiveTipChange(const CBlockIndex& new_tip, bool is_ibd)2176{2177// Ensure mempool mutex was released, otherwise deadlock may occur if another thread holding2178// m_tx_download_mutex waits on the mempool mutex.2179AssertLockNotHeld(m_mempool.cs);2180AssertLockNotHeld(m_tx_download_mutex);2182if (!is_ibd) {2183LOCK(m_tx_download_mutex);2184// If the chain tip has changed, previously rejected transactions might now be valid, e.g. due2185// to a timelock. Reset the rejection filters to give those transactions another chance if we2186// see them again.2187m_txdownloadman.ActiveTipChange();2188}2189}2191/**2192* Evict orphan txn pool entries based on a newly connected2193* block, remember the recently confirmed transactions, and delete tracked2194* announcements for them. Also save the time of the last tip update and2195* possibly reduce dynamic block stalling timeout.2196*/2197void PeerManagerImpl::BlockConnected(2198const ChainstateRole& role,2199const std::shared_ptr<const CBlock>& pblock,2200const CBlockIndex* pindex)2201{2202// Update this for all chainstate roles so that we don't mistakenly see peers2203// helping us do background IBD as having a stale tip.2204m_last_tip_update = GetTime<std::chrono::seconds>();2206// In case the dynamic timeout was doubled once or more, reduce it slowly back to its default value2207auto stalling_timeout = m_block_stalling_timeout.load();2208Assume(stalling_timeout >= BLOCK_STALLING_TIMEOUT_DEFAULT);2209if (stalling_timeout != BLOCK_STALLING_TIMEOUT_DEFAULT) {2210const auto new_timeout = std::max(std::chrono::duration_cast<std::chrono::seconds>(stalling_timeout * 0.85), BLOCK_STALLING_TIMEOUT_DEFAULT);2211if (m_block_stalling_timeout.compare_exchange_strong(stalling_timeout, new_timeout)) {2212LogDebug(BCLog::NET, "Decreased stalling timeout to %d seconds\n", count_seconds(new_timeout));2213}2214}2216// The following task can be skipped since we don't maintain a mempool for2217// the historical chainstate, or during ibd since we don't receive incoming2218// transactions from peers into the mempool.2219if (!role.historical && !m_chainman.IsInitialBlockDownload()) {2220LOCK(m_tx_download_mutex);2221m_txdownloadman.BlockConnected(pblock);2222}2223}2225void PeerManagerImpl::BlockDisconnected(const std::shared_ptr<const CBlock> &block, const CBlockIndex* pindex)2226{2227LOCK(m_tx_download_mutex);2228m_txdownloadman.BlockDisconnected();2229}2231/**2232* Maintain state about the best-seen block and fast-announce a compact block2233* to compatible peers.2234*/2235void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock)2236{2237auto pcmpctblock = std::make_shared<const CBlockHeaderAndShortTxIDs>(*pblock, FastRandomContext().rand64());2239LOCK(cs_main);2241if (pindex->nHeight <= m_highest_fast_announce)2242return;2243m_highest_fast_announce = pindex->nHeight;2245if (!DeploymentActiveAt(*pindex, m_chainman, Consensus::DEPLOYMENT_SEGWIT)) return;2247uint256 hashBlock(pblock->GetHash());2248const std::shared_future<CSerializedNetMsg> lazy_ser{2249std::async(std::launch::deferred, [&] { return NetMsg::Make(NetMsgType::CMPCTBLOCK, *pcmpctblock); })};