Add `zero-conf` test tag for Phoenix taproot tests (#3181)
What changed, and why it matters
This commit only changes test code. It adds a 'zero-conf' test tag and adjusts assertions so that Phoenix taproot channel tests correctly exercise zero-confirmation funding scenarios. There is no change to production code, so it cannot directly affect live users or funds.
No security action required. Treat as a normal test-maintenance commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is confined to two Scala test files. It imports a test helper, adds a checkWatchPublished helper, makes balance assertions relative to initial values, and switches several taproot splice tests from the OptionSimpleTaprootPhoenix tag to OptionSimpleTaproot plus ZeroConf. The production zero-conf detection in ChannelStateTestsHelperMethods is also consulted via alice.commitments.channelParams.zeroConf in addition to the channel type feature flag. No runtime Eclair code is modified.
Changed components
eclair-core test suite: ChannelStateTestsHelperMethods.scalaeclair-core test suite: NormalSplicesStateSpec.scalaInspect captured patch +24 / −14
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 f700595..a566f64 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
@@ -32,7 +32,7 @@ import fr.acinq.eclair.channel._
import fr.acinq.eclair.channel.fsm.Channel
import fr.acinq.eclair.channel.publish.TxPublisher.{PublishFinalTx, PublishReplaceableTx}
import fr.acinq.eclair.channel.publish._
-import fr.acinq.eclair.channel.states.ChannelStateTestsBase.FakeTxPublisherFactory
+import fr.acinq.eclair.channel.states.ChannelStateTestsBase.{FakeTxPublisherFactory, PimpTestFSM}
import fr.acinq.eclair.payment.send.SpontaneousRecipient
import fr.acinq.eclair.payment.{Invoice, OutgoingPaymentPacket}
import fr.acinq.eclair.reputation.Reputation
@@ -373,7 +373,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually {
val fundingTx = eventListener.expectMsgType[TransactionPublished].tx
eventually(assert(alice.stateName == WAIT_FOR_FUNDING_CONFIRMED))
eventually(assert(bob.stateName == WAIT_FOR_FUNDING_CONFIRMED))
- if (channelParams.channelType.features.contains(Features.ZeroConf)) {
+ if (channelParams.channelType.features.contains(Features.ZeroConf) || alice.commitments.channelParams.zeroConf) {
alice2blockchain.expectMsgType[WatchPublished]
bob2blockchain.expectMsgType[WatchPublished]
alice ! WatchPublishedTriggered(fundingTx)
@@ -427,7 +427,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually {
val fundingTx = eventListener.expectMsgType[TransactionPublished].tx
eventually(assert(alice.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED))
eventually(assert(bob.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED))
- if (channelParams.channelType.features.contains(Features.ZeroConf)) {
+ if (channelParams.channelType.features.contains(Features.ZeroConf) || alice.commitments.channelParams.zeroConf) {
alice2blockchain.expectMsgType[WatchPublished]
bob2blockchain.expectMsgType[WatchPublished]
alice ! WatchPublishedTriggered(fundingTx)
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 2f85025..af540aa 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
@@ -248,6 +248,15 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
bob2blockchain.expectNoMessage(100 millis)
}
+ private def checkWatchPublished(f: FixtureParam, spliceTx: Transaction): Unit = {
+ import f._
+
+ alice2blockchain.expectWatchPublished(spliceTx.txid)
+ alice2blockchain.expectNoMessage(100 millis)
+ bob2blockchain.expectWatchPublished(spliceTx.txid)
+ bob2blockchain.expectNoMessage(100 millis)
+ }
+
private def confirmSpliceTx(f: FixtureParam, spliceTx: Transaction): Unit = {
import f._
@@ -271,6 +280,9 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
private def setupHtlcs(f: FixtureParam): TestHtlcs = {
import f._
+ val localBalance = alice.commitments.latest.localCommit.spec.toLocal
+ val remoteBalance = alice.commitments.latest.localCommit.spec.toRemote
+
// Concurrently add htlcs in both directions so that commit indices don't match.
val adda1 = addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice)
val adda2 = addHtlc(15_000_000 msat, alice, bob, alice2bob, bob2alice)
@@ -290,11 +302,9 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
bob2alice.expectMsgType[RevokeAndAck]
bob2alice.forward(alice)
- val initialState = alice.stateData.asInstanceOf[DATA_NORMAL]
- assert(initialState.commitments.localCommitIndex != initialState.commitments.remoteCommitIndex)
- 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)
+ assert(alice.commitments.localCommitIndex != alice.commitments.remoteCommitIndex)
+ assert(alice.commitments.latest.localCommit.spec.toLocal == localBalance - 30_000_000.msat)
+ assert(alice.commitments.latest.localCommit.spec.toRemote == remoteBalance - 35_000_000.msat)
alice2relayer.expectMsgType[Relayer.RelayForward]
alice2relayer.expectMsgType[Relayer.RelayForward]
@@ -2708,7 +2718,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
resendSpliceLockedOnReconnection(f)
}
- test("re-send splice_locked on reconnection (taproot channels)", Tag(ChannelStateTestsTags.OptionSimpleTaprootPhoenix)) { f =>
+ test("re-send splice_locked on reconnection (taproot channels)", Tag(ChannelStateTestsTags.OptionSimpleTaproot)) { f =>
resendSpliceLockedOnReconnection(f)
}
@@ -2855,11 +2865,11 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
}
}
- test("disconnect while updating channel before receiving splice_locked", Tag(ChannelStateTestsTags.OptionSimpleTaprootPhoenix)) { f =>
+ test("disconnect while updating channel before receiving splice_locked", Tag(ChannelStateTestsTags.OptionSimpleTaproot), Tag(ChannelStateTestsTags.ZeroConf)) { f =>
import f._
val spliceTx = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat, pushAmount = 0 msat)))
- checkWatchConfirmed(f, spliceTx)
+ checkWatchPublished(f, spliceTx)
alice2bob.ignoreMsg { case _: ChannelUpdate => true }
bob2alice.ignoreMsg { case _: ChannelUpdate => true }
@@ -3360,13 +3370,13 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
assert(bob.stateData.asInstanceOf[DATA_CLOSED].fundingTxId == fundingTx2.txid)
}
- test("force-close with multiple splices (previous active remote)", Tag(ChannelStateTestsTags.OptionSimpleTaprootPhoenix)) { f =>
+ test("force-close with multiple splices (previous active remote)", Tag(ChannelStateTestsTags.OptionSimpleTaproot), Tag(ChannelStateTestsTags.ZeroConf)) { f =>
import f._
val htlcs = setupHtlcs(f)
val fundingTx1 = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)), spliceOut_opt = Some(SpliceOut(100_000 sat, defaultSpliceOutScriptPubKey)))
- checkWatchConfirmed(f, fundingTx1)
+ checkWatchPublished(f, fundingTx1)
// The first splice confirms on Bob's side.
bob ! WatchFundingConfirmedTriggered(BlockHeight(400000), 42, fundingTx1)
@@ -3375,7 +3385,7 @@ class NormalSplicesStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLik
bob2alice.forward(alice)
val fundingTx2 = initiateSplice(f, spliceIn_opt = Some(SpliceIn(500_000 sat)))
- checkWatchConfirmed(f, fundingTx2)
+ checkWatchPublished(f, fundingTx2)
alice2bob.expectNoMessage(100 millis)
bob2alice.expectNoMessage(100 millis)
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.