Skip to content

Commit dde3f71

Browse files
committed
fix: handle missing mnemonic during VSS backup setup
1 parent 3a4994e commit dde3f71

2 files changed

Lines changed: 46 additions & 5 deletions

File tree

app/src/main/java/to/bitkit/data/backup/VssBackupClient.kt

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import to.bitkit.data.keychain.Keychain
1616
import to.bitkit.di.IoDispatcher
1717
import to.bitkit.env.Env
1818
import to.bitkit.utils.Logger
19-
import to.bitkit.utils.ServiceError
2019
import javax.inject.Inject
2120
import javax.inject.Singleton
2221
import kotlin.time.Duration.Companion.seconds
@@ -29,7 +28,23 @@ class VssBackupClient @Inject constructor(
2928
) {
3029
private var isSetup = CompletableDeferred<Unit>()
3130

32-
suspend fun setup(walletIndex: Int = 0) = withContext(ioDispatcher) {
31+
/**
32+
* Sets up the VSS client. Returns true if setup succeeded, false if mnemonic not available.
33+
* Throws on other errors.
34+
*/
35+
suspend fun setup(walletIndex: Int = 0): Boolean = withContext(ioDispatcher) {
36+
// If already set up successfully, return immediately
37+
if (isSetup.isCompleted && !isSetup.isCancelled) {
38+
runCatching { isSetup.await() }.onSuccess { return@withContext true }
39+
}
40+
41+
// Check if mnemonic is available before proceeding
42+
val mnemonic = keychain.loadString(Keychain.Key.BIP39_MNEMONIC.name)
43+
if (mnemonic == null) {
44+
Logger.warn("VSS client setup deferred: mnemonic not available yet", context = TAG)
45+
return@withContext false
46+
}
47+
3348
runCatching {
3449
withTimeout(30.seconds) {
3550
Logger.debug("VSS client setting up…", context = TAG)
@@ -39,8 +54,6 @@ class VssBackupClient @Inject constructor(
3954
Logger.verbose("Building VSS client with vssUrl: '$vssUrl'", context = TAG)
4055
Logger.verbose("Building VSS client with lnurlAuthServerUrl: '$lnurlAuthServerUrl'", context = TAG)
4156
if (lnurlAuthServerUrl.isNotEmpty()) {
42-
val mnemonic = keychain.loadString(Keychain.Key.BIP39_MNEMONIC.name)
43-
?: throw ServiceError.MnemonicNotFound()
4457
val passphrase = keychain.loadString(Keychain.Key.BIP39_PASSPHRASE.name)
4558

4659
vssNewClientWithLnurlAuth(
@@ -63,6 +76,7 @@ class VssBackupClient @Inject constructor(
6376
isSetup.completeExceptionally(it)
6477
Logger.error("VSS client setup error", e = it, context = TAG)
6578
}
79+
true
6680
}
6781

6882
fun reset() {

app/src/main/java/to/bitkit/repositories/BackupRepo.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class BackupRepo @Inject constructor(
120120
isObserving = true
121121
Logger.debug("Start observing backup statuses and data store changes", context = TAG)
122122

123-
scope.launch { vssBackupClient.setup() }
123+
scope.launch { setupVssClientWithRetry() }
124124

125125
scope.launch {
126126
BackupCategory.entries.forEach { category ->
@@ -166,6 +166,33 @@ class BackupRepo @Inject constructor(
166166
Logger.debug("Stopped observing backup statuses and data store changes", context = TAG)
167167
}
168168

169+
private suspend fun setupVssClientWithRetry() {
170+
var attempt = 0
171+
val maxAttempts = 10
172+
val baseDelayMs = 1000L
173+
174+
while (attempt < maxAttempts && isObserving) {
175+
val success = runCatching { vssBackupClient.setup() }.getOrDefault(false)
176+
if (success) {
177+
Logger.debug("VSS client setup succeeded on attempt ${attempt + 1}", context = TAG)
178+
return
179+
}
180+
attempt++
181+
if (attempt < maxAttempts) {
182+
val delayMs = baseDelayMs * attempt // Linear backoff: 1s, 2s, 3s, ...
183+
Logger.debug(
184+
"VSS client setup deferred, retrying in ${delayMs}ms (attempt $attempt/$maxAttempts)",
185+
context = TAG,
186+
)
187+
delay(delayMs)
188+
}
189+
}
190+
191+
if (isObserving) {
192+
Logger.warn("VSS client setup failed after $maxAttempts attempts", context = TAG)
193+
}
194+
}
195+
169196
private fun startBackupStatusObservers() {
170197
// Observe backup status changes for each category
171198
BackupCategory.entries.forEach { category ->

0 commit comments

Comments
 (0)