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.
This commit is contained in:
parent
450e5a7df4
commit
fa96d707c5
@ -5,6 +5,7 @@ import (
|
|||||||
"container/list"
|
"container/list"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
@ -6239,7 +6240,10 @@ func (lc *LightningChannel) MaxFeeRate(maxAllocation float64) SatPerKWeight {
|
|||||||
balance.ToSatoshis() + lc.channelState.LocalCommitment.CommitFee,
|
balance.ToSatoshis() + lc.channelState.LocalCommitment.CommitFee,
|
||||||
)
|
)
|
||||||
maxFee := feeBalance * maxAllocation
|
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.
|
// RemoteNextRevocation returns the channelState's RemoteNextRevocation.
|
||||||
|
@ -6611,3 +6611,30 @@ func TestForceCloseBorkedState(t *testing.T) {
|
|||||||
t.Fatalf("append remove chain tail should have failed")
|
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)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user