diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index b5a2fecfd7..de33913209 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -133,9 +133,6 @@ case class ChannelParams(channelId: ByteVector32, else Right(remoteScriptPubKey) } - /** If both peers support quiescence, we have to exchange stfu when splicing. */ - def useQuiescence: Boolean = Features.canUseFeature(localParams.initFeatures, remoteParams.initFeatures, Features.Quiescence) - } object ChannelParams { @@ -822,7 +819,7 @@ case class Commitments(params: ChannelParams, def localIsQuiescent: Boolean = changes.localChanges.all.isEmpty def remoteIsQuiescent: Boolean = changes.remoteChanges.all.isEmpty // HTLCs and pending changes are the same for all active commitments, so we don't need to loop through all of them. - def isQuiescent: Boolean = (params.useQuiescence || active.head.hasNoPendingHtlcs) && localIsQuiescent && remoteIsQuiescent + def isQuiescent: Boolean = localIsQuiescent && remoteIsQuiescent def hasNoPendingHtlcsOrFeeUpdate: Boolean = active.head.hasNoPendingHtlcsOrFeeUpdate(changes) def hasPendingOrProposedHtlcs: Boolean = active.head.hasPendingOrProposedHtlcs(changes) def timedOutOutgoingHtlcs(currentHeight: BlockHeight): Set[UpdateAddHtlc] = active.head.timedOutOutgoingHtlcs(currentHeight) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala index 5d73fb0241..1ad6ad4f57 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/Channel.scala @@ -854,21 +854,13 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with case Event(cmd: CMD_SPLICE, d: DATA_NORMAL) => if (d.commitments.params.remoteParams.initFeatures.hasFeature(Features.SplicePrototype)) { d.spliceStatus match { - case SpliceStatus.NoSplice if d.commitments.params.useQuiescence => + case SpliceStatus.NoSplice => startSingleTimer(QuiescenceTimeout.toString, QuiescenceTimeout(peer), nodeParams.channelConf.quiescenceTimeout) if (d.commitments.localIsQuiescent) { stay() using d.copy(spliceStatus = SpliceStatus.InitiatorQuiescent(cmd)) sending Stfu(d.channelId, initiator = true) } else { stay() using d.copy(spliceStatus = SpliceStatus.QuiescenceRequested(cmd)) } - case SpliceStatus.NoSplice if !d.commitments.params.useQuiescence => - initiateSplice(cmd, d) match { - case Left(f) => - cmd.replyTo ! RES_FAILURE(cmd, f) - stay() - case Right(spliceInit) => - stay() using d.copy(spliceStatus = SpliceStatus.SpliceRequested(cmd, spliceInit)) sending spliceInit - } case _ => log.warning("cannot initiate splice, another one is already in progress") cmd.replyTo ! RES_FAILURE(cmd, InvalidSpliceAlreadyInProgress(d.channelId)) @@ -886,62 +878,53 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with stay() case Event(msg: Stfu, d: DATA_NORMAL) => - if (d.commitments.params.useQuiescence) { - if (d.commitments.remoteIsQuiescent) { - d.spliceStatus match { - case SpliceStatus.NoSplice => - startSingleTimer(QuiescenceTimeout.toString, QuiescenceTimeout(peer), nodeParams.channelConf.quiescenceTimeout) - if (d.commitments.localIsQuiescent) { - stay() using d.copy(spliceStatus = SpliceStatus.NonInitiatorQuiescent) sending Stfu(d.channelId, initiator = false) - } else { - stay() using d.copy(spliceStatus = SpliceStatus.ReceivedStfu(msg)) - } - case SpliceStatus.QuiescenceRequested(cmd) => - // We could keep track of our splice attempt and merge it with the remote splice instead of cancelling it. - // But this is an edge case that should rarely occur, so it's probably not worth the additional complexity. - log.warning("our peer initiated quiescence before us, cancelling our splice attempt") - cmd.replyTo ! RES_FAILURE(cmd, ConcurrentRemoteSplice(d.channelId)) + if (d.commitments.remoteIsQuiescent) { + d.spliceStatus match { + case SpliceStatus.NoSplice => + startSingleTimer(QuiescenceTimeout.toString, QuiescenceTimeout(peer), nodeParams.channelConf.quiescenceTimeout) + if (d.commitments.localIsQuiescent) { + stay() using d.copy(spliceStatus = SpliceStatus.NonInitiatorQuiescent) sending Stfu(d.channelId, initiator = false) + } else { stay() using d.copy(spliceStatus = SpliceStatus.ReceivedStfu(msg)) - case SpliceStatus.InitiatorQuiescent(cmd) => - // if both sides send stfu at the same time, the quiescence initiator is the channel opener - if (!msg.initiator || d.commitments.params.localParams.isChannelOpener) { - initiateSplice(cmd, d) match { - case Left(f) => - cmd.replyTo ! RES_FAILURE(cmd, f) - context.system.scheduler.scheduleOnce(2 second, peer, Peer.Disconnect(remoteNodeId)) - stay() using d.copy(spliceStatus = SpliceStatus.NoSplice) sending Warning(d.channelId, f.getMessage) - case Right(spliceInit) => - stay() using d.copy(spliceStatus = SpliceStatus.SpliceRequested(cmd, spliceInit)) sending spliceInit - } - } else { - log.warning("concurrent stfu received and our peer is the channel initiator, cancelling our splice attempt") - cmd.replyTo ! RES_FAILURE(cmd, ConcurrentRemoteSplice(d.channelId)) - stay() using d.copy(spliceStatus = SpliceStatus.NonInitiatorQuiescent) + } + case SpliceStatus.QuiescenceRequested(cmd) => + // We could keep track of our splice attempt and merge it with the remote splice instead of cancelling it. + // But this is an edge case that should rarely occur, so it's probably not worth the additional complexity. + log.warning("our peer initiated quiescence before us, cancelling our splice attempt") + cmd.replyTo ! RES_FAILURE(cmd, ConcurrentRemoteSplice(d.channelId)) + stay() using d.copy(spliceStatus = SpliceStatus.ReceivedStfu(msg)) + case SpliceStatus.InitiatorQuiescent(cmd) => + // if both sides send stfu at the same time, the quiescence initiator is the channel opener + if (!msg.initiator || d.commitments.params.localParams.isChannelOpener) { + initiateSplice(cmd, d) match { + case Left(f) => + cmd.replyTo ! RES_FAILURE(cmd, f) + context.system.scheduler.scheduleOnce(2 second, peer, Peer.Disconnect(remoteNodeId)) + stay() using d.copy(spliceStatus = SpliceStatus.NoSplice) sending Warning(d.channelId, f.getMessage) + case Right(spliceInit) => + stay() using d.copy(spliceStatus = SpliceStatus.SpliceRequested(cmd, spliceInit)) sending spliceInit } - case _ => - log.warning("ignoring duplicate stfu") - stay() - } - } else { - log.warning("our peer sent stfu but is not quiescent") - // NB: we use a small delay to ensure we've sent our warning before disconnecting. - context.system.scheduler.scheduleOnce(2 second, peer, Peer.Disconnect(remoteNodeId)) - stay() using d.copy(spliceStatus = SpliceStatus.NoSplice) sending Warning(d.channelId, InvalidSpliceNotQuiescent(d.channelId).getMessage) + } else { + log.warning("concurrent stfu received and our peer is the channel initiator, cancelling our splice attempt") + cmd.replyTo ! RES_FAILURE(cmd, ConcurrentRemoteSplice(d.channelId)) + stay() using d.copy(spliceStatus = SpliceStatus.NonInitiatorQuiescent) + } + case _ => + log.warning("ignoring duplicate stfu") + stay() } } else { - log.warning("ignoring stfu because both peers do not advertise quiescence") - stay() + log.warning("our peer sent stfu but is not quiescent") + // NB: we use a small delay to ensure we've sent our warning before disconnecting. + context.system.scheduler.scheduleOnce(2 second, peer, Peer.Disconnect(remoteNodeId)) + stay() using d.copy(spliceStatus = SpliceStatus.NoSplice) sending Warning(d.channelId, InvalidSpliceNotQuiescent(d.channelId).getMessage) } case Event(_: QuiescenceTimeout, d: DATA_NORMAL) => handleQuiescenceTimeout(d) - case Event(_: SpliceInit, d: DATA_NORMAL) if d.spliceStatus == SpliceStatus.NoSplice && d.commitments.params.useQuiescence => - log.info("rejecting splice attempt: quiescence not negotiated") - stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceNotQuiescent(d.channelId).getMessage) - case Event(msg: SpliceInit, d: DATA_NORMAL) => d.spliceStatus match { - case SpliceStatus.NoSplice | SpliceStatus.NonInitiatorQuiescent => + case SpliceStatus.NonInitiatorQuiescent => if (!d.commitments.isQuiescent) { log.info("rejecting splice request: channel not quiescent") stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceNotQuiescent(d.channelId).getMessage) @@ -993,6 +976,9 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with stay() using d.copy(spliceStatus = SpliceStatus.SpliceInProgress(cmd_opt = None, sessionId, txBuilder, remoteCommitSig = None)) sending spliceAck } } + case SpliceStatus.NoSplice => + log.info("rejecting splice attempt: quiescence not negotiated") + stay() using d.copy(spliceStatus = SpliceStatus.SpliceAborted) sending TxAbort(d.channelId, InvalidSpliceNotQuiescent(d.channelId).getMessage) case SpliceStatus.SpliceAborted => log.info("rejecting splice attempt: our previous tx_abort was not acked") stay() sending Warning(d.channelId, InvalidSpliceTxAbortNotAcked(d.channelId).getMessage) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala index 6f56850eb0..c9c2418c6f 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/TestConstants.scala @@ -106,6 +106,8 @@ object TestConstants { Features.PaymentMetadata -> FeatureSupport.Optional, Features.RouteBlinding -> FeatureSupport.Optional, Features.StaticRemoteKey -> FeatureSupport.Mandatory, + Features.Quiescence -> FeatureSupport.Optional, + Features.SplicePrototype -> FeatureSupport.Optional, ), unknown = Set(UnknownFeature(TestFeature.optional)) ), @@ -282,6 +284,8 @@ object TestConstants { Features.RouteBlinding -> FeatureSupport.Optional, Features.StaticRemoteKey -> FeatureSupport.Mandatory, Features.AnchorOutputsZeroFeeHtlcTx -> FeatureSupport.Optional, + Features.Quiescence -> FeatureSupport.Optional, + Features.SplicePrototype -> FeatureSupport.Optional, ), pluginParams = Nil, overrideInitFeatures = Map.empty, diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala index 5ec9456251..53b9953633 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala @@ -53,8 +53,6 @@ object ChannelStateTestsTags { val DualFunding = "dual_funding" /** If set, a liquidity ads will be used when opening a channel. */ val LiquidityAds = "liquidity_ads" - /** If set, peers will support splicing. */ - val Splicing = "splicing" /** If set, channels will use option_static_remotekey. */ val StaticRemoteKey = "static_remotekey" /** If set, channels will use option_anchor_outputs. */ @@ -93,8 +91,6 @@ object ChannelStateTestsTags { val RejectRbfAttempts = "reject_rbf_attempts" /** If set, the non-initiator will require a 1-block delay between RBF attempts. */ val DelayRbfAttempts = "delay_rbf_attempts" - /** If set, peers will support the quiesce protocol. */ - val Quiescence = "quiescence" /** If set, channels will adapt their max HTLC amount to the available balance */ val AdaptMaxHtlcAmount = "adapt-max-htlc-amount" } @@ -165,7 +161,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually { .modify(_.channelConf.balanceThresholds).setToIf(tags.contains(ChannelStateTestsTags.AdaptMaxHtlcAmount))(Seq(Channel.BalanceThreshold(1_000 sat, 0 sat), Channel.BalanceThreshold(5_000 sat, 1_000 sat), Channel.BalanceThreshold(10_000 sat, 5_000 sat))) val wallet = wallet_opt match { case Some(wallet) => wallet - case None => if (tags.contains(ChannelStateTestsTags.DualFunding) || tags.contains(ChannelStateTestsTags.Splicing)) new SingleKeyOnChainWallet() else new DummyOnChainWallet() + case None => if (tags.contains(ChannelStateTestsTags.DualFunding)) new SingleKeyOnChainWallet() else new DummyOnChainWallet() } val alice: TestFSMRef[ChannelState, ChannelData, Channel] = { implicit val system: ActorSystem = systemA @@ -192,8 +188,6 @@ trait ChannelStateTestsBase extends Assertions with Eventually { .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.ZeroConf))(_.updated(Features.ZeroConf, FeatureSupport.Optional)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.ScidAlias))(_.updated(Features.ScidAlias, FeatureSupport.Optional)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.DualFunding))(_.updated(Features.DualFunding, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.Splicing))(_.updated(Features.SplicePrototype, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.Quiescence))(_.updated(Features.Quiescence, FeatureSupport.Optional)) .initFeatures() val bobInitFeatures = Bob.nodeParams.features .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.DisableWumbo))(_.removed(Features.Wumbo)) @@ -206,8 +200,6 @@ trait ChannelStateTestsBase extends Assertions with Eventually { .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.ZeroConf))(_.updated(Features.ZeroConf, FeatureSupport.Optional)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.ScidAlias))(_.updated(Features.ScidAlias, FeatureSupport.Optional)) .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.DualFunding))(_.updated(Features.DualFunding, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.Splicing))(_.updated(Features.SplicePrototype, FeatureSupport.Optional)) - .modify(_.activated).usingIf(tags.contains(ChannelStateTestsTags.Quiescence))(_.updated(Features.Quiescence, FeatureSupport.Optional)) .initFeatures() val channelType = ChannelTypes.defaultFromFeatures(aliceInitFeatures, bobInitFeatures, announceChannel = channelFlags.announceChannel) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala index 5a5910ceaa..f441a860a2 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalQuiescentStateSpec.scala @@ -45,7 +45,7 @@ class NormalQuiescentStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteL implicit val log: akka.event.LoggingAdapter = akka.event.NoLogging override def withFixture(test: OneArgTest): Outcome = { - val tags = test.tags + ChannelStateTestsTags.DualFunding + ChannelStateTestsTags.Splicing + ChannelStateTestsTags.Quiescence + val tags = test.tags + ChannelStateTestsTags.DualFunding val setup = init(tags = tags) import setup._ reachNormal(setup, tags) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala index a5c983e606..b8148e633d 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalSplicesStateSpec.scala @@ -59,7 +59,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik implicit val log: akka.event.LoggingAdapter = akka.event.NoLogging override def withFixture(test: OneArgTest): Outcome = { - val tags = test.tags + ChannelStateTestsTags.DualFunding + ChannelStateTestsTags.Splicing + val tags = test.tags + ChannelStateTestsTags.DualFunding val setup = init(tags = tags) import setup._ reachNormal(setup, tags) @@ -72,17 +72,11 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik private val defaultSpliceOutScriptPubKey = hex"0020aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - private def useQuiescence(s: TestFSMRef[ChannelState, ChannelData, Channel]): Boolean = s.stateData.asInstanceOf[ChannelDataWithCommitments].commitments.params.useQuiescence - - private def useQuiescence(f: FixtureParam): Boolean = useQuiescence(f.alice) - private def initiateSpliceWithoutSigs(s: TestFSMRef[ChannelState, ChannelData, Channel], r: TestFSMRef[ChannelState, ChannelData, Channel], s2r: TestProbe, r2s: TestProbe, spliceIn_opt: Option[SpliceIn], spliceOut_opt: Option[SpliceOut]): TestProbe = { val sender = TestProbe() val cmd = CMD_SPLICE(sender.ref, spliceIn_opt, spliceOut_opt, None) s ! cmd - if (useQuiescence(s)) { - exchangeStfu(s, r, s2r, r2s) - } + exchangeStfu(s, r, s2r, r2s) s2r.expectMsgType[SpliceInit] s2r.forward(r) r2s.expectMsgType[SpliceAck] @@ -174,37 +168,29 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik private def setupHtlcs(f: FixtureParam): TestHtlcs = { import f._ - if (useQuiescence(f)) { - // add htlcs in both directions - val htlcsAliceToBob = Seq( - addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice), - addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice) - ) - crossSign(alice, bob, alice2bob, bob2alice) - val htlcsBobToAlice = Seq( - addHtlc(20_000_000 msat, bob, alice, bob2alice, alice2bob), - addHtlc(15_000_000 msat, bob, alice, bob2alice, alice2bob) - ) - crossSign(bob, alice, bob2alice, alice2bob) - - val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - assert(initialState.commitments.latest.capacity == 1_500_000.sat) - assert(initialState.commitments.latest.localCommit.spec.toLocal == 770_000_000.msat) - assert(initialState.commitments.latest.localCommit.spec.toRemote == 665_000_000.msat) - - alice2relayer.expectMsgType[Relayer.RelayForward] - alice2relayer.expectMsgType[Relayer.RelayForward] - bob2relayer.expectMsgType[Relayer.RelayForward] - bob2relayer.expectMsgType[Relayer.RelayForward] - - TestHtlcs(htlcsAliceToBob, htlcsBobToAlice) - } else { - val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] - assert(initialState.commitments.latest.capacity == 1_500_000.sat) - assert(initialState.commitments.latest.localCommit.spec.toLocal == 800_000_000.msat) - assert(initialState.commitments.latest.localCommit.spec.toRemote == 700_000_000.msat) - TestHtlcs(Seq.empty, Seq.empty) - } + // add htlcs in both directions + val htlcsAliceToBob = Seq( + addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice), + addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice) + ) + crossSign(alice, bob, alice2bob, bob2alice) + val htlcsBobToAlice = Seq( + addHtlc(20_000_000 msat, bob, alice, bob2alice, alice2bob), + addHtlc(15_000_000 msat, bob, alice, bob2alice, alice2bob) + ) + crossSign(bob, alice, bob2alice, alice2bob) + + val initialState = alice.stateData.asInstanceOf[DATA_NORMAL] + assert(initialState.commitments.latest.capacity == 1_500_000.sat) + assert(initialState.commitments.latest.localCommit.spec.toLocal == 770_000_000.msat) + assert(initialState.commitments.latest.localCommit.spec.toRemote == 665_000_000.msat) + + alice2relayer.expectMsgType[Relayer.RelayForward] + alice2relayer.expectMsgType[Relayer.RelayForward] + bob2relayer.expectMsgType[Relayer.RelayForward] + bob2relayer.expectMsgType[Relayer.RelayForward] + + TestHtlcs(htlcsAliceToBob, htlcsBobToAlice) } def spliceOutFee(f: FixtureParam, capacity: Satoshi): Satoshi = { @@ -224,7 +210,8 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik import f._ // if the swap includes a splice-in, swap-out fees will be paid from bitcoind so final capacity is predictable - val (outgoingHtlcs, incomingHtlcs) = if (useQuiescence(f)) (30_000_000.msat, 35_000_000.msat) else (0.msat, 0.msat) + val outgoingHtlcs = 30_000_000.msat + val incomingHtlcs = 35_000_000.msat val postSpliceState = alice.stateData.asInstanceOf[ChannelDataWithCommitments] assert(postSpliceState.commitments.latest.capacity == 1_900_000.sat - spliceOutFee) assert(postSpliceState.commitments.latest.localCommit.spec.toLocal == 1_200_000_000.msat - spliceOutFee - outgoingHtlcs) @@ -238,23 +225,21 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik checkPostSpliceState(f, spliceOutFee) - if (useQuiescence(f)) { - // resolve pre-splice HTLCs after splice - val Seq((preimage1a, htlc1a), (preimage2a, htlc2a)) = htlcs.aliceToBob - val Seq((preimage1b, htlc1b), (preimage2b, htlc2b)) = htlcs.bobToAlice - fulfillHtlc(htlc1a.id, preimage1a, bob, alice, bob2alice, alice2bob) - fulfillHtlc(htlc2a.id, preimage2a, bob, alice, bob2alice, alice2bob) - crossSign(bob, alice, bob2alice, alice2bob) - fulfillHtlc(htlc1b.id, preimage1b, alice, bob, alice2bob, bob2alice) - fulfillHtlc(htlc2b.id, preimage2b, alice, bob, alice2bob, bob2alice) - crossSign(alice, bob, alice2bob, bob2alice) - assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.localCommit.spec.htlcs.collect(outgoing).isEmpty) - assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.remoteCommit.spec.htlcs.collect(outgoing).isEmpty) - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.localCommit.spec.htlcs.collect(outgoing).isEmpty) - assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.remoteCommit.spec.htlcs.collect(outgoing).isEmpty) - } + // resolve pre-splice HTLCs after splice + val Seq((preimage1a, htlc1a), (preimage2a, htlc2a)) = htlcs.aliceToBob + val Seq((preimage1b, htlc1b), (preimage2b, htlc2b)) = htlcs.bobToAlice + fulfillHtlc(htlc1a.id, preimage1a, bob, alice, bob2alice, alice2bob) + fulfillHtlc(htlc2a.id, preimage2a, bob, alice, bob2alice, alice2bob) + crossSign(bob, alice, bob2alice, alice2bob) + fulfillHtlc(htlc1b.id, preimage1b, alice, bob, alice2bob, bob2alice) + fulfillHtlc(htlc2b.id, preimage2b, alice, bob, alice2bob, bob2alice) + crossSign(alice, bob, alice2bob, bob2alice) + assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.localCommit.spec.htlcs.collect(outgoing).isEmpty) + assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.remoteCommit.spec.htlcs.collect(outgoing).isEmpty) + assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.localCommit.spec.htlcs.collect(outgoing).isEmpty) + assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.active.head.remoteCommit.spec.htlcs.collect(outgoing).isEmpty) - val settledHtlcs = if (useQuiescence(f)) 5_000_000.msat else 0.msat + val settledHtlcs = 5_000_000.msat val finalState = alice.stateData.asInstanceOf[DATA_NORMAL] assert(finalState.commitments.latest.capacity == 1_900_000.sat - spliceOutFee) assert(finalState.commitments.latest.localCommit.spec.toLocal == 1_200_000_000.msat - spliceOutFee + settledHtlcs) @@ -277,10 +262,10 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik } test("recv CMD_SPLICE (splice-in, non dual-funded channel)") { () => - val f = init(tags = Set(ChannelStateTestsTags.DualFunding, ChannelStateTestsTags.Splicing)) + val f = init(tags = Set(ChannelStateTestsTags.DualFunding)) import f._ - reachNormal(f, tags = Set(ChannelStateTestsTags.Splicing)) // we open a non dual-funded channel + reachNormal(f, tags = Set.empty) // we open a non dual-funded channel alice2bob.ignoreMsg { case _: ChannelUpdate => true } bob2alice.ignoreMsg { case _: ChannelUpdate => true } awaitCond(alice.stateName == NORMAL && bob.stateName == NORMAL) @@ -305,7 +290,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(postSpliceState.commitments.latest.remoteChannelReserve == 15_000.sat) } - test("recv CMD_SPLICE (splice-in, liquidity ads)", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv CMD_SPLICE (splice-in, liquidity ads)") { f => import f._ val sender = TestProbe() @@ -354,7 +339,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik } } - test("recv CMD_SPLICE (splice-in, liquidity ads, invalid will_fund signature)", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv CMD_SPLICE (splice-in, liquidity ads, invalid will_fund signature)") { f => import f._ val sender = TestProbe() @@ -381,7 +366,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.spec.toRemote == 700_000_000.msat) } - test("recv CMD_SPLICE (splice-in, liquidity ads, below minimum funding amount)", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv CMD_SPLICE (splice-in, liquidity ads, below minimum funding amount)") { f => import f._ val sender = TestProbe() @@ -398,7 +383,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik alice2bob.forward(bob) } - test("recv CMD_SPLICE (splice-in, liquidity ads, invalid funding rate)", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv CMD_SPLICE (splice-in, liquidity ads, invalid funding rate)") { f => import f._ val sender = TestProbe() @@ -415,7 +400,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik alice2bob.forward(bob) } - test("recv CMD_SPLICE (splice-in, liquidity ads, cannot pay fees)", Tag(ChannelStateTestsTags.Quiescence), Tag(ChannelStateTestsTags.NoMaxHtlcValueInFlight)) { f => + test("recv CMD_SPLICE (splice-in, liquidity ads, cannot pay fees)", Tag(ChannelStateTestsTags.NoMaxHtlcValueInFlight)) { f => import f._ val sender = TestProbe() @@ -434,7 +419,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(bob2alice.expectMsgType[TxAbort].toAscii.contains("invalid balances")) } - test("recv CMD_SPLICE (splice-in, local and remote commit index mismatch)", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv CMD_SPLICE (splice-in, local and remote commit index mismatch)") { f => import f._ // Alice and Bob asynchronously exchange HTLCs, which makes their commit indices diverge. @@ -498,18 +483,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.spec.toRemote == 700_000_000.msat) } - test("recv CMD_SPLICE (splice-out, would go below reserve)") { f => - import f._ - - setupHtlcs(f) - - val sender = TestProbe() - val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = None, Some(SpliceOut(780_000.sat, defaultSpliceOutScriptPubKey)), requestFunding_opt = None) - alice ! cmd - sender.expectMsgType[RES_FAILURE[_, _]] - } - - test("recv CMD_SPLICE (splice-out, would go below reserve, quiescent)", Tag(ChannelStateTestsTags.Quiescence), Tag(ChannelStateTestsTags.NoMaxHtlcValueInFlight)) { f => + test("recv CMD_SPLICE (splice-out, would go below reserve)", Tag(ChannelStateTestsTags.NoMaxHtlcValueInFlight)) { f => import f._ setupHtlcs(f) @@ -527,6 +501,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val sender = TestProbe() val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(500_000 sat)), spliceOut_opt = None, requestFunding_opt = None) alice ! cmd + exchangeStfu(f) // we tweak the feerate val spliceInit = alice2bob.expectMsgType[SpliceInit].copy(feerate = FeeratePerKw(100.sat)) bob.setFeerates(alice.nodeParams.currentBitcoinCoreFeerates.copy(minimum = FeeratePerKw(101.sat))) @@ -546,6 +521,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val sender = TestProbe() val bobBalance = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.latest.localCommit.spec.toLocal alice ! CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(100_000 sat)), spliceOut_opt = None, requestFunding_opt = None) + exchangeStfu(f) val spliceInit = alice2bob.expectMsgType[SpliceInit] alice2bob.forward(bob, spliceInit) val spliceAck = bob2alice.expectMsgType[SpliceAck] @@ -590,27 +566,18 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik crossSign(alice, bob, alice2bob, bob2alice) } - def testSpliceInAndOutCmd(f: FixtureParam): Unit = { + test("recv CMD_SPLICE (splice-in + splice-out)") { f => val htlcs = setupHtlcs(f) - initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), spliceOut_opt = Some(SpliceOut(100_000 sat, defaultSpliceOutScriptPubKey))) - resolveHtlcs(f, htlcs, spliceOutFee = 0.sat) } - test("recv CMD_SPLICE (splice-in + splice-out)") { f => - testSpliceInAndOutCmd(f) - } - - test("recv CMD_SPLICE (splice-in + splice-out, quiescence)", Tag(ChannelStateTestsTags.Quiescence)) { f => - testSpliceInAndOutCmd(f) - } - test("recv TxAbort (before TxComplete)") { f => import f._ val sender = TestProbe() alice ! CMD_SPLICE(sender.ref, spliceIn_opt = None, spliceOut_opt = Some(SpliceOut(50_000 sat, defaultSpliceOutScriptPubKey)), requestFunding_opt = None) + exchangeStfu(f) alice2bob.expectMsgType[SpliceInit] alice2bob.forward(bob) bob2alice.expectMsgType[SpliceAck] @@ -635,6 +602,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val sender = TestProbe() alice ! CMD_SPLICE(sender.ref, spliceIn_opt = None, spliceOut_opt = Some(SpliceOut(50_000 sat, defaultSpliceOutScriptPubKey)), requestFunding_opt = None) + exchangeStfu(f) alice2bob.expectMsgType[SpliceInit] alice2bob.forward(bob) bob2alice.expectMsgType[SpliceAck] @@ -670,6 +638,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val sender = TestProbe() alice ! CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(50_000 sat)), spliceOut_opt = None, requestFunding_opt = None) + exchangeStfu(f) alice2bob.expectMsgType[SpliceInit] alice2bob.forward(bob) bob2alice.expectMsgType[SpliceAck] @@ -902,7 +871,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.inactive.map(_.fundingTxIndex) == Seq.empty) } - test("emit post-splice events", Tag(ChannelStateTestsTags.NoMaxHtlcValueInFlight), Tag(ChannelStateTestsTags.Quiescence)) { f => + test("emit post-splice events", Tag(ChannelStateTestsTags.NoMaxHtlcValueInFlight)) { f => import f._ // Alice and Bob asynchronously exchange HTLCs, which makes their commit indices diverge. @@ -1052,6 +1021,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val sender = TestProbe() val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(500_000 sat, pushAmount = 0 msat)), spliceOut_opt = None, requestFunding_opt = None) alice ! cmd + exchangeStfu(f) alice2bob.expectMsgType[SpliceInit] alice ! CMD_ADD_HTLC(sender.ref, 500000 msat, randomBytes32(), CltvExpiryDelta(144).toCltvExpiry(currentBlockHeight), TestConstants.emptyOnionPacket, None, 1.0, None, localOrigin(sender.ref)) sender.expectMsgType[RES_ADD_FAILED[_]] @@ -1063,6 +1033,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val sender = TestProbe() val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(500_000 sat, pushAmount = 0 msat)), spliceOut_opt = None, requestFunding_opt = None) alice ! cmd + exchangeStfu(f) alice2bob.expectMsgType[SpliceInit] alice2bob.forward(bob) bob2alice.expectMsgType[SpliceAck] @@ -1073,36 +1044,12 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik alice2bob.expectNoMessage(100 millis) } - test("recv UpdateAddHtlc while a splice is requested") { f => - import f._ - val sender = TestProbe() - val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(500_000 sat, pushAmount = 0 msat)), spliceOut_opt = None, requestFunding_opt = None) - alice ! cmd - alice2bob.expectMsgType[SpliceInit] - // we're holding the splice_init to create a race - - val (_, cmdAdd: CMD_ADD_HTLC) = makeCmdAdd(5_000_000 msat, bob.underlyingActor.remoteNodeId, bob.underlyingActor.nodeParams.currentBlockHeight) - bob ! cmdAdd - bob2alice.expectMsgType[UpdateAddHtlc] - bob2alice.forward(alice) - // now we forward the splice_init - alice2bob.forward(bob) - // bob rejects the SpliceInit because they have a pending htlc - bob2alice.expectMsgType[TxAbort] - bob2alice.forward(alice) - // alice returns a warning and schedules a disconnect after receiving UpdateAddHtlc - alice2bob.expectMsg(Warning(channelId(alice), ForbiddenDuringSplice(channelId(alice), "UpdateAddHtlc").getMessage)) - // alice confirms the splice abort - alice2bob.expectMsgType[TxAbort] - // the htlc is not added - assert(!alice.stateData.asInstanceOf[DATA_NORMAL].commitments.hasPendingOrProposedHtlcs) - } - test("recv UpdateAddHtlc while a splice is in progress") { f => import f._ val sender = TestProbe() val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(500_000 sat, pushAmount = 0 msat)), spliceOut_opt = None, requestFunding_opt = None) alice ! cmd + exchangeStfu(f) alice2bob.expectMsgType[SpliceInit] alice2bob.forward(bob) bob2alice.expectMsgType[SpliceAck] @@ -1241,6 +1188,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik val sender = TestProbe() val cmd = CMD_SPLICE(sender.ref, spliceIn_opt = Some(SpliceIn(500_000 sat, pushAmount = 0 msat)), spliceOut_opt = None, requestFunding_opt = None) alice ! cmd + exchangeStfu(f) alice2bob.expectMsgType[SpliceInit] alice2bob.forward(bob) bob2alice.expectMsgType[SpliceAck] @@ -1252,7 +1200,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(alice.stateData.asInstanceOf[DATA_NORMAL].spliceStatus == SpliceStatus.NoSplice) } - def testDisconnectCommitSigNotReceived(f: FixtureParam): Unit = { + test("disconnect (commit_sig not received)") { f => import f._ val htlcs = setupHtlcs(f) @@ -1283,15 +1231,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, 0.sat) } - test("disconnect (commit_sig not received)") { f => - testDisconnectCommitSigNotReceived(f) - } - - test("disconnect (commit_sig not received, quiescence)", Tag(ChannelStateTestsTags.Quiescence)) { f => - testDisconnectCommitSigNotReceived(f) - } - - def testDisconnectCommitSigReceivedByAlice(f: FixtureParam): Unit = { + test("disconnect (commit_sig received by alice)") { f => import f._ val htlcs = setupHtlcs(f) @@ -1323,15 +1263,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, spliceOutFee = 0.sat) } - test("disconnect (commit_sig received by alice)") { f => - testDisconnectCommitSigReceivedByAlice(f) - } - - test("disconnect (commit_sig received by alice, quiescence)", Tag(ChannelStateTestsTags.Quiescence)) { f => - testDisconnectCommitSigReceivedByAlice(f) - } - - def testDisconnectTxSignaturesSentByBob(f: FixtureParam): Unit = { + test("disconnect (tx_signatures sent by bob)") { f => import f._ val htlcs = setupHtlcs(f) @@ -1365,15 +1297,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, spliceOutFee = 0.sat) } - test("disconnect (tx_signatures sent by bob)") { f => - testDisconnectTxSignaturesSentByBob(f) - } - - test("disconnect (tx_signatures sent by bob, quiescence)", Tag(ChannelStateTestsTags.Quiescence)) { f => - testDisconnectTxSignaturesSentByBob(f) - } - - def testDisconnectTxSignaturesReceivedByAlice(f: FixtureParam): Unit = { + test("disconnect (tx_signatures received by alice)") { f => import f._ val htlcs = setupHtlcs(f) @@ -1414,15 +1338,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, spliceOutFee = 0.sat) } - test("disconnect (tx_signatures received by alice)") { f => - testDisconnectTxSignaturesReceivedByAlice(f) - } - - test("disconnect (tx_signatures received by alice, quiescence)", Tag(ChannelStateTestsTags.Quiescence)) { f => - testDisconnectTxSignaturesReceivedByAlice(f) - } - - def testDisconnectTxSignaturesReceivedByAliceZeroConf(f: FixtureParam): Unit = { + test("disconnect (tx_signatures received by alice, zero-conf)", Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val htlcs = setupHtlcs(f) @@ -1464,14 +1380,6 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, spliceOutFee = 0.sat) } - test("disconnect (tx_signatures received by alice, zero-conf)", Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testDisconnectTxSignaturesReceivedByAliceZeroConf(f) - } - - test("disconnect (tx_signatures received by alice, zero-conf, quiescence)", Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs), Tag(ChannelStateTestsTags.Quiescence)) { f => - testDisconnectTxSignaturesReceivedByAliceZeroConf(f) - } - test("disconnect (tx_signatures sent by alice, splice confirms while bob is offline)") { f => import f._ @@ -1676,7 +1584,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik } } - def testForceCloseWithMultipleSplicesSimple(f: FixtureParam): Unit = { + test("force-close with multiple splices (simple)") { f => import f._ val htlcs = setupHtlcs(f) @@ -1748,15 +1656,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(Helpers.Closing.isClosed(alice.stateData.asInstanceOf[DATA_CLOSING], None).exists(_.isInstanceOf[LocalClose])) } - test("force-close with multiple splices (simple)") { f => - testForceCloseWithMultipleSplicesSimple(f) - } - - test("force-close with multiple splices (simple, quiescence)", Tag(ChannelStateTestsTags.Quiescence)) { f => - testForceCloseWithMultipleSplicesSimple(f) - } - - def testForceCloseWithMultipleSplicesPreviousActiveRemote(f: FixtureParam): Unit = { + test("force-close with multiple splices (previous active remote)", Tag(ChannelStateTestsTags.StaticRemoteKey), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val htlcs = setupHtlcs(f) @@ -1834,15 +1734,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(Helpers.Closing.isClosed(alice.stateData.asInstanceOf[DATA_CLOSING], None).exists(_.isInstanceOf[RemoteClose])) } - test("force-close with multiple splices (previous active remote)", Tag(ChannelStateTestsTags.StaticRemoteKey), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesPreviousActiveRemote(f) - } - - test("force-close with multiple splices (previous active remote, quiescence)", Tag(ChannelStateTestsTags.Quiescence), Tag(ChannelStateTestsTags.StaticRemoteKey), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesPreviousActiveRemote(f) - } - - def testForceCloseWithMultipleSplicesPreviousActiveRevoked(f: FixtureParam): Unit = { + test("force-close with multiple splices (previous active revoked)", Tag(ChannelStateTestsTags.StaticRemoteKey), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val htlcs = setupHtlcs(f) @@ -1914,15 +1806,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(Helpers.Closing.isClosed(alice.stateData.asInstanceOf[DATA_CLOSING], None).exists(_.isInstanceOf[RevokedClose])) } - test("force-close with multiple splices (previous active revoked)", Tag(ChannelStateTestsTags.StaticRemoteKey), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesPreviousActiveRevoked(f) - } - - test("force-close with multiple splices (previous active revoked, quiescent)", Tag(ChannelStateTestsTags.Quiescence), Tag(ChannelStateTestsTags.StaticRemoteKey), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesPreviousActiveRevoked(f) - } - - def testForceCloseWithMultipleSplicesInactiveRemote(f: FixtureParam): Unit = { + test("force-close with multiple splices (inactive remote)", Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val htlcs = setupHtlcs(f) @@ -2029,15 +1913,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(Helpers.Closing.isClosed(alice.stateData.asInstanceOf[DATA_CLOSING], None).exists(_.isInstanceOf[RemoteClose])) } - test("force-close with multiple splices (inactive remote)", Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesInactiveRemote(f) - } - - test("force-close with multiple splices (inactive remote, quiescence)", Tag(ChannelStateTestsTags.Quiescence), Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesInactiveRemote(f) - } - - def testForceCloseWithMultipleSplicesInactiveRevoked(f: FixtureParam): Unit = { + test("force-close with multiple splices (inactive revoked)", Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val htlcs = setupHtlcs(f) @@ -2148,14 +2024,6 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik assert(Helpers.Closing.isClosed(alice.stateData.asInstanceOf[DATA_CLOSING], None).exists(_.isInstanceOf[RevokedClose])) } - test("force-close with multiple splices (inactive revoked)", Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesInactiveRevoked(f) - } - - test("force-close with multiple splices (inactive revoked, quiescence)", Tag(ChannelStateTestsTags.Quiescence), Tag(ChannelStateTestsTags.ZeroConf), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => - testForceCloseWithMultipleSplicesInactiveRevoked(f) - } - test("put back watches after restart") { f => import f._ @@ -2250,7 +2118,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik bob2blockchain.expectNoMessage(100 millis) } - test("recv CMD_SPLICE (splice-in + splice-out) with pre and post splice htlcs", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv CMD_SPLICE (splice-in + splice-out) with pre and post splice htlcs") { f => import f._ val htlcs = setupHtlcs(f) @@ -2287,7 +2155,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, spliceOutFee = 0.sat) } - test("recv CMD_SPLICE (splice-in + splice-out) with pending htlcs, resolved after splice locked", Tag(ChannelStateTestsTags.Quiescence), Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => + test("recv CMD_SPLICE (splice-in + splice-out) with pending htlcs, resolved after splice locked", Tag(ChannelStateTestsTags.AnchorOutputsZeroFeeHtlcTxs)) { f => import f._ val htlcs = setupHtlcs(f) @@ -2306,7 +2174,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, spliceOutFee = 0.sat) } - test("recv multiple CMD_SPLICE (splice-in, splice-out, quiescence)", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv multiple CMD_SPLICE (splice-in, splice-out)") { f => val htlcs = setupHtlcs(f) initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat))) @@ -2315,7 +2183,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik resolveHtlcs(f, htlcs, spliceOutFee = spliceOutFee(f, capacity = 1_900_000.sat)) } - test("recv invalid htlc signatures during splice-in", Tag(ChannelStateTestsTags.Quiescence)) { f => + test("recv invalid htlc signatures during splice-in") { f => import f._ val htlcs = setupHtlcs(f)