-
Notifications
You must be signed in to change notification settings - Fork 127
server/swap: metered block-triggered conf and penalty checks #1629
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
Conversation
buck54321
commented
May 26, 2022
Cool. I guess I should get #1563 out of draft. Lock contention can be just as bad as blocking the ws inHandler or backing up conf checks depending on where it is blocking. |
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.
Minor things
dex/meter/meterer.go
Outdated
if s.scheduled != nil { | ||
if !s.scheduled.Stop() { | ||
<-s.scheduled.C | ||
} | ||
} |
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.
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.
and not completely prevent further usage of
SignalMeterer
I always just assumed this was a one-Stop
type.
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.
yeah, that would be the default assumption for me as well,
just thought comment could be more precise (maybe this code can be re-used in other places as well in the future)
Stop further signalling and cancel any scheduled signals.
server/swap/swap.go
Outdated
@@ -34,6 +35,7 @@ var ( | |||
// txWaitExpiration is the longest the Swapper will wait for a coin waiter. | |||
// This could be thought of as the maximum allowable backend latency. | |||
txWaitExpiration = 2 * time.Minute | |||
minBlockPeriod = time.Second * 10 |
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.
might be useful to describe how/why this value was chosen
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 really pulled it out of thin air. The value is open for debate. Anybody want a different value?
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 just some explanation regarding why this delay is needed in the first place would be nice to have (idk, one can search through git history and find this PR with the answer as well),
can suggest something like:
// minBlockPeriod helps with limiting notification bursts when blocks are generated too fast (e.g. in Ethereum occasionally several blocks can are generated in a matter of several seconds).
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.
Agree a sentence would be good here.
As far as the choice of 10s goes, I suppose that's short enough that it would not be an annoying delay, but also long enough that checks shouldn't pile up too much. (it works for me)
dex/meter/meterer.go
Outdated
// the previous signal, that signal will be scheduled for later to respect the | ||
// configured delay. If multiple signals arrive within minDelay, they will be | ||
// grouped into a single delayed signal. Error signals are never delayed. | ||
type SignalMeterer 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.
Because you have NewSignalMeterer
this does not need to be exported maybe?
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 don't think so. It's used as a concrete type by an importing package. I think it's customary to export it.
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.
Yes agree with @buck54321 . Some linters will even nag if an exported constructor returns and unexported type because it can be "annoying to use" or something to that extent.
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.
Thanks. Understood.
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.
Cool little utility. Overall seems like good logic and it works.
I don't totally love the goroutine use as a means to get unlimited buffering courtesy of the runtime, and I have some ideas there, but nothing that really has to change.
dex/meter/meterer.go
Outdated
defer s.mtx.Unlock() | ||
// Errors are passed immediately. | ||
if err != nil { | ||
go s.recv(err) |
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 think you might as well replace recv func(error)
with recv chan error
, and doing s.recv <- err
instead of go s.recv(err)
.
The goroutine allocations and runtime overhead seem avoidable, and it feels tailored for a channel anyway. I get the sense you're using goroutines as a way to use the runtime for effectively unlimited buffering, which could backfire in addition to being a bit inefficient.
Plus in Swapper
, I think a channel is more natural since you've got a select loop going already. illustration: 124ec64
And as usual lately I'm looking at patterns that eliminate locks and fields with event loops and closure, so I'm toying with this alternate mechanism: 817b800
Just toying around, don't feel like you need to take either suggestion.
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.
817b800 is beautiful 😍.
dex/meter/meterer.go
Outdated
s.mtx.Lock() | ||
defer s.mtx.Unlock() | ||
// Errors are passed immediately. | ||
if err != nil { |
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 move the locking until after this first early return
// TODO: This pattern would still send the block trigger half of the | ||
// time if the ctxMaster is canceled. |
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.
Good catch. That's annoying. Seems harmless, just not really intended.
server/swap/swap.go
Outdated
@@ -34,6 +35,7 @@ var ( | |||
// txWaitExpiration is the longest the Swapper will wait for a coin waiter. | |||
// This could be thought of as the maximum allowable backend latency. | |||
txWaitExpiration = 2 * time.Minute | |||
minBlockPeriod = time.Second * 10 |
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.
Agree a sentence would be good here.
As far as the choice of 10s goes, I suppose that's short enough that it would not be an annoying delay, but also long enough that checks shouldn't pile up too much. (it works for me)
53554f2
to
b1a1bd1
Compare
Ethereum has very short block times. And just for conservation of resources, tightly-grouped blocks need not trigger tightly-grouped conf and penalty checks. This adds a minimum delay window to block notifications. If blocks comes farther than the minimum delay apart, nothing changes from the current behavior. If 1 or more blocks arrives within the delay window of another, they will be collected into a single block notification that occurs once the min delay has passed. The newly implemented DelayedRelay is only used in the swapper for block notifications for now, but might also be useful for the client. Co-authored-by: Jonathan Chappelow <chappjc@gmail.com>