> For the complete documentation index, see [llms.txt](https://bsv.brc.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bsv.brc.dev/transactions/0142.md).

# Multicast Transaction Bundle Frame Format

Jeff Harris (<jeff@lightweb.net>)

## Abstract

This BRC specifies a coalescing extension to the BRC-124 and BRC-128 Multicast Transaction Frame Formats. A *bundle* packs many small BSV transactions — standard (BRC-12 raw) or Extended Format (BRC-30 EF) — that share one shard group and subtree into a single datagram, so a payload that would otherwise cross a multicast fabric as N small packets crosses it as one. It is the inverse of BRC-130 fragmentation, which splits one oversized transaction across many datagrams. Bundling reduces packets-per-second — the dominant per-packet forwarding cost of multicast fan-out — without changing transaction semantics.

## Copyright

This BRC is licensed under the Open BSV License.

## Motivation

Basic BSV payments are small — a typical pay-to-public-key-hash (P2PKH) transaction is only \~200 bytes — even though Bitcoin script imposes no such limit and many transactions are far larger. A large share of fabric traffic is therefore small-packet, and multicast fan-out cost is dominated by packets-per-second, not bandwidth: each replicated packet carries a per-packet forwarding cost largely independent of its size. A node that already forwards individual BRC-124/128 frames can pack many same-destination transactions into one datagram, cutting the packet rate it imposes on every downstream hop while carrying the same transactions. Bundling is an operator-side optimization: senders need not participate, and a node may bundle, or not, without coordination.

## Specification

### Bundle Header Format (66 bytes)

A bundle is identified by Frame Version `0x08`. Unlike BRC-130, a bundle header is **not** layout-compatible with BRC-124 — a bundle has no single Transaction ID. All multi-byte integers are big-endian.

| Offset | Size | Field          | Description                                                                                   |
| ------ | ---- | -------------- | --------------------------------------------------------------------------------------------- |
| 0      | 4    | Network Magic  | 0xE3E1F3E8 (BSV mainnet P2P magic)                                                            |
| 4      | 2    | Protocol Ver   | 0x02BF (703)                                                                                  |
| 6      | 1    | Frame Version  | 0x08 (BRC-142 bundle)                                                                         |
| 7      | 1    | Flags          | bit0 = `TxIDsPresent` (per-member Transaction ID present, all-or-none); bits 1–7 reserved (0) |
| 8      | 32   | Subtree ID     | The single 32-byte subtree shared by all members; zeros = unset                               |
| 40     | 8    | HashKey        | XXH64(senderIPv6 ∥ groupIdx ∥ subtreeID); the bundle flow identity                            |
| 48     | 8    | SeqNum         | Per-flow monotonic counter, starts at 1; 0 = unset                                            |
| 56     | 2    | GroupIdx       | Shard group index this bundle was built for (uint16 BE)                                       |
| 58     | 1    | ShardBits      | Shard-bit width `GroupIdx` was computed at (1–12); pins the generation                        |
| 59     | 1    | Reserved       | 0x00                                                                                          |
| 60     | 2    | TxCount        | Number of members (uint16 BE)                                                                 |
| 62     | 4    | PayloadLen     | Total byte length of the member section that follows (uint32 BE)                              |
| 66     | \*   | Member section | `TxCount` members (below)                                                                     |

### Member Format

The header is followed by `TxCount` length-prefixed members:

| Offset (relative) | Size  | Field | Description                                                       |
| ----------------- | ----- | ----- | ----------------------------------------------------------------- |
| 0                 | 2     | TxLen | Member transaction byte length (uint16 BE)                        |
| 2                 | 32    | TxID  | Present **only** when `Flags.TxIDsPresent`; raw 256-bit TxID      |
| 2 or 34           | TxLen | Tx    | Serialised BSV transaction — BRC-12 raw or BRC-30 Extended Format |

* `TxLen` is a fixed uint16: a member must fit one datagram, so 16 bits suffices; a transaction that would exceed the path MTU is ineligible and uses BRC-130.
* The per-member Transaction ID is **optional** (the `TxIDsPresent` flag) because it is recomputable from the transaction, so carrying it is redundant wire data — and at 32 bytes per member it is a real density cost on small payments (\~14% fewer members for a \~200-byte P2PKH tx), working against the packing this format exists for. Omit it by default and let receivers recompute `SHA256d(Tx)`. Carry it (set the flag) when a receiver needs the id without recompute — line-rate dedup or accounting — or for Extended Format members, whose canonical id is the hash of the de-extended base transaction (**not** of the EF bytes) and so cannot be cheaply recomputed. It is **not** a retransmission aid.
* A member is a transaction in **BRC-12** (raw) or **BRC-30** (Extended Format) serialization; an EF member self-identifies by its 6-byte marker (payload bytes 4–9), so the two may be mixed in one bundle with no per-member type flag. The bundle carries only the transaction bytes — the **egress format is the downstream consumer's contract, not the bundle's**. On decoalesce the edge re-emits each member in the consumer's format: as a multicast frame — **BRC-124** (raw) or **BRC-128** (Extended Format), both Frame Version 0x02 — or in the transaction's own **BRC-12** / **BRC-30** format.
* Parsers read members until `PayloadLen` bytes are consumed; `TxCount` is a cross-check.

### Group, Subtree, and Flow Identity

Every member of a bundle satisfies `GroupIndex(member TxID) == GroupIdx` at `ShardBits` (BRC-129) and carries the bundle's Subtree ID. A bundle is therefore a single `(sender, group, subtree)` flow with one HashKey and one monotonic SeqNum, exactly as a BRC-124 frame. This lets a bundle reuse the BRC-126 retransmission machinery unchanged: gap detection and NACK operate on the bundle SeqNum stream.

A bundle is transport-agnostic: the on-wire bytes are identical under Any-Source (ASM) and Source-Specific (SSM) multicast. Addressing, scopes, and the SSM `(S,G)` join and source-discovery model are those of the underlying shard group in [BRC-129](/transactions/0129.md); the bundle's source is the coalescing node (`senderIPv6`, the first HashKey ingredient), so a receiver joins the same `(S,G)` it would for the group's BRC-124 frames.

`GroupIdx` and `ShardBits` are carried explicitly, rather than derived from member Transaction IDs, so any node can classify and re-bucket a bundle deterministically during a BRC-139 shard-bit transition — when the active `ShardBits`, and therefore the group a Transaction ID maps to, is changing.

### Coalescing and Decoalescing

A coalescing node buckets input frames by `(group, subtree)` and packs each bucket into bundles, starting a new bundle when the next member would exceed the path MTU or `TxCount = 65535`. A bundle never exceeds the path MTU and never fragments: BRC-142 and BRC-130 are mutually exclusive per datagram. Coalescing is bounded so a partial bundle is not held indefinitely — the bound (a maximum delay or a batch window) is implementation-defined — and is opt-in, at an implementation-defined granularity (per node or per flow; latency-sensitive relay opts out).

Decoalescing splits a bundle back into individual transactions in the downstream consumer's format — each re-emitted as a multicast frame (BRC-124 for a raw transaction or BRC-128 for an Extended Format one, both Frame Version 0x02) or in the transaction's own BRC-12 / BRC-30 format. The default is **edge-decoalesce**: the fabric carries bundles and the edge node splits them before per-consumer delivery, leaving the consumer contract unchanged. Each emitted frame inherits the bundle's Subtree ID, carries its own (carried or recomputed) Transaction ID, and is assigned a per-transaction SeqNum on the egress flow. A consumer MAY instead opt to receive bundles directly.

### Retransmission

The retransmission unit is the whole bundle. A lost bundle is a datagram the receiver never saw, so it can only request the bundle by its SeqNum, not a member within it. A retry endpoint caches and retransmits a bundle keyed on `(HashKey, SeqNum)` exactly as a BRC-124 frame.

### Re-bucketing

A relay forwarding a bundle into a domain or generation running a different `ShardBits` MUST re-bucket it: decoalesce and re-coalesce at the target `ShardBits` (learned from the BRC-139 manifest), routing each member to its correct group, preserving the Subtree ID, and re-stamping the flow HashKey and SeqNum. A relay MUST NOT deliver a bundle to a subscriber whose interest is finer than the bundle's `ShardBits` without re-bucketing, since that subscriber would receive — and, on loss, re-request — transactions outside its interest.

### Error Handling

| Condition                             | Action                                                                              |
| ------------------------------------- | ----------------------------------------------------------------------------------- |
| Frame Version ≠ 0x08                  | Not a bundle; decode per its version                                                |
| Bad magic                             | Silent drop                                                                         |
| Datagram shorter than 66-byte header  | Silent drop                                                                         |
| PayloadLen exceeds datagram remainder | Silent drop (truncated)                                                             |
| Member runs past PayloadLen           | Silent drop (malformed)                                                             |
| Member group ≠ GroupIdx at ShardBits  | Encoder invariant — origin MUST pack only same-group members (not decoder-enforced) |

## Compatibility

* BRC-12 (0x01) and BRC-124/128 (0x02) receivers MUST discard datagrams with Frame Version 0x08; a bundle does not parse as a single-transaction frame.
* BRC-142 receivers implement decoalescing (or re-bucketing, at a relay) and deliver individual transactions downstream — as multicast frames (BRC-124/128, 0x02) or in the transaction's base BRC-12 / BRC-30 format, per the consumer's contract — preserving existing consumer behaviour.
* Network Magic and Protocol Version are at the BRC-124 offsets, so firewall rules and classifiers matching those still recognise the datagram. The Transaction ID, HashKey, and SeqNum offsets differ from BRC-124, so a classifier reading those fields must branch on Frame Version 0x08.

## References

* [BRC-12: Raw Transaction Format](/transactions/0012.md) — raw member payload and base egress format
* [BRC-124: Multicast Transaction Frame Format](/transactions/0124.md) — base frame coalesced by this BRC
* [BRC-30: Transaction Extended Format (EF)](/transactions/0030.md) — EF member payload and base egress format
* [BRC-128: Multicast Extended Transaction Frame Format](/transactions/0128.md) — Extended Format members
* [BRC-126: Multicast Transaction NACK Retransmission Protocol](/transactions/0126.md) — bundle-unit retransmission
* [BRC-129: IPv6 Multicast Group Address Assignments](/transactions/0129.md) — group/subtree addressing
* [BRC-130: Multicast Transaction Frame Fragmentation](/transactions/0130.md) — the inverse; mutually exclusive per datagram
* [BRC-139: Multicast Shard Manifest Announcement Protocol](/transactions/0139.md) — ShardBits/generation coordination

## Constants Reference

| Name             | Value | Hex    | Description                           |
| ---------------- | ----- | ------ | ------------------------------------- |
| FrameVerBundle   | 8     | 0x08   | BRC-142 bundle frame version          |
| BundleHeaderSize | 66    | 0x42   | Bundle header size in bytes           |
| FlagTxIDsPresent | 1     | 0x01   | Flags bit 0: per-member TxIDs present |
| MaxMembers       | 65535 | 0xFFFF | TxCount ceiling (uint16)              |
| MaxMemberTxLen   | 65535 | 0xFFFF | Largest member transaction (uint16)   |


---

# 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://bsv.brc.dev/transactions/0142.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.
