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

refactor: use withKeyring method #25435

Merged
merged 24 commits into from
Jul 18, 2024
Merged

refactor: use withKeyring method #25435

merged 24 commits into from
Jul 18, 2024

Conversation

mikesposito
Copy link
Member

@mikesposito mikesposito commented Jun 20, 2024

Description

With @metamask/keyring-controller v16 a new method is available which simplify safe direct keyring interactions which are not available through KeyringController.

Through withKeyring it's possible to lock KeyringController's main mutex and select a specific keyring to interact with while KeyringController will be unusable concurrently. withKeyring also takes care of persisting keyrings and updating the controller state at the end of the operation, which makes it possible to use it in substitution of getKeyringsByType and persistAllKeyrings.

Currently, most of the direct keyring interactions in the extension are made for hardware devices and snaps.

This PR is supposed to be merged after #25033

Open in GitHub Codespaces

Related issues

Fixes: #24276

Manual testing steps

Affected workflows may include:

  • Lock
  • Unlock
  • Add account
  • Remove account
  • Connect hardware wallet
  • All hardware wallet interactions

Screenshots/Recordings

N/A

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.

@mikesposito mikesposito changed the base branch from develop to bump-keyring-controller June 20, 2024 10:00
Comment on lines 3967 to 4036
if (this.isKeyringAvailable(LedgerKeyring.type)) {
await this.withKeyringForDevice(
{ name: HardwareDeviceNames.ledger },
async (keyring) => this.setLedgerTransportPreference(keyring),
);
}
Copy link
Member Author

Choose a reason for hiding this comment

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

I think this could also be completely removed, since there shouldn't be any Ledger keyring right after creating (or restoring) the vault.

The this.isKeyringAvailable(LedgerKeyring.type) condition helps not creating the keyring in case it was not present in the first place

Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately we creates a new Ledger keyring for each user irrespective of whether they are Ledger users. This does seem bad, but I am unsure what the consequences would be for stopping this practice. The comment does suggest that setting this preference as soon as possible was critical, but I don't recall why.

Could we consider continuing the questionable practice of creating a Ledger keyring for all users (as we currently do), and stop doing this in a separate PR? So that we can reduce the changes of complications from this refactor.

Copy link
Member

Choose a reason for hiding this comment

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

We might also want to drop the await here, given the comment above

Copy link
Member Author

@mikesposito mikesposito Jul 16, 2024

Choose a reason for hiding this comment

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

Good point, we can address this in a separate PR. I removed isKeyringAvailable from the two occurrences of this practice for Ledger (and the isKeyringAvailable function itself, since it is now unused), and left the promise dangling.

Perhaps a good place to set the transport preference would be in withKeyringForDevice since it is used for all hardware keyring interactions

Comment on lines 4650 to 4644
const keyring = await this.keyringController.getKeyringForAccount(address);
// Remove account from the keyring
await this.keyringController.removeAccount(address);
const updatedKeyringAccounts = keyring ? await keyring.getAccounts() : {};
if (updatedKeyringAccounts?.length === 0) {
keyring.destroy?.();
}
Copy link
Member Author

Choose a reason for hiding this comment

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

KeyringController calls keyring.destroy() automatically when the keyring is left with no accounts

@mikesposito mikesposito marked this pull request as ready for review June 24, 2024 14:31
@mikesposito mikesposito requested a review from a team as a code owner June 24, 2024 14:31
const keyring = await this.getKeyringForDevice(deviceName);
return this.withKeyringForDevice({ name: deviceName }, async (keyring) => {
for (const address of keyring.accounts) {
await this._onAccountRemoved(address);
Copy link
Member Author

Choose a reason for hiding this comment

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

By extracting side effects from removeAccount we can execute side effects here without ending up in a deadlock.

The account is removed from KeyringController anyway when calling keyring.forgetDevice()

Copy link
Member

Choose a reason for hiding this comment

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

Hmm. These side effects are a little strange (permissions should be automatically removed when an account is deleted, for instance). But I see that this is similar to how it already works today. Seems like a reasonable solution to me

Copy link
Member Author

Choose a reason for hiding this comment

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

I agree. Also, ideally, side effects should be executed after the account removal instead of before since an error could occur (that now would also trigger a rollback)

Base automatically changed from bump-keyring-controller to develop June 25, 2024 08:49
@ccharly ccharly requested review from a team as code owners June 25, 2024 08:49
@Gudahtt Gudahtt marked this pull request as draft June 25, 2024 20:24
@Gudahtt
Copy link
Member

Gudahtt commented Jun 25, 2024

I have temporarily moved this back into draft to resolve conflicts

@Gudahtt Gudahtt changed the base branch from develop to bump-keyring-controller June 25, 2024 20:26
@Gudahtt Gudahtt marked this pull request as ready for review June 25, 2024 20:34
@mikesposito mikesposito requested a review from a team July 9, 2024 09:27
@metamaskbot
Copy link
Collaborator

Builds ready [2baee85]
Page Load Metrics (251 ± 253 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint761561082311
domContentLoaded106727178
load451957251527253
domInteractive106727178
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 273 Bytes (0.01%)
  • ui: 0 Bytes (0.00%)
  • common: 0 Bytes (0.00%)

Copy link

codecov bot commented Jul 12, 2024

Codecov Report

Attention: Patch coverage is 64.00000% with 27 lines in your changes missing coverage. Please review.

Project coverage is 69.75%. Comparing base (d243eed) to head (b93dd74).
Report is 9 commits behind head on develop.

Files Patch % Lines
app/scripts/metamask-controller.js 64.00% 27 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #25435      +/-   ##
===========================================
- Coverage    69.75%   69.75%   -0.00%     
===========================================
  Files         1400     1400              
  Lines        49419    49421       +2     
  Branches     13668    13664       -4     
===========================================
  Hits         34470    34470              
- Misses       14949    14951       +2     

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

Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

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

Looks great! Just one pending issue about the unlockedAddress casing, and one nit.

Gudahtt
Gudahtt previously approved these changes Jul 16, 2024
Copy link
Member

@Gudahtt Gudahtt left a comment

Choose a reason for hiding this comment

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

LGTM!

@mcmire mcmire requested a review from a team July 16, 2024 15:19
@Gudahtt Gudahtt requested a review from a team July 17, 2024 12:51
Copy link

sonarcloud bot commented Jul 18, 2024

Copy link
Contributor

@cryptodev-2s cryptodev-2s left a comment

Choose a reason for hiding this comment

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

LGTM!

@metamaskbot
Copy link
Collaborator

Builds ready [b93dd74]
Page Load Metrics (106 ± 31 ms)
PlatformPageMetricMin (ms)Max (ms)Average (ms)StandardDeviation (ms)MarginOfError (ms)
ChromeHomefirstPaint804821488842
domContentLoaded10257485125
load443561066531
domInteractive10257485125
Bundle size diffs [🚨 Warning! Bundle size has increased!]
  • background: 225 Bytes (0.01%)
  • ui: 0 Bytes (0.00%)
  • common: 0 Bytes (0.00%)

@mikesposito mikesposito merged commit def6b15 into develop Jul 18, 2024
79 checks passed
@mikesposito mikesposito deleted the use-with-keyring branch July 18, 2024 20:01
@github-actions github-actions bot locked and limited conversation to collaborators Jul 18, 2024
@metamaskbot metamaskbot added the release-12.3.0 Issue or pull request that will be included in release 12.3.0 label Jul 18, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
release-12.3.0 Issue or pull request that will be included in release 12.3.0 team-wallet-framework
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[keyring-controller] Mitigate run conditions with >^16.x
4 participants