@@ -61,6 +61,7 @@ import to.bitkit.di.BgDispatcher
6161import to.bitkit.env.Defaults
6262import to.bitkit.env.Env
6363import to.bitkit.ext.getSatsPerVByteFor
64+ import to.bitkit.ext.nowMillis
6465import to.bitkit.ext.nowTimestamp
6566import to.bitkit.ext.toPeerDetailsList
6667import to.bitkit.ext.totalNextOutboundHtlcLimitSats
@@ -99,6 +100,7 @@ import kotlin.time.Duration
99100import kotlin.time.Duration.Companion.milliseconds
100101import kotlin.time.Duration.Companion.minutes
101102import kotlin.time.Duration.Companion.seconds
103+ import kotlin.time.ExperimentalTime
102104
103105@Singleton
104106@Suppress(" LongParameterList" , " TooManyFunctions" , " LargeClass" )
@@ -1620,9 +1622,49 @@ class LightningRepo @Inject constructor(
16201622 graphNodeCount = graph?.nodeCount,
16211623 graphChannelCount = graph?.channelCount,
16221624 latestRgsSyncTimestamp = graph?.latestRgsSyncTimestamp,
1625+ latestPathfindingScoresSyncTimestamp = state.nodeStatus?.latestPathfindingScoresSyncTimestamp,
16231626 syncHealthy = state.isSyncHealthy,
16241627 )
16251628 }
1629+
1630+ /* *
1631+ * Returns the device epoch seconds captured after the VSS deletes and before the node restart,
1632+ * so callers can require any scores sync timestamp to be strictly newer to prove a post-reset download.
1633+ */
1634+ @OptIn(ExperimentalTime ::class )
1635+ suspend fun resetPathfindingScores (walletIndex : Int = 0): Result <Long > = withContext(bgDispatcher) {
1636+ Logger .info(" Resetting pathfinding scores" , context = TAG )
1637+
1638+ waitForNodeToStop().onFailure { return @withContext Result .failure(it) }
1639+ stop().onFailure {
1640+ Logger .error(" Failed to stop node during pathfinding scores reset" , it, context = TAG )
1641+ return @withContext Result .failure(it)
1642+ }
1643+
1644+ runCatching {
1645+ val lifecycleState = _lightningState .value.nodeLifecycleState
1646+ check(lifecycleState == NodeLifecycleState .Stopped ) {
1647+ " Node lifecycle changed to '$lifecycleState ' during pathfinding scores reset"
1648+ }
1649+ vssBackupClientLdk.setup(walletIndex).getOrThrow()
1650+ vssBackupClientLdk.deleteObject(VSS_KEY_SCORER ).getOrThrow()
1651+ vssBackupClientLdk.deleteObject(VSS_KEY_EXTERNAL_SCORES_CACHE ).getOrThrow()
1652+ }.onFailure {
1653+ Logger .error(" Failed to delete pathfinding scores from VSS" , it, context = TAG )
1654+ start(walletIndex = walletIndex, shouldRetry = false ).onFailure { startError ->
1655+ Logger .error(" Failed to restart node after pathfinding scores reset failure" , startError, context = TAG )
1656+ }
1657+ return @withContext Result .failure(it)
1658+ }
1659+
1660+ val resetAtSecs = nowMillis() / 1000
1661+
1662+ start(walletIndex = walletIndex, shouldRetry = false )
1663+ .map { resetAtSecs }
1664+ .onSuccess {
1665+ Logger .info(" Pathfinding scores reset at '$resetAtSecs '" , context = TAG )
1666+ }
1667+ }
16261668 // endregion
16271669
16281670 suspend fun restartNode (): Result <Unit > = withContext(bgDispatcher) {
@@ -1642,6 +1684,8 @@ class LightningRepo @Inject constructor(
16421684 companion object {
16431685 private const val TAG = " LightningRepo"
16441686 private const val LENGTH_CHANNEL_ID_PREVIEW = 10
1687+ private const val VSS_KEY_SCORER = " scorer"
1688+ private const val VSS_KEY_EXTERNAL_SCORES_CACHE = " external_pathfinding_scores_cache"
16451689 private const val MS_SYNC_LOOP_DEBOUNCE = 500L
16461690 private const val SYNC_RETRY_DELAY_MS = 15_000L
16471691 private val CHANNELS_USABLE_TIMEOUT = 15 .seconds
@@ -1702,6 +1746,7 @@ data class ProbeReadiness(
17021746 val graphNodeCount : Int? ,
17031747 val graphChannelCount : Int? ,
17041748 val latestRgsSyncTimestamp : ULong? ,
1749+ val latestPathfindingScoresSyncTimestamp : ULong? ,
17051750 val syncHealthy : Boolean ,
17061751) {
17071752 val ready: Boolean
0 commit comments