Skip to content

Commit 7520b04

Browse files
committed
Allow funder to dip into reserve if increased fee
See lightning/bolts#728 Allow a funder to dip into its channel reserve to pay the increased commit tx fee for one incoming HTLC. This prevents being stuck with an unusable channel.
1 parent cc4a4ab commit 7520b04

File tree

2 files changed

+20
-5
lines changed

2 files changed

+20
-5
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/channel/Commitments.scala

+7-3
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ object Commitments {
190190
} else if (missingForReceiver < 0.msat) {
191191
if (commitments.localParams.isFunder) {
192192
// receiver is fundee; it is ok if it can't maintain its channel_reserve for now, as long as its balance is increasing, which is the case if it is receiving a payment
193+
} else if (missingForReceiver + commitments1.localParams.channelReserve > 0.msat && outgoingHtlcs.size <= 1) {
194+
// receiver is funder; it is allowed to dip into its channel reserve to pay the fee for a single non-dust HTLC
193195
} else {
194196
return Left(RemoteCannotAffordFeesForNewHtlc(commitments.channelId, amount = cmd.amount, missing = -missingForReceiver.truncateToSatoshi, reserve = commitments1.remoteParams.channelReserve, fees = fees))
195197
}
@@ -230,10 +232,12 @@ object Commitments {
230232
if (missingForSender < 0.sat) {
231233
throw InsufficientFunds(commitments.channelId, amount = add.amountMsat, missing = -missingForSender.truncateToSatoshi, reserve = commitments1.localParams.channelReserve, fees = if (commitments1.localParams.isFunder) 0.sat else fees)
232234
} else if (missingForReceiver < 0.sat) {
233-
if (commitments.localParams.isFunder) {
234-
throw CannotAffordFees(commitments.channelId, missing = -missingForReceiver.truncateToSatoshi, reserve = commitments1.remoteParams.channelReserve, fees = fees)
235-
} else {
235+
if (!commitments.localParams.isFunder) {
236236
// receiver is fundee; it is ok if it can't maintain its channel_reserve for now, as long as its balance is increasing, which is the case if it is receiving a payment
237+
} else if (missingForReceiver + commitments1.remoteParams.channelReserve > 0.msat && incomingHtlcs.size <= 1) {
238+
// receiver is funder; it is allowed to dip into its channel reserve to pay the fee for a single non-dust HTLC
239+
} else {
240+
throw CannotAffordFees(commitments.channelId, missing = -missingForReceiver.truncateToSatoshi, reserve = commitments1.remoteParams.channelReserve, fees = fees)
237241
}
238242
}
239243

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

+13-2
Original file line numberDiff line numberDiff line change
@@ -216,10 +216,21 @@ class NormalStateSpec extends TestkitBaseClass with StateTestsHelperMethods {
216216

217217
// actual test begins
218218
// at this point alice has the minimal amount to sustain a channel (29000 sat ~= alice reserve + commit fee)
219-
val add = CMD_ADD_HTLC(120000000 msat, randomBytes32, CltvExpiry(400144), TestConstants.emptyOnionPacket, Upstream.Local(UUID.randomUUID()))
219+
// alice should be allowed to dip into her reserve to pay for the commit tx fee increase (see https://github.com/lightningnetwork/lightning-rfc/issues/728)
220+
sender.send(bob, CMD_ADD_HTLC(85000000 msat, randomBytes32, CltvExpiry(400144), TestConstants.emptyOnionPacket, Upstream.Local(UUID.randomUUID())))
221+
sender.expectMsg("ok")
222+
val htlc = bob2alice.expectMsgType[UpdateAddHtlc]
223+
bob2alice.forward(alice)
224+
225+
// but only one pending HTLC is allowed to dip into alice's reserve; bob must wait for that HTLC to settle before sending another one
226+
val add = CMD_ADD_HTLC(80000000 msat, randomBytes32, CltvExpiry(400144), TestConstants.emptyOnionPacket, Upstream.Local(UUID.randomUUID()))
220227
sender.send(bob, add)
221-
val error = RemoteCannotAffordFeesForNewHtlc(channelId(bob), add.amount, missing = 1680 sat, 10000 sat, 10680 sat)
228+
val error = RemoteCannotAffordFeesForNewHtlc(channelId(bob), add.amount, missing = 3400 sat, 10000 sat, 12400 sat)
222229
sender.expectMsg(Failure(AddHtlcFailed(channelId(bob), add.paymentHash, error, Origin.Local(add.upstream.asInstanceOf[Upstream.Local].id, Some(sender.ref)), Some(bob.stateData.asInstanceOf[DATA_NORMAL].channelUpdate), Some(add))))
230+
bob2alice.expectNoMsg(100 millis)
231+
232+
// alice should accept the first incoming htlc
233+
awaitCond(alice.stateData.asInstanceOf[HasCommitments].commitments.remoteChanges.proposed.contains(htlc))
223234
}
224235

225236
test("recv CMD_ADD_HTLC (insufficient funds w/ pending htlcs and 0 balance)") { f =>

0 commit comments

Comments
 (0)