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

fix: remove goerli infura from network state #12838

Merged
merged 5 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
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
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(`should capture 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('should remove Goerli and Linea Goerli configurations with Infura type', async () => {
salimtb marked this conversation as resolved.
Show resolved Hide resolved
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('should retain configurations that are not Infura type', async () => {
salimtb marked this conversation as resolved.
Show resolved Hide resolved
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('should not modify state if no matching configurations exist', async () => {
salimtb marked this conversation as resolved.
Show resolved Hide resolved
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
Loading