Networking
Bitcoin nodes talk over TCP on port 8333 with a fixed message format. Learn the header, the version handshake and how blocks and transactions are relayed.
By Dimitar Zurnov · Updated 4 Nov 2026
Adapted from Learn Me a Bitcoin by Greg Walker.
Bitcoin nodes talk to each other over the internet with a small binary protocol. Each node opens TCP connections to its peers, usually on port 8333, and sends them messages. Every message has the same header. A handshake opens each connection, and short inventory messages announce new blocks and transactions.
This page covers the bytes on the wire. You need it if you want to write your own client, or if you want to understand what a node sends. You do not need it to use Bitcoin.
Which port does Bitcoin use?
Mainnet nodes listen on TCP port 8333 by default. Test networks use other ports, listed on the magic bytes page. Any language with TCP sockets can open a connection. Your node chooses its own peers, and the node page explains how it finds them.
What does a message look like?
Every message has a 24-byte header followed by a payload. The header says which network the message belongs to, what kind of message it is, how long the payload is, and a checksum that catches damage in transit.
| Field | Size | Contents |
|---|---|---|
| Magic bytes | 4 | The network marker, such as f9beb4d9 on mainnet |
| Command | 12 | The message name in ASCII, padded with zero bytes |
| Length | 4 | The payload size in bytes, little-endian |
| Checksum | 4 | The first 4 bytes of SHA-256 applied twice to the payload |
A node will not accept a payload larger than 4,000,000 bytes (Bitcoin Core source). Some messages have no payload at all, which is why the checksum of an empty payload is always the same. The short Python function below builds a header. It reproduces the verack header from this page.
import hashlib, struct
def header(magic: bytes, command: str, payload: bytes) -> bytes:
checksum = hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4]
return magic + command.encode().ljust(12, b"\x00") + struct.pack("<I", len(payload)) + checksum
print(header(bytes.fromhex("f9beb4d9"), "verack", b"").hex())
# f9beb4d976657261636b000000000000000000005df6e0e2
What does the version message contain?
The first message each side sends is version. It tells the other node the protocol version, which services you offer, the time, and a few addresses. The example below has an empty user agent, so its payload is 85 bytes. It leaves out the relay flag at the end, which BIP 37 added. Bitcoin Core always sends that byte, so a real version message with an empty user agent is 86 bytes.
| Field | Size | Format | Example bytes |
|---|---|---|---|
| Protocol version | 4 | little-endian | 7e110100 (70014) |
| Services | 8 | bit field, little-endian | all zero |
| Time | 8 | Unix time, little-endian | c515cf6100000000 |
| Remote services | 8 | bit field, little-endian | all zero |
| Remote IP | 16 | IPv6, big-endian | 00…ffff2e13894a |
| Remote port | 2 | big-endian | 208d (8333) |
| Local services | 8 | bit field, little-endian | all zero |
| Local IP | 16 | IPv6, big-endian | 00…ffff7f000001 |
| Local port | 2 | big-endian | 208d (8333) |
| Nonce | 8 | little-endian | all zero |
| User agent | 1 | compact size, then ASCII | 00 (empty) |
| Last block | 4 | little-endian | all zero |
| Relay flag | 1 | 1 if you want transactions relayed to you | 01 in Core's messages |
The services field is a bit field. Bit 0 means the node serves the full chain. Bit 3 means it understands SegWit witness data. The IP fields use IPv6 form, so an IPv4 address appears after ffff. The ports are big-endian, unlike the other numbers.
How does the handshake work?
Two messages open every connection: version, then verack, which means version acknowledged. Each side sends its own version, and each side replies with verack. The order matters. Until both sides have exchanged version messages, other messages are not accepted. A peer that gets the order wrong drops the connection. Repeated mistakes can get the sender's address banned for a while.
The verack message has no payload, so its header is the same every time. On mainnet it is f9beb4d976657261636b000000000000000000005df6e0e2.
How do nodes share transactions and blocks?
Nodes do not send every new transaction or block unprompted. They announce them with an inv message. It lists hashes and a type for each item. The receiver asks for the items it lacks with getdata, and the sender answers with a tx or block message. This saves bandwidth, because a small announcement tells the peer what exists without sending it all.
Each item in an inv or getdata message is an inventory vector. Its type is a 4-byte little-endian number:
1(01000000) is a transaction hash, the txid.2(02000000) is a block hash.01000040asks for a transaction with its witness data. Use it for SegWit transactions when you need the signatures.02000040asks for a block with its witness data.
The payload starts with a count, written as a compact size. The getdata payload has the same format as inv, so a node can reply with the same bytes to ask for everything an announcement listed.
What are compact blocks?
Sending a whole block to every peer wastes bandwidth, because most of its transactions are already in the peers' mempools. BIP 152 solves this with compact block relay. The sender announces the block header and a list of short transaction IDs. The receiver rebuilds the block from its own mempool and asks only for the transactions it is missing.
What changed in newer Bitcoin Core versions?
Two things differ from the plain examples above. Bitcoin Core 27.0, released on 16 April 2024, turned on the version 2 transport from BIP 324 by default. That transport encrypts the connection. To talk to a current node with the plain messages on this page, start it with -v2transport=0.
The protocol version has moved on too. The example uses 70014, from an older release. Bitcoin Core 26.0 through 31.2 advertise 70016, which added wtxid relay in BIP 339. Bitcoin Core 32.0 and later advertise 70017, which added feature negotiation. The current release, 32.1, uses 70017. The value is PROTOCOL_VERSION in src/node/protocol_version.h, so check it at the release you run.
How do you keep a connection open?
Peers send ping messages to check that you are still there. Since protocol version 60001 (BIP 31), a ping carries a random 8-byte nonce as its payload. Your reply is a pong with the same nonce. A peer that stops getting timely pongs eventually drops the connection.
Can you try it yourself?
Yes. Any language with a TCP socket can send a version message and read the reply. Start with a node on 127.0.0.1, follow the handshake, and check each header against the table near the top of this page. The full list of messages is on the Bitcoin Wiki. Once you can complete a handshake, the other messages follow the same pattern. For the node itself, see node. For the blocks and transactions you receive, see block and transaction.
In this section
- 1Running a full nodeA bitcoin full node checks every block and transaction itself. Learn the node types, what it needs in disk and RAM, and how to run a bitcoin node.
- 2Magic bytesBitcoin magic bytes are the 4-byte marker at the start of every P2P message. Mainnet uses f9beb4d9, and each test network has its own value.
Something look wrong? Tell us