From 13093720209c412dc56c70414ed771cdd8b200f6 Mon Sep 17 00:00:00 2001 From: Dominique Padiou <5765435+dpad85@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:34:24 +0100 Subject: [PATCH] Use try pattern for PaymentRequest.read (#492) See ACINQ/lightning-kmp#567 which catches invoice decoding exceptions. --- buildSrc/src/main/kotlin/Versions.kt | 2 +- .../android/utils/LegacyMigrationHelper.kt | 4 ++-- .../fr.acinq.phoenix/data/lnurl/LnurlPay.kt | 8 ++++---- .../db/payments/IncomingOriginType.kt | 2 +- .../db/payments/OutgoingDetailsType.kt | 4 ++-- .../kotlin/fr.acinq.phoenix/utils/Parser.kt | 15 +++++++-------- .../db/IncomingPaymentDbTypeVersionTest.kt | 2 +- .../db/OutgoingPaymentDbTypeVersionTest.kt | 2 +- .../phoenix/db/SqlitePaymentsDatabaseTest.kt | 2 +- .../kotlin/fr/acinq/phoenix/utils/ParserTest.kt | 2 +- 10 files changed, 21 insertions(+), 22 deletions(-) diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 1dab515c9..052f74be2 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -1,5 +1,5 @@ object Versions { - const val lightningKmp = "1.5.14" + const val lightningKmp = "1.5.15-SNAPSHOT" const val secp256k1 = "0.11.0" const val torMobile = "0.2.0" diff --git a/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/utils/LegacyMigrationHelper.kt b/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/utils/LegacyMigrationHelper.kt index 79074c996..4a0a8e2d1 100644 --- a/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/utils/LegacyMigrationHelper.kt +++ b/phoenix-android/src/main/kotlin/fr/acinq/phoenix/android/utils/LegacyMigrationHelper.kt @@ -293,7 +293,7 @@ object LegacyMigrationHelper { } } else { IncomingPayment.Origin.Invoice( - paymentRequest = PaymentRequest.read(fr.acinq.eclair.payment.PaymentRequest.write(payment.paymentRequest())) + paymentRequest = PaymentRequest.read(fr.acinq.eclair.payment.PaymentRequest.write(payment.paymentRequest())).get() ) } @@ -363,7 +363,7 @@ object LegacyMigrationHelper { } val paymentRequest = if (head.paymentRequest().isDefined) { - PaymentRequest.read(fr.acinq.eclair.payment.PaymentRequest.write(head.paymentRequest().get())) + PaymentRequest.read(fr.acinq.eclair.payment.PaymentRequest.write(head.paymentRequest().get())).get() } else null // retrieve details from the first payment in the list diff --git a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/lnurl/LnurlPay.kt b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/lnurl/LnurlPay.kt index f20e0957d..eeb356032 100644 --- a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/lnurl/LnurlPay.kt +++ b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/data/lnurl/LnurlPay.kt @@ -20,6 +20,7 @@ import fr.acinq.bitcoin.ByteVector import fr.acinq.bitcoin.Crypto import fr.acinq.lightning.MilliSatoshi import fr.acinq.lightning.payment.PaymentRequest +import fr.acinq.lightning.utils.Try import fr.acinq.phoenix.data.lnurl.Lnurl.Companion.format import fr.acinq.phoenix.data.lnurl.Lnurl.Companion.log import fr.acinq.phoenix.db.cloud.b64Decode @@ -111,10 +112,9 @@ sealed class LnurlPay : Lnurl.Qualified { ): Invoice { try { val pr = json["pr"]?.jsonPrimitive?.content ?: throw LnurlError.Pay.Invoice.Malformed(origin, "missing pr") - val paymentRequest = try { - PaymentRequest.read(pr) // <- throws - } catch (t: Throwable) { - throw LnurlError.Pay.Invoice.Malformed(origin, "unreadable pr") + val paymentRequest = when (val res = PaymentRequest.read(pr)) { + is Try.Success -> res.result + is Try.Failure -> throw LnurlError.Pay.Invoice.Malformed(origin, res.error.message ?: res.error::class.toString()) } val successAction = parseSuccessAction(origin, json) diff --git a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/IncomingOriginType.kt b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/IncomingOriginType.kt index a322538b8..3cdfa418e 100644 --- a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/IncomingOriginType.kt +++ b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/IncomingOriginType.kt @@ -69,7 +69,7 @@ sealed class IncomingOriginData { fun deserialize(typeVersion: IncomingOriginTypeVersion, blob: ByteArray): IncomingPayment.Origin = decodeBlob(blob) { json, format -> when (typeVersion) { IncomingOriginTypeVersion.KEYSEND_V0 -> IncomingPayment.Origin.KeySend - IncomingOriginTypeVersion.INVOICE_V0 -> format.decodeFromString(json).let { IncomingPayment.Origin.Invoice(PaymentRequest.read(it.paymentRequest)) } + IncomingOriginTypeVersion.INVOICE_V0 -> format.decodeFromString(json).let { IncomingPayment.Origin.Invoice(PaymentRequest.read(it.paymentRequest).get()) } IncomingOriginTypeVersion.SWAPIN_V0 -> format.decodeFromString(json).let { IncomingPayment.Origin.SwapIn(it.address) } IncomingOriginTypeVersion.ONCHAIN_V0 -> format.decodeFromString(json).let { IncomingPayment.Origin.OnChain(TxId(it.txId), it.outpoints.toSet()) diff --git a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/OutgoingDetailsType.kt b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/OutgoingDetailsType.kt index 7c26a77d5..cb66333ce 100644 --- a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/OutgoingDetailsType.kt +++ b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/db/payments/OutgoingDetailsType.kt @@ -77,9 +77,9 @@ sealed class OutgoingDetailsData { @Suppress("DEPRECATION") fun deserialize(typeVersion: OutgoingDetailsTypeVersion, blob: ByteArray): LightningOutgoingPayment.Details? = DbTypesHelper.decodeBlob(blob) { json, format -> when (typeVersion) { - OutgoingDetailsTypeVersion.NORMAL_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.Normal(PaymentRequest.read(it.paymentRequest)) } + OutgoingDetailsTypeVersion.NORMAL_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.Normal(PaymentRequest.read(it.paymentRequest).get()) } OutgoingDetailsTypeVersion.KEYSEND_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.KeySend(it.preimage) } - OutgoingDetailsTypeVersion.SWAPOUT_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.SwapOut(it.address, PaymentRequest.read(it.paymentRequest), it.swapOutFee) } + OutgoingDetailsTypeVersion.SWAPOUT_V0 -> format.decodeFromString(json).let { LightningOutgoingPayment.Details.SwapOut(it.address, PaymentRequest.read(it.paymentRequest).get(), it.swapOutFee) } OutgoingDetailsTypeVersion.CLOSING_V0 -> null } } diff --git a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/utils/Parser.kt b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/utils/Parser.kt index 84f108f09..eb8c8dd49 100644 --- a/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/utils/Parser.kt +++ b/phoenix-shared/src/commonMain/kotlin/fr.acinq.phoenix/utils/Parser.kt @@ -20,6 +20,7 @@ import fr.acinq.bitcoin.* import fr.acinq.bitcoin.utils.Either import fr.acinq.lightning.NodeParams import fr.acinq.lightning.payment.PaymentRequest +import fr.acinq.lightning.utils.Try import fr.acinq.lightning.utils.sat import fr.acinq.phoenix.data.* import io.ktor.http.* @@ -70,10 +71,9 @@ object Parser { /** Reads a payment request after stripping prefixes. Return null if input is invalid. */ fun readPaymentRequest( input: String - ): PaymentRequest? = try { - PaymentRequest.read(trimMatchingPrefix(removeExcessInput(input), lightningPrefixes)) - } catch (t: Throwable) { - null + ): PaymentRequest? = when (val res = PaymentRequest.read(trimMatchingPrefix(removeExcessInput(input), lightningPrefixes))) { + is Try.Success -> res.get() + is Try.Failure -> null } /** @@ -117,10 +117,9 @@ object Parser { val label = url.parameters["label"] val message = url.parameters["message"] val lightning = url.parameters["lightning"]?.let { - try { - PaymentRequest.read(it) - } catch (e: Exception) { - null + when (val res = PaymentRequest.read(it)) { + is Try.Success -> res.get() + is Try.Failure -> null } } val otherParams = ParametersBuilder().apply { diff --git a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/IncomingPaymentDbTypeVersionTest.kt b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/IncomingPaymentDbTypeVersionTest.kt index 7932caa99..67d1fd78f 100644 --- a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/IncomingPaymentDbTypeVersionTest.kt +++ b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/IncomingPaymentDbTypeVersionTest.kt @@ -36,7 +36,7 @@ class IncomingPaymentDbTypeVersionTest { val channelId1 = ByteVector32.fromValidHex("3b6208285563c9adb009781acf1626f1c2a3b1a3492d5ec312ead8282c7ad6da") val address1 = "tb1q97tpc0y4rvdnu9wm7nu354lmmzdm8du228u3g4" val invoice1 = - PaymentRequest.read("lntb1500n1ps9u963pp5llphsu6evgmzgk8g2e73su44wn6txmwywdzwvtdwzrt9pqxc9f5sdpzxysy2umswfjhxum0yppk76twypgxzmnwvycqp7xqrrss9qy9qsqsp5qa7092geq6ptp24uzlfw0vj3w4whh2zuc9rquwca69acwx5khckqvslyw2n6dallc868vxu3uueyhw6pe00cmluynv7ca4tknz7g274rp9ucwqpx5ydejsmzl4xpegqtemcq6vwvu8alpxttlj82e7j26gspfj06gn") + PaymentRequest.read("lntb1500n1ps9u963pp5llphsu6evgmzgk8g2e73su44wn6txmwywdzwvtdwzrt9pqxc9f5sdpzxysy2umswfjhxum0yppk76twypgxzmnwvycqp7xqrrss9qy9qsqsp5qa7092geq6ptp24uzlfw0vj3w4whh2zuc9rquwca69acwx5khckqvslyw2n6dallc868vxu3uueyhw6pe00cmluynv7ca4tknz7g274rp9ucwqpx5ydejsmzl4xpegqtemcq6vwvu8alpxttlj82e7j26gspfj06gn").get() @Test fun incoming_origin_invoice() { diff --git a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/OutgoingPaymentDbTypeVersionTest.kt b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/OutgoingPaymentDbTypeVersionTest.kt index f7426cceb..242ca76b8 100644 --- a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/OutgoingPaymentDbTypeVersionTest.kt +++ b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/OutgoingPaymentDbTypeVersionTest.kt @@ -35,7 +35,7 @@ class OutgoingPaymentDbTypeVersionTest { val address1 = "tb1q97tpc0y4rvdnu9wm7nu354lmmzdm8du228u3g4" val preimage1 = randomBytes32() val paymentRequest1 = - PaymentRequest.read("lntb1500n1ps9utezpp5xjfvpvgg3zykv2kdd9yws86xw5ww2kr60h9yphth2h6fly87a9gqdpzxysy2umswfjhxum0yppk76twypgxzmnwvycqp7xqrrss9qy9qsqsp5vm25lch9spq2m9fxqrgcxq0mxrgaehstd9javflyadsle5d97p9qmu9zsjn7l59lmps3568tz9ppla4xhawjptjyrw32jed84fe75z0ka0kmnntc9la95acvc0mjav6rdv5037y6zq9e0eqhenlt8y0yh8cpj467cl") + PaymentRequest.read("lntb1500n1ps9utezpp5xjfvpvgg3zykv2kdd9yws86xw5ww2kr60h9yphth2h6fly87a9gqdpzxysy2umswfjhxum0yppk76twypgxzmnwvycqp7xqrrss9qy9qsqsp5vm25lch9spq2m9fxqrgcxq0mxrgaehstd9javflyadsle5d97p9qmu9zsjn7l59lmps3568tz9ppla4xhawjptjyrw32jed84fe75z0ka0kmnntc9la95acvc0mjav6rdv5037y6zq9e0eqhenlt8y0yh8cpj467cl").get() @Test fun outgoing_details_normal() { diff --git a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/SqlitePaymentsDatabaseTest.kt b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/SqlitePaymentsDatabaseTest.kt index 269375a0b..5bd084017 100644 --- a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/SqlitePaymentsDatabaseTest.kt +++ b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/db/SqlitePaymentsDatabaseTest.kt @@ -142,7 +142,7 @@ class SqlitePaymentsDatabaseTest { @Test fun incoming__is_expired() = runTest { val expiredInvoice = - PaymentRequest.read("lntb1p0ufamxpp5l23zy5f8h2dcr8hxynptkcyuzdygy36pz76hgayp7n9q45a3cwuqdqqxqyjw5q9qtzqqqqqq9qsqsp5vusneyeywvawt4d7sslx3kx0eh7kk68l7j26qr0ge7z04lxhe5ssrzjqwfn3p9278ttzzpe0e00uhyxhned3j5d9acqak5emwfpflp8z2cnfluw6cwxn8wdcyqqqqlgqqqqqeqqjqmjvx0y3cfw54syp4jqw6jlj73qt97vxftjd3w3ywx6v2jqkdx9uxw3hk9qq6st9qyfpu3nzrpefwye63vmnyyzn6z8n7nkqsjj6lsaspu2p3mm") + PaymentRequest.read("lntb1p0ufamxpp5l23zy5f8h2dcr8hxynptkcyuzdygy36pz76hgayp7n9q45a3cwuqdqqxqyjw5q9qtzqqqqqq9qsqsp5vusneyeywvawt4d7sslx3kx0eh7kk68l7j26qr0ge7z04lxhe5ssrzjqwfn3p9278ttzzpe0e00uhyxhned3j5d9acqak5emwfpflp8z2cnfluw6cwxn8wdcyqqqqlgqqqqqeqqjqmjvx0y3cfw54syp4jqw6jlj73qt97vxftjd3w3ywx6v2jqkdx9uxw3hk9qq6st9qyfpu3nzrpefwye63vmnyyzn6z8n7nkqsjj6lsaspu2p3mm").get() db.addIncomingPayment(preimage1, IncomingPayment.Origin.Invoice(expiredInvoice), 0) db.receivePayment(paymentHash1, receivedWith1, 10) assertTrue(db.getIncomingPayment(paymentHash1)!!.isExpired()) diff --git a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/utils/ParserTest.kt b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/utils/ParserTest.kt index 643a76720..4505db22e 100644 --- a/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/utils/ParserTest.kt +++ b/phoenix-shared/src/commonTest/kotlin/fr/acinq/phoenix/utils/ParserTest.kt @@ -142,7 +142,7 @@ class ParserTest { "bitcoin:bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4?foo=bar&lightning=lntb15u1p05vazrpp5apz75ghtq3ynmc5qm98tsgucmsav44fyffpguhzdep2kcgkfme4sdq4xysyymr0vd4kzcmrd9hx7cqp2xqrrss9qy9qsqsp5v4hqr48qe0u7al6lxwdpmp3w6k7evjdavm0lh7arpv3qaf038s5st2d8k8vvmxyav2wkfym9jp4mk64srmswgh7l6sqtq7l4xl3nknf8snltamvpw5p3yl9nxg0ax9k0698rr94qx6unrv8yhccmh4z9ghcq77hxps" to Either.Right( BitcoinUri( chain = NodeParams.Chain.Mainnet, address = "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4", - paymentRequest = PaymentRequest.read("lntb15u1p05vazrpp5apz75ghtq3ynmc5qm98tsgucmsav44fyffpguhzdep2kcgkfme4sdq4xysyymr0vd4kzcmrd9hx7cqp2xqrrss9qy9qsqsp5v4hqr48qe0u7al6lxwdpmp3w6k7evjdavm0lh7arpv3qaf038s5st2d8k8vvmxyav2wkfym9jp4mk64srmswgh7l6sqtq7l4xl3nknf8snltamvpw5p3yl9nxg0ax9k0698rr94qx6unrv8yhccmh4z9ghcq77hxps"), + paymentRequest = PaymentRequest.read("lntb15u1p05vazrpp5apz75ghtq3ynmc5qm98tsgucmsav44fyffpguhzdep2kcgkfme4sdq4xysyymr0vd4kzcmrd9hx7cqp2xqrrss9qy9qsqsp5v4hqr48qe0u7al6lxwdpmp3w6k7evjdavm0lh7arpv3qaf038s5st2d8k8vvmxyav2wkfym9jp4mk64srmswgh7l6sqtq7l4xl3nknf8snltamvpw5p3yl9nxg0ax9k0698rr94qx6unrv8yhccmh4z9ghcq77hxps").get(), ignoredParams = ParametersBuilder().apply { set("foo", "bar") }.build() ) ),