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.
4251return;4252}4254// if (feature_id == NetMsgFeature::FOO) {4255// ...4256// return;4257// }4259// ignore unknown feature_id4260LogDebug(BCLog::NET, "unknown feature advertised: %s", SanitizeString(feature_id));4261return;4262}4264// Received from a peer demonstrating readiness to announce transactions via reconciliations.4265// This feature negotiation must happen between VERSION and VERACK to avoid relay problems4266// from switching announcement protocols after the connection is up.4267if (msg_type == NetMsgType::SENDTXRCNCL) {4268if (!m_txreconciliation) {4269LogDebug(BCLog::NET, "sendtxrcncl from peer=%d ignored, as our node does not have txreconciliation enabled\n", pfrom.GetId());4270return;4271}4273if (pfrom.fSuccessfullyConnected) {4274LogDebug(BCLog::NET, "sendtxrcncl received after verack, %s", pfrom.DisconnectMsg());4275pfrom.fDisconnect = true;4276return;4277}4279// Peer must not offer us reconciliations if we specified no tx relay support in VERSION.4280if (RejectIncomingTxs(pfrom)) {4281LogDebug(BCLog::NET, "sendtxrcncl received to which we indicated no tx relay, %s", pfrom.DisconnectMsg());4282pfrom.fDisconnect = true;4283return;4284}4286// Peer must not offer us reconciliations if they specified no tx relay support in VERSION.4287// This flag might also be false in other cases, but the RejectIncomingTxs check above4288// eliminates them, so that this flag fully represents what we are looking for.4289const auto* tx_relay = peer.GetTxRelay();4290if (!tx_relay || !WITH_LOCK(tx_relay->m_bloom_filter_mutex, return tx_relay->m_relay_txs)) {4291LogDebug(BCLog::NET, "sendtxrcncl received which indicated no tx relay to us, %s", pfrom.DisconnectMsg());4292pfrom.fDisconnect = true;4293return;4294}4296uint32_t peer_txreconcl_version;4297uint64_t remote_salt;4298vRecv >> peer_txreconcl_version >> remote_salt;4300const ReconciliationRegisterResult result = m_txreconciliation->RegisterPeer(pfrom.GetId(), pfrom.IsInboundConn(),4301peer_txreconcl_version, remote_salt);4302switch (result) {4303case ReconciliationRegisterResult::NOT_FOUND:4304LogDebug(BCLog::NET, "Ignore unexpected txreconciliation signal from peer=%d\n", pfrom.GetId());4305break;4306case ReconciliationRegisterResult::SUCCESS:4307break;4308case ReconciliationRegisterResult::ALREADY_REGISTERED:4309LogDebug(BCLog::NET, "txreconciliation protocol violation (sendtxrcncl received from already registered peer), %s", pfrom.DisconnectMsg());4310pfrom.fDisconnect = true;4311return;4312case ReconciliationRegisterResult::PROTOCOL_VIOLATION:4313LogDebug(BCLog::NET, "txreconciliation protocol violation, %s", pfrom.DisconnectMsg());4314pfrom.fDisconnect = true;4315return;4316}4317return;4318}4320if (!pfrom.fSuccessfullyConnected) {4321LogDebug(BCLog::NET, "Unsupported message \"%s\" prior to verack from peer=%d\n", SanitizeString(msg_type), pfrom.GetId());4322return;4323}4325if (pfrom.IsPrivateBroadcastConn()) {4326if (msg_type != NetMsgType::PONG && msg_type != NetMsgType::GETDATA) {4327LogDebug(BCLog::PRIVBROADCAST, "Ignoring incoming message '%s', %s", msg_type, pfrom.LogPeer());4328return;4329}4330}4332if (msg_type == NetMsgType::ADDR || msg_type == NetMsgType::ADDRV2) {4333const auto ser_params{4334msg_type == NetMsgType::ADDRV2 ?4335// Set V2 param so that the CNetAddr and CAddress4336// unserialize methods know that an address in v2 format is coming.4337CAddress::V2_NETWORK :4338CAddress::V1_NETWORK,4339};4341std::vector<CAddress> vAddr;4342vRecv >> ser_params(vAddr);4343ProcessAddrs(msg_type, pfrom, peer, std::move(vAddr), interruptMsgProc);4344return;4345}4347if (msg_type == NetMsgType::INV) {4348std::vector<CInv> vInv;4349vRecv >> vInv;4350if (vInv.size() > MAX_INV_SZ)4351{4352Misbehaving(peer, strprintf("inv message size = %u", vInv.size()));4353return;4354}4356const bool reject_tx_invs{RejectIncomingTxs(pfrom)};4357std::unordered_set<uint256, SaltedUint256Hasher> seen_txids{0, m_txhash_hasher};4358std::unordered_set<uint256, SaltedUint256Hasher> seen_wtxids{0, m_txhash_hasher};4360LOCK2(cs_main, m_tx_download_mutex);4362const auto current_time{GetTime<std::chrono::microseconds>()};4363uint256* best_block{nullptr};4365for (CInv& inv : vInv) {4366if (interruptMsgProc) return;4368// Ignore INVs that don't match wtxidrelay setting.4369// Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.4370// This is fine as no INV messages are involved in that process.4371if (peer.m_wtxid_relay) {4372if (inv.IsMsgTx()) continue;4373} else {4374if (inv.IsMsgWtx()) continue;4375}4377if (inv.IsMsgBlk()) {4378const bool fAlreadyHave = AlreadyHaveBlock(inv.hash);4379LogDebug(BCLog::NET, "got inv: %s %s peer=%d", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());4381UpdateBlockAvailability(pfrom.GetId(), inv.hash);4382if (!fAlreadyHave && !m_chainman.m_blockman.LoadingBlocks() && !IsBlockRequested(inv.hash)) {4383// Headers-first is the primary method of announcement on4384// the network. If a node fell back to sending blocks by4385// inv, it may be for a re-org, or because we haven't4386// completed initial headers sync. The final block hash4387// provided should be the highest, so send a getheaders and4388// then fetch the blocks we need to catch up.4389best_block = &inv.hash;4390}4391} else if (inv.IsGenTxMsg()) {4392if (reject_tx_invs) {4393LogDebug(BCLog::NET, "transaction (%s) inv sent in violation of protocol, %s", inv.hash.ToString(), pfrom.DisconnectMsg());4394pfrom.fDisconnect = true;4395return;4396}4397// MSG_WITNESS_TX is treated as a txid, despite only being specified for getdata.4398auto& seen_hashes{inv.IsMsgWtx() ? seen_wtxids : seen_txids};4399if (!seen_hashes.insert(inv.hash).second) continue;4400const GenTxid gtxid = ToGenTxid(inv);4401AddKnownTx(peer, inv.hash);4403if (!m_chainman.IsInitialBlockDownload()) {4404const bool fAlreadyHave{m_txdownloadman.AddTxAnnouncement(pfrom.GetId(), gtxid, current_time)};4405LogDebug(BCLog::NET, "got inv: %s %s peer=%d", inv.ToString(), fAlreadyHave ? "have" : "new", pfrom.GetId());4406}4407} else {4408LogDebug(BCLog::NET, "Unknown inv type \"%s\" received from peer=%d\n", inv.ToString(), pfrom.GetId());4409}4410}4412if (best_block != nullptr) {4413// If we haven't started initial headers-sync with this peer, then4414// consider sending a getheaders now. On initial startup, there's a4415// reliability vs bandwidth tradeoff, where we are only trying to do4416// initial headers sync with one peer at a time, with a long4417// timeout (at which point, if the sync hasn't completed, we will4418// disconnect the peer and then choose another). In the meantime,4419// as new blocks are found, we are willing to add one new peer per4420// block to sync with as well, to sync quicker in the case where4421// our initial peer is unresponsive (but less bandwidth than we'd4422// use if we turned on sync with all peers).4423CNodeState& state{*Assert(State(pfrom.GetId()))};4424if (state.fSyncStarted || (!peer.m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {4425if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), peer)) {4426LogDebug(BCLog::NET, "getheaders (%d) %s to peer=%d\n",4427m_chainman.m_best_header->nHeight, best_block->ToString(),4428pfrom.GetId());4429}4430if (!state.fSyncStarted) {4431peer.m_inv_triggered_getheaders_before_sync = true;4432// Update the last block hash that triggered a new headers4433// sync, so that we don't turn on headers sync with more4434// than 1 new peer every new block.4435m_last_block_inv_triggering_headers_sync = *best_block;4436}4437}4438}4440return;4441}4443if (msg_type == NetMsgType::GETDATA) {4444std::vector<CInv> vInv;4445vRecv >> vInv;4446if (vInv.size() > MAX_INV_SZ)4447{4448Misbehaving(peer, strprintf("getdata message size = %u", vInv.size()));4449return;4450}4452LogDebug(BCLog::NET, "received getdata (%u invsz) peer=%d\n", vInv.size(), pfrom.GetId());4454if (vInv.size() > 0) {4455LogDebug(BCLog::NET, "received getdata for: %s peer=%d\n", vInv[0].ToString(), pfrom.GetId());4456}4458if (pfrom.IsPrivateBroadcastConn()) {4459const auto pushed_tx_opt{m_tx_for_private_broadcast.GetTxForNode(pfrom.GetId())};4460if (!pushed_tx_opt) {4461LogDebug(BCLog::PRIVBROADCAST, "Disconnecting: got GETDATA without sending an INV, %s",4462pfrom.LogPeer());4463pfrom.fDisconnect = true;4464return;4465}4467const CTransactionRef& pushed_tx{*pushed_tx_opt};4469// The GETDATA request must contain exactly one inv and it must be for the transaction4470// that we INVed to the peer earlier.4471if (vInv.size() == 1 && vInv[0].IsMsgTx() && vInv[0].hash == pushed_tx->GetHash().ToUint256()) {4473MakeAndPushMessage(pfrom, NetMsgType::TX, TX_WITH_WITNESS(*pushed_tx));4475peer.m_ping_queued = true; // Ensure a ping will be sent: mimic a request via RPC.4476MaybeSendPing(pfrom, peer, NodeClock::now());4477} else {4478LogDebug(BCLog::PRIVBROADCAST, "Disconnecting: got an unexpected GETDATA message, %s",4479pfrom.LogPeer());4480pfrom.fDisconnect = true;4481}4482return;4483}4485{4486LOCK(peer.m_getdata_requests_mutex);4487peer.m_getdata_requests.insert(peer.m_getdata_requests.end(), vInv.begin(), vInv.end());4488ProcessGetData(pfrom, peer, interruptMsgProc);4489}4491return;4492}4494if (msg_type == NetMsgType::GETBLOCKS) {4495CBlockLocator locator;4496uint256 hashStop;4497vRecv >> locator >> hashStop;4499if (locator.vHave.size() > MAX_LOCATOR_SZ) {4500LogDebug(BCLog::NET, "getblocks locator size %lld > %d, %s", locator.vHave.size(), MAX_LOCATOR_SZ, pfrom.DisconnectMsg());