From fa96d707c5bf4e6dfbe2bbd6a2120f6160134821 Mon Sep 17 00:00:00 2001 From: Wilmer Paulino Date: Thu, 3 Oct 2019 17:10:18 -0400 Subject: [PATCH] lnwallet: enforce fee floor on max fee allocation Without this, it was possible for a combination of our balance and max fee allocation to result in a fee rate below the fee floor causing the remote party to reject the update and close the channel. --- lnwallet/channel.go | 6 +++++- lnwallet/channel_test.go | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 720f5d0d..f4e99b6e 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -5,6 +5,7 @@ import ( "container/list" "crypto/sha256" "fmt" + "math" "sort" "sync" @@ -6239,7 +6240,10 @@ func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) SatPerKWeight { balance.ToSatoshis() + lc.channelState.LocalCommitment.CommitFee, ) maxFee := feeBalance * maxAllocation - return SatPerKWeight(maxFee / (float64(weight) / 1000)) + + // Ensure the fee rate doesn't dip below the fee floor. + maxFeeRate := maxFee / (float64(weight) / 1000) + return SatPerKWeight(math.Max(maxFeeRate, float64(FeePerKwFloor))) } // RemoteNextRevocation returns the channelState's RemoteNextRevocation. diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index 91e5e17d..ef0b5234 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -6611,3 +6611,30 @@ func TestForceCloseBorkedState(t *testing.T) { t.Fatalf("append remove chain tail should have failed") } } + +// TestChannelMaxFeeRate ensures we correctly compute a channel initiator's max +// fee rate based on an allocation and its available balance. It should never +// dip below the established fee floor. +func TestChannelMaxFeeRate(t *testing.T) { + t.Parallel() + + aliceChannel, _, cleanUp, err := CreateTestChannels(true) + if err != nil { + t.Fatalf("unable to create test channels: %v", err) + } + defer cleanUp() + + assertMaxFeeRate := func(maxAlloc float64, expFeeRate SatPerKWeight) { + maxFeeRate := aliceChannel.MaxFeeRate(maxAlloc) + if maxFeeRate != expFeeRate { + t.Fatalf("expected max fee rate of %v with max "+ + "allocation of %v, got %v", expFeeRate, + maxAlloc, maxFeeRate) + } + } + + assertMaxFeeRate(1.0, 690607734) + assertMaxFeeRate(0.001, 690607) + assertMaxFeeRate(0.000001, 690) + assertMaxFeeRate(0.0000001, FeePerKwFloor) +}