@@ -92,6 +92,7 @@ class MigrationService @Inject constructor(
9292 private const val RN_PENDING_METADATA_KEY = " rnPendingMetadata"
9393 private const val RN_PENDING_TRANSFERS_KEY = " rnPendingTransfers"
9494 private const val RN_PENDING_BOOSTS_KEY = " rnPendingBoosts"
95+ private const val RN_DID_ATTEMPT_PEER_RECOVERY_KEY = " rnDidAttemptMigrationPeerRecovery"
9596 private const val OPENING_CURLY_BRACE = " {"
9697 private const val MMKV_ROOT = " persist:root"
9798 private const val RN_WALLET_NAME = " wallet0"
@@ -1253,6 +1254,44 @@ class MigrationService @Inject constructor(
12531254 Logger .info(" RN migration completed, marked for post-migration sync" , context = TAG )
12541255 }
12551256
1257+ private suspend fun isRnMigrationCompleted (): Boolean {
1258+ val key = stringPreferencesKey(RN_MIGRATION_COMPLETED_KEY )
1259+ return rnMigrationStore.data.first()[key] == " true"
1260+ }
1261+
1262+ private suspend fun didAttemptPeerRecovery (): Boolean {
1263+ val key = stringPreferencesKey(RN_DID_ATTEMPT_PEER_RECOVERY_KEY )
1264+ return rnMigrationStore.data.first()[key] == " true"
1265+ }
1266+
1267+ private suspend fun setDidAttemptPeerRecovery () {
1268+ val key = stringPreferencesKey(RN_DID_ATTEMPT_PEER_RECOVERY_KEY )
1269+ rnMigrationStore.edit { it[key] = " true" }
1270+ }
1271+
1272+ suspend fun tryFetchMigrationPeersFromBackup (): List <String > {
1273+ if (! isRnMigrationCompleted()) return emptyList()
1274+ if (didAttemptPeerRecovery()) return emptyList()
1275+
1276+ setDidAttemptPeerRecovery()
1277+
1278+ return runCatching {
1279+ val data = rnBackupClient.retrieve(" peers" , fileGroup = " ldk" ) ? : return emptyList()
1280+ val peers = json.decodeFromString<List <BackupPeerEntry >>(String (data))
1281+ if (peers.isEmpty()) return emptyList()
1282+
1283+ val trustedIds = Env .trustedLnPeers.map { it.nodeId }.toSet()
1284+ val uris = peers
1285+ .filter { it.pubKey !in trustedIds }
1286+ .map { " ${it.pubKey} @${it.address} :${it.port} " }
1287+
1288+ Logger .info(" Migration peer recovery: fetched ${uris.size} peer(s) from remote backup" , context = TAG )
1289+ uris
1290+ }.onFailure {
1291+ Logger .warn(" Migration peer recovery failed (will not retry)" , it, context = TAG )
1292+ }.getOrDefault(emptyList())
1293+ }
1294+
12561295 suspend fun cleanupAfterMigration () {
12571296 clearPersistedMigrationData()
12581297 setNeedsPostMigrationSync(false )
@@ -2120,6 +2159,13 @@ data class RNWidgetsWithOptions(
21202159 val widgetOptions : Map <String , ByteArray >,
21212160)
21222161
2162+ @Serializable
2163+ data class BackupPeerEntry (
2164+ val pubKey : String ,
2165+ val address : String ,
2166+ val port : UShort ,
2167+ )
2168+
21232169private val Context .rnMigrationDataStore: DataStore <Preferences > by preferencesDataStore(" rn_migration" )
21242170private val Context .rnKeychainDataStore: DataStore <Preferences > by preferencesDataStore(" RN_KEYCHAIN" )
21252171
0 commit comments