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.
751return nCopy;753// deserialize to CMessageHeader754try {755hdrbuf >> hdr;756}757catch (const std::exception&) {758LogDebug(BCLog::NET, "Header error: Unable to deserialize, peer=%d\n", m_node_id);759return -1;760}762// Check start string, network magic763if (hdr.pchMessageStart != m_magic_bytes) {764LogDebug(BCLog::NET, "Header error: Wrong MessageStart %s received, peer=%d\n", HexStr(hdr.pchMessageStart), m_node_id);765return -1;766}768// reject messages larger than MAX_SIZE or MAX_PROTOCOL_MESSAGE_LENGTH769// NOTE: failing to perform this check previously allowed a malicious peer to make us allocate 32MiB of memory per770// connection. See https://bitcoincore.org/en/2024/07/03/disclose_receive_buffer_oom.771if (hdr.nMessageSize > MAX_SIZE || hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {772LogDebug(BCLog::NET, "Header error: Size too large (%s, %u bytes), peer=%d\n", SanitizeString(hdr.GetMessageType()), hdr.nMessageSize, m_node_id);773return -1;774}776// switch state to reading message data777in_data = true;779return nCopy;780}782int V1Transport::readData(std::span<const uint8_t> msg_bytes)783{784AssertLockHeld(m_recv_mutex);785unsigned int nRemaining = hdr.nMessageSize - nDataPos;786unsigned int nCopy = std::min<unsigned int>(nRemaining, msg_bytes.size());788if (vRecv.size() < nDataPos + nCopy) {789// Allocate up to 256 KiB ahead, but never more than the total message size.790vRecv.resize(std::min(hdr.nMessageSize, nDataPos + nCopy + 256 * 1024));791}793hasher.Write(msg_bytes.first(nCopy));794memcpy(&vRecv[nDataPos], msg_bytes.data(), nCopy);795nDataPos += nCopy;797return nCopy;798}800const uint256& V1Transport::GetMessageHash() const801{802AssertLockHeld(m_recv_mutex);803assert(CompleteInternal());804if (data_hash.IsNull())805hasher.Finalize(data_hash);806return data_hash;807}809CNetMessage V1Transport::GetReceivedMessage(NodeClock::time_point time, bool& reject_message)810{811AssertLockNotHeld(m_recv_mutex);812// Initialize out parameter813reject_message = false;814// decompose a single CNetMessage from the TransportDeserializer815LOCK(m_recv_mutex);816CNetMessage msg(std::move(vRecv));818// store message type string, time, and sizes819msg.m_type = hdr.GetMessageType();820msg.m_time = time;821msg.m_message_size = hdr.nMessageSize;822msg.m_raw_message_size = hdr.nMessageSize + CMessageHeader::HEADER_SIZE;824uint256 hash = GetMessageHash();826// We just received a message off the wire, harvest entropy from the time (and the message checksum)827RandAddEvent(ReadLE32(hash.begin()));829// Check checksum and header message type string830if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) {831LogDebug(BCLog::NET, "Header error: Wrong checksum (%s, %u bytes), expected %s was %s, peer=%d\n",832SanitizeString(msg.m_type), msg.m_message_size,833HexStr(std::span{hash}.first(CMessageHeader::CHECKSUM_SIZE)),834HexStr(hdr.pchChecksum),835m_node_id);836reject_message = true;837} else if (!hdr.IsMessageTypeValid()) {838LogDebug(BCLog::NET, "Header error: Invalid message type (%s, %u bytes), peer=%d\n",839SanitizeString(hdr.GetMessageType()), msg.m_message_size, m_node_id);840reject_message = true;841}843// Always reset the network deserializer (prepare for the next message)844Reset();845return msg;846}848bool V1Transport::SetMessageToSend(CSerializedNetMsg& msg) noexcept849{850AssertLockNotHeld(m_send_mutex);851// Determine whether a new message can be set.852LOCK(m_send_mutex);853if (m_sending_header || m_bytes_sent < m_message_to_send.data.size()) return false;855// create dbl-sha256 checksum856uint256 hash = Hash(msg.data);858// create header859CMessageHeader hdr(m_magic_bytes, msg.m_type.c_str(), msg.data.size());860memcpy(hdr.pchChecksum, hash.begin(), CMessageHeader::CHECKSUM_SIZE);862// serialize header863m_header_to_send.clear();864VectorWriter{m_header_to_send, 0, hdr};866// update state867m_message_to_send = std::move(msg);868m_sending_header = true;869m_bytes_sent = 0;870return true;871}873Transport::BytesToSend V1Transport::GetBytesToSend(bool have_next_message) const noexcept874{875AssertLockNotHeld(m_send_mutex);876LOCK(m_send_mutex);877if (m_sending_header) {878return {std::span{m_header_to_send}.subspan(m_bytes_sent),879// We have more to send after the header if the message has payload, or if there880// is a next message after that.881have_next_message || !m_message_to_send.data.empty(),882m_message_to_send.m_type883};884} else {885return {std::span{m_message_to_send.data}.subspan(m_bytes_sent),886// We only have more to send after this message's payload if there is another887// message.888have_next_message,889m_message_to_send.m_type890};891}892}894void V1Transport::MarkBytesSent(size_t bytes_sent) noexcept895{896AssertLockNotHeld(m_send_mutex);897LOCK(m_send_mutex);898m_bytes_sent += bytes_sent;899if (m_sending_header && m_bytes_sent == m_header_to_send.size()) {900// We're done sending a message's header. Switch to sending its data bytes.901m_sending_header = false;902m_bytes_sent = 0;903} else if (!m_sending_header && m_bytes_sent == m_message_to_send.data.size()) {904// We're done sending a message's data. Wipe the data vector to reduce memory consumption.905ClearShrink(m_message_to_send.data);906m_bytes_sent = 0;907}908}910size_t V1Transport::GetSendMemoryUsage() const noexcept911{912AssertLockNotHeld(m_send_mutex);913LOCK(m_send_mutex);914// Don't count sending-side fields besides m_message_to_send, as they're all small and bounded.915return m_message_to_send.GetMemoryUsage();916}918namespace {920/** List of short messages as defined in BIP324, in order.921*922* Only message types that are actually implemented in this codebase need to be listed, as other923* messages get ignored anyway - whether we know how to decode them or not.924*/925const std::array<std::string, BIP324_SHORTIDS_IMPLEMENTED> V2_MESSAGE_IDS = {926"", // 12 bytes follow encoding the message type like in V1927NetMsgType::ADDR,928NetMsgType::BLOCK,929NetMsgType::BLOCKTXN,930NetMsgType::CMPCTBLOCK,931NetMsgType::FEEFILTER,932NetMsgType::FILTERADD,933NetMsgType::FILTERCLEAR,934NetMsgType::FILTERLOAD,935NetMsgType::GETBLOCKS,936NetMsgType::GETBLOCKTXN,937NetMsgType::GETDATA,938NetMsgType::GETHEADERS,939NetMsgType::HEADERS,940NetMsgType::INV,941NetMsgType::MEMPOOL,942NetMsgType::MERKLEBLOCK,943NetMsgType::NOTFOUND,944NetMsgType::PING,945NetMsgType::PONG,946NetMsgType::SENDCMPCT,947NetMsgType::TX,948NetMsgType::GETCFILTERS,949NetMsgType::CFILTER,950NetMsgType::GETCFHEADERS,951NetMsgType::CFHEADERS,952NetMsgType::GETCFCHECKPT,953NetMsgType::CFCHECKPT,954NetMsgType::ADDRV2,955"", "", "", // Unimplemented message types 29-31956"", "", "", "", // Unimplemented message types 32-35957"", // Unimplemented message type 36958NetMsgType::FEATURE,959};961class V2MessageMap962{963std::unordered_map<std::string, uint8_t> m_map;965public:966V2MessageMap() noexcept967{968for (size_t i = 1; i < std::size(V2_MESSAGE_IDS); ++i) {969m_map.emplace(V2_MESSAGE_IDS[i], i);970}971}973std::optional<uint8_t> operator()(const std::string& message_name) const noexcept974{975auto it = m_map.find(message_name);976if (it == m_map.end()) return std::nullopt;977return it->second;978}979};981const V2MessageMap V2_MESSAGE_MAP;983std::vector<uint8_t> GenerateRandomGarbage() noexcept984{985std::vector<uint8_t> ret;986FastRandomContext rng;987ret.resize(rng.randrange(V2Transport::MAX_GARBAGE_LEN + 1));988rng.fillrand(MakeWritableByteSpan(ret));989return ret;990}992} // namespace994void V2Transport::StartSendingHandshake() noexcept995{996AssertLockHeld(m_send_mutex);997Assume(m_send_state == SendState::AWAITING_KEY);998Assume(m_send_buffer.empty());999// Initialize the send buffer with ellswift pubkey + provided garbage.1000m_send_buffer.resize(EllSwiftPubKey::size() + m_send_garbage.size());