Skip to content
This repository was archived by the owner on Oct 16, 2025. It is now read-only.

fix: internal listeners infinite retry loop#284

Merged
mikesposito merged 25 commits intomainfrom
fix/internal-listeners
Dec 3, 2024
Merged

fix: internal listeners infinite retry loop#284
mikesposito merged 25 commits intomainfrom
fix/internal-listeners

Conversation

@mikesposito
Copy link
Copy Markdown
Member

@mikesposito mikesposito commented Nov 13, 2024

Our block tracker implementation relies on the presence of listeners to establish whether the polling should be continued or stopped.

However, an internal listener is being added in the getLatestBlock method, which will count as the other external listeners and will prevent the instance from stopping fetching new blocks. This creates an infinite loop in case the network is unreachable, because of the retry mechanism.

This PR aims to fix this behavior by keeping track of internal listeners' references in order to exclude them from the listener's count

Fixes #163

@mikesposito mikesposito requested a review from a team as a code owner November 13, 2024 13:15
@mikesposito
Copy link
Copy Markdown
Member Author

It would be good to cover this with tests

Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.ts
Comment thread src/PollingBlockTracker.ts Outdated
@mikesposito mikesposito requested a review from Gudahtt November 20, 2024 14:23
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread CHANGELOG.md Outdated
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.ts Outdated
Comment thread src/PollingBlockTracker.test.ts Outdated
* Suggestion to simplify prevention of dangling Promise on destroy

The `fix/internal-listeners` branch has a number of changes intended to
ensure we don't have a dangling unresolved Promise when the block
tracker is destroyed. This solution involved adding an additional
listener to capture errors, and it involved not removing internal
listeners when `destroy` is called. This required changes to some
logging in `_updateAndQueue` as well.

This commit is an alternative solution that avoids the use of internal
listeners, thus avoiding much of the complexity in the previous
solution. Instead an internal deferred Promise is used. This also
might be slightly more efficient when `getLatestBlock` is called
repeatedly, as we can reuse the same listener rather than creating a
new one each time.

* Unset pending latest block after it has resolved
Comment thread src/PollingBlockTracker.ts Outdated
this._newPotentialLatest(blockNumber);
} catch (e) {
this.emit('error', e);
this.#rejectPendingLatestBlock(e);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

If the request fails at this point, the pending promise must be rejected as there will be no retry

this._subscriptionId = null;
} catch (e) {
this.emit('error', e);
this.#rejectPendingLatestBlock(e);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

If the request fails at this point, the pending promise must be rejected as there will be no retry

Copy link
Copy Markdown
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

Aside from the tests which we've been discussing, this looks good!

Comment thread src/PollingBlockTracker.test.ts Outdated
Comment thread src/SubscribeBlockTracker.test.ts Outdated
Comment thread src/PollingBlockTracker.test.ts Outdated
Copy link
Copy Markdown
Contributor

@mcmire mcmire left a comment

Choose a reason for hiding this comment

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

LGTM.

@mikesposito mikesposito merged commit b41e033 into main Dec 3, 2024
@mikesposito mikesposito deleted the fix/internal-listeners branch December 3, 2024 18:26
mikesposito added a commit to MetaMask/core that referenced this pull request Dec 5, 2024
## Explanation

This PR bumps `@metamask/eth-block-tracker` to `^11.0.3` across core
packages.

The only change that is being pulled is:
```
- Avoid risk of infinite retry loops when fetching new blocks ([#284](MetaMask/eth-block-tracker#284))
  - When the provider returns an error and `PollingBlockTracker` or `SubscribeBlockTracker` is destroyed, the promise returned by the `getLatestBlock` method will be rejected.
  ```

Related to: MetaMask/metamask-extension#17040
## References

<!--
Are there any issues that this pull request is tied to?
Are there other links that reviewers should consult to understand these changes better?
Are there client or consumer pull requests to adopt any breaking changes?

For example:

* Fixes #12345
* Related to #67890
-->

## Changelog

<!--
If you're making any consumer-facing changes, list those changes here as if you were updating a changelog, using the template below as a guide.

(CATEGORY is one of BREAKING, ADDED, CHANGED, DEPRECATED, REMOVED, or FIXED. For security-related issues, follow the Security Advisory process.)

Please take care to name the exact pieces of the API you've added or changed (e.g. types, interfaces, functions, or methods).

If there are any breaking changes, make sure to offer a solution for consumers to follow once they upgrade to the changes.

Finally, if you're only making changes to development scripts or tests, you may replace the template below with "None".
-->

### `@metamask/network-controller`

- **CHANGED**: Bump `@metamask/eth-block-tracker` from `^11.0.2` to `^11.0.3`

## Checklist

- [ ] I've updated the test suite for new or updated code as appropriate
- [ ] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
- [ ] I've highlighted breaking changes using the "BREAKING" category above as appropriate
- [ ] I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Endless failed request polling loop

3 participants