From 50685410443dd11a588e55610936b7eb7c832f34 Mon Sep 17 00:00:00 2001 From: bryanvu Date: Wed, 31 May 2017 22:09:03 -0700 Subject: [PATCH] lnwallet: apply dust HTLC amounts to fees MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an HTLC’s value is below a node’s dust limit, the amount for that HTLC should be applied to to the fee used for the channel’s commitment transaction. --- lnwallet/channel.go | 7 ++++-- lnwallet/channel_test.go | 54 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 38a51272..554bc92e 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -1307,7 +1307,7 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool, // * tally in separate accumulator, subtract from fee amount // * when dumping fees back into initiator output, only dumb explicit // fee - var dustLimit btcutil.Amount + var dustLimit, dustFees btcutil.Amount if remoteChain { dustLimit = lc.channelState.TheirDustLimit } else { @@ -1316,12 +1316,14 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool, numHTLCs := 0 for _, htlc := range filteredHTLCView.ourUpdates { if htlc.Amount < dustLimit { + dustFees += htlc.Amount continue } numHTLCs++ } for _, htlc := range filteredHTLCView.theirUpdates { if htlc.Amount < dustLimit { + dustFees += htlc.Amount continue } numHTLCs++ @@ -1332,7 +1334,8 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool, // by the current fee-per-kw, then divide by 1000 to get the proper // fee. totalCommitWeight := commitWeight + btcutil.Amount(htlcWeight*numHTLCs) - commitFee := (lc.channelState.FeePerKw * totalCommitWeight) / 1000 + commitFee := lc.channelState.FeePerKw * totalCommitWeight / 1000 + commitFee -= dustFees // Currently, within the protocol, the initiator always pays the fees. // So we'll subtract the fee amount from the balance of the current diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 535f03a9..4a11cc3e 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -932,6 +932,60 @@ func TestForceClose(t *testing.T) { } } +// TestDustHTLCFees checks that fees are calculated correctly when HTLCs fall +// below the nodes' dust limit. In these cases, the amount of the dust HTLCs +// should be applied to the commitment transaction fee. +func TestDustHTLCFees(t *testing.T) { + createHTLC := func(data, amount btcutil.Amount) (*lnwire.UpdateAddHTLC, + [32]byte) { + preimage := bytes.Repeat([]byte{byte(data)}, 32) + paymentHash := sha256.Sum256(preimage) + + var returnPreimage [32]byte + copy(returnPreimage[:], preimage) + + return &lnwire.UpdateAddHTLC{ + PaymentHash: paymentHash, + Amount: amount, + Expiry: uint32(5), + }, returnPreimage + } + + // Create a test channel which will be used for the duration of this + // unittest. The channel will be funded evenly with Alice having 5 BTC, + // and Bob having 5 BTC. + aliceChannel, bobChannel, cleanUp, err := createTestChannels(3) + if err != nil { + t.Fatalf("unable to create test channels: %v", err) + } + defer cleanUp() + + // This HTLC amount should be lower than the dust limits of both nodes. + htlcAmount := btcutil.Amount(100) + htlc, _ := createHTLC(0, htlcAmount) + if _, err := aliceChannel.AddHTLC(htlc); err != nil { + t.Fatalf("alice unable to add htlc: %v", err) + } + if _, err := bobChannel.ReceiveHTLC(htlc); err != nil { + t.Fatalf("bob unable to receive htlc: %v", err) + } + if err := forceStateTransition(aliceChannel, bobChannel); err != nil { + t.Fatalf("Can't update the channel state: %v", err) + } + + defaultFee := calcStaticFee(0) + if aliceChannel.channelState.CommitFee != defaultFee-htlcAmount { + t.Fatalf("dust htlc amounts not subtracted from commitment fee "+ + "expected %v, got %v", defaultFee-htlcAmount, + aliceChannel.channelState.CommitFee) + } + if bobChannel.channelState.CommitFee != defaultFee-htlcAmount { + t.Fatalf("dust htlc amounts not subtracted from commitment fee "+ + "expected %v, got %v", defaultFee-htlcAmount, + bobChannel.channelState.CommitFee) + } +} + // TestCheckDustLimit checks that unsettled HTLC with dust limit not included in // commitment transaction as output, but sender balance is decreased (thereby all // unsettled dust HTLCs will go to miners fee).