-
Notifications
You must be signed in to change notification settings - Fork 277
Sam/optimize initialize account #5858
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
base: develop
Are you sure you want to change the base?
Conversation
TEMPORARY COMMIT - DO NOT MERGE Adds 'Settings-optimized.json' as a new settings file for testing: - Read: tries optimized file first, falls back to original Settings.json - Write: always writes to optimized file only This preserves the original Settings.json (with bloated denomination data) while the optimized build uses a separate file. Allows comparing loginWithKey and initializeAccount performance on the same account: - "Before" build (develop): reads/writes Settings.json - "After" build (this branch): reads optimized first, falls back to original, writes only to optimized Remove this commit before merging PR.
The showScamWarningModal function was already disabled (always returns false), making these calls unnecessary async overhead during login and other operations. Removes calls from: - initializeAccount (firstLogin) - WcConnectionsScene (firstWalletConnect) - WalletListMenuActions (firstPrivateKeyView)
When Settings.json doesn't exist (new account or first login), return default values without writing them to disk. Defaults are derived from cleaners, so they don't need to be persisted. Settings will be written when the user explicitly changes a value. This eliminates unnecessary disk I/O during the login flow.
When local Settings.json doesn't exist (new account), return default values without writing them to disk. Defaults are derived from cleaners, so they don't need to be persisted. Settings will be written when values actually change. This eliminates unnecessary disk I/O during the login flow.
Move biometric checks (isTouchEnabled, getSupportedBiometryType) from blocking awaits to background Promise execution. This removes two blocking native module calls from the critical login path. The biometric state is loaded asynchronously and dispatched via a new UI/SETTINGS/SET_TOUCH_ID_SUPPORT action when available. The UI will use default values (false) until the background check completes. Also removes the redundant refreshTouchId call - this is already called by edge-login-ui-rn in submitLogin() before the onLogin callback, so the call here was unnecessary.
Add a migration that removes default denomination values from the synced settings file. This migration: 1. Runs once per account (tracked via denominationSettingsOptimized flag) 2. Compares each saved denomination to the default from currencyInfo 3. Removes entries that match the default (they're derived on-demand) 4. Reduces settings file size for existing accounts The migration runs in the background after ACCOUNT_INIT_COMPLETE to avoid blocking the login flow. For existing accounts with many saved denominations, this significantly reduces the settings file size.
Remove the expensive nested loop that merged default denomination settings with synced settings. Since default denominations are no longer populated in the LOGIN reducer, we can use synced settings directly. The synced settings contain only user customizations. Default denominations are derived on-demand from currencyInfo via selectors.
Remove the expensive loop that populated denomination defaults for all currency plugins and tokens during LOGIN. This loop iterated through every plugin and token to set default denominations in Redux state. Denomination defaults are already available from currencyInfo and can be derived on-demand via selectors (selectDisplayDenom already has fallback logic to currencyConfig). This change eliminates unnecessary work during the login critical path.
Add promise-based caching for local account settings to ensure only one disk read occurs even with concurrent callers during login. - Add getLocalAccountSettings() cached getter in LocalSettingsActions - Add resetLocalAccountSettingsCache() called on logout - Update cache on write to keep reads consistent - Keep optimized settings filenames for A/B performance comparison - Remove duplicate perf measurement sharing same end marker - Fix ESLint issues in RequestReviewActions and ReviewTriggerTestScene This reduces login_readLocalAccountSettings time from ~870ms to ~500ms by eliminating redundant disk reads during the initialization flow.
5956aee to
5d92708
Compare
src/actions/LoginActions.tsx
Outdated
| .changeUserSettings(userSettings) | ||
| .catch((error: unknown) => { | ||
| showError(error) | ||
| .catch((err: unknown) => { |
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.
Why rename this? If we had to standardize on one name, I would prefer "error" over "err" or "e".
src/actions/LoginActions.tsx
Outdated
|
|
||
| for (const plugin of Object.keys(defaultDenominationSettings)) { | ||
| // @ts-expect-error | ||
| // @ts-expect-error - Dynamic object property assignment for denomination merging |
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.
These comments are the wrong fix. The mergedDenominationSettings should be typed as const mergedDenominationSettings: DenominationSettings = {}. Then the error itself goes away.
src/actions/LoginActions.tsx
Outdated
| // @ts-expect-error - Dynamic object property assignment for denomination merging | ||
| mergedDenominationSettings[plugin] = {} | ||
| // @ts-expect-error | ||
| // @ts-expect-error - Dynamic object property access for denomination merging |
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.
The solution to this error is a simple ?? []
src/actions/LoginActions.tsx
Outdated
| // @ts-expect-error - Dynamic object property assignment for denomination merging | ||
| mergedDenominationSettings[plugin][code] = { | ||
| // @ts-expect-error | ||
| // @ts-expect-error - Dynamic object property access for denomination merging |
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.
The solution to these errors is:
mergedDenominationSettings[plugin][code] = {
...defaultDenominationSettings[plugin]?.[code],
...syncedDenominationSettings[plugin]?.[code],
name: '',
multiplier: '',
symbol: ''
}I know we are just going to delete this code, but I'd rather not get in the habit of doubling down on @ts-expect-error comments when they are trivial to fix.
src/actions/RequestReviewActions.tsx
Outdated
| swapCount: Number.isNaN(parseInt(swapCountData.swapCount)) | ||
| ? 0 | ||
| : parseInt(swapCountData.swapCount) |
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.
I don't like the double-parse. Why not:
const swapCount = parseInt(swapCountData.swapCount)
const migratedData: ReviewTriggerData = {
...initReviewTriggerData(),
swapCount: Number.isNaN(swapCount) ? 0 : swapCount| interface Props extends WalletsTabSceneProps<'walletList'> {} | ||
|
|
||
| export function WalletListScene(props: Props) { | ||
| export function WalletListScene(props: Props): React.JSX.Element { |
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.
This should be export const WalletListScene: React.FC<Props> = props => {
src/actions/LoginActions.tsx
Outdated
| Promise.all([isTouchEnabled(account), getSupportedBiometryType()]) | ||
| .then(([touchEnabled, supportedType]) => { | ||
| dispatch({ | ||
| type: 'UI/SETTINGS/SET_TOUCH_ID_SUPPORT', | ||
| data: { | ||
| isTouchEnabled: touchEnabled, | ||
| isTouchSupported: supportedType !== false | ||
| } | ||
| }) | ||
| }) | ||
| .catch(() => { | ||
| // Fail silently - biometric state will remain at defaults | ||
| }) |
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.
This is not what we agreed in our meeting. Since these states are only used in the settings scene, we want to remove them from global redux, and make them local settings scene state. In the settings scene, it would be:
const touchState = useAsyncValue(() =>
Promise.all([isTouchEnabled(account), getSupportedBiometryType()]),
[account]
)| const PER_WALLET_TIMEOUT = 5000 | ||
| const MIN_CREATE_WALLET_TIMEOUT = 20000 | ||
|
|
||
| type SyncedSettings = ReturnType<typeof readSyncedSettings> extends Promise< |
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.
This type is already exported as SyncedAccountSettings.
| // We don't want to pester the user with too many interrupting flows. | ||
| let hideSurvey = false | ||
| // Step 1: Common early initialization | ||
| const { syncedSettings, referralPromise } = await initializeAccountInner( |
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.
Now that we no longer need to modify the settings, but instead dispatch them straight to redux, we should get rid of the ACCOUNT_INIT_COMPLETE action. The items in that payload are:
- SyncedSettings (which we have)
pinLoginEnabled, which is only used on the settings scene, and therefore should be removed from redux.- The selected wallet (walletId and currencyCode), which @peachbits has completely removed as part of his currency code PR.
- The account local settings, which we load as part of the init process.
By eliminating 2 & 3, and putting 1 straight into the LOGIN action, this only leaves 4. As mentioned elsewhere, we need to move 4 into redux anyhow, so perhaps we should just load it an stick it into the LOGIN action as well. At this point, everything we need to show the home scene or wallet list will be available in redux, and therefore we can navigate to those scenes immediately after dispatching LOGIN. That's the goal of the whole PR, after all.
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.
I also don't like factoring out initializeAccountInner and finalizeAccountInit, since they are part of every login flow, and it makes sense to see them inline. I do like the way you factored out navigateToNewAccountFlow and navigateToExistingAccountHome, because those are different between the two cases.
|
|
||
| let readSettingsFromDisk = false | ||
| // Use a promise to ensure only one disk read happens, even with concurrent callers | ||
| let readSettingsPromise: Promise<LocalAccountSettings> | null = null |
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.
This is the wrong direction. Paul tried to move some stuff out of redux as an experiment, but after several postmortems and failed projects, we now agree that this was a mistake. Redux is the perfect place for globally-available information like account settings, and the local settings definitely belong in there.
The correct solution is to delete the let localAccountSettings cache, and then initializeAccount directly reads the settings from disk and sticks them in redux (which it is already doing). After that, nobody else ever reads the settings from disk, but we do write to disk when making changes.
To make the settings load go faster, as we should probably be doing Promise.all([readSyncedSettings, readLocalAccountSettings]), and then dispatching these to redux as early as possible, as part of the LOGIN action.
CHANGELOG
Does this branch warrant an entry to the CHANGELOG?
Dependencies
noneRequirements
If you have made any visual changes to the GUI. Make sure you have:
Note
Speeds up login by caching local settings, using optimized settings files with fallback, refactoring init flow, and cleaning denomination settings; also updates review-trigger logic and related UI/actions.
getLocalAccountSettingswith single-read promise andresetLocalAccountSettingsCacheon logout.Settings-optimized.json(local and synced), falling back toSettings.json; avoid writing defaults.migrateDenominationSettingsto remove default denoms and setdenominationSettingsOptimizedflag.initializeAccountintoinitializeAccountInner,navigateToNewAccountFlow,navigateToExistingAccountHome,finalizeAccountInit, andcompleteAccountInit.UI/SETTINGS/SET_TOUCH_ID_SUPPORT.swapCountData.jsonmigration and parsing; tests updated to reset cache and expect optimized filename writes.LOGINdenomination handling; addUI/SETTINGS/SET_TOUCH_ID_SUPPORT; saferSET_DENOMINATION_KEYmerge; update synced settings read/write with optimized files.WalletListSceneand test scene.WalletListMenuActionsandWcConnectionsScenebefore certain actions.denominationSettingsOptimized.Written by Cursor Bugbot for commit 5d92708. This will update automatically on new commits. Configure here.