Skip to content

Commit

Permalink
Implement the option_simple_close protocol
Browse files Browse the repository at this point in the history
We update the `Negotiating` state to exchange the `closing_complete` and
`closing_sig` messages, and allow RBF-ing previous transactions and
updating our closing script.

We stay in that state until one of the transactions confirms, or a force
close is detected. This is important to ensure we're able to correctly
reconnect and negotiate RBF candidates.
  • Loading branch information
t-bast committed Jan 21, 2025
1 parent eec9cf8 commit c650799
Show file tree
Hide file tree
Showing 52 changed files with 1,323 additions and 2,330 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ data class NodeParams(
require(features.hasFeature(Feature.ChannelType, FeatureSupport.Mandatory)) { "${Feature.ChannelType.rfcName} should be mandatory" }
require(features.hasFeature(Feature.DualFunding, FeatureSupport.Mandatory)) { "${Feature.DualFunding.rfcName} should be mandatory" }
require(features.hasFeature(Feature.RouteBlinding)) { "${Feature.RouteBlinding.rfcName} should be supported" }
require(features.hasFeature(Feature.ShutdownAnySegwit, FeatureSupport.Mandatory)) { "${Feature.ShutdownAnySegwit.rfcName} should be mandatory" }
require(features.hasFeature(Feature.SimpleClose, FeatureSupport.Mandatory)) { "${Feature.SimpleClose.rfcName} should be mandatory" }
require(!features.hasFeature(Feature.ZeroConfChannels)) { "${Feature.ZeroConfChannels.rfcName} has been deprecated: use the zeroConfPeers whitelist instead" }
require(!features.hasFeature(Feature.TrustedSwapInClient)) { "${Feature.TrustedSwapInClient.rfcName} has been deprecated" }
require(!features.hasFeature(Feature.TrustedSwapInProvider)) { "${Feature.TrustedSwapInProvider.rfcName} has been deprecated" }
Expand Down Expand Up @@ -204,6 +206,7 @@ data class NodeParams(
Feature.Quiescence to FeatureSupport.Mandatory,
Feature.ChannelType to FeatureSupport.Mandatory,
Feature.PaymentMetadata to FeatureSupport.Optional,
Feature.SimpleClose to FeatureSupport.Mandatory,
Feature.ExperimentalTrampolinePayment to FeatureSupport.Optional,
Feature.ZeroReserveChannels to FeatureSupport.Optional,
Feature.WakeUpNotificationClient to FeatureSupport.Optional,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import fr.acinq.lightning.MilliSatoshi
import fr.acinq.lightning.blockchain.WatchEvent
import fr.acinq.lightning.blockchain.electrum.WalletState
import fr.acinq.lightning.blockchain.fee.FeeratePerKw
import fr.acinq.lightning.channel.states.ClosingFeerates
import fr.acinq.lightning.channel.states.PersistedChannelState
import fr.acinq.lightning.crypto.KeyManager
import fr.acinq.lightning.utils.UUID
Expand Down Expand Up @@ -105,7 +104,7 @@ sealed class ChannelCommand {
}

sealed class Close : ChannelCommand() {
data class MutualClose(val scriptPubKey: ByteVector?, val feerates: ClosingFeerates?) : Close(), ForbiddenDuringSplice, ForbiddenDuringQuiescence
data class MutualClose(val scriptPubKey: ByteVector?, val feerate: FeeratePerKw) : Close(), ForbiddenDuringSplice, ForbiddenDuringQuiescence
data object ForceClose : Close()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import fr.acinq.lightning.logging.LoggingContext
import fr.acinq.lightning.transactions.Scripts
import fr.acinq.lightning.transactions.Transactions.TransactionWithInputInfo.*
import fr.acinq.lightning.utils.toMilliSatoshi
import fr.acinq.lightning.wire.ClosingSigned

/**
* Details about a force-close where we published our commitment.
Expand Down Expand Up @@ -370,10 +369,6 @@ data class LocalParams(
features = nodeParams.features.initFeatures()
)

// The node responsible for the commit tx fees is also the node paying the mutual close fees.
// The other node's balance may be empty, which wouldn't allow them to pay the closing fees.
val paysClosingFees: Boolean = paysCommitTxFees

fun channelKeys(keyManager: KeyManager) = keyManager.channelKeys(fundingKeyPath)
}

Expand All @@ -397,8 +392,6 @@ data class RemoteParams(
*/
data class ChannelFlags(val announceChannel: Boolean, val nonInitiatorPaysCommitFees: Boolean)

data class ClosingTxProposed(val unsignedTx: ClosingTx, val localClosingSigned: ClosingSigned)

/**
* @param miningFee fee paid to miners for the underlying on-chain transaction.
* @param serviceFee fee paid to our peer for any service provided with the on-chain transaction.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package fr.acinq.lightning.channel

import fr.acinq.bitcoin.BlockHash
import fr.acinq.bitcoin.ByteVector32
import fr.acinq.bitcoin.Satoshi
import fr.acinq.bitcoin.TxId
import fr.acinq.bitcoin.*
import fr.acinq.lightning.CltvExpiry
import fr.acinq.lightning.CltvExpiryDelta
import fr.acinq.lightning.MilliSatoshi
Expand Down Expand Up @@ -62,8 +59,10 @@ data class FeerateTooSmall (override val channelId: Byte
data class FeerateTooDifferent (override val channelId: ByteVector32, val localFeeratePerKw: FeeratePerKw, val remoteFeeratePerKw: FeeratePerKw) : ChannelException(channelId, "local/remote feerates are too different: remoteFeeratePerKw=${remoteFeeratePerKw.toLong()} localFeeratePerKw=${localFeeratePerKw.toLong()}")
data class InvalidCommitmentSignature (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid commitment signature: txId=$txId")
data class InvalidHtlcSignature (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid htlc signature: txId=$txId")
data class CannotGenerateClosingTx (override val channelId: ByteVector32) : ChannelException(channelId, "failed to generate closing transaction: all outputs are trimmed")
data class MissingCloseSignature (override val channelId: ByteVector32) : ChannelException(channelId, "closing_complete is missing a signature for a closing transaction including our output")
data class InvalidCloseSignature (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid close signature: txId=$txId")
data class InvalidCloseAmountBelowDust (override val channelId: ByteVector32, val txId: TxId) : ChannelException(channelId, "invalid closing tx: some outputs are below dust: txId=$txId")
data class InvalidCloseeScript (override val channelId: ByteVector32, val received: ByteVector, val expected: ByteVector) : ChannelException(channelId, "invalid closee script used in closing_complete: our latest script is $expected, you're using $received")
data class CommitSigCountMismatch (override val channelId: ByteVector32, val expected: Int, val actual: Int) : ChannelException(channelId, "commit sig count mismatch: expected=$expected actual=$actual")
data class HtlcSigCountMismatch (override val channelId: ByteVector32, val expected: Int, val actual: Int) : ChannelException(channelId, "htlc sig count mismatch: expected=$expected actual: $actual")
data class ForcedLocalCommit (override val channelId: ByteVector32) : ChannelException(channelId, "forced local commit")
Expand Down
Loading

0 comments on commit c650799

Please sign in to comment.