How BitChat Sync Schedule Prioritizes Different Message Types: Priority Levels Explained
BitChat uses a six-level priority system encoded in a SyncTypeFlags bit-field to determine which message types are included in each REQUEST_SYNC packet, ensuring public chat content syncs first while deferring large file transfers and excluding ephemeral traffic.
The mesh messaging protocol in permissionlesstech/bitchat orchestrates peer-to-peer synchronization through a carefully weighted schedule that ranks message importance by bandwidth impact and user necessity. Understanding how the BitChat sync schedule prioritizes different message types reveals why core chat packets propagate immediately while file transfers wait for dedicated rounds. This system centers on the SyncTypeFlags option set defined in SyncTypeFlags.swift, which maps message categories to specific bit positions within every sync request TLV.
The Six-Level Message Priority Hierarchy
When the GossipSyncManager builds a REQUEST_SYNC packet, it constructs a compact bit-field that tells peers exactly which message categories to re-deliver. The scheduler adds flags in strict priority order until it hits the per-tick bandwidth cap.
1. Public Traffic (Highest Priority)
announce (bit 0) and message (bit 1) form the SyncTypeFlags.publicMessages baseline. These flags are always set in every sync round because they carry core chat content that every user expects to receive. The scheduler never omits these types, ensuring mesh-wide consistency for public conversations.
2. Fragment Re-assembly
fragment (bit 5) is appended when the local fragment buffer detects stalled broadcast reassembly. By elevating fragments to priority 2, the schedule allows peers to fetch missing pieces of large payloads before attempting to sync lower-priority data.
3. Board and Pre-Key Data
boardPost (bit 8) and prekeyBundle (bit 9) are added only if bandwidth permits. Board posts and X3DH pre-key bundles support onboarding and community features, but they are less time-critical than live chat. The GossipSyncManager probes remaining capacity after handling public traffic and fragments before setting these bits.
4. Group Messages
groupMessage (bit 10) follows board and pre-key traffic. Group chat payloads are synchronized after public and fragment data, respecting the same bandwidth caps that constrain priority 3 items.
5. File Transfers
fileTransfer (bit 7) is deliberately deferred to later sync rounds. Large payloads are excluded from early rounds to prevent saturating the mesh with heavy traffic while critical control messages are still pending.
6. Low-Priority and Ephemeral Types
courierEnvelope, ping, pong, nostrCarrier, and voiceFrame return nil when queried for their sync flag. These directed, ephemeral, or real-time media messages are never included in gossip syncs because replaying them later wastes airtime and offers no value to the receiving peer.
How GossipSyncManager Orchestrates Sync Rounds
The sync workflow in GossipSyncManager.swift executes four discrete steps each time the periodic sync task fires:
- Collect candidates – The manager examines pending outbound queues, fragment-assembly buffers, and forced resync requests to determine which types have outstanding data.
- Create
SyncTypeFlags– It initializes the flag set with.publicMessages, then iterates through priorities 2–5, adding bits until the bandwidth limit is reached. - Rate-limit responses –
SyncResponseRateLimiter.swiftenforces a hard cap: a peer cannot answer the same request type more than 8 times in 30 seconds, preventing adversaries from flooding specific high-priority channels. - Encode for transmission – The
SyncTypeFlags.toData()method serializes the bit-field (1–8 bytes, little-endian) and wraps it in aRequestSyncPacket(TLV type0x04).
Because the bit-to-type mapping lives in SyncTypeFlags.swift, the protocol maintains forward compatibility: unknown high bits are ignored by older clients, allowing the network to sync understood types without version negotiation failures.
Implementing SyncTypeFlags in Swift
The following patterns from SyncTypeFlags.swift and RequestSyncPacket.swift demonstrate how to build, check, and serialize priority flags:
// Build a flag set for a normal sync round
let flags = SyncTypeFlags.publicMessages
.union(.fragment) // include missing fragments
.union(.board) // add board posts if bandwidth allows
// Check whether a received REQUEST_SYNC wants a given type
if receivedFlags.contains(.message) {
// enqueue messages for retransmission
}
// Serialize the flag set for the TLV payload
if let payload = flags.toData() {
let requestSync = RequestSyncPacket(payload: payload)
// send via BLE or GCS
}
// Decode an incoming payload back to a flag set
if let incoming = SyncTypeFlags.decode(incomingData) {
// use `incoming.contains(.fragment)` etc.
}
Summary
- Public traffic (
announce,message) always syncs first viaSyncTypeFlags.publicMessages. - Fragments receive priority treatment to unblock stalled reassembly, followed by board posts, pre-key bundles, and group messages as bandwidth allows.
- File transfers are explicitly deprioritized to avoid mesh saturation.
- Ephemeral types (
ping,pong,voiceFrame, etc.) are excluded entirely from the gossip sync schedule. GossipSyncManager.swiftenforces these rules whileSyncResponseRateLimiter.swiftcaps responses at 8 per 30 seconds to prevent abuse.
Frequently Asked Questions
What message types does BitChat sync first?
BitChat always synchronizes announce and message types first, encoded as SyncTypeFlags.publicMessages. These bits are set in every REQUEST_SYNC packet regardless of bandwidth constraints because they carry essential public chat content.
How does BitChat prevent sync flooding attacks?
The SyncResponseRateLimiter class restricts each peer to answering the same sync request type no more than 8 times within any 30-second window. This rate limit applies per message type, preventing adversaries from exploiting high-priority flags to overwhelm the mesh.
Can older BitChat clients handle new message types in sync requests?
Yes. The SyncTypeFlags.decode() method in SyncTypeFlags.swift ignores unknown high bits, so legacy clients continue to sync the message types they recognize without failing when newer flags are present. This bit-mask approach preserves interoperability as the protocol evolves.
Why are file transfers deprioritized in the sync schedule?
fileTransfer (bit 7) is assigned priority level 5 because file payloads are large and would congest the mesh if synchronized alongside critical control traffic. The GossipSyncManager defers these transfers until higher-priority queues are cleared, ensuring real-time chat remains responsive.
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 →