Handling infura blockage (#10883)

* Handling infura blockage

* Adding blockage home notification

* Updating copy, adding temporary notification dismissal

* Addressing review feedback

* Using eth_blockNumber method to check Infura availability

* Handling network changes in availability check
feature/default_network_editable
ryanml 4 years ago committed by Dan Miller
parent 14b5c389ed
commit 7c00ad0dde
  1. 4
      app/_locales/en/messages.json
  2. 55
      app/scripts/controllers/network/network.js
  3. 27
      app/scripts/controllers/preferences.js
  4. 2
      shared/constants/network.js
  5. 27
      ui/app/pages/home/home.component.js
  6. 2
      ui/app/pages/home/home.container.js
  7. 4
      ui/app/selectors/selectors.js

@ -878,6 +878,10 @@
"infoHelp": {
"message": "Info & Help"
},
"infuraBlockedNotification": {
"message": "MetaMask is unable to connect to the blockchain host. Review possible reasons $1.",
"description": "$1 is a clickable link with with text defined by the 'here' key"
},
"initialTransactionConfirmed": {
"message": "Your initial transaction was confirmed by the network. Click OK to go back."
},

@ -17,16 +17,19 @@ import {
NETWORK_TYPE_TO_ID_MAP,
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
INFURA_BLOCKED_KEY,
} from '../../../../shared/constants/network';
import {
isPrefixedFormattedHexString,
isSafeChainId,
} from '../../../../shared/modules/network.utils';
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout';
import createMetamaskMiddleware from './createMetamaskMiddleware';
import createInfuraClient from './createInfuraClient';
import createJsonRpcClient from './createJsonRpcClient';
const env = process.env.METAMASK_ENV;
const fetchWithTimeout = getFetchWithTimeout(30000);
let defaultProviderConfigOpts;
if (process.env.IN_TEST === 'true') {
@ -52,6 +55,10 @@ export const NETWORK_EVENTS = {
NETWORK_DID_CHANGE: 'networkDidChange',
// Fired when the actively selected network *will* change
NETWORK_WILL_CHANGE: 'networkWillChange',
// Fired when Infura returns an error indicating no support
INFURA_IS_BLOCKED: 'infuraIsBlocked',
// Fired when not using an Infura network or when Infura returns no error, indicating support
INFURA_IS_UNBLOCKED: 'infuraIsUnblocked',
};
export default class NetworkController extends EventEmitter {
@ -152,6 +159,15 @@ export default class NetworkController extends EventEmitter {
// Ping the RPC endpoint so we can confirm that it works
const ethQuery = new EthQuery(this._provider);
const initialNetwork = this.getNetworkState();
const { type } = this.getProviderConfig();
const isInfura = INFURA_PROVIDER_TYPES.includes(type);
if (isInfura) {
this._checkInfuraAvailability(type);
} else {
this.emit(NETWORK_EVENTS.INFURA_IS_UNBLOCKED);
}
ethQuery.sendAsync({ method: 'net_version' }, (err, networkVersion) => {
const currentNetwork = this.getNetworkState();
if (initialNetwork === currentNetwork) {
@ -235,6 +251,45 @@ export default class NetworkController extends EventEmitter {
// Private
//
async _checkInfuraAvailability(network) {
const rpcUrl = `https://${network}.infura.io/v3/${this._infuraProjectId}`;
let networkChanged = false;
this.once(NETWORK_EVENTS.NETWORK_DID_CHANGE, () => {
networkChanged = true;
});
try {
const response = await fetchWithTimeout(rpcUrl, {
method: 'POST',
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_blockNumber',
params: [],
id: 1,
}),
});
if (networkChanged) {
return;
}
if (response.ok) {
this.emit(NETWORK_EVENTS.INFURA_IS_UNBLOCKED);
} else {
const responseMessage = await response.json();
if (networkChanged) {
return;
}
if (responseMessage.error === INFURA_BLOCKED_KEY) {
this.emit(NETWORK_EVENTS.INFURA_IS_BLOCKED);
}
}
} catch (err) {
log.warn(`MetaMask - Infura availability check failed`, err);
}
}
_switchNetwork(opts) {
this.emit(NETWORK_EVENTS.NETWORK_WILL_CHANGE);
this.setNetworkState('loading');

@ -66,6 +66,7 @@ export default class PreferencesController {
completedOnboarding: false,
// ENS decentralized website resolution
ipfsGateway: 'dweb.link',
infuraBlocked: null,
...opts.initState,
};
@ -75,6 +76,7 @@ export default class PreferencesController {
this.openPopup = opts.openPopup;
this.migrateAddressBookState = opts.migrateAddressBookState;
this._subscribeToNetworkDidChange();
this._subscribeToInfuraAvailability();
global.setPreference = (key, value) => {
return this.setFeatureFlag(key, value);
@ -679,6 +681,31 @@ export default class PreferencesController {
});
}
_subscribeToInfuraAvailability() {
this.network.on(NETWORK_EVENTS.INFURA_IS_BLOCKED, () => {
this._setInfuraBlocked(true);
});
this.network.on(NETWORK_EVENTS.INFURA_IS_UNBLOCKED, () => {
this._setInfuraBlocked(false);
});
}
/**
*
* A setter for the `infuraBlocked` property
* @param {boolean} isBlocked - Bool indicating whether Infura is blocked
*
*/
_setInfuraBlocked(isBlocked) {
const { infuraBlocked } = this.store.getState();
if (infuraBlocked === isBlocked) {
return;
}
this.store.updateState({ infuraBlocked: isBlocked });
}
/**
* Updates `accountTokens`, `tokens`, `accountHiddenTokens` and `hiddenTokens` of current account and network according to it.
*

@ -93,3 +93,5 @@ export const NATIVE_CURRENCY_TOKEN_IMAGE_MAP = {
[TEST_ETH_SYMBOL]: TEST_ETH_TOKEN_IMAGE_URL,
[BNB_SYMBOL]: BNB_TOKEN_IMAGE_URL,
};
export const INFURA_BLOCKED_KEY = 'countryBlocked';

@ -34,6 +34,8 @@ const LEARN_MORE_URL =
'https://metamask.zendesk.com/hc/en-us/articles/360045129011-Intro-to-MetaMask-v8-extension';
const LEGACY_WEB3_URL =
'https://metamask.zendesk.com/hc/en-us/articles/360053147012';
const INFURA_BLOCKAGE_URL =
'https://metamask.zendesk.com/hc/en-us/articles/360059386712';
export default class Home extends PureComponent {
static contextTypes = {
@ -74,10 +76,12 @@ export default class Home extends PureComponent {
originOfCurrentTab: PropTypes.string,
disableWeb3ShimUsageAlert: PropTypes.func.isRequired,
pendingConfirmations: PropTypes.arrayOf(PropTypes.object).isRequired,
infuraBlocked: PropTypes.bool.isRequired,
};
state = {
mounted: false,
canShowBlockageNotification: true,
};
componentDidMount() {
@ -176,6 +180,7 @@ export default class Home extends PureComponent {
setWeb3ShimUsageAlertDismissed,
originOfCurrentTab,
disableWeb3ShimUsageAlert,
infuraBlocked,
} = this.props;
return (
@ -241,6 +246,28 @@ export default class Home extends PureComponent {
key="home-privacyModeDefault"
/>
) : null}
{infuraBlocked && this.state.canShowBlockageNotification ? (
<HomeNotification
descriptionText={t('infuraBlockedNotification', [
<span
key="infuraBlockedNotificationLink"
className="home-notification__text-link"
onClick={() =>
global.platform.openTab({ url: INFURA_BLOCKAGE_URL })
}
>
{t('here')}
</span>,
])}
ignoreText={t('dismiss')}
onIgnore={() => {
this.setState({
canShowBlockageNotification: false,
});
}}
key="home-infuraBlockedNotification"
/>
) : null}
</MultipleNotifications>
);
}

@ -11,6 +11,7 @@ import {
getUnapprovedTemplatedConfirmations,
getWeb3ShimUsageStateForOrigin,
unconfirmedTransactionsCountSelector,
getInfuraBlocked,
} from '../../selectors';
import {
@ -104,6 +105,7 @@ const mapStateToProps = (state) => {
originOfCurrentTab,
shouldShowWeb3ShimUsageNotification,
pendingConfirmations,
infuraBlocked: getInfuraBlocked(state),
};
};

@ -419,6 +419,10 @@ export function getIpfsGateway(state) {
return state.metamask.ipfsGateway;
}
export function getInfuraBlocked(state) {
return Boolean(state.metamask.infuraBlocked);
}
export function getUSDConversionRate(state) {
return state.metamask.usdConversionRate;
}

Loading…
Cancel
Save