diff --git a/.gitignore b/.gitignore index d66282f25..fe9c51cb2 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,9 @@ swift.swiftdoc *.a *.d +# macOS Finder metadata (icon positions, view options) +.DS_Store + # IDE and local files .idea .build diff --git a/CHANGELOG.md b/CHANGELOG.md index a618f6f1f..ce75d12a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,12 @@ ## Synonym Fork Additions +- Added pre-flight probe correlation: `Event::ProbeSuccessful` and `Event::ProbeFailed` (from LDK + probe lifecycle), plus `ProbeHandle` (`payment_id`, synthetic `payment_hash`) returned by + `Bolt11Payment::send_probes`, `send_probes_using_amount`, and `SpontaneousPayment::send_probes` + (one handle per probe path). Match handles to events by `payment_id` (and optionally + `payment_hash`); these are not the BOLT11 invoice payment hash. UniFFI: `dictionary ProbeHandle` + in `ldk_node.udl`. - Added `connection_timeout_secs` field to `ElectrumSyncConfig` (default: 10 s). This bounds Electrum socket operations for both the BDK on-chain and LDK tx-sync clients, preventing Tokio's blocking thread pool from being exhausted by threads stuck on dead sockets under total packet diff --git a/Package.swift b/Package.swift index 9d261f9dc..3cc7a6aff 100644 --- a/Package.swift +++ b/Package.swift @@ -4,7 +4,7 @@ import PackageDescription let tag = "v0.7.0-rc.36" -let checksum = "de56fe19149808ccc5e517047ea7bf6b4d5d2c2e33d3ad539ef0155bf1aec8f7" +let checksum = "e46e7c75c03831175b437fe032cef1cd43ba5c171871f82c4337a4bd5da62f5f" let url = "https://github.com/synonymdev/ldk-node/releases/download/\(tag)/LDKNodeFFI.xcframework.zip" let package = Package( diff --git a/bindings/kotlin/.editorconfig b/bindings/kotlin/.editorconfig new file mode 100644 index 000000000..ae0948687 --- /dev/null +++ b/bindings/kotlin/.editorconfig @@ -0,0 +1,7 @@ +# ktlint uses EditorConfig for indentation. Without this file it defaults to +# 2 spaces for Kotlin script, while Gradle/IntelliJ convention here is 4 spaces. +root = true + +[*.{kt,kts}] +indent_style = space +indent_size = 4 diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so index b5cd3ffea..b0e81ee48 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/arm64-v8a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so index 4562ceaa7..ceebbd517 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/armeabi-v7a/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so index 4c7768d1d..b9dead6ee 100755 Binary files a/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so and b/bindings/kotlin/ldk-node-android/lib/src/main/jniLibs/x86_64/libldk_node.so differ diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.android.kt b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.android.kt index 5a12c371c..3a5be7f9d 100644 --- a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.android.kt +++ b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.android.kt @@ -1754,14 +1754,14 @@ internal interface UniffiLib : Library { `invoice`: Pointer?, `routeParameters`: RustBufferByValue, uniffiCallStatus: UniffiRustCallStatus, - ): Unit + ): RustBufferByValue fun uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( `ptr`: Pointer?, `invoice`: Pointer?, `amountMsat`: Long, `routeParameters`: RustBufferByValue, uniffiCallStatus: UniffiRustCallStatus, - ): Unit + ): RustBufferByValue fun uniffi_ldk_node_fn_method_bolt11payment_send_using_amount( `ptr`: Pointer?, `invoice`: Pointer?, @@ -2704,7 +2704,7 @@ internal interface UniffiLib : Library { `amountMsat`: Long, `nodeId`: RustBufferByValue, uniffiCallStatus: UniffiRustCallStatus, - ): Unit + ): RustBufferByValue fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs( `ptr`: Pointer?, `amountMsat`: Long, @@ -3512,10 +3512,10 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 19286.toShort()) { + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 5976.toShort()) { + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793.toShort()) { @@ -3977,7 +3977,7 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 25937.toShort()) { + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876.toShort()) { @@ -4912,8 +4912,8 @@ open class Bolt11Payment: Disposable, Bolt11PaymentInterface { } @Throws(NodeException::class) - override fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?) { - callWithPointer { + override fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes( it, @@ -4922,12 +4922,12 @@ open class Bolt11Payment: Disposable, Bolt11PaymentInterface { uniffiRustCallStatus, ) } - } + }) } @Throws(NodeException::class) - override fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?) { - callWithPointer { + override fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( it, @@ -4937,7 +4937,7 @@ open class Bolt11Payment: Disposable, Bolt11PaymentInterface { uniffiRustCallStatus, ) } - } + }) } @Throws(NodeException::class) @@ -8630,8 +8630,8 @@ open class SpontaneousPayment: Disposable, SpontaneousPaymentInterface { } @Throws(NodeException::class) - override fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey) { - callWithPointer { + override fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes( it, @@ -8640,7 +8640,7 @@ open class SpontaneousPayment: Disposable, SpontaneousPaymentInterface { uniffiRustCallStatus, ) } - } + }) } @Throws(NodeException::class) @@ -9976,6 +9976,28 @@ object FfiConverterTypePeerDetails: FfiConverterRustBuffer { +object FfiConverterTypeProbeHandle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ProbeHandle { + return ProbeHandle( + FfiConverterTypePaymentHash.read(buf), + FfiConverterTypePaymentId.read(buf), + ) + } + + override fun allocationSize(value: ProbeHandle) = ( + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + + override fun write(value: ProbeHandle, buf: ByteBuffer) { + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + } +} + + + + object FfiConverterTypeRouteHintHop: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): RouteHintHop { return RouteHintHop( @@ -10746,69 +10768,78 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ FfiConverterBoolean.read(buf), FfiConverterOptionalULong.read(buf), ) - 6 -> Event.ChannelPending( + 6 -> Event.ProbeSuccessful( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + ) + 7 -> Event.ProbeFailed( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 8 -> Event.ChannelPending( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterTypeChannelId.read(buf), FfiConverterTypePublicKey.read(buf), FfiConverterTypeOutPoint.read(buf), ) - 7 -> Event.ChannelReady( + 9 -> Event.ChannelReady( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterOptionalTypePublicKey.read(buf), FfiConverterOptionalTypeOutPoint.read(buf), ) - 8 -> Event.ChannelClosed( + 10 -> Event.ChannelClosed( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterOptionalTypePublicKey.read(buf), FfiConverterOptionalTypeClosureReason.read(buf), ) - 9 -> Event.SplicePending( + 11 -> Event.SplicePending( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterTypePublicKey.read(buf), FfiConverterTypeOutPoint.read(buf), ) - 10 -> Event.SpliceFailed( + 12 -> Event.SpliceFailed( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterTypePublicKey.read(buf), FfiConverterOptionalTypeOutPoint.read(buf), ) - 11 -> Event.OnchainTransactionConfirmed( + 13 -> Event.OnchainTransactionConfirmed( FfiConverterTypeTxid.read(buf), FfiConverterTypeBlockHash.read(buf), FfiConverterUInt.read(buf), FfiConverterULong.read(buf), FfiConverterTypeTransactionDetails.read(buf), ) - 12 -> Event.OnchainTransactionReceived( + 14 -> Event.OnchainTransactionReceived( FfiConverterTypeTxid.read(buf), FfiConverterTypeTransactionDetails.read(buf), ) - 13 -> Event.OnchainTransactionReplaced( + 15 -> Event.OnchainTransactionReplaced( FfiConverterTypeTxid.read(buf), FfiConverterSequenceTypeTxid.read(buf), ) - 14 -> Event.OnchainTransactionReorged( + 16 -> Event.OnchainTransactionReorged( FfiConverterTypeTxid.read(buf), ) - 15 -> Event.OnchainTransactionEvicted( + 17 -> Event.OnchainTransactionEvicted( FfiConverterTypeTxid.read(buf), ) - 16 -> Event.SyncProgress( + 18 -> Event.SyncProgress( FfiConverterTypeSyncType.read(buf), FfiConverterUByte.read(buf), FfiConverterUInt.read(buf), FfiConverterUInt.read(buf), ) - 17 -> Event.SyncCompleted( + 19 -> Event.SyncCompleted( FfiConverterTypeSyncType.read(buf), FfiConverterUInt.read(buf), ) - 18 -> Event.BalanceChanged( + 20 -> Event.BalanceChanged( FfiConverterULong.read(buf), FfiConverterULong.read(buf), FfiConverterULong.read(buf), @@ -10877,6 +10908,23 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ + FfiConverterOptionalULong.allocationSize(value.`outboundAmountForwardedMsat`) ) } + is Event.ProbeSuccessful -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + ) + } + is Event.ProbeFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalULong.allocationSize(value.`shortChannelId`) + ) + } is Event.ChannelPending -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( @@ -11049,8 +11097,21 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ FfiConverterOptionalULong.write(value.`outboundAmountForwardedMsat`, buf) Unit } - is Event.ChannelPending -> { + is Event.ProbeSuccessful -> { buf.putInt(6) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + Unit + } + is Event.ProbeFailed -> { + buf.putInt(7) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalULong.write(value.`shortChannelId`, buf) + Unit + } + is Event.ChannelPending -> { + buf.putInt(8) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterTypeChannelId.write(value.`formerTemporaryChannelId`, buf) @@ -11059,7 +11120,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.ChannelReady -> { - buf.putInt(7) + buf.putInt(9) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11067,7 +11128,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.ChannelClosed -> { - buf.putInt(8) + buf.putInt(10) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11075,7 +11136,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.SplicePending -> { - buf.putInt(9) + buf.putInt(11) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11083,7 +11144,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.SpliceFailed -> { - buf.putInt(10) + buf.putInt(12) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11091,7 +11152,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.OnchainTransactionConfirmed -> { - buf.putInt(11) + buf.putInt(13) FfiConverterTypeTxid.write(value.`txid`, buf) FfiConverterTypeBlockHash.write(value.`blockHash`, buf) FfiConverterUInt.write(value.`blockHeight`, buf) @@ -11100,29 +11161,29 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.OnchainTransactionReceived -> { - buf.putInt(12) + buf.putInt(14) FfiConverterTypeTxid.write(value.`txid`, buf) FfiConverterTypeTransactionDetails.write(value.`details`, buf) Unit } is Event.OnchainTransactionReplaced -> { - buf.putInt(13) + buf.putInt(15) FfiConverterTypeTxid.write(value.`txid`, buf) FfiConverterSequenceTypeTxid.write(value.`conflicts`, buf) Unit } is Event.OnchainTransactionReorged -> { - buf.putInt(14) + buf.putInt(16) FfiConverterTypeTxid.write(value.`txid`, buf) Unit } is Event.OnchainTransactionEvicted -> { - buf.putInt(15) + buf.putInt(17) FfiConverterTypeTxid.write(value.`txid`, buf) Unit } is Event.SyncProgress -> { - buf.putInt(16) + buf.putInt(18) FfiConverterTypeSyncType.write(value.`syncType`, buf) FfiConverterUByte.write(value.`progressPercent`, buf) FfiConverterUInt.write(value.`currentBlockHeight`, buf) @@ -11130,13 +11191,13 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.SyncCompleted -> { - buf.putInt(17) + buf.putInt(19) FfiConverterTypeSyncType.write(value.`syncType`, buf) FfiConverterUInt.write(value.`syncedBlockHeight`, buf) Unit } is Event.BalanceChanged -> { - buf.putInt(18) + buf.putInt(20) FfiConverterULong.write(value.`oldSpendableOnchainBalanceSats`, buf) FfiConverterULong.write(value.`newSpendableOnchainBalanceSats`, buf) FfiConverterULong.write(value.`oldTotalOnchainBalanceSats`, buf) @@ -13771,6 +13832,31 @@ object FfiConverterSequenceTypePeerDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeProbeHandle.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeProbeHandle.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeProbeHandle.write(it, buf) + } + } +} + + + + object FfiConverterSequenceTypeRouteHintHop: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): List { val len = buf.getInt() diff --git a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt index e79493a9f..5223da8bc 100644 --- a/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt +++ b/bindings/kotlin/ldk-node-android/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt @@ -185,10 +185,10 @@ interface Bolt11PaymentInterface { fun `send`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): PaymentId @Throws(NodeException::class) - fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?) + fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List @Throws(NodeException::class) - fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?) + fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List @Throws(NodeException::class) fun `sendUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): PaymentId @@ -650,7 +650,7 @@ interface SpontaneousPaymentInterface { fun `send`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?): PaymentId @Throws(NodeException::class) - fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey) + fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List @Throws(NodeException::class) fun `sendWithCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?, `customTlvs`: List): PaymentId @@ -1114,6 +1114,16 @@ data class PeerDetails ( +@kotlinx.serialization.Serializable +data class ProbeHandle ( + val `paymentHash`: PaymentHash, + val `paymentId`: PaymentId +) { + companion object +} + + + @kotlinx.serialization.Serializable data class RouteHintHop ( val `srcNodeId`: PublicKey, @@ -1497,6 +1507,19 @@ sealed class Event { ) : Event() { } @kotlinx.serialization.Serializable + data class ProbeSuccessful( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ProbeFailed( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `shortChannelId`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable data class ChannelPending( val `channelId`: ChannelId, val `userChannelId`: UserChannelId, @@ -2247,6 +2270,8 @@ enum class WordCount { + + diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt index e79493a9f..5223da8bc 100644 --- a/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt +++ b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.common.kt @@ -185,10 +185,10 @@ interface Bolt11PaymentInterface { fun `send`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): PaymentId @Throws(NodeException::class) - fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?) + fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List @Throws(NodeException::class) - fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?) + fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List @Throws(NodeException::class) fun `sendUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): PaymentId @@ -650,7 +650,7 @@ interface SpontaneousPaymentInterface { fun `send`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?): PaymentId @Throws(NodeException::class) - fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey) + fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List @Throws(NodeException::class) fun `sendWithCustomTlvs`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey, `routeParameters`: RouteParametersConfig?, `customTlvs`: List): PaymentId @@ -1114,6 +1114,16 @@ data class PeerDetails ( +@kotlinx.serialization.Serializable +data class ProbeHandle ( + val `paymentHash`: PaymentHash, + val `paymentId`: PaymentId +) { + companion object +} + + + @kotlinx.serialization.Serializable data class RouteHintHop ( val `srcNodeId`: PublicKey, @@ -1497,6 +1507,19 @@ sealed class Event { ) : Event() { } @kotlinx.serialization.Serializable + data class ProbeSuccessful( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + ) : Event() { + } + @kotlinx.serialization.Serializable + data class ProbeFailed( + val `paymentId`: PaymentId, + val `paymentHash`: PaymentHash, + val `shortChannelId`: kotlin.ULong?, + ) : Event() { + } + @kotlinx.serialization.Serializable data class ChannelPending( val `channelId`: ChannelId, val `userChannelId`: UserChannelId, @@ -2247,6 +2270,8 @@ enum class WordCount { + + diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.jvm.kt b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.jvm.kt index f61b26797..f1cc54635 100644 --- a/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.jvm.kt +++ b/bindings/kotlin/ldk-node-jvm/lib/src/main/kotlin/org/lightningdevkit/ldknode/ldk_node.jvm.kt @@ -1752,14 +1752,14 @@ internal interface UniffiLib : Library { `invoice`: Pointer?, `routeParameters`: RustBufferByValue, uniffiCallStatus: UniffiRustCallStatus, - ): Unit + ): RustBufferByValue fun uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( `ptr`: Pointer?, `invoice`: Pointer?, `amountMsat`: Long, `routeParameters`: RustBufferByValue, uniffiCallStatus: UniffiRustCallStatus, - ): Unit + ): RustBufferByValue fun uniffi_ldk_node_fn_method_bolt11payment_send_using_amount( `ptr`: Pointer?, `invoice`: Pointer?, @@ -2702,7 +2702,7 @@ internal interface UniffiLib : Library { `amountMsat`: Long, `nodeId`: RustBufferByValue, uniffiCallStatus: UniffiRustCallStatus, - ): Unit + ): RustBufferByValue fun uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs( `ptr`: Pointer?, `amountMsat`: Long, @@ -3510,10 +3510,10 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 19286.toShort()) { + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 5976.toShort()) { + if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793.toShort()) { @@ -3975,7 +3975,7 @@ private fun uniffiCheckApiChecksums(lib: UniffiLib) { if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } - if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 25937.toShort()) { + if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206.toShort()) { throw RuntimeException("UniFFI API checksum mismatch: try cleaning and rebuilding your project") } if (lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876.toShort()) { @@ -4901,8 +4901,8 @@ open class Bolt11Payment: Disposable, Bolt11PaymentInterface { } @Throws(NodeException::class) - override fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?) { - callWithPointer { + override fun `sendProbes`(`invoice`: Bolt11Invoice, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes( it, @@ -4911,12 +4911,12 @@ open class Bolt11Payment: Disposable, Bolt11PaymentInterface { uniffiRustCallStatus, ) } - } + }) } @Throws(NodeException::class) - override fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?) { - callWithPointer { + override fun `sendProbesUsingAmount`(`invoice`: Bolt11Invoice, `amountMsat`: kotlin.ULong, `routeParameters`: RouteParametersConfig?): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount( it, @@ -4926,7 +4926,7 @@ open class Bolt11Payment: Disposable, Bolt11PaymentInterface { uniffiRustCallStatus, ) } - } + }) } @Throws(NodeException::class) @@ -8619,8 +8619,8 @@ open class SpontaneousPayment: Disposable, SpontaneousPaymentInterface { } @Throws(NodeException::class) - override fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey) { - callWithPointer { + override fun `sendProbes`(`amountMsat`: kotlin.ULong, `nodeId`: PublicKey): List { + return FfiConverterSequenceTypeProbeHandle.lift(callWithPointer { uniffiRustCallWithError(NodeExceptionErrorHandler) { uniffiRustCallStatus -> UniffiLib.INSTANCE.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes( it, @@ -8629,7 +8629,7 @@ open class SpontaneousPayment: Disposable, SpontaneousPaymentInterface { uniffiRustCallStatus, ) } - } + }) } @Throws(NodeException::class) @@ -9965,6 +9965,28 @@ object FfiConverterTypePeerDetails: FfiConverterRustBuffer { +object FfiConverterTypeProbeHandle: FfiConverterRustBuffer { + override fun read(buf: ByteBuffer): ProbeHandle { + return ProbeHandle( + FfiConverterTypePaymentHash.read(buf), + FfiConverterTypePaymentId.read(buf), + ) + } + + override fun allocationSize(value: ProbeHandle) = ( + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + ) + + override fun write(value: ProbeHandle, buf: ByteBuffer) { + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + } +} + + + + object FfiConverterTypeRouteHintHop: FfiConverterRustBuffer { override fun read(buf: ByteBuffer): RouteHintHop { return RouteHintHop( @@ -10735,69 +10757,78 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ FfiConverterBoolean.read(buf), FfiConverterOptionalULong.read(buf), ) - 6 -> Event.ChannelPending( + 6 -> Event.ProbeSuccessful( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + ) + 7 -> Event.ProbeFailed( + FfiConverterTypePaymentId.read(buf), + FfiConverterTypePaymentHash.read(buf), + FfiConverterOptionalULong.read(buf), + ) + 8 -> Event.ChannelPending( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterTypeChannelId.read(buf), FfiConverterTypePublicKey.read(buf), FfiConverterTypeOutPoint.read(buf), ) - 7 -> Event.ChannelReady( + 9 -> Event.ChannelReady( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterOptionalTypePublicKey.read(buf), FfiConverterOptionalTypeOutPoint.read(buf), ) - 8 -> Event.ChannelClosed( + 10 -> Event.ChannelClosed( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterOptionalTypePublicKey.read(buf), FfiConverterOptionalTypeClosureReason.read(buf), ) - 9 -> Event.SplicePending( + 11 -> Event.SplicePending( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterTypePublicKey.read(buf), FfiConverterTypeOutPoint.read(buf), ) - 10 -> Event.SpliceFailed( + 12 -> Event.SpliceFailed( FfiConverterTypeChannelId.read(buf), FfiConverterTypeUserChannelId.read(buf), FfiConverterTypePublicKey.read(buf), FfiConverterOptionalTypeOutPoint.read(buf), ) - 11 -> Event.OnchainTransactionConfirmed( + 13 -> Event.OnchainTransactionConfirmed( FfiConverterTypeTxid.read(buf), FfiConverterTypeBlockHash.read(buf), FfiConverterUInt.read(buf), FfiConverterULong.read(buf), FfiConverterTypeTransactionDetails.read(buf), ) - 12 -> Event.OnchainTransactionReceived( + 14 -> Event.OnchainTransactionReceived( FfiConverterTypeTxid.read(buf), FfiConverterTypeTransactionDetails.read(buf), ) - 13 -> Event.OnchainTransactionReplaced( + 15 -> Event.OnchainTransactionReplaced( FfiConverterTypeTxid.read(buf), FfiConverterSequenceTypeTxid.read(buf), ) - 14 -> Event.OnchainTransactionReorged( + 16 -> Event.OnchainTransactionReorged( FfiConverterTypeTxid.read(buf), ) - 15 -> Event.OnchainTransactionEvicted( + 17 -> Event.OnchainTransactionEvicted( FfiConverterTypeTxid.read(buf), ) - 16 -> Event.SyncProgress( + 18 -> Event.SyncProgress( FfiConverterTypeSyncType.read(buf), FfiConverterUByte.read(buf), FfiConverterUInt.read(buf), FfiConverterUInt.read(buf), ) - 17 -> Event.SyncCompleted( + 19 -> Event.SyncCompleted( FfiConverterTypeSyncType.read(buf), FfiConverterUInt.read(buf), ) - 18 -> Event.BalanceChanged( + 20 -> Event.BalanceChanged( FfiConverterULong.read(buf), FfiConverterULong.read(buf), FfiConverterULong.read(buf), @@ -10866,6 +10897,23 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ + FfiConverterOptionalULong.allocationSize(value.`outboundAmountForwardedMsat`) ) } + is Event.ProbeSuccessful -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + ) + } + is Event.ProbeFailed -> { + // Add the size for the Int that specifies the variant plus the size needed for all fields + ( + 4UL + + FfiConverterTypePaymentId.allocationSize(value.`paymentId`) + + FfiConverterTypePaymentHash.allocationSize(value.`paymentHash`) + + FfiConverterOptionalULong.allocationSize(value.`shortChannelId`) + ) + } is Event.ChannelPending -> { // Add the size for the Int that specifies the variant plus the size needed for all fields ( @@ -11038,8 +11086,21 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ FfiConverterOptionalULong.write(value.`outboundAmountForwardedMsat`, buf) Unit } - is Event.ChannelPending -> { + is Event.ProbeSuccessful -> { buf.putInt(6) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + Unit + } + is Event.ProbeFailed -> { + buf.putInt(7) + FfiConverterTypePaymentId.write(value.`paymentId`, buf) + FfiConverterTypePaymentHash.write(value.`paymentHash`, buf) + FfiConverterOptionalULong.write(value.`shortChannelId`, buf) + Unit + } + is Event.ChannelPending -> { + buf.putInt(8) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterTypeChannelId.write(value.`formerTemporaryChannelId`, buf) @@ -11048,7 +11109,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.ChannelReady -> { - buf.putInt(7) + buf.putInt(9) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11056,7 +11117,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.ChannelClosed -> { - buf.putInt(8) + buf.putInt(10) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterOptionalTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11064,7 +11125,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.SplicePending -> { - buf.putInt(9) + buf.putInt(11) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11072,7 +11133,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.SpliceFailed -> { - buf.putInt(10) + buf.putInt(12) FfiConverterTypeChannelId.write(value.`channelId`, buf) FfiConverterTypeUserChannelId.write(value.`userChannelId`, buf) FfiConverterTypePublicKey.write(value.`counterpartyNodeId`, buf) @@ -11080,7 +11141,7 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.OnchainTransactionConfirmed -> { - buf.putInt(11) + buf.putInt(13) FfiConverterTypeTxid.write(value.`txid`, buf) FfiConverterTypeBlockHash.write(value.`blockHash`, buf) FfiConverterUInt.write(value.`blockHeight`, buf) @@ -11089,29 +11150,29 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.OnchainTransactionReceived -> { - buf.putInt(12) + buf.putInt(14) FfiConverterTypeTxid.write(value.`txid`, buf) FfiConverterTypeTransactionDetails.write(value.`details`, buf) Unit } is Event.OnchainTransactionReplaced -> { - buf.putInt(13) + buf.putInt(15) FfiConverterTypeTxid.write(value.`txid`, buf) FfiConverterSequenceTypeTxid.write(value.`conflicts`, buf) Unit } is Event.OnchainTransactionReorged -> { - buf.putInt(14) + buf.putInt(16) FfiConverterTypeTxid.write(value.`txid`, buf) Unit } is Event.OnchainTransactionEvicted -> { - buf.putInt(15) + buf.putInt(17) FfiConverterTypeTxid.write(value.`txid`, buf) Unit } is Event.SyncProgress -> { - buf.putInt(16) + buf.putInt(18) FfiConverterTypeSyncType.write(value.`syncType`, buf) FfiConverterUByte.write(value.`progressPercent`, buf) FfiConverterUInt.write(value.`currentBlockHeight`, buf) @@ -11119,13 +11180,13 @@ object FfiConverterTypeEvent : FfiConverterRustBuffer{ Unit } is Event.SyncCompleted -> { - buf.putInt(17) + buf.putInt(19) FfiConverterTypeSyncType.write(value.`syncType`, buf) FfiConverterUInt.write(value.`syncedBlockHeight`, buf) Unit } is Event.BalanceChanged -> { - buf.putInt(18) + buf.putInt(20) FfiConverterULong.write(value.`oldSpendableOnchainBalanceSats`, buf) FfiConverterULong.write(value.`newSpendableOnchainBalanceSats`, buf) FfiConverterULong.write(value.`oldTotalOnchainBalanceSats`, buf) @@ -13760,6 +13821,31 @@ object FfiConverterSequenceTypePeerDetails: FfiConverterRustBuffer> { + override fun read(buf: ByteBuffer): List { + val len = buf.getInt() + return List(len) { + FfiConverterTypeProbeHandle.read(buf) + } + } + + override fun allocationSize(value: List): ULong { + val sizeForLength = 4UL + val sizeForItems = value.sumOf { FfiConverterTypeProbeHandle.allocationSize(it) } + return sizeForLength + sizeForItems + } + + override fun write(value: List, buf: ByteBuffer) { + buf.putInt(value.size) + value.iterator().forEach { + FfiConverterTypeProbeHandle.write(it, buf) + } + } +} + + + + object FfiConverterSequenceTypeRouteHintHop: FfiConverterRustBuffer> { override fun read(buf: ByteBuffer): List { val len = buf.getInt() diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib index e5bfee794..596e0c6d5 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-aarch64/libldk_node.dylib differ diff --git a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib index ad19d4d19..7ad1fd9de 100644 Binary files a/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib and b/bindings/kotlin/ldk-node-jvm/lib/src/main/resources/darwin-x86-64/libldk_node.dylib differ diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 6f2f57380..3407471c3 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -235,9 +235,9 @@ interface Bolt11Payment { [Throws=NodeError] PaymentId send_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat, RouteParametersConfig? route_parameters); [Throws=NodeError] - void send_probes([ByRef]Bolt11Invoice invoice, RouteParametersConfig? route_parameters); + sequence send_probes([ByRef]Bolt11Invoice invoice, RouteParametersConfig? route_parameters); [Throws=NodeError] - void send_probes_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat, RouteParametersConfig? route_parameters); + sequence send_probes_using_amount([ByRef]Bolt11Invoice invoice, u64 amount_msat, RouteParametersConfig? route_parameters); [Throws=NodeError] void claim_for_hash(PaymentHash payment_hash, u64 claimable_amount_msat, PaymentPreimage preimage); [Throws=NodeError] @@ -295,7 +295,7 @@ interface SpontaneousPayment { [Throws=NodeError] PaymentId send_with_preimage_and_custom_tlvs(u64 amount_msat, PublicKey node_id, sequence custom_tlvs, PaymentPreimage preimage, RouteParametersConfig? route_parameters); [Throws=NodeError] - void send_probes(u64 amount_msat, PublicKey node_id); + sequence send_probes(u64 amount_msat, PublicKey node_id); }; interface OnchainPayment { @@ -518,6 +518,8 @@ interface Event { PaymentClaimable(PaymentId payment_id, PaymentHash payment_hash, u64 claimable_amount_msat, u32? claim_deadline, sequence custom_records); PaymentForwarded(ChannelId prev_channel_id, ChannelId next_channel_id, UserChannelId? prev_user_channel_id, UserChannelId? next_user_channel_id, PublicKey? prev_node_id, PublicKey? next_node_id, u64? total_fee_earned_msat, u64? skimmed_fee_msat, boolean claim_from_onchain_tx, u64? outbound_amount_forwarded_msat); + ProbeSuccessful(PaymentId payment_id, PaymentHash payment_hash); + ProbeFailed(PaymentId payment_id, PaymentHash payment_hash, u64? short_channel_id); ChannelPending(ChannelId channel_id, UserChannelId user_channel_id, ChannelId former_temporary_channel_id, PublicKey counterparty_node_id, OutPoint funding_txo); ChannelReady(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, OutPoint? funding_txo); ChannelClosed(ChannelId channel_id, UserChannelId user_channel_id, PublicKey? counterparty_node_id, ClosureReason? reason); @@ -621,6 +623,11 @@ dictionary RouteParametersConfig { u8 max_channel_saturation_power_of_half; }; +dictionary ProbeHandle { + PaymentHash payment_hash; + PaymentId payment_id; +}; + dictionary CustomTlvRecord { u64 type_num; sequence value; diff --git a/bindings/python/src/ldk_node/ldk_node.py b/bindings/python/src/ldk_node/ldk_node.py index 22fc4ff43..ddfc57e22 100644 --- a/bindings/python/src/ldk_node/ldk_node.py +++ b/bindings/python/src/ldk_node/ldk_node.py @@ -527,9 +527,9 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 19286: + if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 5976: + if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") @@ -837,7 +837,7 @@ def _uniffi_check_api_checksums(lib): raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") - if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 25937: + if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") if lib.uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876: raise InternalError("UniFFI API checksum mismatch: try cleaning and rebuilding your project") @@ -1224,7 +1224,7 @@ class _UniffiVTableCallbackInterfaceVssHeaderProvider(ctypes.Structure): _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), ) -_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes.restype = _UniffiRustBuffer _UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount.argtypes = ( ctypes.c_void_p, ctypes.c_void_p, @@ -1232,7 +1232,7 @@ class _UniffiVTableCallbackInterfaceVssHeaderProvider(ctypes.Structure): _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), ) -_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount.restype = _UniffiRustBuffer _UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_using_amount.argtypes = ( ctypes.c_void_p, ctypes.c_void_p, @@ -2369,7 +2369,7 @@ class _UniffiVTableCallbackInterfaceVssHeaderProvider(ctypes.Structure): _UniffiRustBuffer, ctypes.POINTER(_UniffiRustCallStatus), ) -_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes.restype = None +_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes.restype = _UniffiRustBuffer _UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_with_custom_tlvs.argtypes = ( ctypes.c_void_p, ctypes.c_uint64, @@ -4048,32 +4048,34 @@ def send(self, invoice: "Bolt11Invoice",route_parameters: "typing.Optional[Route - def send_probes(self, invoice: "Bolt11Invoice",route_parameters: "typing.Optional[RouteParametersConfig]") -> None: + def send_probes(self, invoice: "Bolt11Invoice",route_parameters: "typing.Optional[RouteParametersConfig]") -> "typing.List[ProbeHandle]": _UniffiConverterTypeBolt11Invoice.check_lower(invoice) _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) - _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes,self._uniffi_clone_pointer(), + return _UniffiConverterSequenceTypeProbeHandle.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes,self._uniffi_clone_pointer(), _UniffiConverterTypeBolt11Invoice.lower(invoice), _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) + ) - - def send_probes_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int",route_parameters: "typing.Optional[RouteParametersConfig]") -> None: + def send_probes_using_amount(self, invoice: "Bolt11Invoice",amount_msat: "int",route_parameters: "typing.Optional[RouteParametersConfig]") -> "typing.List[ProbeHandle]": _UniffiConverterTypeBolt11Invoice.check_lower(invoice) _UniffiConverterUInt64.check_lower(amount_msat) _UniffiConverterOptionalTypeRouteParametersConfig.check_lower(route_parameters) - _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount,self._uniffi_clone_pointer(), + return _UniffiConverterSequenceTypeProbeHandle.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount,self._uniffi_clone_pointer(), _UniffiConverterTypeBolt11Invoice.lower(invoice), _UniffiConverterUInt64.lower(amount_msat), _UniffiConverterOptionalTypeRouteParametersConfig.lower(route_parameters)) - + ) @@ -7116,15 +7118,16 @@ def send(self, amount_msat: "int",node_id: "PublicKey",route_parameters: "typing - def send_probes(self, amount_msat: "int",node_id: "PublicKey") -> None: + def send_probes(self, amount_msat: "int",node_id: "PublicKey") -> "typing.List[ProbeHandle]": _UniffiConverterUInt64.check_lower(amount_msat) _UniffiConverterTypePublicKey.check_lower(node_id) - _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes,self._uniffi_clone_pointer(), + return _UniffiConverterSequenceTypeProbeHandle.lift( + _uniffi_rust_call_with_error(_UniffiConverterTypeNodeError,_UniffiLib.uniffi_ldk_node_fn_method_spontaneouspayment_send_probes,self._uniffi_clone_pointer(), _UniffiConverterUInt64.lower(amount_msat), _UniffiConverterTypePublicKey.lower(node_id)) - + ) @@ -9127,6 +9130,42 @@ def write(value, buf): _UniffiConverterBool.write(value.is_connected, buf) +class ProbeHandle: + payment_hash: "PaymentHash" + payment_id: "PaymentId" + def __init__(self, *, payment_hash: "PaymentHash", payment_id: "PaymentId"): + self.payment_hash = payment_hash + self.payment_id = payment_id + + def __str__(self): + return "ProbeHandle(payment_hash={}, payment_id={})".format(self.payment_hash, self.payment_id) + + def __eq__(self, other): + if self.payment_hash != other.payment_hash: + return False + if self.payment_id != other.payment_id: + return False + return True + +class _UniffiConverterTypeProbeHandle(_UniffiConverterRustBuffer): + @staticmethod + def read(buf): + return ProbeHandle( + payment_hash=_UniffiConverterTypePaymentHash.read(buf), + payment_id=_UniffiConverterTypePaymentId.read(buf), + ) + + @staticmethod + def check_lower(value): + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + + @staticmethod + def write(value, buf): + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + + class RouteHintHop: src_node_id: "PublicKey" short_channel_id: "int" @@ -10822,6 +10861,50 @@ def __eq__(self, other): return False return True + class PROBE_SUCCESSFUL: + payment_id: "PaymentId" + payment_hash: "PaymentHash" + + def __init__(self,payment_id: "PaymentId", payment_hash: "PaymentHash"): + self.payment_id = payment_id + self.payment_hash = payment_hash + + def __str__(self): + return "Event.PROBE_SUCCESSFUL(payment_id={}, payment_hash={})".format(self.payment_id, self.payment_hash) + + def __eq__(self, other): + if not other.is_probe_successful(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + return True + + class PROBE_FAILED: + payment_id: "PaymentId" + payment_hash: "PaymentHash" + short_channel_id: "typing.Optional[int]" + + def __init__(self,payment_id: "PaymentId", payment_hash: "PaymentHash", short_channel_id: "typing.Optional[int]"): + self.payment_id = payment_id + self.payment_hash = payment_hash + self.short_channel_id = short_channel_id + + def __str__(self): + return "Event.PROBE_FAILED(payment_id={}, payment_hash={}, short_channel_id={})".format(self.payment_id, self.payment_hash, self.short_channel_id) + + def __eq__(self, other): + if not other.is_probe_failed(): + return False + if self.payment_id != other.payment_id: + return False + if self.payment_hash != other.payment_hash: + return False + if self.short_channel_id != other.short_channel_id: + return False + return True + class CHANNEL_PENDING: channel_id: "ChannelId" user_channel_id: "UserChannelId" @@ -11168,6 +11251,10 @@ def is_payment_claimable(self) -> bool: return isinstance(self, Event.PAYMENT_CLAIMABLE) def is_payment_forwarded(self) -> bool: return isinstance(self, Event.PAYMENT_FORWARDED) + def is_probe_successful(self) -> bool: + return isinstance(self, Event.PROBE_SUCCESSFUL) + def is_probe_failed(self) -> bool: + return isinstance(self, Event.PROBE_FAILED) def is_channel_pending(self) -> bool: return isinstance(self, Event.CHANNEL_PENDING) def is_channel_ready(self) -> bool: @@ -11204,6 +11291,8 @@ def is_balance_changed(self) -> bool: Event.PAYMENT_RECEIVED = type("Event.PAYMENT_RECEIVED", (Event.PAYMENT_RECEIVED, Event,), {}) # type: ignore Event.PAYMENT_CLAIMABLE = type("Event.PAYMENT_CLAIMABLE", (Event.PAYMENT_CLAIMABLE, Event,), {}) # type: ignore Event.PAYMENT_FORWARDED = type("Event.PAYMENT_FORWARDED", (Event.PAYMENT_FORWARDED, Event,), {}) # type: ignore +Event.PROBE_SUCCESSFUL = type("Event.PROBE_SUCCESSFUL", (Event.PROBE_SUCCESSFUL, Event,), {}) # type: ignore +Event.PROBE_FAILED = type("Event.PROBE_FAILED", (Event.PROBE_FAILED, Event,), {}) # type: ignore Event.CHANNEL_PENDING = type("Event.CHANNEL_PENDING", (Event.CHANNEL_PENDING, Event,), {}) # type: ignore Event.CHANNEL_READY = type("Event.CHANNEL_READY", (Event.CHANNEL_READY, Event,), {}) # type: ignore Event.CHANNEL_CLOSED = type("Event.CHANNEL_CLOSED", (Event.CHANNEL_CLOSED, Event,), {}) # type: ignore @@ -11267,6 +11356,17 @@ def read(buf): _UniffiConverterOptionalUInt64.read(buf), ) if variant == 6: + return Event.PROBE_SUCCESSFUL( + _UniffiConverterTypePaymentId.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + ) + if variant == 7: + return Event.PROBE_FAILED( + _UniffiConverterTypePaymentId.read(buf), + _UniffiConverterTypePaymentHash.read(buf), + _UniffiConverterOptionalUInt64.read(buf), + ) + if variant == 8: return Event.CHANNEL_PENDING( _UniffiConverterTypeChannelId.read(buf), _UniffiConverterTypeUserChannelId.read(buf), @@ -11274,35 +11374,35 @@ def read(buf): _UniffiConverterTypePublicKey.read(buf), _UniffiConverterTypeOutPoint.read(buf), ) - if variant == 7: + if variant == 9: return Event.CHANNEL_READY( _UniffiConverterTypeChannelId.read(buf), _UniffiConverterTypeUserChannelId.read(buf), _UniffiConverterOptionalTypePublicKey.read(buf), _UniffiConverterOptionalTypeOutPoint.read(buf), ) - if variant == 8: + if variant == 10: return Event.CHANNEL_CLOSED( _UniffiConverterTypeChannelId.read(buf), _UniffiConverterTypeUserChannelId.read(buf), _UniffiConverterOptionalTypePublicKey.read(buf), _UniffiConverterOptionalTypeClosureReason.read(buf), ) - if variant == 9: + if variant == 11: return Event.SPLICE_PENDING( _UniffiConverterTypeChannelId.read(buf), _UniffiConverterTypeUserChannelId.read(buf), _UniffiConverterTypePublicKey.read(buf), _UniffiConverterTypeOutPoint.read(buf), ) - if variant == 10: + if variant == 12: return Event.SPLICE_FAILED( _UniffiConverterTypeChannelId.read(buf), _UniffiConverterTypeUserChannelId.read(buf), _UniffiConverterTypePublicKey.read(buf), _UniffiConverterOptionalTypeOutPoint.read(buf), ) - if variant == 11: + if variant == 13: return Event.ONCHAIN_TRANSACTION_CONFIRMED( _UniffiConverterTypeTxid.read(buf), _UniffiConverterTypeBlockHash.read(buf), @@ -11310,37 +11410,37 @@ def read(buf): _UniffiConverterUInt64.read(buf), _UniffiConverterTypeTransactionDetails.read(buf), ) - if variant == 12: + if variant == 14: return Event.ONCHAIN_TRANSACTION_RECEIVED( _UniffiConverterTypeTxid.read(buf), _UniffiConverterTypeTransactionDetails.read(buf), ) - if variant == 13: + if variant == 15: return Event.ONCHAIN_TRANSACTION_REPLACED( _UniffiConverterTypeTxid.read(buf), _UniffiConverterSequenceTypeTxid.read(buf), ) - if variant == 14: + if variant == 16: return Event.ONCHAIN_TRANSACTION_REORGED( _UniffiConverterTypeTxid.read(buf), ) - if variant == 15: + if variant == 17: return Event.ONCHAIN_TRANSACTION_EVICTED( _UniffiConverterTypeTxid.read(buf), ) - if variant == 16: + if variant == 18: return Event.SYNC_PROGRESS( _UniffiConverterTypeSyncType.read(buf), _UniffiConverterUInt8.read(buf), _UniffiConverterUInt32.read(buf), _UniffiConverterUInt32.read(buf), ) - if variant == 17: + if variant == 19: return Event.SYNC_COMPLETED( _UniffiConverterTypeSyncType.read(buf), _UniffiConverterUInt32.read(buf), ) - if variant == 18: + if variant == 20: return Event.BALANCE_CHANGED( _UniffiConverterUInt64.read(buf), _UniffiConverterUInt64.read(buf), @@ -11389,6 +11489,15 @@ def check_lower(value): _UniffiConverterBool.check_lower(value.claim_from_onchain_tx) _UniffiConverterOptionalUInt64.check_lower(value.outbound_amount_forwarded_msat) return + if value.is_probe_successful(): + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + return + if value.is_probe_failed(): + _UniffiConverterTypePaymentId.check_lower(value.payment_id) + _UniffiConverterTypePaymentHash.check_lower(value.payment_hash) + _UniffiConverterOptionalUInt64.check_lower(value.short_channel_id) + return if value.is_channel_pending(): _UniffiConverterTypeChannelId.check_lower(value.channel_id) _UniffiConverterTypeUserChannelId.check_lower(value.user_channel_id) @@ -11499,70 +11608,79 @@ def write(value, buf): _UniffiConverterOptionalUInt64.write(value.skimmed_fee_msat, buf) _UniffiConverterBool.write(value.claim_from_onchain_tx, buf) _UniffiConverterOptionalUInt64.write(value.outbound_amount_forwarded_msat, buf) - if value.is_channel_pending(): + if value.is_probe_successful(): buf.write_i32(6) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + if value.is_probe_failed(): + buf.write_i32(7) + _UniffiConverterTypePaymentId.write(value.payment_id, buf) + _UniffiConverterTypePaymentHash.write(value.payment_hash, buf) + _UniffiConverterOptionalUInt64.write(value.short_channel_id, buf) + if value.is_channel_pending(): + buf.write_i32(8) _UniffiConverterTypeChannelId.write(value.channel_id, buf) _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) _UniffiConverterTypeChannelId.write(value.former_temporary_channel_id, buf) _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) _UniffiConverterTypeOutPoint.write(value.funding_txo, buf) if value.is_channel_ready(): - buf.write_i32(7) + buf.write_i32(9) _UniffiConverterTypeChannelId.write(value.channel_id, buf) _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) _UniffiConverterOptionalTypePublicKey.write(value.counterparty_node_id, buf) _UniffiConverterOptionalTypeOutPoint.write(value.funding_txo, buf) if value.is_channel_closed(): - buf.write_i32(8) + buf.write_i32(10) _UniffiConverterTypeChannelId.write(value.channel_id, buf) _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) _UniffiConverterOptionalTypePublicKey.write(value.counterparty_node_id, buf) _UniffiConverterOptionalTypeClosureReason.write(value.reason, buf) if value.is_splice_pending(): - buf.write_i32(9) + buf.write_i32(11) _UniffiConverterTypeChannelId.write(value.channel_id, buf) _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) _UniffiConverterTypeOutPoint.write(value.new_funding_txo, buf) if value.is_splice_failed(): - buf.write_i32(10) + buf.write_i32(12) _UniffiConverterTypeChannelId.write(value.channel_id, buf) _UniffiConverterTypeUserChannelId.write(value.user_channel_id, buf) _UniffiConverterTypePublicKey.write(value.counterparty_node_id, buf) _UniffiConverterOptionalTypeOutPoint.write(value.abandoned_funding_txo, buf) if value.is_onchain_transaction_confirmed(): - buf.write_i32(11) + buf.write_i32(13) _UniffiConverterTypeTxid.write(value.txid, buf) _UniffiConverterTypeBlockHash.write(value.block_hash, buf) _UniffiConverterUInt32.write(value.block_height, buf) _UniffiConverterUInt64.write(value.confirmation_time, buf) _UniffiConverterTypeTransactionDetails.write(value.details, buf) if value.is_onchain_transaction_received(): - buf.write_i32(12) + buf.write_i32(14) _UniffiConverterTypeTxid.write(value.txid, buf) _UniffiConverterTypeTransactionDetails.write(value.details, buf) if value.is_onchain_transaction_replaced(): - buf.write_i32(13) + buf.write_i32(15) _UniffiConverterTypeTxid.write(value.txid, buf) _UniffiConverterSequenceTypeTxid.write(value.conflicts, buf) if value.is_onchain_transaction_reorged(): - buf.write_i32(14) + buf.write_i32(16) _UniffiConverterTypeTxid.write(value.txid, buf) if value.is_onchain_transaction_evicted(): - buf.write_i32(15) + buf.write_i32(17) _UniffiConverterTypeTxid.write(value.txid, buf) if value.is_sync_progress(): - buf.write_i32(16) + buf.write_i32(18) _UniffiConverterTypeSyncType.write(value.sync_type, buf) _UniffiConverterUInt8.write(value.progress_percent, buf) _UniffiConverterUInt32.write(value.current_block_height, buf) _UniffiConverterUInt32.write(value.target_block_height, buf) if value.is_sync_completed(): - buf.write_i32(17) + buf.write_i32(19) _UniffiConverterTypeSyncType.write(value.sync_type, buf) _UniffiConverterUInt32.write(value.synced_block_height, buf) if value.is_balance_changed(): - buf.write_i32(18) + buf.write_i32(20) _UniffiConverterUInt64.write(value.old_spendable_onchain_balance_sats, buf) _UniffiConverterUInt64.write(value.new_spendable_onchain_balance_sats, buf) _UniffiConverterUInt64.write(value.old_total_onchain_balance_sats, buf) @@ -15643,6 +15761,31 @@ def read(cls, buf): +class _UniffiConverterSequenceTypeProbeHandle(_UniffiConverterRustBuffer): + @classmethod + def check_lower(cls, value): + for item in value: + _UniffiConverterTypeProbeHandle.check_lower(item) + + @classmethod + def write(cls, value, buf): + items = len(value) + buf.write_i32(items) + for item in value: + _UniffiConverterTypeProbeHandle.write(item, buf) + + @classmethod + def read(cls, buf): + count = buf.read_i32() + if count < 0: + raise InternalError("Unexpected negative sequence length") + + return [ + _UniffiConverterTypeProbeHandle.read(buf) for i in range(count) + ] + + + class _UniffiConverterSequenceTypeRouteHintHop(_UniffiConverterRustBuffer): @classmethod def check_lower(cls, value): @@ -16609,6 +16752,7 @@ def generate_entropy_mnemonic(word_count: "typing.Optional[WordCount]") -> "Mnem "OutPoint", "PaymentDetails", "PeerDetails", + "ProbeHandle", "RouteHintHop", "RouteParametersConfig", "RoutingFees", diff --git a/bindings/swift/Sources/LDKNode/LDKNode.swift b/bindings/swift/Sources/LDKNode/LDKNode.swift index 12dc76ce2..6df5b6859 100644 --- a/bindings/swift/Sources/LDKNode/LDKNode.swift +++ b/bindings/swift/Sources/LDKNode/LDKNode.swift @@ -850,9 +850,9 @@ public protocol Bolt11PaymentProtocol: AnyObject { func send(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws -> PaymentId - func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws + func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] - func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws + func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] func sendUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> PaymentId } @@ -1021,21 +1021,21 @@ open class Bolt11Payment: }) } - open func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { + open func sendProbes(invoice: Bolt11Invoice, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] { + return try FfiConverterSequenceTypeProbeHandle.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { uniffi_ldk_node_fn_method_bolt11payment_send_probes(self.uniffiClonePointer(), FfiConverterTypeBolt11Invoice.lower(invoice), FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) - } + }) } - open func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { + open func sendProbesUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> [ProbeHandle] { + return try FfiConverterSequenceTypeProbeHandle.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { uniffi_ldk_node_fn_method_bolt11payment_send_probes_using_amount(self.uniffiClonePointer(), FfiConverterTypeBolt11Invoice.lower(invoice), FfiConverterUInt64.lower(amountMsat), FfiConverterOptionTypeRouteParametersConfig.lower(routeParameters), $0) - } + }) } open func sendUsingAmount(invoice: Bolt11Invoice, amountMsat: UInt64, routeParameters: RouteParametersConfig?) throws -> PaymentId { @@ -3727,7 +3727,7 @@ public func FfiConverterTypeRefund_lower(_ value: Refund) -> UnsafeMutableRawPoi public protocol SpontaneousPaymentProtocol: AnyObject { func send(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?) throws -> PaymentId - func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws + func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws -> [ProbeHandle] func sendWithCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?, customTlvs: [CustomTlvRecord]) throws -> PaymentId @@ -3794,12 +3794,12 @@ open class SpontaneousPayment: }) } - open func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws { - try rustCallWithError(FfiConverterTypeNodeError.lift) { + open func sendProbes(amountMsat: UInt64, nodeId: PublicKey) throws -> [ProbeHandle] { + return try FfiConverterSequenceTypeProbeHandle.lift(rustCallWithError(FfiConverterTypeNodeError.lift) { uniffi_ldk_node_fn_method_spontaneouspayment_send_probes(self.uniffiClonePointer(), FfiConverterUInt64.lower(amountMsat), FfiConverterTypePublicKey.lower(nodeId), $0) - } + }) } open func sendWithCustomTlvs(amountMsat: UInt64, nodeId: PublicKey, routeParameters: RouteParametersConfig?, customTlvs: [CustomTlvRecord]) throws -> PaymentId { @@ -6552,6 +6552,67 @@ public func FfiConverterTypePeerDetails_lower(_ value: PeerDetails) -> RustBuffe return FfiConverterTypePeerDetails.lower(value) } +public struct ProbeHandle { + public var paymentHash: PaymentHash + public var paymentId: PaymentId + + /// Default memberwise initializers are never public by default, so we + /// declare one manually. + public init(paymentHash: PaymentHash, paymentId: PaymentId) { + self.paymentHash = paymentHash + self.paymentId = paymentId + } +} + +extension ProbeHandle: Equatable, Hashable { + public static func == (lhs: ProbeHandle, rhs: ProbeHandle) -> Bool { + if lhs.paymentHash != rhs.paymentHash { + return false + } + if lhs.paymentId != rhs.paymentId { + return false + } + return true + } + + public func hash(into hasher: inout Hasher) { + hasher.combine(paymentHash) + hasher.combine(paymentId) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public struct FfiConverterTypeProbeHandle: FfiConverterRustBuffer { + public static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> ProbeHandle { + return + try ProbeHandle( + paymentHash: FfiConverterTypePaymentHash.read(from: &buf), + paymentId: FfiConverterTypePaymentId.read(from: &buf) + ) + } + + public static func write(_ value: ProbeHandle, into buf: inout [UInt8]) { + FfiConverterTypePaymentHash.write(value.paymentHash, into: &buf) + FfiConverterTypePaymentId.write(value.paymentId, into: &buf) + } +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeProbeHandle_lift(_ buf: RustBuffer) throws -> ProbeHandle { + return try FfiConverterTypeProbeHandle.lift(buf) +} + +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +public func FfiConverterTypeProbeHandle_lower(_ value: ProbeHandle) -> RustBuffer { + return FfiConverterTypeProbeHandle.lower(value) +} + public struct RouteHintHop { public var srcNodeId: PublicKey public var shortChannelId: UInt64 @@ -7886,6 +7947,8 @@ public enum Event { case paymentReceived(paymentId: PaymentId?, paymentHash: PaymentHash, amountMsat: UInt64, customRecords: [CustomTlvRecord]) case paymentClaimable(paymentId: PaymentId, paymentHash: PaymentHash, claimableAmountMsat: UInt64, claimDeadline: UInt32?, customRecords: [CustomTlvRecord]) case paymentForwarded(prevChannelId: ChannelId, nextChannelId: ChannelId, prevUserChannelId: UserChannelId?, nextUserChannelId: UserChannelId?, prevNodeId: PublicKey?, nextNodeId: PublicKey?, totalFeeEarnedMsat: UInt64?, skimmedFeeMsat: UInt64?, claimFromOnchainTx: Bool, outboundAmountForwardedMsat: UInt64?) + case probeSuccessful(paymentId: PaymentId, paymentHash: PaymentHash) + case probeFailed(paymentId: PaymentId, paymentHash: PaymentHash, shortChannelId: UInt64?) case channelPending(channelId: ChannelId, userChannelId: UserChannelId, formerTemporaryChannelId: ChannelId, counterpartyNodeId: PublicKey, fundingTxo: OutPoint) case channelReady(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey?, fundingTxo: OutPoint?) case channelClosed(channelId: ChannelId, userChannelId: UserChannelId, counterpartyNodeId: PublicKey?, reason: ClosureReason?) @@ -7920,31 +7983,35 @@ public struct FfiConverterTypeEvent: FfiConverterRustBuffer { case 5: return try .paymentForwarded(prevChannelId: FfiConverterTypeChannelId.read(from: &buf), nextChannelId: FfiConverterTypeChannelId.read(from: &buf), prevUserChannelId: FfiConverterOptionTypeUserChannelId.read(from: &buf), nextUserChannelId: FfiConverterOptionTypeUserChannelId.read(from: &buf), prevNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), nextNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), totalFeeEarnedMsat: FfiConverterOptionUInt64.read(from: &buf), skimmedFeeMsat: FfiConverterOptionUInt64.read(from: &buf), claimFromOnchainTx: FfiConverterBool.read(from: &buf), outboundAmountForwardedMsat: FfiConverterOptionUInt64.read(from: &buf)) - case 6: return try .channelPending(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), formerTemporaryChannelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), fundingTxo: FfiConverterTypeOutPoint.read(from: &buf)) + case 6: return try .probeSuccessful(paymentId: FfiConverterTypePaymentId.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf)) + + case 7: return try .probeFailed(paymentId: FfiConverterTypePaymentId.read(from: &buf), paymentHash: FfiConverterTypePaymentHash.read(from: &buf), shortChannelId: FfiConverterOptionUInt64.read(from: &buf)) - case 7: return try .channelReady(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), fundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf)) + case 8: return try .channelPending(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), formerTemporaryChannelId: FfiConverterTypeChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), fundingTxo: FfiConverterTypeOutPoint.read(from: &buf)) - case 8: return try .channelClosed(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), reason: FfiConverterOptionTypeClosureReason.read(from: &buf)) + case 9: return try .channelReady(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), fundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf)) - case 9: return try .splicePending(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), newFundingTxo: FfiConverterTypeOutPoint.read(from: &buf)) + case 10: return try .channelClosed(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterOptionTypePublicKey.read(from: &buf), reason: FfiConverterOptionTypeClosureReason.read(from: &buf)) - case 10: return try .spliceFailed(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), abandonedFundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf)) + case 11: return try .splicePending(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), newFundingTxo: FfiConverterTypeOutPoint.read(from: &buf)) - case 11: return try .onchainTransactionConfirmed(txid: FfiConverterTypeTxid.read(from: &buf), blockHash: FfiConverterTypeBlockHash.read(from: &buf), blockHeight: FfiConverterUInt32.read(from: &buf), confirmationTime: FfiConverterUInt64.read(from: &buf), details: FfiConverterTypeTransactionDetails.read(from: &buf)) + case 12: return try .spliceFailed(channelId: FfiConverterTypeChannelId.read(from: &buf), userChannelId: FfiConverterTypeUserChannelId.read(from: &buf), counterpartyNodeId: FfiConverterTypePublicKey.read(from: &buf), abandonedFundingTxo: FfiConverterOptionTypeOutPoint.read(from: &buf)) - case 12: return try .onchainTransactionReceived(txid: FfiConverterTypeTxid.read(from: &buf), details: FfiConverterTypeTransactionDetails.read(from: &buf)) + case 13: return try .onchainTransactionConfirmed(txid: FfiConverterTypeTxid.read(from: &buf), blockHash: FfiConverterTypeBlockHash.read(from: &buf), blockHeight: FfiConverterUInt32.read(from: &buf), confirmationTime: FfiConverterUInt64.read(from: &buf), details: FfiConverterTypeTransactionDetails.read(from: &buf)) - case 13: return try .onchainTransactionReplaced(txid: FfiConverterTypeTxid.read(from: &buf), conflicts: FfiConverterSequenceTypeTxid.read(from: &buf)) + case 14: return try .onchainTransactionReceived(txid: FfiConverterTypeTxid.read(from: &buf), details: FfiConverterTypeTransactionDetails.read(from: &buf)) - case 14: return try .onchainTransactionReorged(txid: FfiConverterTypeTxid.read(from: &buf)) + case 15: return try .onchainTransactionReplaced(txid: FfiConverterTypeTxid.read(from: &buf), conflicts: FfiConverterSequenceTypeTxid.read(from: &buf)) - case 15: return try .onchainTransactionEvicted(txid: FfiConverterTypeTxid.read(from: &buf)) + case 16: return try .onchainTransactionReorged(txid: FfiConverterTypeTxid.read(from: &buf)) - case 16: return try .syncProgress(syncType: FfiConverterTypeSyncType.read(from: &buf), progressPercent: FfiConverterUInt8.read(from: &buf), currentBlockHeight: FfiConverterUInt32.read(from: &buf), targetBlockHeight: FfiConverterUInt32.read(from: &buf)) + case 17: return try .onchainTransactionEvicted(txid: FfiConverterTypeTxid.read(from: &buf)) - case 17: return try .syncCompleted(syncType: FfiConverterTypeSyncType.read(from: &buf), syncedBlockHeight: FfiConverterUInt32.read(from: &buf)) + case 18: return try .syncProgress(syncType: FfiConverterTypeSyncType.read(from: &buf), progressPercent: FfiConverterUInt8.read(from: &buf), currentBlockHeight: FfiConverterUInt32.read(from: &buf), targetBlockHeight: FfiConverterUInt32.read(from: &buf)) - case 18: return try .balanceChanged(oldSpendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), newSpendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), oldTotalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), newTotalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), oldTotalLightningBalanceSats: FfiConverterUInt64.read(from: &buf), newTotalLightningBalanceSats: FfiConverterUInt64.read(from: &buf)) + case 19: return try .syncCompleted(syncType: FfiConverterTypeSyncType.read(from: &buf), syncedBlockHeight: FfiConverterUInt32.read(from: &buf)) + + case 20: return try .balanceChanged(oldSpendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), newSpendableOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), oldTotalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), newTotalOnchainBalanceSats: FfiConverterUInt64.read(from: &buf), oldTotalLightningBalanceSats: FfiConverterUInt64.read(from: &buf), newTotalLightningBalanceSats: FfiConverterUInt64.read(from: &buf)) default: throw UniffiInternalError.unexpectedEnumCase } @@ -7993,8 +8060,19 @@ public struct FfiConverterTypeEvent: FfiConverterRustBuffer { FfiConverterBool.write(claimFromOnchainTx, into: &buf) FfiConverterOptionUInt64.write(outboundAmountForwardedMsat, into: &buf) - case let .channelPending(channelId, userChannelId, formerTemporaryChannelId, counterpartyNodeId, fundingTxo): + case let .probeSuccessful(paymentId, paymentHash): writeInt(&buf, Int32(6)) + FfiConverterTypePaymentId.write(paymentId, into: &buf) + FfiConverterTypePaymentHash.write(paymentHash, into: &buf) + + case let .probeFailed(paymentId, paymentHash, shortChannelId): + writeInt(&buf, Int32(7)) + FfiConverterTypePaymentId.write(paymentId, into: &buf) + FfiConverterTypePaymentHash.write(paymentHash, into: &buf) + FfiConverterOptionUInt64.write(shortChannelId, into: &buf) + + case let .channelPending(channelId, userChannelId, formerTemporaryChannelId, counterpartyNodeId, fundingTxo): + writeInt(&buf, Int32(8)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterTypeChannelId.write(formerTemporaryChannelId, into: &buf) @@ -8002,35 +8080,35 @@ public struct FfiConverterTypeEvent: FfiConverterRustBuffer { FfiConverterTypeOutPoint.write(fundingTxo, into: &buf) case let .channelReady(channelId, userChannelId, counterpartyNodeId, fundingTxo): - writeInt(&buf, Int32(7)) + writeInt(&buf, Int32(9)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterOptionTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterOptionTypeOutPoint.write(fundingTxo, into: &buf) case let .channelClosed(channelId, userChannelId, counterpartyNodeId, reason): - writeInt(&buf, Int32(8)) + writeInt(&buf, Int32(10)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterOptionTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterOptionTypeClosureReason.write(reason, into: &buf) case let .splicePending(channelId, userChannelId, counterpartyNodeId, newFundingTxo): - writeInt(&buf, Int32(9)) + writeInt(&buf, Int32(11)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterTypeOutPoint.write(newFundingTxo, into: &buf) case let .spliceFailed(channelId, userChannelId, counterpartyNodeId, abandonedFundingTxo): - writeInt(&buf, Int32(10)) + writeInt(&buf, Int32(12)) FfiConverterTypeChannelId.write(channelId, into: &buf) FfiConverterTypeUserChannelId.write(userChannelId, into: &buf) FfiConverterTypePublicKey.write(counterpartyNodeId, into: &buf) FfiConverterOptionTypeOutPoint.write(abandonedFundingTxo, into: &buf) case let .onchainTransactionConfirmed(txid, blockHash, blockHeight, confirmationTime, details): - writeInt(&buf, Int32(11)) + writeInt(&buf, Int32(13)) FfiConverterTypeTxid.write(txid, into: &buf) FfiConverterTypeBlockHash.write(blockHash, into: &buf) FfiConverterUInt32.write(blockHeight, into: &buf) @@ -8038,37 +8116,37 @@ public struct FfiConverterTypeEvent: FfiConverterRustBuffer { FfiConverterTypeTransactionDetails.write(details, into: &buf) case let .onchainTransactionReceived(txid, details): - writeInt(&buf, Int32(12)) + writeInt(&buf, Int32(14)) FfiConverterTypeTxid.write(txid, into: &buf) FfiConverterTypeTransactionDetails.write(details, into: &buf) case let .onchainTransactionReplaced(txid, conflicts): - writeInt(&buf, Int32(13)) + writeInt(&buf, Int32(15)) FfiConverterTypeTxid.write(txid, into: &buf) FfiConverterSequenceTypeTxid.write(conflicts, into: &buf) case let .onchainTransactionReorged(txid): - writeInt(&buf, Int32(14)) + writeInt(&buf, Int32(16)) FfiConverterTypeTxid.write(txid, into: &buf) case let .onchainTransactionEvicted(txid): - writeInt(&buf, Int32(15)) + writeInt(&buf, Int32(17)) FfiConverterTypeTxid.write(txid, into: &buf) case let .syncProgress(syncType, progressPercent, currentBlockHeight, targetBlockHeight): - writeInt(&buf, Int32(16)) + writeInt(&buf, Int32(18)) FfiConverterTypeSyncType.write(syncType, into: &buf) FfiConverterUInt8.write(progressPercent, into: &buf) FfiConverterUInt32.write(currentBlockHeight, into: &buf) FfiConverterUInt32.write(targetBlockHeight, into: &buf) case let .syncCompleted(syncType, syncedBlockHeight): - writeInt(&buf, Int32(17)) + writeInt(&buf, Int32(19)) FfiConverterTypeSyncType.write(syncType, into: &buf) FfiConverterUInt32.write(syncedBlockHeight, into: &buf) case let .balanceChanged(oldSpendableOnchainBalanceSats, newSpendableOnchainBalanceSats, oldTotalOnchainBalanceSats, newTotalOnchainBalanceSats, oldTotalLightningBalanceSats, newTotalLightningBalanceSats): - writeInt(&buf, Int32(18)) + writeInt(&buf, Int32(20)) FfiConverterUInt64.write(oldSpendableOnchainBalanceSats, into: &buf) FfiConverterUInt64.write(newSpendableOnchainBalanceSats, into: &buf) FfiConverterUInt64.write(oldTotalOnchainBalanceSats, into: &buf) @@ -10939,6 +11017,31 @@ private struct FfiConverterSequenceTypePeerDetails: FfiConverterRustBuffer { } } +#if swift(>=5.8) + @_documentation(visibility: private) +#endif +private struct FfiConverterSequenceTypeProbeHandle: FfiConverterRustBuffer { + typealias SwiftType = [ProbeHandle] + + static func write(_ value: [ProbeHandle], into buf: inout [UInt8]) { + let len = Int32(value.count) + writeInt(&buf, len) + for item in value { + FfiConverterTypeProbeHandle.write(item, into: &buf) + } + } + + static func read(from buf: inout (data: Data, offset: Data.Index)) throws -> [ProbeHandle] { + let len: Int32 = try readInt(&buf) + var seq = [ProbeHandle]() + seq.reserveCapacity(Int(len)) + for _ in 0 ..< len { + try seq.append(FfiConverterTypeProbeHandle.read(from: &buf)) + } + return seq + } +} + #if swift(>=5.8) @_documentation(visibility: private) #endif @@ -12269,10 +12372,10 @@ private var initializationResult: InitializationResult = { if uniffi_ldk_node_checksum_method_bolt11payment_send() != 12953 { return InitializationResult.apiChecksumMismatch } - if uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 19286 { + if uniffi_ldk_node_checksum_method_bolt11payment_send_probes() != 16067 { return InitializationResult.apiChecksumMismatch } - if uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 5976 { + if uniffi_ldk_node_checksum_method_bolt11payment_send_probes_using_amount() != 37281 { return InitializationResult.apiChecksumMismatch } if uniffi_ldk_node_checksum_method_bolt11payment_send_using_amount() != 42793 { @@ -12734,7 +12837,7 @@ private var initializationResult: InitializationResult = { if uniffi_ldk_node_checksum_method_spontaneouspayment_send() != 27905 { return InitializationResult.apiChecksumMismatch } - if uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 25937 { + if uniffi_ldk_node_checksum_method_spontaneouspayment_send_probes() != 44206 { return InitializationResult.apiChecksumMismatch } if uniffi_ldk_node_checksum_method_spontaneouspayment_send_with_custom_tlvs() != 17876 { diff --git a/src/event.rs b/src/event.rs index c60076611..f33da9559 100644 --- a/src/event.rs +++ b/src/event.rs @@ -418,6 +418,22 @@ pub enum Event { /// Custom TLV records attached to the payment custom_records: Vec, }, + /// A sent payment probe was successful. + ProbeSuccessful { + /// A local identifier used to track the probe. + payment_id: PaymentId, + /// The hash of the probe payment. + payment_hash: PaymentHash, + }, + /// A sent payment probe has failed. + ProbeFailed { + /// A local identifier used to track the probe. + payment_id: PaymentId, + /// The hash of the probe payment. + payment_hash: PaymentHash, + /// The channel responsible for the failed probe, if known. + short_channel_id: Option, + }, /// A channel has been created and is pending confirmation on-chain. ChannelPending { /// The `channel_id` of the channel. @@ -944,6 +960,15 @@ impl_writeable_tlv_based_enum!(Event, (6, new_total_onchain_balance_sats, required), (8, old_total_lightning_balance_sats, required), (10, new_total_lightning_balance_sats, required), + }, + (18, ProbeSuccessful) => { + (0, payment_hash, required), + (2, payment_id, required), + }, + (19, ProbeFailed) => { + (0, payment_hash, required), + (1, short_channel_id, option), + (3, payment_id, required), } ); @@ -1779,8 +1804,26 @@ where LdkEvent::PaymentPathSuccessful { .. } => {}, LdkEvent::PaymentPathFailed { .. } => {}, - LdkEvent::ProbeSuccessful { .. } => {}, - LdkEvent::ProbeFailed { .. } => {}, + LdkEvent::ProbeSuccessful { payment_id, payment_hash, .. } => { + let event = Event::ProbeSuccessful { payment_id, payment_hash }; + match self.event_queue.add_event(event).await { + Ok(_) => {}, + Err(e) => { + log_error!(self.logger, "Failed to push probe event: {}", e); + return Err(ReplayEvent()); + }, + } + }, + LdkEvent::ProbeFailed { payment_id, payment_hash, short_channel_id, .. } => { + let event = Event::ProbeFailed { payment_id, payment_hash, short_channel_id }; + match self.event_queue.add_event(event).await { + Ok(_) => {}, + Err(e) => { + log_error!(self.logger, "Failed to push probe event: {}", e); + return Err(ReplayEvent()); + }, + } + }, LdkEvent::HTLCHandlingFailed { failure_type, .. } => { if let Some(liquidity_source) = self.liquidity_source.as_ref() { liquidity_source.handle_htlc_handling_failed(failure_type).await; @@ -2573,4 +2616,40 @@ mod tests { } assert_eq!(event_queue.next_event(), None); } + + #[tokio::test] + async fn probe_events_persistence_roundtrip() { + let store: Arc = Arc::new(InMemoryStore::new()); + let logger = Arc::new(TestLogger::new()); + let event_queue = Arc::new(EventQueue::new(Arc::clone(&store), Arc::clone(&logger))); + + assert_eq!(event_queue.next_event(), None); + + let payment_hash = PaymentHash([7u8; 32]); + let payment_id = PaymentId(payment_hash.0); + let expected_event = + Event::ProbeFailed { payment_id, payment_hash, short_channel_id: Some(42) }; + + event_queue.add_event(expected_event.clone()).await.unwrap(); + + // Check we get the expected event and that it is returned until handled. + assert_eq!(event_queue.next_event_async().await, expected_event); + assert_eq!(event_queue.next_event(), Some(expected_event.clone())); + + // Check we can read back what we persisted. + let persisted_bytes = KVStore::read( + &*store, + EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE, + EVENT_QUEUE_PERSISTENCE_SECONDARY_NAMESPACE, + EVENT_QUEUE_PERSISTENCE_KEY, + ) + .await + .unwrap(); + let deser_event_queue = + EventQueue::read(&mut &persisted_bytes[..], (Arc::clone(&store), logger)).unwrap(); + assert_eq!(deser_event_queue.next_event_async().await, expected_event); + + event_queue.event_handled().await.unwrap(); + assert_eq!(event_queue.next_event(), None); + } } diff --git a/src/lib.rs b/src/lib.rs index 7300bf411..8497b5c33 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -96,6 +96,7 @@ pub mod logger; mod message_handler; pub mod payment; mod peer_store; +mod probe_handle; mod runtime; mod scoring; mod tx_broadcaster; @@ -161,6 +162,7 @@ use payment::{ UnifiedQrPayment, }; use peer_store::{PeerInfo, PeerStore}; +pub use probe_handle::ProbeHandle; use rand::Rng; use runtime::Runtime; use types::{ diff --git a/src/payment/bolt11.rs b/src/payment/bolt11.rs index 9b256d3be..eb79439c0 100644 --- a/src/payment/bolt11.rs +++ b/src/payment/bolt11.rs @@ -38,6 +38,7 @@ use crate::payment::store::{ use crate::peer_store::{PeerInfo, PeerStore}; use crate::runtime::Runtime; use crate::types::{ChannelManager, PaymentStore, Router}; +use crate::ProbeHandle; #[cfg(not(feature = "uniffi"))] type Bolt11Invoice = LdkBolt11Invoice; #[cfg(feature = "uniffi")] @@ -834,9 +835,13 @@ impl Bolt11Payment { /// /// If `route_parameters` are provided they will override the default as well as the /// node-wide parameters configured via [`Config::route_parameters`] on a per-field basis. + /// + /// Returns one [`ProbeHandle`] per probe path. Use [`ProbeHandle::payment_id`] (and/or + /// [`ProbeHandle::payment_hash`]) to match [`crate::Event::ProbeSuccessful`] / + /// [`crate::Event::ProbeFailed`]. These values are **not** the invoice payment hash. pub fn send_probes( &self, invoice: &Bolt11Invoice, route_parameters: Option, - ) -> Result<(), Error> { + ) -> Result, Error> { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); } @@ -870,12 +875,16 @@ impl Bolt11Payment { self.channel_manager .send_preflight_probes(route_params, liquidity_limit_multiplier) + .map(|pairs| { + pairs + .into_iter() + .map(|(payment_hash, payment_id)| ProbeHandle { payment_hash, payment_id }) + .collect() + }) .map_err(|e| { log_error!(self.logger, "Failed to send payment probes: {:?}", e); Error::ProbeSendingFailed - })?; - - Ok(()) + }) } /// Sends payment probes over all paths of a route that would be used to pay the given @@ -887,11 +896,11 @@ impl Bolt11Payment { /// If `route_parameters` are provided they will override the default as well as the /// node-wide parameters configured via [`Config::route_parameters`] on a per-field basis. /// - /// See [`Self::send_probes`] for more information. + /// See [`Self::send_probes`] for return value semantics and correlation with probe events. pub fn send_probes_using_amount( &self, invoice: &Bolt11Invoice, amount_msat: u64, route_parameters: Option, - ) -> Result<(), Error> { + ) -> Result, Error> { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); } @@ -932,12 +941,16 @@ impl Bolt11Payment { self.channel_manager .send_preflight_probes(route_params, liquidity_limit_multiplier) + .map(|pairs| { + pairs + .into_iter() + .map(|(payment_hash, payment_id)| ProbeHandle { payment_hash, payment_id }) + .collect() + }) .map_err(|e| { log_error!(self.logger, "Failed to send payment probes: {:?}", e); Error::ProbeSendingFailed - })?; - - Ok(()) + }) } /// Estimates the routing fees for a given invoice. diff --git a/src/payment/spontaneous.rs b/src/payment/spontaneous.rs index 6c074f308..251d57970 100644 --- a/src/payment/spontaneous.rs +++ b/src/payment/spontaneous.rs @@ -20,6 +20,7 @@ use crate::error::Error; use crate::logger::{log_error, log_info, LdkLogger, Logger}; use crate::payment::store::{PaymentDetails, PaymentDirection, PaymentKind, PaymentStatus}; use crate::types::{ChannelManager, CustomTlvRecord, KeysManager, PaymentStore}; +use crate::ProbeHandle; // The default `final_cltv_expiry_delta` we apply when not set. const LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA: u32 = 144; @@ -191,10 +192,13 @@ impl SpontaneousPayment { /// Sends payment probes over all paths of a route that would be used to pay the given /// amount to the given `node_id`. /// - /// See [`Bolt11Payment::send_probes`] for more information. + /// See [`Bolt11Payment::send_probes`] for semantics and how returned [`ProbeHandle`] values + /// correlate with [`crate::Event::ProbeSuccessful`] / [`crate::Event::ProbeFailed`]. /// /// [`Bolt11Payment::send_probes`]: crate::payment::Bolt11Payment - pub fn send_probes(&self, amount_msat: u64, node_id: PublicKey) -> Result<(), Error> { + pub fn send_probes( + &self, amount_msat: u64, node_id: PublicKey, + ) -> Result, Error> { if !*self.is_running.read().unwrap() { return Err(Error::NotRunning); } @@ -208,11 +212,15 @@ impl SpontaneousPayment { LDK_DEFAULT_FINAL_CLTV_EXPIRY_DELTA, liquidity_limit_multiplier, ) + .map(|pairs| { + pairs + .into_iter() + .map(|(payment_hash, payment_id)| ProbeHandle { payment_hash, payment_id }) + .collect() + }) .map_err(|e| { log_error!(self.logger, "Failed to send payment probes: {:?}", e); Error::ProbeSendingFailed - })?; - - Ok(()) + }) } } diff --git a/src/probe_handle.rs b/src/probe_handle.rs new file mode 100644 index 000000000..d5ac5e582 --- /dev/null +++ b/src/probe_handle.rs @@ -0,0 +1,29 @@ +// This file is Copyright its original authors, visible in version control history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license , at your option. You may not use this file except in +// accordance with one or both of these licenses. + +//! Handle returned when sending pre-flight probes. +//! +//! UniFFI uses `dictionary ProbeHandle` in `bindings/ldk_node.udl`; this module defines the Rust +//! struct with the same fields. With `feature = "uniffi"`, `lib.rs` must `pub use` this type +//! **before** `uniffi::include_scaffolding!` so the generated `FfiConverter` impl applies here (same +//! pattern as [`crate::SpendableUtxo`], [`crate::PeerDetails`], etc.). + +use lightning::ln::channelmanager::PaymentId; +use lightning_types::payment::PaymentHash; + +/// Identifies one outbound probe; match against [`crate::Event::ProbeSuccessful`] / +/// [`crate::Event::ProbeFailed`] using [`Self::payment_id`] and/or [`Self::payment_hash`]. +/// +/// The [`PaymentHash`] is **not** the BOLT11 invoice payment hash; LDK generates a synthetic hash +/// per probe. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ProbeHandle { + /// Synthetic probe payment hash (not the BOLT11 invoice payment hash). + pub payment_hash: PaymentHash, + /// Local id for this probe; matches probe [`crate::Event`] variants. + pub payment_id: PaymentId, +}