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.
3251const CBlockIndex *pindexLast = nullptr;3253// We'll set already_validated_work to true if these headers are3254// successfully processed as part of a low-work headers sync in progress3255// (either in PRESYNC or REDOWNLOAD phase).3256// If true, this will mean that any headers returned to us (ie during3257// REDOWNLOAD) can be validated without further anti-DoS checks.3258bool already_validated_work = false;3260// If we're in the middle of headers sync, let it do its magic.3261bool have_headers_sync = false;3262{3263LOCK(peer.m_headers_sync_mutex);3265already_validated_work = IsContinuationOfLowWorkHeadersSync(peer, pfrom, headers);3267// The headers we passed in may have been:3268// - untouched, perhaps if no headers-sync was in progress, or some3269// failure occurred3270// - erased, such as if the headers were successfully processed and no3271// additional headers processing needs to take place (such as if we3272// are still in PRESYNC)3273// - replaced with headers that are now ready for validation, such as3274// during the REDOWNLOAD phase of a low-work headers sync.3275// So just check whether we still have headers that we need to process,3276// or not.3277if (headers.empty()) {3278return;3279}3281have_headers_sync = !!peer.m_headers_sync;3282}3284// Do these headers connect to something in our block index?3285const CBlockIndex *chain_start_header{WITH_LOCK(::cs_main, return m_chainman.m_blockman.LookupBlockIndex(headers[0].hashPrevBlock))};3286bool headers_connect_blockindex{chain_start_header != nullptr};3288if (!headers_connect_blockindex) {3289// This could be a BIP 130 block announcement, use3290// special logic for handling headers that don't connect, as this3291// could be benign.3292HandleUnconnectingHeaders(pfrom, peer, headers);3293return;3294}3296// If headers connect, assume that this is in response to any outstanding getheaders3297// request we may have sent, and clear out the time of our last request. Non-connecting3298// headers cannot be a response to a getheaders request.3299peer.m_last_getheaders_timestamp = {};3301// If the headers we received are already in memory and an ancestor of3302// m_best_header or our tip, skip anti-DoS checks. These headers will not3303// use any more memory (and we are not leaking information that could be3304// used to fingerprint us).3305const CBlockIndex *last_received_header{nullptr};3306{3307LOCK(cs_main);3308last_received_header = m_chainman.m_blockman.LookupBlockIndex(headers.back().GetHash());3309already_validated_work = already_validated_work || IsAncestorOfBestHeaderOrTip(last_received_header);3310}3312// If our peer has NetPermissionFlags::NoBan privileges, then bypass our3313// anti-DoS logic (this saves bandwidth when we connect to a trusted peer3314// on startup).3315if (pfrom.HasPermission(NetPermissionFlags::NoBan)) {3316already_validated_work = true;3317}3319// At this point, the headers connect to something in our block index.3320// Do anti-DoS checks to determine if we should process or store for later3321// processing.3322if (!already_validated_work && TryLowWorkHeadersSync(peer, pfrom,3323*chain_start_header, headers)) {3324// If we successfully started a low-work headers sync, then there3325// should be no headers to process any further.3326Assume(headers.empty());3327return;3328}3330// At this point, we have a set of headers with sufficient work on them3331// which can be processed.3333// If we don't have the last header, then this peer will have given us3334// something new (if these headers are valid).3335bool received_new_header{last_received_header == nullptr};3337// Now process all the headers.3338BlockValidationState state;3339const bool processed{m_chainman.ProcessNewBlockHeaders(headers,3340/*min_pow_checked=*/true,3341state, &pindexLast)};3342if (!processed) {3343if (state.IsInvalid()) {3344if (!pfrom.IsInboundConn() && state.GetResult() == BlockValidationResult::BLOCK_CACHED_INVALID) {3345// Warn user if outgoing peers send us headers of blocks that we previously marked as invalid.3346LogWarning("%s (received from peer=%i). "3347"If this happens with all peers, consider database corruption (that -reindex may fix) "3348"or a potential consensus incompatibility.",3349state.GetDebugMessage(), pfrom.GetId());3350}3351MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");3352return;3353}3354}3355assert(pindexLast);3357if (processed && received_new_header) {3358LogBlockHeader(*pindexLast, pfrom, /*via_compact_block=*/false);3359}3361// Consider fetching more headers if we are not using our headers-sync mechanism.3362if (nCount == m_opts.max_headers_result && !have_headers_sync) {3363// Headers message had its maximum size; the peer may have more headers.3364if (MaybeSendGetHeaders(pfrom, GetLocator(pindexLast), peer)) {3365LogDebug(BCLog::NET, "more getheaders (%d) to end to peer=%d", pindexLast->nHeight, pfrom.GetId());3366}3367}3369UpdatePeerStateForReceivedHeaders(pfrom, *pindexLast, received_new_header, nCount == m_opts.max_headers_result);3371// Consider immediately downloading blocks.3372HeadersDirectFetchBlocks(pfrom, peer, *pindexLast);3374return;3375}3377std::optional<node::PackageToValidate> PeerManagerImpl::ProcessInvalidTx(NodeId nodeid, const CTransactionRef& ptx, const TxValidationState& state,3378bool first_time_failure)3379{3380AssertLockNotHeld(m_peer_mutex);3381AssertLockHeld(g_msgproc_mutex);3382AssertLockHeld(m_tx_download_mutex);3384PeerRef peer{GetPeerRef(nodeid)};3386LogDebug(BCLog::MEMPOOLREJ, "%s (wtxid=%s) from peer=%d was not accepted: %s\n",3387ptx->GetHash().ToString(),3388ptx->GetWitnessHash().ToString(),3389nodeid,3390state.ToString());3392const auto& [add_extra_compact_tx, unique_parents, package_to_validate] = m_txdownloadman.MempoolRejectedTx(ptx, state, nodeid, first_time_failure);3394if (add_extra_compact_tx && RecursiveDynamicUsage(*ptx) < 100000) {3395AddToCompactExtraTransactions(ptx);3396}3397for (const Txid& parent_txid : unique_parents) {3398if (peer) AddKnownTx(*peer, parent_txid.ToUint256());3399}3401return package_to_validate;3402}3404void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, const std::list<CTransactionRef>& replaced_transactions)3405{3406AssertLockNotHeld(m_peer_mutex);3407AssertLockHeld(g_msgproc_mutex);3408AssertLockHeld(m_tx_download_mutex);3410m_txdownloadman.MempoolAcceptedTx(tx);3412LogDebug(BCLog::MEMPOOL, "AcceptToMemoryPool: peer=%d: accepted %s (wtxid=%s) (poolsz %u txn, %u kB)\n",3413nodeid,3414tx->GetHash().ToString(),3415tx->GetWitnessHash().ToString(),3416m_mempool.size(), m_mempool.DynamicMemoryUsage() / 1000);3418InitiateTxBroadcastToAll(tx->GetWitnessHash());3420for (const CTransactionRef& removedTx : replaced_transactions) {3421AddToCompactExtraTransactions(removedTx);3422}3423}3425void PeerManagerImpl::ProcessPackageResult(const node::PackageToValidate& package_to_validate, const PackageMempoolAcceptResult& package_result)3426{3427AssertLockNotHeld(m_peer_mutex);3428AssertLockHeld(g_msgproc_mutex);3429AssertLockHeld(m_tx_download_mutex);3431const auto& package = package_to_validate.m_txns;3432const auto& senders = package_to_validate.m_senders;3434if (package_result.m_state.IsInvalid()) {3435m_txdownloadman.MempoolRejectedPackage(package);3436}3437// We currently only expect to process 1-parent-1-child packages. Remove if this changes.3438if (!Assume(package.size() == 2)) return;3440// Iterate backwards to erase in-package descendants from the orphanage before they become3441// relevant in AddChildrenToWorkSet.3442auto package_iter = package.rbegin();3443auto senders_iter = senders.rbegin();3444while (package_iter != package.rend()) {3445const auto& tx = *package_iter;3446const NodeId nodeid = *senders_iter;3447const auto it_result{package_result.m_tx_results.find(tx->GetWitnessHash())};3449// It is not guaranteed that a result exists for every transaction.3450if (it_result != package_result.m_tx_results.end()) {3451const auto& tx_result = it_result->second;3452switch (tx_result.m_result_type) {3453case MempoolAcceptResult::ResultType::VALID:3454{3455ProcessValidTx(nodeid, tx, tx_result.m_replaced_transactions);3456break;3457}3458case MempoolAcceptResult::ResultType::INVALID:3459case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:3460{3461// Don't add to vExtraTxnForCompact, as these transactions should have already been3462// added there when added to the orphanage or rejected for TX_RECONSIDERABLE.3463// This should be updated if package submission is ever used for transactions3464// that haven't already been validated before.3465ProcessInvalidTx(nodeid, tx, tx_result.m_state, /*first_time_failure=*/false);3466break;3467}3468case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:3469{3470// AlreadyHaveTx() should be catching transactions that are already in mempool.3471Assume(false);3472break;3473}3474}3475}3476package_iter++;3477senders_iter++;3478}3479}3481// NOTE: the orphan processing used to be uninterruptible and quadratic, which could allow a peer to stall the node for3482// hours with specially crafted transactions. See https://bitcoincore.org/en/2024/07/03/disclose-orphan-dos.3483bool PeerManagerImpl::ProcessOrphanTx(Peer& peer)3484{3485AssertLockHeld(g_msgproc_mutex);3486LOCK2(::cs_main, m_tx_download_mutex);3488while (CTransactionRef porphanTx = m_txdownloadman.GetTxToReconsider(peer.m_id)) {3489const MempoolAcceptResult result = m_chainman.ProcessTransaction(porphanTx);3490const TxValidationState& state = result.m_state;3491const Txid& orphanHash = porphanTx->GetHash();3492const Wtxid& orphan_wtxid = porphanTx->GetWitnessHash();3494if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {3495LogDebug(BCLog::TXPACKAGES, " accepted orphan tx %s (wtxid=%s)\n", orphanHash.ToString(), orphan_wtxid.ToString());3496ProcessValidTx(peer.m_id, porphanTx, result.m_replaced_transactions);3497return true;3498} else if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS) {3499LogDebug(BCLog::TXPACKAGES, " invalid orphan tx %s (wtxid=%s) from peer=%d. %s\n",3500orphanHash.ToString(),