BitChat BLE Mesh TTL: What Is the Default Hop Limit for Multi-Hop Relay?
TL;DR: BitChat's Bluetooth Low Energy mesh network enforces a default Time-To-Live (TTL) of 7 hops for multi-hop relay, ensuring packets traverse a maximum of seven intermediary nodes before expiration to balance network reachability with power consumption and radio interference.
BitChat (permissionlesstech/bitchat) implements a decentralized BLE mesh protocol where understanding the TTL for multi-hop relay is critical for optimizing message propagation and debugging connectivity boundaries. The mesh uses a decrementing counter mechanism to prevent infinite broadcast loops while allowing sufficient reach across the network topology.
Default TTL Configuration in BitChat
The origin TTL value is hardcoded as a transport-layer constant. In TransportConfig.swift, the system defines the maximum relay depth:
public static let messageTTLDefault: UInt8 = 7 // default TTL for BLE messages
This UInt8 value initializes every new BitchatPacket with a hop budget of 7. When a packet enters the mesh, this counter represents the remaining relay operations permitted before the message must be consumed rather than forwarded.
Calculating Hop Count from TTL Values
BitChat derives the actual transmission distance by comparing the origin TTL against the received TTL. The MeshPingPayload.swift file contains the authoritative calculation logic:
public static func hopCount(originTTL: UInt8, receivedTTL: UInt8) -> Int? {
guard originTTL >= receivedTTL else { return nil }
return Int(originTTL - receivedTTL) + 1
}
This function returns nil for invalid packet states (where the received TTL exceeds the origin, indicating corruption or misconfiguration). For valid packets, it computes the traversed distance by measuring the decrement difference and adding 1 to account for the final receiving node that processes the packet without retransmitting it.
Relay Logic and TTL Enforcement
Relay nodes implement strict validation before forwarding. The forwarding decision logic requires packet.ttl > 0 as a prerequisite for retransmission. When a node relays a packet, it performs a wrapping decrement to safely handle unsigned integer underflow:
var forwarded = packet
forwarded.ttl &-= 1 // decrement TTL
If the TTL reaches 0 after decrementing, the packet is processed locally but dropped from the outbound queue. This mechanism ensures that REQUEST_SYNC packets and other messages with TTL 0 or 1 are never relayed, as confirmed by BLESourceRouteOriginationPolicyTests.swift.
Practical Implementation Examples
Creating a packet with the default hop limit requires referencing the transport configuration:
let packet = BitchatPacket(
type: .announce,
ttl: TransportConfig.messageTTLDefault,
payload: myPayload
)
To audit network performance, calculate the actual hop distance upon receipt:
if let hopCount = MeshPingPayload.hopCount(
originTTL: received.originTTL,
receivedTTL: received.ttl
) {
print("Packet travelled \(hopCount) hops")
}
For custom relay implementations, enforce the TTL constraint before forwarding:
func shouldRelay(packet: BitchatPacket) -> Bool {
return packet.ttl > 0
}
Key Source Files
The TTL implementation spans the following files in the permissionlesstech/bitchat repository:
TransportConfig.swift(bitchat/Services/TransportConfig.swift): DefinesmessageTTLDefault = 7and other transport-layer constants governing BLE behavior.MeshPingPayload.swift(localPackages/BitFoundation/Sources/BitFoundation/MeshPingPayload.swift): Implements thehopCount(originTTL:receivedTTL:)function used to derive transmission distance.BLEServiceTests.swift(bitchatTests/BLEServiceTests.swift): Unit tests verifying TTL initialization, decrementing, and boundary handling in the BLE stack.BLEOutboundLinkPlannerTests.swift(bitchatTests/Services/BLEOutboundLinkPlannerTests.swift): Validates that relay candidates are selected only whenTTL > 0and that the decrement operation occurs before transmission.BLESourceRouteOriginationPolicyTests.swift(bitchatTests/Services/BLESourceRouteOriginationPolicyTests.swift): Demonstrates that packets with TTL values of 0 or 1 (such as synchronization requests) are correctly identified as non-relayable.
Summary
- BitChat's BLE mesh uses a default TTL of 7 hops defined by
TransportConfig.messageTTLDefaultinTransportConfig.swift. - The
hopCount()method inMeshPingPayload.swiftcalculates traversed distance by comparing the packet's origin TTL against its received TTL. - Relay nodes use wrapping subtraction (
&-= 1) to decrement TTL and cease forwarding when the counter reaches 0, preventing infinite propagation. - This 7-hop limit optimally balances mesh network coverage against battery consumption and wireless congestion constraints inherent to BLE communications.
Frequently Asked Questions
What is the maximum number of hops in BitChat's BLE mesh?
The maximum transmission distance is strictly capped at 7 hops, as defined by the messageTTLDefault constant in TransportConfig.swift. Once a packet has traversed seven relay nodes, the TTL reaches 0 and the packet is discarded rather than forwarded, creating a hard boundary on network diameter.
How does BitChat calculate the number of hops a packet traveled?
BitChat uses the MeshPingPayload.hopCount(originTTL:receivedTTL:) function to compute distance. This method subtracts the received TTL from the origin TTL and adds 1 to account for the final receiving node. If the received TTL exceeds the origin TTL (indicating protocol violation), the function returns nil.
What happens when a packet's TTL reaches zero?
When a packet's TTL counter reaches 0, the current node processes the payload locally but does not forward the packet to other mesh peers. This termination condition prevents broadcast storms and infinite loops, as verified by the test coverage in BLESourceRouteOriginationPolicyTests.swift.
Can the default TTL be modified in BitChat?
While TransportConfig.messageTTLDefault is defined as a static constant, developers can override the TTL value during BitchatPacket initialization by passing a custom UInt8 value. However, exceeding the default 7 hops is discouraged as it violates the protocol's power management assumptions and may cause increased radio interference in dense mesh deployments.
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 →