Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Bitkit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -893,7 +893,7 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/synonymdev/vss-rust-client-ffi";
requirement = {
branch = "master";
branch = master;
kind = branch;
};
};
Expand Down Expand Up @@ -925,8 +925,8 @@
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/synonymdev/ldk-node";
requirement = {
branch = main;
kind = branch;
kind = revision;
revision = d2a82a2d111e5eb84a0eec02f4754e39fea4189a;
};
};
96DEA0382DE8BBA1009932BF /* XCRemoteSwiftPackageReference "bitkit-core" */ = {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Bitkit/Constants/Env.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ enum Env {
return [
.init(nodeId: "039b8b4dd1d88c2c5db374290cda397a8f5d79f312d6ea5d5bfdfc7c6ff363eae3", host: "34.65.111.104", port: 9735),
.init(nodeId: "03816141f1dce7782ec32b66a300783b1d436b19777e7c686ed00115bd4b88ff4b", host: "34.65.191.64", port: 9735),
.init(nodeId: "02a371038863605300d0b3fc9de0cf5ccb57728b7f8906535709a831b16e311187", host: "34.65.186.40", port: 9735),
.init(nodeId: "02a371038863605300d0b3fc9de0cf5ccb57728b7f8906535709a831b16e311187", host: "34.65.153.174", port: 9735),
]
case .signet:
return []
Expand Down
45 changes: 43 additions & 2 deletions Bitkit/Services/LightningService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -306,20 +306,61 @@
Logger.info("Deleted network graph cache at: \(graphPath.path)")
}

func connectToTrustedPeers() async throws {
func connectToTrustedPeers(remotePeers: [LnPeer]? = nil) async throws {
guard let node else {
throw AppError(serviceError: .nodeNotSetup)
}

let peers: [LnPeer]
let usingRemotePeers: Bool
if let remotePeers, !remotePeers.isEmpty {
Logger.info("Using \(remotePeers.count) trusted peers from Blocktank API")
peers = remotePeers
usingRemotePeers = true
} else {
Logger.warn("No remote peers available, falling back to preconfigured env peers")
peers = Env.trustedLnPeers
usingRemotePeers = false
}

try await ServiceQueue.background(.ldk) {
for peer in Env.trustedLnPeers {
for peer in peers {
do {
try node.connect(nodeId: peer.nodeId, address: peer.address, persist: true)
Logger.info("Connected to trusted peer: \(peer.nodeId)")
} catch {
Logger.error(error, context: "Peer: \(peer.nodeId)")
}
}

if usingRemotePeers {
self.verifyTrustedPeersOrFallback(node: node, trustedPeers: peers)
}
}
}

private func verifyTrustedPeersOrFallback(node: Node, trustedPeers: [LnPeer]) {
let connectedPeerIds = Set(node.listPeers().filter(\.isConnected).map(\.nodeId))
let trustedConnected = trustedPeers.filter { connectedPeerIds.contains($0.nodeId) }.count
let trustedPeerIds = Set(trustedPeers.map(\.nodeId))

if trustedConnected == 0, !trustedPeers.isEmpty {
let fallbackPeers = Env.trustedLnPeers.filter { !trustedPeerIds.contains($0.nodeId) }
if fallbackPeers.isEmpty {
Logger.warn("No trusted peers connected. All preconfigured env peers overlap with API peers (not retrying with stale addresses).")
} else {
Logger.warn("No trusted peers connected, trying \(fallbackPeers.count) preconfigured env peer(s) not in API list")
for peer in fallbackPeers {
do {
try node.connect(nodeId: peer.nodeId, address: peer.address, persist: true)
Logger.info("Connected to fallback peer: \(peer.nodeId)")
} catch {
Logger.error(error, context: "Fallback peer: \(peer.nodeId)")
}
}
}
} else {
Logger.info("Connected to \(trustedConnected)/\(trustedPeers.count) trusted peers")
}
}

Expand Down Expand Up @@ -541,7 +582,7 @@
}

func closeChannel(_ channel: ChannelDetails, force: Bool = false, forceCloseReason: String? = nil) async throws {
guard let node else {

Check warning on line 585 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

value 'node' was defined but never used; consider replacing with boolean test

Check warning on line 585 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

value 'node' was defined but never used; consider replacing with boolean test

Check warning on line 585 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

value 'node' was defined but never used; consider replacing with boolean test

Check warning on line 585 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

value 'node' was defined but never used; consider replacing with boolean test
throw AppError(serviceError: .nodeNotStarted)
}

Expand Down Expand Up @@ -916,7 +957,7 @@
onEvent?(event)

switch event {
case let .paymentSuccessful(paymentId, paymentHash, paymentPreimage, feePaidMsat):

Check warning on line 960 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'paymentPreimage' was never used; consider replacing with '_' or removing it
Logger.info("✅ Payment successful: paymentId: \(paymentId ?? "?") paymentHash: \(paymentHash) feePaidMsat: \(feePaidMsat ?? 0)")
Task {
let hash = paymentId ?? paymentHash
Expand All @@ -941,7 +982,7 @@
Logger.warn("No paymentId or paymentHash available for failed payment", context: "LightningService")
}
}
case let .paymentReceived(paymentId, paymentHash, amountMsat, feePaidMsat):

Check warning on line 985 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'feePaidMsat' was never used; consider replacing with '_' or removing it
Logger.info("🤑 Payment received: paymentId: \(paymentId ?? "?") paymentHash: \(paymentHash) amountMsat: \(amountMsat)")
Task {
let hash = paymentId ?? paymentHash
Expand All @@ -951,7 +992,7 @@
Logger.error("Failed to handle payment received for \(hash): \(error)", context: "LightningService")
}
}
case let .paymentClaimable(paymentId, paymentHash, claimableAmountMsat, claimDeadline, customRecords):

Check warning on line 995 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'customRecords' was never used; consider replacing with '_' or removing it

Check warning on line 995 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'claimDeadline' was never used; consider replacing with '_' or removing it
Logger.info(
"🫰 Payment claimable: paymentId: \(paymentId) paymentHash: \(paymentHash) claimableAmountMsat: \(claimableAmountMsat)"
)
Expand Down Expand Up @@ -980,7 +1021,7 @@

if let channel {
await registerClosedChannel(channel: channel, reason: reasonString)
await MainActor.run {

Check warning on line 1024 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

result of call to 'run(resultType:body:)' is unused

Check warning on line 1024 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

result of call to 'run(resultType:body:)' is unused

Check warning on line 1024 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Tests

result of call to 'run(resultType:body:)' is unused

Check warning on line 1024 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

result of call to 'run(resultType:body:)' is unused
channelCache.removeValue(forKey: channelIdString)
}
} else {
Expand All @@ -1003,7 +1044,7 @@
Logger.error("Failed to handle transaction received for \(txid): \(error)", context: "LightningService")
}
}
case let .onchainTransactionConfirmed(txid, blockHash, blockHeight, confirmationTime, details):

Check warning on line 1047 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'confirmationTime' was never used; consider replacing with '_' or removing it

Check warning on line 1047 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'blockHash' was never used; consider replacing with '_' or removing it
Logger.info("✅ Onchain transaction confirmed: txid=\(txid) blockHeight=\(blockHeight) amountSats=\(details.amountSats)")
Task {
do {
Expand Down Expand Up @@ -1057,7 +1098,7 @@

// MARK: Balance Events

case let .balanceChanged(oldSpendableOnchain, newSpendableOnchain, oldTotalOnchain, newTotalOnchain, oldLightning, newLightning):

Check warning on line 1101 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'newTotalOnchain' was never used; consider replacing with '_' or removing it

Check warning on line 1101 in Bitkit/Services/LightningService.swift

View workflow job for this annotation

GitHub Actions / Run Integration Tests

immutable value 'oldTotalOnchain' was never used; consider replacing with '_' or removing it
Logger
.info("💰 Balance changed: onchain=\(oldSpendableOnchain)->\(newSpendableOnchain) lightning=\(oldLightning)->\(newLightning)")

Expand Down
25 changes: 24 additions & 1 deletion Bitkit/ViewModels/WalletViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ class WalletViewModel: ObservableObject {
syncState()

do {
try await lightningService.connectToTrustedPeers()
let remotePeers = await fetchTrustedPeersFromBlocktank()
try await lightningService.connectToTrustedPeers(remotePeers: remotePeers)
} catch {
Logger.error("Failed to connect to trusted peers")
}
Expand All @@ -232,6 +233,28 @@ class WalletViewModel: ObservableObject {
}
}

private func fetchTrustedPeersFromBlocktank() async -> [LnPeer]? {
var info: IBtInfo?
do {
info = try await coreService.blocktank.info(refresh: true)
} catch {
Logger.warn("Blocktank API refresh failed, trying cache: \(error)")
}
if info == nil {
info = try? await coreService.blocktank.info(refresh: false)
}
guard let nodes = info?.nodes, !nodes.isEmpty else { return nil }
let peers = nodes.compactMap { node -> LnPeer? in
guard let connString = node.connectionStrings.first else { return nil }
let address = connString.contains("@") ? String(connString.split(separator: "@").last ?? "") : connString
let parts = address.split(separator: ":")
guard parts.count == 2, let port = UInt16(parts[1]) else { return nil }
return LnPeer(nodeId: node.pubkey, host: String(parts[0]), port: port)
}
Logger.info("Fetched \(peers.count) trusted peers from Blocktank API")
return peers.isEmpty ? nil : peers
}

func stopLightningNode(clearEventCallback: Bool = false) async throws {
nodeLifecycleState = .stopping
try await lightningService.stop(clearEventCallback: clearEventCallback)
Expand Down
Loading