-
Notifications
You must be signed in to change notification settings - Fork 2k
BCFR-1201 bind lp filter fix race #17095
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
Changes from all commits
3b1867a
7977e65
79bd5f5
c91fc0a
31ab393
7e5a49d
85ef2e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "chainlink": patch | ||
| --- | ||
|
|
||
| #bugfix bind reg filter before unreg & bind noop when no new addresses |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,16 +22,44 @@ type syncedFilter struct { | |
| // internal state properties | ||
| mu sync.RWMutex | ||
| filter logpoller.Filter | ||
|
|
||
| // identifies if filter was modified between updates | ||
| dirty bool | ||
| } | ||
|
|
||
| func newSyncedFilter() *syncedFilter { | ||
| return &syncedFilter{} | ||
| } | ||
|
|
||
| func (r *syncedFilter) Update(ctx context.Context, registrar Registrar, updatedName string) error { | ||
| r.mu.Lock() | ||
| defer r.mu.Unlock() | ||
|
|
||
| oldName := r.filter.Name | ||
| if !r.dirty { | ||
| return nil | ||
| } | ||
|
|
||
| r.filter.Name = updatedName | ||
|
|
||
| if err := r.register(ctx, registrar); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // filter updated successfully, it's not dirty anymore | ||
| r.dirty = false | ||
|
|
||
| return r.unregister(ctx, registrar, oldName) | ||
| } | ||
|
|
||
| func (r *syncedFilter) Register(ctx context.Context, registrar Registrar) error { | ||
| r.mu.RLock() | ||
| defer r.mu.RUnlock() | ||
|
|
||
| return r.register(ctx, registrar) | ||
| } | ||
|
|
||
| func (r *syncedFilter) register(ctx context.Context, registrar Registrar) error { | ||
| if !registrar.HasFilter(r.filter.Name) { | ||
| if err := registrar.RegisterFilter(ctx, r.filter); err != nil { | ||
| return FilterError{ | ||
|
|
@@ -49,11 +77,15 @@ func (r *syncedFilter) Unregister(ctx context.Context, registrar Registrar) erro | |
| r.mu.RLock() | ||
| defer r.mu.RUnlock() | ||
|
|
||
| if !registrar.HasFilter(r.filter.Name) { | ||
| return r.unregister(ctx, registrar, r.filter.Name) | ||
| } | ||
|
|
||
| func (r *syncedFilter) unregister(ctx context.Context, registrar Registrar, name string) error { | ||
| if !registrar.HasFilter(name) { | ||
| return nil | ||
| } | ||
|
|
||
| if err := registrar.UnregisterFilter(ctx, r.filter.Name); err != nil { | ||
| if err := registrar.UnregisterFilter(ctx, name); err != nil { | ||
| return FilterError{ | ||
| Err: fmt.Errorf("%w: %s", types.ErrInternal, err.Error()), | ||
| Action: "unregister", | ||
|
|
@@ -68,27 +100,35 @@ func (r *syncedFilter) SetFilter(filter logpoller.Filter) { | |
| r.mu.Lock() | ||
| defer r.mu.Unlock() | ||
|
|
||
| r.dirty = true | ||
|
|
||
| r.filter = filter | ||
| } | ||
|
|
||
| func (r *syncedFilter) SetName(name string) { | ||
| r.mu.Lock() | ||
| defer r.mu.Unlock() | ||
|
|
||
| r.dirty = true | ||
|
|
||
| r.filter.Name = name | ||
| } | ||
|
|
||
| func (r *syncedFilter) AddAddress(address common.Address) { | ||
| r.mu.Lock() | ||
| defer r.mu.Unlock() | ||
|
|
||
| r.dirty = true | ||
|
|
||
| r.filter.Addresses = append(r.filter.Addresses, address) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like we should have some sort of check here to make sure the address isn't already in the list (or perhaps, use a set instead of a list?). I'm not sure how often we unregister and re-register the same filter, but if it's a lol then we'll keep appending more and more copies of the same address onto the list.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point, I noticed this is already handled by common and event readers (since they make precheck that address is bounded). So it won't keep appending copies at least in its current usage
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prior to this PR yes, but with the introduction of this PR it becomes possible. I'll comment above on the place where the check is removed.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That said, it doesn't pose any serious problem so if you want to leave it as-is I'm okay with that. |
||
| } | ||
|
|
||
| func (r *syncedFilter) RemoveAddress(address common.Address) { | ||
| r.mu.Lock() | ||
| defer r.mu.Unlock() | ||
|
|
||
| r.dirty = true | ||
|
|
||
| var addrIdx int | ||
| for idx, addr := range r.filter.Addresses { | ||
| if addr.Hex() == address.Hex() { | ||
|
|
@@ -107,6 +147,13 @@ func (r *syncedFilter) Count() int { | |
| return len(r.filter.Addresses) | ||
| } | ||
|
|
||
| func (r *syncedFilter) Dirty() bool { | ||
| r.mu.RLock() | ||
| defer r.mu.RUnlock() | ||
|
|
||
| return r.dirty | ||
| } | ||
|
|
||
| func (r *syncedFilter) HasEventSigs() bool { | ||
| r.mu.RLock() | ||
| defer r.mu.RUnlock() | ||
|
|
||
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.
Here is what I was referring to below. Previously, we were calling
cb.Unregisterwhich callsRemoveAddressbefore callingAddAddress, so it gets removed and then re-added--you can't add the same one twice. But now we skip theisBoundso it can be added multiple times. Right?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.
cb.Unregister() doesn't call RemoveAddress, we cant add address multiple times because of
if cb.bindingExists(binding) { continue }