From 3ae9a4ae37297e0527bb83f22135860bcc3e49b3 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> Date: Fri, 16 Jul 2021 13:31:24 +0200 Subject: [PATCH] Additional reestablish test (#1875) This test was added to lightning-kmp where this case wasn't correctly handled: https://github.com/ACINQ/lightning-kmp/pull/278 It is correctly handled by eclair, but an additional test doesn't hurt. --- .../channel/states/e/OfflineStateSpec.scala | 58 +++++++++++++++++-- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala index fb42df2ab..5e74e22e5 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala @@ -231,6 +231,53 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with awaitCond(bob.stateName == NORMAL) } + test("resume htlc settlement") { f => + import f._ + + // Successfully send a first payment. + val (r1, htlc1) = addHtlc(15_000_000 msat, bob, alice, bob2alice, alice2bob) + crossSign(bob, alice, bob2alice, alice2bob) + fulfillHtlc(htlc1.id, r1, alice, bob, alice2bob, bob2alice) + crossSign(alice, bob, alice2bob, bob2alice) + + // Send a second payment and disconnect right after the fulfill was signed. + val (r2, htlc2) = addHtlc(25_000_000 msat, bob, alice, bob2alice, alice2bob) + crossSign(bob, alice, bob2alice, alice2bob) + fulfillHtlc(htlc2.id, r2, alice, bob, alice2bob, bob2alice) + val sender = TestProbe() + alice ! CMD_SIGN(Some(sender.ref)) + sender.expectMsgType[RES_SUCCESS[CMD_SIGN]] + alice2bob.expectMsgType[CommitSig] + alice2bob.forward(bob) + val revB = bob2alice.expectMsgType[RevokeAndAck] + bob2alice.expectMsgType[CommitSig] + disconnect(alice, bob) + + reconnect(alice, bob, alice2bob, bob2alice) + val reestablishA = alice2bob.expectMsgType[ChannelReestablish] + assert(reestablishA.nextLocalCommitmentNumber === 4) + assert(reestablishA.nextRemoteRevocationNumber === 3) + val reestablishB = bob2alice.expectMsgType[ChannelReestablish] + assert(reestablishB.nextLocalCommitmentNumber === 5) + assert(reestablishB.nextRemoteRevocationNumber === 3) + + bob2alice.forward(alice, reestablishB) + // alice does not re-send messages bob already received + alice2bob.expectNoMessage(100 millis) + + alice2bob.forward(bob, reestablishA) + // bob re-sends its revocation and signature, alice then completes the update + bob2alice.expectMsg(revB) + bob2alice.forward(alice) + bob2alice.expectMsgType[CommitSig] + bob2alice.forward(alice) + alice2bob.expectMsgType[RevokeAndAck] + alice2bob.forward(bob) + + assert(alice.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.index === 4) + assert(bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.index === 4) + } + test("discover that we have a revoked commitment") { f => import f._ @@ -258,11 +305,11 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with reconnect(alice, bob, alice2bob, bob2alice) // peers exchange channel_reestablish messages - alice2bob.expectMsgType[ChannelReestablish] - bob2alice.expectMsgType[ChannelReestablish] + val reestablishA = alice2bob.expectMsgType[ChannelReestablish] + val reestablishB = bob2alice.expectMsgType[ChannelReestablish] // alice then realizes it has an old state... - bob2alice.forward(alice) + bob2alice.forward(alice, reestablishB) // ... and ask bob to publish its current commitment val error = alice2bob.expectMsgType[Error] assert(error === Error(channelId(alice), PleasePublishYourCommitment(channelId(alice)).getMessage)) @@ -270,8 +317,9 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // alice now waits for bob to publish its commitment awaitCond(alice.stateName == WAIT_FOR_REMOTE_PUBLISH_FUTURE_COMMITMENT) - // bob is nice and publishes its commitment - val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.commitTxAndRemoteSig.commitTx.tx + // bob publishes its commitment when it detects that alice has an outdated commitment + alice2bob.forward(bob, reestablishA) + val bobCommitTx = bob2blockchain.expectMsgType[PublishRawTx].tx alice ! WatchFundingSpentTriggered(bobCommitTx) // alice is able to claim its main output