From b183e9cdd2fb1afb664b135ede6a96ded9f85920 Mon Sep 17 00:00:00 2001 From: sstone Date: Sun, 8 Dec 2024 21:38:03 +0100 Subject: [PATCH] Add a specific channel type for taproot channels --- .../kotlin/fr/acinq/lightning/Features.kt | 2 +- .../fr/acinq/lightning/channel/ChannelFeatures.kt | 4 ++-- .../acinq/lightning/channel/states/WaitForInit.kt | 4 +++- .../kotlin/fr/acinq/lightning/io/Peer.kt | 14 ++++++++++++-- .../lightning/channel/states/SpliceTestsCommon.kt | 4 ++++ .../states/WaitForFundingCreatedTestsCommon.kt | 4 ++-- 6 files changed, 24 insertions(+), 8 deletions(-) diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/Features.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/Features.kt index f47e63a32..8a2c97f57 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/Features.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/Features.kt @@ -395,7 +395,7 @@ data class Features(val activated: Map, val unknown: Se Feature.ExperimentalTrampolinePayment to listOf(Feature.PaymentSecret), Feature.OnTheFlyFunding to listOf(Feature.ExperimentalSplice), Feature.FundingFeeCredit to listOf(Feature.OnTheFlyFunding), - Feature.SimpleTaprootStaging to listOf(Feature.AnchorOutputs, Feature.StaticRemoteKey) + Feature.SimpleTaprootStaging to listOf(Feature.StaticRemoteKey) ) class FeatureException(message: String) : IllegalArgumentException(message) diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelFeatures.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelFeatures.kt index c940b38b8..049fe92e6 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelFeatures.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/ChannelFeatures.kt @@ -61,7 +61,7 @@ sealed class ChannelType { object SimpleTaprootStaging : SupportedChannelType() { override val name: String get() = "simple_taproot_staging" - override val features: Set get() = setOf(Feature.StaticRemoteKey, Feature.AnchorOutputs, Feature.SimpleTaprootStaging) + override val features: Set get() = setOf(Feature.StaticRemoteKey, Feature.AnchorOutputs, Feature.ZeroReserveChannels, Feature.SimpleTaprootStaging) } } @@ -77,7 +77,7 @@ sealed class ChannelType { // @formatter:off Features(Feature.StaticRemoteKey to FeatureSupport.Mandatory, Feature.AnchorOutputs to FeatureSupport.Mandatory, Feature.ZeroReserveChannels to FeatureSupport.Mandatory) -> SupportedChannelType.AnchorOutputsZeroReserve Features(Feature.StaticRemoteKey to FeatureSupport.Mandatory, Feature.AnchorOutputs to FeatureSupport.Mandatory) -> SupportedChannelType.AnchorOutputs - Features(Feature.StaticRemoteKey to FeatureSupport.Mandatory, Feature.AnchorOutputs to FeatureSupport.Mandatory, Feature.SimpleTaprootStaging to FeatureSupport.Mandatory) -> SupportedChannelType.SimpleTaprootStaging + Features(Feature.StaticRemoteKey to FeatureSupport.Mandatory, Feature.AnchorOutputs to FeatureSupport.Mandatory, Feature.ZeroReserveChannels to FeatureSupport.Mandatory, Feature.SimpleTaprootStaging to FeatureSupport.Mandatory) -> SupportedChannelType.SimpleTaprootStaging else -> UnsupportedChannelType(features) // @formatter:on } diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForInit.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForInit.kt index 6c3c9e097..20ceb75e0 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForInit.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/channel/states/WaitForInit.kt @@ -1,5 +1,7 @@ package fr.acinq.lightning.channel.states +import fr.acinq.lightning.Feature +import fr.acinq.lightning.Features import fr.acinq.lightning.blockchain.BITCOIN_FUNDING_DEPTHOK import fr.acinq.lightning.blockchain.BITCOIN_FUNDING_SPENT import fr.acinq.lightning.blockchain.WatchConfirmed @@ -52,7 +54,7 @@ data object WaitForInit : ChannelState() { buildSet { add(ChannelTlv.ChannelTypeTlv(cmd.channelType)) cmd.requestRemoteFunding?.let { add(ChannelTlv.RequestFundingTlv(it)) } - if (cmd.channelType == ChannelType.SupportedChannelType.SimpleTaprootStaging) add( + if (Features.canUseFeature(cmd.localParams.features, cmd.remoteInit.features, Feature.SimpleTaprootStaging)) add( ChannelTlv.NextLocalNoncesTlv( listOf( channelKeys.verificationNonce(0, 0).second, diff --git a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt index ba7833d6e..ca7927094 100644 --- a/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt +++ b/modules/core/src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt @@ -1357,6 +1357,11 @@ class Peer( // We ask our peer to pay the commit tx fees. val localParams = LocalParams(nodeParams, isChannelOpener = true, payCommitTxFees = false) val channelFlags = ChannelFlags(announceChannel = false, nonInitiatorPaysCommitFees = true) + val channelType = if (Features.canUseFeature(localParams.features, theirInit!!.features, Feature.SimpleTaprootStaging)) { + ChannelType.SupportedChannelType.SimpleTaprootStaging + } else { + ChannelType.SupportedChannelType.AnchorOutputsZeroReserve + } val initCommand = ChannelCommand.Init.Initiator( replyTo = CompletableDeferred(), fundingAmount = localFundingAmount, @@ -1367,7 +1372,7 @@ class Peer( remoteInit = theirInit!!, channelFlags = channelFlags, channelConfig = ChannelConfig.standard, - channelType = ChannelType.SupportedChannelType.AnchorOutputsZeroReserve, + channelType = channelType, requestRemoteFunding = requestRemoteFunding, channelOrigin = Origin.OnChainWallet(cmd.walletInputs.map { it.outPoint }.toSet(), cmd.totalAmount.toMilliSatoshi(), fees), ) @@ -1472,6 +1477,11 @@ class Peer( } else -> { logger.info { "requesting on-the-fly channel for paymentHash=${cmd.paymentHash} feerate=$fundingFeerate fee=${totalFees.total} paymentType=${paymentDetails.paymentType}" } + val channelType = if (Features.canUseFeature(localParams.features, theirInit!!.features, Feature.SimpleTaprootStaging)) { + ChannelType.SupportedChannelType.SimpleTaprootStaging + } else { + ChannelType.SupportedChannelType.AnchorOutputsZeroReserve + } val (state, actions) = WaitForInit.process( ChannelCommand.Init.Initiator( replyTo = CompletableDeferred(), @@ -1483,7 +1493,7 @@ class Peer( remoteInit = theirInit!!, channelFlags = channelFlags, channelConfig = ChannelConfig.standard, - channelType = ChannelType.SupportedChannelType.AnchorOutputsZeroReserve, + channelType = channelType, requestRemoteFunding = LiquidityAds.RequestFunding(cmd.requestedAmount, cmd.fundingRate, paymentDetails), channelOrigin = Origin.OffChainPayment(cmd.preimage, cmd.paymentAmount, totalFees), ) diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt index 6d4913b41..aa9573ebf 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/SpliceTestsCommon.kt @@ -1,6 +1,7 @@ package fr.acinq.lightning.channel.states import fr.acinq.bitcoin.* +import fr.acinq.lightning.Feature import fr.acinq.lightning.Lightning.randomBytes32 import fr.acinq.lightning.Lightning.randomKey import fr.acinq.lightning.blockchain.* @@ -154,6 +155,9 @@ open class SpliceTestsCommon : LightningTestSuite() { @Test fun `splice funds out -- would go below reserve`() { + if (defaultChannelType.toFeatures().hasFeature(Feature.ZeroReserveChannels)) { + return + } val (alice, bob) = reachNormalWithConfirmedFundingTx(defaultChannelType) val (alice1, bob1, _) = setupHtlcs(alice, bob) val cmd = createSpliceOutRequest(810_000.sat) diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt index 268d57724..40a5c9dfc 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/channel/states/WaitForFundingCreatedTestsCommon.kt @@ -99,8 +99,8 @@ class WaitForFundingCreatedTestsCommon : LightningTestSuite() { actionsBob3.has() assertIs(alice2.state) assertIs(bob3.state) - assertEquals(alice2.state.channelParams.channelFeatures, ChannelFeatures(setOf(Feature.StaticRemoteKey, Feature.AnchorOutputs, Feature.DualFunding, Feature.SimpleTaprootStaging))) - assertEquals(bob3.state.channelParams.channelFeatures, ChannelFeatures(setOf(Feature.StaticRemoteKey, Feature.AnchorOutputs, Feature.DualFunding, Feature.SimpleTaprootStaging))) + assertEquals(alice2.state.channelParams.channelFeatures, ChannelFeatures(setOf(Feature.StaticRemoteKey, Feature.AnchorOutputs, Feature.ZeroReserveChannels, Feature.DualFunding, Feature.SimpleTaprootStaging))) + assertEquals(bob3.state.channelParams.channelFeatures, ChannelFeatures(setOf(Feature.StaticRemoteKey, Feature.AnchorOutputs, Feature.ZeroReserveChannels, Feature.DualFunding, Feature.SimpleTaprootStaging))) verifyCommits(alice2.state.signingSession, bob3.state.signingSession, TestConstants.aliceFundingAmount.toMilliSatoshi(), 0.msat) }