Skip to content

Commit b13e59b

Browse files
committed
Don't force-close on remote error
When using zero-fee commitments, we don't force-close when receiving an `error` from our peer: if they want to force-close the channel, they can publish their commitment instead of forcing us to publish ours. It is especially true when the commit tx doesn't pay any fees, because the publisher will pay the entire fees for the force-close. Note that for wallet peers, we could introduce a mechanism where they send us their signed commit tx in the error message if they don't have any wallet input to pay the fees, and we could be nice and publish it while paying the fees from our main output (which isn't delayed since it is the remote commit from our point of view).
1 parent e462565 commit b13e59b

File tree

2 files changed

+7
-1
lines changed

2 files changed

+7
-1
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/channel/fsm/ErrorHandlers.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ trait ErrorHandlers extends CommonHandlers {
160160
// The channel closing is retried on every reconnect of the channel, until it succeeds.
161161
log.warning("ignoring remote 'link failed to shutdown', probably coming from lnd")
162162
stay() sending Warning(d.channelId, "ignoring your 'link failed to shutdown' to avoid an unnecessary force-close")
163+
} else if (hasCommitments.commitments.latest.commitmentFormat == ZeroFeeCommitmentFormat) {
164+
// When using v3 transactions, we want to avoid using our wallet inputs as much as possible.
165+
// It is much more convenient if our peer publishes their commitment transaction if they're having an issue,
166+
// because we can use our main output for pay the fees of the commitment transaction directly (if necessary).
167+
log.warning("ignoring remote error: waiting for remote commit tx to be published")
168+
stay() sending Warning(d.channelId, "ignoring your error: please publish your commitment if you want to force-close the channel")
163169
} else {
164170
spendLocalCurrent(hasCommitments, maxClosingFeerateOverride_opt = None)
165171
}

eclair-core/src/test/scala/fr/acinq/eclair/channel/states/ChannelStateTestsHelperMethods.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -648,7 +648,7 @@ trait ChannelStateTestsBase extends Assertions with Eventually {
648648
}
649649

650650
def localClose(s: TestFSMRef[ChannelState, ChannelData, Channel], s2blockchain: TestProbe, htlcSuccessCount: Int = 0, htlcTimeoutCount: Int = 0): (LocalCommitPublished, PublishedForceCloseTxs) = {
651-
s ! Error(ByteVector32.Zeroes, "oops")
651+
s ! CMD_FORCECLOSE(ActorRef.noSender, None, None)
652652
eventually(assert(s.stateName == CLOSING))
653653
val closingState = s.stateData.asInstanceOf[DATA_CLOSING]
654654
assert(closingState.localCommitPublished.isDefined)

0 commit comments

Comments
 (0)