From 23f00e8d5f3dcf056eef93b80cb13ae02d19e9cf Mon Sep 17 00:00:00 2001 From: t-bast Date: Tue, 2 Jan 2024 17:10:31 +0100 Subject: [PATCH] Add require_confirmed_inputs to RBF messages This was missing from the spec, but is more flexible and clearer than inheriting values from the previous attempt. We don't really support checking that flag yet, but we should ensure our codecs support reading it. --- .../fr/acinq/lightning/wire/InteractiveTxTlv.kt | 14 ++++++++++++++ .../fr/acinq/lightning/wire/LightningMessages.kt | 12 ++++++++++-- .../lightning/wire/LightningCodecsTestsCommon.kt | 4 ++-- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt index 9e3ea7dd1..8ae941069 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/InteractiveTxTlv.kt @@ -119,6 +119,13 @@ sealed class TxInitRbfTlv : Tlv { override fun read(input: Input): SharedOutputContributionTlv = SharedOutputContributionTlv(LightningCodecs.int64(input).sat) } } + + /** Require confirmed inputs for the transaction being built. */ + object RequireConfirmedInputsTlv : TxInitRbfTlv(), TlvValueReader { + override val tag: Long get() = 2 + override fun write(out: Output) = Unit + override fun read(input: Input): RequireConfirmedInputsTlv = this + } } sealed class TxAckRbfTlv : Tlv { @@ -137,6 +144,13 @@ sealed class TxAckRbfTlv : Tlv { override fun read(input: Input): SharedOutputContributionTlv = SharedOutputContributionTlv(LightningCodecs.int64(input).sat) } } + + /** Require confirmed inputs for the transaction being built. */ + object RequireConfirmedInputsTlv : TxAckRbfTlv(), TlvValueReader { + override val tag: Long get() = 2 + override fun write(out: Output) = Unit + override fun read(input: Input): RequireConfirmedInputsTlv = this + } } sealed class TxAbortTlv : Tlv diff --git a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt index b3d969b63..5fcbceb7d 100644 --- a/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt +++ b/src/commonMain/kotlin/fr/acinq/lightning/wire/LightningMessages.kt @@ -535,6 +535,7 @@ data class TxInitRbf( constructor(channelId: ByteVector32, lockTime: Long, feerate: FeeratePerKw, fundingContribution: Satoshi) : this(channelId, lockTime, feerate, TlvStream(TxInitRbfTlv.SharedOutputContributionTlv(fundingContribution))) val fundingContribution = tlvs.get()?.amount ?: 0.sat + val requireConfirmedInputs: Boolean = tlvs.get()?.let { true } ?: false override val type: Long get() = TxInitRbf.type @@ -549,7 +550,10 @@ data class TxInitRbf( const val type: Long = 72 @Suppress("UNCHECKED_CAST") - val readers = mapOf(TxInitRbfTlv.SharedOutputContributionTlv.tag to TxInitRbfTlv.SharedOutputContributionTlv.Companion as TlvValueReader) + val readers = mapOf( + TxInitRbfTlv.SharedOutputContributionTlv.tag to TxInitRbfTlv.SharedOutputContributionTlv.Companion as TlvValueReader, + TxInitRbfTlv.RequireConfirmedInputsTlv.tag to TxInitRbfTlv.RequireConfirmedInputsTlv as TlvValueReader, + ) override fun read(input: Input): TxInitRbf = TxInitRbf( LightningCodecs.bytes(input, 32).byteVector32(), @@ -567,6 +571,7 @@ data class TxAckRbf( constructor(channelId: ByteVector32, fundingContribution: Satoshi) : this(channelId, TlvStream(TxAckRbfTlv.SharedOutputContributionTlv(fundingContribution))) val fundingContribution = tlvs.get()?.amount ?: 0.sat + val requireConfirmedInputs: Boolean = tlvs.get()?.let { true } ?: false override val type: Long get() = TxAckRbf.type @@ -579,7 +584,10 @@ data class TxAckRbf( const val type: Long = 73 @Suppress("UNCHECKED_CAST") - val readers = mapOf(TxAckRbfTlv.SharedOutputContributionTlv.tag to TxAckRbfTlv.SharedOutputContributionTlv.Companion as TlvValueReader) + val readers = mapOf( + TxAckRbfTlv.SharedOutputContributionTlv.tag to TxAckRbfTlv.SharedOutputContributionTlv.Companion as TlvValueReader, + TxAckRbfTlv.RequireConfirmedInputsTlv.tag to TxAckRbfTlv.RequireConfirmedInputsTlv as TlvValueReader, + ) override fun read(input: Input): TxAckRbf = TxAckRbf( LightningCodecs.bytes(input, 32).byteVector32(), diff --git a/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt b/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt index 50fe736e3..1835ef597 100644 --- a/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt +++ b/src/commonTest/kotlin/fr/acinq/lightning/wire/LightningCodecsTestsCommon.kt @@ -418,13 +418,13 @@ class LightningCodecsTestsCommon : LightningTestSuite() { TxSignatures(channelId2, tx1, listOf(), signature, listOf(), swapInSignatures) to ByteVector("0047 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 1f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106 0000 fd0259 40 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb fd025d 80 c49269a9baa73a5ec44b63bdcaabf9c7c6477f72866b822f8502e5c989aa3562fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c3 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db252a2f914ea1fcbd580b80cdea60226f63288cd44bd84a8850c9189a24f08c7cc5"), TxSignatures(channelId2, tx1, listOf(), signature, swapInSignatures.take(1), swapInSignatures.drop(1)) to ByteVector("0047 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 1f2ec025a33e39ef8e177afcdc1adc855bf128dc906182255aeb64efa825f106 0000 fd0259 40 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb fd025b 40 c49269a9baa73a5ec44b63bdcaabf9c7c6477f72866b822f8502e5c989aa3562fe69d72bec62025d3474b9c2d947ec6d68f9f577be5fab8ee80503cefd8846c3 fd025d 40 2dadacd65b585e4061421b5265ff543e2a7bdc4d4a7fea932727426bdc53db252a2f914ea1fcbd580b80cdea60226f63288cd44bd84a8850c9189a24f08c7cc5"), TxInitRbf(channelId1, 8388607, FeeratePerKw(4000.sat)) to ByteVector("0048 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 007fffff 00000fa0"), - TxInitRbf(channelId1, 0, FeeratePerKw(4000.sat), TlvStream(TxInitRbfTlv.SharedOutputContributionTlv(1_500_000.sat))) to ByteVector("0048 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 00000000 00000fa0 0008000000000016e360"), + TxInitRbf(channelId1, 0, FeeratePerKw(4000.sat), TlvStream(TxInitRbfTlv.SharedOutputContributionTlv(1_500_000.sat), TxInitRbfTlv.RequireConfirmedInputsTlv)) to ByteVector("0048 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 00000000 00000fa0 0008000000000016e360 0200"), TxInitRbf(channelId1, 0, FeeratePerKw(4000.sat), TlvStream(TxInitRbfTlv.SharedOutputContributionTlv(0.sat))) to ByteVector("0048 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 00000000 00000fa0 00080000000000000000"), TxInitRbf(channelId1, 0, FeeratePerKw(4000.sat), TlvStream(TxInitRbfTlv.SharedOutputContributionTlv((-25_000).sat))) to ByteVector("0048 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 00000000 00000fa0 0008ffffffffffff9e58"), TxAckRbf(channelId2) to ByteVector("0049 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"), TxAckRbf(channelId2, TlvStream(TxAckRbfTlv.SharedOutputContributionTlv(450_000.sat))) to ByteVector("0049 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0008000000000006ddd0"), TxAckRbf(channelId2, TlvStream(TxAckRbfTlv.SharedOutputContributionTlv(0.sat))) to ByteVector("0049 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 00080000000000000000"), - TxAckRbf(channelId2, TlvStream(TxAckRbfTlv.SharedOutputContributionTlv((-250_000).sat))) to ByteVector("0049 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0008fffffffffffc2f70"), + TxAckRbf(channelId2, TlvStream(TxAckRbfTlv.SharedOutputContributionTlv((-250_000).sat), TxAckRbfTlv.RequireConfirmedInputsTlv)) to ByteVector("0049 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0008fffffffffffc2f70 0200"), TxAbort(channelId1, "") to ByteVector("004a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 0000"), TxAbort(channelId1, "internal error") to ByteVector("004a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 000e 696e7465726e616c206572726f72"), // @formatter:on