lnwallet/channel: enforce absolute fee floor of 250 sat/kw
This enforces the _actualized_ fee rate of the commitment transaction, rather than the fee floor used for estimation. The new value of 250 sat/kw corresponds to 1 sat/byte, rather than 253 which is only rounded up during estimation to account for the fact that BOLT 3 rounds down to the nearest satoshi and that the vbyte fee estimation is lossy. Previously we would incorrectly fail to sign the next commitment even though the fee was technically high enough. Restarting with this commit should solve the issue as long as the channel hasn't already gone to chain.
This commit is contained in:
parent
3ab5899853
commit
89bd58786e
@ -9,8 +9,13 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
|
// FeePerKwFloor is the lowest fee rate in sat/kw that we should use for
|
||||||
// determining transaction fees.
|
// estimating transaction fees before signing.
|
||||||
FeePerKwFloor SatPerKWeight = 253
|
FeePerKwFloor SatPerKWeight = 253
|
||||||
|
|
||||||
|
// AbsoluteFeePerKwFloor is the lowest fee rate in sat/kw of a
|
||||||
|
// transaction that we should ever _create_. This is the the equivalent
|
||||||
|
// of 1 sat/byte in sat/kw.
|
||||||
|
AbsoluteFeePerKwFloor SatPerKWeight = 250
|
||||||
)
|
)
|
||||||
|
|
||||||
// SatPerKVByte represents a fee rate in sat/kb.
|
// SatPerKVByte represents a fee rate in sat/kb.
|
||||||
|
@ -2412,7 +2412,7 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
|
|||||||
|
|
||||||
effFeeRate := chainfee.SatPerKWeight(fee) * 1000 /
|
effFeeRate := chainfee.SatPerKWeight(fee) * 1000 /
|
||||||
chainfee.SatPerKWeight(weight)
|
chainfee.SatPerKWeight(weight)
|
||||||
if effFeeRate < chainfee.FeePerKwFloor {
|
if effFeeRate < chainfee.AbsoluteFeePerKwFloor {
|
||||||
return nil, fmt.Errorf("height=%v, for ChannelPoint(%v) "+
|
return nil, fmt.Errorf("height=%v, for ChannelPoint(%v) "+
|
||||||
"attempts to create commitment with feerate %v: %v",
|
"attempts to create commitment with feerate %v: %v",
|
||||||
nextHeight, lc.channelState.FundingOutpoint,
|
nextHeight, lc.channelState.FundingOutpoint,
|
||||||
|
@ -7638,3 +7638,41 @@ func TestChannelMaxFeeRate(t *testing.T) {
|
|||||||
assertMaxFeeRate(0.000001, 690)
|
assertMaxFeeRate(0.000001, 690)
|
||||||
assertMaxFeeRate(0.0000001, chainfee.FeePerKwFloor)
|
assertMaxFeeRate(0.0000001, chainfee.FeePerKwFloor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestChannelFeeRateFloor asserts that valid commitments can be proposed and
|
||||||
|
// received using chainfee.FeePerKwFloor as the initiator's fee rate.
|
||||||
|
func TestChannelFeeRateFloor(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
alice, bob, cleanUp, err := CreateTestChannels(
|
||||||
|
channeldb.SingleFunderTweaklessBit,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create test channels: %v", err)
|
||||||
|
}
|
||||||
|
defer cleanUp()
|
||||||
|
|
||||||
|
// Set the fee rate to the proposing fee rate floor.
|
||||||
|
minFee := chainfee.FeePerKwFloor
|
||||||
|
|
||||||
|
// Alice is the initiator, so only she can propose fee updates.
|
||||||
|
if err := alice.UpdateFee(minFee); err != nil {
|
||||||
|
t.Fatalf("unable to send fee update")
|
||||||
|
}
|
||||||
|
if err := bob.ReceiveUpdateFee(minFee); err != nil {
|
||||||
|
t.Fatalf("unable to receive fee update")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that alice can still sign commitments.
|
||||||
|
sig, htlcSigs, _, err := alice.SignNextCommitment()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("alice unable to sign commitment: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that bob can still receive commitments.
|
||||||
|
err = bob.ReceiveNewCommitment(sig, htlcSigs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("bob unable to process alice's new commitment: %v",
|
||||||
|
err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user