@@ -63,6 +63,7 @@ import to.bitkit.di.BgDispatcher
6363import to.bitkit.env.Defaults
6464import to.bitkit.env.Env
6565import to.bitkit.ext.getSatsPerVByteFor
66+ import to.bitkit.ext.nowMillis
6667import to.bitkit.ext.nowTimestamp
6768import to.bitkit.ext.toPeerDetailsList
6869import to.bitkit.ext.totalNextOutboundHtlcLimitSats
@@ -101,6 +102,7 @@ import kotlin.time.Duration
101102import kotlin.time.Duration.Companion.milliseconds
102103import kotlin.time.Duration.Companion.minutes
103104import kotlin.time.Duration.Companion.seconds
105+ import kotlin.time.ExperimentalTime
104106
105107@Singleton
106108@Suppress(" LongParameterList" , " TooManyFunctions" , " LargeClass" )
@@ -1622,9 +1624,49 @@ class LightningRepo @Inject constructor(
16221624 graphNodeCount = graph?.nodeCount,
16231625 graphChannelCount = graph?.channelCount,
16241626 latestRgsSyncTimestamp = graph?.latestRgsSyncTimestamp,
1627+ latestPathfindingScoresSyncTimestamp = state.nodeStatus?.latestPathfindingScoresSyncTimestamp,
16251628 syncHealthy = state.isSyncHealthy,
16261629 )
16271630 }
1631+
1632+ /* *
1633+ * Returns the device epoch seconds captured after the VSS deletes and before the node restart,
1634+ * so callers can require any scores sync timestamp to be strictly newer to prove a post-reset download.
1635+ */
1636+ @OptIn(ExperimentalTime ::class )
1637+ suspend fun resetPathfindingScores (walletIndex : Int = 0): Result <Long > = withContext(bgDispatcher) {
1638+ Logger .info(" Resetting pathfinding scores" , context = TAG )
1639+
1640+ waitForNodeToStop().onFailure { return @withContext Result .failure(it) }
1641+ stop().onFailure {
1642+ Logger .error(" Failed to stop node during pathfinding scores reset" , it, context = TAG )
1643+ return @withContext Result .failure(it)
1644+ }
1645+
1646+ runCatching {
1647+ val lifecycleState = _lightningState .value.nodeLifecycleState
1648+ check(lifecycleState == NodeLifecycleState .Stopped ) {
1649+ " Node lifecycle changed to '$lifecycleState ' during pathfinding scores reset"
1650+ }
1651+ vssBackupClientLdk.setup(walletIndex).getOrThrow()
1652+ vssBackupClientLdk.deleteObject(VSS_KEY_SCORER ).getOrThrow()
1653+ vssBackupClientLdk.deleteObject(VSS_KEY_EXTERNAL_SCORES_CACHE ).getOrThrow()
1654+ }.onFailure {
1655+ Logger .error(" Failed to delete pathfinding scores from VSS" , it, context = TAG )
1656+ start(walletIndex = walletIndex, shouldRetry = false ).onFailure { startError ->
1657+ Logger .error(" Failed to restart node after pathfinding scores reset failure" , startError, context = TAG )
1658+ }
1659+ return @withContext Result .failure(it)
1660+ }
1661+
1662+ val resetAtSecs = nowMillis() / 1000
1663+
1664+ start(walletIndex = walletIndex, shouldRetry = false )
1665+ .map { resetAtSecs }
1666+ .onSuccess {
1667+ Logger .info(" Pathfinding scores reset at '$resetAtSecs '" , context = TAG )
1668+ }
1669+ }
16281670 // endregion
16291671
16301672 suspend fun restartNode (): Result <Unit > = withContext(bgDispatcher) {
@@ -1644,6 +1686,8 @@ class LightningRepo @Inject constructor(
16441686 companion object {
16451687 private const val TAG = " LightningRepo"
16461688 private const val LENGTH_CHANNEL_ID_PREVIEW = 10
1689+ private const val VSS_KEY_SCORER = " scorer"
1690+ private const val VSS_KEY_EXTERNAL_SCORES_CACHE = " external_pathfinding_scores_cache"
16471691 private const val MS_SYNC_LOOP_DEBOUNCE = 500L
16481692 private const val SYNC_RETRY_DELAY_MS = 15_000L
16491693 private val CHANNELS_USABLE_TIMEOUT = 15 .seconds
@@ -1720,6 +1764,7 @@ data class ProbeReadiness(
17201764 val graphNodeCount : Int? ,
17211765 val graphChannelCount : Int? ,
17221766 val latestRgsSyncTimestamp : ULong? ,
1767+ val latestPathfindingScoresSyncTimestamp : ULong? ,
17231768 val syncHealthy : Boolean ,
17241769) {
17251770 val ready: Boolean
0 commit comments