@@ -232,7 +232,10 @@ trait ErrorHandlers extends CommonHandlers {
232232
233233 /** Publish 2nd-stage transactions for our local commitment. */
234234 def doPublish (lcp : LocalCommitPublished , txs : Closing .LocalClose .SecondStageTransactions , commitment : FullCommitment ): Unit = {
235- val publishCommitTx = PublishFinalTx (lcp.commitTx, commitment.fundingInput, " commit-tx" , Closing .commitTxFee(commitment.commitInput(channelKeys), lcp.commitTx, commitment.localChannelParams.paysCommitTxFees), None )
235+ val publishCommitTx_opt = commitment.commitmentFormat match {
236+ case _ : AnchorOutputsCommitmentFormat | _ : SimpleTaprootChannelCommitmentFormat => Some (PublishFinalTx (lcp.commitTx, commitment.fundingInput, " commit-tx" , Closing .commitTxFee(commitment.commitInput(channelKeys), lcp.commitTx, commitment.localChannelParams.paysCommitTxFees), None ))
237+ case ZeroFeeCommitmentFormat => None // we will publish the commit-tx alongside the anchor tx
238+ }
236239 val publishAnchorTx_opt = txs.anchorTx_opt match {
237240 case Some (anchorTx) if ! lcp.isConfirmed =>
238241 val confirmationTarget = Closing .confirmationTarget(commitment.localCommit, commitment.localCommitParams.dustLimit, commitment.commitmentFormat, nodeParams.onChainFeeConf)
@@ -241,7 +244,7 @@ trait ErrorHandlers extends CommonHandlers {
241244 }
242245 val publishMainDelayedTx_opt = txs.mainDelayedTx_opt.map(tx => PublishFinalTx (tx, None ))
243246 val publishHtlcTxs = txs.htlcTxs.map(htlcTx => PublishReplaceableTx (htlcTx, lcp.commitTx, commitment, Closing .confirmationTarget(htlcTx)))
244- val publishQueue = Seq (publishCommitTx) ++ publishAnchorTx_opt ++ publishMainDelayedTx_opt ++ publishHtlcTxs
247+ val publishQueue = publishCommitTx_opt.toSeq ++ publishAnchorTx_opt ++ publishMainDelayedTx_opt ++ publishHtlcTxs
245248 publishIfNeeded(publishQueue, lcp.irrevocablySpent)
246249
247250 if (! lcp.isConfirmed) {
@@ -275,7 +278,7 @@ trait ErrorHandlers extends CommonHandlers {
275278 case _ => nodeParams.onChainFeeConf.getClosingFeerate(nodeParams.currentBitcoinCoreFeerates, maxClosingFeerateOverride_opt = None )
276279 }
277280 context.system.eventStream.publish(TransactionPublished (d.channelId, remoteNodeId, commitTx, Closing .commitTxFee(commitments.commitInput(channelKeys), commitTx, d.commitments.localChannelParams.paysCommitTxFees), " remote-commit" ))
278- val (remoteCommitPublished, closingTxs) = Closing .RemoteClose .claimCommitTxOutputs(channelKeys, commitments, commitments.remoteCommit, commitTx, closingFeerate, finalScriptPubKey, nodeParams.onChainFeeConf.spendAnchorWithoutHtlcs)
281+ val (remoteCommitPublished, closingTxs) = Closing .RemoteClose .claimCommitTxOutputs(channelKeys, commitments, commitments.remoteCommit, commitTx, closingFeerate, nodeParams.currentBitcoinCoreFeerates, finalScriptPubKey, nodeParams.onChainFeeConf.spendAnchorWithoutHtlcs)
279282 val nextData = d match {
280283 case closing : DATA_CLOSING => closing.copy(remoteCommitPublished = Some (remoteCommitPublished))
281284 case negotiating : DATA_NEGOTIATING => DATA_CLOSING (d.commitments, waitingSince = nodeParams.currentBlockHeight, finalScriptPubKey = finalScriptPubKey, mutualCloseProposed = negotiating.closingTxProposed.flatten.map(_.unsignedTx), remoteCommitPublished = Some (remoteCommitPublished))
@@ -297,7 +300,7 @@ trait ErrorHandlers extends CommonHandlers {
297300 case _ => nodeParams.onChainFeeConf.getClosingFeerate(nodeParams.currentBitcoinCoreFeerates, maxClosingFeerateOverride_opt = None )
298301 }
299302 context.system.eventStream.publish(TransactionPublished (d.channelId, remoteNodeId, commitTx, Closing .commitTxFee(commitment.commitInput(channelKeys), commitTx, d.commitments.localChannelParams.paysCommitTxFees), " next-remote-commit" ))
300- val (remoteCommitPublished, closingTxs) = Closing .RemoteClose .claimCommitTxOutputs(channelKeys, commitment, remoteCommit, commitTx, closingFeerate, finalScriptPubKey, nodeParams.onChainFeeConf.spendAnchorWithoutHtlcs)
303+ val (remoteCommitPublished, closingTxs) = Closing .RemoteClose .claimCommitTxOutputs(channelKeys, commitment, remoteCommit, commitTx, closingFeerate, nodeParams.currentBitcoinCoreFeerates, finalScriptPubKey, nodeParams.onChainFeeConf.spendAnchorWithoutHtlcs)
301304 val nextData = d match {
302305 case closing : DATA_CLOSING => closing.copy(nextRemoteCommitPublished = Some (remoteCommitPublished))
303306 case negotiating : DATA_NEGOTIATING => DATA_CLOSING (d.commitments, waitingSince = nodeParams.currentBlockHeight, finalScriptPubKey = finalScriptPubKey, mutualCloseProposed = negotiating.closingTxProposed.flatten.map(_.unsignedTx), nextRemoteCommitPublished = Some (remoteCommitPublished))
@@ -314,13 +317,19 @@ trait ErrorHandlers extends CommonHandlers {
314317 case Some (commit) if rcp.commitTx.txid == commit.txId => commit
315318 case _ => commitment.remoteCommit
316319 }
320+ val confirmationTarget = Closing .confirmationTarget(remoteCommit, commitment.remoteCommitParams.dustLimit, commitment.commitmentFormat, nodeParams.onChainFeeConf)
317321 val publishAnchorTx_opt = txs.anchorTx_opt match {
318- case Some (anchorTx) if ! rcp.isConfirmed =>
319- val confirmationTarget = Closing .confirmationTarget(remoteCommit, commitment.remoteCommitParams.dustLimit, commitment.commitmentFormat, nodeParams.onChainFeeConf)
320- Some (PublishReplaceableTx (anchorTx, rcp.commitTx, commitment, confirmationTarget))
322+ case Some (anchorTx) if ! rcp.isConfirmed => Some (PublishReplaceableTx (anchorTx, rcp.commitTx, commitment, confirmationTarget))
321323 case _ => None
322324 }
323- val publishMainTx_opt = txs.mainTx_opt.map(tx => PublishFinalTx (tx, None ))
325+ val publishMainTx_opt = txs.mainTx_opt.map(tx => commitment.commitmentFormat match {
326+ case ZeroFeeCommitmentFormat => publishAnchorTx_opt match {
327+ // Instead of creating a dedicated anchor transaction, we use our main output to pay commit fees whenever possible.
328+ case None if ! rcp.isConfirmed => PublishReplaceableTx (tx, rcp.commitTx, commitment, confirmationTarget)
329+ case _ => PublishFinalTx (tx, None )
330+ }
331+ case _ : AnchorOutputsCommitmentFormat | _ : SimpleTaprootChannelCommitmentFormat => PublishFinalTx (tx, None )
332+ })
324333 val publishHtlcTxs = txs.htlcTxs.map(htlcTx => PublishReplaceableTx (htlcTx, rcp.commitTx, commitment, Closing .confirmationTarget(htlcTx)))
325334 val publishQueue = publishAnchorTx_opt ++ publishMainTx_opt ++ publishHtlcTxs
326335 publishIfNeeded(publishQueue, rcp.irrevocablySpent)
@@ -334,7 +343,7 @@ trait ErrorHandlers extends CommonHandlers {
334343 // we will watch for its confirmation. This ensures that we detect double-spends that could come from:
335344 // - our own RBF attempts
336345 // - remote transactions for outputs that both parties may spend (e.g. HTLCs)
337- val watchSpentQueue = rcp.localOutput_opt ++ (if (! rcp.isConfirmed ) rcp.anchorOutput_opt else None ) ++ rcp.htlcOutputs.toSeq
346+ val watchSpentQueue = rcp.localOutput_opt ++ (if (publishAnchorTx_opt.nonEmpty ) rcp.anchorOutput_opt else None ) ++ rcp.htlcOutputs.toSeq
338347 watchSpentIfNeeded(rcp.commitTx, watchSpentQueue, rcp.irrevocablySpent)
339348 }
340349
0 commit comments