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 51a89eedc1..907328e152 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 @@ -327,7 +327,7 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with Transaction.correctlySpends(claimMainOutput, bobCommitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) } - test("discover that they have a more recent commit than the one we know") { f => + test("discover that they have a more recent commit than the one we know (but counterparty can't tell)") { f => import f._ // we start by storing the current state @@ -353,16 +353,65 @@ class OfflineStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with // then we reconnect them 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) + // bob cannot detect that alice is late in this scenario (because alice has just missed one state) + alice2bob.forward(bob, reestablishA) + bob2alice.expectMsgType[RevokeAndAck] + bob2alice.expectMsgType[CommitSig] + bob2alice.expectNoMessage(100 millis) + bob2blockchain.expectNoMessage(100 millis) - // bob sees that alice is late and stays in stand-by + // alice realizes she has an old state when receiving Bob's reestablish + bob2alice.forward(alice, reestablishB) + // alice asks bob to publish its current commitment + val error = alice2bob.expectMsgType[Error] + assert(error === Error(channelId(alice), PleasePublishYourCommitment(channelId(alice)).getMessage)) alice2bob.forward(bob) + // 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 + alice ! WatchFundingSpentTriggered(bobCommitTx) + + // alice is able to claim its main output + val claimMainOutput = alice2blockchain.expectMsgType[PublishRawTx].tx + Transaction.correctlySpends(claimMainOutput, bobCommitTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS) + } + + test("discover that they have a more recent commit than the one we know") { f => + import f._ + + // we start by storing the current state + val oldStateData = alice.stateData + // then we add an htlc and sign it + addHtlc(250000000 msat, alice, bob, alice2bob, bob2alice) + crossSign(alice, bob, alice2bob, bob2alice) + + // we keep track of bob commitment tx for later + val bobCommitTx = bob.stateData.asInstanceOf[DATA_NORMAL].commitments.localCommit.commitTxAndRemoteSig.commitTx.tx + + // we simulate a disconnection + disconnect(alice, bob) + + // then we manually replace alice's state with an older one + alice.setState(OFFLINE, oldStateData) + + // then we reconnect them + reconnect(alice, bob, alice2bob, bob2alice) + + val reestablishA = alice2bob.expectMsgType[ChannelReestablish] + val reestablishB = bob2alice.expectMsgType[ChannelReestablish] + + // bob realizes that alice is late and goes in standby + alice2bob.forward(bob, reestablishA) + bob2alice.expectNoMessage(100 millis) + bob2blockchain.expectNoMessage(100 millis) + + // alice realizes she has an old state when receiving Bob's reestablish + bob2alice.forward(alice, reestablishB) // alice asks bob to publish its current commitment val error = alice2bob.expectMsgType[Error] assert(error === Error(channelId(alice), PleasePublishYourCommitment(channelId(alice)).getMessage))