Multicast Subtree Data Frame Format
Knowing a subtree exists is not the same as having the transaction hashes in it. This defines a frame carrying those contents to everyone subscribed, so nobody has to request them.
Summary
- Why
- Reconstructing and verifying a block's Merkle subtree, or assembling a block, required retrieving every individual transaction rather than the subtree's contents as a unit.
- What
- BRC-132 defines a multicast wire frame (version 0x05) that carries the full transaction hash list, and optionally fee and size, for a Merkle subtree.
- How
- A sender fills a 92-byte header (identical layout to BRC-124 but with a SubtreeID and MsgType instead of a TxID) followed by a payload of either bare transaction hashes or hash+fee+size nodes plus a conflict list, sends it to the GroupSubtreeDataAnnounce multicast group, and lets the existing BRC-130 fragmentation and
What this lets you do
- Send full transaction hash lists for a Merkle subtree over multicast
- Send per-transaction fee and size data alongside hashes with FullNodes mode
- Rebuild a subtree's Merkle tree locally without fetching each transaction
- Fragment and reassemble oversized subtree payloads using BRC-130
- Verify received subtree contents against the SubtreeID Merkle root
Written by claude-sonnet-5 from the specification text. Where the two differ, the original is correct.
Reference for an AI
Everything an assistant needs to answer questions about BRC-132 accurately, including what it depends on.
The specification
Abstract
This BRC defines frame version 0x05 for distributing complete Merkle subtree
contents — transaction hashes and optional per-transaction metadata — over the
IPv6 multicast fabric. Subtree data frames are delivered to all subscribers via
the dedicated GroupSubtreeDataAnnounce multicast group (FF0X::B:FFFB),
independently of the per-shard groups used for individual transaction
distribution.
Copyright
This BRC is licensed under the Open BSV License.
Motivation
The multicast fabric distributes individual transactions shard-by-shard (BRC-124) and block-level metadata (BRC-131). BRC-132 fills the remaining gap: delivering the contents of each Merkle subtree so that subscribers can:
- Reconstruct the subtree Merkle tree locally.
- Verify block inclusion without fetching individual transactions.
- Power block-assembly tooling and downstream analytics without per-transaction retrieval.
BRC-132 complements BRC-127, which maps SubtreeIDs to GroupIDs for shard-level filtering. BRC-127 announces where a subtree lives; BRC-132 delivers what it contains.
Specification
Multicast Group
Subtree data frames are sent to the GroupSubtreeDataAnnounce group (index
0xFFFB):
| Index | Scope | Compressed Address | Constant |
|---|---|---|---|
| 0xFFFB | site | FF05::B:FFFB | GroupSubtreeDataAnnounce |
| 0xFFFB | org | FF08::B:FFFB | GroupSubtreeDataAnnounce |
| 0xFFFB | global | FF0E::B:FFFB | GroupSubtreeDataAnnounce |
Scope selection follows the GroupBeacon pattern defined in BRC-129. Operators
select one or more scopes via the -announce-scope flag on listening
components.
Addresses are shown in ASM (FF0x) form; under SSM, substitute the FF3x
prefix per BRC-129 (FF3E::B:FFFB for inter-domain scope, SSM-only
per RFC 8815). The frame format and NACK/fragmentation paths are unchanged.
Under SSM, receivers (S,G)-join using the subtree-data source (the emitting
proxy, senderIPv6); the source set is distributed per BRC-129 (data-plane
sources via the shard manifest).
Frame Header Format (92 bytes)
The BRC-132 header is layout-identical to the BRC-124 header. All infrastructure components that inspect Magic, HashKey, or SeqNum read correct values at the same offsets. The header is read using the same 44+48 two-step protocol as BRC-124 and BRC-131.
| Offset | Size | Align | Field | Value / Notes |
|---|---|---|---|---|
| 0 | 4 | — | Network Magic | 0xE3E1F3E8 (BSV mainnet P2P magic) |
| 4 | 2 | — | Protocol Ver | 0x02BF (703, BSV large-block baseline) |
| 6 | 1 | — | Frame Version | 0x05 — BRC-132 subtree data |
| 7 | 1 | — | MsgType | 0x01 = HashesOnly, 0x02 = FullNodes |
| 8 | 32 | 8B | SubtreeID | SHA-256 Merkle root of the subtree (content ID) |
| 40 | 8 | 8B | HashKey | XXH64(senderIPv6 ∥ 0xFFFB ∥ SubtreeID); proxy-stamped |
| 48 | 8 | 8B | SeqNum | Monotonic counter per (sender, SubtreeID); proxy-stamped |
| 56 | 32 | 8B | LayoutPad32 | All zeros; retained for uniform HeaderSize = 92 |
| 88 | 4 | 8B | PayloadLen | Payload size in bytes (uint32 BE) |
| 92 | * | — | Payload | MsgType-specific subtree data (see §Payload Format) |
Key distinctions from BRC-124:
- Byte 7 carries
MsgTyperather thanReserved = 0x00. - Bytes 8–39 carry
SubtreeID(the Merkle root), not aTxID. LayoutPad32(bytes 56–87) is always zero. SubtreeID already serves as content identifier and flow scope; no secondary field is needed. The field is retained so thatHeaderSize = 92remains uniform across V2/V4/V5.HashKeyis computed asXXH64(senderIPv6 ∥ 0xFFFB ∥ SubtreeID). Each distinct subtree from the same sender has an independent sequence stream, so loss in one subtree does not create false gaps in another.
MsgType Values
| MsgType | Constant | Node Size | Description |
|---|---|---|---|
0x01 | SubtreeMsgHashesOnly | 32 bytes | TxHashes only (network transfer format) |
0x02 | SubtreeMsgFullNodes | 48 bytes | TxHash + Fee + Size per node |
Any other MsgType value causes the frame to be rejected with ErrBadSubtreeMsg.
Payload Format
Both MsgType variants share a 24-byte metadata prefix followed by N node entries and a conflict set.
Common Prefix (24 bytes)
| Offset | Size | Field | Description |
|---|---|---|---|
| 0 | 8 | TotalFees | Aggregate fee sum for the subtree (uint64 BE) |
| 8 | 8 | TotalSizeBytes | Aggregate serialised tx size (uint64 BE, bytes) |
| 16 | 8 | NodeCount | Number of transaction nodes (uint64 BE) |
MsgType 0x01 — HashesOnly
| Offset | Size | Field |
|---|---|---|
| 24 | 32 × N | TxHashes |
| 24 + 32N | 8 | ConflictCount (uint64 BE) |
| 24 + 32N + 8 | 32 × M | ConflictHashes |
Maximum size at 1M nodes, 0 conflicts: 24 + 32 × 1,048,576 + 8 ≈ 32 MB.
MsgType 0x02 — FullNodes
| Offset | Size | Field |
|---|---|---|
| 24 | 48 × N | Nodes: TxHash (32B) ∥ Fee (8B BE) ∥ Size (8B BE) |
| 24 + 48N | 8 | ConflictCount (uint64 BE) |
| 24 + 48N + 8 | 32 × M | ConflictHashes |
Maximum size at 1M nodes, 0 conflicts: 24 + 48 × 1,048,576 + 8 ≈ 48 MB.
Fragmentation
Payloads of 32–48 MB exceed any path MTU. The proxy fragments each BRC-132 frame using BRC-130:
OrigFrameVer = 0x05in each BRC-130 fragment header (byte 100).MsgTypeis preserved in fragment header byte 7 (same pattern as BRC-131fragmentBlock).- Fragment reassembly is keyed by SubtreeID (bytes 8–39), matching the
TxIDslot used by BRC-124 fragments. - SHA256d hash verification does not apply — SubtreeID is a Merkle root, not
a payload double-hash. The
verifyHashflag must befalsefor V5 reassembly slots. - Optional post-reassembly Merkle-root verification is available (see §Merkle Verification).
Fragment counts at MTU 9000 (fragDataSize = 8848 bytes):
| Subtree size | Fragments |
|---|---|
| ~32 MB (HashesOnly, 1M nodes) | ~3,793 |
| ~48 MB (FullNodes, 1M nodes) | ~5,689 |
Both fit within the uint16 FragTotal limit of 65,535.
Sequence Tracking and Retransmission
BRC-132 frames participate in the same NACK-based reliability mechanism as BRC-124 and BRC-131:
- The proxy stamps
HashKeyandSeqNumin-place before forwarding. Each(senderIPv6, SubtreeID)pair owns an independent monotonic sequence stream. - If
SeqNumis already non-zero on arrival, the frame is forwarded verbatim (pre-stamped path). - Listeners detect gaps on the
(HashKey, 0xFFFB, SubtreeID)flow and dispatch BRC-126 NACKs to retry endpoints. - Retry endpoints join
FF0X::B:FFFBand cache BRC-132 frames and BRC-130 fragments (OrigFrameVer = 0x05) byHashKey ∥ SeqNum. On NACK, the frame is retransmitted toFF0X::B:FFFB. The retry endpoint TTL for BRC-132 frames defaults to 120 s (compared to 60 s for transaction frames) to accommodate large reassembly windows.
Merkle Verification
After reassembly, optional Merkle-root recomputation verifies the SubtreeID:
- Enabled by
-subtree-data-verify-merkle/SUBTREE_DATA_VERIFY_MERKLE=trueon the listener. - The listener decodes the payload into nodes and computes SHA256d pairwise up the binary tree, then compares the root to SubtreeID.
- Computationally significant at 1M nodes (~1M double-SHA256 operations); disabled by default.
- On mismatch: drop the reassembly slot; increment
bsl_reassembly_merkle_mismatch_total.
Error Handling
| Condition | Action |
|---|---|
raw[6] != 0x05 | Not BRC-132; handled by other decoders |
| Bad magic | Silent drop |
| Unknown MsgType | Drop; ErrBadSubtreeMsg |
| PayloadLen exceeds buffer | Drop; io.ErrUnexpectedEOF |
| Datagram shorter than 92 bytes | Drop; ErrTooShort |
SeqNum == 0 | Frame not proxy-stamped; listener discards |
| Merkle mismatch (optional) | Drop; bsl_reassembly_merkle_mismatch_total++ |
Constants Reference
| Name | Value | Hex | Description |
|---|---|---|---|
FrameVerV5 | 5 | 0x05 | BRC-132 subtree data frame version |
SubtreeMsgHashesOnly | 1 | 0x01 | MsgType: TxHashes only (32B per node) |
SubtreeMsgFullNodes | 2 | 0x02 | MsgType: TxHash + Fee + Size (48B per node) |
GroupSubtreeDataAnnounce | 65531 | 0xFFFB | Subtree data multicast group index |
HeaderSize | 92 | 0x5C | BRC-132 header size (identical to BRC-124) |
SubtreeDataPayloadHeaderSize | 24 | 0x18 | Fixed metadata prefix size |
SubtreeNodeHashSize | 32 | 0x20 | Node size in HashesOnly payload |
SubtreeNodeFullSize | 48 | 0x30 | Node size in FullNodes payload |
References
- BRC-119: SubTree Unified Merkle Path (STUMP) Format — SubtreeID definition and Merkle subtree structure
- BRC-124: Multicast Transaction Frame Format — Base header layout reused by BRC-132
- BRC-126: BSV Multicast NACK Retransmission Protocol — NACK-based reliability used for subtree frame retransmission
- BRC-127: Multicast Subtree Group Announcement Frame Format — SubtreeID→GroupID metadata; distinct from BRC-132 data delivery
- BRC-129: IPv6 Multicast Group Address Assignments —
Group index allocations;
0xFFFB= GroupSubtreeDataAnnounce - BRC-130: Multicast Frame Fragmentation — Fragmentation for large
subtree payloads;
OrigFrameVer = 0x05 - BRC-131: Block Announcement Protocol —
FrameVerV4pattern followed by BRC-132