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.
This commit is contained in:
Johan T. Halseth 2020-02-19 12:27:42 +01:00
parent f94464d987
commit e398544b8b
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
2 changed files with 34 additions and 8 deletions

@ -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

@ -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)