From 49698454010e8dff89cd59137bc62093ea3b188d Mon Sep 17 00:00:00 2001 From: Pierre-Marie Padiou Date: Tue, 17 Oct 2017 13:09:15 +0200 Subject: [PATCH] Base checks in `sendAdd` on the *last* sent sig (#180) fixes #175 --- .../fr/acinq/eclair/channel/Commitments.scala | 4 +++- .../channel/states/e/NormalStateSpec.scala | 22 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala index 44599ba8e..0b40802c9 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala @@ -90,7 +90,9 @@ object Commitments extends Logging { // let's compute the current commitment *as seen by them* with this change taken into account val add = UpdateAddHtlc(commitments.channelId, commitments.localNextHtlcId, cmd.amountMsat, cmd.paymentHash, cmd.expiry, cmd.onion) val commitments1 = addLocalProposal(commitments, add).copy(localNextHtlcId = commitments.localNextHtlcId + 1) - val reduced = CommitmentSpec.reduce(commitments1.remoteCommit.spec, commitments1.remoteChanges.acked, commitments1.localChanges.proposed) + // we need to base the next current commitment on the last sig we sent, even if we didn't yet receive their revocation + val remoteCommit1 = commitments1.remoteNextCommitInfo.left.toOption.map(_.nextRemoteCommit).getOrElse(commitments1.remoteCommit) + val reduced = CommitmentSpec.reduce(remoteCommit1.spec, commitments1.remoteChanges.acked, commitments1.localChanges.proposed) val htlcValueInFlight = UInt64(reduced.htlcs.map(_.add.amountMsat).sum) if (htlcValueInFlight > commitments1.remoteParams.maxHtlcValueInFlightMsat) { diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala index 3fd3507d5..f8619bdde 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/NormalStateSpec.scala @@ -4,7 +4,7 @@ import akka.actor.Status.Failure import akka.testkit.{TestFSMRef, TestProbe} import fr.acinq.bitcoin.Crypto.Scalar import fr.acinq.bitcoin.{BinaryData, Crypto, Satoshi, ScriptFlags, Transaction} -import fr.acinq.eclair.TestConstants.Bob +import fr.acinq.eclair.TestConstants.{Alice, Bob} import fr.acinq.eclair.blockchain._ import fr.acinq.eclair.channel.states.StateTestsHelperMethods import fr.acinq.eclair.channel.{Data, State, _} @@ -212,6 +212,26 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods { } } + test("recv CMD_ADD_HTLC (while waiting for a revocation)") { case (alice, _, alice2bob, _, _, _, relayer) => + within(30 seconds) { + val sender = TestProbe() + val add1 = CMD_ADD_HTLC(TestConstants.fundingSatoshis * 2/3 * 1000, "11" * 32, 400144) + sender.send(alice, add1) + sender.expectMsg("ok") + alice2bob.expectMsgType[UpdateAddHtlc] + relayer.expectMsgType[AddHtlcSucceeded] + sender.send(alice, CMD_SIGN) + sender.expectMsg("ok") + alice2bob.expectMsgType[CommitSig] + // this is over channel-capacity + val add2 = CMD_ADD_HTLC(TestConstants.fundingSatoshis * 2/3 * 1000, "22" * 32, 400144) + sender.send(alice, add2) + sender.expectMsgType[Failure] + relayer.expectMsgType[AddHtlcFailed] + alice2bob.expectNoMsg(200 millis) + } + } + test("recv CMD_ADD_HTLC (while waiting for Shutdown)") { case (alice, _, alice2bob, _, alice2blockchain, _, _) => within(30 seconds) { val sender = TestProbe()