From e398544b8bc385f16d5688021d7ca5101ec4f7a1 Mon Sep 17 00:00:00 2001 From: "Johan T. Halseth" Date: Wed, 19 Feb 2020 12:27:42 +0100 Subject: [PATCH] lnwallet/channel: take remote commitment view into availableBalance calculation Since our HTLC must also be added to the remote commitment, we do the balance caluclation also from the remote chain perspective and report our minimum balance from the two commit views as our available balance. --- lnwallet/channel.go | 29 +++++++++++++++++++++++++---- lnwallet/channel_test.go | 13 +++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 0cc512d5..01be6117 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -6030,9 +6030,19 @@ func (lc *LightningChannel) availableBalance() (lnwire.MilliSatoshi, int64) { // add updates concurrently, causing our balance to go down if we're // the initiator, but this is a problem on the protocol level. ourLocalCommitBalance, commitWeight := lc.availableCommitmentBalance( - htlcView, + htlcView, false, ) + // Do the same calculation from the remote commitment point of view. + ourRemoteCommitBalance, _ := lc.availableCommitmentBalance( + htlcView, true, + ) + + // Return which ever balance is lowest. + if ourRemoteCommitBalance < ourLocalCommitBalance { + return ourRemoteCommitBalance, commitWeight + } + return ourLocalCommitBalance, commitWeight } @@ -6043,14 +6053,14 @@ func (lc *LightningChannel) availableBalance() (lnwire.MilliSatoshi, int64) { // commitment, increasing the commitment fee we must pay as an initiator, // eating into our balance. It will make sure we won't violate the channel // reserve constraints for this amount. -func (lc *LightningChannel) availableCommitmentBalance(view *htlcView) ( - lnwire.MilliSatoshi, int64) { +func (lc *LightningChannel) availableCommitmentBalance(view *htlcView, + remoteChain bool) (lnwire.MilliSatoshi, int64) { // Compute the current balances for this commitment. This will take // into account HTLCs to determine the commit weight, which the // initiator must pay the fee for. ourBalance, theirBalance, commitWeight, filteredView, err := lc.computeView( - view, false, false, + view, remoteChain, false, ) if err != nil { lc.log.Errorf("Unable to fetch available balance: %v", err) @@ -6118,6 +6128,17 @@ func (lc *LightningChannel) availableCommitmentBalance(view *htlcView) ( htlcTimeoutFee(feePerKw), ) + // If we are looking at the remote commitment, we must use the remote + // dust limit and the fee for adding an HTLC success transaction. + if remoteChain { + dustlimit = lnwire.NewMSatFromSatoshis( + lc.channelState.RemoteChanCfg.DustLimit, + ) + htlcFee = lnwire.NewMSatFromSatoshis( + htlcSuccessFee(feePerKw), + ) + } + // The HTLC output will be manifested on the commitment if it // is non-dust after paying the HTLC fee. nonDustHtlcAmt := dustlimit + htlcFee diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index be739520..c4c88670 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -4749,9 +4749,6 @@ func TestChanAvailableBalanceNearHtlcFee(t *testing.T) { aliceDustlimit := lnwire.NewMSatFromSatoshis( aliceChannel.channelState.LocalChanCfg.DustLimit, ) - bobDustlimit := lnwire.NewMSatFromSatoshis( - bobChannel.channelState.LocalChanCfg.DustLimit, - ) feeRate := chainfee.SatPerKWeight( aliceChannel.channelState.LocalCommitment.FeePerKw, ) @@ -4764,6 +4761,9 @@ func TestChanAvailableBalanceNearHtlcFee(t *testing.T) { htlcTimeoutFee := lnwire.NewMSatFromSatoshis( htlcTimeoutFee(feeRate), ) + htlcSuccessFee := lnwire.NewMSatFromSatoshis( + htlcSuccessFee(feeRate), + ) // Helper method to check the current reported balance. checkBalance := func(t *testing.T, expBalanceAlice, @@ -4889,7 +4889,12 @@ func TestChanAvailableBalanceNearHtlcFee(t *testing.T) { // HTLC from Bob to the commitment transaction. Bob's balance should // reflect this, by only reporting dust amount being available. Alice // should still report a zero balance. - bobNonDustHtlc := bobDustlimit + htlcTimeoutFee + + // Since the dustlimit is different for the two commitments, the + // largest HTLC Bob can send that Alice can afford on both commitments + // (remember she cannot afford to pay the HTLC fee) is the largest dust + // HTLC on Alice's commitemnt, since her dust limit is lower. + bobNonDustHtlc := aliceDustlimit + htlcSuccessFee expBobBalance = bobNonDustHtlc - 1 expAliceBalance = 0 checkBalance(t, expAliceBalance, expBobBalance)