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

fix: setupControllerConnection outstream end event listener #26141

Merged
merged 17 commits into from
Jul 29, 2024

Conversation

danjm
Copy link
Contributor

@danjm danjm commented Jul 25, 2024

Description

This PR addresses a problem which had the following surface level symptoms: when the UI is closed, the extension continues to send network requests to the provider.

Upon some investigation, we discovered that these requests were the result of polling initiated from the account tracker. And then upon further investigation, we discovered that the callback in the outstream 'end' listener in setupControllerConnection of metamask-controller.js was not being called when the UI was closed.

This problem was introduced with #24533. That PR updates the object-multiplex dependency to v2.0.0. The major change in that update is the update of the readable-stream dependency from a v2 version to a v3 version. With that update, we see new premature-close errors in the background. It seems that these errors are still present in v2, but they are handled differently, resulting in an 'error' event instead of an 'end' event. We still have not established a definitive understanding of why this is happening, and follow up investigation will be needed.

However, this PR still puts forward a fix that safely resolves the issue. The solution added here is to make use of the readableStream.finished function. The callback passed to this function will be called when the stream is ended. This function has the same behaviour as the outstream.on('end' listener had prior to the aforementioned PR.

Instead of fully replacing the existing listener, we have added the readableStream.finished call in addition to the existing listener. The reason for this is explained in a code comment:

The presence of both of the below handlers may be redundant. After upgrading metamask/object-multiples to v2.0.0, which included an upgrade of readable-streams from v2 to v3, we saw that the outStream.on('end' handler was almost never being called. This seems to related to how v3 handles errors vs how v2 handles errors; there are "premature close" errors in both cases, although in the case of v2 they don't prevent outStream.on('end' from being called. At the time that this comment was committed, it was known that we need to investigate and resolve the underlying error, however, for expediency, we are not addressing them at this time. Instead, we can observe that readableStream.finished preserves the same functionality as we had when we relied on readable-stream v2. Meanwhile, the outStream.on('end' handler was observed to have been called at least once. As we do not yet fully understand the conditions under which both of these are being called, we include both handlers at the risk of redundancy. Logic has been added to the handler to ensure that calling it more than once does not have any affect.

To achieve "Logic has been added to the handler to ensure that calling it more than once does not have any affect.", the PR adds a unique id to each stream passed to setupControllerConnection, and uses a Set to ensure the handler code only runs once per stream.

This PR then adds automated tests. The added unit tests are focused on validating both pre-existing and new behaviour of setupControllerChanged. The added e2e tests focus on the inititially mentioned surface level symptoms: it confirms that eth_call and eth_getBalance calls, the calls coming from the account-tracker initiated polling, are not continued after the UI is closed. This e2e test fails on current develop but passes on this branch.

MetaMask team members can see more details in this thread: https://consensys.slack.com/archives/CTQAGKY5V/p1721653870583869

Open in GitHub Codespaces

Related issues

Fixes: #26002

Manual testing steps

To observe the bug on develop:

  1. Install and onboard
  2. Open the service worker dev console and go to the network tab
  3. Observe eth_call and eth_getBalance requests to infura
  4. Close the UI, observe that the requests from step 3 continue

On this branch, in step 4, after closing the UI, those requests will not continue.

Screenshots/Recordings

Before

After

Pre-merge author checklist

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

danjm added 2 commits July 25, 2024 10:13
…ection in metamask-controller.js is called when it should be
@danjm danjm requested review from a team as code owners July 25, 2024 18:52
Copy link
Contributor

CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes.

@danjm danjm changed the title Fix setup controller connection outstream end Fix setupControllerConnection outstream end event listener Jul 25, 2024
@danjm danjm changed the title Fix setupControllerConnection outstream end event listener fix: setupControllerConnection outstream end event listener Jul 25, 2024
Copy link
Member

Choose a reason for hiding this comment

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

For a later PR: We should consider sorting this with prettier (prettier-plugin-sort-json can do it)

privacy-snapshot.json Outdated Show resolved Hide resolved
@legobeat

This comment was marked as resolved.

];
}

async function getAllInfuraJsonRpcRequests(
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks nice and like it could be useful elsewhere!

Copy link
Contributor

Choose a reason for hiding this comment

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

+1!

@legobeat legobeat requested a review from a team July 25, 2024 22:11
privacy-snapshot.json Outdated Show resolved Hide resolved
legobeat
legobeat previously approved these changes Jul 25, 2024
@legobeat legobeat requested a review from a team July 25, 2024 23:42
mockedEndpoint,
);

await driver.openNewURL('chrome://extensions');
Copy link
Contributor

@seaona seaona Jul 26, 2024

Choose a reason for hiding this comment

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

It looks like this makes the firefox test fail. Could we selectively go to:

Suggested change
await driver.openNewURL('chrome://extensions');
if (process.env.SELENIUM_BROWSER === 'chrome') {
await driver.openNewURL('chrome://extensions');
} else if (process.env.SELENIUM_BROWSER === 'firefox') {
await driver.openNewURL('about:debugging#/runtime/this-firefox');
}

or something similar? This solves the issue in my end

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 fixed it by replacing the url with about:blank a315444

Copy link
Contributor

Choose a reason for hiding this comment

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

oh nice 😍 ty!!

}

describe('Account Tracker API Usage', function () {
it('should not make eth_call or eth_getBalance requests before the UI is opened and should make those requests after the UI is opened', async function () {
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that the account tracker is also responsible from initiating eth_getBlockByNumber calls. Should we also include them here?

account-tracker-getblockbynumber.mp4

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good suggestion, added here ac50f66

Copy link
Contributor

Choose a reason for hiding this comment

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

thank you Dan, great refactor! Could it be that we are missing it here and in the test description (not a blocker though)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, in that case there is an eth_getBlockbyNumber call before the UI opens, for other reasons. That should be addressed separately.

I will create a ticket for that and add a code comment and update the test description

Copy link
Contributor

Choose a reason for hiding this comment

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

oh gotcha, thank you Dan!

@metamaskbot
Copy link
Collaborator

Builds ready [a315444]
Page Load Metrics (412 ± 325 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint772281173416
domContentLoaded118033199
load431894412677325
domInteractive118033199
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 96 Bytes (0.00%)
  • ui: 0 Bytes (0.00%)
  • common: 0 Bytes (0.00%)

Copy link

codecov bot commented Jul 26, 2024

Codecov Report

Attention: Patch coverage is 80.00000% with 3 lines in your changes missing coverage. Please review.

Project coverage is 69.95%. Comparing base (b27dd2b) to head (27df50c).
Report is 16 commits behind head on develop.

Files Patch % Lines
app/scripts/metamask-controller.js 80.00% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #26141      +/-   ##
===========================================
+ Coverage    69.94%   69.95%   +0.01%     
===========================================
  Files         1409     1409              
  Lines        49794    49799       +5     
  Branches     13773    13771       -2     
===========================================
+ Hits         34826    34832       +6     
+ Misses       14968    14967       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@metamaskbot
Copy link
Collaborator

Builds ready [98a10a1]
Page Load Metrics (63 ± 8 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint6413090157
domContentLoaded86125126
load3911463178
domInteractive86125126
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 96 Bytes (0.00%)
  • ui: 0 Bytes (0.00%)
  • common: 0 Bytes (0.00%)

@chloeYue
Copy link
Contributor

QA test OK !

);

await driver.openNewURL('about:blank');
await driver.delay(20000);
Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we need this to be 20000 ms long. I have added a code comment to explain 27df50c

@danjm danjm force-pushed the fix-setupControllerConnection-outstream-end branch from 7a00c1f to 27df50c Compare July 29, 2024 14:56
Copy link

Copy link
Contributor

@seaona seaona left a comment

Choose a reason for hiding this comment

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

tests look good, though might be good to have a dev approval too, for the controllers change

@metamaskbot
Copy link
Collaborator

Builds ready [27df50c]
Page Load Metrics (218 ± 212 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint73164982210
domContentLoaded96825167
load421570218441212
domInteractive96825167
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 96 Bytes (0.00%)
  • ui: 0 Bytes (0.00%)
  • common: 0 Bytes (0.00%)

@DDDDDanica DDDDDanica merged commit 8f6c83e into develop Jul 29, 2024
76 checks passed
@DDDDDanica DDDDDanica deleted the fix-setupControllerConnection-outstream-end branch July 29, 2024 15:35
@github-actions github-actions bot locked and limited conversation to collaborators Jul 29, 2024
@metamaskbot metamaskbot added release-12.4.0 Issue or pull request that will be included in release 12.4.0 release-12.0.0 Issue or pull request that will be included in release 12.0.0 and removed release-12.4.0 Issue or pull request that will be included in release 12.4.0 labels Jul 29, 2024
@metamaskbot
Copy link
Collaborator

Missing release label release-12.0.0 on PR. Adding release label release-12.0.0 on PR and removing other release labels(release-12.4.0), as PR was cherry-picked in branch 12.0.0.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
QA Passed release-12.0.0 Issue or pull request that will be included in release 12.0.0 team-extension-platform
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Outstream on 'end' callback, in setupControllerConnection of MM controller, is not called on UI close
7 participants