Skip to content
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

Unregister validator - fix behind feature flag #12316

Merged
merged 45 commits into from
Apr 28, 2023

Conversation

james-prysm
Copy link
Contributor

@james-prysm james-prysm commented Apr 20, 2023

What type of PR is this?

Bug fix

What does this PR do? Why is it needed?

This cache implementation is hidden behind a feature flag and is only applicable while using mev relay features.
--enable-registration-cache and will not completely replace the db.
By enabling the registration cache we are migrating away from persistent registration storage on the beacon node side. We will also be adding expiration to validator registrations to be more aligned with other client teams.

note: This flag and feature will not be recommended for those who are still using the keymanager apis to configure the fee recipients.
The following PR #12354 will add the features required for persistent keymanager API changes with --enable-registration-cache

jaeger with db (old)
image

jaeger with cache (new)
image

Learn more about builders here.
https://ethereum.github.io/builder-specs/#/Builder

Which issues(s) does this PR fix?

Fixes #12274

@james-prysm james-prysm added Builder PR or issue that supports builder related work UX cosmetic / user experience related labels Apr 20, 2023
@james-prysm james-prysm marked this pull request as ready for review April 21, 2023 19:54
@james-prysm james-prysm requested a review from a team as a code owner April 21, 2023 19:54
beacon-chain/cache/registration.go Outdated Show resolved Hide resolved
Comment on lines 38 to 41
if timeStampExpired(v.Timestamp) {
delete(regCache.indexToRegistration, id)
return nil, errors.Wrapf(ErrNotFoundRegistration, "validator id %d", id)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a mutating operation. You will need to use a write lock if you want to modify the map in this method

Comment on lines 566 to 574
func timeStampExpired(ts uint64) bool {
expiryDuration := time.Duration(params.BeaconConfig().SecondsPerSlot*uint64(params.BeaconConfig().SlotsPerEpoch)*3) * time.Second
// safely convert unint64 to int64
t, err := strconv.ParseInt(fmt.Sprint(ts), 10, 64)
if err != nil {
return false
}
return time.Unix(t, 0).Add(expiryDuration).Unix() < time.Now().Unix()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this different from the other timeStampExpired in this PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is the same, I didn't find a great place to place this but will try to put it in a place where it'd make sense. was thinking maybe we can keep it in both places until full removal but will try to find a better spot without circular dependencies.

Comment on lines 47 to 48
// safely convert unint64 to int64
t, err := strconv.ParseInt(fmt.Sprint(ts), 10, 64)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like an expensive conversion to string and then to int64. Don't we have some more performance based conversions somewhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will use a better solution based on slack discussions

james-prysm and others added 2 commits April 24, 2023 10:37
Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
}

func RegistrationTimeStampExpired(ts uint64) bool {
expiryDuration := time.Duration(params.BeaconConfig().SecondsPerSlot*uint64(params.BeaconConfig().SlotsPerEpoch)*3) * time.Second
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a spec derived value ? Even if its only a prysm specific value, it shouldn't be a magic number in this function. The number of epochs for the expiry duration should be a constant set outside this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not in the specs, but was a number that most other clients also chose from the original proposal

func RegistrationTimeStampExpired(ts uint64) bool {
expiryDuration := time.Duration(params.BeaconConfig().SecondsPerSlot*uint64(params.BeaconConfig().SlotsPerEpoch)*3) * time.Second
// safely convert unint64 to int64
t := new(big.Int).SetUint64(ts).Int64()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better to use our helper here

if err := decode(ctx, enc, reg); err != nil {
return err
}
if cache.RegistrationTimeStampExpired(reg.Timestamp) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we checking the cache in the db like this ? It seems like a bad separation of concerns

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a utility function I just didn't find a great place to put this time function, i tried to add it in the builder at first but it creates circular dependencies.

if err != nil {
return false, err
}
expiryDuration := params.BeaconConfig().RegistrationDuration
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hope this is a good way of doing it...

func NewRegistrationCache() *RegistrationCache {
return &RegistrationCache{
indexToRegistration: make(map[primitives.ValidatorIndex]*ethpb.ValidatorRegistrationV1),
lock: sync.RWMutex{},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deepsource complained the lock was open on the struct so now i added it internally here, can revert to align with other caches.

Copy link
Member

@prestonvanloon prestonvanloon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment, otherwise LGTM

Comment on lines 33 to 34
// GetRegistrationByIndex returns the registration by index in the cache and also removes items in the cache if expired.
func (regCache *RegistrationCache) GetRegistrationByIndex(id primitives.ValidatorIndex) (*ethpb.ValidatorRegistrationV1, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: effective go guidelines suggest that you don't use the prefix "Get" for a getter and simply call it the thing like regCache.RegistrationByIndex(...

https://go.dev/doc/effective_go#Getters

@prylabs-bulldozer prylabs-bulldozer bot merged commit 83416f3 into develop Apr 28, 2023
5 checks passed
@delete-merged-branch delete-merged-branch bot deleted the unregister-validator branch April 28, 2023 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Builder PR or issue that supports builder related work UX cosmetic / user experience related
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Investigate potential builder setting caching
3 participants