diff --git a/htlcswitch/link.go b/htlcswitch/link.go index 80b90f48..e127cfa1 100644 --- a/htlcswitch/link.go +++ b/htlcswitch/link.go @@ -2127,26 +2127,21 @@ func (l *channelLink) ChanID() lnwire.ChannelID { // // NOTE: Part of the ChannelLink interface. func (l *channelLink) Bandwidth() lnwire.MilliSatoshi { + // Get the balance available on the channel for new HTLCs. This takes + // the channel reserve into account so HTLCs up to this value won't + // violate it. channelBandwidth := l.channel.AvailableBalance() - overflowBandwidth := l.overflowQueue.TotalHtlcAmount() // To compute the total bandwidth, we'll take the current available // bandwidth, then subtract the overflow bandwidth as we'll eventually // also need to evaluate those HTLC's once space on the commitment // transaction is free. - linkBandwidth := channelBandwidth - overflowBandwidth - - // If the channel reserve is greater than the total available balance - // of the link, just return 0. - reserve := lnwire.NewMSatFromSatoshis(l.channel.LocalChanReserve()) - if linkBandwidth < reserve { + overflowBandwidth := l.overflowQueue.TotalHtlcAmount() + if channelBandwidth < overflowBandwidth { return 0 } - // Else the amount that is available to flow through the link at this - // point is the available balance minus the reserve amount we are - // required to keep as collateral. - return linkBandwidth - reserve + return channelBandwidth - overflowBandwidth } // AttachMailBox updates the current mailbox used by this link, and hooks up diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 074c8bf2..f8512d72 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -6057,6 +6057,17 @@ func (lc *LightningChannel) availableCommitmentBalance(view *htlcView) ( return 0, 0 } + // We can never spend from the channel reserve, so we'll subtract it + // from our available balance. + ourReserve := lnwire.NewMSatFromSatoshis( + lc.channelState.LocalChanCfg.ChanReserve, + ) + if ourReserve <= ourBalance { + ourBalance -= ourReserve + } else { + ourBalance = 0 + } + // Given the commitment weight, find the commitment fee in case of no // added HTLC output. feePerKw := filteredView.feePerKw @@ -6067,6 +6078,9 @@ func (lc *LightningChannel) availableCommitmentBalance(view *htlcView) ( // If we are the channel initiator, we must to subtract the commitment // fee from our available balance. if lc.channelState.IsInitiator { + if ourBalance < baseCommitFee { + return 0, commitWeight + } ourBalance -= baseCommitFee } @@ -6278,13 +6292,14 @@ func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) chainfee.SatPerKWe // The maximum fee depends of the available balance that can be // committed towards fees. - balance, weight := lc.availableBalance() + commit := lc.channelState.LocalCommitment feeBalance := float64( - balance.ToSatoshis() + lc.channelState.LocalCommitment.CommitFee, + commit.LocalBalance.ToSatoshis() + commit.CommitFee, ) maxFee := feeBalance * maxAllocation // Ensure the fee rate doesn't dip below the fee floor. + _, weight := lc.availableBalance() maxFeeRate := maxFee / (float64(weight) / 1000) return chainfee.SatPerKWeight( math.Max(maxFeeRate, float64(chainfee.FeePerKwFloor)), diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index e9455b75..77af8d3f 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -4599,6 +4599,10 @@ func TestChanAvailableBandwidth(t *testing.T) { } defer cleanUp() + aliceReserve := lnwire.NewMSatFromSatoshis( + aliceChannel.channelState.LocalChanCfg.ChanReserve, + ) + assertBandwidthEstimateCorrect := func(aliceInitiate bool) { // With the HTLC's added, we'll now query the AvailableBalance // method for the current available channel bandwidth from @@ -4625,11 +4629,14 @@ func TestChanAvailableBandwidth(t *testing.T) { // Now, we'll obtain the current available bandwidth in Alice's // latest commitment and compare that to the prior estimate. aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance - if aliceBalance != aliceAvailableBalance { + + // The balance we have available for new HTLCs should be the + // current local commitment balance, minus the channel reserve. + expBalance := aliceBalance - aliceReserve + if expBalance != aliceAvailableBalance { _, _, line, _ := runtime.Caller(1) t.Fatalf("line: %v, incorrect balance: expected %v, "+ - "got %v", line, aliceBalance, - aliceAvailableBalance) + "got %v", line, expBalance, aliceAvailableBalance) } }