Multicast Transaction Frame Fragmentation
Jeff Harris (jeff@lightweb.net)
Abstract
This BRC specifies a fragmentation extension to the BRC-124 Multicast Transaction Frame Format. When a BSV transaction payload exceeds the path MTU available on a multicast fabric, the proxy decomposes the payload into a sequence of fixed-size fragment datagrams. Listeners reassemble the fragments and verify the reconstructed payload against the transaction ID before forwarding. The fragment header is a strict superset of the BRC-124 header, enabling mixed-version infrastructure to identify and discard fragment frames it cannot process.
Fragmentation is transport-agnostic: fragment datagrams are identical on the wire under ASM and SSM, and every fragment of a transaction is emitted from the same proxy source (senderIPv6), so a receiver joins a single (S,G) for all of them. Multicast addressing and the SSM join and source-discovery model are specified in BRC-129.
Copyright
This BRC is licensed under the Open BSV License.
Motivation
BSV transactions can be arbitrarily large. The 1500-byte Ethernet MTU imposes a hard limit on single-datagram UDP delivery; transactions exceeding ~1300 bytes of payload after IPv6 and UDP overhead cannot be transported in a single BRC-124 frame without IP fragmentation, which is unreliable on multicast paths and disabled by default on many fabrics.
Rather than rely on IP-layer fragmentation (which requires receiver kernel reassembly and breaks on many switch configurations), BRC-130 performs fragmentation at the application layer:
The proxy slices the payload into k equal-sized chunks and emits k independent UDP datagrams.
Each datagram carries a complete BRC-130 header that is layout-compatible with BRC-124, allowing existing firewall rules, packet classifiers, and traffic monitors to inspect the frame header fields.
Listeners reassemble fragments keyed on the Transaction ID, and MAY verify the reassembled payload against that identifier before forwarding.
Specification
Fragment Header Format (104 bytes)
A BRC-130 fragment datagram consists of a 104-byte header followed by the fragment data. All multi-byte integers are big-endian.
0
4
—
Network Magic
0xE3E1F3E8 (BSV mainnet P2P magic)
4
2
—
Protocol Ver
0x02BF (703, BSV large-block baseline)
6
1
—
Frame Version
0x03 (BRC-130 fragment)
7
1
—
MsgType
Carried-through MsgType (byte 7); 0x00 for BRC-124/128
8
32
8B
Transaction ID
SHA256d(reassembled payload); same on every fragment
40
8
8B
HashKey
XXH64(senderIPv6 ∥ groupIdx ∥ subtreeID); per-flow
48
8
8B
SeqNum
Per-flow monotonic counter; independent per fragment
56
32
8B
Subtree ID
32-byte batch identifier; zeros = unset
88
4
8B
PayloadLen
Size of this fragment's data bytes (uint32 BE)
92
4
4B
OrigPayloadLen
Total unfragmented payload length (uint32 BE)
96
2
2B
FragIndex
0-based index of this fragment (uint16 BE)
98
2
2B
FragTotal
Total number of fragments in this transaction (uint16 BE)
100
1
—
OrigFrameVer
Original FrameVer before fragmentation; 0x00 ⇒ 0x02
101
3
—
Reserved
Must be 0x000000
104
*
—
Fragment data
Slice of the original payload (PayloadLen bytes)
Bytes 0–91 are layout-identical to a BRC-124 frame header (FrameVer=0x03 and the byte-7 MsgType excepted). Existing infrastructure that inspects the Transaction ID, HashKey, SeqNum, or Subtree ID fields in a BRC-124 header will read correct values from a BRC-130 datagram at the same offsets.
Field Definitions
Network Magic (bytes 0–3)
0xE3E1F3E8 — identical to BRC-124. Enables BSV firewall rules and monitoring tools to classify fragment datagrams without modification.
Protocol Version (bytes 4–5)
0x02BF — identical to BRC-124. Informational; receivers do not validate it.
Frame Version (byte 6)
0x03 — identifies this datagram as a BRC-130 fragment. Infrastructure that does not implement BRC-130 reassembly must silently discard datagrams with this version byte.
MsgType (byte 7)
The frame-type MsgType carried through from byte 7 of the original (pre-fragmentation) frame, so reassembly can reconstruct it. For fragmented BRC-124/128 transaction frames this byte is 0x00 (their byte 7 is reserved); for fragmented BRC-131 block frames it is 0x01/0x02, for BRC-132 subtree frames 0x01/0x02, and for BRC-149 BEEF object frames 0x00 (their byte 7 is reserved). Together with OrigFrameVer (byte 100) it fully restores the original header bytes 6–7 on reassembly.
Transaction ID (bytes 8–39)
The 32-byte canonical transaction identifier of the complete unfragmented payload. For a standard (BRC-12 or BRC-124) payload this is the double-SHA256 of the payload bytes:
For an Extended Format payload (BRC-128) it is not the hash of the payload bytes. EF carries the marker and per-input source data that the identifier does not cover, so the identifier is computed over the standard serialization of the transaction, exactly as it is everywhere else in Bitcoin. Hashing the EF bytes directly yields a value that will never match.
The same TxID appears on every fragment of a transaction. It serves as the reassembly key, and as an integrity proof a listener MAY check after reassembly. Verification is OPTIONAL rather than required: at line rate it costs a full pass over every reassembled payload, and an implementation that offers it SHOULD make it configurable. A listener that verifies MUST drop the object on mismatch.
HashKey (bytes 40–47)
An 8-byte stable per-flow identifier, computed by the proxy as:
XXH64 is the 64-bit xxHash algorithm (github.com/cespare/xxhash/v2). HashKey is the same for every BRC-124 and BRC-130 frame emitted by the same (sender, multicast-group, subtree-batch) flow. Senders set this field to 0; the proxy stamps it in-place.
Note: For fragment datagrams, the proxy stamps an independent HashKey and SeqNum per fragment (i.e., each fragment is treated as a separate frame for gap-tracking purposes). This allows retransmission of individual lost fragments via the standard BRC-126 NACK mechanism without changes to the retry endpoint.
SeqNum (bytes 48–55)
An 8-byte per-flow monotonic counter, starting at 1. The proxy increments the per-flow counter independently for each fragment datagram. Listeners detect gaps at the fragment granularity, enabling single-fragment retransmission.
Senders set SeqNum to 0; the proxy stamps it before forwarding.
Subtree ID (bytes 56–87)
Identical to BRC-124. A 32-byte batch identifier shared by all transactions belonging to the same subtree (BRC-119 STUMP root). All-zero bytes indicate the field is unset.
PayloadLen (bytes 88–91)
The number of fragment data bytes carried by this datagram — not the total original payload length. Equals min(fragDataSize, origPayloadLen - fragIndex * fragDataSize) for the last fragment, and fragDataSize for all prior fragments.
OrigPayloadLen (bytes 92–95)
The total length of the unfragmented payload in bytes. All fragments of the same transaction carry the same OrigPayloadLen value. Receivers use this to allocate a reassembly buffer of exactly the correct size.
FragIndex (bytes 96–97)
The 0-based index of this fragment within the transaction. Values range from 0 to FragTotal - 1.
FragTotal (bytes 98–99)
The total number of fragments into which the payload was divided. All fragments of the same transaction carry the same FragTotal value. Must be ≥ 1. FragTotal = 1 is valid and means the payload was not split (degenerate case, used only for testing).
OrigFrameVer (byte 100)
The FrameVer of the original frame before fragmentation (0x02 BRC-124/128, 0x04 BRC-131, 0x05 BRC-132, 0x09 BRC-149 BEEF object). A value of 0x00 defaults to 0x02 (BRC-124). Listeners use it — together with the byte-7 MsgType — to reconstruct the correct synthetic frame on reassembly.
Reserved (bytes 101–103)
Must be 0x000000. Reserved for future protocol extensions.
Fragment Data (byte 104 onward)
The slice of the original payload bytes corresponding to this fragment:
The last fragment carries the remaining bytes, which may be shorter than fragDataSize.
Fragment Data Size
The fragment data size (fragDataSize) is derived from the configured path MTU:
For standard Ethernet (pathMTU = 1500): fragDataSize = 1348 bytes.
For jumbo frames (pathMTU = 9000): fragDataSize = 8848 bytes.
Reassembly
A listener reassembles a fragmented transaction as follows:
Slot allocation. On receipt of the first fragment for a reassembly key, allocate a slot containing a
OrigPayloadLen-byte buffer, a received-fragment bitmask ofFragTotalbits, and a TTL timer.The reassembly key is the Transaction ID (bytes 8–39), except where the carried plane derives that hash from payload content that several concurrent frames legitimately share. For
OrigFrameVer = 0x09(BRC-149 BEEF object) the key MUST be the pair (Transaction ID, Subtree ID) — bytes 8–39 carry the ContentID and bytes 56–87 the TopicID, and one object submitted to several topics is emitted once per topic with a shared ContentID and a distinct TopicID. Keying such fragments on bytes 8–39 alone merges the sibling emissions into a single slot, so all but one topic silently lose the object.Fragment placement. Copy fragment data into the buffer at
offset = fragIndex * fragDataSize. Mark the fragment index as received.Completion check. When all
FragTotalfragment indices are marked received, proceed to verification.Hash verification. Where bytes 8–39 are a double-SHA256 of the payload —
OrigFrameVer0x00/0x02(transaction, TxID) and0x09(BRC-149 BEEF object, ContentID) — computeSHA256(SHA256(buffer))and compare. If they differ, drop the slot and incrementbsl_reassembly_hash_mismatch_total.This check does not apply to planes whose bytes 8–39 carry a different commitment:
0x04(BRC-131 block control) and0x05(BRC-132 subtree data, whose Subtree ID is a Merkle root rather than a hash of the fragmented bytes). Those planes complete on the fragment bitmask alone; a subtree implementation MAY additionally verify the reassembled data against the Merkle root it commits to.Delivery. Construct a synthetic frame of the original type —
FrameVer = OrigFrameVer(byte 100,0x00⇒0x02) with byte 7 restored from the carriedMsgType— carrying the reassembled payload and the Transaction ID, HashKey, SeqNum, and Subtree ID from the first fragment received. A BEEF object (0x09) is therefore rebuilt as a BRC-149 frame with its ContentID and TopicID in place, not as a BRC-124 transaction frame; reconstructing every plane as0x02would strip the routing identity the downstream filter needs. Route the frame through the normal filter → egress → gap-tracking path for its plane.TTL eviction. If a slot's TTL expires before all fragments arrive, discard the partial buffer and increment
bsl_reassembly_abandoned_total. The default TTL is 10 seconds.Slot limits. A reassembly buffer implementation may enforce a maximum number of concurrent slots (default: 4096). When the limit is reached, the oldest incomplete slot is evicted to make room for the new TxID.
Duplicate fragments. Duplicate fragments (same TxID + FragIndex) are silently ignored.
Reassembly Metrics
Listeners implementing BRC-130 reassembly expose the following Prometheus counters:
bsl_reassembly_started_total
New reassembly slots opened (first fragment received)
bsl_reassembly_completed_total
Reassemblies completed and delivered downstream
bsl_reassembly_abandoned_total
Slots evicted due to TTL expiry or max-slots eviction
bsl_reassembly_hash_mismatch_total
Reassembled payloads that failed SHA256d verification
Error Handling
Fragment version byte ≠ 0x03
Not a BRC-130 datagram; decode as BRC-124
Bad magic
Silent drop
FragIndex ≥ FragTotal
Silent drop (malformed fragment)
FragTotal = 0
Silent drop (malformed)
OrigPayloadLen = 0
Silent drop
PayloadLen > fragDataSize
Silent drop
Datagram shorter than header
Silent drop
Hash mismatch after reassembly
Drop slot; increment hash_mismatch counter
TTL expiry
Drop slot; increment abandoned counter
Examples
Two-Fragment Transaction (1500-byte path MTU)
A 2000-byte transaction payload is split into two fragments under a 1500-byte path MTU (fragDataSize = 1348):
Fragment 0 (1452 bytes on wire):
Fragment 1 (756 bytes on wire):
Compatibility
BRC-12 (FrameVer 0x01) receivers: Must discard datagrams with FrameVer 0x03.
BRC-124 (FrameVer 0x02) receivers: Must discard datagrams with FrameVer 0x03. BRC-130 fragments will not parse as valid BRC-124 frames because the
PayloadLenfield carries the fragment data size, not the full transaction length.BRC-130 receivers: Implement the reassembly procedure above and deliver a synthetic BRC-124 frame to downstream consumers.
The BRC-130 header is intentionally layout-compatible with BRC-124 at bytes 0–91 so that packet classifiers, firewall rules, and monitoring tools that inspect common header fields (magic, version, TxID, HashKey, SeqNum, SubtreeID) work correctly on fragment datagrams without modification.
References
BRC-12: Raw Transaction Format — Payload format for BSV transactions
BRC-124: Multicast Transaction Frame Format — Base frame format extended by this BRC
BRC-119: SubTree Unified Merkle Path (STUMP) Format — Defines the Subtree ID concept
BRC-129: Multicast Group Address Assignments — SSM/ASM addressing, scopes, and
(S,G)source discovery
Constants Reference
FrameVerV3
3
0x03
BRC-130 fragment frame version
HeaderSizeV3
104
0x68
BRC-130 header size in bytes
IPv6HeaderSize
40
0x28
IPv6 header overhead
UDPHeaderSize
8
0x08
UDP header overhead
MinPathMTU
1280
0x500
IPv6 minimum MTU (RFC 8200)
EthernetMTU
1500
0x5DC
Standard Ethernet MTU
JumboMTU
9000
0x2328
Jumbo frame MTU
DefaultFragDataSize
1348
0x544
fragDataSize at 1500-byte path MTU
Last updated
