From 1ac714a9943a401dfe871c048acf3e178cebf434 Mon Sep 17 00:00:00 2001 From: pm47 Date: Fri, 6 Mar 2020 13:54:37 +0100 Subject: [PATCH] Re-send ChannelUpdate on reconnection (vol 2) Previous implementation in #1317 wasn't working because in a bug in the transition. Added a test and fixed it. --- .../fr/acinq/eclair/channel/Channel.scala | 2 +- .../channel/states/e/OfflineStateSpec.scala | 65 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala index f4b7609a0d..ac4e38f1f3 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Channel.scala @@ -1681,7 +1681,7 @@ class Channel(val nodeParams: NodeParams, val wallet: EclairWallet, remoteNodeId case (_, _, d1: DATA_NORMAL, d2: DATA_NORMAL) if !d1.commitments.announceChannel && !d1.buried && d2.buried => // for a private channel, when the tx was just buried we need to send the channel_update to our peer (even if it didn't change) forwarder ! d2.channelUpdate - case (OFFLINE, NORMAL, d1: DATA_NORMAL, d2: DATA_NORMAL) if !d1.commitments.announceChannel && d2.buried => + case (SYNCING, NORMAL, d1: DATA_NORMAL, d2: DATA_NORMAL) if !d1.commitments.announceChannel && d2.buried => // otherwise if we're coming back online, we rebroadcast the latest channel_update // this makes sure that if the channel_update was missed, we have a chance to re-send it forwarder ! d2.channelUpdate 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 0d9d574631..16472a0104 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 @@ -534,4 +534,69 @@ class OfflineStateSpec extends TestkitBaseClass with StateTestsHelperMethods { sender.send(bob, CurrentFeerates(highFeerate)) bob2blockchain.expectMsg(PublishAsap(bobCommitTx)) } + + test("re-send channel_update at reconnection for private channels") { f => + import f._ + val sender = TestProbe() + + // we simulate a disconnection / reconnection + sender.send(alice, INPUT_DISCONNECTED) + sender.send(bob, INPUT_DISCONNECTED) + awaitCond(alice.stateName == OFFLINE) + awaitCond(bob.stateName == OFFLINE) + sender.send(alice, INPUT_RECONNECTED(alice2bob.ref, aliceInit, bobInit)) + sender.send(bob, INPUT_RECONNECTED(bob2alice.ref, bobInit, aliceInit)) + alice2bob.expectMsgType[ChannelReestablish] + bob2alice.expectMsgType[ChannelReestablish] + bob2alice.forward(alice) + alice2bob.forward(bob) + + // at this point the channel isn't deeply buried: channel_update isn't sent again + alice2bob.expectMsgType[FundingLocked] + bob2alice.expectMsgType[FundingLocked] + alice2bob.expectNoMsg() + bob2alice.expectNoMsg() + + // we make the peers exchange a few messages + addHtlc(250000000 msat, alice, bob, alice2bob, bob2alice) + crossSign(alice, bob, alice2bob, bob2alice) + + // we simulate a disconnection / reconnection + sender.send(alice, INPUT_DISCONNECTED) + sender.send(bob, INPUT_DISCONNECTED) + awaitCond(alice.stateName == OFFLINE) + awaitCond(bob.stateName == OFFLINE) + sender.send(alice, INPUT_RECONNECTED(alice2bob.ref, aliceInit, bobInit)) + sender.send(bob, INPUT_RECONNECTED(bob2alice.ref, bobInit, aliceInit)) + alice2bob.expectMsgType[ChannelReestablish] + bob2alice.expectMsgType[ChannelReestablish] + bob2alice.forward(alice) + alice2bob.forward(bob) + + // point the channel still isn't deeply buried: channel_update isn't sent again + alice2bob.expectNoMsg() + bob2alice.expectNoMsg() + + // funding tx gets 6 confirmations, channel is private so there is no announcement sigs + sender.send(alice, WatchEventConfirmed(BITCOIN_FUNDING_DEEPLYBURIED, 400000, 42, null)) + sender.send(bob, WatchEventConfirmed(BITCOIN_FUNDING_DEEPLYBURIED, 400000, 42, null)) + alice2bob.expectMsgType[ChannelUpdate] + bob2alice.expectMsgType[ChannelUpdate] + + // we get disconnected again + sender.send(alice, INPUT_DISCONNECTED) + sender.send(bob, INPUT_DISCONNECTED) + awaitCond(alice.stateName == OFFLINE) + awaitCond(bob.stateName == OFFLINE) + sender.send(alice, INPUT_RECONNECTED(alice2bob.ref, aliceInit, bobInit)) + sender.send(bob, INPUT_RECONNECTED(bob2alice.ref, bobInit, aliceInit)) + alice2bob.expectMsgType[ChannelReestablish] + bob2alice.expectMsgType[ChannelReestablish] + bob2alice.forward(alice) + alice2bob.forward(bob) + + // this time peers re-send their channel_update + alice2bob.expectMsgType[ChannelUpdate] + bob2alice.expectMsgType[ChannelUpdate] + } }