mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
Use unflattened state for Sentry (#20428)
The unflattened background state is now attached to any Sentry errors from the background process. This provides a clearer picture of the state of the wallet, and unblocks further improvements to Sentry state which will come in later PRs.
This commit is contained in:
parent
419bf92282
commit
63a0ae765f
@ -886,14 +886,14 @@ browser.runtime.onInstalled.addListener(({ reason }) => {
|
|||||||
|
|
||||||
function setupSentryGetStateGlobal(store) {
|
function setupSentryGetStateGlobal(store) {
|
||||||
global.stateHooks.getSentryState = function () {
|
global.stateHooks.getSentryState = function () {
|
||||||
const backgroundState = store.getState();
|
const backgroundState = store.memStore.getState();
|
||||||
const maskedBackgroundState = maskObject(
|
const maskedBackgroundState = maskObject(
|
||||||
backgroundState,
|
backgroundState,
|
||||||
SENTRY_BACKGROUND_STATE,
|
SENTRY_BACKGROUND_STATE,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
browser: window.navigator.userAgent,
|
browser: window.navigator.userAgent,
|
||||||
store: { metamask: maskedBackgroundState },
|
store: maskedBackgroundState,
|
||||||
version: platform.getVersion(),
|
version: platform.getVersion(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -27,60 +27,103 @@ export const ERROR_URL_ALLOWLIST = {
|
|||||||
// sent to Sentry These properties have some potential to be useful for
|
// sent to Sentry These properties have some potential to be useful for
|
||||||
// debugging, and they do not contain any identifiable information.
|
// debugging, and they do not contain any identifiable information.
|
||||||
export const SENTRY_BACKGROUND_STATE = {
|
export const SENTRY_BACKGROUND_STATE = {
|
||||||
alertEnabledness: true,
|
AccountTracker: {
|
||||||
completedOnboarding: true,
|
currentBlockGasLimit: true,
|
||||||
connectedStatusPopoverHasBeenShown: true,
|
},
|
||||||
conversionDate: true,
|
AlertController: {
|
||||||
conversionRate: true,
|
alertEnabledness: true,
|
||||||
currentAppVersion: true,
|
},
|
||||||
currentBlockGasLimit: true,
|
AppMetadataController: {
|
||||||
currentCurrency: true,
|
currentAppVersion: true,
|
||||||
currentLocale: true,
|
previousAppVersion: true,
|
||||||
currentMigrationVersion: true,
|
previousMigrationVersion: true,
|
||||||
customNonceValue: true,
|
currentMigrationVersion: true,
|
||||||
defaultHomeActiveTabName: true,
|
},
|
||||||
desktopEnabled: true,
|
AppStateController: {
|
||||||
featureFlags: true,
|
connectedStatusPopoverHasBeenShown: true,
|
||||||
firstTimeFlowType: true,
|
defaultHomeActiveTabName: true,
|
||||||
forgottenPassword: true,
|
},
|
||||||
incomingTxLastFetchedBlockByChainId: true,
|
CurrencyController: {
|
||||||
ipfsGateway: true,
|
conversionDate: true,
|
||||||
isAccountMenuOpen: true,
|
conversionRate: true,
|
||||||
isInitialized: true,
|
currentCurrency: true,
|
||||||
isUnlocked: true,
|
nativeCurrency: true,
|
||||||
metaMetricsId: true,
|
},
|
||||||
nativeCurrency: true,
|
DecryptMessageController: {
|
||||||
networkId: true,
|
unapprovedDecryptMsgCount: true,
|
||||||
networkStatus: true,
|
},
|
||||||
nextNonce: true,
|
DesktopController: {
|
||||||
participateInMetaMetrics: true,
|
desktopEnabled: true,
|
||||||
preferences: true,
|
},
|
||||||
previousAppVersion: true,
|
EncryptionPublicKeyController: {
|
||||||
previousMigrationVersion: true,
|
unapprovedEncryptionPublicKeyMsgCount: true,
|
||||||
providerConfig: {
|
},
|
||||||
nickname: true,
|
IncomingTransactionsController: {
|
||||||
ticker: true,
|
incomingTxLastFetchedBlockByChainId: true,
|
||||||
type: true,
|
},
|
||||||
|
KeyringController: {
|
||||||
|
isUnlocked: true,
|
||||||
|
},
|
||||||
|
MetaMetricsController: {
|
||||||
|
metaMetricsId: true,
|
||||||
|
participateInMetaMetrics: true,
|
||||||
|
},
|
||||||
|
NetworkController: {
|
||||||
|
networkId: true,
|
||||||
|
networkStatus: true,
|
||||||
|
providerConfig: {
|
||||||
|
nickname: true,
|
||||||
|
ticker: true,
|
||||||
|
type: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OnboardingController: {
|
||||||
|
completedOnboarding: true,
|
||||||
|
firstTimeFlowType: true,
|
||||||
|
seedPhraseBackedUp: true,
|
||||||
|
},
|
||||||
|
PreferencesController: {
|
||||||
|
currentLocale: true,
|
||||||
|
featureFlags: true,
|
||||||
|
forgottenPassword: true,
|
||||||
|
ipfsGateway: true,
|
||||||
|
preferences: true,
|
||||||
|
useBlockie: true,
|
||||||
|
useNonceField: true,
|
||||||
|
usePhishDetect: true,
|
||||||
|
},
|
||||||
|
SignatureController: {
|
||||||
|
unapprovedMsgCount: true,
|
||||||
|
unapprovedPersonalMsgCount: true,
|
||||||
|
unapprovedTypedMessagesCount: true,
|
||||||
},
|
},
|
||||||
seedPhraseBackedUp: true,
|
|
||||||
unapprovedDecryptMsgCount: true,
|
|
||||||
unapprovedEncryptionPublicKeyMsgCount: true,
|
|
||||||
unapprovedMsgCount: true,
|
|
||||||
unapprovedPersonalMsgCount: true,
|
|
||||||
unapprovedTypedMessagesCount: true,
|
|
||||||
useBlockie: true,
|
|
||||||
useNonceField: true,
|
|
||||||
usePhishDetect: true,
|
|
||||||
welcomeScreenSeen: true,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const flattenedBackgroundStateMask = Object.values(
|
||||||
|
SENTRY_BACKGROUND_STATE,
|
||||||
|
).reduce((partialBackgroundState, controllerState) => {
|
||||||
|
return {
|
||||||
|
...partialBackgroundState,
|
||||||
|
...controllerState,
|
||||||
|
};
|
||||||
|
}, {});
|
||||||
|
|
||||||
// This describes the subset of Redux state attached to errors sent to Sentry
|
// This describes the subset of Redux state attached to errors sent to Sentry
|
||||||
// These properties have some potential to be useful for debugging, and they do
|
// These properties have some potential to be useful for debugging, and they do
|
||||||
// not contain any identifiable information.
|
// not contain any identifiable information.
|
||||||
export const SENTRY_UI_STATE = {
|
export const SENTRY_UI_STATE = {
|
||||||
gas: true,
|
gas: true,
|
||||||
history: true,
|
history: true,
|
||||||
metamask: SENTRY_BACKGROUND_STATE,
|
metamask: {
|
||||||
|
...flattenedBackgroundStateMask,
|
||||||
|
// This property comes from the background but isn't in controller state
|
||||||
|
isInitialized: true,
|
||||||
|
// These properties are in the `metamask` slice but not in the background state
|
||||||
|
customNonceValue: true,
|
||||||
|
isAccountMenuOpen: true,
|
||||||
|
nextNonce: true,
|
||||||
|
welcomeScreenSeen: true,
|
||||||
|
},
|
||||||
unconnectedAccount: true,
|
unconnectedAccount: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@ const { format } = require('prettier');
|
|||||||
const { convertToHexValue, withFixtures } = require('../helpers');
|
const { convertToHexValue, withFixtures } = require('../helpers');
|
||||||
const FixtureBuilder = require('../fixture-builder');
|
const FixtureBuilder = require('../fixture-builder');
|
||||||
|
|
||||||
const dateFields = ['metamask.conversionDate'];
|
const backgroundDateFields = ['CurrencyController.conversionDate'];
|
||||||
|
const uiDateFields = ['metamask.conversionDate'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform date properties to value types, to ensure that state is
|
* Transform date properties to value types, to ensure that state is
|
||||||
@ -15,8 +16,23 @@ const dateFields = ['metamask.conversionDate'];
|
|||||||
*
|
*
|
||||||
* @param {unknown} data - The data to transform
|
* @param {unknown} data - The data to transform
|
||||||
*/
|
*/
|
||||||
function transformDates(data) {
|
function transformBackgroundDates(data) {
|
||||||
for (const field of dateFields) {
|
for (const field of backgroundDateFields) {
|
||||||
|
if (has(data, field)) {
|
||||||
|
set(data, field, typeof get(data, field));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform date properties to value types, to ensure that state is
|
||||||
|
* consistent between test runs.
|
||||||
|
*
|
||||||
|
* @param {unknown} data - The data to transform
|
||||||
|
*/
|
||||||
|
function transformUiDates(data) {
|
||||||
|
for (const field of uiDateFields) {
|
||||||
if (has(data, field)) {
|
if (has(data, field)) {
|
||||||
set(data, field, typeof get(data, field));
|
set(data, field, typeof get(data, field));
|
||||||
}
|
}
|
||||||
@ -33,12 +49,10 @@ function transformDates(data) {
|
|||||||
* @param {boolean} [args.update] - Whether to update the snapshot if it doesn't match.
|
* @param {boolean} [args.update] - Whether to update the snapshot if it doesn't match.
|
||||||
*/
|
*/
|
||||||
async function matchesSnapshot({
|
async function matchesSnapshot({
|
||||||
data: unprocessedData,
|
data,
|
||||||
snapshot,
|
snapshot,
|
||||||
update = process.env.UPDATE_SNAPSHOTS === 'true',
|
update = process.env.UPDATE_SNAPSHOTS === 'true',
|
||||||
}) {
|
}) {
|
||||||
const data = transformDates(unprocessedData);
|
|
||||||
|
|
||||||
const snapshotPath = resolve(__dirname, `./state-snapshots/${snapshot}.json`);
|
const snapshotPath = resolve(__dirname, `./state-snapshots/${snapshot}.json`);
|
||||||
const rawSnapshotData = await fs.readFile(snapshotPath, {
|
const rawSnapshotData = await fs.readFile(snapshotPath, {
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
@ -243,7 +257,7 @@ describe('Sentry errors', function () {
|
|||||||
const mockJsonBody = JSON.parse(mockTextBody[2]);
|
const mockJsonBody = JSON.parse(mockTextBody[2]);
|
||||||
const appState = mockJsonBody?.extra?.appState;
|
const appState = mockJsonBody?.extra?.appState;
|
||||||
await matchesSnapshot({
|
await matchesSnapshot({
|
||||||
data: appState,
|
data: transformBackgroundDates(appState),
|
||||||
snapshot: 'errors-before-init-opt-in-background-state',
|
snapshot: 'errors-before-init-opt-in-background-state',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -328,7 +342,7 @@ describe('Sentry errors', function () {
|
|||||||
const mockJsonBody = JSON.parse(mockTextBody[2]);
|
const mockJsonBody = JSON.parse(mockTextBody[2]);
|
||||||
const appState = mockJsonBody?.extra?.appState;
|
const appState = mockJsonBody?.extra?.appState;
|
||||||
await matchesSnapshot({
|
await matchesSnapshot({
|
||||||
data: appState,
|
data: transformUiDates(appState),
|
||||||
snapshot: 'errors-before-init-opt-in-ui-state',
|
snapshot: 'errors-before-init-opt-in-ui-state',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -436,7 +450,8 @@ describe('Sentry errors', function () {
|
|||||||
const mockJsonBody = JSON.parse(mockTextBody[2]);
|
const mockJsonBody = JSON.parse(mockTextBody[2]);
|
||||||
const { level, extra } = mockJsonBody;
|
const { level, extra } = mockJsonBody;
|
||||||
const [{ type, value }] = mockJsonBody.exception.values;
|
const [{ type, value }] = mockJsonBody.exception.values;
|
||||||
const { participateInMetaMetrics } = extra.appState.store.metamask;
|
const { participateInMetaMetrics } =
|
||||||
|
extra.appState.store.MetaMetricsController;
|
||||||
// Verify request
|
// Verify request
|
||||||
assert.equal(type, 'TestError');
|
assert.equal(type, 'TestError');
|
||||||
assert.equal(value, 'Test Error');
|
assert.equal(value, 'Test Error');
|
||||||
@ -494,7 +509,7 @@ describe('Sentry errors', function () {
|
|||||||
'Invalid version state',
|
'Invalid version state',
|
||||||
);
|
);
|
||||||
await matchesSnapshot({
|
await matchesSnapshot({
|
||||||
data: appState.store,
|
data: transformBackgroundDates(appState.store),
|
||||||
snapshot: 'errors-after-init-opt-in-background-state',
|
snapshot: 'errors-after-init-opt-in-background-state',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -588,7 +603,7 @@ describe('Sentry errors', function () {
|
|||||||
'Invalid version state',
|
'Invalid version state',
|
||||||
);
|
);
|
||||||
await matchesSnapshot({
|
await matchesSnapshot({
|
||||||
data: appState.store,
|
data: transformUiDates(appState.store),
|
||||||
snapshot: 'errors-after-init-opt-in-ui-state',
|
snapshot: 'errors-after-init-opt-in-ui-state',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -1,52 +1,32 @@
|
|||||||
{
|
{
|
||||||
"metamask": {
|
"AccountTracker": { "currentBlockGasLimit": "0x1c9c380" },
|
||||||
"isInitialized": true,
|
"AppStateController": {
|
||||||
"connectedStatusPopoverHasBeenShown": true,
|
"connectedStatusPopoverHasBeenShown": true,
|
||||||
"defaultHomeActiveTabName": null,
|
"defaultHomeActiveTabName": null
|
||||||
"currentAppVersion": "10.34.4",
|
},
|
||||||
"previousAppVersion": "",
|
"CurrencyController": {
|
||||||
"previousMigrationVersion": 0,
|
"conversionDate": "number",
|
||||||
"currentMigrationVersion": 94,
|
"conversionRate": 1700,
|
||||||
|
"nativeCurrency": "ETH",
|
||||||
|
"currentCurrency": "usd"
|
||||||
|
},
|
||||||
|
"DecryptMessageController": { "unapprovedDecryptMsgCount": 0 },
|
||||||
|
"EncryptionPublicKeyController": {
|
||||||
|
"unapprovedEncryptionPublicKeyMsgCount": 0
|
||||||
|
},
|
||||||
|
"MetaMetricsController": {
|
||||||
|
"participateInMetaMetrics": true,
|
||||||
|
"metaMetricsId": "fake-metrics-id"
|
||||||
|
},
|
||||||
|
"NetworkController": {
|
||||||
"networkId": "1337",
|
"networkId": "1337",
|
||||||
"providerConfig": {
|
"providerConfig": {
|
||||||
"nickname": "Localhost 8545",
|
"nickname": "Localhost 8545",
|
||||||
"ticker": "ETH",
|
"ticker": "ETH",
|
||||||
"type": "rpc"
|
"type": "rpc"
|
||||||
},
|
}
|
||||||
"isUnlocked": false,
|
},
|
||||||
"useBlockie": false,
|
"SignatureController": {
|
||||||
"useNonceField": false,
|
|
||||||
"usePhishDetect": true,
|
|
||||||
"featureFlags": { "showIncomingTransactions": true },
|
|
||||||
"currentLocale": "en",
|
|
||||||
"forgottenPassword": false,
|
|
||||||
"preferences": {
|
|
||||||
"hideZeroBalanceTokens": false,
|
|
||||||
"showFiatInTestnets": false,
|
|
||||||
"showTestNetworks": false,
|
|
||||||
"useNativeCurrencyAsPrimaryCurrency": true
|
|
||||||
},
|
|
||||||
"ipfsGateway": "dweb.link",
|
|
||||||
"participateInMetaMetrics": true,
|
|
||||||
"metaMetricsId": "fake-metrics-id",
|
|
||||||
"conversionDate": "number",
|
|
||||||
"conversionRate": 1700,
|
|
||||||
"nativeCurrency": "ETH",
|
|
||||||
"currentCurrency": "usd",
|
|
||||||
"alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true },
|
|
||||||
"seedPhraseBackedUp": true,
|
|
||||||
"firstTimeFlowType": "import",
|
|
||||||
"completedOnboarding": true,
|
|
||||||
"incomingTxLastFetchedBlockByChainId": {
|
|
||||||
"0x1": null,
|
|
||||||
"0xe708": null,
|
|
||||||
"0x5": null,
|
|
||||||
"0xaa36a7": null,
|
|
||||||
"0xe704": null
|
|
||||||
},
|
|
||||||
"currentBlockGasLimit": "0x1c9c380",
|
|
||||||
"unapprovedDecryptMsgCount": 0,
|
|
||||||
"unapprovedEncryptionPublicKeyMsgCount": 0,
|
|
||||||
"unapprovedMsgCount": 0,
|
"unapprovedMsgCount": 0,
|
||||||
"unapprovedPersonalMsgCount": 0,
|
"unapprovedPersonalMsgCount": 0,
|
||||||
"unapprovedTypedMessagesCount": 0
|
"unapprovedTypedMessagesCount": 0
|
||||||
|
Loading…
Reference in New Issue
Block a user