mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-26 21:45:22 +00:00
Make ordinary Noise reconnects atomic and race-safe (#1463)
Replaces destroy-then-rebuild Noise re-handshakes with an atomic reconnect protocol: prepared XX message-1 handoff tokens (claim-once, invalidated by crossed inbound initiations), receive-only quarantine of the established transport while an inbound replacement proves identity (promote on success, rollback+cooldown on failure/timeout), deterministic lower-peerID-wins crossed-initiator resolution, and a per-link-epoch BLE revalidation policy that re-proves cached sessions inside the same bleQueue critical section as the link rebind. On main, a fresh msg1 simply destroys an established session and rekey spans two non-atomic barriers. Includes the review fix: timeout-restores defer outbound queue draining until the convergence retry completes (restore reason plumbed end-to-end), so DMs are never drained under keys a restarted peer already discarded — with a deterministic interleaving test. Identity-mismatch restores drain immediately. Full local suite 1768 tests green.
This commit is contained in:
@@ -12,6 +12,7 @@ import Testing
|
||||
@testable import BitFoundation // to avoid unnecessary public's
|
||||
@testable import bitchat
|
||||
|
||||
@Suite("Integration Tests", .serialized)
|
||||
struct IntegrationTests {
|
||||
|
||||
private var helper = TestNetworkHelper()
|
||||
@@ -272,8 +273,18 @@ struct IntegrationTests {
|
||||
// Re-establish Noise handshake explicitly via managers
|
||||
do {
|
||||
let m1 = try helper.noiseManagers["Bob"]!.initiateHandshake(with: helper.nodes["Alice"]!.peerID)
|
||||
let m2 = try helper.noiseManagers["Alice"]!.handleIncomingHandshake(from: helper.nodes["Bob"]!.peerID, message: m1)!
|
||||
let m3 = try helper.noiseManagers["Bob"]!.handleIncomingHandshake(from: helper.nodes["Alice"]!.peerID, message: m2)!
|
||||
let m2 = try #require(
|
||||
try helper.noiseManagers["Alice"]!.handleIncomingHandshake(
|
||||
from: helper.nodes["Bob"]!.peerID,
|
||||
message: m1
|
||||
)
|
||||
)
|
||||
let m3 = try #require(
|
||||
try helper.noiseManagers["Bob"]!.handleIncomingHandshake(
|
||||
from: helper.nodes["Alice"]!.peerID,
|
||||
message: m2
|
||||
)
|
||||
)
|
||||
_ = try helper.noiseManagers["Alice"]!.handleIncomingHandshake(from: helper.nodes["Bob"]!.peerID, message: m3)
|
||||
} catch {
|
||||
Issue.record("Failed to re-establish Noise session after restart: \(error)")
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
import Testing
|
||||
@testable import BitFoundation // to avoid unnecessary public's
|
||||
@testable import bitchat
|
||||
|
||||
@@ -27,9 +28,14 @@ final class TestNetworkHelper {
|
||||
node.mockNickname = name
|
||||
nodes[name] = node
|
||||
|
||||
// Create/replace Noise manager for this node
|
||||
// This synchronous helper directly drives all three XX messages and
|
||||
// has no transport callback loop for delayed collision recovery.
|
||||
let key = Curve25519.KeyAgreement.PrivateKey()
|
||||
noiseManagers[name] = NoiseSessionManager(localStaticKey: key, keychain: mockKeychain)
|
||||
noiseManagers[name] = NoiseSessionManager(
|
||||
localStaticKey: key,
|
||||
keychain: mockKeychain,
|
||||
recentInitiatorCompletionGracePeriod: 0
|
||||
)
|
||||
return node
|
||||
}
|
||||
|
||||
@@ -108,8 +114,18 @@ final class TestNetworkHelper {
|
||||
let peer2ID = nodes[node2]?.peerID else { return }
|
||||
|
||||
let msg1 = try manager1.initiateHandshake(with: peer2ID)
|
||||
let msg2 = try manager2.handleIncomingHandshake(from: peer1ID, message: msg1)!
|
||||
let msg3 = try manager1.handleIncomingHandshake(from: peer2ID, message: msg2)!
|
||||
let msg2 = try #require(
|
||||
try manager2.handleIncomingHandshake(
|
||||
from: peer1ID,
|
||||
message: msg1
|
||||
)
|
||||
)
|
||||
let msg3 = try #require(
|
||||
try manager1.handleIncomingHandshake(
|
||||
from: peer2ID,
|
||||
message: msg2
|
||||
)
|
||||
)
|
||||
_ = try manager2.handleIncomingHandshake(from: peer1ID, message: msg3)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user