From fc3011a84bd251960d05624909d32a0679b07bfc Mon Sep 17 00:00:00 2001 From: Zachary Belford Date: Fri, 25 Nov 2022 10:30:36 -0800 Subject: [PATCH 1/3] Moved subscribe and filter into network controller fixes #16573 --- .../controllers/network/createInfuraClient.js | 15 ++++++++++++++- .../controllers/network/createJsonRpcClient.js | 17 ++++++++++++++++- app/scripts/controllers/network/network.js | 7 ++++++- app/scripts/metamask-controller.js | 18 +----------------- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 111e742ce68a..fe03a9175963 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -10,6 +10,8 @@ import { import { createInfuraMiddleware } from '@metamask/eth-json-rpc-infura'; import { PollingBlockTracker } from 'eth-block-tracker'; +import createFilterMiddleware from 'eth-json-rpc-filters'; +import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; import { BUILT_IN_NETWORKS } from '../../../../shared/constants/network'; @@ -23,6 +25,15 @@ export default function createInfuraClient({ network, projectId }) { const infuraProvider = providerFromMiddleware(infuraMiddleware); const blockTracker = new PollingBlockTracker({ provider: infuraProvider }); + const filterMiddleware = createFilterMiddleware({ + infuraProvider, + blockTracker, + }); + const subscriptionManager = createSubscriptionManager({ + infuraProvider, + blockTracker, + }); + const networkMiddleware = mergeMiddleware([ createNetworkAndChainIdMiddleware({ network }), createBlockCacheMiddleware({ blockTracker }), @@ -31,8 +42,10 @@ export default function createInfuraClient({ network, projectId }) { createRetryOnEmptyMiddleware({ blockTracker, provider: infuraProvider }), createBlockTrackerInspectorMiddleware({ blockTracker }), infuraMiddleware, + filterMiddleware, + subscriptionManager.middleware, ]); - return { networkMiddleware, blockTracker }; + return { networkMiddleware, blockTracker, subscriptionManager }; } function createNetworkAndChainIdMiddleware({ network }) { diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index d4e412b8f79f..c958489ff39b 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -8,6 +8,8 @@ import { providerFromMiddleware, } from 'eth-json-rpc-middleware'; import { PollingBlockTracker } from 'eth-block-tracker'; +import createFilterMiddleware from 'eth-json-rpc-filters'; +import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; import { SECOND } from '../../../../shared/constants/time'; const inTest = process.env.IN_TEST; @@ -19,11 +21,22 @@ const getTestMiddlewares = () => { export default function createJsonRpcClient({ rpcUrl, chainId }) { const fetchMiddleware = createFetchMiddleware({ rpcUrl }); const blockProvider = providerFromMiddleware(fetchMiddleware); + + // create subscription polyfill middleware const blockTracker = new PollingBlockTracker({ ...blockTrackerOpts, provider: blockProvider, }); + const filterMiddleware = createFilterMiddleware({ + blockProvider, + blockTracker, + }); + const subscriptionManager = createSubscriptionManager({ + blockProvider, + blockTracker, + }); + const networkMiddleware = mergeMiddleware([ ...getTestMiddlewares(), createChainIdMiddleware(chainId), @@ -32,9 +45,11 @@ export default function createJsonRpcClient({ rpcUrl, chainId }) { createInflightCacheMiddleware(), createBlockTrackerInspectorMiddleware({ blockTracker }), fetchMiddleware, + filterMiddleware, + subscriptionManager.middleware, ]); - return { networkMiddleware, blockTracker }; + return { networkMiddleware, blockTracker, subscriptionManager }; } function createChainIdMiddleware(chainId) { diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index d0f6bdd65c2a..2b68205c1b11 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -433,11 +433,16 @@ export default class NetworkController extends EventEmitter { this._setNetworkClient(networkClient); } - _setNetworkClient({ networkMiddleware, blockTracker }) { + _setNetworkClient({ networkMiddleware, blockTracker, subscriptionManager }) { const metamaskMiddleware = createMetamaskMiddleware( this._baseProviderParams, ); const engine = new JsonRpcEngine(); + + subscriptionManager.events.on('notification', (message) => + engine.emit('notification', message), + ); + engine.push(metamaskMiddleware); engine.push(networkMiddleware); const provider = providerFromEngine(engine); diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 8e738f712ddf..c20475f97196 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -5,8 +5,6 @@ import { storeAsStream } from '@metamask/obs-store/dist/asStream'; import { JsonRpcEngine } from 'json-rpc-engine'; import { debounce } from 'lodash'; import createEngineStream from 'json-rpc-middleware-stream/engineStream'; -import createFilterMiddleware from 'eth-json-rpc-filters'; -import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; import { providerAsMiddleware } from 'eth-json-rpc-middleware'; import KeyringController from 'eth-keyring-controller'; import { @@ -3710,19 +3708,7 @@ export default class MetamaskController extends EventEmitter { setupProviderEngine({ origin, subjectType, sender, tabId }) { // setup json rpc engine stack const engine = new JsonRpcEngine(); - const { blockTracker, provider } = this; - - // create filter polyfill middleware - const filterMiddleware = createFilterMiddleware({ provider, blockTracker }); - - // create subscription polyfill middleware - const subscriptionManager = createSubscriptionManager({ - provider, - blockTracker, - }); - subscriptionManager.events.on('notification', (message) => - engine.emit('notification', message), - ); + const { provider } = this; // append origin to each request engine.push(createOriginMiddleware({ origin })); @@ -3890,8 +3876,6 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IN // filter and subscription polyfills - engine.push(filterMiddleware); - engine.push(subscriptionManager.middleware); if (subjectType !== SUBJECT_TYPES.INTERNAL) { // permissions engine.push( From e51455a36612ef7a1feb40880863e74c77b0b7f5 Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Fri, 16 Dec 2022 16:32:10 -0700 Subject: [PATCH 2/3] Remove extraneous comments --- app/scripts/controllers/network/createJsonRpcClient.js | 1 - app/scripts/metamask-controller.js | 1 - 2 files changed, 2 deletions(-) diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index c958489ff39b..edaf50d9a5bd 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -22,7 +22,6 @@ export default function createJsonRpcClient({ rpcUrl, chainId }) { const fetchMiddleware = createFetchMiddleware({ rpcUrl }); const blockProvider = providerFromMiddleware(fetchMiddleware); - // create subscription polyfill middleware const blockTracker = new PollingBlockTracker({ ...blockTrackerOpts, provider: blockProvider, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 3c2c3fc3cd62..6ed199afc090 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3905,7 +3905,6 @@ export default class MetamaskController extends EventEmitter { ); ///: END:ONLY_INCLUDE_IN - // filter and subscription polyfills if (subjectType !== SUBJECT_TYPES.INTERNAL) { // permissions engine.push( From 469bbed580be40d466cc76a97d7910f727eea5cb Mon Sep 17 00:00:00 2001 From: Elliot Winkler Date: Fri, 16 Dec 2022 16:58:43 -0700 Subject: [PATCH 3/3] Fix issues --- .../controllers/network/createInfuraClient.js | 15 +---------- .../network/createJsonRpcClient.js | 16 +----------- app/scripts/controllers/network/network.js | 25 ++++++++++++++++--- .../controllers/permissions/specifications.js | 2 ++ app/scripts/metamask-controller.js | 12 ++++++++- 5 files changed, 36 insertions(+), 34 deletions(-) diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index fe03a9175963..111e742ce68a 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -10,8 +10,6 @@ import { import { createInfuraMiddleware } from '@metamask/eth-json-rpc-infura'; import { PollingBlockTracker } from 'eth-block-tracker'; -import createFilterMiddleware from 'eth-json-rpc-filters'; -import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; import { BUILT_IN_NETWORKS } from '../../../../shared/constants/network'; @@ -25,15 +23,6 @@ export default function createInfuraClient({ network, projectId }) { const infuraProvider = providerFromMiddleware(infuraMiddleware); const blockTracker = new PollingBlockTracker({ provider: infuraProvider }); - const filterMiddleware = createFilterMiddleware({ - infuraProvider, - blockTracker, - }); - const subscriptionManager = createSubscriptionManager({ - infuraProvider, - blockTracker, - }); - const networkMiddleware = mergeMiddleware([ createNetworkAndChainIdMiddleware({ network }), createBlockCacheMiddleware({ blockTracker }), @@ -42,10 +31,8 @@ export default function createInfuraClient({ network, projectId }) { createRetryOnEmptyMiddleware({ blockTracker, provider: infuraProvider }), createBlockTrackerInspectorMiddleware({ blockTracker }), infuraMiddleware, - filterMiddleware, - subscriptionManager.middleware, ]); - return { networkMiddleware, blockTracker, subscriptionManager }; + return { networkMiddleware, blockTracker }; } function createNetworkAndChainIdMiddleware({ network }) { diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index edaf50d9a5bd..d4e412b8f79f 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -8,8 +8,6 @@ import { providerFromMiddleware, } from 'eth-json-rpc-middleware'; import { PollingBlockTracker } from 'eth-block-tracker'; -import createFilterMiddleware from 'eth-json-rpc-filters'; -import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; import { SECOND } from '../../../../shared/constants/time'; const inTest = process.env.IN_TEST; @@ -21,21 +19,11 @@ const getTestMiddlewares = () => { export default function createJsonRpcClient({ rpcUrl, chainId }) { const fetchMiddleware = createFetchMiddleware({ rpcUrl }); const blockProvider = providerFromMiddleware(fetchMiddleware); - const blockTracker = new PollingBlockTracker({ ...blockTrackerOpts, provider: blockProvider, }); - const filterMiddleware = createFilterMiddleware({ - blockProvider, - blockTracker, - }); - const subscriptionManager = createSubscriptionManager({ - blockProvider, - blockTracker, - }); - const networkMiddleware = mergeMiddleware([ ...getTestMiddlewares(), createChainIdMiddleware(chainId), @@ -44,11 +32,9 @@ export default function createJsonRpcClient({ rpcUrl, chainId }) { createInflightCacheMiddleware(), createBlockTrackerInspectorMiddleware({ blockTracker }), fetchMiddleware, - filterMiddleware, - subscriptionManager.middleware, ]); - return { networkMiddleware, blockTracker, subscriptionManager }; + return { networkMiddleware, blockTracker }; } function createChainIdMiddleware(chainId) { diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 61dc2c68760b..10fe0b78cb02 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -2,13 +2,18 @@ import { strict as assert } from 'assert'; import EventEmitter from 'events'; import { ComposedStore, ObservableStore } from '@metamask/obs-store'; import { JsonRpcEngine } from 'json-rpc-engine'; -import { providerFromEngine } from 'eth-json-rpc-middleware'; +import { + providerFromEngine, + providerFromMiddleware, +} from 'eth-json-rpc-middleware'; import log from 'loglevel'; import { createSwappableProxy, createEventEmitterProxy, } from 'swappable-obj-proxy'; import EthQuery from 'eth-query'; +import createFilterMiddleware from 'eth-json-rpc-filters'; +import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'; import { INFURA_PROVIDER_TYPES, BUILT_IN_NETWORKS, @@ -424,19 +429,31 @@ export default class NetworkController extends EventEmitter { this._setNetworkClient(networkClient); } - _setNetworkClient({ networkMiddleware, blockTracker, subscriptionManager }) { + _setNetworkClient({ networkMiddleware, blockTracker }) { + const networkProvider = providerFromMiddleware(networkMiddleware); + const filterMiddleware = createFilterMiddleware({ + provider: networkProvider, + blockTracker, + }); + const subscriptionManager = createSubscriptionManager({ + provider: networkProvider, + blockTracker, + }); const metamaskMiddleware = createMetamaskMiddleware( this._baseProviderParams, ); - const engine = new JsonRpcEngine(); + const engine = new JsonRpcEngine(); subscriptionManager.events.on('notification', (message) => engine.emit('notification', message), ); - + engine.push(filterMiddleware); + engine.push(subscriptionManager.middleware); engine.push(metamaskMiddleware); engine.push(networkMiddleware); + const provider = providerFromEngine(engine); + this._setProviderAndBlockTracker({ provider, blockTracker }); } diff --git a/app/scripts/controllers/permissions/specifications.js b/app/scripts/controllers/permissions/specifications.js index 4072398d12b9..3779a904a232 100644 --- a/app/scripts/controllers/permissions/specifications.js +++ b/app/scripts/controllers/permissions/specifications.js @@ -260,10 +260,12 @@ export const unrestrictedMethods = Object.freeze([ 'eth_signTypedData_v1', 'eth_signTypedData_v3', 'eth_signTypedData_v4', + 'eth_subscribe', 'eth_submitHashrate', 'eth_submitWork', 'eth_syncing', 'eth_uninstallFilter', + 'eth_unsubscribe', 'metamask_getProviderState', 'metamask_watchAsset', 'net_listening', diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 6ed199afc090..91441727b3fc 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -3732,9 +3732,19 @@ export default class MetamaskController extends EventEmitter { * @param {tabId} [options.tabId] - The tab ID of the sender - if the sender is within a tab */ setupProviderEngine({ origin, subjectType, sender, tabId }) { + const { provider } = this; + // setup json rpc engine stack const engine = new JsonRpcEngine(); - const { provider } = this; + + // forward notifications from network provider + provider.on('data', (error, message) => { + if (error) { + // This should never happen, this error parameter is never set + throw error; + } + engine.emit('notification', message); + }); if (isManifestV3) { engine.push(createDupeReqFilterMiddleware());