Skip to content

feat: kyoto #315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 40 commits into from
Aug 14, 2025
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2a912c8
wip: working i think
reez Jul 31, 2025
8718349
fix(untested): show block height immediately
reez Aug 5, 2025
c967bd6
refactor: broadcast sync
reez Aug 5, 2025
381d36c
refactor: remove log parsing
reez Aug 5, 2025
6e4c2d0
Revert "refactor: remove log parsing"
reez Aug 5, 2025
4b7c354
`This does not throw`
reez Aug 6, 2025
99b85ae
`Why is this here`
reez Aug 6, 2025
08e6b12
use `Info::NewChainHeight`
reez Aug 6, 2025
3c4ed6f
Covered by `Info::SuccessfulHandshake`
reez Aug 6, 2025
b4db0ae
This is a warning condition `Warning::NeedConnections`
reez Aug 6, 2025
a97544c
set the progress to 20 percent after startup
reez Aug 6, 2025
2e251d4
fix: progress calculation
reez Aug 6, 2025
9f7ebfa
ui: progressview (bar) increase width
reez Aug 6, 2025
364c28d
misc: comment
reez Aug 7, 2025
de50f90
ui: hide fullscan button in settingsview (if kyoto)
reez Aug 7, 2025
92c4670
fix: auto-refresh wallet when new block height
reez Aug 7, 2025
e82c6cc
fix: block height font size once synced
reez Aug 7, 2025
c15e6e6
ui: always show latest height
reez Aug 7, 2025
b9d59e9
fix: kyoto could get into .notStarted state
reez Aug 7, 2025
20fb312
ui: dont show green checkmark for kyoto (already have connected green…
reez Aug 7, 2025
2fb7143
fix: restrict kyoto to signet
reez Aug 8, 2025
303aeb4
ui: load previous transaction state when app restart
reez Aug 11, 2025
2877b4b
fix: progress percent in walletviewmodel
reez Aug 11, 2025
b2be622
fix: client progress values are different
reez Aug 11, 2025
072c513
fix: network switch because of kyoto forced network signet
reez Aug 11, 2025
e8c9eb6
fix: regression from 2fb7143a203662386b6aa235579f26824ceb80f5
reez Aug 11, 2025
6673a1a
fix: make sure kyoto tasks killed when switching networks
reez Aug 11, 2025
6e7c631
fix: esplora percent progress
reez Aug 11, 2025
460da00
chore: temporary logging for kyoto due to not getting info from peer …
reez Aug 11, 2025
9062dc4
chore: more temp logging because not getting peer info today
reez Aug 11, 2025
19be079
chore: temp log making sure data dir is ok for peer info
reez Aug 11, 2025
466fa26
chore: temp logging nextlog
reez Aug 11, 2025
862f3f1
misc: remove onion
reez Aug 11, 2025
c1977a0
ui: show connected if progress or height
reez Aug 11, 2025
ada2f0a
fix: infrequent but persistent issue with ui state
reez Aug 14, 2025
9976389
fix: infrequent but persistent issue with ui state (part 2)
reez Aug 14, 2025
b85d9de
fix: block height not showing on sync sometimes for kyoto
reez Aug 14, 2025
e31d484
ui: fine tune connected state by adding gray state
reez Aug 14, 2025
286c39b
misc: remove print
reez Aug 14, 2025
bc35d67
format
reez Aug 14, 2025
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
4 changes: 4 additions & 0 deletions BDKSwiftExampleWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
AE4984832A1BBBD7009951E2 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AE4984822A1BBBD7009951E2 /* Preview Assets.xcassets */; };
AE49848D2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE49848C2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift */; };
AE4984A62A1BBCB8009951E2 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = AE4984A52A1BBCB8009951E2 /* README.md */; };
AE4D97572E3AFF2500E88A38 /* CbfClient+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE4D97562E3AFF2500E88A38 /* CbfClient+Extensions.swift */; };
AE6715FA2A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715F92A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift */; };
AE6715FD2A9AC056005C193F /* PriceServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715FC2A9AC056005C193F /* PriceServiceError.swift */; };
AE6715FF2A9AC066005C193F /* FeeServiceError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE6715FE2A9AC066005C193F /* FeeServiceError.swift */; };
Expand Down Expand Up @@ -163,6 +164,7 @@
AE4984882A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BDKSwiftExampleWalletTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
AE49848C2A1BBBD8009951E2 /* BDKSwiftExampleWalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BDKSwiftExampleWalletTests.swift; sourceTree = "<group>"; };
AE4984A52A1BBCB8009951E2 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
AE4D97562E3AFF2500E88A38 /* CbfClient+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CbfClient+Extensions.swift"; sourceTree = "<group>"; };
AE6474732CE559E000A270C6 /* BDKSwiftExampleWallet.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BDKSwiftExampleWallet.entitlements; sourceTree = "<group>"; };
AE6715F92A9A9220005C193F /* BDKSwiftExampleWalletPriceServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BDKSwiftExampleWalletPriceServiceTests.swift; sourceTree = "<group>"; };
AE6715FC2A9AC056005C193F /* PriceServiceError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PriceServiceError.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -572,6 +574,7 @@
isa = PBXGroup;
children = (
77EDA65A2E2A5B3800A5E3AD /* URL+Extensions.swift */,
AE4D97562E3AFF2500E88A38 /* CbfClient+Extensions.swift */,
AE97E74C2E315A8F000A407D /* AddressType+Extensions.swift */,
77F0FDC82DA9A93700B30E4F /* Persister+Extensions.swift */,
AEE6C74B2ABCB3E200442ADD /* Transaction+Extensions.swift */,
Expand Down Expand Up @@ -756,6 +759,7 @@
AE73239B2DF9C00F00D9BAE2 /* TxId+Extensions.swift in Sources */,
AE1390C72A7DB0AF0098127A /* KeyService.swift in Sources */,
AED4CC0A2A1D297600CE1831 /* BDKService.swift in Sources */,
AE4D97572E3AFF2500E88A38 /* CbfClient+Extensions.swift in Sources */,
AED4CC102A1D522100CE1831 /* WalletView.swift in Sources */,
AE7F67092A7451AA00CED561 /* Price.swift in Sources */,
AE184EFC2BFE52C800374362 /* Amount+Extensions.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
//
// CbfClient+Extensions.swift
// BDKSwiftExampleWallet
//
// Created by Matthew Ramsden on 7/30/25.
//

import BitcoinDevKit
import Foundation

extension CbfClient {
static func createComponents(wallet: Wallet) -> (client: CbfClient, node: CbfNode) {
do {
let components = try CbfBuilder()
.logLevel(logLevel: .debug)
.scanType(scanType: .sync)
.dataDir(dataDir: Constants.Config.Kyoto.dbPath)
.peers(peers: Constants.Networks.Signet.Regular.kyotoPeers)
.build(wallet: wallet)
Task {
do {
try await components.node.run()
} catch {
// Kyoto: Failed to start node
}
}

components.client.startBackgroundMonitoring()

return (client: components.client, node: components.node)
} catch {
fatalError("Failed to create CBF components: \(error)")
}
}

func startBackgroundMonitoring() {
Task {
var isConnected = false
while true {
if let log = try? await self.nextLog() {
// Parse specific sync stage messages
if log.contains("Attempting to load headers from the database") {
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoProgressUpdate"),
object: nil,
userInfo: ["progress": Float(0.2)]
)
}
} else if log.contains("]: headers") {
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoProgressUpdate"),
object: nil,
userInfo: ["progress": Float(0.4)]
)
}
} else if log.contains("Chain updated") {
let components = log.components(separatedBy: " ")
if components.count >= 4,
components[0] == "Chain" && components[1] == "updated",
let height = UInt32(components[2])
{
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoChainHeightUpdate"),
object: nil,
userInfo: ["height": height]
)
}
}

if !isConnected {
isConnected = true
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoConnectionUpdate"),
object: nil,
userInfo: ["connected": true]
)
}
}
}

if log.contains("Established an encrypted connection") && !isConnected {
isConnected = true
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoConnectionUpdate"),
object: nil,
userInfo: ["connected": true]
)
}
}

if log.contains("Need connections") && isConnected {
isConnected = false
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoConnectionUpdate"),
object: nil,
userInfo: ["connected": false]
)
}
}
}
try? await Task.sleep(nanoseconds: 100_000_000)
}
}

Task {
var hasEstablishedConnection = false
while true {
if let info = try? await self.nextInfo() {
switch info {
case let .progress(progress):
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoProgressUpdate"),
object: nil,
userInfo: ["progress": progress]
)
}
case let .newChainHeight(height):
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoChainHeightUpdate"),
object: nil,
userInfo: ["height": height]
)

if !hasEstablishedConnection {
hasEstablishedConnection = true
NotificationCenter.default.post(
name: NSNotification.Name("KyotoConnectionUpdate"),
object: nil,
userInfo: ["connected": true]
)
}
}
case .connectionsMet:
await MainActor.run {
hasEstablishedConnection = true
NotificationCenter.default.post(
name: NSNotification.Name("KyotoConnectionUpdate"),
object: nil,
userInfo: ["connected": true]
)
}
default:
break
}
}
}
}

Task {
while true {
if let warning = try? await self.nextWarning() {
switch warning {
case .needConnections:
await MainActor.run {
NotificationCenter.default.post(
name: NSNotification.Name("KyotoConnectionUpdate"),
object: nil,
userInfo: ["connected": false]
)
}
default:
break
}
}
}
}
}
}
15 changes: 15 additions & 0 deletions BDKSwiftExampleWallet/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,9 @@
}
}
}
},
"Block %u" : {

},
"Build Transaction Error" : {
"localizations" : {
Expand All @@ -483,6 +486,9 @@
}
}
}
},
"Client" : {

},
"Coldcard Verify Address" : {

Expand Down Expand Up @@ -623,6 +629,9 @@
}
}
}
},
"Esplora" : {

},
"Esplora Server" : {
"localizations" : {
Expand Down Expand Up @@ -733,6 +742,9 @@
}
}
}
},
"Kyoto" : {

},
"Navigation Title" : {
"extractionState" : "stale",
Expand Down Expand Up @@ -1049,6 +1061,9 @@
}
}
}
},
"Select Client Type" : {

},
"Select Fee" : {
"localizations" : {
Expand Down
Loading