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.
3501orphan_wtxid.ToString(),3502peer.m_id,3503state.ToString());3505if (Assume(state.IsInvalid() &&3506state.GetResult() != TxValidationResult::TX_UNKNOWN &&3507state.GetResult() != TxValidationResult::TX_NO_MEMPOOL &&3508state.GetResult() != TxValidationResult::TX_RESULT_UNSET)) {3509ProcessInvalidTx(peer.m_id, porphanTx, state, /*first_time_failure=*/false);3510}3511return true;3512}3513}3515return false;3516}3518bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer,3519BlockFilterType filter_type, uint32_t start_height,3520const uint256& stop_hash, uint32_t max_height_diff,3521const CBlockIndex*& stop_index,3522BlockFilterIndex*& filter_index)3523{3524const bool supported_filter_type =3525(filter_type == BlockFilterType::BASIC &&3526(peer.m_our_services & NODE_COMPACT_FILTERS));3527if (!supported_filter_type) {3528LogDebug(BCLog::NET, "peer requested unsupported block filter type: %d, %s",3529static_cast<uint8_t>(filter_type), node.DisconnectMsg());3530node.fDisconnect = true;3531return false;3532}3534{3535LOCK(cs_main);3536stop_index = m_chainman.m_blockman.LookupBlockIndex(stop_hash);3538// Check that the stop block exists and the peer would be allowed to fetch it.3539if (!stop_index || !BlockRequestAllowed(*stop_index)) {3540LogDebug(BCLog::NET, "peer requested invalid block hash: %s, %s",3541stop_hash.ToString(), node.DisconnectMsg());3542node.fDisconnect = true;3543return false;3544}3545}3547uint32_t stop_height = stop_index->nHeight;3548if (start_height > stop_height) {3549LogDebug(BCLog::NET, "peer sent invalid getcfilters/getcfheaders with "3550"start height %d and stop height %d, %s",3551start_height, stop_height, node.DisconnectMsg());3552node.fDisconnect = true;3553return false;3554}3555if (stop_height - start_height >= max_height_diff) {3556LogDebug(BCLog::NET, "peer requested too many cfilters/cfheaders: %d / %d, %s",3557stop_height - start_height + 1, max_height_diff, node.DisconnectMsg());3558node.fDisconnect = true;3559return false;3560}3562filter_index = GetBlockFilterIndex(filter_type);3563if (!filter_index) {3564LogDebug(BCLog::NET, "Filter index for supported type %s not found\n", BlockFilterTypeName(filter_type));3565return false;3566}3568return true;3569}3571void PeerManagerImpl::ProcessGetCFilters(CNode& node, Peer& peer, DataStream& vRecv)3572{3573uint8_t filter_type_ser;3574uint32_t start_height;3575uint256 stop_hash;3577vRecv >> filter_type_ser >> start_height >> stop_hash;3579const BlockFilterType filter_type = static_cast<BlockFilterType>(filter_type_ser);3581const CBlockIndex* stop_index;3582BlockFilterIndex* filter_index;3583if (!PrepareBlockFilterRequest(node, peer, filter_type, start_height, stop_hash,3584MAX_GETCFILTERS_SIZE, stop_index, filter_index)) {3585return;3586}3588std::vector<BlockFilter> filters;3589if (!filter_index->LookupFilterRange(start_height, stop_index, filters)) {3590LogDebug(BCLog::NET, "Failed to find block filter in index: filter_type=%s, start_height=%d, stop_hash=%s\n",3591BlockFilterTypeName(filter_type), start_height, stop_hash.ToString());3592return;3593}3595for (const auto& filter : filters) {3596MakeAndPushMessage(node, NetMsgType::CFILTER, filter);3597}3598}3600void PeerManagerImpl::ProcessGetCFHeaders(CNode& node, Peer& peer, DataStream& vRecv)3601{3602uint8_t filter_type_ser;3603uint32_t start_height;3604uint256 stop_hash;3606vRecv >> filter_type_ser >> start_height >> stop_hash;3608const BlockFilterType filter_type = static_cast<BlockFilterType>(filter_type_ser);3610const CBlockIndex* stop_index;3611BlockFilterIndex* filter_index;3612if (!PrepareBlockFilterRequest(node, peer, filter_type, start_height, stop_hash,3613MAX_GETCFHEADERS_SIZE, stop_index, filter_index)) {3614return;3615}3617uint256 prev_header;3618if (start_height > 0) {3619const CBlockIndex* const prev_block =3620stop_index->GetAncestor(static_cast<int>(start_height - 1));3621if (!filter_index->LookupFilterHeader(prev_block, prev_header)) {3622LogDebug(BCLog::NET, "Failed to find block filter header in index: filter_type=%s, block_hash=%s\n",3623BlockFilterTypeName(filter_type), prev_block->GetBlockHash().ToString());3624return;3625}3626}3628std::vector<uint256> filter_hashes;3629if (!filter_index->LookupFilterHashRange(start_height, stop_index, filter_hashes)) {3630LogDebug(BCLog::NET, "Failed to find block filter hashes in index: filter_type=%s, start_height=%d, stop_hash=%s\n",3631BlockFilterTypeName(filter_type), start_height, stop_hash.ToString());3632return;3633}3635MakeAndPushMessage(node, NetMsgType::CFHEADERS,3636filter_type_ser,3637stop_index->GetBlockHash(),3638prev_header,3639filter_hashes);3640}3642void PeerManagerImpl::ProcessGetCFCheckPt(CNode& node, Peer& peer, DataStream& vRecv)3643{3644uint8_t filter_type_ser;3645uint256 stop_hash;3647vRecv >> filter_type_ser >> stop_hash;3649const BlockFilterType filter_type = static_cast<BlockFilterType>(filter_type_ser);3651const CBlockIndex* stop_index;3652BlockFilterIndex* filter_index;3653if (!PrepareBlockFilterRequest(node, peer, filter_type, /*start_height=*/0, stop_hash,3654/*max_height_diff=*/std::numeric_limits<uint32_t>::max(),3655stop_index, filter_index)) {3656return;3657}3659std::vector<uint256> headers(stop_index->nHeight / CFCHECKPT_INTERVAL);3661// Populate headers.3662const CBlockIndex* block_index = stop_index;3663for (int i = headers.size() - 1; i >= 0; i--) {3664int height = (i + 1) * CFCHECKPT_INTERVAL;3665block_index = block_index->GetAncestor(height);3667if (!filter_index->LookupFilterHeader(block_index, headers[i])) {3668LogDebug(BCLog::NET, "Failed to find block filter header in index: filter_type=%s, block_hash=%s\n",3669BlockFilterTypeName(filter_type), block_index->GetBlockHash().ToString());3670return;3671}3672}3674MakeAndPushMessage(node, NetMsgType::CFCHECKPT,3675filter_type_ser,3676stop_index->GetBlockHash(),3677headers);3678}3680void PeerManagerImpl::ProcessBlock(CNode& node, const std::shared_ptr<const CBlock>& block, bool force_processing, bool min_pow_checked)3681{3682bool new_block{false};3683m_chainman.ProcessNewBlock(block, force_processing, min_pow_checked, &new_block);3684if (new_block) {3685node.m_last_block_time = GetTime<std::chrono::seconds>();3686// In case this block came from a different peer than we requested3687// from, we can erase the block request now anyway (as we just stored3688// this block to disk).3689LOCK(cs_main);3690RemoveBlockRequest(block->GetHash(), std::nullopt);3691} else {3692LOCK(cs_main);3693mapBlockSource.erase(block->GetHash());3694}3695}3697void PeerManagerImpl::ProcessCompactBlockTxns(CNode& pfrom, Peer& peer, const BlockTransactions& block_transactions)3698{3699std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();3700bool fBlockRead{false};3701{3702LOCK(cs_main);3704auto range_flight = mapBlocksInFlight.equal_range(block_transactions.blockhash);3705size_t already_in_flight = std::distance(range_flight.first, range_flight.second);3706bool requested_block_from_this_peer{false};3708// Multimap ensures ordering of outstanding requests. It's either empty or first in line.3709bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());3711while (range_flight.first != range_flight.second) {3712auto [node_id, block_it] = range_flight.first->second;3713if (node_id == pfrom.GetId() && block_it->partialBlock) {3714requested_block_from_this_peer = true;3715break;3716}3717range_flight.first++;3718}3720if (!requested_block_from_this_peer) {3721LogDebug(BCLog::NET, "Peer %d sent us block transactions for block we weren't expecting\n", pfrom.GetId());3722return;3723}3725PartiallyDownloadedBlock& partialBlock = *range_flight.first->second.second->partialBlock;3727if (partialBlock.header.IsNull()) {3728// It is possible for the header to be empty if a previous call to FillBlock wiped the header, but left3729// the PartiallyDownloadedBlock pointer around (i.e. did not call RemoveBlockRequest). In this case, we3730// should not call LookupBlockIndex below.3731RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId());3732Misbehaving(peer, "previous compact block reconstruction attempt failed");3733LogDebug(BCLog::NET, "Peer %d sent compact block transactions multiple times", pfrom.GetId());3734return;3735}3737// We should not have gotten this far in compact block processing unless it's attached to a known header3738const CBlockIndex* prev_block{Assume(m_chainman.m_blockman.LookupBlockIndex(partialBlock.header.hashPrevBlock))};3739ReadStatus status = partialBlock.FillBlock(*pblock, block_transactions.txn,3740/*segwit_active=*/DeploymentActiveAfter(prev_block, m_chainman, Consensus::DEPLOYMENT_SEGWIT));3741if (status == READ_STATUS_INVALID) {3742RemoveBlockRequest(block_transactions.blockhash, pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect3743Misbehaving(peer, "invalid compact block/non-matching block transactions");3744return;3745} else if (status == READ_STATUS_FAILED) {3746if (first_in_flight) {3747// Might have collided, fall back to getdata now :(3748// We keep the failed partialBlock to disallow processing another compact block announcement from the same3749// peer for the same block. We let the full block download below continue under the same m_downloading_since3750// timer.