Skip to content

Commit

Permalink
Add tests with both pending incoming and outgoing htlcs
Browse files Browse the repository at this point in the history
  • Loading branch information
remyers committed Nov 14, 2023
1 parent 6bb0d69 commit 688d2af
Showing 1 changed file with 36 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import fr.acinq.lightning.blockchain.electrum.WalletState
import fr.acinq.lightning.blockchain.fee.FeeratePerKw
import fr.acinq.lightning.channel.*
import fr.acinq.lightning.channel.TestsHelper.crossSign
import fr.acinq.lightning.channel.TestsHelper.htlcSuccessTxs
import fr.acinq.lightning.channel.TestsHelper.htlcTimeoutTxs
import fr.acinq.lightning.channel.TestsHelper.reachNormal
import fr.acinq.lightning.crypto.KeyManager
import fr.acinq.lightning.tests.TestConstants
Expand Down Expand Up @@ -340,7 +342,36 @@ class QuiescenceTestsCommon : LightningTestSuite() {
}

@Test
fun `incoming htlc timeout during quiescence negotiation with pending htlc failure` () {
fun `outgoing htlc timeout during quiescence negotiation` () {
val (alice, bob) = init()
val (nodes1, _, add) = TestsHelper.addHtlc(50_000_000.msat, alice, bob)
val (alice1, bob1) = nodes1
val (alice2, bob2, _) = crossSign(alice1, bob1)
val (alice3, _, _) = initiateQuiescence(alice2, bob2, sendInitialStfu = true)
assertIs<LNChannel<Normal>>(alice3)

// the outgoing HTLC from alice has timed out, alice should fail the htlc to avoid an on-chain race
val (alice4, _) = run {
val tmp = alice3.copy(ctx = alice3.ctx.copy(currentBlockHeight = add.cltvExpiry.toLong().toInt()))
tmp.process(ChannelCommand.Commitment.CheckHtlcTimeout)
}

// when the HTLC times out, alice needs to force close the channel
assertIs<LNChannel<Closing>>(alice4)
val lcp = alice4.state.localCommitPublished
assertNotNull(lcp)
assertEquals(1, lcp.htlcTxs.size)
val htlcTimeoutTxs = lcp.htlcTimeoutTxs()
assertEquals(1, htlcTimeoutTxs.size)
val htlcSuccessTxs = lcp.htlcSuccessTxs()
assertEquals(0, htlcSuccessTxs.size)

// Valid txs should be detected:
htlcTimeoutTxs.forEach { tx -> assertTrue(lcp.isHtlcTimeout(tx.tx)) }
}

@Test
fun `incoming htlc timeout during quiescence negotiation with pending htlc failure or success` () {
val (alice, bob) = init()
val (nodes1, preimage, add) = TestsHelper.addHtlc(50_000_000.msat, bob, alice)
val (bob1, alice1) = nodes1
Expand All @@ -354,14 +385,14 @@ class QuiescenceTestsCommon : LightningTestSuite() {
).forEach {
val (alice4, actionsAlice4) = alice3.process(it)
assertEquals(actionsAlice4.size, 0)
// the incoming HTLC from bob has timed out, alice should fail the htlc to avoid an on-chain race
// the incoming HTLC from bob will soon timeout, alice should fail the htlc to avoid an on-chain race
val (alice5, aliceActions5) = run {
val tmp = alice3.copy(ctx = alice4.ctx.copy(currentBlockHeight = add.cltvExpiry.toLong().toInt()))
val tmp = alice3.copy(ctx = alice4.ctx.copy(currentBlockHeight = add.cltvExpiry.toLong().toInt() - TestConstants.Alice.nodeParams.fulfillSafetyBeforeTimeoutBlocks.toInt()))
tmp.process(ChannelCommand.Commitment.CheckHtlcTimeout)
}
// alice does not close the channel with bob
// alice does not close the channel with bob immediately
assertEquals(aliceActions5.size, 0)
// alice processes the incoming htlc after quiescence
// alice will process the incoming htlc settlement after quiescence
val (_, aliceActions6) = alice5.process(ChannelCommand.MessageReceived(TxAbort(alice5.channelId, "deadbeef")))
assertContains(aliceActions6, ChannelAction.ProcessIncomingHtlc(add))
// alice should fail the htlc because the current height is now too close to its expiry
Expand Down

0 comments on commit 688d2af

Please sign in to comment.