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: Refactor state classes to prepare for state corruption backup mitigation #29745

Merged
merged 48 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
8d2ca8c
refactor storage system
brad-decker Apr 12, 2024
4421f54
Re-refactor state classes
danjm Jan 16, 2025
1ca62ea
Lint and type error fixes
danjm Jan 20, 2025
3401019
Code comment update
danjm Jan 20, 2025
e4f03bc
Fix storeAlreadyExisted/firstTimeInstalled mistake in onInstall()
danjm Jan 20, 2025
bf23d04
Cleanup
danjm Jan 20, 2025
731fbd2
Update app/scripts/lib/Stores/BaseStore.ts
danjm Jan 23, 2025
ab230de
Update app/scripts/lib/Stores/BaseStore.ts
danjm Jan 23, 2025
d7621df
Update app/scripts/lib/Stores/PersistanceManager.ts
danjm Jan 23, 2025
1ed21ce
Update app/scripts/lib/Stores/ExtensionStore.ts
danjm Jan 23, 2025
7addfa1
Update app/scripts/lib/Stores/ReadOnlyNetworkStore.ts
danjm Jan 23, 2025
43a36a5
Update app/scripts/lib/Stores/ExtensionStore.ts
danjm Jan 23, 2025
7296ee9
Update app/scripts/lib/Stores/ReadOnlyNetworkStore.ts
danjm Jan 23, 2025
9dd5642
Update names in app/scripts/lib/stores/ directory
danjm Jan 23, 2025
261351e
Rename localStore -> persistanceManager in background.js
danjm Jan 23, 2025
c9443ff
Stop exporting unused type
danjm Jan 23, 2025
46d664a
Update error handling in extension-store, and some lint fixes
danjm Jan 23, 2025
590aed2
Remove unnecessary getter and setter for metadata in persistence-manager
danjm Jan 23, 2025
c990f4c
Make dataPersistenceFailing, isExtensionInitialized, mostRecentRetrie…
danjm Jan 24, 2025
9308f75
Remove inaccurate comment for metadata
danjm Jan 24, 2025
86fedf0
Update app/scripts/lib/stores/read-only-network-store.ts
danjm Jan 24, 2025
1dfef6f
Update app/scripts/lib/stores/read-only-network-store.test.ts
danjm Jan 24, 2025
aee5098
Removed unused typed
danjm Jan 24, 2025
f4356d8
Correct variable name
danjm Jan 24, 2025
20f2f4e
Removed unused test code
danjm Jan 24, 2025
51cb8dd
Initialize persistence store instance variables where they are declared
danjm Jan 24, 2025
1a2ce8f
Use ts-expect-error exception to pass uncorrect type in read-only-net…
danjm Jan 24, 2025
23bb694
Improve test description: avoid referencing internal implementation d…
danjm Jan 24, 2025
1dd96ee
Remove redundant test
danjm Jan 24, 2025
a76aa9b
Group read-only-network-store.test.ts tests accoring to 'arrange, act…
danjm Jan 24, 2025
3b5e8a7
Improve variable naming and jsdoc for read-only-network-store set
danjm Jan 24, 2025
f4fb07e
Improve test for extension-store get
danjm Jan 24, 2025
d5fd20d
Update test descriptions
danjm Jan 27, 2025
e67b3fe
Update app/scripts/lib/stores/persistence-manager.test.ts
danjm Jan 27, 2025
72048af
Update app/scripts/lib/stores/extension-store.test.ts
danjm Jan 27, 2025
48826df
Update app/scripts/lib/stores/extension-store.test.ts
danjm Jan 27, 2025
1846094
Update app/scripts/lib/stores/extension-store.test.ts
danjm Jan 27, 2025
775e5f5
Change misleading name and description of intermediary state type
danjm Jan 27, 2025
fc418df
Restore setMetadata method
danjm Jan 27, 2025
f91397b
Update app/scripts/lib/stores/extension-store.test.ts
danjm Jan 28, 2025
c5669c9
Correct type import
danjm Jan 28, 2025
1d4aa02
Improve test
danjm Jan 28, 2025
b5a4a5d
Move test data to const
danjm Jan 28, 2025
acd53a0
Correct spelling persistance -> persistence
danjm Jan 28, 2025
3236ed2
Lint fix
danjm Jan 29, 2025
ee61d60
Fix error
danjm Jan 29, 2025
0b72887
Fix unit tests
danjm Jan 29, 2025
1aa223e
Lint fix
danjm Jan 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 30 additions & 34 deletions app/scripts/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ import {
import { getCurrentChainId } from '../../shared/modules/selectors/networks';
import { addNonceToCsp } from '../../shared/modules/add-nonce-to-csp';
import { checkURLForProviderInjection } from '../../shared/modules/provider-injection';
import { PersistenceManager } from './lib/stores/persistence-manager';
import ExtensionStore from './lib/stores/extension-store';
import ReadOnlyNetworkStore from './lib/stores/read-only-network-store';
import migrations from './migrations';
import Migrator from './lib/migrator';
import ExtensionPlatform from './platforms/extension';
import LocalStore from './lib/local-store';
import ReadOnlyNetworkStore from './lib/network-store';
import { SENTRY_BACKGROUND_STATE } from './constants/sentry-state';

import createStreamSink from './lib/createStreamSink';
Expand All @@ -63,7 +64,6 @@ import NotificationManager, {
import MetamaskController, {
METAMASK_CONTROLLER_EVENTS,
} from './metamask-controller';
import rawFirstTimeState from './first-time-state';
import getFirstPreferredLangCode from './lib/get-first-preferred-lang-code';
import getObjStructure from './lib/getObjStructure';
import setupEnsIpfsResolver from './lib/ens-ipfs/setup';
Expand All @@ -72,8 +72,9 @@ import {
getPlatform,
shouldEmitDappViewedEvent,
} from './lib/util';
import { generateWalletState } from './fixtures/generate-wallet-state';
import { createOffscreen } from './offscreen';
import { generateWalletState } from './fixtures/generate-wallet-state';
import rawFirstTimeState from './first-time-state';

/* eslint-enable import/first */

Expand All @@ -87,9 +88,17 @@ const BADGE_MAX_COUNT = 9;

// Setup global hook for improved Sentry state snapshots during initialization
const inTest = process.env.IN_TEST;
const localStore = inTest ? new ReadOnlyNetworkStore() : new LocalStore();
const migrator = new Migrator({
migrations,
defaultVersion: process.env.WITH_STATE
? FIXTURE_STATE_METADATA_VERSION
: null,
});

const localStore = inTest ? new ReadOnlyNetworkStore() : new ExtensionStore();
const persistenceManager = new PersistenceManager({ localStore });
global.stateHooks.getMostRecentPersistedState = () =>
localStore.mostRecentRetrievedState;
persistenceManager.mostRecentRetrievedState;

const { sentry } = global;
let firstTimeState = { ...rawFirstTimeState };
Expand All @@ -113,11 +122,11 @@ let uiIsTriggering = false;
const openMetamaskTabsIDs = {};
const requestAccountTabIds = {};
let controller;
let versionedData;
const tabOriginMapping = {};

if (inTest || process.env.METAMASK_DEBUG) {
global.stateHooks.metamaskGetState = localStore.get.bind(localStore);
global.stateHooks.metamaskGetState =
persistenceManager.get.bind(persistenceManager);
}

const phishingPageUrl = new URL(process.env.PHISHING_WARNING_PAGE_URL);
Expand Down Expand Up @@ -599,12 +608,6 @@ async function loadPhishingWarningPage() {
*/
export async function loadStateFromPersistence() {
// migrations
const migrator = new Migrator({
migrations,
defaultVersion: process.env.WITH_STATE
? FIXTURE_STATE_METADATA_VERSION
: null,
});
migrator.on('error', console.warn);

if (process.env.WITH_STATE) {
Expand All @@ -614,31 +617,22 @@ export async function loadStateFromPersistence() {

// read from disk
// first from preferred, async API:
versionedData =
(await localStore.get()) || migrator.generateInitialState(firstTimeState);

// check if somehow state is empty
// this should never happen but new error reporting suggests that it has
// for a small number of users
// https://github.com/metamask/metamask-extension/issues/3919
if (versionedData && !versionedData.data) {
// unable to recover, clear state
versionedData = migrator.generateInitialState(firstTimeState);
sentry.captureMessage('MetaMask - Empty vault found - unable to recover');
Gudahtt marked this conversation as resolved.
Show resolved Hide resolved
}
const preMigrationVersionedData =
(await persistenceManager.get()) ||
migrator.generateInitialState(firstTimeState);

// report migration errors to sentry
migrator.on('error', (err) => {
// get vault structure without secrets
const vaultStructure = getObjStructure(versionedData);
const vaultStructure = getObjStructure(preMigrationVersionedData);
sentry.captureException(err, {
// "extra" key is required by Sentry
extra: { vaultStructure },
});
});

// migrate data
versionedData = await migrator.migrateData(versionedData);
const versionedData = await migrator.migrateData(preMigrationVersionedData);
if (!versionedData) {
throw new Error('MetaMask - migrator returned undefined');
} else if (!isObject(versionedData.meta)) {
Expand All @@ -656,10 +650,10 @@ export async function loadStateFromPersistence() {
);
}
// this initializes the meta/version data as a class variable to be used for future writes
localStore.setMetadata(versionedData.meta);
persistenceManager.setMetadata(versionedData.meta);

// write to disk
localStore.set(versionedData.data);
persistenceManager.set(versionedData.data);

// return just the data
return versionedData;
Expand Down Expand Up @@ -821,7 +815,7 @@ export function setupController(
getOpenMetamaskTabsIds: () => {
return openMetamaskTabsIDs;
},
localStore,
persistenceManager,
overrides,
isFirstMetaMaskControllerSetup,
currentMigrationVersion: stateMetadata.version,
Expand All @@ -845,7 +839,7 @@ export function setupController(
storeAsStream(controller.store),
debounce(1000),
createStreamSink(async (state) => {
await localStore.set(state);
await persistenceManager.set(state);
statePersistenceEvents.emit('state-persisted', state);
}),
(error) => {
Expand Down Expand Up @@ -1304,12 +1298,14 @@ const addAppInstalledEvent = () => {

// On first install, open a new tab with MetaMask
async function onInstall() {
const storeAlreadyExisted = Boolean(await localStore.get());
const storeAlreadyExisted = Boolean(await persistenceManager.get());
// If the store doesn't exist, then this is the first time running this script,
// and is therefore an install
if (process.env.IN_TEST) {
addAppInstalledEvent();
} else if (!storeAlreadyExisted && !process.env.METAMASK_DEBUG) {
// If storeAlreadyExisted is true then this is a fresh installation
// and an app installed event should be tracked.
addAppInstalledEvent();
platform.openExtensionInBrowser();
}
Expand Down Expand Up @@ -1358,7 +1354,7 @@ async function initBackground() {
window.document?.documentElement?.classList.add('controller-loaded');
}
}
localStore.cleanUpMostRecentRetrievedState();
persistenceManager.cleanUpMostRecentRetrievedState();
} catch (error) {
log.error(error);
}
Expand Down
139 changes: 0 additions & 139 deletions app/scripts/lib/local-store.js

This file was deleted.

Loading
Loading