@@ -686,9 +686,11 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
686686 // we were waiting for our pending htlcs to be signed before replying with our local shutdown
687687 val finalScriptPubKey = getOrGenerateFinalScriptPubKey(d)
688688 val localShutdown = Shutdown (d.channelId, finalScriptPubKey)
689+ // this should always be defined, we provide a fallback for backward compat with older channels
690+ val closeStatus = d.closeStatus_opt.getOrElse(CloseStatus .NonInitiator (None ))
689691 // note: it means that we had pending htlcs to sign, therefore we go to SHUTDOWN, not to NEGOTIATING
690692 require(commitments1.latest.remoteCommit.spec.htlcs.nonEmpty, " we must have just signed new htlcs, otherwise we would have sent our Shutdown earlier" )
691- goto(SHUTDOWN ) using DATA_SHUTDOWN (commitments1, localShutdown, d.remoteShutdown.get, d.closingFeerates ) storing() sending localShutdown
693+ goto(SHUTDOWN ) using DATA_SHUTDOWN (commitments1, localShutdown, d.remoteShutdown.get, closeStatus ) storing() sending localShutdown
692694 } else {
693695 stay() using d.copy(commitments = commitments1) storing()
694696 }
@@ -711,7 +713,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
711713 case Left (e) => handleCommandError(e, c)
712714 case Right (localShutdownScript) =>
713715 val shutdown = Shutdown (d.channelId, localShutdownScript)
714- handleCommandSuccess(c, d.copy(localShutdown = Some (shutdown), closingFeerates = c.feerates)) storing() sending shutdown
716+ handleCommandSuccess(c, d.copy(localShutdown = Some (shutdown), closeStatus_opt = Some ( CloseStatus . Initiator ( c.feerates)) )) storing() sending shutdown
715717 }
716718 }
717719
@@ -752,7 +754,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
752754 self ! CMD_SIGN ()
753755 }
754756 // in the meantime we won't send new changes
755- stay() using d.copy(remoteShutdown = Some (remoteShutdown))
757+ stay() using d.copy(remoteShutdown = Some (remoteShutdown), closeStatus_opt = Some ( CloseStatus . NonInitiator ( None )) )
756758 } else {
757759 // so we don't have any unsigned outgoing changes
758760 val (localShutdown, sendList) = d.localShutdown match {
@@ -763,23 +765,29 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
763765 // we need to send our shutdown if we didn't previously
764766 (localShutdown, localShutdown :: Nil )
765767 }
768+ val closeStatus = d.localShutdown match {
769+ case Some (_) =>
770+ // this should always be defined, we provide a fallback for backward compat with older channels
771+ d.closeStatus_opt.getOrElse(CloseStatus .Initiator (None ))
772+ case None => CloseStatus .NonInitiator (None )
773+ }
766774 // are there pending signed changes on either side? we need to have received their last revocation!
767775 if (d.commitments.hasNoPendingHtlcsOrFeeUpdate) {
768776 // there are no pending signed changes, let's directly negotiate a closing transaction
769777 if (Features .canUseFeature(d.commitments.params.localParams.initFeatures, d.commitments.params.remoteParams.initFeatures, Features .SimpleClose )) {
770- val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, d.closingFeerates )
778+ val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, closeStatus )
771779 goto(NEGOTIATING_SIMPLE ) using d1 storing() sending sendList ++ closingComplete_opt.toSeq
772780 } else if (d.commitments.params.localParams.paysClosingFees) {
773781 // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed
774- val (closingTx, closingSigned) = MutualClose .makeFirstClosingTx(keyManager, d.commitments.latest, localShutdown.scriptPubKey, remoteShutdownScript, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, d.closingFeerates )
782+ val (closingTx, closingSigned) = MutualClose .makeFirstClosingTx(keyManager, d.commitments.latest, localShutdown.scriptPubKey, remoteShutdownScript, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, closeStatus.feerates_opt )
775783 goto(NEGOTIATING ) using DATA_NEGOTIATING (d.commitments, localShutdown, remoteShutdown, List (List (ClosingTxProposed (closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None ) storing() sending sendList :+ closingSigned
776784 } else {
777785 // we are not the channel initiator, will wait for their closing_signed
778786 goto(NEGOTIATING ) using DATA_NEGOTIATING (d.commitments, localShutdown, remoteShutdown, closingTxProposed = List (List ()), bestUnpublishedClosingTx_opt = None ) storing() sending sendList
779787 }
780788 } else {
781789 // there are some pending signed changes, we need to wait for them to be settled (fail/fulfill htlcs and sign fee updates)
782- goto(SHUTDOWN ) using DATA_SHUTDOWN (d.commitments, localShutdown, remoteShutdown, d.closingFeerates ) storing() sending sendList
790+ goto(SHUTDOWN ) using DATA_SHUTDOWN (d.commitments, localShutdown, remoteShutdown, closeStatus ) storing() sending sendList
783791 }
784792 }
785793 }
@@ -1569,7 +1577,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
15691577 stay()
15701578 }
15711579
1572- case Event (commit : CommitSig , d@ DATA_SHUTDOWN (_, localShutdown, remoteShutdown, closingFeerates )) =>
1580+ case Event (commit : CommitSig , d@ DATA_SHUTDOWN (_, localShutdown, remoteShutdown, closeStatus )) =>
15731581 aggregateSigs(commit) match {
15741582 case Some (sigs) =>
15751583 d.commitments.receiveCommit(sigs, keyManager) match {
@@ -1579,11 +1587,11 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
15791587 context.system.eventStream.publish(ChannelSignatureReceived (self, commitments1))
15801588 if (commitments1.hasNoPendingHtlcsOrFeeUpdate) {
15811589 if (Features .canUseFeature(d.commitments.params.localParams.initFeatures, d.commitments.params.remoteParams.initFeatures, Features .SimpleClose )) {
1582- val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, d.closingFeerates )
1590+ val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, closeStatus )
15831591 goto(NEGOTIATING_SIMPLE ) using d1 storing() sending revocation +: closingComplete_opt.toSeq
15841592 } else if (d.commitments.params.localParams.paysClosingFees) {
15851593 // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed
1586- val (closingTx, closingSigned) = MutualClose .makeFirstClosingTx(keyManager, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, closingFeerates )
1594+ val (closingTx, closingSigned) = MutualClose .makeFirstClosingTx(keyManager, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, d.closeStatus.feerates_opt )
15871595 goto(NEGOTIATING ) using DATA_NEGOTIATING (commitments1, localShutdown, remoteShutdown, List (List (ClosingTxProposed (closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None ) storing() sending revocation :: closingSigned :: Nil
15881596 } else {
15891597 // we are not the channel initiator, will wait for their closing_signed
@@ -1601,7 +1609,7 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
16011609 case None => stay()
16021610 }
16031611
1604- case Event (revocation : RevokeAndAck , d@ DATA_SHUTDOWN (_, localShutdown, remoteShutdown, closingFeerates )) =>
1612+ case Event (revocation : RevokeAndAck , d@ DATA_SHUTDOWN (_, localShutdown, remoteShutdown, closeStatus )) =>
16051613 // we received a revocation because we sent a signature
16061614 // => all our changes have been acked including the shutdown message
16071615 d.commitments.receiveRevocation(revocation, nodeParams.onChainFeeConf.feerateToleranceFor(remoteNodeId).dustTolerance.maxExposure) match {
@@ -1624,11 +1632,11 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
16241632 if (commitments1.hasNoPendingHtlcsOrFeeUpdate) {
16251633 log.debug(" switching to NEGOTIATING spec:\n {}" , commitments1.latest.specs2String)
16261634 if (Features .canUseFeature(d.commitments.params.localParams.initFeatures, d.commitments.params.remoteParams.initFeatures, Features .SimpleClose )) {
1627- val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, d.closingFeerates )
1635+ val (d1, closingComplete_opt) = startSimpleClose(d.commitments, localShutdown, remoteShutdown, d.closeStatus )
16281636 goto(NEGOTIATING_SIMPLE ) using d1 storing() sending closingComplete_opt.toSeq
16291637 } else if (d.commitments.params.localParams.paysClosingFees) {
16301638 // we pay the closing fees, so we initiate the negotiation by sending the first closing_signed
1631- val (closingTx, closingSigned) = MutualClose .makeFirstClosingTx(keyManager, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, closingFeerates )
1639+ val (closingTx, closingSigned) = MutualClose .makeFirstClosingTx(keyManager, commitments1.latest, localShutdown.scriptPubKey, remoteShutdown.scriptPubKey, nodeParams.currentFeeratesForFundingClosing, nodeParams.onChainFeeConf, d.closeStatus.feerates_opt )
16321640 goto(NEGOTIATING ) using DATA_NEGOTIATING (commitments1, localShutdown, remoteShutdown, List (List (ClosingTxProposed (closingTx, closingSigned))), bestUnpublishedClosingTx_opt = None ) storing() sending closingSigned
16331641 } else {
16341642 // we are not the channel initiator, will wait for their closing_signed
@@ -1664,7 +1672,11 @@ class Channel(val nodeParams: NodeParams, val wallet: OnChainChannelFunder with
16641672 if (c.scriptPubKey.exists(_ != d.localShutdown.scriptPubKey) && ! useSimpleClose) {
16651673 handleCommandError(ClosingAlreadyInProgress (d.channelId), c)
16661674 } else if (localShutdown_opt.nonEmpty || c.feerates.nonEmpty) {
1667- val d1 = d.copy(localShutdown = localShutdown_opt.getOrElse(d.localShutdown), closingFeerates = c.feerates.orElse(d.closingFeerates))
1675+ val closeStatus1 = d.closeStatus match {
1676+ case initiator : CloseStatus .Initiator => initiator.copy(feerates_opt = c.feerates.orElse(initiator.feerates_opt))
1677+ case nonInitiator : CloseStatus .NonInitiator => nonInitiator.copy(feerates_opt = c.feerates.orElse(nonInitiator.feerates_opt)) // NB: this is the corner case where we can be non-initiator and have custom feerates
1678+ }
1679+ val d1 = d.copy(localShutdown = localShutdown_opt.getOrElse(d.localShutdown), closeStatus = closeStatus1)
16681680 handleCommandSuccess(c, d1) storing() sending localShutdown_opt.toSeq
16691681 } else {
16701682 handleCommandError(ClosingAlreadyInProgress (d.channelId), c)
0 commit comments