SV Node Wire Protocol
Message framing and message types of the SV Node P2P wire protocol (non-consensus)
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 for why. The message payloads for tx and block carry the consensus serialization specified in Transactions and Blocks; this page specifies only the envelope that carries them between peers.
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 and src/protocol.cpp, the protocol-version constants from src/version.h, and the network magic values from src/chainparams.cpp. The BSV-specific message extensions are also specified in the bitcoin-sv-specs/protocol 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.var_stris avar_intlength followed by that many bytes of UTF-8 text.var_bytesis avar_intlength 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).
Basic header
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.
Network magic
The 4-byte magic prefix identifies which network a message belongs to and frames the start of each message on the stream.
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 message during the handshake, and behaviour is gated on the negotiated minimum of the two peers' versions. Notable version thresholds:
70016
EXTENDED_PAYLOAD_VERSION — peer understands 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:
Each side sends a
versionmessage describing itself.Each side replies with
verackto acknowledge the peer'sversion.Only after both
veracks may other message types be sent. Optionally,protoconfis sent immediately afterverackto advertise relaxed limits.
version message
4
version
int32_t
Protocol version of the sending node.
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. Optional; absence signals a peer that does not support associations.
The association_id field is a BSV addition appended after relay; see 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.
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
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
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).
createstrm
Opens an additional stream within an association.
streamack
Acknowledges a createstrm.
Peer discovery
getaddr
Requests known peer addresses.
addr
Advertises peer addresses (each a net_addr with time).
Inventory and data transfer
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).
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:
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
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
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)
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
extmsg
Envelope indicating an extended (large) payload follows.
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.
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.
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.
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.
Rules of use:
protoconfmay only be sent afterverack, at most once per connection, and should be sent immediately afterverack.It can only relax limits, never tighten them below the defaults — this preserves compatibility with peers that ignore the message.
The
protoconfpayload itself is capped at 1 MiB.Advertising
maxRecvPayloadLengthalso lifts the legacyMAX_INV_SZ(50 000) cap oninv/getdataelement counts; those are then bounded only by the advertised payload length.
See the protoconf specification.
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:
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:
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. See the multi-streams specification.
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.
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.
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.
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.
Last updated
