-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
to batch account restore operation
#11409
base: main
Are you sure you want to change the base?
Conversation
Bitrise❌❌❌ Commit hash: 2e16358 Note
Tip
|
We could make this even more efficient by batching the queried balances, and it would look something like this:
This would result in 1 single network call and 1 single state update. Additionally, it would allow to restore accounts with balance even if there's an empty balance account in the middle |
51b0b10
to
6e55ca9
Compare
Bitrise❌❌❌ Commit hash: 6e55ca9 Note
Tip
|
app/util/importAdditionalAccounts.js
Outdated
await KeyringController.withKeyring( | ||
{ type: ExtendedKeyringTypes.hd }, | ||
async (primaryKeyring) => { | ||
let i = 0; | ||
// seek out the first zero balance | ||
while (i < MAX) { | ||
const [newAccount] = await primaryKeyring.addAccounts(1); | ||
const newAccountBalance = await getBalance(newAccount, ethQuery); | ||
|
||
let i = 0; | ||
// seek out the first zero balance | ||
while (lastBalance !== ZERO_BALANCE) { | ||
if (i === MAX) break; | ||
await KeyringController.addNewAccountWithoutUpdate(primaryKeyring); | ||
accounts = await KeyringController.getAccounts(); | ||
lastBalance = await getBalance(accounts[accounts.length - 1], ethQuery); | ||
i++; | ||
} | ||
if (newAccountBalance === ZERO_BALANCE) { | ||
// remove extra zero balance account we just added and break the loop | ||
primaryKeyring.removeAccount(newAccount); | ||
break; | ||
} | ||
|
||
// remove extra zero balance account potentially created from seeking ahead | ||
if (accounts.length > 1 && lastBalance === ZERO_BALANCE) { | ||
await KeyringController.removeAccount(accounts[accounts.length - 1]); | ||
accounts = await KeyringController.getAccounts(); | ||
} | ||
i++; | ||
} | ||
}, | ||
); |
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.
KeyringController
wil do all the heavy lifting here: race condition protection, primary keyring existence check, batch state update with the resulting keyring, rollback in case of error and automatic vault update
This code has never been covered |
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.
LGTM! The main feedback I have is to add unit test to the method to ensure the happy path case is working as expected. A minor and optional request would be to refactor this file to TS if possible.
We should also manual test it. We can handle that in the accounts team. |
@gantunesr I will convert the file to typescript, add tests and post a recording of the flow |
Quality Gate failedFailed conditions |
I am working on bumping the accounts controller and the keyring controller. This PR will need to merge before I can merge mine. |
@mikesposito once you get the unit tests passing let me know and I can re review. |
Description
The problem
With the current used version of
KeyringController
, theaddNewAccountWithoutUpdate
method is not doing what its name claims - the state is updated everytime the function is called.This is because
KeyringController
has no control over its messenger's listeners, and soPreferencesController
andAccountsController
(and so on downstream) will react to keyrings state updates everytimeaddNewAccountWithoutUpdate
is called.The result is that the
importAdditionalAccounts
helper present on mobile is incredibly inefficient, as accounts will be added one by one, executing all side effects at every single iteration.The solution
This PR leverages the new
withKeyring
method from KeyringController to batch these iterations into one single atomic state update - take a look at the code for more info about how it is doneRelated issues
Related: MetaMask/core#3848
Manual testing steps
Screenshots/Recordings
Before
After
Pre-merge author checklist
Pre-merge reviewer checklist