BitChat Relay Controller Flood Control Policy: Mesh Network Traffic Management
The BitChat relay controller implements a topology-aware flood control policy that filters packets based on type, TTL, and node degree, selectively relaying session-critical traffic while applying degree-based TTL caps to broadcasts and fragments.
BitChat's mesh networking layer uses the RelayController class to prevent broadcast storms in dense peer-to-peer topologies. According to the permissionlesstech/bitchat source code, the controller analyzes every packet's characteristics alongside local network topology metrics to determine whether to forward, drop, or modify messages before transmission.
How the RelayController Makes Forwarding Decisions
The decide method in RelayController.swift (lines 10-95) evaluates multiple packet properties to determine forwarding behavior. This centralized logic ensures consistent flood control across the mesh network.
Dropping Link-Local and Expired Traffic
The controller immediately suppresses certain packet categories to prevent unnecessary network utilization. According to lines 30-37 of the source:
- REQUEST_SYNC packets: These link-local synchronization requests are never relayed (
shouldRelay = false), as they are intended strictly for direct neighbors (lines 30-31). - Expired or local packets: Any packet with TTL ≤ 1, or those originating from or destined for the local node, are dropped outright (lines 35-37).
Prioritizing Session-Critical Traffic
Session maintenance and encrypted communications receive preferential treatment. As implemented in lines 40-48:
Handshakes, directed encrypted packets, and directed fragments are always relayed with a deterministic TTL decrement. The controller adds modest jitter to these critical flows—10-35 ms for handshake messages and 20-60 ms for other directed encrypted traffic—to prevent synchronization while ensuring timely delivery.
Topology-Aware TTL Management
BitChat's flood control adapts to network density through degree-aware TTL (Time To Live) limitations. The controller examines the local node's degree (number of connected peers) to determine appropriate propagation bounds.
Degree-Based Caps for Voice and Fragments
Live voice traffic and fragmented packets use specialized TTL caps that depend on neighborhood density. Lines 50-66 implement the following logic:
- Dense graphs (degree ≥ highDegreeThreshold): Fragments clamp to
TransportConfig.bleFragmentRelayTtlCapDense. - Sparse graphs: Use the regular fragment TTL cap.
- Relay condition: If the capped TTL ≤ 1, the packet is not relayed.
After determining eligibility, the controller applies a random delay within TransportConfig.bleFragmentRelayMinDelayMs to TransportConfig.bleFragmentRelayMaxDelayMs to prevent transmission collisions.
Broadcast Traffic Clamping Rules
Public messages, node announcements, and urgent board posts follow a sophisticated TTL-clamping policy (lines 70-84):
- Dense neighborhoods: Maximum TTL 5 (minimum 2).
- Thin chains (degree ≤ 2): Original TTL preserved.
- Standard conditions: Preferred TTL 6 (or 7 for announces/urgent posts).
The final TTL is always decremented by 1 before forwarding to ensure propagation limits are enforced.
Jitter Scheduling and Collision Avoidance
After establishing the appropriate TTL, the RelayController adds randomized transmission delays to reduce duplicate-suppression races. Lines 86-94 implement a tiered delay system based on node degree:
- Degree 0-2: 10-40 ms delay
- Degree 3-5: 60-150 ms delay
- Degree 6-9: 80-180 ms delay
- Degree ≥ 10: 100-220 ms delay
This widening delay range in dense topologies prevents simultaneous retransmissions that could overwhelm the mesh.
Code Examples: Flood Control in Action
The following Swift examples demonstrate how RelayController.decide() evaluates different packet scenarios:
Relaying a Public Message
let decision = RelayController.decide(
ttl: 7,
senderIsSelf: false,
recipientIsSelf: false,
isEncrypted: false,
isDirectedEncrypted: false,
isFragment: false,
isDirectedFragment: false,
isHandshake: false,
isAnnounce: false,
isRequestSync: false,
isUrgentBoardPost: false,
isVoiceFrame: false,
degree: 4, // moderate-degree node
highDegreeThreshold: 6 // dense-graph threshold
)
// → shouldRelay = true, newTTL = 5, delayMs ≈ 120 ms
This example shows a standard public message from a moderate-degree node receiving a clamped TTL of 5 and approximately 120ms of jitter.
Handling Voice Fragments in Dense Networks
let decision = RelayController.decide(
ttl: 7,
senderIsSelf: false,
recipientIsSelf: false,
isEncrypted: false,
isDirectedEncrypted: false,
isFragment: true,
isDirectedFragment: false,
isHandshake: false,
isAnnounce: false,
isRequestSync: false,
isUrgentBoardPost: false,
isVoiceFrame: true,
degree: 8, // dense graph (≥ highDegreeThreshold)
highDegreeThreshold: 6
)
// → uses bleFragmentRelayTtlCapDense, newTTL = 3, delayMs within fragment range
Dense network conditions trigger the fragment TTL cap, reducing the voice frame's propagation hop count to prevent flooding while maintaining audio stream continuity.
Suppressing Link-Local Synchronization
let decision = RelayController.decide(
ttl: 5,
senderIsSelf: false,
recipientIsSelf: false,
isEncrypted: false,
isDirectedEncrypted: false,
isFragment: false,
isDirectedFragment: false,
isHandshake: false,
isAnnounce: false,
isRequestSync: true, // link-local request
isUrgentBoardPost: false,
isVoiceFrame: false,
degree: 3,
highDegreeThreshold: 6
)
// → shouldRelay = false
Despite having sufficient TTL, REQUEST_SYNC packets are explicitly blocked from relaying to maintain link-local boundaries.
Related Components and Configuration
The flood control policy relies on several supporting files in the BitChat repository:
TransportConfig.swift: Defines TTL defaults and fragment relay caps (bleFragmentRelayTtlCapDense,bleFragmentRelayMinDelayMs,bleFragmentRelayMaxDelayMs).BLEService.swift: InvokesRelayController.decidewhen forwarding Bluetooth Low Energy packets.BLERouteForwardingPolicy.swift: Applies the controller's decisions to actual routing paths.MessageRateLimiter.swift: Works alongside the flood policy to limit per-content traffic.
Summary
The BitChat relay controller flood control policy balances mesh network reliability with bandwidth conservation through:
- Selective dropping of REQUEST_SYNC and expired TTL packets at lines 30-37 of
RelayController.swift. - Priority relaying of session-critical traffic with minimal deterministic jitter.
- Degree-aware TTL clamping that reduces broadcast propagation in dense networks while preserving reach in sparse topologies.
- Tiered jitter scheduling that increases delays proportionally to node degree, preventing transmission collisions.
Frequently Asked Questions
What happens to packets with TTL less than or equal to 1?
Packets with TTL ≤ 1 are dropped immediately by the RelayController and never relayed. According to lines 35-37 of RelayController.swift, this suppression applies to prevent "time exceeded" packets from circulating in the mesh, effectively defining the boundary of flood control.
How does BitChat prevent broadcast storms in dense mesh networks?
BitChat prevents broadcast storms through degree-based TTL clamping. When a node's degree (number of connected peers) exceeds the highDegreeThreshold, the controller clamps broadcast TTL to maximum 5 and fragment TTL to bleFragmentRelayTtlCapDense. Additionally, jitter delays increase from 10-40ms to 100-220ms as degree grows, reducing simultaneous retransmission probability.
Why are REQUEST_SYNC packets never relayed?
REQUEST_SYNC packets are treated as link-local control messages intended only for immediate neighbors. As implemented at lines 30-31 of RelayController.swift, these synchronization requests return shouldRelay = false regardless of TTL or network conditions, ensuring that topology discovery remains localized and doesn't propagate across the entire mesh.
What is the difference between how voice fragments and broadcast messages are handled?
Voice fragments use TransportConfig.bleFragmentRelayTtlCapDense as a hard ceiling in dense graphs, while broadcast messages (public posts, announces) apply a graduated clamping policy: maximum TTL 5 in dense networks, original TTL preserved in thin chains (degree ≤ 2), and preferred TTL 6 or 7 for standard or urgent broadcasts. Both receive degree-proportional jitter, but fragments use the specialized fragment delay ranges defined in TransportConfig.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →