The P2P Version Message Payload
The P2P Version Message: Byte Layout and Payload Specifications
The version message is the foundational payload that initiating peers transmit upon opening a TCP connection. It acts as the negotiation contract, detailing the node’s protocol capabilities, system time, network addresses, user-agent details, and block synchronization heights.
This guide details the complete byte serialization layout and field specifications of the standard version message payload.
📐 1. The Serialization Blueprint
The version payload contains 11 distinct fields, varying in size. Below is the precise sequential schema:
| Offset (Bytes) | Field Name | Data Type | Endianness | Description |
|---|---|---|---|---|
0 - 3 |
Version | int32_t |
Little Endian | Identifies the protocol version (e.g., 70016). |
4 - 11 |
Services | uint64_t |
Little Endian | Bitfield of service capabilities (e.g., NODE_NETWORK = 1). |
12 - 19 |
Timestamp | int64_t |
Little Endian | Epoch system timestamp in seconds of the sending node. |
20 - 45 |
Addr Recv | net_addr |
Big Endian | Network address details of the receiving node (peer). |
46 - 71 |
Addr From | net_addr |
Big Endian | Network address details of the sending node (self). |
72 - 79 |
Nonce | uint64_t |
Little Endian | Cryptographic random number to identify self-connections. |
80 - ? |
User Agent | var_str |
Raw (ASCII) | The name of the client software (e.g., /Satoshi:25.0.0/). |
? - ? |
Start Height | int32_t |
Little Endian | Current active tip block height of the sending node. |
? |
Relay | bool |
Raw | Flag (0 or 1) indicating if node should receive unconfirmed txs. |
📡 2. Detailed Field Analysis
A. Network Address Serialization (net_addr)
To support unified IPv4 and IPv6 networks inside a standard schema, net addresses are always serialized as 26-byte structs:
* Services: 8 Bytes (uint64, little-endian) outlining recipient capabilities.
* IP Address: 16 Bytes (big-endian).
* Port: 2 Bytes (uint16, big-endian network byte order).
IPv4-to-IPv6 Mapping Format
IPv4 addresses are padded inside the 16-byte IP field using the standard mapping syntax:
* First 10 bytes: set to \x00
* Next 2 bytes: set to \xFF\xFF
* Last 4 bytes: the actual IPv4 address.
$$\text{IPv4 Mapping: } \underbrace{\texttt{00 00 ... 00}}{10\text{ bytes}} \underbrace{\texttt{FF FF}}{2\text{ bytes}} \underbrace{\text{IP Address}}_{4\text{ bytes}}$$
For example, 127.0.0.1 is serialized as:
$$\texttt{00 00 00 00 00 00 00 00 00 00 FF FF 7F 00 00 01}$$
B. User Agent Variable String (var_str)
The User Agent is stored as a variable-length string. It starts with a CompactSize integer (1–9 bytes) defining the length of the string, followed by the ASCII characters.
For example, the string /Satoshi:25.0.0/ is 16 bytes:
* Length: 0x10 (16)
* Value (Hex): 2f 53 61 74 6f 73 68 69 3a 32 35 2e 30 2e 30 2f
C. Self-Connection Detection via Nonce
When a node broadcasts its IP, it might accidentally initiate a connection to itself. To prevent infinite loops:
* The node generates a cryptographically secure random uint64_t Nonce during startup.
* This Nonce is included in every outgoing version packet.
* If an incoming version packet contains the node’s own active Nonce, it detects the self-connection and closes the socket immediately.
TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation: