Files
bitchat/bitchatTests/Services/BLESourceRouteOriginationPolicyTests.swift
T
jackandClaude Fable 5 18dcc747d7 Originate v2 source routes and wire fragmentIdFilter targeted resync
Part A — source-route origination policy:
- Gate route application (BLESourceRouteOriginationPolicy): only packets we
  author, directed at a single peer, with TTL headroom, whose recipient is
  not directly connected. Relays no longer attach routes to (and re-sign)
  packets they merely forward.
- Version-gate paths: MeshTopologyTracker records the highest protocol
  version observed per peer; BFS routes require every intermediate hop and
  the recipient to be v2-observed, capped at 4 intermediate hops.
- Degrade on failure: BLESourceRouteFailureCache marks a routed send that
  sees no inbound traffic from the recipient within 10s as failed and floods
  for 60s before retrying routes.

Part B — REQUEST_SYNC fragmentIdFilter (TLV 0x06):
- Requester: BLEFragmentAssemblyBuffer reports stalled broadcast
  reassemblies (no new fragment for 5s, retried at most every 10s); the
  maintenance pass sends a types=fragment REQUEST_SYNC naming the stalled
  8-byte fragment stream IDs to each connected peer.
- Responder: GossipSyncManager restricts the fragment diff to exactly the
  named streams, bypassing the since-cursor while the GCS filter still
  excludes pieces the requester holds; RSR/TTL-0/rate-limit semantics
  unchanged and REQUEST_SYNC stays link-local.
- Bounds: at most 60 IDs per request (60*17-1 = 1019 bytes <= the 1024-byte
  decoder cap); oversized 0x06 values are ignored, not fatal.

Docs: SOURCE_ROUTING.md gains the iOS origination policy (§8);
REQUEST_SYNC_MANAGER.md documents 0x05/0x06 as implemented.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 20:02:12 +02:00

99 lines
3.2 KiB
Swift

//
// BLESourceRouteOriginationPolicyTests.swift
// bitchatTests
//
// This is free and unencumbered software released into the public domain.
// For more information, see <https://unlicense.org>
//
import Testing
import Foundation
import BitFoundation
@testable import bitchat
struct BLESourceRouteOriginationPolicyTests {
private let localPeerIDData = Data(hexString: "0102030405060708")!
private let recipient = PeerID(str: "1112131415161718")
private let hop = Data(hexString: "2122232425262728")!
private func makePacket(
senderID: Data? = nil,
recipientID: Data? = Data(hexString: "1112131415161718"),
ttl: UInt8 = 7
) -> BitchatPacket {
BitchatPacket(
type: MessageType.noiseEncrypted.rawValue,
senderID: senderID ?? localPeerIDData,
recipientID: recipientID,
timestamp: UInt64(Date().timeIntervalSince1970 * 1000),
payload: Data([0x01]),
signature: nil,
ttl: ttl
)
}
private func route(
packet: BitchatPacket,
isRecipientConnected: Bool = false,
shouldAttemptRoute: Bool = true,
computedRoute: [Data]? = nil
) -> [Data]? {
BLESourceRouteOriginationPolicy.route(
for: packet,
to: recipient,
localPeerIDData: localPeerIDData,
isRecipientConnected: { _ in isRecipientConnected },
shouldAttemptRoute: { _ in shouldAttemptRoute },
computeRoute: { _ in computedRoute ?? [self.hop] }
)
}
@Test func routesWhenAllGatesPass() {
#expect(route(packet: makePacket()) == [hop])
}
@Test func relayedPacketNeverGetsRoute() {
let relayed = makePacket(senderID: Data(hexString: "aabbccddeeff0011"))
#expect(route(packet: relayed) == nil)
}
@Test func broadcastRecipientNeverGetsRoute() {
let broadcast = makePacket(recipientID: Data(repeating: 0xFF, count: 8))
#expect(route(packet: broadcast) == nil)
let noRecipient = makePacket(recipientID: nil)
#expect(route(packet: noRecipient) == nil)
}
@Test func linkLocalTTLNeverGetsRoute() {
// TTL 0/1 packets (e.g. REQUEST_SYNC) cannot traverse hops.
#expect(route(packet: makePacket(ttl: 0)) == nil)
#expect(route(packet: makePacket(ttl: 1)) == nil)
}
@Test func directlyConnectedRecipientNeverGetsRoute() {
#expect(route(packet: makePacket(), isRecipientConnected: true) == nil)
}
@Test func suppressedRecipientFallsBackToFlood() {
#expect(route(packet: makePacket(), shouldAttemptRoute: false) == nil)
}
@Test func missingOrEmptyRouteFallsBackToFlood() {
var sawComputeRoute = false
let result = BLESourceRouteOriginationPolicy.route(
for: makePacket(),
to: recipient,
localPeerIDData: localPeerIDData,
isRecipientConnected: { _ in false },
shouldAttemptRoute: { _ in true },
computeRoute: { _ in
sawComputeRoute = true
return nil
}
)
#expect(result == nil)
#expect(sawComputeRoute)
#expect(route(packet: makePacket(), computedRoute: []) == nil)
}
}