From a97e5776b1d4ccaf9ae1de44a2208b18d2a21453 Mon Sep 17 00:00:00 2001 From: Pierre-Marie Padiou Date: Thu, 16 May 2024 18:07:36 +0200 Subject: [PATCH] Update lightning-kmp to 1.6.2-FEECREDIT-7 (#51) --- buildSrc/src/main/kotlin/Versions.kt | 2 +- .../kotlin/fr/acinq/lightning/bin/Api.kt | 3 +- .../lightning/bin/db/SqlitePaymentsDb.kt | 2 +- .../bin/db/payments/IncomingOriginType.kt | 1 + .../payments/LightningOutgoingDetailsType.kt | 10 +--- .../LightningOutgoingPartStatusType.kt | 52 +++++++++++++++++-- .../db/payments/LightningOutgoingQueries.kt | 4 +- .../payments/LightningOutgoingStatusType.kt | 6 ++- .../lightning/bin/json/JsonSerializers.kt | 2 +- 9 files changed, 63 insertions(+), 19 deletions(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 1eae033..e11cee1 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,6 +1,6 @@ object Versions { val kotlin = "1.9.23" - val lightningKmp = "1.6.2-FEECREDIT-6" + val lightningKmp = "1.6.2-FEECREDIT-7" val sqlDelight = "2.0.1" val okio = "3.8.0" val clikt = "4.2.2" diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/Api.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/Api.kt index 84352ff..acb3b5c 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/Api.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/Api.kt @@ -160,9 +160,10 @@ class Api(private val nodeParams: NodeParams, private val peer: Peer, private va val overrideAmount = formParameters["amountSat"]?.let { it.toLongOrNull() ?: invalidType("amountSat", "integer") }?.sat?.toMilliSatoshi() val invoice = formParameters.getInvoice("invoice") val amount = (overrideAmount ?: invoice.amount) ?: missing("amountSat") - when (val event = peer.sendLightning(amount, invoice)) { + when (val event = peer.payInvoice(amount, invoice)) { is fr.acinq.lightning.io.PaymentSent -> call.respond(PaymentSent(event)) is fr.acinq.lightning.io.PaymentNotSent -> call.respond(PaymentFailed(event)) + is fr.acinq.lightning.io.OfferNotPaid -> TODO() } } post("sendtoaddress") { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/SqlitePaymentsDb.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/SqlitePaymentsDb.kt index aaea790..562779d 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/SqlitePaymentsDb.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/SqlitePaymentsDb.kt @@ -120,7 +120,7 @@ class SqlitePaymentsDb(val database: PhoenixDatabase) : PaymentsDb { override suspend fun completeOutgoingLightningPart( partId: UUID, - failure: Either, + failure: LightningOutgoingPayment.Part.Status.Failure, completedAt: Long ) { withContext(Dispatchers.Default) { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/IncomingOriginType.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/IncomingOriginType.kt index 2539c79..3650a11 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/IncomingOriginType.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/IncomingOriginType.kt @@ -88,4 +88,5 @@ fun IncomingPayment.Origin.mapToDb(): Pair Json.encodeToString(IncomingOriginData.SwapIn.V0(address)).toByteArray(Charsets.UTF_8) is IncomingPayment.Origin.OnChain -> IncomingOriginTypeVersion.ONCHAIN_V0 to Json.encodeToString(IncomingOriginData.OnChain.V0(txId.value, localInputs.toList())).toByteArray(Charsets.UTF_8) + is IncomingPayment.Origin.Offer -> TODO() } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingDetailsType.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingDetailsType.kt index 1af6ea2..da6e824 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingDetailsType.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingDetailsType.kt @@ -37,7 +37,6 @@ import kotlinx.serialization.json.Json enum class LightningOutgoingDetailsTypeVersion { NORMAL_V0, - KEYSEND_V0, SWAPOUT_V0, } @@ -48,11 +47,6 @@ sealed class LightningOutgoingDetailsData { data class V0(val paymentRequest: String) : Normal() } - sealed class KeySend : LightningOutgoingDetailsData() { - @Serializable - data class V0(@Serializable val preimage: ByteVector32) : KeySend() - } - sealed class SwapOut : LightningOutgoingDetailsData() { @Serializable data class V0(val address: String, val paymentRequest: String, @Serializable val swapOutFee: Satoshi) : SwapOut() @@ -63,7 +57,6 @@ sealed class LightningOutgoingDetailsData { fun deserialize(typeVersion: LightningOutgoingDetailsTypeVersion, blob: ByteArray): LightningOutgoingPayment.Details = DbTypesHelper.decodeBlob(blob) { json, format -> when (typeVersion) { LightningOutgoingDetailsTypeVersion.NORMAL_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.Normal(Bolt11Invoice.read(it.paymentRequest).get()) } - LightningOutgoingDetailsTypeVersion.KEYSEND_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.KeySend(it.preimage) } LightningOutgoingDetailsTypeVersion.SWAPOUT_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.SwapOut(it.address, Bolt11Invoice.read(it.paymentRequest).get(), it.swapOutFee) } } } @@ -73,8 +66,7 @@ sealed class LightningOutgoingDetailsData { fun LightningOutgoingPayment.Details.mapToDb(): Pair = when (this) { is LightningOutgoingPayment.Details.Normal -> LightningOutgoingDetailsTypeVersion.NORMAL_V0 to Json.encodeToString(LightningOutgoingDetailsData.Normal.V0(paymentRequest.write())).toByteArray(Charsets.UTF_8) - is LightningOutgoingPayment.Details.KeySend -> LightningOutgoingDetailsTypeVersion.KEYSEND_V0 to - Json.encodeToString(LightningOutgoingDetailsData.KeySend.V0(preimage)).toByteArray(Charsets.UTF_8) is LightningOutgoingPayment.Details.SwapOut -> LightningOutgoingDetailsTypeVersion.SWAPOUT_V0 to Json.encodeToString(LightningOutgoingDetailsData.SwapOut.V0(address, paymentRequest.write(), swapOutFee)).toByteArray(Charsets.UTF_8) + is LightningOutgoingPayment.Details.Blinded -> TODO() } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingPartStatusType.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingPartStatusType.kt index e3e970d..b4ee595 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingPartStatusType.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingPartStatusType.kt @@ -33,7 +33,9 @@ import kotlinx.serialization.json.Json enum class LightningOutgoingPartStatusTypeVersion { SUCCEEDED_V0, + /* Obsolete, do not use anymore. Failed parts are now typed, with a code and an option string message. */ FAILED_V0, + FAILED_V1, } sealed class LightningOutgoingPartStatusData { @@ -46,6 +48,9 @@ sealed class LightningOutgoingPartStatusData { sealed class Failed : LightningOutgoingPartStatusData() { @Serializable data class V0(val remoteFailureCode: Int?, val details: String) : Failed() + + @Serializable + data class V1(val code: Int, val details: String?) : Failed() } companion object { @@ -58,7 +63,31 @@ sealed class LightningOutgoingPartStatusData { LightningOutgoingPayment.Part.Status.Succeeded(it.preimage, completedAt) } LightningOutgoingPartStatusTypeVersion.FAILED_V0 -> format.decodeFromString(json).let { - LightningOutgoingPayment.Part.Status.Failed(it.remoteFailureCode, it.details, completedAt) + LightningOutgoingPayment.Part.Status.Failed( + failure = LightningOutgoingPayment.Part.Status.Failure.Uninterpretable(message = it.details), + completedAt = completedAt, + ) + } + LightningOutgoingPartStatusTypeVersion.FAILED_V1 -> format.decodeFromString(json).let { + LightningOutgoingPayment.Part.Status.Failed( + failure = when (it.code) { + 0 -> LightningOutgoingPayment.Part.Status.Failure.Uninterpretable(it.details ?: "n/a") + 1 -> LightningOutgoingPayment.Part.Status.Failure.PaymentAmountTooSmall + 2 -> LightningOutgoingPayment.Part.Status.Failure.PaymentAmountTooBig + 3 -> LightningOutgoingPayment.Part.Status.Failure.NotEnoughFunds + 4 -> LightningOutgoingPayment.Part.Status.Failure.NotEnoughFees + 5 -> LightningOutgoingPayment.Part.Status.Failure.PaymentExpiryTooBig + 6 -> LightningOutgoingPayment.Part.Status.Failure.TooManyPendingPayments + 7 -> LightningOutgoingPayment.Part.Status.Failure.ChannelIsSplicing + 8 -> LightningOutgoingPayment.Part.Status.Failure.ChannelIsClosing + 9 -> LightningOutgoingPayment.Part.Status.Failure.TemporaryRemoteFailure + 10 -> LightningOutgoingPayment.Part.Status.Failure.RecipientLiquidityIssue + 11 -> LightningOutgoingPayment.Part.Status.Failure.RecipientIsOffline + 12 -> LightningOutgoingPayment.Part.Status.Failure.RecipientRejectedPayment + else -> LightningOutgoingPayment.Part.Status.Failure.Uninterpretable(it.details ?: "n/a") + }, + completedAt = completedAt, + ) } } } @@ -68,5 +97,22 @@ sealed class LightningOutgoingPartStatusData { fun LightningOutgoingPayment.Part.Status.Succeeded.mapToDb() = LightningOutgoingPartStatusTypeVersion.SUCCEEDED_V0 to Json.encodeToString(LightningOutgoingPartStatusData.Succeeded.V0(preimage)).toByteArray(Charsets.UTF_8) -fun LightningOutgoingPayment.Part.Status.Failed.mapToDb() = LightningOutgoingPartStatusTypeVersion.FAILED_V0 to - Json.encodeToString(LightningOutgoingPartStatusData.Failed.V0(remoteFailureCode, details)).toByteArray(Charsets.UTF_8) +fun LightningOutgoingPayment.Part.Status.Failure.mapToDb(): Pair { + val (code, details) = when (this) { + is LightningOutgoingPayment.Part.Status.Failure.Uninterpretable -> 0 to message + is LightningOutgoingPayment.Part.Status.Failure.PaymentAmountTooSmall -> 1 to null + is LightningOutgoingPayment.Part.Status.Failure.PaymentAmountTooBig -> 2 to null + is LightningOutgoingPayment.Part.Status.Failure.NotEnoughFunds -> 3 to null + is LightningOutgoingPayment.Part.Status.Failure.NotEnoughFees -> 4 to null + is LightningOutgoingPayment.Part.Status.Failure.PaymentExpiryTooBig -> 5 to null + is LightningOutgoingPayment.Part.Status.Failure.TooManyPendingPayments -> 6 to null + is LightningOutgoingPayment.Part.Status.Failure.ChannelIsSplicing -> 7 to null + is LightningOutgoingPayment.Part.Status.Failure.ChannelIsClosing -> 8 to null + is LightningOutgoingPayment.Part.Status.Failure.TemporaryRemoteFailure -> 9 to null + is LightningOutgoingPayment.Part.Status.Failure.RecipientLiquidityIssue -> 10 to null + is LightningOutgoingPayment.Part.Status.Failure.RecipientIsOffline -> 11 to null + is LightningOutgoingPayment.Part.Status.Failure.RecipientRejectedPayment -> 12 to null + } + return LightningOutgoingPartStatusTypeVersion.FAILED_V1 to + Json.encodeToString(LightningOutgoingPartStatusData.Failed.V1(code, details)).toByteArray(Charsets.UTF_8) +} \ No newline at end of file diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingQueries.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingQueries.kt index 6c4865b..0f4998d 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingQueries.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingQueries.kt @@ -115,11 +115,11 @@ class LightningOutgoingQueries(val database: PhoenixDatabase) { fun updateLightningPart( partId: UUID, - failure: Either, + failure: LightningOutgoingPayment.Part.Status.Failure, completedAt: Long ): Boolean { var result = true - val (statusTypeVersion, statusData) = OutgoingPaymentFailure.convertFailure(failure).mapToDb() + val (statusTypeVersion, statusData) = failure.mapToDb() database.transaction { queries.updateLightningPart( part_id = partId.toString(), diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingStatusType.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingStatusType.kt index 70cb523..04d1df4 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingStatusType.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/db/payments/LightningOutgoingStatusType.kt @@ -72,10 +72,14 @@ sealed class LightningOutgoingStatusData { FinalFailure.InvalidPaymentId::class.simpleName -> FinalFailure.InvalidPaymentId FinalFailure.NoAvailableChannels::class.simpleName -> FinalFailure.NoAvailableChannels FinalFailure.InsufficientBalance::class.simpleName -> FinalFailure.InsufficientBalance - FinalFailure.NoRouteToRecipient::class.simpleName -> FinalFailure.NoRouteToRecipient FinalFailure.RecipientUnreachable::class.simpleName -> FinalFailure.RecipientUnreachable FinalFailure.RetryExhausted::class.simpleName -> FinalFailure.RetryExhausted FinalFailure.WalletRestarted::class.simpleName -> FinalFailure.WalletRestarted + FinalFailure.AlreadyPaid::class.simpleName -> FinalFailure.AlreadyPaid + FinalFailure.ChannelClosing::class.simpleName -> FinalFailure.ChannelClosing + FinalFailure.ChannelOpening::class.simpleName -> FinalFailure.ChannelOpening + FinalFailure.ChannelNotConnected::class.simpleName -> FinalFailure.ChannelNotConnected + FinalFailure.FeaturesNotSupported::class.simpleName -> FinalFailure.FeaturesNotSupported else -> FinalFailure.UnknownError } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/bin/json/JsonSerializers.kt b/src/commonMain/kotlin/fr/acinq/lightning/bin/json/JsonSerializers.kt index 628cfe6..b9e83fe 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/bin/json/JsonSerializers.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/bin/json/JsonSerializers.kt @@ -96,7 +96,7 @@ sealed class ApiType { @Serializable @SerialName("payment_failed") data class PaymentFailed(val paymentHash: ByteVector32, val reason: String) : ApiType() { - constructor(event: fr.acinq.lightning.io.PaymentNotSent) : this(event.request.paymentHash, event.reason.reason.toString()) + constructor(event: fr.acinq.lightning.io.PaymentNotSent) : this(event.request.paymentHash, event.reason.explain().fold({ it.toString() }, { it.toString() })) } @Serializable