From 5b11f76e00db4c7e46a37ded6239f2f6810e4616 Mon Sep 17 00:00:00 2001 From: Bastien Teinturier <31281497+t-bast@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:05:54 +0100 Subject: [PATCH] Ignore duplicate dual-funding signatures (#2770) If our peer sends us some `tx_signatures` that we already received, we can safely ignore them. --- .../channel/fsm/ChannelOpenDualFunded.scala | 3 +++ ...WaitForDualFundingConfirmedStateSpec.scala | 23 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala index 2802b7aeac..d95a3f80da 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ChannelOpenDualFunded.scala @@ -473,6 +473,9 @@ trait ChannelOpenDualFunded extends DualFundingHandlers with ErrorHandlers { val d1 = DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED(commitments1, d.localPushAmount, d.remotePushAmount, d.waitingSince, d.lastChecked, RbfStatus.NoRbf, d.deferred) stay() using d1 storing() sending signingSession1.localSigs calling publishFundingTx(signingSession1.fundingTx) } + case _ if d.commitments.all.exists(_.fundingTxId == txSigs.txId) => + log.debug("ignoring tx_signatures that we already received for txId={}", txSigs.txId) + stay() case _ => log.debug("rejecting unexpected tx_signatures for txId={}", txSigs.txId) reportRbfFailure(d.rbfStatus, UnexpectedFundingSignatures(d.channelId)) diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala index 64c77476e8..de59a118b6 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/c/WaitForDualFundingConfirmedStateSpec.scala @@ -127,11 +127,30 @@ class WaitForDualFundingConfirmedStateSpec extends TestKitBaseClass with Fixture val aliceSigs = alice.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED].latestFundingTx.sharedTx.localSigs alice2bob.forward(bob, aliceSigs) - bob2alice.expectMsgType[TxAbort] + bob2alice.expectNoMessage(100 millis) val bobSigs = bob.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED].latestFundingTx.sharedTx.localSigs bob2alice.forward(alice, bobSigs) - alice2bob.expectMsgType[TxAbort] + alice2bob.expectNoMessage(100 millis) + + assert(alice.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) + assert(bob.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) + } + + test("recv TxSignatures (duplicate, rbf attempt)", Tag(ChannelStateTestsTags.DualFunding)) { f => + import f._ + + val aliceSigs = alice.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED].latestFundingTx.sharedTx.localSigs + val bobSigs = bob.stateData.asInstanceOf[DATA_WAIT_FOR_DUAL_FUNDING_CONFIRMED].latestFundingTx.sharedTx.localSigs + val rbfTx = testBumpFundingFees(f) + + alice2bob.forward(bob, aliceSigs) + alice2bob.forward(bob, rbfTx.localSigs) + bob2alice.expectNoMessage(100 millis) + + bob2alice.forward(alice, bobSigs) + bob2alice.forward(alice, rbfTx.remoteSigs) + alice2bob.expectNoMessage(100 millis) assert(alice.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED) assert(bob.stateName == WAIT_FOR_DUAL_FUNDING_CONFIRMED)