Skip to content

Commit d4f17e5

Browse files
committed
feat: add LDK debug action to export pathfinding scores
Mirrors the existing network-graph export pattern: a new "Export Scorer" button under a PATHFINDING SCORER section in LDK Debug calls node.exportPathfindingScores(), writes the bytes to cacheDir/exports, and triggers the Android share sheet via FileProvider so the file can be moved off-device for inspection (e.g. with the scorer-inspect CLI in synonymdev/ldk-node). Also nulls the regtest ldkScorerUrl. The regtest endpoint serves a 5-byte minimal payload, so the only effect of pointing the node at it is a no-op merge; setting it to null makes "we don't use the scorer on regtest" explicit.
1 parent 15c51a7 commit d4f17e5

6 files changed

Lines changed: 75 additions & 1 deletion

File tree

app/src/main/java/to/bitkit/env/Env.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ internal object Env {
7676
val ldkScorerUrl
7777
get() = when (network) {
7878
Network.BITCOIN -> "https://api.blocktank.to/scorer-prod"
79-
Network.REGTEST -> "https://api.stag0.blocktank.to/scorer"
8079
else -> null
8180
}
8281

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,11 @@ class LightningRepo @Inject constructor(
13601360
executeWhenNodeRunning("exportNetworkGraphToFile") {
13611361
lightningService.exportNetworkGraphToFile(outputDir)
13621362
}
1363+
1364+
suspend fun exportPathfindingScoresToFile(outputDir: String): Result<File> =
1365+
executeWhenNodeRunning("exportPathfindingScoresToFile") {
1366+
lightningService.exportPathfindingScoresToFile(outputDir)
1367+
}
13631368
// endregion
13641369

13651370
// region probing

app/src/main/java/to/bitkit/services/LightningService.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,14 @@ class LightningService @Inject constructor(
10501050
return loggerLdk.exportNetworkGraphToFile(node, outputDir, fileName)
10511051
}
10521052

1053+
suspend fun exportPathfindingScoresToFile(
1054+
outputDir: String,
1055+
fileName: String = "pathfinding_scores.bin",
1056+
): Result<File> {
1057+
val node = this.node ?: return Result.failure(ServiceError.NodeNotSetup())
1058+
return loggerLdk.exportPathfindingScoresToFile(node, outputDir, fileName)
1059+
}
1060+
10531061
// endregion
10541062
}
10551063

app/src/main/java/to/bitkit/ui/screens/settings/LdkDebugScreen.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ fun LdkDebugScreen(
5757
onPasteAndAddPeer = viewModel::pasteAndAddPeer,
5858
onLogNetworkGraphInfo = viewModel::logNetworkGraphInfo,
5959
onExportNetworkGraph = viewModel::exportNetworkGraph,
60+
onExportScorer = viewModel::exportScorer,
6061
onRestartNode = viewModel::restartNode,
6162
)
6263
}
@@ -70,6 +71,7 @@ private fun LdkDebugContent(
7071
onPasteAndAddPeer: () -> Unit,
7172
onLogNetworkGraphInfo: () -> Unit,
7273
onExportNetworkGraph: (onFileReady: (File) -> Unit) -> Unit,
74+
onExportScorer: (onFileReady: (File) -> Unit) -> Unit,
7375
onRestartNode: () -> Unit,
7476
) {
7577
val context = LocalContext.current
@@ -143,6 +145,20 @@ private fun LdkDebugContent(
143145
},
144146
)
145147

148+
SectionHeader("PATHFINDING SCORER")
149+
SettingsTextButtonRow(
150+
title = "Export Scorer",
151+
iconRes = R.drawable.ic_share,
152+
iconSize = 24.dp,
153+
enabled = !uiState.isLoading,
154+
onClick = {
155+
onExportScorer { file ->
156+
val uri = FileProvider.getUriForFile(context, Env.FILE_PROVIDER_AUTHORITY, file)
157+
context.shareFile(uri, "application/octet-stream")
158+
}
159+
},
160+
)
161+
146162
SectionHeader("NODE")
147163
SettingsTextButtonRow(
148164
title = "Restart",
@@ -171,6 +187,7 @@ private fun Preview() {
171187
onPasteAndAddPeer = {},
172188
onLogNetworkGraphInfo = {},
173189
onExportNetworkGraph = {},
190+
onExportScorer = {},
174191
onRestartNode = {},
175192
)
176193
}

app/src/main/java/to/bitkit/utils/LoggerLdk.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,25 @@ class LoggerLdk @Inject constructor(
191191
Logger.error("Failed to export network graph to file", it, context = TAG)
192192
}
193193
}
194+
195+
suspend fun exportPathfindingScoresToFile(
196+
node: Node,
197+
outputDir: String,
198+
fileName: String = "pathfinding_scores.bin",
199+
): Result<File> = withContext(ioDispatcher) {
200+
runCatching {
201+
val bytes = node.exportPathfindingScores()
202+
val outputFile = File(outputDir, fileName)
203+
outputFile.writeBytes(bytes)
204+
Logger.info(
205+
"Exported pathfinding scores '${bytes.size}' bytes to '${outputFile.absolutePath}'",
206+
context = TAG,
207+
)
208+
outputFile
209+
}.onFailure {
210+
Logger.error("Failed to export pathfinding scores to file", it, context = TAG)
211+
}
212+
}
194213
}
195214

196215
class LdkLogWriter(

app/src/main/java/to/bitkit/viewmodels/LdkDebugViewModel.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,32 @@ class LdkDebugViewModel @Inject constructor(
155155
}
156156
}
157157

158+
fun exportScorer(onFileReady: (File) -> Unit) {
159+
viewModelScope.launch(bgDispatcher) {
160+
_uiState.update { it.copy(isLoading = true) }
161+
val outputDir = File(context.cacheDir, DIR_EXPORTS).apply { mkdirs() }.absolutePath
162+
lightningRepo.exportPathfindingScoresToFile(outputDir).onSuccess { file ->
163+
Logger.info(
164+
"Pathfinding scores exported to '${file.absolutePath}' (${file.length()} bytes)",
165+
context = TAG,
166+
)
167+
ToastEventBus.send(
168+
type = Toast.ToastType.INFO,
169+
title = "Scorer exported (${file.length()} bytes)",
170+
)
171+
onFileReady(file)
172+
}.onFailure { e ->
173+
Logger.error("Failed to export pathfinding scores", e, context = TAG)
174+
ToastEventBus.send(
175+
type = Toast.ToastType.ERROR,
176+
title = "Failed to export scorer",
177+
description = e.message,
178+
)
179+
}
180+
_uiState.update { it.copy(isLoading = false) }
181+
}
182+
}
183+
158184
fun restartNode() {
159185
viewModelScope.launch(bgDispatcher) {
160186
_uiState.update { it.copy(isLoading = true) }

0 commit comments

Comments
 (0)