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.
4001// Only if this fails, disconnect this peer.4002if (MaybeDisconnectForTxRelayCapacity(pfrom, msg_type, /*protect_peer=*/pfrom.GetId())) return;4003MakeAndPushMessage(pfrom, NetMsgType::VERACK);4005// Potentially mark this peer as a preferred download peer.4006{4007LOCK(cs_main);4008CNodeState* state = State(pfrom.GetId());4009state->fPreferredDownload = (!pfrom.IsInboundConn() || pfrom.HasPermission(NetPermissionFlags::NoBan)) && !pfrom.IsAddrFetchConn() && CanServeBlocks(peer);4010m_num_preferred_download_peers += state->fPreferredDownload;4011}4013// Attempt to initialize address relay for outbound peers and use result4014// to decide whether to send GETADDR, so that we don't send it to4015// inbound, feelers, or outbound block-relay-only peers.4016bool send_getaddr{false};4017if (!pfrom.IsInboundConn()) {4018send_getaddr = SetupAddressRelay(pfrom, peer);4019}4020if (send_getaddr) {4021// Do a one-time address fetch to help populate/update our addrman.4022// If we're starting up for the first time, our addrman may be pretty4023// empty, so this mechanism is important to help us connect to the network.4024// We skip this for block-relay-only peers. We want to avoid4025// potentially leaking addr information and we do not want to4026// indicate to the peer that we will participate in addr relay.4027MakeAndPushMessage(pfrom, NetMsgType::GETADDR);4028peer.m_getaddr_sent = true;4029// When requesting a getaddr, accept an additional MAX_ADDR_TO_SEND addresses in response4030// (bypassing the MAX_ADDR_PROCESSING_TOKEN_BUCKET limit).4031peer.m_addr_token_bucket += MAX_ADDR_TO_SEND;4032}4034if (!pfrom.IsInboundConn()) {4035// For non-inbound connections, we update the addrman to record4036// connection success so that addrman will have an up-to-date4037// notion of which peers are online and available.4038//4039// While we strive to not leak information about block-relay-only4040// connections via the addrman, not moving an address to the tried4041// table is also potentially detrimental because new-table entries4042// are subject to eviction in the event of addrman collisions. We4043// mitigate the information-leak by never calling4044// AddrMan::Connected() on block-relay-only peers; see4045// FinalizeNode().4046//4047// This moves an address from New to Tried table in Addrman,4048// resolves tried-table collisions, etc.4049m_addrman.Good(pfrom.addr);4050}4052peer.m_time_offset = NodeSeconds{std::chrono::seconds{nTime}} - Now<NodeSeconds>();4053if (!pfrom.IsInboundConn()) {4054// Don't use timedata samples from inbound peers to make it4055// harder for others to create false warnings about our clock being out of sync.4056m_outbound_time_offsets.Add(peer.m_time_offset);4057m_outbound_time_offsets.WarnIfOutOfSync();4058}4060// If the peer is old enough to have the old alert system, send it the final alert.4061if (greatest_common_version <= 70012) {4062constexpr auto finalAlert{"60010000000000000000000000ffffff7f00000000ffffff7ffeffff7f01ffffff7f00000000ffffff7f00ffffff7f002f555247454e543a20416c657274206b657920636f6d70726f6d697365642c2075706772616465207265717569726564004630440220653febd6410f470f6bae11cad19c48413becb1ac2c17f908fd0fd53bdc3abd5202206d0e9c96fe88d4a0f01ed9dedae2b6f9e00da94cad0fecaae66ecf689bf71b50"_hex};4063MakeAndPushMessage(pfrom, "alert", finalAlert);4064}4066// Feeler connections exist only to verify if address is online.4067if (pfrom.IsFeelerConn()) {4068LogDebug(BCLog::NET, "feeler connection completed, %s", pfrom.DisconnectMsg());4069pfrom.fDisconnect = true;4070}4071return;4072}4074if (pfrom.nVersion == 0) {4075// Must have a version message before anything else4076LogDebug(BCLog::NET, "non-version message before version handshake. Message \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId());4077return;4078}4080if (msg_type == NetMsgType::VERACK) {4081if (pfrom.fSuccessfullyConnected) {4082LogDebug(BCLog::NET, "ignoring redundant verack message from peer=%d\n", pfrom.GetId());4083return;4084}4086auto new_peer_msg = [&]() {4087const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};4088return strprintf("New %s peer connected: transport: %s, version: %d, %s%s",4089pfrom.ConnectionTypeAsString(),4090TransportTypeAsString(pfrom.m_transport->GetInfo().transport_type),4091pfrom.nVersion.load(), pfrom.LogPeer(),4092(mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));4093};4095// Log successful connections unconditionally for outbound, but not for inbound as those4096// can be triggered by an attacker at high rate.4097if (pfrom.IsInboundConn()) {4098LogDebug(BCLog::NET, "%s", new_peer_msg());4099} else {4100LogInfo("%s", new_peer_msg());4101}4103if (auto tx_relay = peer.GetTxRelay()) {4104// `TxRelay::m_tx_inventory_to_send` must be empty before the4105// version handshake is completed as4106// `TxRelay::m_next_inv_send_time` is first initialised in4107// `SendMessages` after the verack is received. Any transactions4108// received during the version handshake would otherwise4109// immediately be advertised without random delay, potentially4110// leaking the time of arrival to a spy.4111Assume(WITH_LOCK(4112tx_relay->m_tx_inventory_mutex,4113return tx_relay->m_tx_inventory_to_send.empty() &&4114tx_relay->m_next_inv_send_time == 0s));4115}4117if (pfrom.IsPrivateBroadcastConn()) {4118pfrom.fSuccessfullyConnected = true;4119// The peer may intend to later send us NetMsgType::FEEFILTER limiting4120// cheap transactions, but we don't wait for that and thus we may send4121// them a transaction below their threshold. This is ok because this4122// relay logic is designed to work even in cases when the peer drops4123// the transaction (due to it being too cheap, or for other reasons).4124PushPrivateBroadcastTx(pfrom);4125return;4126}4128if (pfrom.GetCommonVersion() >= SHORT_IDS_BLOCKS_VERSION) {4129// Tell our peer we are willing to provide version 2 cmpctblocks.4130// However, we do not request new block announcements using4131// cmpctblock messages.4132// We send this to non-NODE NETWORK peers as well, because4133// they may wish to request compact blocks from us4134MakeAndPushMessage(pfrom, NetMsgType::SENDCMPCT, /*high_bandwidth=*/false, /*version=*/CMPCTBLOCKS_VERSION);4135}4137if (m_txreconciliation) {4138if (!peer.m_wtxid_relay || !m_txreconciliation->IsPeerRegistered(pfrom.GetId())) {4139// We could have optimistically pre-registered/registered the peer. In that case,4140// we should forget about the reconciliation state here if this wasn't followed4141// by WTXIDRELAY (since WTXIDRELAY can't be announced later).4142m_txreconciliation->ForgetPeer(pfrom.GetId());4143}4144}4146{4147LOCK2(::cs_main, m_tx_download_mutex);4148const CNodeState* state = State(pfrom.GetId());4149m_txdownloadman.ConnectedPeer(pfrom.GetId(), node::TxDownloadConnectionInfo {4150.m_preferred = state->fPreferredDownload,4151.m_relay_permissions = pfrom.HasPermission(NetPermissionFlags::Relay),4152.m_wtxid_relay = peer.m_wtxid_relay,4153});4154}4156pfrom.fSuccessfullyConnected = true;4157return;4158}4160if (msg_type == NetMsgType::SENDHEADERS) {4161peer.m_prefers_headers = true;4162return;4163}4165if (msg_type == NetMsgType::SENDCMPCT) {4166uint8_t sendcmpct_hb{0};4167uint64_t sendcmpct_version{0};4168vRecv >> sendcmpct_hb >> sendcmpct_version;4170// BIP152: the first integer is interpreted as a boolean and MUST have a4171// value of either 1 or 0.4172if (sendcmpct_hb > 1) {4173Misbehaving(peer, "invalid sendcmpct announce field");4174return;4175}4177// Only support compact block relay with witnesses4178if (sendcmpct_version != CMPCTBLOCKS_VERSION) return;4180LOCK(cs_main);4181CNodeState* nodestate = State(pfrom.GetId());4182nodestate->m_provides_cmpctblocks = true;4183nodestate->m_requested_hb_cmpctblocks = sendcmpct_hb;4184// save whether peer selects us as BIP152 high-bandwidth peer4185// (receiving sendcmpct(1) signals high-bandwidth, sendcmpct(0) low-bandwidth)4186pfrom.m_bip152_highbandwidth_from = sendcmpct_hb;4187return;4188}4190// BIP339 defines feature negotiation of wtxidrelay, which must happen between4191// VERSION and VERACK to avoid relay problems from switching after a connection is up.4192if (msg_type == NetMsgType::WTXIDRELAY) {4193if (pfrom.fSuccessfullyConnected) {4194// Disconnect peers that send a wtxidrelay message after VERACK.4195LogDebug(BCLog::NET, "wtxidrelay received after verack, %s", pfrom.DisconnectMsg());4196pfrom.fDisconnect = true;4197return;4198}4199if (pfrom.GetCommonVersion() >= WTXID_RELAY_VERSION) {4200if (!peer.m_wtxid_relay) {4201peer.m_wtxid_relay = true;4202m_wtxid_relay_peers++;4203} else {4204LogDebug(BCLog::NET, "ignoring duplicate wtxidrelay from peer=%d\n", pfrom.GetId());4205}4206} else {4207LogDebug(BCLog::NET, "ignoring wtxidrelay due to old common version=%d from peer=%d\n", pfrom.GetCommonVersion(), pfrom.GetId());4208}4209return;4210}4212// BIP155 defines feature negotiation of addrv2 and sendaddrv2, which must happen4213// between VERSION and VERACK.4214if (msg_type == NetMsgType::SENDADDRV2) {4215if (pfrom.fSuccessfullyConnected) {4216// Disconnect peers that send a SENDADDRV2 message after VERACK.4217LogDebug(BCLog::NET, "sendaddrv2 received after verack, %s", pfrom.DisconnectMsg());4218pfrom.fDisconnect = true;4219return;4220}4221peer.m_wants_addrv2 = true;4222return;4223}4225if (msg_type == NetMsgType::FEATURE) {4226if (pfrom.fSuccessfullyConnected) {4227// Disconnect peers that send a FEATURE message after VERACK.4228LogDebug(BCLog::NET, "feature received after verack, %s", pfrom.DisconnectMsg());4229pfrom.fDisconnect = true;4230return;4231} else if (pfrom.GetCommonVersion() < FEATURE_VERSION) {4232// Disconnect peers that send a FEATURE message without valid version negotiation.4233LogDebug(BCLog::NET, "feature received with incompatible version %d, %s", pfrom.GetCommonVersion(), pfrom.DisconnectMsg());4234pfrom.fDisconnect = true;4235return;4236}4238std::string feature_id;4239DataStream feature_data;4240try {4241vRecv >> LIMITED_STRING(feature_id, MAX_FEATUREID_LENGTH);4242std::vector<unsigned char> feature_data_vec;4243vRecv >> LIMITED_VECTOR(feature_data_vec, MAX_FEATUREDATA_LENGTH);4244feature_data = DataStream(feature_data_vec);4245} catch (const std::exception&) {4246feature_id.clear(); // use empty feature_id as error indicator4247}4248if (feature_id.size() < 4 || !vRecv.empty()) {4249LogDebug(BCLog::NET, "invalid feature payload, %s", pfrom.DisconnectMsg());4250pfrom.fDisconnect = true;