diff --git a/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt b/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt index d4456f6a2..20ba6aac0 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/json/JsonSerializers.kt @@ -666,7 +666,7 @@ object JsonSerializers { val description: String?, val metadata: ByteVector?, val expirySeconds: Long?, - val nodeId: PublicKey?, + val issuerId: PublicKey?, val path: List?, val features: Features?, val unknownTlvs: List? @@ -690,7 +690,7 @@ object JsonSerializers { description = o.description, metadata = o.metadata, expirySeconds = o.expirySeconds, - nodeId = o.nodeId, + issuerId = o.issuerId, path = o.paths?.map { it.route }?.run { ifEmpty { null } }, features = o.features.let { if (it == Features.empty) null else it }, unknownTlvs = o.records.unknown.toList().run { ifEmpty { null } } diff --git a/src/commonMain/kotlin/fr/acinq/lightning/payment/Bolt12Invoice.kt b/src/commonMain/kotlin/fr/acinq/lightning/payment/Bolt12Invoice.kt index a0257a95d..d487e682a 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/payment/Bolt12Invoice.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/payment/Bolt12Invoice.kt @@ -52,7 +52,7 @@ data class Bolt12Invoice(val records: TlvStream) : PaymentRequest() // It is assumed that the request is valid for this offer. fun validateFor(request: InvoiceRequest): Either { - val offerNodeIds = invoiceRequest.offer.nodeId?.let { listOf(it) } ?: invoiceRequest.offer.paths!!.map { it.route.blindedNodeIds.last() } + val offerNodeIds = invoiceRequest.offer.issuerId?.let { listOf(it) } ?: invoiceRequest.offer.paths!!.map { it.route.blindedNodeIds.last() } return if (invoiceRequest.unsigned() != request.unsigned()) { Either.Left("Invoice does not match request") } else if (!offerNodeIds.contains(nodeId)) { diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt index 8bc70d23f..55d8704a7 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/OfferTypes.kt @@ -262,21 +262,21 @@ object OfferTypes { } /** - * Public key of the offer creator. + * Public key of the offer issuer. * If `OfferPaths` is present, they must be used to retrieve an invoice even if this public key corresponds to a node id in the public network. * If `OfferPaths` is not present, this public key must correspond to a node id in the public network that needs to be contacted to retrieve an invoice. */ - data class OfferNodeId(val publicKey: PublicKey) : OfferTlv() { - override val tag: Long get() = OfferNodeId.tag + data class OfferIssuerId(val publicKey: PublicKey) : OfferTlv() { + override val tag: Long get() = OfferIssuerId.tag override fun write(out: Output) { LightningCodecs.writeBytes(publicKey.value, out) } - companion object : TlvValueReader { + companion object : TlvValueReader { const val tag: Long = 22 - override fun read(input: Input): OfferNodeId { - return OfferNodeId(PublicKey(LightningCodecs.bytes(input, input.availableBytes))) + override fun read(input: Input): OfferIssuerId { + return OfferIssuerId(PublicKey(LightningCodecs.bytes(input, input.availableBytes))) } } } @@ -732,10 +732,10 @@ object OfferTypes { val paths: List? = records.get()?.paths val issuer: String? = records.get()?.issuer val quantityMax: Long? = records.get()?.max?.let { if (it == 0L) Long.MAX_VALUE else it } - val nodeId: PublicKey? = records.get()?.publicKey - // A valid offer must contain a blinded path or a nodeId. - val contactInfos: List = paths ?: listOf(ContactInfo.RecipientNodeId(nodeId!!)) - val contactNodeIds: List = contactInfos.map { it.nodeId } + val issuerId: PublicKey? = records.get()?.publicKey + // A valid offer must contain a blinded path or an issuerId (and may contain both). + // When both are provided, the blinded paths should be tried first. + val contactInfos: List = paths ?: listOf(ContactInfo.RecipientNodeId(issuerId!!)) fun encode(): String { val data = tlvSerializer.write(records) @@ -773,7 +773,7 @@ object OfferTypes { amount?.let { OfferAmount(it) }, description?.let { OfferDescription(it) }, features.bolt12Features().let { if (it != Features.empty) OfferFeatures(it) else null }, - OfferNodeId(nodeId) + OfferIssuerId(nodeId) ) return Offer(TlvStream(tlvs + additionalTlvs, customTlvs)) } @@ -813,7 +813,7 @@ object OfferTypes { fun validate(records: TlvStream): Either { if (records.get() == null && records.get() != null) return Left(MissingRequiredTlv(10)) - if (records.get() == null && records.get() == null) return Left(MissingRequiredTlv(22)) + if (records.get() == null && records.get() == null) return Left(MissingRequiredTlv(22)) if (records.unknown.any { !isOfferTlv(it) }) return Left(ForbiddenTlv(records.unknown.find { !isOfferTlv(it) }!!.tag)) return Right(Offer(records)) } @@ -830,7 +830,7 @@ object OfferTypes { OfferPaths.tag to OfferPaths as TlvValueReader, OfferIssuer.tag to OfferIssuer as TlvValueReader, OfferQuantityMax.tag to OfferQuantityMax as TlvValueReader, - OfferNodeId.tag to OfferNodeId as TlvValueReader, + OfferIssuerId.tag to OfferIssuerId as TlvValueReader, ) ) @@ -958,7 +958,7 @@ object OfferTypes { OfferPaths.tag to OfferPaths as TlvValueReader, OfferIssuer.tag to OfferIssuer as TlvValueReader, OfferQuantityMax.tag to OfferQuantityMax as TlvValueReader, - OfferNodeId.tag to OfferNodeId as TlvValueReader, + OfferIssuerId.tag to OfferIssuerId as TlvValueReader, // Invoice request part InvoiceRequestChain.tag to InvoiceRequestChain as TlvValueReader, InvoiceRequestAmount.tag to InvoiceRequestAmount as TlvValueReader, @@ -998,7 +998,7 @@ object OfferTypes { OfferPaths.tag to OfferPaths as TlvValueReader, OfferIssuer.tag to OfferIssuer as TlvValueReader, OfferQuantityMax.tag to OfferQuantityMax as TlvValueReader, - OfferNodeId.tag to OfferNodeId as TlvValueReader, + OfferIssuerId.tag to OfferIssuerId as TlvValueReader, InvoiceRequestChain.tag to InvoiceRequestChain as TlvValueReader, InvoiceRequestAmount.tag to InvoiceRequestAmount as TlvValueReader, InvoiceRequestFeatures.tag to InvoiceRequestFeatures as TlvValueReader, diff --git a/src/commonTest/kotlin/fr/acinq/lightning/payment/Bolt12InvoiceTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/payment/Bolt12InvoiceTestsCommon.kt index 598f1b9e8..2bfba6dd1 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/payment/Bolt12InvoiceTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/payment/Bolt12InvoiceTestsCommon.kt @@ -37,7 +37,7 @@ import fr.acinq.lightning.wire.OfferTypes.OfferChains import fr.acinq.lightning.wire.OfferTypes.OfferDescription import fr.acinq.lightning.wire.OfferTypes.OfferFeatures import fr.acinq.lightning.wire.OfferTypes.OfferIssuer -import fr.acinq.lightning.wire.OfferTypes.OfferNodeId +import fr.acinq.lightning.wire.OfferTypes.OfferIssuerId import fr.acinq.lightning.wire.OfferTypes.OfferQuantityMax import fr.acinq.lightning.wire.OfferTypes.PaymentInfo import fr.acinq.lightning.wire.OfferTypes.Signature @@ -173,7 +173,7 @@ class Bolt12InvoiceTestsCommon : LightningTestSuite() { val otherNodeKey = randomKey() val withOtherNodeId = signInvoice(Bolt12Invoice(TlvStream(invoice.records.records.map { when (it) { - is OfferNodeId -> OfferNodeId(otherNodeKey.publicKey()) + is OfferIssuerId -> OfferIssuerId(otherNodeKey.publicKey()) else -> it } }.toSet())), nodeKey) @@ -236,7 +236,7 @@ class Bolt12InvoiceTestsCommon : LightningTestSuite() { val tlvs = setOf( InvoiceRequestMetadata(ByteVector.fromHex("010203040506")), OfferDescription("offer description"), - OfferNodeId(nodeKey.publicKey()), + OfferIssuerId(nodeKey.publicKey()), InvoiceRequestAmount(15000.msat), InvoiceRequestPayerId(payerKey.publicKey()), InvoiceRequestPayerNote("I am Batman"), @@ -306,7 +306,7 @@ class Bolt12InvoiceTestsCommon : LightningTestSuite() { val nodeKey = randomKey() val tlvs = setOf( InvoiceRequestMetadata(ByteVector.fromHex("012345")), - OfferNodeId(nodeKey.publicKey()), + OfferIssuerId(nodeKey.publicKey()), InvoiceRequestPayerId(randomKey().publicKey()), InvoicePaths(listOf(createPaymentBlindedRoute(randomKey().publicKey()).route)), InvoiceBlindedPay(listOf(PaymentInfo(0.msat, 0, CltvExpiryDelta(0), 0.msat, 765432.msat, Features.empty))), @@ -360,7 +360,7 @@ class Bolt12InvoiceTestsCommon : LightningTestSuite() { OfferDescription(description), OfferFeatures(Features.empty), OfferIssuer(issuer), - OfferNodeId(nodeKey.publicKey()), + OfferIssuerId(nodeKey.publicKey()), InvoiceRequestChain(chain), InvoiceRequestAmount(amount), InvoiceRequestQuantity(quantity), @@ -489,7 +489,7 @@ class Bolt12InvoiceTestsCommon : LightningTestSuite() { OfferDescription("offer with quantity"), OfferIssuer("alice@bigshop.com"), OfferQuantityMax(1000), - OfferNodeId(nodeKey.publicKey()) + OfferIssuerId(nodeKey.publicKey()) ) ) val encodedOffer = "lno1qgsyxjtl6luzd9t3pr62xr7eemp6awnejusgf6gw45q75vcfqqqqqqqgqvqcdgq2zdhkven9wgs8w6t5dqs8zatpde6xjarezggkzmrfvdj5qcnfvaeksmms9e3k7mg5qgp7s93pqvn6l4vemgezdarq3wt2kpp0u4vt74vzz8futen7ej97n93jypp57" diff --git a/src/commonTest/kotlin/fr/acinq/lightning/wire/OfferTypesTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/wire/OfferTypesTestsCommon.kt index 6a63baab4..41da7e5d9 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/wire/OfferTypesTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/wire/OfferTypesTestsCommon.kt @@ -29,7 +29,7 @@ import fr.acinq.lightning.wire.OfferTypes.OfferAmount import fr.acinq.lightning.wire.OfferTypes.OfferChains import fr.acinq.lightning.wire.OfferTypes.OfferDescription import fr.acinq.lightning.wire.OfferTypes.OfferIssuer -import fr.acinq.lightning.wire.OfferTypes.OfferNodeId +import fr.acinq.lightning.wire.OfferTypes.OfferIssuerId import fr.acinq.lightning.wire.OfferTypes.OfferQuantityMax import fr.acinq.lightning.wire.OfferTypes.Signature import fr.acinq.lightning.wire.OfferTypes.readPath @@ -55,13 +55,13 @@ class OfferTypesTestsCommon : LightningTestSuite() { @Test fun `minimal offer`() { - val tlvs = setOf(OfferNodeId(nodeId)) + val tlvs = setOf(OfferIssuerId(nodeId)) val offer = Offer(TlvStream(tlvs)) val encoded = "lno1zcssxr0juddeytv7nwawhk9nq9us0arnk8j8wnsq8r2e86vzgtfneupe" assertEquals(offer, Offer.decode(encoded).get()) assertNull(offer.amount) assertNull(offer.description) - assertEquals(nodeId, offer.nodeId) + assertEquals(nodeId, offer.issuerId) // We can't create an empty offer. assertTrue(Offer.validate(TlvStream.empty()).isLeft) } @@ -75,14 +75,14 @@ class OfferTypesTestsCommon : LightningTestSuite() { OfferDescription("offer with quantity"), OfferIssuer("alice@bigshop.com"), OfferQuantityMax(0), - OfferNodeId(nodeId) + OfferIssuerId(nodeId) ) ) val encoded = "lno1qgsyxjtl6luzd9t3pr62xr7eemp6awnejusgf6gw45q75vcfqqqqqqqgqyeq5ym0venx2u3qwa5hg6pqw96kzmn5d968jys3v9kxjcm9gp3xjemndphhqtnrdak3gqqkyypsmuhrtwfzm85mht4a3vcp0yrlgua3u3m5uqpc6kf7nqjz6v70qwg" assertEquals(offer, Offer.decode(encoded).get()) assertEquals(50.msat, offer.amount) assertEquals("offer with quantity", offer.description) - assertEquals(nodeId, offer.nodeId) + assertEquals(nodeId, offer.issuerId) assertEquals("alice@bigshop.com", offer.issuer) assertEquals(Long.MAX_VALUE, offer.quantityMax) } @@ -149,7 +149,7 @@ class OfferTypesTestsCommon : LightningTestSuite() { @Test fun `check that invoice request matches offer - without chain`() { - val offer = Offer(TlvStream(OfferAmount(100.msat), OfferDescription("offer without chains"), OfferNodeId(randomKey().publicKey()))) + val offer = Offer(TlvStream(OfferAmount(100.msat), OfferDescription("offer without chains"), OfferIssuerId(randomKey().publicKey()))) val payerKey = randomKey() val tlvs: Set = offer.records.records + setOf( InvoiceRequestMetadata(ByteVector.fromHex("012345")), @@ -171,7 +171,7 @@ class OfferTypesTestsCommon : LightningTestSuite() { fun `check that invoice request matches offer - with chains`() { val chain1 = BlockHash(randomBytes32()) val chain2 = BlockHash(randomBytes32()) - val offer = Offer(TlvStream(OfferChains(listOf(chain1, chain2)), OfferAmount(100.msat), OfferDescription("offer with chains"), OfferNodeId(randomKey().publicKey()))) + val offer = Offer(TlvStream(OfferChains(listOf(chain1, chain2)), OfferAmount(100.msat), OfferDescription("offer with chains"), OfferIssuerId(randomKey().publicKey()))) val payerKey = randomKey() val request1 = InvoiceRequest(offer, 100.msat, 1, Features.empty, payerKey, null, chain1) assertTrue(request1.isValid()) @@ -196,7 +196,7 @@ class OfferTypesTestsCommon : LightningTestSuite() { TlvStream( OfferAmount(500.msat), OfferDescription("offer for multiple items"), - OfferNodeId(randomKey().publicKey()), + OfferIssuerId(randomKey().publicKey()), OfferQuantityMax(10), ) ) @@ -216,7 +216,7 @@ class OfferTypesTestsCommon : LightningTestSuite() { val payerKey = PrivateKey.fromHex("527d410ec920b626ece685e8af9abc976a48dbf2fe698c1b35d90a1c5fa2fbca") val tlvsWithoutSignature = setOf( InvoiceRequestMetadata(ByteVector.fromHex("abcdef")), - OfferNodeId(nodeId), + OfferIssuerId(nodeId), InvoiceRequestPayerId(payerKey.publicKey()), ) val signature = signSchnorr(InvoiceRequest.signatureTag, rootHash(TlvStream(tlvsWithoutSignature)), payerKey) @@ -226,7 +226,7 @@ class OfferTypesTestsCommon : LightningTestSuite() { assertEquals(invoiceRequest, InvoiceRequest.decode(encoded).get()) assertNull(invoiceRequest.offer.amount) assertNull(invoiceRequest.offer.description) - assertEquals(nodeId, invoiceRequest.offer.nodeId) + assertEquals(nodeId, invoiceRequest.offer.issuerId) assertEquals(ByteVector.fromHex("abcdef"), invoiceRequest.metadata) assertEquals(payerKey.publicKey(), invoiceRequest.payerId) // Removing any TLV from the minimal invoice request makes it invalid. @@ -514,7 +514,7 @@ class OfferTypesTestsCommon : LightningTestSuite() { assertNull(offer.description) assertEquals(Features.empty, offer.features) // the offer shouldn't have any feature to guarantee stability assertNull(offer.expirySeconds) - assertNull(offer.nodeId) // the offer should not leak our node_id + assertNull(offer.issuerId) // the offer should not leak our node_id assertEquals(1, offer.contactInfos.size) val path = offer.contactInfos.first() assertIs(path)