Multicast Transaction NACK Retransmission Protocol
Jeff Harris (jeff@lightweb.net)
Abstract
This BRC specifies the NACK-based retransmission and endpoint discovery protocol for the BSV multicast transaction distribution pipeline. It defines five UDP datagram formats — ADVERT, NACK, MISS, ACK, and THROTTLED — along with tier/preference-based endpoint selection, an escalation state machine, and configurable retransmit modes. The protocol operates on top of the BRC-124 data-plane and enables reliable gap recovery without requiring connection state at the ingress or listener tiers.
Copyright
This BRC is licensed under the Open BSV License.
Motivation
The BRC-124 data-plane delivers BSV transactions over IPv6 multicast with best-effort semantics. Network congestion, interface buffer overflows, and MLD snooping transitions can cause individual frames to be lost. Because BRC-124 frames carry a stable per-flow HashKey and a monotonic SeqNum stamped by the ingress proxy, listeners can detect exactly which frame is missing without a central sequence authority.
This BRC adds the reliability layer that allows listeners to recover those gaps:
Gap detection — listeners identify missing frames when a frame's
SeqNumadvances by more than 1 from the last-seen value for a givenHashKeyflow.NACK dispatch — listeners send a 64-byte NACK datagram to a retry endpoint identifying the missing frame by its flow (
HashKey) and sequence number.ACK/MISS/THROTTLED responses — every served NACK receives a deterministic 16-byte response; ACK confirms retransmit dispatched, MISS triggers immediate escalation, and the optional THROTTLED signals honest congestion (hold and retry the same endpoint without escalating).
Endpoint discovery — retry endpoints periodically multicast a 56-byte ADVERT beacon; listeners maintain a dynamic registry sorted by tier and preference, with no manual configuration required in well-connected deployments.
Flood prevention — deduplication and fill-suppression mechanisms prevent retransmit storms at scale.
Specification
Common Message Preamble
All BRC-126 datagrams begin with a 7-byte preamble:
0
4
Network Magic
0xE3E1F3E8 (BSV mainnet P2P magic)
4
2
Protocol Ver
0x02BF (703, BSV large-block baseline)
6
1
MsgType
Identifies the message type (see below)
The MsgType byte at offset 6 is in the same position as FrameVersion in BRC-124 data frames. Values 0x10–0x2F are reserved for BRC-126 control messages and are distinct from the data-frame version codes (0x01–0x07).
MsgType Values
0x10
NACK
64 B
Listener → Retry endpoint
0x11
MISS
16 B
Retry endpoint → Listener
0x12
ACK
16 B
Retry endpoint → Listener
0x13
THROTTLED
16 B
Retry endpoint → Listener
0x20
ADVERT
56 B
Retry endpoint → Beacon group
ADVERT Wire Format (MsgType 0x20) — 56 bytes
MsgType 0x20) — 56 bytesSent periodically by retry endpoints to the beacon multicast group. Listeners use it to build and maintain their endpoint registry.
0
4
Network Magic
0xE3E1F3E8
4
2
Protocol Ver
0x02BF
6
1
MsgType
0x20 (ADVERT)
7
1
Scope
0x05 = site-local, 0x08 = org, 0x0E = global
8
16
NACKAddr
IPv6 unicast address listeners use for NACK requests
24
2
NACKPort
UDP port for NACK requests (default 9300)
26
1
Tier
Operator-assigned proximity tier; 0 = source-adjacent
27
1
Preference
Within-tier priority; higher = more preferred (default 128)
28
2
BeaconInterval
Beacon send interval in seconds; listeners TTL = 3 × this
30
2
Flags
Capability bitmask (see below)
32
4
InstanceID
CRC32c of hostname; stable across restarts
36
4
Reserved
Must be 0x00000000
40
16
Reserved
Must be all zeros; reserved for future capability bitmap
ADVERT Flags Bitmask
0x01
(reserved)
Unused; must be zero
0x02
HasParent
Endpoint forwards cache-miss NACKs to an upstream endpoint
0x04
Draining
Entering shutdown; listeners should stop routing new NACKs
0x08
UnicastRetransmit
Supports unicast frame delivery to the NACK source
0x10
MulticastRetransmit
Retransmits via multicast to the original shard group
HasParent: When set, the endpoint maintains a connection to a parent (higher-tier) endpoint and forwards NACKs on local cache miss. Listeners need only know their local tier; inter-tier forwarding is handled transparently.
Beacon group addresses are derived from the shard address scheme using the reserved control-plane index 0xFFFD:
Site (0x05)
FF05::B:FFFD
Org (0x08)
FF08::B:FFFD
Global (0x0E)
FF0E::B:FFFD
Addresses use the IANA-aligned layout: bytes 0–1 carry the scope prefix, bytes 2–11 are zero (IANA 96-bit boundary), bytes 12–13 carry the IANA Bitcoin group-id (0x000B), and bytes 14–15 carry the group index. Operators MAY override the group-id via -mc-group-id.
NACK Wire Format (MsgType 0x10) — 64 bytes
MsgType 0x10) — 64 bytesSent by a listener to a retry endpoint when a gap is detected. Identifies the missing frame by its flow (HashKey) and sequence number range. For current single-frame retrieval, StartSeq == EndSeq; range requests (StartSeq < EndSeq) are reserved for future use.
0
4
Magic
0xE3E1F3E8
4
2
ProtoVer
0x02BF
6
1
MsgType
0x10 (NACK)
7
1
Flags
Bit 0 (0x01) = Proxied; bits 1–7 reserved, must be 0
8
8
HashKey
Stable per-flow XXH64 identifier; from BRC-124 frame bytes 40–47
16
8
StartSeq
First missing SeqNum (inclusive)
24
8
EndSeq
Last missing SeqNum (inclusive); equals StartSeq for single-frame retrieval
32
32
SubtreeID
32-byte batch identifier; from BRC-124 frame bytes 56–87; zeros = unset
The listener opens a per-request ephemeral UDP socket ([::]:0), sends the NACK, and waits up to 300 ms for a single response (MISS or ACK).
HashKey (offset 8) is the
HashKeyfield from the BRC-124 frame, computed asXXH64(senderIPv6 ∥ groupIdx ∥ subtreeID). It uniquely identifies the flow. The retry endpoint usesHashKeyas a per-flow rate-limiting key (NACK storm cap). A value of0bypasses the per-flow check.StartSeq / EndSeq (offsets 16/24) specify the range of missing sequence numbers. For current single-frame retrieval,
StartSeq == EndSeq. The retry endpoint looks up the frame using the 16-byte cache keyHashKey ∥ StartSeq.SubtreeID (offset 32) is carried for informational purposes; the cache key is
HashKey ∥ SeqNumand does not require SubtreeID for disambiguation.Flags / Proxied (offset 7, bit
0x01) marks a NACK that an endpoint issued on behalf of a downstream multicast domain (cross-domain proxying — see NACK Proxying). An endpoint receiving a NACK with this bit set MUST serve it from its own cache but MUST NOT re-proxy it, bounding any proxy chain to a single hop. The bit was previously reserved and is ignored by legacy endpoints, which simply never re-proxy.
NACK Proxying (cross-domain recovery)
A retry endpoint serving a downstream multicast domain (one fed by a listener's multicast egress rather than directly by the ingress proxy) can only cache what the listener actually emitted. A frame the listener never put on the downstream wire — egress send error, interface flap, or in-fabric loss — is missed identically by the downstream endpoint and every downstream consumer, so a downstream-only cache cannot repair it. NACK proxying recovers such frames from an upstream endpoint that received them directly from the ingress proxy:
A downstream consumer NACKs the downstream endpoint, which suffers a local cache miss and returns
MISSimmediately.The downstream endpoint forwards the NACK to a statically configured upstream endpoint with the Proxied flag set (
0x01). Recovery is asynchronous ("cache-warm"); no NACK worker is held waiting.The upstream endpoint serves the proxied NACK from its cache. Because the requester (the downstream endpoint) is not joined to the upstream shard groups, the frame is returned by unicast to the NACK source — a proxied NACK is always served a unicast copy regardless of the upstream's advertised retransmit mode.
The downstream endpoint re-caches the recovered frame (keyed
HashKey ∥ SeqNum, per-FrameVer TTL) and multicast-retransmits it into the downstream domain; the consumer's gap auto-fills viaTracker.Fill().
One-hop bound. The Proxied flag prevents an upstream endpoint from re-proxying, so any proxy chain is at most one hop. Upstream discovery is by static configuration, because a separated downstream domain generally cannot receive upstream multicast ADVERT beacons. The HasParent ADVERT flag (0x02) signals that an endpoint has an upstream parent configured. When several downstream endpoints run with proxying enabled against a shared cache backend, an in-flight claim deduplicates the upstream NACKs so only one endpoint recovers each gap.
MISS Response (MsgType 0x11) — 16 bytes
MsgType 0x11) — 16 bytesSent unicast to the NACK source when the requested frame is not in the endpoint's cache. On receipt, the listener advances immediately to the next endpoint (no backoff delay).
0
4
Magic
0xE3E1F3E8
4
2
ProtoVer
0x02BF
6
1
MsgType
0x11 (MISS)
7
1
Flags
Reserved; must be 0x00
8
8
SeqNum
Always 0 on MISS
ACK Response (MsgType 0x12) — 16 bytes
MsgType 0x12) — 16 bytesSent unicast to the NACK source when the frame was found and retransmit dispatched. On receipt, the listener cancels the gap entry immediately.
0
4
Magic
0xE3E1F3E8
4
2
ProtoVer
0x02BF
6
1
MsgType
0x12 (ACK)
7
1
Flags
0x01 = multicast sent; 0x02 = unicast sent
8
8
SeqNum
SeqNum of the retransmitted frame (from BRC-124 bytes 48–55)
The listener uses the SeqNum echo to confirm the gap entry matches before cancelling it.
THROTTLED Response (MsgType 0x13) — 16 bytes
MsgType 0x13) — 16 bytesSent unicast to the NACK source when the request was rejected by a congestion-control tier that limits per-gap or per-flow request rate (see Flood Prevention). It is a flow-control signal, not a failure: the endpoint is healthy, and for a per-gap throttle a retransmit for this exact gap was likely just served and is propagating over the multicast data plane. On receipt a listener MUST hold the gap for the hinted backoff and retry the same endpoint; it MUST NOT escalate to another endpoint and MUST NOT count the throttle as a recovery failure.
0
4
Magic
0xE3E1F3E8
4
2
ProtoVer
0x02BF
6
1
MsgType
0x13 (THROTTLED)
7
1
Flags
Bits 0-3 = backoff bucket; 4-7 reserved
8
8
SeqNum
Echo of the throttled request's StartSeq
Backoff hint. The suggested hold is ThrottleHintBase << bucket, where ThrottleHintBase = 125 ms and bucket is the Flags low nibble. Endpoints SHOULD use bucket 2 (~500 ms) for a per-gap throttle and bucket 3 (~1 s) for a per-flow throttle. Listeners SHOULD apply jitter (e.g. uniform over [hold/2, hold]) to de-synchronise and MAY clamp the hold to a local maximum. The gap's absolute TTL remains the upper bound; a multicast repair cancels the gap regardless.
Emission rules.
THROTTLED is OPTIONAL and SHOULD default to disabled; it is a load-shedding refinement for high-fan-out deployments.
An endpoint MUST NOT send THROTTLED for a flood-tier (per-source) rejection: that tier sheds abusive or spoofed-source load, and answering it would permit reflection. (The 16-byte response is smaller than the 64-byte NACK, so the protocol is never a bandwidth amplifier regardless.)
An endpoint that does not implement THROTTLED stays silent; the listener falls back to timeout + backoff.
A listener that does not recognise
0x13treats it as an unparseable response (timeout-equivalent), so emission is backward-compatible.
Tier / Preference Model
Retry endpoints are organised into tiers representing proximity to the transaction source, and assigned a preference within each tier.
0
Same AS as bitcoin-shard-proxy (source-adjacent)
1
One AS boundary from source
N
N AS hops from source
0xFF
Static seed (no beacon received; lowest priority)
Endpoints discovered via ADVERT carry their operator-assigned Tier (0–254) and Preference (0–255). Endpoints registered via static configuration seed the registry at Tier=0xFF, Preference=0.
Listeners sort the endpoint registry by (Tier ASC, Preference DESC). NACK dispatch always selects the head of the sorted list; on MISS or timeout, the listener advances to the next position.
Escalation State Machine
ACK received: Cancel gap entry. No further NACKs sent for this gap.
MISS received: Advance to next endpoint at same tier by Preference; if tier exhausted, move to next tier; retry immediately.
Timeout: Apply exponential backoff (capped at
nack-backoff-max); retry on next sweeper tick.THROTTLED received: Hold the gap for the hinted backoff and retry the same endpoint. Do not escalate and do not count it as a recovery failure — it is congestion control (see THROTTLED Response).
Multicast fill: The data-plane receive goroutine calls
Tracker.Fill()independently; gap cancelled regardless of NACK state.
Beacon Scopes
Three scope bytes are defined for the ADVERT wire format. The reference implementation's -beacon-scope flag accepts site, global, or both (sends to site + global simultaneously):
Site (0x05)
0x05
FF05::B:FFFD
Intra-site discovery; all listeners join at startup
Org (0x08)
0x08
FF08::B:FFFD
Organisation-wide discovery for multi-site AS
Global (0x0E)
0x0E
FF0E::B:FFFD
Inter-AS discovery via MP-BGP MVPN / MSDP
Scope byte 0xFF is used in ADVERT datagrams when the sender intends to cover both site and global simultaneously (sends two ADVERTs). Listeners parse the scope byte from each individual datagram.
To cover multiple scopes, run separate endpoint instances each configured with a different -beacon-scope value. Each scope can use independent Tier and Preference tuning.
Listeners compute TTL as 3 × BeaconInterval. An endpoint not heard for that duration is evicted from the registry. Static seeds (-retry-endpoints) are never evicted.
Configurable Retransmit Modes
Retransmit behavior is controlled by flags on the retry endpoint:
-retransmit-multicast
true
Retransmit frame to original multicast shard group
-retransmit-unicast
false
Retransmit frame unicast to NACK source
-suppress-miss
false
Do not send MISS response on cache miss
-suppress-ack
false
Do not send ACK response on cache hit
Deployment profiles:
On-fabric (default):
-retransmit-multicast=true— all listeners on the fabric receive the retransmit simultaneously.Edge / unicast:
-retransmit-unicast=true -retransmit-multicast=false— for listeners not on the multicast fabric.High-volume:
-suppress-ack=true— reduces per-frame ACK traffic; MISS responses are preserved for escalation correctness.
Flood Prevention
Cache TTL (60 s)
Retry endpoint
Frames expire naturally; bounds retransmit window
Tracker.Fill()
Listener
Multicast repair cancels all pending NACKs for a gap
Jitter hold-off
Listener
Randomised delay before first NACK suppresses correlated duplicates
Exponential backoff
Listener
Reduces NACK rate on persistent or repeated gaps
MaxRetries + GapTTL
Listener
Gap entries evicted after retry exhaustion or absolute deadline
THROTTLED hint
Retry endpoint
Tells throttled listeners to hold (vs. timeout + escalate), cutting NACK load on honest congestion; IP flood tier stays silent
Examples
ADVERT Datagram (56 bytes)
A site-scope endpoint at fd20::24, port 9300, Tier 0, Preference 128, 60-second interval, multicast retransmit enabled:
NACK Datagram (64 bytes)
Single-frame retrieval: missing frame for flow HashKey=0xA1B2C3D400000001, SeqNum=1235:
MISS Response (16 bytes)
ACK Response (16 bytes)
Frame found and retransmitted via multicast:
References
BRC-12: Raw Transaction Format — Payload format for transaction data within BRC-124 frames
BRC-124: Multicast Transaction Frame Format — Data-plane frame format; defines
HashKey,SeqNum, andSubtree IDstamped by the proxy
Constants Reference
MagicBSV
3823236072
0xE3E1F3E8
BSV mainnet P2P magic
ProtoVer
703
0x02BF
Protocol version
MsgTypeNACK
16
0x10
NACK request
MsgTypeMISS
17
0x11
MISS response
MsgTypeACK
18
0x12
ACK response
MsgTypeADVERT
32
0x20
Endpoint advertisement beacon
ScopeSite
5
0x05
Site-local beacon scope
ScopeOrg
8
0x08
Organisation beacon scope
ScopeGlobal
14
0x0E
Global beacon scope
NACKSize
64
0x40
NACK datagram size in bytes
FlagProxied
1
0x01
NACK flag: proxied, one-hop downstream
FlagMulticastSent
1
0x01
ACK flag: multicast retransmit sent
FlagUnicastSent
2
0x02
ACK flag: unicast retransmit sent
FlagHasParent
2
0x02
ADVERT flag: upstream endpoint set
FlagDraining
4
0x04
ADVERT flag: endpoint is draining
FlagUnicastRetransmit
8
0x08
ADVERT flag: unicast retransmit
FlagMcastRetransmit
16
0x10
ADVERT flag: multicast retransmit
GroupBeacon
65533
0xFFFD
Control-plane beacon group index
DefaultNACKPort
9300
0x2454
Default NACK/ADVERT UDP port
DefaultBeaconInterval
60
—
Default ADVERT send interval (s)
DefaultCacheTTL
60
—
Default frame cache TTL (s)
TierStaticSeed
255
0xFF
Tier assigned to static seed endpoints
Last updated
Was this helpful?

