mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-24 23:25:19 +00:00
Optimize BLE mesh network for robustness and range (#314)
- Fixed relay probability calculation for 2-node networks (0% relay needed) - Added protocol ACKs to prevent unnecessary retransmissions - Implemented MessageState for enhanced duplicate detection - Added exponential backoff for collision avoidance - Fixed duplicate sends for bidirectional connections - Resolved packet ID generation issues using immutable fields only - Implemented smart rate limiting with progressive throttling - Removed unnecessary debug logging and fixed build warnings - Optimized message routing to prevent flooding in small networks Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
@@ -19,11 +19,12 @@ extension Data {
|
||||
}
|
||||
|
||||
// Binary Protocol Format:
|
||||
// Header (Fixed 13 bytes):
|
||||
// Header (Fixed 17 bytes):
|
||||
// - Version: 1 byte
|
||||
// - Type: 1 byte
|
||||
// - TTL: 1 byte
|
||||
// - Timestamp: 8 bytes (UInt64)
|
||||
// - SequenceNumber: 4 bytes (UInt32)
|
||||
// - Flags: 1 byte (bit 0: hasRecipient, bit 1: hasSignature)
|
||||
// - PayloadLength: 2 bytes (UInt16)
|
||||
//
|
||||
@@ -34,7 +35,7 @@ extension Data {
|
||||
// - Signature: 64 bytes (if hasSignature flag set)
|
||||
|
||||
struct BinaryProtocol {
|
||||
static let headerSize = 13
|
||||
static let headerSize = 17
|
||||
static let senderIDSize = 8
|
||||
static let recipientIDSize = 8
|
||||
static let signatureSize = 64
|
||||
@@ -77,6 +78,11 @@ struct BinaryProtocol {
|
||||
data.append(UInt8((packet.timestamp >> (i * 8)) & 0xFF))
|
||||
}
|
||||
|
||||
// Sequence number (4 bytes, big-endian)
|
||||
for i in (0..<4).reversed() {
|
||||
data.append(UInt8((packet.sequenceNumber >> (i * 8)) & 0xFF))
|
||||
}
|
||||
|
||||
// Flags
|
||||
var flags: UInt8 = 0
|
||||
if packet.recipientID != nil {
|
||||
@@ -165,6 +171,13 @@ struct BinaryProtocol {
|
||||
}
|
||||
offset += 8
|
||||
|
||||
// Sequence number
|
||||
let sequenceData = unpaddedData[offset..<offset+4]
|
||||
let sequenceNumber = sequenceData.reduce(0) { result, byte in
|
||||
(result << 8) | UInt32(byte)
|
||||
}
|
||||
offset += 4
|
||||
|
||||
// Flags
|
||||
let flags = unpaddedData[offset]; offset += 1
|
||||
let hasRecipient = (flags & Flags.hasRecipient) != 0
|
||||
@@ -240,7 +253,8 @@ struct BinaryProtocol {
|
||||
timestamp: timestamp,
|
||||
payload: payload,
|
||||
signature: signature,
|
||||
ttl: ttl
|
||||
ttl: ttl,
|
||||
sequenceNumber: sequenceNumber
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,8 +139,9 @@ struct BitchatPacket: Codable {
|
||||
let payload: Data
|
||||
let signature: Data?
|
||||
var ttl: UInt8
|
||||
let sequenceNumber: UInt32 // New field for duplicate detection
|
||||
|
||||
init(type: UInt8, senderID: Data, recipientID: Data?, timestamp: UInt64, payload: Data, signature: Data?, ttl: UInt8) {
|
||||
init(type: UInt8, senderID: Data, recipientID: Data?, timestamp: UInt64, payload: Data, signature: Data?, ttl: UInt8, sequenceNumber: UInt32 = 0) {
|
||||
self.version = 1
|
||||
self.type = type
|
||||
self.senderID = senderID
|
||||
@@ -149,10 +150,11 @@ struct BitchatPacket: Codable {
|
||||
self.payload = payload
|
||||
self.signature = signature
|
||||
self.ttl = ttl
|
||||
self.sequenceNumber = sequenceNumber
|
||||
}
|
||||
|
||||
// Convenience initializer for new binary format
|
||||
init(type: UInt8, ttl: UInt8, senderID: String, payload: Data) {
|
||||
init(type: UInt8, ttl: UInt8, senderID: String, payload: Data, sequenceNumber: UInt32 = 0) {
|
||||
self.version = 1
|
||||
self.type = type
|
||||
// Convert hex string peer ID to binary data (8 bytes)
|
||||
@@ -171,6 +173,7 @@ struct BitchatPacket: Codable {
|
||||
self.payload = payload
|
||||
self.signature = nil
|
||||
self.ttl = ttl
|
||||
self.sequenceNumber = sequenceNumber
|
||||
}
|
||||
|
||||
var data: Data? {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -365,7 +365,8 @@ final class PrivateChatE2ETests: XCTestCase {
|
||||
timestamp: packet.timestamp,
|
||||
payload: encrypted,
|
||||
signature: packet.signature,
|
||||
ttl: packet.ttl
|
||||
ttl: packet.ttl,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
self.bob.simulateIncomingPacket(encryptedPacket)
|
||||
} catch {
|
||||
|
||||
@@ -122,7 +122,8 @@ final class PublicChatE2ETests: XCTestCase {
|
||||
timestamp: packet.timestamp,
|
||||
payload: relayPayload,
|
||||
signature: packet.signature,
|
||||
ttl: packet.ttl - 1
|
||||
ttl: packet.ttl - 1,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
|
||||
// Simulate relay to Charlie
|
||||
@@ -450,7 +451,8 @@ final class PublicChatE2ETests: XCTestCase {
|
||||
timestamp: packet.timestamp,
|
||||
payload: relayPayload,
|
||||
signature: packet.signature,
|
||||
ttl: packet.ttl - 1
|
||||
ttl: packet.ttl - 1,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
|
||||
// Relay to next hops
|
||||
|
||||
@@ -197,7 +197,8 @@ final class IntegrationTests: XCTestCase {
|
||||
timestamp: packet.timestamp,
|
||||
payload: encrypted,
|
||||
signature: packet.signature,
|
||||
ttl: packet.ttl
|
||||
ttl: packet.ttl,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
self.nodes["Bob"]!.simulateIncomingPacket(encPacket)
|
||||
}
|
||||
@@ -698,7 +699,8 @@ final class IntegrationTests: XCTestCase {
|
||||
timestamp: packet.timestamp,
|
||||
payload: encrypted,
|
||||
signature: packet.signature,
|
||||
ttl: packet.ttl
|
||||
ttl: packet.ttl,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
self.nodes["Bob"]!.simulateIncomingPacket(encPacket)
|
||||
}
|
||||
@@ -805,7 +807,8 @@ final class IntegrationTests: XCTestCase {
|
||||
timestamp: packet.timestamp,
|
||||
payload: relayPayload,
|
||||
signature: packet.signature,
|
||||
ttl: packet.ttl - 1
|
||||
ttl: packet.ttl - 1,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
|
||||
for hop in nextHops {
|
||||
|
||||
@@ -73,7 +73,8 @@ class MockBluetoothMeshService: BluetoothMeshService {
|
||||
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
|
||||
payload: payload,
|
||||
signature: nil,
|
||||
ttl: 3
|
||||
ttl: 3,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
|
||||
sentMessages.append((message, packet))
|
||||
@@ -111,7 +112,8 @@ class MockBluetoothMeshService: BluetoothMeshService {
|
||||
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
|
||||
payload: payload,
|
||||
signature: nil,
|
||||
ttl: 3
|
||||
ttl: 3,
|
||||
sequenceNumber: 1
|
||||
)
|
||||
|
||||
sentMessages.append((message, packet))
|
||||
|
||||
@@ -55,7 +55,8 @@ class TestHelpers {
|
||||
recipientID: String? = nil,
|
||||
payload: Data = "test payload".data(using: .utf8)!,
|
||||
signature: Data? = nil,
|
||||
ttl: UInt8 = 3
|
||||
ttl: UInt8 = 3,
|
||||
sequenceNumber: UInt32 = 1
|
||||
) -> BitchatPacket {
|
||||
return BitchatPacket(
|
||||
type: type,
|
||||
@@ -64,7 +65,8 @@ class TestHelpers {
|
||||
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
|
||||
payload: payload,
|
||||
signature: signature,
|
||||
ttl: ttl
|
||||
ttl: ttl,
|
||||
sequenceNumber: sequenceNumber
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user