@@ -6,6 +6,7 @@ import android.net.Uri
66import android.os.Binder
77import android.os.Bundle
88import android.os.Process
9+ import android.os.SystemClock
910import androidx.core.os.bundleOf
1011import dagger.hilt.EntryPoint
1112import dagger.hilt.InstallIn
@@ -114,16 +115,19 @@ private sealed interface DevCommand {
114115 context = TAG ,
115116 )
116117
118+ val startedAt = SystemClock .elapsedRealtime()
117119 return deps.lightningRepo().sendProbeForInvoice(args.bolt11, amountSats)
118120 .fold(
119121 onSuccess = {
120122 deps.lightningRepo().waitForProbeOutcome(it.paymentIds, timeout)
121123 .fold(
122- onSuccess = { outcome -> outcome.toDevResult(it.paymentIds) },
123- onFailure = { error -> DevResult .ProbeFailure .from(error, it.paymentIds) },
124+ onSuccess = { outcome -> outcome.toDevResult(it.paymentIds, startedAt.durationMs()) },
125+ onFailure = { error ->
126+ DevResult .ProbeFailure .from(error, it.paymentIds, startedAt.durationMs())
127+ },
124128 )
125129 },
126- onFailure = { DevResult .ProbeFailure .from(it) },
130+ onFailure = { DevResult .ProbeFailure .from(it, durationMs = startedAt.durationMs() ) },
127131 )
128132 }
129133 }
@@ -153,16 +157,19 @@ private sealed interface DevCommand {
153157 context = TAG ,
154158 )
155159
160+ val startedAt = SystemClock .elapsedRealtime()
156161 return deps.lightningRepo().sendProbeForNode(args.nodeId, amountSats)
157162 .fold(
158163 onSuccess = {
159164 deps.lightningRepo().waitForProbeOutcome(it.paymentIds, timeout)
160165 .fold(
161- onSuccess = { outcome -> outcome.toDevResult(it.paymentIds) },
162- onFailure = { error -> DevResult .ProbeFailure .from(error, it.paymentIds) },
166+ onSuccess = { outcome -> outcome.toDevResult(it.paymentIds, startedAt.durationMs()) },
167+ onFailure = { error ->
168+ DevResult .ProbeFailure .from(error, it.paymentIds, startedAt.durationMs())
169+ },
163170 )
164171 },
165- onFailure = { DevResult .ProbeFailure .from(it) },
172+ onFailure = { DevResult .ProbeFailure .from(it, durationMs = startedAt.durationMs() ) },
166173 )
167174 }
168175 }
@@ -206,6 +213,8 @@ private sealed interface DevResult {
206213 val success : Boolean = true ,
207214 val paymentId : String ,
208215 val paymentHash : String ,
216+ val durationMs : Long ,
217+ val routeFeeMsat : ULong? ,
209218 val paymentIds : List <String >,
210219 ) : DevResult
211220
@@ -215,12 +224,19 @@ private sealed interface DevResult {
215224 val message : String? = null ,
216225 val paymentId : String? = null ,
217226 val paymentHash : String? = null ,
218- val shortChannelId : ULong? = null ,
227+ val shortChannelId : String? = null ,
228+ val durationMs : Long ,
229+ val routeFeeMsat : ULong? = null ,
219230 val paymentIds : List <String > = emptyList(),
220231 ) : DevResult {
221232 companion object {
222- fun from (error : Throwable , paymentIds : Set <String > = emptySet()) = ProbeFailure (
233+ fun from (
234+ error : Throwable ,
235+ paymentIds : Set <String > = emptySet(),
236+ durationMs : Long ,
237+ ) = ProbeFailure (
223238 message = error.message,
239+ durationMs = durationMs,
224240 paymentIds = paymentIds.toList(),
225241 )
226242 }
@@ -243,6 +259,7 @@ private sealed interface DevResult {
243259 val graphChannelCount : Int? = null ,
244260 val latestRgsSyncTimestamp : ULong? = null ,
245261 val latestPathfindingScoresSyncTimestamp : ULong? = null ,
262+ val probeRuntimeConfig : ProbeRuntimeConfig ,
246263 ) : DevResult {
247264 companion object {
248265 fun from (readiness : NodeProbeReadiness ) = ProbeReadiness (
@@ -261,29 +278,91 @@ private sealed interface DevResult {
261278 graphChannelCount = readiness.graphChannelCount,
262279 latestRgsSyncTimestamp = readiness.latestRgsSyncTimestamp,
263280 latestPathfindingScoresSyncTimestamp = readiness.latestPathfindingScoresSyncTimestamp,
281+ probeRuntimeConfig = ProbeRuntimeConfig .from(readiness.probeRuntimeConfig),
264282 )
265283 }
266284 }
267285
286+ @Serializable
287+ data class ProbeRuntimeConfig (
288+ val sampleAmountMsat : ULong ,
289+ val route : ProbeRouteConfig ,
290+ val scoring : ProbeScoringConfig ,
291+ ) {
292+ companion object {
293+ fun from (config : to.bitkit.services.ProbeRuntimeConfig ) = ProbeRuntimeConfig (
294+ sampleAmountMsat = config.sampleAmountMsat,
295+ route = ProbeRouteConfig (
296+ maxTotalRoutingFeeMsat = config.route.maxTotalRoutingFeeMsat,
297+ maxTotalCltvExpiryDelta = config.route.maxTotalCltvExpiryDelta,
298+ maxPathCount = config.route.maxPathCount,
299+ maxChannelSaturationPowerOfHalf = config.route.maxChannelSaturationPowerOfHalf,
300+ ),
301+ scoring = ProbeScoringConfig (
302+ basePenaltyMsat = config.scoring.basePenaltyMsat,
303+ basePenaltyAmountMultiplierMsat = config.scoring.basePenaltyAmountMultiplierMsat,
304+ liquidityPenaltyMultiplierMsat = config.scoring.liquidityPenaltyMultiplierMsat,
305+ liquidityPenaltyAmountMultiplierMsat = config.scoring.liquidityPenaltyAmountMultiplierMsat,
306+ historicalLiquidityPenaltyMultiplierMsat =
307+ config.scoring.historicalLiquidityPenaltyMultiplierMsat,
308+ historicalLiquidityPenaltyAmountMultiplierMsat =
309+ config.scoring.historicalLiquidityPenaltyAmountMultiplierMsat,
310+ antiProbingPenaltyMsat = config.scoring.antiProbingPenaltyMsat,
311+ consideredImpossiblePenaltyMsat = config.scoring.consideredImpossiblePenaltyMsat,
312+ linearSuccessProbability = config.scoring.linearSuccessProbability,
313+ probingDiversityPenaltyMsat = config.scoring.probingDiversityPenaltyMsat,
314+ ),
315+ )
316+ }
317+ }
318+
319+ @Serializable
320+ data class ProbeRouteConfig (
321+ val maxTotalRoutingFeeMsat : ULong? ,
322+ val maxTotalCltvExpiryDelta : UInt ,
323+ val maxPathCount : Int ,
324+ val maxChannelSaturationPowerOfHalf : Int ,
325+ )
326+
327+ @Serializable
328+ data class ProbeScoringConfig (
329+ val basePenaltyMsat : ULong ,
330+ val basePenaltyAmountMultiplierMsat : ULong ,
331+ val liquidityPenaltyMultiplierMsat : ULong ,
332+ val liquidityPenaltyAmountMultiplierMsat : ULong ,
333+ val historicalLiquidityPenaltyMultiplierMsat : ULong ,
334+ val historicalLiquidityPenaltyAmountMultiplierMsat : ULong ,
335+ val antiProbingPenaltyMsat : ULong ,
336+ val consideredImpossiblePenaltyMsat : ULong ,
337+ val linearSuccessProbability : Boolean ,
338+ val probingDiversityPenaltyMsat : ULong ,
339+ )
340+
268341 @Serializable data class Error (val message : String? = null ) : DevResult
269342
270343 fun toBundle () = bundleOf(KEY_RESULT to DEV_JSON .encodeToString(this ))
271344}
272345
273- private fun ProbeOutcome.toDevResult (paymentIds : Set <String >): DevResult = when (this ) {
346+ private fun ProbeOutcome.toDevResult (paymentIds : Set <String >, durationMs : Long ): DevResult = when (this ) {
274347 is ProbeOutcome .Success -> DevResult .ProbeSuccess (
275348 paymentId = paymentId,
276349 paymentHash = paymentHash,
350+ durationMs = durationMs,
351+ routeFeeMsat = routeFeeMsat,
277352 paymentIds = paymentIds.toList(),
278353 )
279354 is ProbeOutcome .Failure -> DevResult .ProbeFailure (
280355 message = " Probe failed" ,
281356 paymentId = paymentId,
282357 paymentHash = paymentHash,
283- shortChannelId = shortChannelId,
358+ shortChannelId = shortChannelId?.toString(),
359+ durationMs = durationMs,
360+ routeFeeMsat = routeFeeMsat,
284361 paymentIds = paymentIds.toList(),
285362 )
286363}
287364
288365private inline fun <reified T > String?.deserialize (): T =
289366 if (isNullOrBlank()) Json .decodeFromString(" {}" ) else Json .decodeFromString(this )
367+
368+ private fun Long.durationMs () = SystemClock .elapsedRealtime() - this
0 commit comments