How BitChat Implements Relay Flood Control Using Degree-Based TTL Clamping
BitChat prevents Bluetooth mesh flooding by dynamically clamping packet TTL values based on node graph density, applying stricter limits to high-degree nodes in dense network regions.
BitChat is an open-source messaging protocol designed for permissionless Bluetooth mesh networks. To protect devices from battery drain and bandwidth exhaustion caused by uncontrolled packet propagation, the codebase employs relay flood control using degree-based TTL clamping that adapts to local network topology. The implementation centers on the RelayController.decide method in bitchat/Services/RelayController.swift, which evaluates each packet against the forwarding node's graph degree before determining relay parameters.
The Core Logic: RelayController.decide
The flood control mechanism lives in RelayController.decide (lines 10-95), a Swift function that receives the current packet TTL (time-to-live) and the node's current graph degree (number of neighboring links). This method separates network regions into dense and sparse categories using a configurable threshold, then applies protocol-specific clamps.
Detecting Dense vs. Sparse Regions
The controller distinguishes between dense and sparse mesh topologies using highDegreeThreshold, imported from TransportConfig.bleHighDegreeThreshold.
- Dense graphs: Nodes with
degree >= highDegreeThreshold - Sparse graphs: Nodes with
degree < highDegreeThreshold - Very sparse: Specifically identified when
degree <= 2
This classification occurs at the start of the decision process and determines which TTL caps apply to subsequent traffic.
Fragment Traffic Handling
For media fragments and live-voice frames, the controller applies specialized caps to prevent high-bandwidth content from flooding the mesh. According to the implementation in RelayController.swift (lines 54-66):
- Dense graphs: Use
TransportConfig.bleFragmentRelayTtlCapDense(hardcoded to 5) - Sparse graphs: Use
TransportConfig.bleFragmentRelayTtlCap(hardcoded to 7)
The algorithm clamps the incoming TTL against the appropriate cap, then decrements by one before relaying. This ensures fragments travel shorter distances in well-connected regions while maintaining reachability across sparse chains.
Broadcast Traffic Clamping
After fragment handling, the controller evaluates broadcast traffic (announcements, board posts, and generic messages) using a ttlLimit closure (lines 74-83). The clamping rules follow this hierarchy:
- Dense nodes (
degree >= highDegreeThreshold): TTL limited tomax(2, min(ttlCap, 5)) - Very sparse nodes (
degree <= 2): OriginalttlCappreserved (no reduction) - Moderate density: TTL limited to 7 for announces/urgent posts, or 6 for normal traffic, never dropping below 2
This tiered approach prevents dense clusters from amplifying floods while preserving message propagation across long chain-like networks where each hop is costly.
Configuration Constants in TransportConfig
All thresholds and caps are centralized in bitchat/Services/TransportConfig.swift (lines 6-12 and 27-31). Key constants include:
bleHighDegreeThreshold: Defines the boundary between dense and sparse graphsbleFragmentRelayTtlCapDense: 5-hop limit for fragments in dense areasbleFragmentRelayTtlCap: 7-hop limit for fragments in sparse areas- Base TTL caps for broadcast traffic (6 or 7 depending on urgency)
Centralizing these values allows network operators to tune flood control behavior without modifying the core logic in RelayController.
Why Graph Degree Matters for Flood Control
In dense mesh regions, a node with many neighbors can reach hundreds of devices within a few hops. Without clamping, a single broadcast could trigger exponential relay proliferation, exhausting device batteries and saturating the 2.4 GHz spectrum. By capping TTL to 5 or lower for high-degree nodes, BitChat contains the flood radius before it engulfs the entire dense cluster.
Conversely, in sparse topologies where nodes form long chains or isolated islands, each relay represents a necessary bridge rather than a redundant amplification. The algorithm therefore preserves higher TTL values for low-degree nodes, ensuring messages can still traverse the maximum configurable distance to reach isolated recipients.
Code Examples
The following Swift code demonstrates how RelayController.decide processes a normal broadcast packet in a dense network region:
// Example: deciding whether to relay a normal broadcast packet
let decision = RelayController.decide(
ttl: 7, // packet arrived with full TTL
senderIsSelf: false,
recipientIsSelf: false,
isEncrypted: false,
isDirectedEncrypted: false,
isFragment: false,
isDirectedFragment: false,
isHandshake: false,
isAnnounce: true, // an announce packet
isRequestSync: false,
isUrgentBoardPost: false,
isVoiceFrame: false,
degree: 8, // node sees 8 neighboring links
highDegreeThreshold: TransportConfig.bleHighDegreeThreshold
)
// decision.shouldRelay == true
// decision.newTTL == 4 // dense-graph clamp (max 5) then -1 for the hop
For fragment traffic on sparse nodes, the controller permits longer propagation paths:
// Example: fragment traffic on a sparse node
let fragmentDecision = 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: false,
degree: 3, // sparse graph
highDegreeThreshold: TransportConfig.bleHighDegreeThreshold
)
// fragmentDecision.newTTL == 6 // uses bleFragmentRelayTtlCap (7) then -1
Summary
- BitChat implements flood control through
RelayController.decideinbitchat/Services/RelayController.swift, which clamps TTL based on node degree. - Dense graphs (degree >= threshold) use stricter caps: 5-hop maximum for fragments and aggressive broadcast clamping.
- Sparse graphs preserve higher TTL values (up to 7 hops) to ensure reachability across chain-like topologies.
- Configuration is centralized in
TransportConfig.swift, enabling topology-specific tuning without logic changes. - The mechanism balances battery preservation in dense clusters against network reachability in sparse regions.
Frequently Asked Questions
How does BitChat determine if a node is in a dense or sparse network region?
BitChat uses the highDegreeThreshold constant from TransportConfig.swift to classify nodes. If a node's current graph degree (number of visible neighbors) meets or exceeds this threshold, the RelayController.decide method treats it as a dense-graph node and applies stricter TTL caps. Nodes with degree values of 2 or below are treated as very sparse and retain their original TTL values.
Why are fragment packets treated differently from broadcast messages?
Media fragments and voice frames consume significantly more bandwidth than text broadcasts. According to the source code in RelayController.swift lines 54-66, fragments utilize separate TTL constants—specifically bleFragmentRelayTtlCapDense (5 hops) versus bleFragmentRelayTtlCap (7 hops)—to prevent high-bandwidth content from flooding dense mesh clusters while still allowing transmission across sparse networks.
What prevents TTL clamping from breaking message delivery in sparse networks?
The algorithm specifically checks for very sparse conditions (degree <= 2) and bypasses aggressive clamping for these nodes. As implemented in the ttlLimit closure (lines 74-83), sparse nodes either retain the full TTL cap or use higher limits (6-7 hops) compared to dense nodes (capped at 5). This ensures messages can traverse long chain-like topologies where each intermediate hop is necessary for end-to-end delivery.
Where can I modify the degree threshold and TTL caps?
All tunable parameters reside in bitchat/Services/TransportConfig.swift. The bleHighDegreeThreshold defines the boundary between dense and sparse classifications, while bleFragmentRelayTtlCap and bleFragmentRelayTtlCapDense control fragment propagation limits. Modifying these constants changes flood control behavior across the entire mesh without requiring changes to RelayController.swift.
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 →