Skip to content

Commit

Permalink
fix: remove goerli infura from network state (#12838)
Browse files Browse the repository at this point in the history
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

core PR: MetaMask/core#5094
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Related issues**

Fixes: #12837

## **Manual testing steps**

1. Run the app locally
2. you should not see the verbose logs , or any request sent to Goerli

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [ ] I’ve followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I’ve included tests if applicable
- [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I’ve applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
  • Loading branch information
salimtb authored Jan 9, 2025
1 parent cacbd20 commit 2215339
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 56 deletions.
177 changes: 177 additions & 0 deletions app/store/migrations/065.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import migrate from './065';
import { merge } from 'lodash';
import { captureException } from '@sentry/react-native';
import initialRootState from '../../util/test/initial-root-state';
import { RootState } from '../../components/UI/BasicFunctionality/BasicFunctionalityModal/BasicFunctionalityModal.test';

jest.mock('@sentry/react-native', () => ({
captureException: jest.fn(),
}));
const mockedCaptureException = jest.mocked(captureException);

describe('Migration: Remove Goerli and Linea Goerli if Infura type', () => {
beforeEach(() => {
jest.restoreAllMocks();
jest.resetAllMocks();
});

const invalidStates = [
{
state: null,
errorMessage: "Migration: Invalid root state: 'object'",
scenario: 'state is invalid',
},
{
state: merge({}, initialRootState, {
engine: null,
}),
errorMessage: "Migration: Invalid root engine state: 'object'",
scenario: 'engine state is invalid',
},
{
state: merge({}, initialRootState, {
engine: {
backgroundState: null,
},
}),
errorMessage: "Migration: Invalid root engine backgroundState: 'object'",
scenario: 'backgroundState is invalid',
},
{
state: merge({}, initialRootState, {
engine: {
backgroundState: { NetworkController: null },
},
}),
errorMessage: "Migration: Invalid NetworkController state: 'object'",
scenario: 'NetworkController is invalid',
},
];

for (const { errorMessage, scenario, state } of invalidStates) {
it(`captures exception if ${scenario}`, async () => {
const newState = await migrate(state);

expect(newState).toStrictEqual(state);
expect(mockedCaptureException).toHaveBeenCalledWith(expect.any(Error));
expect(mockedCaptureException.mock.calls[0][0].message).toBe(
errorMessage,
);
});
}

it('removes Goerli and Linea Goerli configurations with Infura type', async () => {
const mockState = {
engine: {
backgroundState: {
NetworkController: {
networkConfigurationsByChainId: {
'0x5': {
blockExplorerUrls: [],
chainId: '0x5',
rpcEndpoints: [
{
networkClientId: 'goerli',
type: 'infura',
},
],
},
'0xe704': {
blockExplorerUrls: [],
chainId: '0xe704',
rpcEndpoints: [
{
networkClientId: 'linea-goerli',
type: 'infura',
},
],
},
},
},
},
},
};

const migratedState = (await migrate(mockState)) as RootState;

expect(
migratedState.engine.backgroundState.NetworkController
.networkConfigurationsByChainId,
).not.toHaveProperty('0x5');
expect(
migratedState.engine.backgroundState.NetworkController
.networkConfigurationsByChainId,
).not.toHaveProperty('0xe704');
});

it('retains configurations that are not Infura type', async () => {
const mockState = {
engine: {
backgroundState: {
NetworkController: {
networkConfigurationsByChainId: {
'0x5': {
blockExplorerUrls: [],
chainId: '0x5',
rpcEndpoints: [
{
networkClientId: 'goerli',
type: 'custom',
},
],
},
'0xe704': {
blockExplorerUrls: [],
chainId: '0xe704',
rpcEndpoints: [
{
networkClientId: 'linea-goerli',
type: 'custom',
},
],
},
},
},
},
},
};

const migratedState = (await migrate(mockState)) as RootState;

expect(
migratedState.engine.backgroundState.NetworkController
.networkConfigurationsByChainId,
).toHaveProperty('0x5');
expect(
migratedState.engine.backgroundState.NetworkController
.networkConfigurationsByChainId,
).toHaveProperty('0xe704');
});

it('does not modify state if no matching configurations exist', async () => {
const mockState = {
engine: {
backgroundState: {
NetworkController: {
networkConfigurationsByChainId: {
'0x1': {
blockExplorerUrls: [],
chainId: '0x1',
rpcEndpoints: [
{
networkClientId: 'mainnet',
type: 'infura',
},
],
},
},
},
},
},
};

const migratedState = await migrate(mockState);

expect(migratedState).toEqual(mockState);
});
});
83 changes: 83 additions & 0 deletions app/store/migrations/065.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { captureException } from '@sentry/react-native';
import { isObject, hasProperty } from '@metamask/utils';
import { NetworkState, RpcEndpointType } from '@metamask/network-controller';
import { CHAIN_IDS } from '@metamask/transaction-controller';

/**
* Migration to delete Goerli and Linea Goerli configurations if they are Infura types.
* @param {unknown} stateAsync - Promise Redux state.
* @returns Migrated Redux state.
*/
export default async function migrate(stateAsync: unknown) {
const state = await stateAsync;

if (!isObject(state)) {
captureException(
new Error(`Migration: Invalid root state: '${typeof state}'`),
);
return state;
}

if (!isObject(state.engine)) {
captureException(
new Error(
`Migration: Invalid root engine state: '${typeof state.engine}'`,
),
);
return state;
}

if (!isObject(state.engine.backgroundState)) {
captureException(
new Error(
`Migration: Invalid root engine backgroundState: '${typeof state.engine
.backgroundState}'`,
),
);
return state;
}

const networkControllerState = state.engine.backgroundState
.NetworkController as NetworkState;
if (!isObject(networkControllerState)) {
captureException(
new Error(
`Migration: Invalid NetworkController state: '${typeof networkControllerState}'`,
),
);
return state;
}

const networkConfigurationsByChainId =
networkControllerState.networkConfigurationsByChainId;

if (!isObject(networkConfigurationsByChainId)) {
captureException(
new Error(
`Migration: Invalid networkConfigurationsByChainId: '${typeof networkConfigurationsByChainId}'`,
),
);
return state;
}

// Chain IDs to remove
const chainIdsToRemove = [CHAIN_IDS.GOERLI, CHAIN_IDS.LINEA_GOERLI];

// Filter out Goerli and Linea Goerli configurations with Infura type
chainIdsToRemove.forEach((chainId) => {
if (hasProperty(networkConfigurationsByChainId, chainId)) {
const config = networkConfigurationsByChainId[chainId];

if (
Array.isArray(config.rpcEndpoints) &&
config.rpcEndpoints.some(
(endpoint) => endpoint.type === RpcEndpointType.Infura,
)
) {
delete networkConfigurationsByChainId[chainId];
}
}
});

return state;
}
2 changes: 2 additions & 0 deletions app/store/migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import migration61 from './061';
import migration62 from './062';
import migration63 from './063';
import migration64 from './064';
import migration65 from './065';

type MigrationFunction = (state: unknown) => unknown;
type AsyncMigrationFunction = (state: unknown) => Promise<unknown>;
Expand Down Expand Up @@ -142,6 +143,7 @@ export const migrationList: MigrationsList = {
62: migration62,
63: migration63,
64: migration64,
65: migration65,
};

// Enable both synchronous and asynchronous migrations
Expand Down
28 changes: 0 additions & 28 deletions app/util/logs/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,6 @@ exports[`logs :: generateStateLogs generates a valid json export 1`] = `
},
],
},
"0x5": {
"blockExplorerUrls": [],
"chainId": "0x5",
"defaultRpcEndpointIndex": 0,
"name": "Goerli",
"nativeCurrency": "GoerliETH",
"rpcEndpoints": [
{
"networkClientId": "goerli",
"type": "infura",
"url": "https://goerli.infura.io/v3/{infuraProjectId}",
},
],
},
"0xaa36a7": {
"blockExplorerUrls": [],
"chainId": "0xaa36a7",
Expand All @@ -99,20 +85,6 @@ exports[`logs :: generateStateLogs generates a valid json export 1`] = `
},
],
},
"0xe704": {
"blockExplorerUrls": [],
"chainId": "0xe704",
"defaultRpcEndpointIndex": 0,
"name": "Linea Goerli",
"nativeCurrency": "LineaETH",
"rpcEndpoints": [
{
"networkClientId": "linea-goerli",
"type": "infura",
"url": "https://linea-goerli.infura.io/v3/{infuraProjectId}",
},
],
},
"0xe705": {
"blockExplorerUrls": [],
"chainId": "0xe705",
Expand Down
28 changes: 0 additions & 28 deletions app/util/test/initial-background-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,6 @@
}
]
},
"0x5": {
"blockExplorerUrls": [],
"chainId": "0x5",
"defaultRpcEndpointIndex": 0,
"name": "Goerli",
"nativeCurrency": "GoerliETH",
"rpcEndpoints": [
{
"networkClientId": "goerli",
"type": "infura",
"url": "https://goerli.infura.io/v3/{infuraProjectId}"
}
]
},
"0xaa36a7": {
"blockExplorerUrls": [],
"chainId": "0xaa36a7",
Expand All @@ -99,20 +85,6 @@
}
]
},
"0xe704": {
"blockExplorerUrls": [],
"chainId": "0xe704",
"defaultRpcEndpointIndex": 0,
"name": "Linea Goerli",
"nativeCurrency": "LineaETH",
"rpcEndpoints": [
{
"networkClientId": "linea-goerli",
"type": "infura",
"url": "https://linea-goerli.infura.io/v3/{infuraProjectId}"
}
]
},
"0xe705": {
"blockExplorerUrls": [],
"chainId": "0xe705",
Expand Down
Loading

0 comments on commit 2215339

Please sign in to comment.