Skip to content

Commit ad8b2e3

Browse files
authored
Add "phoenix zero reserve" feature bit (#3176)
* Add PhoenixZeroReserve feature bit Add a feature bit for zero-reserve channel. It is used by phoenix wallets and different from the feature bit proposed in lightning/bolts#1140. * Simplify SimpleTaprootChannelsPhoenix channel type It does not make sense to have versions with/without scid-alias and zero-conf.
1 parent abe2cc9 commit ad8b2e3

File tree

6 files changed

+34
-31
lines changed

6 files changed

+34
-31
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/Features.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,11 @@ object Features {
312312
val mandatory = 60
313313
}
314314

315+
case object PhoenixZeroReserve extends Feature with InitFeature with ChannelTypeFeature with PermanentChannelFeature {
316+
val rfcName = "phoenix_zero_reserve"
317+
val mandatory = 128
318+
}
319+
315320
/** This feature bit indicates that the node is a mobile wallet that can be woken up via push notifications. */
316321
case object WakeUpNotificationClient extends Feature with InitFeature {
317322
val rfcName = "wake_up_notification_client"
@@ -401,7 +406,8 @@ object Features {
401406
AsyncPaymentPrototype,
402407
SplicePrototype,
403408
OnTheFlyFunding,
404-
FundingFeeCredit
409+
FundingFeeCredit,
410+
PhoenixZeroReserve
405411
)
406412

407413
// Features may depend on other features, as specified in Bolt 9.

eclair-core/src/main/scala/fr/acinq/eclair/channel/ChannelFeatures.scala

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,6 @@ object ChannelTypes {
118118
override def commitmentFormat: CommitmentFormat = ZeroFeeHtlcTxAnchorOutputsCommitmentFormat
119119
override def toString: String = s"anchor_outputs_zero_fee_htlc_tx${if (scidAlias) "+scid_alias" else ""}${if (zeroConf) "+zeroconf" else ""}"
120120
}
121-
case class SimpleTaprootChannelsPhoenix(scidAlias: Boolean = false, zeroConf: Boolean = false) extends SupportedChannelType {
122-
/** Known channel-type features */
123-
override def features: Set[ChannelTypeFeature] = Set(
124-
if (scidAlias) Some(Features.ScidAlias) else None,
125-
if (zeroConf) Some(Features.ZeroConf) else None,
126-
Some(Features.SimpleTaprootChannelsPhoenix),
127-
).flatten
128-
override def paysDirectlyToWallet: Boolean = false
129-
override def commitmentFormat: CommitmentFormat = PhoenixSimpleTaprootChannelCommitmentFormat
130-
override def toString: String = s"simple_taproot_channel_phoenix${if (scidAlias) "+scid_alias" else ""}${if (zeroConf) "+zeroconf" else ""}"
131-
}
132121
case class SimpleTaprootChannelsStaging(scidAlias: Boolean = false, zeroConf: Boolean = false) extends SupportedChannelType {
133122
/** Known channel-type features */
134123
override def features: Set[ChannelTypeFeature] = Set(
@@ -145,6 +134,16 @@ object ChannelTypes {
145134
override def features: Set[InitFeature] = featureBits.activated.keySet
146135
override def toString: String = s"0x${featureBits.toByteVector.toHex}"
147136
}
137+
138+
// Phoenix uses custom channel types, that we may remove in the future.
139+
case object SimpleTaprootChannelsPhoenix extends SupportedChannelType {
140+
/** Known channel-type features */
141+
override def features: Set[ChannelTypeFeature] = Set(Features.PhoenixZeroReserve, Features.SimpleTaprootChannelsPhoenix)
142+
override def paysDirectlyToWallet: Boolean = false
143+
override def commitmentFormat: CommitmentFormat = PhoenixSimpleTaprootChannelCommitmentFormat
144+
override def toString: String = "phoenix_simple_taproot_channel"
145+
}
146+
148147
// @formatter:on
149148

150149
private val features2ChannelType: Map[Features[_ <: InitFeature], SupportedChannelType] = Set(
@@ -164,10 +163,7 @@ object ChannelTypes {
164163
AnchorOutputsZeroFeeHtlcTx(zeroConf = true),
165164
AnchorOutputsZeroFeeHtlcTx(scidAlias = true),
166165
AnchorOutputsZeroFeeHtlcTx(scidAlias = true, zeroConf = true),
167-
SimpleTaprootChannelsPhoenix(),
168-
SimpleTaprootChannelsPhoenix(zeroConf = true),
169-
SimpleTaprootChannelsPhoenix(scidAlias = true),
170-
SimpleTaprootChannelsPhoenix(scidAlias = true, zeroConf = true),
166+
SimpleTaprootChannelsPhoenix,
171167
SimpleTaprootChannelsStaging(),
172168
SimpleTaprootChannelsStaging(zeroConf = true),
173169
SimpleTaprootChannelsStaging(scidAlias = true),
@@ -188,7 +184,7 @@ object ChannelTypes {
188184
if (canUse(Features.SimpleTaprootChannelsStaging)) {
189185
SimpleTaprootChannelsStaging(scidAlias, zeroConf)
190186
} else if (canUse(Features.SimpleTaprootChannelsPhoenix)) {
191-
SimpleTaprootChannelsPhoenix(scidAlias, zeroConf)
187+
SimpleTaprootChannelsPhoenix
192188
} else if (canUse(Features.AnchorOutputsZeroFeeHtlcTx)) {
193189
AnchorOutputsZeroFeeHtlcTx(scidAlias, zeroConf)
194190
} else if (canUse(Features.AnchorOutputs)) {

eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import fr.acinq.eclair.blockchain._
3030
import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher
3131
import fr.acinq.eclair.blockchain.bitcoind.ZmqWatcher._
3232
import fr.acinq.eclair.blockchain.bitcoind.rpc.BitcoinCoreClient
33+
import fr.acinq.eclair.channel.ChannelTypes.SimpleTaprootChannelsPhoenix
3334
import fr.acinq.eclair.channel.Commitments.PostRevocationAction
3435
import fr.acinq.eclair.channel.Helpers.Closing.MutualClose
3536
import fr.acinq.eclair.channel.Helpers.Syncing.SyncResult
@@ -1113,8 +1114,8 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall
11131114
// We only support updating phoenix channels to taproot: we ignore other attempts at upgrading the
11141115
// commitment format and will simply apply the previous commitment format.
11151116
val nextCommitmentFormat = msg.channelType_opt match {
1116-
case Some(channelType: ChannelTypes.SimpleTaprootChannelsPhoenix) if parentCommitment.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat =>
1117-
log.info(s"accepting upgrade to $channelType during splice from commitment format ${parentCommitment.commitmentFormat}")
1117+
case Some(ChannelTypes.SimpleTaprootChannelsPhoenix) if parentCommitment.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat =>
1118+
log.info(s"accepting upgrade to SimpleTaprootChannelsPhoenix during splice from commitment format ${parentCommitment.commitmentFormat}")
11181119
PhoenixSimpleTaprootChannelCommitmentFormat
11191120
case Some(channelType) =>
11201121
log.info(s"rejecting upgrade to $channelType during splice from commitment format ${parentCommitment.commitmentFormat}")
@@ -1181,7 +1182,7 @@ class Channel(val nodeParams: NodeParams, val channelKeys: ChannelKeys, val wall
11811182
// We only support updating phoenix channels to taproot: we ignore other attempts at upgrading the
11821183
// commitment format and will simply apply the previous commitment format.
11831184
val nextCommitmentFormat = msg.channelType_opt match {
1184-
case Some(_: ChannelTypes.SimpleTaprootChannelsPhoenix) if parentCommitment.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat => PhoenixSimpleTaprootChannelCommitmentFormat
1185+
case Some(ChannelTypes.SimpleTaprootChannelsPhoenix) if parentCommitment.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat => PhoenixSimpleTaprootChannelCommitmentFormat
11851186
case _ => parentCommitment.commitmentFormat
11861187
}
11871188
val fundingParams = InteractiveTxParams(

eclair-core/src/test/scala/fr/acinq/eclair/channel/InteractiveTxBuilderSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
825825
val utxosA = Seq(150_000 sat)
826826
val fundingB1 = 90_000 sat
827827
val utxosB = Seq(130_000 sat)
828-
withFixture(ChannelTypes.SimpleTaprootChannelsPhoenix(), fundingA1, utxosA, fundingB1, utxosB, FeeratePerKw(1000 sat), 660 sat, 0, RequireConfirmedInputs(forLocal = true, forRemote = true)) { f =>
828+
withFixture(ChannelTypes.SimpleTaprootChannelsPhoenix, fundingA1, utxosA, fundingB1, utxosB, FeeratePerKw(1000 sat), 660 sat, 0, RequireConfirmedInputs(forLocal = true, forRemote = true)) { f =>
829829
import f._
830830

831831
val probe = TestProbe()
@@ -2934,7 +2934,7 @@ class InteractiveTxBuilderSpec extends TestKitBaseClass with AnyFunSuiteLike wit
29342934
test("invalid commit_sig (taproot)") {
29352935
val (alice2bob, bob2alice) = (TestProbe(), TestProbe())
29362936
val wallet = new SingleKeyOnChainWallet()
2937-
val params = createFixtureParams(ChannelTypes.SimpleTaprootChannelsPhoenix(), 100_000 sat, 25_000 sat, FeeratePerKw(5000 sat), 330 sat, 0)
2937+
val params = createFixtureParams(ChannelTypes.SimpleTaprootChannelsPhoenix, 100_000 sat, 25_000 sat, FeeratePerKw(5000 sat), 330 sat, 0)
29382938
val alice = params.spawnTxBuilderAlice(wallet)
29392939
val bob = params.spawnTxBuilderBob(wallet)
29402940
alice ! Start(alice2bob.ref)

eclair-core/src/test/scala/fr/acinq/eclair/channel/states/a/WaitForAcceptChannelStateSpec.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS
110110
test("recv AcceptChannel (simple taproot channels phoenix)", Tag(ChannelStateTestsTags.OptionSimpleTaprootPhoenix)) { f =>
111111
import f._
112112
val accept = bob2alice.expectMsgType[AcceptChannel]
113-
assert(accept.channelType_opt.contains(ChannelTypes.SimpleTaprootChannelsPhoenix()))
113+
assert(accept.channelType_opt.contains(ChannelTypes.SimpleTaprootChannelsPhoenix))
114114
assert(accept.commitNonce_opt.isDefined)
115115
bob2alice.forward(alice)
116116
awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL)
@@ -121,7 +121,7 @@ class WaitForAcceptChannelStateSpec extends TestKitBaseClass with FixtureAnyFunS
121121
test("recv AcceptChannel (simple taproot channels outputs, missing nonce)", Tag(ChannelStateTestsTags.OptionSimpleTaprootPhoenix)) { f =>
122122
import f._
123123
val accept = bob2alice.expectMsgType[AcceptChannel]
124-
assert(accept.channelType_opt.contains(ChannelTypes.SimpleTaprootChannelsPhoenix()))
124+
assert(accept.channelType_opt.contains(ChannelTypes.SimpleTaprootChannelsPhoenix))
125125
assert(accept.commitNonce_opt.isDefined)
126126
bob2alice.forward(alice, accept.copy(tlvStream = accept.tlvStream.copy(records = accept.tlvStream.records.filterNot(_.isInstanceOf[ChannelTlv.NextLocalNonceTlv]))))
127127
alice2bob.expectMsg(Error(accept.temporaryChannelId, MissingCommitNonce(accept.temporaryChannelId, TxId(ByteVector32.Zeroes), 0).getMessage))

eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
757757
import f._
758758

759759
val htlcs = setupHtlcs(f)
760-
initiateSplice(f, spliceIn_opt = Some(SpliceIn(400_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix()))
760+
initiateSplice(f, spliceIn_opt = Some(SpliceIn(400_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix))
761761
assert(alice.commitments.active.head.commitmentFormat == PhoenixSimpleTaprootChannelCommitmentFormat)
762762
assert(alice.commitments.active.last.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat)
763763
resolveHtlcs(f, htlcs)
@@ -767,7 +767,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
767767
import f._
768768

769769
val htlcs = setupHtlcs(f)
770-
initiateSplice(f, spliceIn_opt = Some(SpliceIn(400_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix()))
770+
initiateSplice(f, spliceIn_opt = Some(SpliceIn(400_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix))
771771
assert(alice.commitments.active.head.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat)
772772
assert(alice.commitments.active.last.commitmentFormat == ZeroFeeHtlcTxAnchorOutputsCommitmentFormat)
773773
resolveHtlcs(f, htlcs)
@@ -3724,7 +3724,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
37243724
val htlcs = setupHtlcs(f)
37253725

37263726
// Our first splice upgrades the channel to taproot.
3727-
val fundingTx1 = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix()))
3727+
val fundingTx1 = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix))
37283728
checkWatchConfirmed(f, fundingTx1)
37293729

37303730
// The first splice confirms on Bob's side.
@@ -3819,7 +3819,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
38193819
val htlcs = setupHtlcs(f)
38203820

38213821
// Our splice upgrades the channel to taproot.
3822-
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix()))
3822+
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix))
38233823
assert(alice.commitments.active.head.commitmentFormat == PhoenixSimpleTaprootChannelCommitmentFormat)
38243824
assert(alice.commitments.active.last.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat)
38253825
checkWatchConfirmed(f, spliceTx)
@@ -3860,7 +3860,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
38603860
val htlcs = setupHtlcs(f)
38613861

38623862
// Our splice upgrades the channel to taproot.
3863-
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix()))
3863+
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix))
38643864
assert(alice.commitments.active.head.commitmentFormat == PhoenixSimpleTaprootChannelCommitmentFormat)
38653865
assert(alice.commitments.active.last.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat)
38663866
checkWatchConfirmed(f, spliceTx)
@@ -3911,7 +3911,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
39113911
val htlcs = setupHtlcs(f)
39123912

39133913
// Our splice upgrades the channel to taproot.
3914-
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix()))
3914+
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix))
39153915
assert(alice.commitments.active.head.commitmentFormat == PhoenixSimpleTaprootChannelCommitmentFormat)
39163916
assert(alice.commitments.active.last.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat)
39173917
checkWatchConfirmed(f, spliceTx)
@@ -3947,7 +3947,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
39473947
val htlcs = setupHtlcs(f)
39483948

39493949
// Our splice upgrades the channel to taproot.
3950-
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix()))
3950+
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), channelType_opt = Some(ChannelTypes.SimpleTaprootChannelsPhoenix))
39513951
assert(alice.commitments.active.head.commitmentFormat == PhoenixSimpleTaprootChannelCommitmentFormat)
39523952
assert(alice.commitments.active.last.commitmentFormat == UnsafeLegacyAnchorOutputsCommitmentFormat)
39533953
assert(alice2blockchain.expectMsgType[WatchPublished].txId == spliceTx.txid)

0 commit comments

Comments
 (0)