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

Support keyring metadata in KeyringController #5112

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open

Conversation

PatrykLucka
Copy link

@PatrykLucka PatrykLucka commented Jan 8, 2025

Explanation

Currently, we assume that the only HD Keyring is the Primary Keyring. Most methods related to adding accounts or displaying the SRP assume that it refers to the first keyring, which is the Primary Keyring. To enable having more than one SRP, and consequently more than one HD Keyring, this PR adds an array called keyringsMetadata, which contains an id that can be used to identify all keyrings and a proper place to keep other data we might want to add to each keyring such as name.

keyringsMetadata is a separate in order to minimize changes that we need to make to keyrings and the way we process them. We also can keep this data outside of the vault, as it's not storing any sensitive data.

References

Related to ADR 0002-keyring-id-and-name.md
Blocks Extension PR

Changelog

@metamask/keyring-controller

  • ADDED: { id: string } selector to withKeyring function
  • ADDED: optional keyringId param to addNewAccount function
  • ADDED: optional keyringId param to exportSeedPhrase function
  • ADDED: optional keyringId param to getAccounts function
  • ADDED: optional keyringId param to verifySeedPhrase function
  • ADDED: private #getKeyringById helper function
  • ADDED: optional keyringId param to #verifySeedPhrase function
  • ADDED: optional metadata param to #newKeyring function
  • ADDED: optional metadata param to #newKeyring function

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

@PatrykLucka PatrykLucka self-assigned this Jan 8, 2025
@PatrykLucka
Copy link
Author

@metamaskbot publish-preview

Copy link
Contributor

github-actions bot commented Jan 8, 2025

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "20.0.2-preview-e96ca40c",
  "@metamask-previews/address-book-controller": "6.0.2-preview-e96ca40c",
  "@metamask-previews/announcement-controller": "7.0.2-preview-e96ca40c",
  "@metamask-previews/approval-controller": "7.1.1-preview-e96ca40c",
  "@metamask-previews/assets-controllers": "45.1.2-preview-e96ca40c",
  "@metamask-previews/base-controller": "7.0.2-preview-e96ca40c",
  "@metamask-previews/build-utils": "3.0.2-preview-e96ca40c",
  "@metamask-previews/chain-controller": "0.2.2-preview-e96ca40c",
  "@metamask-previews/composable-controller": "10.0.0-preview-e96ca40c",
  "@metamask-previews/controller-utils": "11.4.4-preview-e96ca40c",
  "@metamask-previews/ens-controller": "15.0.1-preview-e96ca40c",
  "@metamask-previews/eth-json-rpc-provider": "4.1.6-preview-e96ca40c",
  "@metamask-previews/gas-fee-controller": "22.0.2-preview-e96ca40c",
  "@metamask-previews/json-rpc-engine": "10.0.1-preview-e96ca40c",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.5-preview-e96ca40c",
  "@metamask-previews/keyring-controller": "19.0.2-preview-e96ca40c",
  "@metamask-previews/logging-controller": "6.0.3-preview-e96ca40c",
  "@metamask-previews/message-manager": "11.0.3-preview-e96ca40c",
  "@metamask-previews/multichain": "1.1.2-preview-e96ca40c",
  "@metamask-previews/name-controller": "8.0.2-preview-e96ca40c",
  "@metamask-previews/network-controller": "22.1.1-preview-e96ca40c",
  "@metamask-previews/notification-services-controller": "0.15.0-preview-e96ca40c",
  "@metamask-previews/permission-controller": "11.0.4-preview-e96ca40c",
  "@metamask-previews/permission-log-controller": "3.0.2-preview-e96ca40c",
  "@metamask-previews/phishing-controller": "12.3.1-preview-e96ca40c",
  "@metamask-previews/polling-controller": "12.0.2-preview-e96ca40c",
  "@metamask-previews/preferences-controller": "15.0.1-preview-e96ca40c",
  "@metamask-previews/profile-sync-controller": "3.1.1-preview-e96ca40c",
  "@metamask-previews/queued-request-controller": "8.0.2-preview-e96ca40c",
  "@metamask-previews/rate-limit-controller": "6.0.2-preview-e96ca40c",
  "@metamask-previews/remote-feature-flag-controller": "1.2.0-preview-e96ca40c",
  "@metamask-previews/selected-network-controller": "20.0.2-preview-e96ca40c",
  "@metamask-previews/signature-controller": "23.1.0-preview-e96ca40c",
  "@metamask-previews/transaction-controller": "42.0.0-preview-e96ca40c",
  "@metamask-previews/user-operation-controller": "21.0.0-preview-e96ca40c"
}

Copy link

socket-security bot commented Jan 13, 2025

New dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/[email protected] None +1 75.3 kB perrymitchell

View full report↗︎

@PatrykLucka
Copy link
Author

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "20.0.2-preview-407f96d",
  "@metamask-previews/address-book-controller": "6.0.2-preview-407f96d",
  "@metamask-previews/announcement-controller": "7.0.2-preview-407f96d",
  "@metamask-previews/approval-controller": "7.1.1-preview-407f96d",
  "@metamask-previews/assets-controllers": "45.1.2-preview-407f96d",
  "@metamask-previews/base-controller": "7.1.0-preview-407f96d",
  "@metamask-previews/build-utils": "3.0.2-preview-407f96d",
  "@metamask-previews/chain-controller": "0.2.2-preview-407f96d",
  "@metamask-previews/composable-controller": "10.0.0-preview-407f96d",
  "@metamask-previews/controller-utils": "11.4.4-preview-407f96d",
  "@metamask-previews/ens-controller": "15.0.1-preview-407f96d",
  "@metamask-previews/eth-json-rpc-provider": "4.1.7-preview-407f96d",
  "@metamask-previews/gas-fee-controller": "22.0.2-preview-407f96d",
  "@metamask-previews/json-rpc-engine": "10.0.2-preview-407f96d",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.6-preview-407f96d",
  "@metamask-previews/keyring-controller": "19.0.2-preview-407f96d",
  "@metamask-previews/logging-controller": "6.0.3-preview-407f96d",
  "@metamask-previews/message-manager": "11.0.3-preview-407f96d",
  "@metamask-previews/multichain": "2.0.0-preview-407f96d",
  "@metamask-previews/name-controller": "8.0.2-preview-407f96d",
  "@metamask-previews/network-controller": "22.1.1-preview-407f96d",
  "@metamask-previews/notification-services-controller": "0.15.0-preview-407f96d",
  "@metamask-previews/permission-controller": "11.0.4-preview-407f96d",
  "@metamask-previews/permission-log-controller": "3.0.2-preview-407f96d",
  "@metamask-previews/phishing-controller": "12.3.1-preview-407f96d",
  "@metamask-previews/polling-controller": "12.0.2-preview-407f96d",
  "@metamask-previews/preferences-controller": "15.0.1-preview-407f96d",
  "@metamask-previews/profile-sync-controller": "3.3.0-preview-407f96d",
  "@metamask-previews/queued-request-controller": "8.0.2-preview-407f96d",
  "@metamask-previews/rate-limit-controller": "6.0.2-preview-407f96d",
  "@metamask-previews/remote-feature-flag-controller": "1.3.0-preview-407f96d",
  "@metamask-previews/selected-network-controller": "20.0.2-preview-407f96d",
  "@metamask-previews/signature-controller": "23.2.0-preview-407f96d",
  "@metamask-previews/transaction-controller": "42.1.0-preview-407f96d",
  "@metamask-previews/user-operation-controller": "21.0.0-preview-407f96d"
}

@PatrykLucka PatrykLucka force-pushed the multi-srp-mvp branch 2 times, most recently from bc69ea1 to b9ca305 Compare January 17, 2025 10:41
PatrykLucka and others added 7 commits January 17, 2025 11:44
<!--
Thanks for your contribution! Take a moment to answer these questions so
that reviewers have the information they need to properly understand
your changes:

* What is the current state of things and why does it need to change?
* What is the solution your changes offer and how does it work?
* Are there any changes whose purpose might not obvious to those
unfamiliar with the domain?
* If your primary goal was to update one package but you found you had
to update another one along the way, why did you do so?
* If you had to upgrade a dependency, why did you do so?
-->
The `KeyringController.verifySeedPhrase` method was not included in the
mutable methods that lock the controller mutex because it doesn't change
the state. Though, if another operation gets somehow overlapped (e.g. a
consumer calls `addNewAccount`), the call to `verifySeedPhrase` can
potentially fail.

To fix this, this PR is moving verifySeedPhrase behind
KeyringController's mutex. Since `addNewAccount` internally calls
`verifySeedPhrase`, and having a lock on both would create a deadlock,
the `verifySeedPhrase` implementation has been moved to an internal
method.

<!--
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
-->

<!--
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".
-->

- **FIXED**:  `verifySeedPhrase` is now mutually exclusive

- [ ] 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
@PatrykLucka
Copy link
Author

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "21.0.1-preview-83c8a21",
  "@metamask-previews/address-book-controller": "6.0.2-preview-83c8a21",
  "@metamask-previews/announcement-controller": "7.0.2-preview-83c8a21",
  "@metamask-previews/approval-controller": "7.1.2-preview-83c8a21",
  "@metamask-previews/assets-controllers": "46.0.0-preview-83c8a21",
  "@metamask-previews/base-controller": "7.1.1-preview-83c8a21",
  "@metamask-previews/build-utils": "3.0.2-preview-83c8a21",
  "@metamask-previews/composable-controller": "10.0.0-preview-83c8a21",
  "@metamask-previews/controller-utils": "11.4.5-preview-83c8a21",
  "@metamask-previews/ens-controller": "15.0.1-preview-83c8a21",
  "@metamask-previews/eth-json-rpc-provider": "4.1.7-preview-83c8a21",
  "@metamask-previews/gas-fee-controller": "22.0.2-preview-83c8a21",
  "@metamask-previews/json-rpc-engine": "10.0.2-preview-83c8a21",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.6-preview-83c8a21",
  "@metamask-previews/keyring-controller": "19.0.3-preview-83c8a21",
  "@metamask-previews/logging-controller": "6.0.3-preview-83c8a21",
  "@metamask-previews/message-manager": "12.0.0-preview-83c8a21",
  "@metamask-previews/multichain": "2.0.0-preview-83c8a21",
  "@metamask-previews/name-controller": "8.0.2-preview-83c8a21",
  "@metamask-previews/network-controller": "22.1.1-preview-83c8a21",
  "@metamask-previews/notification-services-controller": "0.16.0-preview-83c8a21",
  "@metamask-previews/permission-controller": "11.0.5-preview-83c8a21",
  "@metamask-previews/permission-log-controller": "3.0.2-preview-83c8a21",
  "@metamask-previews/phishing-controller": "12.3.1-preview-83c8a21",
  "@metamask-previews/polling-controller": "12.0.2-preview-83c8a21",
  "@metamask-previews/preferences-controller": "15.0.1-preview-83c8a21",
  "@metamask-previews/profile-sync-controller": "4.1.0-preview-83c8a21",
  "@metamask-previews/queued-request-controller": "8.0.2-preview-83c8a21",
  "@metamask-previews/rate-limit-controller": "6.0.2-preview-83c8a21",
  "@metamask-previews/remote-feature-flag-controller": "1.3.0-preview-83c8a21",
  "@metamask-previews/selected-network-controller": "20.0.2-preview-83c8a21",
  "@metamask-previews/signature-controller": "23.2.0-preview-83c8a21",
  "@metamask-previews/transaction-controller": "43.0.0-preview-83c8a21",
  "@metamask-previews/user-operation-controller": "22.0.0-preview-83c8a21"
}

@PatrykLucka PatrykLucka marked this pull request as ready for review January 18, 2025 09:26
@PatrykLucka PatrykLucka requested review from a team as code owners January 18, 2025 09:26
@shane-t shane-t changed the title Multi srp mvp Support keyring metadata in KeyringController Jan 21, 2025
@@ -1028,7 +1082,7 @@ export class KeyringController extends BaseController<
}
const newKeyring = (await this.#newKeyring(KeyringTypes.simple, [
privateKey,
])) as EthKeyring<Json>;
], { id: ulid(), name: '' })) as EthKeyring<Json>;
Copy link
Member

@mikesposito mikesposito Jan 21, 2025

Choose a reason for hiding this comment

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

It looks like we are always passsing the same object to this.#newKeyring:

{
  id: ulid(),
  name: '',
}

Have you considered moving this directly to #newKeyring, removing the need for an additional method argument?

Comment on lines 1413 to 1416
async verifySeedPhrase(keyringId?: string): Promise<Uint8Array> {
return this.#withControllerLock(async () =>
this.#verifySeedPhrase(keyringId),
);
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, this may not work as intended because this method works with the HD Keyrings only, and all other keyring types will throw errors that are difficult to analyse as they would not be that specific

Copy link
Contributor

Choose a reason for hiding this comment

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

We can add a guard to check if the keyring instance is a hd keyring and throw if its any other keyrings.

Comment on lines 686 to 689
async addNewAccount(
accountCount?: number,
keyringId?: string,
): Promise<string> {
Copy link
Member

Choose a reason for hiding this comment

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

Similarly to my comment on verifySeedPhrase, this seems too broad and would break with any non-HD keyring. I believe that the client could add new accounts using withKeyring alone, which makes this change unnecessary

Comment on lines 902 to 912
async getAccounts(keyringId?: string): Promise<string[]> {
if (keyringId) {
const keyringIndex = this.state.keyringsMetadata.findIndex(
(keyring) => keyring.id === keyringId,
);
const keyring = this.state.keyrings[keyringIndex];
if (!keyring) {
throw new Error('Keyring not found');
}
return keyring.accounts;
}
Copy link
Member

Choose a reason for hiding this comment

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

Do you think this is really needed? The client can access all accounts divided by keyring through KeyringController.state and withKeyring

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we can remove this

Comment on lines 2029 to 2035

if (this.state.keyringsMetadata.length > this.#keyrings.length) {
this.update((state) => {
// remove metadata from the end of the array to have the same length as the keyrings array
state.keyringsMetadata = state.keyringsMetadata.slice(0, -1 * (state.keyringsMetadata.length - this.#keyrings.length));
})
}
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, this feels like an unexpected situation where I'm not sure it would be safe to 'just delete the last ones'. Maybe we should just throw an error here?

Comment on lines 2204 to 2206
if (updatedKeyrings.length < state.keyringsMetadata.length) {
state.keyringsMetadata = state.keyringsMetadata.slice(0, -1 * (state.keyringsMetadata.length - updatedKeyrings.length));
}
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, this feels like an unexpected situation where I'm not sure it would be safe to 'just delete the last ones'. Maybe we should just throw an error here?

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm but if we throw an error here, the user would not be able to load the extension.

Copy link
Member

Choose a reason for hiding this comment

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

That's a good point, but I'm also thinking that when a consumer initialises this KeyringController version coming from an older version we'll have an empty keyringMetadata array, which would create several issues in how these are matched with the related keyring

Perhaps we should have checks in place for both scenarios, and a strategy to realign them for when it happens.

The issue that I see is that if other controllers keep track of these IDs (which could be since keyringMetadata is publicly accessible), they could end up keeping track of unreferenced IDs if we remove / change them

Copy link
Member

Choose a reason for hiding this comment

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

Also, what happens if a keyring from the middle of the array is removed?

Copy link
Contributor

Choose a reason for hiding this comment

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

For the clients, there will be a migration to generate the keyringMetadata for all keyrings.

I've added checks to clear the metadata of a keyring if its removed.

We also probably need a new event to notify controllers of metadata changes, like KeyringController:keyringMetadataChanged.

Copy link
Member

Choose a reason for hiding this comment

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

For the clients, there will be a migration to generate the keyringMetadata for all keyrings.

If you are referring to a state migration, that would be run before unlocking the wallet so keyrings won't be readable at that point

Copy link
Member

@mikesposito mikesposito Jan 22, 2025

Choose a reason for hiding this comment

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

The thing i'm not sure how to handle is, if there is a mismatch between the number of keyrings and keyringsMetadata. I don't think there is a reliable way to match the id to the keyring instance, since we are currently only using the index.

Yeah, this is a pain point of this solution along with this other one. I advocated on keeping metadata out of the vault to avoid changing its shape (which is just an array of serialized keyrings at the moment), but perhaps saving metadata into the vault would help with these two issues - something to consider at least

Copy link
Member

Choose a reason for hiding this comment

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

For the clients, there will be a migration to generate the keyringMetadata for all keyrings.

About this, I don't think there is a way to get a list of available keyrings or to manipulate the keyrings array before the vault is injected into KeyringController via constructor and submitPassword is called with the password typed by the user. So KeyringController will have to deal with the possibility of receiving keyrings with no ID, even just to support older states

Copy link
Contributor

Choose a reason for hiding this comment

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

For the clients, there will be a migration to generate the keyringMetadata for all keyrings.

About this, I don't think there is a way to get a list of available keyrings or to manipulate the keyrings array before the vault is injected into KeyringController via constructor and submitPassword is called with the password typed by the user. So KeyringController will have to deal with the possibility of receiving keyrings with no ID, even just to support older states

I used the number of keyring types thats available in the accounts controller to determine the number of KeyringMetadata to be created. There should only be one unique instances of each keyring because the multi srp feature isn't live. But youre right, if we want to use KeyringController.state.keyrings it would have to be after submitPassword is called. I think there is a need for this type of migration tool.

Copy link
Member

Choose a reason for hiding this comment

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

I used the number of keyring types thats available in the accounts controller to determine the number of KeyringMetadata to be created.

That would indeed work but not if the user has multiple imported accounts, since each of them will have its own SimpleKeyring instance

Comment on lines 1820 to 1823
const index = this.state.keyringsMetadata.findIndex(
(metadata) => metadata.id === keyringId,
);
return this.#keyrings[index] as EthKeyring<Json>;
Copy link
Member

Choose a reason for hiding this comment

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

In the case the ID doesn't find a match, index will be set to -1 and undefined will return instead of a Keyring. Perhaps we should either add undefined as possible return type, or check for keyring existence and throw an error in case it doesn't

Copy link
Contributor

Choose a reason for hiding this comment

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

Adding undefined as a possible return makes sense.

Copy link
Member

Choose a reason for hiding this comment

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

We should add a test case for when a keyring is removed (e.g. when all accounts from a keyring are removed)

Copy link

@mirceanis mirceanis left a comment

Choose a reason for hiding this comment

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

Let's make sure the keyring metadata also bubbles up to the AccountsController events.
I believe this block would need an update for that to happen.

Also, do we expect 1 keyring ID === 1 SRP ?
or would we ever have multiple keyrings derived from 1 SRP?

Comment on lines 679 to 683
* Adds a new account to the default (first) HD seed phrase keyring.
*
* @param accountCount - Number of accounts before adding a new one, used to
* @param keyringId - The id of the keyring to add the account to.
* make the method idempotent.

Choose a reason for hiding this comment

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

Suggested change
* Adds a new account to the default (first) HD seed phrase keyring.
*
* @param accountCount - Number of accounts before adding a new one, used to
* @param keyringId - The id of the keyring to add the account to.
* make the method idempotent.
* Adds a new account to the specified keyring
* or to the default (first) HD seed phrase keyring if none is specified.
*
* @param accountCount - Number of accounts before adding a new one, used to
* make the method idempotent.
* @param keyringId - The id of the keyring to add the account to.

@montelaidev
Copy link
Contributor

@metamaskbot publish-preview

@montelaidev
Copy link
Contributor

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/accounts-controller": "21.0.1-preview-183f0b5a",
  "@metamask-previews/address-book-controller": "6.0.2-preview-183f0b5a",
  "@metamask-previews/announcement-controller": "7.0.2-preview-183f0b5a",
  "@metamask-previews/approval-controller": "7.1.2-preview-183f0b5a",
  "@metamask-previews/assets-controllers": "46.0.0-preview-183f0b5a",
  "@metamask-previews/base-controller": "7.1.1-preview-183f0b5a",
  "@metamask-previews/build-utils": "3.0.2-preview-183f0b5a",
  "@metamask-previews/composable-controller": "10.0.0-preview-183f0b5a",
  "@metamask-previews/controller-utils": "11.4.5-preview-183f0b5a",
  "@metamask-previews/ens-controller": "15.0.1-preview-183f0b5a",
  "@metamask-previews/eth-json-rpc-provider": "4.1.7-preview-183f0b5a",
  "@metamask-previews/gas-fee-controller": "22.0.2-preview-183f0b5a",
  "@metamask-previews/json-rpc-engine": "10.0.2-preview-183f0b5a",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.6-preview-183f0b5a",
  "@metamask-previews/keyring-controller": "19.0.3-preview-183f0b5a",
  "@metamask-previews/logging-controller": "6.0.3-preview-183f0b5a",
  "@metamask-previews/message-manager": "12.0.0-preview-183f0b5a",
  "@metamask-previews/multichain": "2.0.0-preview-183f0b5a",
  "@metamask-previews/name-controller": "8.0.2-preview-183f0b5a",
  "@metamask-previews/network-controller": "22.1.1-preview-183f0b5a",
  "@metamask-previews/notification-services-controller": "0.16.0-preview-183f0b5a",
  "@metamask-previews/permission-controller": "11.0.5-preview-183f0b5a",
  "@metamask-previews/permission-log-controller": "3.0.2-preview-183f0b5a",
  "@metamask-previews/phishing-controller": "12.3.1-preview-183f0b5a",
  "@metamask-previews/polling-controller": "12.0.2-preview-183f0b5a",
  "@metamask-previews/preferences-controller": "15.0.1-preview-183f0b5a",
  "@metamask-previews/profile-sync-controller": "4.1.0-preview-183f0b5a",
  "@metamask-previews/queued-request-controller": "8.0.2-preview-183f0b5a",
  "@metamask-previews/rate-limit-controller": "6.0.2-preview-183f0b5a",
  "@metamask-previews/remote-feature-flag-controller": "1.3.0-preview-183f0b5a",
  "@metamask-previews/selected-network-controller": "20.0.2-preview-183f0b5a",
  "@metamask-previews/signature-controller": "23.2.0-preview-183f0b5a",
  "@metamask-previews/token-search-discovery-controller": "1.0.0-preview-183f0b5a",
  "@metamask-previews/transaction-controller": "43.0.0-preview-183f0b5a",
  "@metamask-previews/user-operation-controller": "22.0.0-preview-183f0b5a"
}

Comment on lines +2391 to +2394

this.update((state) => {
state.keyringsMetadata = validKeyringMetadata;
});
Copy link
Member

@mikesposito mikesposito Jan 22, 2025

Choose a reason for hiding this comment

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

Updating the state here will cause other controllers' state change listeners to run, though since the rest of the KeyringController state is updated atomically only after this wrapped callback executes, other controllers will receive a version of the state where keyringsMetadata has been updated, but not the other state properties (e.g. the removed accounts and keyrings are still there)

Copy link
Member

@mikesposito mikesposito Jan 22, 2025

Choose a reason for hiding this comment

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

I think there are other instances of this problem on this PR, perhaps we should try if it's possible to move the metadata update to a single place, where also keyrings and the rest of the state are updated together, like here:

Comment on lines +763 to +765
sinon
.stub(encryptor, 'decrypt')
.throws(new Error('Invalid password'));
Copy link
Member

Choose a reason for hiding this comment

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

Can we use jest here?

Comment on lines +58 to +61
jest.mock('ulidx', () => ({
ulid: () => 'ULID01234567890ABCDEFGHIJKLMN',
monotonicFactory: () => () => 'ULID01234567890ABCDEFGHIJKLMN',
}));
Copy link
Member

Choose a reason for hiding this comment

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

Instead of mocking here and assigning the same ID to all keyrings, perhaps we can mock it at test case level so we can test additional functionality

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants