-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
htlcswitch: randomize link fee updates #1229
htlcswitch: randomize link fee updates #1229
Conversation
htlcswitch/link.go
Outdated
// UpdateFeeInterval is the interval at which the update fee timer will | ||
// fire at in order to determine if the link should update its | ||
// commitment fee. | ||
UpdateFeeInterval func() time.Duration |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to be a method? It can simply be an attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, alternatively, it can be a min/max. Don't have a strong opinion in either direction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
htlcswitch/link_test.go
Outdated
} | ||
// For the sake of this test, we'll reset the timer to fire in a second | ||
// so that Alice's link queries for a new network fee. | ||
n.aliceChannelLink.updateFeeTimer.Reset(time.Second) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not lower it even further to instantaneously trigger a fee update
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
peer.go
Outdated
@@ -438,6 +441,9 @@ func (p *peer) loadActiveChannels(chans []*channeldb.OpenChannel) error { | |||
time.NewTicker(time.Minute)), | |||
BatchSize: 10, | |||
UnsafeReplay: cfg.UnsafeReplay, | |||
UpdateFeeInterval: func() time.Duration { | |||
return time.Duration(prand.Intn(60)+11) * time.Minute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Magic numbers should be lifted up into constants.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
peer.go
Outdated
@@ -1416,6 +1422,9 @@ out: | |||
time.NewTicker(time.Minute)), | |||
BatchSize: 10, | |||
UnsafeReplay: cfg.UnsafeReplay, | |||
UpdateFeeInterval: func() time.Duration { | |||
return time.Duration(prand.Intn(60)+11) * time.Minute |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here w.r.t magic numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
htlcswitch/link.go
Outdated
@@ -2012,7 +1996,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, | |||
continue | |||
} | |||
|
|||
heightNow := l.bestHeight | |||
heightNow := atomic.LoadUint32(&l.cfg.Switch.bestHeight) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than accessing a private member, the links should access a public method of the switch. This way, the details (the atomic load), don't need to be leaked to the lower layers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe make retrieve it using a new method BestHeight()
set in the channel link config.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed to use the a BestHeight
method, although I'm not sure we need to set it in the config since we already have a reference to the switch itself in there.
|
||
// Notifier is an instance of a chain notifier that we'll use to signal | ||
// the switch when a new block has arrived. | ||
Notifier chainntnfs.ChainNotifier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why pass the full notifier, when we can pass an already instantiated BlockEpoch
struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the time the switch is declared in server.go
, the ChainNotifier
instance hasn't been initialized yet.
htlcswitch/switch.go
Outdated
|
||
// bestHeight is the best known height of the main chain. The links will | ||
// use this information to govern decisions based on HTLC timeouts. | ||
bestHeight uint32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment should note that this must be used atomically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this should be moved to the top of the struct in order to not run into alignment issues with 32-bit systems.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
htlcswitch/switch.go
Outdated
@@ -1712,6 +1744,8 @@ func (s *Switch) Stop() error { | |||
// accessed and modified. | |||
s.mailOrchestrator.Stop() | |||
|
|||
s.blockEpochs.Cancel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be placed in the main goroutine as a defer instead. As otherwise, it's possible for the switch to exit, but the Stop
method to not have been called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
break out | ||
} | ||
|
||
atomic.StoreUint32(&s.bestHeight, uint32(blockEpoch.Height)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Carrying over a comment here to recommend a method is added so the link don't need to directly access this attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
@@ -438,6 +449,7 @@ func (l *channelLink) Stop() { | |||
l.cfg.ChainEvents.Cancel() | |||
} | |||
|
|||
l.updateFeeTimer.Stop() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can this just be started and stopped within the htlcManager
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't due to needing to reset the timer withinTestChannelLinkUpdateCommitFee
. Otherwise, we'll run into a race where we might update the timer without it being initialized first.
htlcswitch/link_test.go
Outdated
// Make the BatchSize and UpdateFeeInterval large enough to not | ||
// trigger commit updates automatically during tests. | ||
BatchSize: 10000, | ||
UpdateFeeInterval: func() time.Duration { return time.Hour }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use the BatchTicker
pattern to control the ticks instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The BatchTicker
seems to be of better use when wanting continuous ticks within the same interval, rather than a different interval after every tick.
htlcswitch/link.go
Outdated
@@ -2012,7 +1996,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, | |||
continue | |||
} | |||
|
|||
heightNow := l.bestHeight | |||
heightNow := atomic.LoadUint32(&l.cfg.Switch.bestHeight) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe make retrieve it using a new method BestHeight()
set in the channel link config.
53e7824
to
c9a84ae
Compare
@@ -2074,7 +2064,7 @@ func (l *channelLink) processRemoteAdds(fwdPkg *channeldb.FwdPkg, | |||
continue | |||
} | |||
|
|||
heightNow := l.bestHeight | |||
heightNow := l.cfg.Switch.BestHeight() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the l.bestHeight
can be removed after this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
for { | ||
select { | ||
case blockEpoch, ok := <-s.blockEpochStream.Epochs: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the reason we are not usingGetBestBlock()
performance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe so. In the Neutrino case, we end up going to disk. This also notifies us as soon as we know about the new block, rather than having to do some kind of long-polling with GetBestBlock
.
c9a84ae
to
66b2d80
Compare
66b2d80
to
58b358c
Compare
htlcswitch/link.go
Outdated
func (l *channelLink) randomFeeUpdateTimeout() time.Duration { | ||
lower := int64(l.cfg.MinFeeUpdateTimeout) | ||
upper := int64(l.cfg.MaxFeeUpdateTimeout) | ||
rand := prand.Int63n(upper) + lower + 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can cause is to accept (in the worst case), a value of lower+upper+1
, rather than [lower, upper). Instead we can do something like the following:
lower := int64(l.cfg.MinFeeUpdateTimeout)
upper := int64(l.cfg.MaxFeeUpdateTimeout)
rand := prand.Int63n(upper)
if rand < lower {
rand = lower
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
In this commit, we modify the behavior of links updating their commitment fees. Rather than attempting to update the commitment fee for each link every time a new block comes in, we'll use a timer with a random interval between 10 and 60 minutes for each link to determine when to update their corresponding commitment fee. This prevents us from oscillating the fee rate for our various commitment transactions.
In this commit, we move the block height dependency from the links in the switch to the switch itself. This is possible due to a recent change on the links no longer depending on the block height to update their commitment fees. We'll now only have the switch be alerted of new blocks coming in and links will retrieve the height from it atomically.
58b358c
to
8198466
Compare
In this PR, we modify the behavior of links updating their commitment fees. Rather than attempting to update the commitment fee for each link every time a new block comes in, we'll use a timer with a random interval between 10 and 60 minutes for each link to determine when to update their corresponding commitment fee. This prevents us from oscillating the fee rate for our various commitment transactions.
We also move the block height dependency from the links in the switch to the switch itself. This is possible due to a recent change on the links no longer depending on the block height to update their commitment fees. We'll now only have the switch be alerted of new blocks coming in and
links will retrieve the height from it atomically.
Fixes #1129.