1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Consolidate network stores (#18595)

* Consolidate network stores

The network controller used to have multiple different state stores,
which were composed together to form the main controller state store.
They have been consolidated into a single store. This required few
changes because most state access was already being done through the
composed store.

Fixes https://github.com/MetaMask/metamask-extension/issues/18303

* Add JSDoc comment
This commit is contained in:
Mark Stacey 2023-04-17 13:24:13 -02:30 committed by GitHub
parent 3588e6d28e
commit 39dff02a04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 88 deletions

View File

@ -1,6 +1,6 @@
import { strict as assert } from 'assert'; import { strict as assert } from 'assert';
import EventEmitter from 'events'; import EventEmitter from 'events';
import { ComposedStore, ObservableStore } from '@metamask/obs-store'; import { ObservableStore } from '@metamask/obs-store';
import log from 'loglevel'; import log from 'loglevel';
import { import {
createSwappableProxy, createSwappableProxy,
@ -379,6 +379,21 @@ function buildDefaultNetworkConfigurationsState(): NetworkConfigurations {
return {}; return {};
} }
/**
* Builds the default state for the network controller.
*
* @returns The default network controller state.
*/
function buildDefaultState() {
return {
provider: buildDefaultProviderConfigState(),
networkId: buildDefaultNetworkIdState(),
networkStatus: buildDefaultNetworkStatusState(),
networkDetails: buildDefaultNetworkDetailsState(),
networkConfigurations: buildDefaultNetworkConfigurationsState(),
};
}
/** /**
* Returns whether the given argument is a type that our Infura middleware * Returns whether the given argument is a type that our Infura middleware
* recognizes. We can't calculate this inline because the usual type of `type`, * recognizes. We can't calculate this inline because the usual type of `type`,
@ -414,43 +429,17 @@ export class NetworkController extends EventEmitter {
*/ */
#messenger: NetworkControllerMessenger; #messenger: NetworkControllerMessenger;
/**
* Observable store containing the provider configuration.
*/
providerStore: ObservableStore<ProviderConfiguration>;
/** /**
* Observable store containing the provider configuration for the previously * Observable store containing the provider configuration for the previously
* configured network. * configured network.
*/ */
#previousProviderConfig: ProviderConfiguration; #previousProviderConfig: ProviderConfiguration;
/**
* Observable store containing the network ID for the current network or null
* if there is no current network.
*/
networkIdStore: ObservableStore<NetworkIdState>;
/**
* Observable store for the network status.
*/
networkStatusStore: ObservableStore<NetworkStatus>;
/**
* Observable store for details about the network.
*/
networkDetails: ObservableStore<NetworkDetails>;
/**
* Observable store for network configurations.
*/
networkConfigurationsStore: ObservableStore<NetworkConfigurations>;
/** /**
* Observable store containing a combination of data from all of the * Observable store containing a combination of data from all of the
* individual stores. * individual stores.
*/ */
store: ComposedStore<NetworkControllerState>; store: ObservableStore<NetworkControllerState>;
#provider: SafeEventEmitterProvider | null; #provider: SafeEventEmitterProvider | null;
@ -484,35 +473,11 @@ export class NetworkController extends EventEmitter {
this.#messenger = messenger; this.#messenger = messenger;
// create stores this.store = new ObservableStore({
this.providerStore = new ObservableStore( ...buildDefaultState(),
state.provider || buildDefaultProviderConfigState(), ...state,
);
this.#previousProviderConfig = this.providerStore.getState();
this.networkIdStore = new ObservableStore(buildDefaultNetworkIdState());
this.networkStatusStore = new ObservableStore(
buildDefaultNetworkStatusState(),
);
// We need to keep track of a few details about the current network.
// Ideally we'd merge this.networkStatusStore with this new store, but doing
// so will require a decent sized refactor of how we're accessing network
// state. Currently this is only used for detecting EIP-1559 support but can
// be extended to track other network details.
this.networkDetails = new ObservableStore(
state.networkDetails || buildDefaultNetworkDetailsState(),
);
this.networkConfigurationsStore = new ObservableStore(
state.networkConfigurations || buildDefaultNetworkConfigurationsState(),
);
this.store = new ComposedStore<NetworkControllerState>({
provider: this.providerStore,
networkId: this.networkIdStore,
networkStatus: this.networkStatusStore,
networkDetails: this.networkDetails,
networkConfigurations: this.networkConfigurationsStore,
}); });
this.#previousProviderConfig = this.store.getState().provider;
// provider and block tracker // provider and block tracker
this.#provider = null; this.#provider = null;
@ -543,7 +508,7 @@ export class NetworkController extends EventEmitter {
* using the provider to gather details about the network. * using the provider to gather details about the network.
*/ */
async initializeProvider(): Promise<void> { async initializeProvider(): Promise<void> {
const { type, rpcUrl, chainId } = this.providerStore.getState(); const { type, rpcUrl, chainId } = this.store.getState().provider;
this.#configureProvider({ type, rpcUrl, chainId }); this.#configureProvider({ type, rpcUrl, chainId });
await this.lookupNetwork(); await this.lookupNetwork();
} }
@ -569,7 +534,7 @@ export class NetworkController extends EventEmitter {
* and false otherwise. * and false otherwise.
*/ */
async getEIP1559Compatibility(): Promise<boolean> { async getEIP1559Compatibility(): Promise<boolean> {
const { EIPS } = this.networkDetails.getState(); const { EIPS } = this.store.getState().networkDetails;
// NOTE: This isn't necessary anymore because the block cache middleware // NOTE: This isn't necessary anymore because the block cache middleware
// already prevents duplicate requests from taking place // already prevents duplicate requests from taking place
if (EIPS[1559] !== undefined) { if (EIPS[1559] !== undefined) {
@ -585,11 +550,15 @@ export class NetworkController extends EventEmitter {
} }
const supportsEIP1559 = await this.#determineEIP1559Compatibility(provider); const supportsEIP1559 = await this.#determineEIP1559Compatibility(provider);
this.networkDetails.updateState({ const { networkDetails } = this.store.getState();
this.store.updateState({
networkDetails: {
...networkDetails,
EIPS: { EIPS: {
...this.networkDetails.getState().EIPS, ...networkDetails.EIPS,
1559: supportsEIP1559, 1559: supportsEIP1559,
}, },
},
}); });
return supportsEIP1559; return supportsEIP1559;
} }
@ -606,7 +575,7 @@ export class NetworkController extends EventEmitter {
* blocking requests, or if the network is not Infura-supported. * blocking requests, or if the network is not Infura-supported.
*/ */
async lookupNetwork(): Promise<void> { async lookupNetwork(): Promise<void> {
const { chainId, type } = this.providerStore.getState(); const { chainId, type } = this.store.getState().provider;
const { provider } = this.getProviderAndBlockTracker(); const { provider } = this.getProviderAndBlockTracker();
let networkChanged = false; let networkChanged = false;
let networkId: NetworkIdState = null; let networkId: NetworkIdState = null;
@ -692,15 +661,21 @@ export class NetworkController extends EventEmitter {
listener, listener,
); );
this.networkStatusStore.putState(networkStatus); this.store.updateState({
networkStatus,
});
if (networkStatus === NetworkStatus.Available) { if (networkStatus === NetworkStatus.Available) {
this.networkIdStore.putState(networkId); const { networkDetails } = this.store.getState();
this.networkDetails.updateState({ this.store.updateState({
networkId,
networkDetails: {
...networkDetails,
EIPS: { EIPS: {
...this.networkDetails.getState().EIPS, ...networkDetails.EIPS,
1559: supportsEIP1559, 1559: supportsEIP1559,
}, },
},
}); });
} else { } else {
this.#resetNetworkId(); this.#resetNetworkId();
@ -731,7 +706,7 @@ export class NetworkController extends EventEmitter {
*/ */
setActiveNetwork(networkConfigurationId: NetworkConfigurationId): string { setActiveNetwork(networkConfigurationId: NetworkConfigurationId): string {
const targetNetwork = const targetNetwork =
this.networkConfigurationsStore.getState()[networkConfigurationId]; this.store.getState().networkConfigurations[networkConfigurationId];
if (!targetNetwork) { if (!targetNetwork) {
throw new Error( throw new Error(
@ -779,7 +754,7 @@ export class NetworkController extends EventEmitter {
* Re-initializes the provider and block tracker for the current network. * Re-initializes the provider and block tracker for the current network.
*/ */
resetConnection(): void { resetConnection(): void {
this.#setProviderConfig(this.providerStore.getState()); this.#setProviderConfig(this.store.getState().provider);
} }
/** /**
@ -789,7 +764,9 @@ export class NetworkController extends EventEmitter {
*/ */
async rollbackToPreviousProvider() { async rollbackToPreviousProvider() {
const config = this.#previousProviderConfig; const config = this.#previousProviderConfig;
this.providerStore.putState(config); this.store.updateState({
provider: config,
});
await this.#switchNetwork(config); await this.#switchNetwork(config);
} }
@ -843,21 +820,27 @@ export class NetworkController extends EventEmitter {
* Clears the stored network ID. * Clears the stored network ID.
*/ */
#resetNetworkId(): void { #resetNetworkId(): void {
this.networkIdStore.putState(buildDefaultNetworkIdState()); this.store.updateState({
networkId: buildDefaultNetworkIdState(),
});
} }
/** /**
* Resets network status to the default ("unknown"). * Resets network status to the default ("unknown").
*/ */
#resetNetworkStatus(): void { #resetNetworkStatus(): void {
this.networkStatusStore.putState(buildDefaultNetworkStatusState()); this.store.updateState({
networkStatus: buildDefaultNetworkStatusState(),
});
} }
/** /**
* Clears details previously stored for the network. * Clears details previously stored for the network.
*/ */
#resetNetworkDetails(): void { #resetNetworkDetails(): void {
this.networkDetails.putState(buildDefaultNetworkDetailsState()); this.store.updateState({
networkDetails: buildDefaultNetworkDetailsState(),
});
} }
/** /**
@ -867,8 +850,8 @@ export class NetworkController extends EventEmitter {
* @param providerConfig - The provider configuration. * @param providerConfig - The provider configuration.
*/ */
async #setProviderConfig(providerConfig: ProviderConfiguration) { async #setProviderConfig(providerConfig: ProviderConfiguration) {
this.#previousProviderConfig = this.providerStore.getState(); this.#previousProviderConfig = this.store.getState().provider;
this.providerStore.putState(providerConfig); this.store.updateState({ provider: providerConfig });
await this.#switchNetwork(providerConfig); await this.#switchNetwork(providerConfig);
} }
@ -1105,7 +1088,7 @@ export class NetworkController extends EventEmitter {
); );
} }
const networkConfigurations = this.networkConfigurationsStore.getState(); const { networkConfigurations } = this.store.getState();
const newNetworkConfiguration = { const newNetworkConfiguration = {
rpcUrl, rpcUrl,
chainId, chainId,
@ -1120,12 +1103,14 @@ export class NetworkController extends EventEmitter {
)?.id; )?.id;
const newNetworkConfigurationId = oldNetworkConfigurationId || uuid(); const newNetworkConfigurationId = oldNetworkConfigurationId || uuid();
this.networkConfigurationsStore.putState({ this.store.updateState({
networkConfigurations: {
...networkConfigurations, ...networkConfigurations,
[newNetworkConfigurationId]: { [newNetworkConfigurationId]: {
...newNetworkConfiguration, ...newNetworkConfiguration,
id: newNetworkConfigurationId, id: newNetworkConfigurationId,
}, },
},
}); });
if (!oldNetworkConfigurationId) { if (!oldNetworkConfigurationId) {
@ -1160,9 +1145,11 @@ export class NetworkController extends EventEmitter {
networkConfigurationId: NetworkConfigurationId, networkConfigurationId: NetworkConfigurationId,
): void { ): void {
const networkConfigurations = { const networkConfigurations = {
...this.networkConfigurationsStore.getState(), ...this.store.getState().networkConfigurations,
}; };
delete networkConfigurations[networkConfigurationId]; delete networkConfigurations[networkConfigurationId];
this.networkConfigurationsStore.putState(networkConfigurations); this.store.updateState({
networkConfigurations,
});
} }
} }

View File

@ -544,7 +544,7 @@ export default class MetamaskController extends EventEmitter {
messenger: currencyRateMessenger, messenger: currencyRateMessenger,
state: { state: {
...initState.CurrencyController, ...initState.CurrencyController,
nativeCurrency: this.networkController.providerStore.getState().ticker, nativeCurrency: this.networkController.store.getState().provider.ticker,
}, },
}); });
@ -981,8 +981,16 @@ export default class MetamaskController extends EventEmitter {
getNetworkId: () => this.networkController.store.getState().networkId, getNetworkId: () => this.networkController.store.getState().networkId,
getNetworkStatus: () => getNetworkStatus: () =>
this.networkController.store.getState().networkStatus, this.networkController.store.getState().networkStatus,
onNetworkStateChange: (listener) => onNetworkStateChange: (listener) => {
this.networkController.networkIdStore.subscribe(listener), let previousNetworkId =
this.networkController.store.getState().networkId;
this.networkController.store.subscribe((state) => {
if (previousNetworkId !== state.networkId) {
listener();
previousNetworkId = state.networkId;
}
});
},
getCurrentChainId: () => getCurrentChainId: () =>
this.networkController.store.getState().provider.chainId, this.networkController.store.getState().provider.chainId,
preferencesStore: this.preferencesController.store, preferencesStore: this.preferencesController.store,