> For the complete documentation index, see [llms.txt](https://hub.bsvblockchain.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hub.bsvblockchain.org/bitcoin-protocol-documentation/peer-to-peer-networking/sv-node-wire-protocol.md).

# SV Node Wire Protocol

{% hint style="warning" %}
This page documents a **network transport**, not the protocol. Nothing on this page affects whether a transaction or block is valid — see [Peer-to-Peer Networking](/bitcoin-protocol-documentation/peer-to-peer-networking/p2p.md) for why. The message *payloads* for `tx` and `block` carry the consensus serialization specified in [Transactions](/bitcoin-protocol-documentation/specification/transactions.md) and [Blocks](/bitcoin-protocol-documentation/specification/blocks.md); this page specifies only the envelope that carries them between peers.
{% endhint %}

The reference node exchanges data with its peers over TCP using a message-based protocol descended from the original Bitcoin wire protocol. This page specifies the message framing, the connection handshake, the catalogue of message types, and the BSV-specific extensions that support unbounded block sizes and higher throughput.

**Ground truth.** The message framing, message-type names, protocol version, and size limits below derive from [`src/protocol.h`](https://github.com/bitcoin-sv/bitcoin-sv/blob/879fc8b42168dd0e608dafd51b39c6dabad37d4d/src/protocol.h) and [`src/protocol.cpp`](https://github.com/bitcoin-sv/bitcoin-sv/blob/879fc8b42168dd0e608dafd51b39c6dabad37d4d/src/protocol.cpp), the protocol-version constants from [`src/version.h`](https://github.com/bitcoin-sv/bitcoin-sv/blob/879fc8b42168dd0e608dafd51b39c6dabad37d4d/src/version.h), and the network magic values from [`src/chainparams.cpp`](https://github.com/bitcoin-sv/bitcoin-sv/blob/879fc8b42168dd0e608dafd51b39c6dabad37d4d/src/chainparams.cpp). The BSV-specific message extensions are also specified in the [`bitcoin-sv-specs/protocol`](https://github.com/bitcoin-sv-specs/protocol/tree/master/p2p) documents referenced inline. All citations are pinned to release **v1.2.2** (commit `879fc8b`).

## Conventions

* **Little-endian** unless stated otherwise: integer header and payload fields are serialized least-significant byte first. The one exception is the network port inside an address, which is big-endian (network byte order).
* **`char[n]`** fields are fixed-width and NULL-padded.
* **`var_int`** (CompactSize) is the variable-length integer used for counts and lengths, identical to the encoding used throughout the consensus serialization — see [CompactSize](/bitcoin-protocol-documentation/specification/transactions.md#compactsize-varint).
* **`var_str`** is a `var_int` length followed by that many bytes of UTF-8 text.
* **`var_bytes`** is a `var_int` length followed by that many raw bytes.

## Message structure

Every message is a fixed-size header followed by a payload. There are two header forms: the **basic** 24-byte header used by all ordinary messages, and the **extended** header used to carry payloads larger than 4 GiB (see [Extended messages](#extended-large-messages)).

### Basic header

| Field size | Name       | Data type   | Description                                                                        |
| ---------- | ---------- | ----------- | ---------------------------------------------------------------------------------- |
| 4          | `magic`    | `char[4]`   | Network magic value identifying the network (see [Network magic](#network-magic)). |
| 12         | `command`  | `char[12]`  | Message type identifier, ASCII, NULL-padded (e.g. `version`, `tx`, `block`).       |
| 4          | `length`   | `uint32_t`  | Byte length of `payload`.                                                          |
| 4          | `checksum` | `char[4]`   | First 4 bytes of the double-SHA-256 of `payload`.                                  |
| `length`   | `payload`  | `uint8_t[]` | The message body.                                                                  |

The header is 24 bytes (`MESSAGE_START_SIZE` 4 + `COMMAND_SIZE` 12 + `length` 4 + `CHECKSUM_SIZE` 4). Because `length` is a `uint32_t`, a basic message payload is limited to `0xFFFFFFFF` (4 GiB − 1) bytes; larger payloads use the [extended header](#extended-large-messages).

### Network magic

The 4-byte magic prefix identifies which network a message belongs to and frames the start of each message on the stream.

| Network                    | Magic (bytes, in order) |
| -------------------------- | ----------------------- |
| Mainnet                    | `e3 e1 f3 e8`           |
| Testnet                    | `f4 e5 f3 f4`           |
| STN (scaling test network) | `fb ce c4 f9`           |
| Regtest                    | `da b5 bf fa`           |

## Protocol version

The current P2P protocol version is **70016** (`PROTOCOL_VERSION`). Each peer advertises its version in the [`version`](#the-handshake) message during the handshake, and behaviour is gated on the negotiated minimum of the two peers' versions. Notable version thresholds:

| Version | Meaning                                                                                                                                                                         |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 70016   | `EXTENDED_PAYLOAD_VERSION` — peer understands [extended (large) messages](#extended-large-messages). A node must not send extended-format messages to peers below this version. |
| 70015   | `INVALID_CB_NO_BAN_VERSION`                                                                                                                                                     |
| 70014   | `SHORT_IDS_BLOCKS_VERSION` — compact blocks.                                                                                                                                    |
| 70013   | `FEEFILTER_VERSION` — `feefilter` message.                                                                                                                                      |
| 70012   | `SENDHEADERS_VERSION` — `sendheaders` message.                                                                                                                                  |
| 70011   | `NO_BLOOM_VERSION` — bloom filtering no longer advertised by default.                                                                                                           |
| 31800   | `GETHEADERS_VERSION` = `MIN_PEER_PROTO_VERSION`; peers below this are not accepted.                                                                                             |

## The handshake

A connection begins with a version handshake before any other message is exchanged:

1. Each side sends a `version` message describing itself.
2. Each side replies with `verack` to acknowledge the peer's `version`.
3. Only after both `verack`s may other message types be sent. Optionally, [`protoconf`](#protoconf) is sent immediately after `verack` to advertise relaxed limits.

### `version` message

| Field size | Name             | Data type   | Description                                                                                                                      |
| ---------- | ---------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------- |
| 4          | `version`        | `int32_t`   | Protocol version of the sending node.                                                                                            |
| 8          | `services`       | `uint64_t`  | Bitfield of services offered (see [Service flags](#service-flags)).                                                              |
| 8          | `timestamp`      | `int64_t`   | Current UNIX time in seconds.                                                                                                    |
| 26         | `addr_recv`      | `net_addr`  | Address of the receiving node (as seen by the sender).                                                                           |
| 26         | `addr_from`      | `net_addr`  | Address of the sending node.                                                                                                     |
| 8          | `nonce`          | `uint64_t`  | Random nonce; used to detect connections to self.                                                                                |
| 1+         | `user_agent`     | `var_str`   | Human-readable client identifier.                                                                                                |
| 4          | `start_height`   | `int32_t`   | Height of the sender's best block.                                                                                               |
| 1          | `relay`          | `bool`      | Whether the peer should relay transactions (BIP 37).                                                                             |
| 1+         | `association_id` | `var_bytes` | Association identifier for [multi-streams](#multi-streams). Optional; absence signals a peer that does not support associations. |

The `association_id` field is a BSV addition appended after `relay`; see [Multi-streams](#multi-streams). The `version` message uses the **26-byte** `net_addr` form (services + IP + port, with **no** timestamp).

### `net_addr`

Network addresses appear in `version` and `addr` messages.

| Field size | Name       | Data type  | Description                                                                             |
| ---------- | ---------- | ---------- | --------------------------------------------------------------------------------------- |
| 4          | `time`     | `uint32_t` | UNIX timestamp the address was last seen. **Present in `addr` only**, not in `version`. |
| 8          | `services` | `uint64_t` | Service bits advertised by that address.                                                |
| 16         | `ip`       | `char[16]` | IPv6 address, or an IPv4 address mapped into IPv6 (`::ffff:a.b.c.d`).                   |
| 2          | `port`     | `uint16_t` | TCP port, **big-endian** (network byte order).                                          |

### Service flags

| Bit      | Name                | Meaning                                                                                           |
| -------- | ------------------- | ------------------------------------------------------------------------------------------------- |
| `1 << 0` | `NODE_NETWORK`      | Node serves the full blockchain. Set by all reference nodes; unset by SPV/light clients.          |
| `1 << 1` | `NODE_GETUTXO`      | BIP 64 `getutxo`. Not supported by the reference node.                                            |
| `1 << 2` | `NODE_BLOOM`        | Willing to serve bloom-filtered connections. No longer advertised by default as of version 70011. |
| `1 << 4` | `NODE_XTHIN`        | Xtreme Thinblocks support.                                                                        |
| `1 << 5` | `NODE_BITCOIN_CASH` | Legacy UAHF-era separation bit.                                                                   |

Service bits are unauthenticated advertisements; implementations must be robust against peers that advertise services they do not actually provide.

## Message types

The reference node recognises the following message types (`allNetMessageTypes` in `protocol.cpp`). Message types not on this list are ignored, which is what allows optional messages like `protoconf` to be introduced without a protocol-version bump.

### Connection and control

| Command         | Description                                                               |
| --------------- | ------------------------------------------------------------------------- |
| `version`       | Opening handshake; advertises version, services, and address.             |
| `verack`        | Acknowledges a received `version`.                                        |
| `ping` / `pong` | Liveness check; `pong` echoes the `ping` nonce (BIP 31, version ≥ 60000). |
| `reject`        | Reports rejection of a previous message.                                  |
| `protoconf`     | Advertises relaxed protocol limits (see [protoconf](#protoconf)).         |
| `createstrm`    | Opens an additional [stream](#multi-streams) within an association.       |
| `streamack`     | Acknowledges a `createstrm`.                                              |

### Peer discovery

| Command   | Description                                                |
| --------- | ---------------------------------------------------------- |
| `getaddr` | Requests known peer addresses.                             |
| `addr`    | Advertises peer addresses (each a `net_addr` with `time`). |

### Inventory and data transfer

| Command     | Description                                                                              |
| ----------- | ---------------------------------------------------------------------------------------- |
| `inv`       | Announces available objects by type and hash.                                            |
| `getdata`   | Requests objects previously announced in an `inv`.                                       |
| `notfound`  | Reports that requested objects are unavailable.                                          |
| `tx`        | A transaction.                                                                           |
| `block`     | A full block.                                                                            |
| `mempool`   | Requests the peer's mempool contents (see [mempool message](#extended-mempool-message)). |
| `feefilter` | Requests that the peer not relay transactions below a fee rate (version ≥ 70013).        |

An `inv`/`getdata`/`notfound` entry pairs a 4-byte type with a 32-byte hash. The object types are:

| Value | Name                 | Object                                |
| ----- | -------------------- | ------------------------------------- |
| 1     | `MSG_TX`             | Transaction.                          |
| 2     | `MSG_BLOCK`          | Block.                                |
| 3     | `MSG_FILTERED_BLOCK` | Bloom-filtered block (`merkleblock`). |
| 4     | `MSG_CMPCT_BLOCK`    | Compact block.                        |
| 5     | `MSG_DATAREF_TX`     | Dataref transaction.                  |

### Headers and block synchronisation

| Command       | Description                                                                              |
| ------------- | ---------------------------------------------------------------------------------------- |
| `getblocks`   | Requests an `inv` of block hashes from a locator.                                        |
| `getheaders`  | Requests block headers from a locator.                                                   |
| `headers`     | Delivers block headers.                                                                  |
| `sendheaders` | Requests that new blocks be announced via `headers` rather than `inv` (version ≥ 70012). |
| `gethdrsen`   | Requests enriched headers.                                                               |
| `hdrsen`      | Delivers enriched headers.                                                               |
| `sendhdrsen`  | Requests enriched-header announcements.                                                  |

### Compact blocks

| Command       | Description                                                  |
| ------------- | ------------------------------------------------------------ |
| `sendcmpct`   | Negotiates compact-block relay (version ≥ 70014).            |
| `cmpctblock`  | A compact block (short transaction IDs).                     |
| `getblocktxn` | Requests the full transactions missing from a compact block. |
| `blocktxn`    | Delivers the requested transactions.                         |

### Bloom filtering (BIP 37)

| Command       | Description                                                                            |
| ------------- | -------------------------------------------------------------------------------------- |
| `filterload`  | Installs a bloom filter on the connection.                                             |
| `filteradd`   | Adds an element to the current filter.                                                 |
| `filterclear` | Removes the current filter.                                                            |
| `merkleblock` | A block reduced to the transactions matching the filter, plus a partial Merkle branch. |

### Large-message framing

| Command  | Description                                                                          |
| -------- | ------------------------------------------------------------------------------------ |
| `extmsg` | Envelope indicating an [extended (large) payload](#extended-large-messages) follows. |

{% hint style="info" %}
The reference node also defines message types for features **outside the wire protocol proper** — Miner ID (`revokemid`), node authentication (`authch`, `authresp`), dataref transactions (`datareftx`), and double-spend detection (`dsdetected`). These are not part of the core wire protocol and are not documented here.
{% endhint %}

## BSV extensions

The following extensions distinguish the BSV wire protocol from the original Bitcoin protocol. All are designed for backward compatibility: a peer that does not understand an extension either negotiates it away during the handshake or simply ignores the unknown message.

### Extended (large) messages

The basic header's `length` field is a `uint32_t`, capping a basic payload at 4 GiB. To carry blocks (and potentially other objects) larger than that, an **extended header** is used. It is signalled by the special command `extmsg`, after which the real command and a 64-bit length follow before the payload.

| Field size   | Name          | Data type   | Description                                                                                                    |
| ------------ | ------------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
| 4            | `magic`       | `char[4]`   | Network magic.                                                                                                 |
| 12           | `command`     | `char[12]`  | Set to `extmsg`.                                                                                               |
| 4            | `length`      | `uint32_t`  | Set to `0xFFFFFFFF` to mark an extended message. The real length is in `ext_length`.                           |
| 4            | `checksum`    | `char[4]`   | Set to `0x00000000` and **not checked**; computing a checksum over multi-gigabyte payloads has little utility. |
| 12           | `ext_command` | `char[12]`  | The real message type (e.g. `block`).                                                                          |
| 8            | `ext_length`  | `uint64_t`  | The real payload length.                                                                                       |
| `ext_length` | `payload`     | `uint8_t[]` | The message body.                                                                                              |

Extended messages require protocol version **70016** (`EXTENDED_PAYLOAD_VERSION`). A node must not send an extended-format message to a peer advertising a lower version, or it risks being banned. See the [large-message specification](https://github.com/bitcoin-sv-specs/protocol/blob/master/p2p/large_messages.md).

### `protoconf`

By default a peer will accept messages up to `DEFAULT_MAX_PROTOCOL_RECV_PAYLOAD_LENGTH` (2 MiB), falling back to `LEGACY_MAX_PROTOCOL_PAYLOAD_LENGTH` (1 MiB) for peers that predate this message. The optional `protoconf` message lets a peer advertise **relaxed** limits so larger non-block messages can be exchanged.

| Field size | Name                   | Data type  | Description                                                                                                                                |
| ---------- | ---------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| variable   | `numberOfFields`       | `var_int`  | Number of fields that follow; also serves as the message version. Must be ≥ 1 (version 0 is invalid); this specification is version 2.     |
| 4          | `maxRecvPayloadLength` | `uint32_t` | Maximum non-block message payload the sender is willing to receive. Minimum (and default) 1 MiB; advertising less is a protocol violation. |
| variable   | `streamPolicies`       | `var_str`  | Comma-separated list of supported [stream policies](#multi-streams).                                                                       |

Rules of use:

* `protoconf` may only be sent **after** `verack`, at most **once** per connection, and should be sent immediately after `verack`.
* It can only **relax** limits, never tighten them below the defaults — this preserves compatibility with peers that ignore the message.
* The `protoconf` payload itself is capped at 1 MiB.
* Advertising `maxRecvPayloadLength` also lifts the legacy `MAX_INV_SZ` (50 000) cap on `inv`/`getdata` element counts; those are then bounded only by the advertised payload length.

See the [protoconf specification](https://github.com/bitcoin-sv-specs/protocol/blob/master/p2p/protoconf.md).

### Multi-streams

A single TCP connection to a peer suffers head-of-line blocking: a newly-arrived block can be stuck behind a large batch of transactions already being transmitted. Multi-streams lets peers open several TCP connections (**streams**) grouped into one logical **association**, and dedicate streams to particular traffic categories (for example, a high-priority stream for blocks).

An association is identified by the `association_id` a peer includes in its `version` message. If the responding node echoes the same `association_id`, both peers support associations and further streams can be opened.

**`createstrm`** — sent as the first message on a new connection (in place of `version`) to attach it as a stream to an existing association:

| Field size | Name             | Data type   | Description                                  |
| ---------- | ---------------- | ----------- | -------------------------------------------- |
| 1+         | `association_id` | `var_bytes` | The association this stream joins.           |
| 1          | `stream_type`    | `byte`      | Stream category (1–4).                       |
| 0+         | `stream_policy`  | `var_str`   | (Optional) name of the stream policy to use. |

**`streamack`** — the response confirming the stream, echoing the association ID and stream type:

| Field size | Name             | Data type   | Description                         |
| ---------- | ---------------- | ----------- | ----------------------------------- |
| 1+         | `association_id` | `var_bytes` | The association being acknowledged. |
| 1          | `stream_type`    | `byte`      | The stream type being acknowledged. |

A failed `createstrm` yields a `reject` and the connection is closed.

Two stream policies are implemented: **`Default`** (no additional streams; behaves like a single traditional connection) and **`BlockPriority`** (one extra stream carrying block and control messages, so they are prioritised over bulk transaction traffic). Supported policy names are exchanged via the `streamPolicies` field of [`protoconf`](#protoconf). See the [multi-streams specification](https://github.com/bitcoin-sv-specs/protocol/blob/master/p2p/multistreams.md).

### Extended `mempool` message

The `mempool` message may carry an optional **age** field. A node responding to a `mempool` request restricts the transactions it reports to those that have been in its mempool for at least the given number of seconds.

| Field size | Name  | Data type  | Description                                                                     |
| ---------- | ----- | ---------- | ------------------------------------------------------------------------------- |
| 0+         | `age` | `uint64_t` | Minimum mempool age (seconds) for a transaction to be included in the response. |

Old nodes continue to use the field-less form unchanged. See the [mempool message specification](https://github.com/bitcoin-sv-specs/protocol/blob/master/p2p/mempool.md).

## Message-size limits

The reference node applies per-message size limits as a transport-layer defence. These are **policy limits on the network layer**, not consensus rules; exceeding them causes a peer to be disconnected or banned but says nothing about the validity of any transaction or block.

| Limit                                      | Value                             | Applies to                                                                                                                    |
| ------------------------------------------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `LEGACY_MAX_PROTOCOL_PAYLOAD_LENGTH`       | 1 MiB                             | Peers that do not support `protoconf`; also the `protoconf` payload cap.                                                      |
| `DEFAULT_MAX_PROTOCOL_RECV_PAYLOAD_LENGTH` | 2 MiB                             | Default cap for non-block messages, overridable upward via `protoconf`.                                                       |
| `MAX_PROTOCOL_RECV_PAYLOAD_LENGTH`         | 1 GiB                             | Ceiling for the configurable receive limit.                                                                                   |
| Block-like messages                        | Max block size                    | `block`, `cmpctblock`, `blocktxn`, `hdrsen` are bounded by the configured maximum block size, not the protocol payload limit. |
| `tx`                                       | Max post-Genesis transaction size | A `tx` (and `datareftx`) is bounded by the consensus maximum transaction size.                                                |

Because block-like and transaction messages are exempt from the general payload limit, block and transaction propagation scales with the configured block size rather than a fixed network cap.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://hub.bsvblockchain.org/bitcoin-protocol-documentation/peer-to-peer-networking/sv-node-wire-protocol.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
