-
Notifications
You must be signed in to change notification settings - Fork 197
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
Add storage and resend for validators preferences #149
Add storage and resend for validators preferences #149
Conversation
Very nice, and thoughtful! I noticed that |
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
cmd/mev-boost/main.go
Outdated
defaultRelayTimeoutMs = getEnvInt("RELAY_TIMEOUT_MS", 2000) // timeout for all the requests to the relay | ||
defaultRelayCheck = os.Getenv("RELAY_STARTUP_CHECK") != "" | ||
defaultGenesisForkVersion = getEnv("GENESIS_FORK_VERSION", "") | ||
defaultRegisterValidatorInterval = getEnvInt("REGISTER_VALIDATOR_INTERVAL_SEC", 5) |
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.
Let's think about a sane default, if all of the validators send their registration every 5 seconds it will effectively be a DDoS attack on the unfortunate relay on the receiving end
Slot is 12 seconds, that's a sane lower bound
An epoch is 384 seconds, and validators are asked to re-register once per epoch so it's an upper bound
I think something like a fourth (96s) of an epoch is already frequent enough
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.
even resending once an epoch should be fine (and instantly on receiving)
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 agree with your comments, but it seems like it's a bad idea to let the user decide of the interval in the end, wdyt ?
select { | ||
case <-done: | ||
return | ||
case <-ticker.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.
One issue that arises is that we can send twice in a short interval (if a registration request comes near the timer tick)
In this approach it's not easy to solve it, and I think we could come at this from a different angle:
- make registerValidatorAtInterval the only place responsible for sending the registration
- listen on both the timer, and a new channel that accepts new registration requests
- on new registration request, send the preferences and reset the timer
This has some nice benefits:
- m.vp is now an object local to registerValidatorAtInterval
- validator preferences struct can become just a plain old map
- no need for mutex
- after a registration you will correctly wait until the next interval
The only downside is that you'll need to return the registration status back over a channel (or a callback), but it should be okay.
We can submit a PR to this PR if you prefer not implementing 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.
Totally agree with this comment ! Thanks a lot for raising the issue and proposing an alternative 👍
I can make the updates don't worry.
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.
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
server/service.go
Outdated
// Send the payload to the goroutine responsible for handling the resend at interval | ||
m.newRegistrationsRequests <- payload | ||
// Block until we get the number of successful requests back from this goroutine | ||
numSuccessRequestsToRelay := <-m.numSuccessRequestsToRelay |
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.
Once context (timeout) handling is implemented this will become a race, the result channel (or callback) should be specific to the request.
I think pushing a pair of (payload, result chan) would be a clean way to solve it that will also work nicely with context timeouts.
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 like the idea of pushing the response channel, I've added this in 2d26f24
server/service.go
Outdated
|
||
// Used to stop registerValidatorAtInterval | ||
done chan bool | ||
// Used by registerValidator to share new incoming registration request with the goroutine holding the ticker |
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.
It'd be great to avoid fields shared across requests as they usually introduce a race
server/service.go
Outdated
@@ -56,10 +57,17 @@ type BoostService struct { | |||
serverTimeouts HTTPServerTimeouts | |||
|
|||
httpClient http.Client | |||
|
|||
// Used to stop registerValidatorAtInterval | |||
done chan bool |
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.
Another way to implement shutdowns will be to have a context with cancel, and storing the cancel function.
Since we are not using contexts yet this is good too.
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 agree, that's what they've been made after all.
Fixed in a2bb054
server/service.go
Outdated
@@ -110,10 +122,15 @@ func (m *BoostService) StartHTTPServer() error { | |||
IdleTimeout: m.serverTimeouts.Idle, | |||
} | |||
|
|||
// Start separate process to send validator preferences at regular interval. | |||
go m.registerValidatorAtInterval(time.Second*384, m.done) |
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'm guessing this should be registerValidatorIntervalSec
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.
Missed that, thanks ! Fixed in e1d6572.
server/service.go
Outdated
@@ -384,3 +435,7 @@ func (m *BoostService) handleGetPayload(w http.ResponseWriter, req *http.Request | |||
return | |||
} | |||
} | |||
|
|||
func (m *BoostService) shutdown() { | |||
m.done <- true |
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.
using a context would be better because if there's multiple things to shut down, this channel would only work for one of them. could be okay for now, and we can also do this in another PR.
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 as above, fixed in a2bb054
server/service.go
Outdated
case <-done: | ||
// mev-boost has probably stopped | ||
return | ||
case payload = <-m.newRegistrationsRequests: |
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 will overwrite the previous payload, but it's conceivable that there's multiple validators using one BN that would then overwrite each others registrations. perhaps better to make this additive?
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'm actually not sure about it, the expectation is to have a single BN connecting to mev-boost, and forcing this to be additive would mean you cannot ever remove a registration.
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've implemented the merging process between the old (local payload list) and the new one (received from the channel) but not pushed it, so you'll just have to tell me !
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.
@Ruteri expectation is a single BN, but this single BN could have many validator clients connected! We can not ignore this case.
One approach could be to add a time to each registration and remove old ones.
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
return | ||
case srr := <-m.registrationsRequests: | ||
// registerValidator has received new registrations and forwards them to here | ||
srr.numSuccessRequestsToRelay <- m.sendValidatorPreferences(log, srr.preferences) |
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.
payload
isn't updated
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 a3d5a4b
Signed-off-by: Luca Georges Francois <luca.georges-francois@epitech.eu>
It was closed because the temporary develop branch was deleted after merging into main. Please point that PR towards the main branch, I seem to not be able to do it from my user, and can't reopen until then :) |
Description:
This PR adds a way to send validators preferences at a regular interval to the relays.
It follows the implementation proposed in #141 and is part of the steps to achieve v1 as described in #95.
Problem(s) & goal(s):
//
Additional context & references:
This PR adds a method to handle the logic of sending the preferences to the relays, which is used by both the standard handler and a new method used to send the already registered prefs at a provided interval.
Several questions still remains regarding the implementation, see #141 for more.
I have run these commands:
make lint
make test
make run-mergemock-integration
go mod tidy