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.
4751}4753if (package_to_validate) {4754const auto package_result{ProcessNewPackage(m_chainman.ActiveChainstate(), m_mempool, package_to_validate->m_txns, /*test_accept=*/false, /*client_maxfeerate=*/std::nullopt)};4755LogDebug(BCLog::TXPACKAGES, "package evaluation for %s: %s\n", package_to_validate->ToString(),4756package_result.m_state.IsValid() ? "package accepted" : "package rejected");4757ProcessPackageResult(package_to_validate.value(), package_result);4758}4759return;4760}4762// ReceivedTx should not be telling us to validate the tx and a package.4763Assume(!package_to_validate.has_value());4765const MempoolAcceptResult result = m_chainman.ProcessTransaction(ptx);4766const TxValidationState& state = result.m_state;4768if (result.m_result_type == MempoolAcceptResult::ResultType::VALID) {4769ProcessValidTx(pfrom.GetId(), ptx, result.m_replaced_transactions);4770pfrom.m_last_tx_time = GetTime<std::chrono::seconds>();4771}4772if (state.IsInvalid()) {4773if (auto package_to_validate{ProcessInvalidTx(pfrom.GetId(), ptx, state, /*first_time_failure=*/true)}) {4774const auto package_result{ProcessNewPackage(m_chainman.ActiveChainstate(), m_mempool, package_to_validate->m_txns, /*test_accept=*/false, /*client_maxfeerate=*/std::nullopt)};4775LogDebug(BCLog::TXPACKAGES, "package evaluation for %s: %s\n", package_to_validate->ToString(),4776package_result.m_state.IsValid() ? "package accepted" : "package rejected");4777ProcessPackageResult(package_to_validate.value(), package_result);4778}4779}4781return;4782}4784if (msg_type == NetMsgType::CMPCTBLOCK)4785{4786// Ignore cmpctblock received while importing4787if (m_chainman.m_blockman.LoadingBlocks()) {4788LogDebug(BCLog::CMPCTBLOCK, "%s sent us a compact block even though we are still loading blocks!", pfrom.LogPeer());4789return;4790} else if (m_opts.ignore_incoming_txs) {4791LogDebug(BCLog::CMPCTBLOCK, "%s sent us a compact block even though we are blocksonly!", pfrom.LogPeer());4792return;4793}4795{4796LOCK(cs_main);4797const CNodeState *nodestate = State(pfrom.GetId());4798if (!nodestate->m_provides_cmpctblocks) {4799LogDebug(BCLog::CMPCTBLOCK, "%s sent us a compact block despite never having sent us a SENDCMPCT!", pfrom.LogPeer());4800return;4801}4802}4804CBlockHeaderAndShortTxIDs cmpctblock;4805vRecv >> cmpctblock;4807bool received_new_header = false;4808const auto blockhash = cmpctblock.header.GetHash();4810{4811LOCK(cs_main);4813const CBlockIndex* prev_block = m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock);4814if (!prev_block) {4815// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers4816if (!m_chainman.IsInitialBlockDownload()) {4817MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), peer);4818}4819return;4820} else if (prev_block->nChainWork + GetBlockProof(cmpctblock.header) < GetAntiDoSWorkThreshold()) {4821// If we get a low-work header in a compact block, we can ignore it.4822LogDebug(BCLog::NET, "Ignoring low-work compact block from peer %d\n", pfrom.GetId());4823return;4824}4826if (!m_chainman.m_blockman.LookupBlockIndex(blockhash)) {4827received_new_header = true;4828}4829}4831const CBlockIndex *pindex = nullptr;4832BlockValidationState state;4833if (!m_chainman.ProcessNewBlockHeaders({{cmpctblock.header}}, /*min_pow_checked=*/true, state, &pindex)) {4834if (state.IsInvalid()) {4835MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block=*/true, "invalid header via cmpctblock");4836return;4837}4838}4840// If AcceptBlockHeader returned true, it set pindex4841Assert(pindex);4842if (received_new_header) {4843LogBlockHeader(*pindex, pfrom, /*via_compact_block=*/true);4844}4846bool fProcessBLOCKTXN = false;4848// If we end up treating this as a plain headers message, call that as well4849// without cs_main.4850bool fRevertToHeaderProcessing = false;4852// Keep a CBlock for "optimistic" compactblock reconstructions (see4853// below)4854std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();4855bool fBlockReconstructed = false;4857{4858LOCK(cs_main);4859UpdateBlockAvailability(pfrom.GetId(), pindex->GetBlockHash());4861CNodeState *nodestate = State(pfrom.GetId());4863// If this was a new header with more work than our tip, update the4864// peer's last block announcement time4865if (received_new_header && pindex->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {4866nodestate->m_last_block_announcement = GetTime();4867}4869if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here4870return;4872auto range_flight = mapBlocksInFlight.equal_range(pindex->GetBlockHash());4873size_t already_in_flight = std::distance(range_flight.first, range_flight.second);4874bool requested_block_from_this_peer{false};4876// Multimap ensures ordering of outstanding requests. It's either empty or first in line.4877bool first_in_flight = already_in_flight == 0 || (range_flight.first->second.first == pfrom.GetId());4879while (range_flight.first != range_flight.second) {4880if (range_flight.first->second.first == pfrom.GetId()) {4881requested_block_from_this_peer = true;4882break;4883}4884range_flight.first++;4885}4887if (!requested_block_from_this_peer && !pfrom.m_bip152_highbandwidth_to) {4888LogDebug(BCLog::CMPCTBLOCK, "%s, not marked as high-bandwidth, sent us an unsolicited compact block!", pfrom.LogPeer());4889return;4890}4892if (pindex->nChainWork <= m_chainman.ActiveChain().Tip()->nChainWork || // We know something better4893pindex->nTx != 0) { // We had this block at some point, but pruned it4894if (requested_block_from_this_peer) {4895// We requested this block for some reason, but our mempool will probably be useless4896// so we just grab the block via normal getdata4897std::vector<CInv> vInv(1);4898vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(peer), blockhash);4899MakeAndPushMessage(pfrom, NetMsgType::GETDATA, vInv);4900}4901return;4902}4904// If we're not close to tip yet, give up and let parallel block fetch work its magic4905if (!already_in_flight && !CanDirectFetch()) {4906return;4907}4909// We want to be a bit conservative just to be extra careful about DoS4910// possibilities in compact block processing...4911if (pindex->nHeight <= m_chainman.ActiveChain().Height() + 2) {4912if ((already_in_flight < MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK && nodestate->vBlocksInFlight.size() < MAX_BLOCKS_IN_TRANSIT_PER_PEER) ||4913requested_block_from_this_peer) {4914std::list<QueuedBlock>::iterator* queuedBlockIt = nullptr;4915if (!BlockRequested(pfrom.GetId(), *pindex, &queuedBlockIt)) {4916if (!(*queuedBlockIt)->partialBlock)4917(*queuedBlockIt)->partialBlock.reset(new PartiallyDownloadedBlock(&m_mempool));4918else {4919// The block was already in flight using compact blocks from the same peer4920LogDebug(BCLog::NET, "Peer sent us compact block we were already syncing!\n");4921return;4922}4923}4925PartiallyDownloadedBlock& partialBlock = *(*queuedBlockIt)->partialBlock;4926ReadStatus status = partialBlock.InitData(cmpctblock, vExtraTxnForCompact);4927if (status == READ_STATUS_INVALID) {4928RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId()); // Reset in-flight state in case Misbehaving does not result in a disconnect4929Misbehaving(peer, "invalid compact block");4930return;4931} else if (status == READ_STATUS_FAILED) {4932if (first_in_flight) {4933// Duplicate txindexes, the block is now in-flight, so just request it4934std::vector<CInv> vInv(1);4935vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(peer), blockhash);4936MakeAndPushMessage(pfrom, NetMsgType::GETDATA, vInv);4937} else {4938// Give up for this peer and wait for other peer(s)4939RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId());4940}4941return;4942}4944BlockTransactionsRequest req;4945for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) {4946if (!partialBlock.IsTxAvailable(i))4947req.indexes.push_back(i);4948}4949if (req.indexes.empty()) {4950fProcessBLOCKTXN = true;4951} else if (first_in_flight) {4952// We will try to round-trip any compact blocks we get on failure,4953// as long as it's first...4954req.blockhash = pindex->GetBlockHash();4955MakeAndPushMessage(pfrom, NetMsgType::GETBLOCKTXN, req);4956} else if (pfrom.m_bip152_highbandwidth_to &&4957(!pfrom.IsInboundConn() ||4958IsBlockRequestedFromOutbound(blockhash) ||4959already_in_flight < MAX_CMPCTBLOCKS_INFLIGHT_PER_BLOCK - 1)) {4960// ... or it's a hb relay peer and:4961// - peer is outbound, or4962// - we already have an outbound attempt in flight(so we'll take what we can get), or4963// - it's not the final parallel download slot (which we may reserve for first outbound)4964req.blockhash = pindex->GetBlockHash();4965MakeAndPushMessage(pfrom, NetMsgType::GETBLOCKTXN, req);4966} else {4967// Give up for this peer and wait for other peer(s)4968RemoveBlockRequest(pindex->GetBlockHash(), pfrom.GetId());4969}4970} else {4971// This block is either already in flight from a different4972// peer, or this peer has too many blocks outstanding to4973// download from.4974// Optimistically try to reconstruct anyway since we might be4975// able to without any round trips.4976PartiallyDownloadedBlock tempBlock(&m_mempool);4977ReadStatus status = tempBlock.InitData(cmpctblock, vExtraTxnForCompact);4978if (status != READ_STATUS_OK) {4979// TODO: don't ignore failures4980return;4981}4982std::vector<CTransactionRef> dummy;4983const CBlockIndex* prev_block{Assume(m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock))};4984status = tempBlock.FillBlock(*pblock, dummy,4985/*segwit_active=*/DeploymentActiveAfter(prev_block, m_chainman, Consensus::DEPLOYMENT_SEGWIT));4986if (status == READ_STATUS_OK) {4987fBlockReconstructed = true;4988}4989}4990} else {4991if (requested_block_from_this_peer) {4992// We requested this block, but its far into the future, so our4993// mempool will probably be useless - request the block normally4994std::vector<CInv> vInv(1);4995vInv[0] = CInv(MSG_BLOCK | GetFetchFlags(peer), blockhash);4996MakeAndPushMessage(pfrom, NetMsgType::GETDATA, vInv);4997return;4998} else {4999// If this was an announce-cmpctblock, we want the same treatment as a header message5000fRevertToHeaderProcessing = true;