htlcswitch: respect minimum relay fee

When channels fee rates are being considered for an update, the minimum
relay fee should also be considered.
This commit is contained in:
Elle Mouton committed 2021-10-05 18:30:41 +02:00
1 parent 6712595618
commit f667683e6c
5 files changed
+317 -60

No files matched your search

+25 -13
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"crypto/sha256"
"fmt"
"math"
prand "math/rand"
"sync"
"sync/atomic"
@@ -619,9 +618,18 @@ func (l *channelLink) sampleNetworkFee() (chainfee.SatPerKWeight, error) {
// shouldAdjustCommitFee returns true if we should update our commitment fee to
// match that of the network fee. We'll only update our commitment fee if the
// network fee is +/- 10% to our network fee.
func shouldAdjustCommitFee(netFee, chanFee chainfee.SatPerKWeight) bool {
// network fee is +/- 10% to our commitment fee or if our current commitment
// fee is below the minimum relay fee.
func shouldAdjustCommitFee(netFee, chanFee,
minRelayFee chainfee.SatPerKWeight) bool {
switch {
// If the network fee is greater than our current commitment fee and
// our current commitment fee is below the minimum relay fee then
// we should switch to it no matter if it is less than a 10% increase.
case netFee > chanFee && chanFee < minRelayFee:
return true
// If the network fee is greater than the commitment fee, then we'll
// switch to it if it's at least 10% greater than the commit fee.
case netFee > chanFee && netFee >= (chanFee+(chanFee*10)/100):
@@ -1106,18 +1114,22 @@ func (l *channelLink) htlcManager() {
continue
}
// We'll check to see if we should update the fee rate
// based on our current set fee rate. We'll cap the new
// fee rate to our max fee allocation.
commitFee := l.channel.CommitFeeRate()
maxFee := l.channel.MaxFeeRate(
l.cfg.MaxFeeAllocation,
minRelayFee := l.cfg.FeeEstimator.RelayFeePerKW()
newCommitFee := l.channel.IdealCommitFeeRate(
netFee, minRelayFee,
l.cfg.MaxAnchorsCommitFeeRate,
l.cfg.MaxFeeAllocation,
)
newCommitFee := chainfee.SatPerKWeight(
math.Min(float64(netFee), float64(maxFee)),
)
if !shouldAdjustCommitFee(newCommitFee, commitFee) {
// We determine if we should adjust the commitment fee
// based on the current commitment fee, the suggested
// new commitment fee and the current minimum relay fee
// rate.
commitFee := l.channel.CommitFeeRate()
if !shouldAdjustCommitFee(
newCommitFee, commitFee, minRelayFee,
) {
continue
}
+41 -7
View File
@@ -3744,6 +3744,7 @@ func TestShouldAdjustCommitFee(t *testing.T) {
tests := []struct {
netFee chainfee.SatPerKWeight
chanFee chainfee.SatPerKWeight
minRelayFee chainfee.SatPerKWeight
shouldAdjust bool
}{
@@ -3819,11 +3820,22 @@ func TestShouldAdjustCommitFee(t *testing.T) {
chanFee: 1000,
shouldAdjust: false,
},
// The network fee is higher than our commitment fee,
// hasn't yet crossed our activation threshold, but the
// current commitment fee is below the minimum relay fee and
// so the fee should be updated.
{
netFee: 1100,
chanFee: 1098,
minRelayFee: 1099,
shouldAdjust: true,
},
}
for i, test := range tests {
adjustedFee := shouldAdjustCommitFee(
test.netFee, test.chanFee,
test.netFee, test.chanFee, test.minRelayFee,
)
if adjustedFee && !test.shouldAdjust {
@@ -4009,6 +4021,13 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
{"bob", "alice", &lnwire.RevokeAndAck{}, false},
{"bob", "alice", &lnwire.CommitSig{}, false},
{"alice", "bob", &lnwire.RevokeAndAck{}, false},
// Third fee update.
{"alice", "bob", &lnwire.UpdateFee{}, false},
{"alice", "bob", &lnwire.CommitSig{}, false},
{"bob", "alice", &lnwire.RevokeAndAck{}, false},
{"bob", "alice", &lnwire.CommitSig{}, false},
{"alice", "bob", &lnwire.RevokeAndAck{}, false},
}
n.aliceServer.intersect(createInterceptorFunc("[alice] <-- [bob]",
"alice", messages, chanID, false))
@@ -4025,8 +4044,8 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
// triggerFeeUpdate is a helper closure to determine whether a fee
// update was triggered and completed properly.
triggerFeeUpdate := func(feeEstimate, newFeeRate chainfee.SatPerKWeight,
shouldUpdate bool) {
triggerFeeUpdate := func(feeEstimate, minRelayFee,
newFeeRate chainfee.SatPerKWeight, shouldUpdate bool) {
t.Helper()
@@ -4046,6 +4065,13 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
t.Fatalf("alice didn't query for the new network fee")
}
// We also send the min relay fee response to Alice.
select {
case n.feeEstimator.relayFee <- minRelayFee:
case <-time.After(time.Second * 5):
t.Fatalf("alice didn't query for the min relay fee")
}
// Record the fee rates after the links have processed the fee
// update and ensure they are correct based on whether a fee
// update should have been triggered.
@@ -4071,20 +4097,28 @@ func TestChannelLinkUpdateCommitFee(t *testing.T) {
}, 10*time.Second, time.Second)
}
minRelayFee := startingFeeRate / 3
// Triggering the link to update the fee of the channel with the same
// fee rate should not send a fee update.
triggerFeeUpdate(startingFeeRate, startingFeeRate, false)
triggerFeeUpdate(startingFeeRate, minRelayFee, startingFeeRate, false)
// Triggering the link to update the fee of the channel with a much
// larger fee rate _should_ send a fee update.
newFeeRate := startingFeeRate * 3
triggerFeeUpdate(newFeeRate, newFeeRate, true)
triggerFeeUpdate(newFeeRate, minRelayFee, newFeeRate, true)
// Triggering the link to update the fee of the channel with a fee rate
// that exceeds its maximum fee allocation should result in a fee rate
// corresponding to the maximum fee allocation.
const maxFeeRate chainfee.SatPerKWeight = 207182320
triggerFeeUpdate(maxFeeRate+1, maxFeeRate, true)
const maxFeeRate chainfee.SatPerKWeight = 207180182
triggerFeeUpdate(maxFeeRate+1, minRelayFee, maxFeeRate, true)
// Triggering the link to update the fee of the channel with a fee rate
// that is below the current min relay fee rate should result in a fee
// rate corresponding to the minimum relay fee.
newFeeRate = minRelayFee / 2
triggerFeeUpdate(newFeeRate, minRelayFee, minRelayFee, true)
}
// TestChannelLinkAcceptDuplicatePayment tests that if a link receives an
+8 -1
View File
@@ -71,6 +71,7 @@ func (m *mockPreimageCache) SubscribeUpdates() *contractcourt.WitnessSubscriptio
type mockFeeEstimator struct {
byteFeeIn chan chainfee.SatPerKWeight
relayFee chan chainfee.SatPerKWeight
quit chan struct{}
}
@@ -78,6 +79,7 @@ type mockFeeEstimator struct {
func newMockFeeEstimator() *mockFeeEstimator {
return &mockFeeEstimator{
byteFeeIn: make(chan chainfee.SatPerKWeight),
relayFee: make(chan chainfee.SatPerKWeight),
quit: make(chan struct{}),
}
}
@@ -94,7 +96,12 @@ func (m *mockFeeEstimator) EstimateFeePerKW(
}
func (m *mockFeeEstimator) RelayFeePerKW() chainfee.SatPerKWeight {
return 1e3
select {
case feeRate := <-m.relayFee:
return feeRate
case <-m.quit:
return 0
}
}
func (m *mockFeeEstimator) Start() error {