Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion lnwallet/chainfee/rates.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ import (

const (
// 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

// 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.
Expand Down
4 changes: 2 additions & 2 deletions lnwallet/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -2412,9 +2412,9 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,

effFeeRate := chainfee.SatPerKWeight(fee) * 1000 /
chainfee.SatPerKWeight(weight)
if effFeeRate < chainfee.FeePerKwFloor {
if effFeeRate < chainfee.AbsoluteFeePerKwFloor {
return nil, fmt.Errorf("height=%v, for ChannelPoint(%v) "+
"attempts to create commitment wigh feerate %v: %v",
"attempts to create commitment with feerate %v: %v",
nextHeight, lc.channelState.FundingOutpoint,
effFeeRate, spew.Sdump(commitTx))
}
Expand Down
38 changes: 38 additions & 0 deletions lnwallet/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7638,3 +7638,41 @@ func TestChannelMaxFeeRate(t *testing.T) {
assertMaxFeeRate(0.000001, 690)
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)
}
}