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.
251template <typename Stream>252void Unserialize(Stream& s)253{254if (s.template GetParams<SerParams>().enc == Encoding::V2) {255UnserializeV2Stream(s);256} else {257UnserializeV1Stream(s);258}259}261/**262* BIP155 network ids recognized by this software.263*/264enum BIP155Network : uint8_t {265IPV4 = 1,266IPV6 = 2,267TORV2 = 3,268TORV3 = 4,269I2P = 5,270CJDNS = 6,271};273friend class CSubNet;275private:276/**277* Parse a Tor address and set this object to it.278* @param[in] addr Address to parse, must be a valid C string, for example279* pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.280* @returns Whether the operation was successful.281* @see CNetAddr::IsTor()282*/283bool SetTor(std::string_view addr);285/**286* Parse an I2P address and set this object to it.287* @param[in] addr Address to parse, must be a valid C string, for example288* ukeu3k5oycgaauneqgtnvselmt4yemvoilkln7jpvamvfx7dnkdq.b32.i2p.289* @returns Whether the operation was successful.290* @see CNetAddr::IsI2P()291*/292bool SetI2P(std::string_view addr);294/**295* Size of CNetAddr when serialized as ADDRv1 (pre-BIP155) (in bytes).296*/297static constexpr size_t V1_SERIALIZATION_SIZE = ADDR_IPV6_SIZE;299/**300* Maximum size of an address as defined in BIP155 (in bytes).301* This is only the size of the address, not the entire CNetAddr object302* when serialized.303*/304static constexpr size_t MAX_ADDRV2_SIZE = 512;306/**307* Get the BIP155 network id of this address.308* Must not be called for IsInternal() objects.309* @returns BIP155 network id, except TORV2 which is no longer supported.310*/311BIP155Network GetBIP155Network() const;313/**314* Set `m_net` from the provided BIP155 network id and size after validation.315* @retval true the network was recognized, is valid and `m_net` was set316* @retval false not recognised (from future?) and should be silently ignored317* @throws std::ios_base::failure if the network is one of the BIP155 founding318* networks (id 1..6) with wrong address size.319*/320bool SetNetFromBIP155Network(uint8_t possible_bip155_net, size_t address_size);322/**323* Serialize in pre-ADDRv2/BIP155 format to an array.324*/325void SerializeV1Array(uint8_t (&arr)[V1_SERIALIZATION_SIZE]) const326{327size_t prefix_size;329switch (m_net) {330case NET_IPV6:331assert(m_addr.size() == sizeof(arr));332memcpy(arr, m_addr.data(), m_addr.size());333return;334case NET_IPV4:335prefix_size = sizeof(IPV4_IN_IPV6_PREFIX);336assert(prefix_size + m_addr.size() == sizeof(arr));337memcpy(arr, IPV4_IN_IPV6_PREFIX.data(), prefix_size);338memcpy(arr + prefix_size, m_addr.data(), m_addr.size());339return;340case NET_INTERNAL:341prefix_size = sizeof(INTERNAL_IN_IPV6_PREFIX);342assert(prefix_size + m_addr.size() == sizeof(arr));343memcpy(arr, INTERNAL_IN_IPV6_PREFIX.data(), prefix_size);344memcpy(arr + prefix_size, m_addr.data(), m_addr.size());345return;346case NET_ONION:347case NET_I2P:348case NET_CJDNS:349break;350case NET_UNROUTABLE:351case NET_MAX:352assert(false);353} // no default case, so the compiler can warn about missing cases355// Serialize ONION, I2P and CJDNS as all-zeros.356memset(arr, 0x0, V1_SERIALIZATION_SIZE);357}359/**360* Serialize in pre-ADDRv2/BIP155 format to a stream.361*/362template <typename Stream>363void SerializeV1Stream(Stream& s) const364{365uint8_t serialized[V1_SERIALIZATION_SIZE];367SerializeV1Array(serialized);369s << serialized;370}372/**373* Serialize as ADDRv2 / BIP155.374*/375template <typename Stream>376void SerializeV2Stream(Stream& s) const377{378if (IsInternal()) {379// Serialize NET_INTERNAL as embedded in IPv6. We need to380// serialize such addresses from addrman.381s << static_cast<uint8_t>(BIP155Network::IPV6);382s << COMPACTSIZE(ADDR_IPV6_SIZE);383SerializeV1Stream(s);384return;385}387s << static_cast<uint8_t>(GetBIP155Network());388s << m_addr;389}391/**392* Unserialize from a pre-ADDRv2/BIP155 format from an array.393*394* This function is only called from UnserializeV1Stream() and is a wrapper395* for SetLegacyIPv6(); however, we keep it for symmetry with396* SerializeV1Array() to have pairs of ser/unser functions and to make clear397* that if one is altered, a corresponding reverse modification should be398* applied to the other.399*/400void UnserializeV1Array(uint8_t (&arr)[V1_SERIALIZATION_SIZE])401{402// Use SetLegacyIPv6() so that m_net is set correctly. For example403// ::FFFF:0102:0304 should be set as m_net=NET_IPV4 (1.2.3.4).404SetLegacyIPv6(arr);405}407/**408* Unserialize from a pre-ADDRv2/BIP155 format from a stream.409*/410template <typename Stream>411void UnserializeV1Stream(Stream& s)412{413uint8_t serialized[V1_SERIALIZATION_SIZE];415s >> serialized;417UnserializeV1Array(serialized);418}420/**421* Unserialize from a ADDRv2 / BIP155 format.422*/423template <typename Stream>424void UnserializeV2Stream(Stream& s)425{426uint8_t bip155_net;427s >> bip155_net;429size_t address_size;430s >> COMPACTSIZE(address_size);432if (address_size > MAX_ADDRV2_SIZE) {433throw std::ios_base::failure(strprintf(434"Address too long: %u > %u", address_size, MAX_ADDRV2_SIZE));435}437m_scope_id = 0;439if (SetNetFromBIP155Network(bip155_net, address_size)) {440m_addr.resize(address_size);441s >> std::span{m_addr};443if (m_net != NET_IPV6) {444return;445}447// Do some special checks on IPv6 addresses.449// Recognize NET_INTERNAL embedded in IPv6, such addresses are not450// gossiped but could be coming from addrman, when unserializing from451// disk.452if (util::HasPrefix(m_addr, INTERNAL_IN_IPV6_PREFIX)) {453m_net = NET_INTERNAL;454memmove(m_addr.data(), m_addr.data() + INTERNAL_IN_IPV6_PREFIX.size(),455ADDR_INTERNAL_SIZE);456m_addr.resize(ADDR_INTERNAL_SIZE);457return;458}460if (!util::HasPrefix(m_addr, IPV4_IN_IPV6_PREFIX) &&461!util::HasPrefix(m_addr, TORV2_IN_IPV6_PREFIX)) {462return;463}465// IPv4 and TORv2 are not supposed to be embedded in IPv6 (like in V1466// encoding). Unserialize as !IsValid(), thus ignoring them.467} else {468// If we receive an unknown BIP155 network id (from the future?) then469// ignore the address - unserialize as !IsValid().470s.ignore(address_size);471}473// Mimic a default-constructed CNetAddr object which is !IsValid() and thus474// will not be gossiped, but continue reading next addresses from the stream.475m_net = NET_IPV6;476m_addr.assign(ADDR_IPV6_SIZE, 0x0);477}478};480class CSubNet481{482protected:483/// Network (base) address484CNetAddr network;485/// Netmask, in network byte order486uint8_t netmask[16];487/// Is this value valid? (only used to signal parse errors)488bool valid;490public:491/**492* Construct an invalid subnet (empty, `Match()` always returns false).493*/494CSubNet();496/**497* Construct from a given network start and number of bits (CIDR mask).498* @param[in] addr Network start. Must be IPv4 or IPv6, otherwise an invalid subnet is499* created.500* @param[in] mask CIDR mask, must be in [0, 32] for IPv4 addresses and in [0, 128] for
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.