From 088d7930e0895ef1802823c5fc843dd1c19b9661 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 20:46:34 -0700 Subject: network - create provider and block-tracker via json-rpc-engine --- .../controllers/network/createInfuraClient.js | 34 ++++++ .../controllers/network/createJsonRpcClient.js | 35 +++++++ .../controllers/network/createLocalhostClient.js | 33 ++++++ .../network/createMetamaskMiddleware.js | 43 ++++++++ app/scripts/controllers/network/network.js | 116 +++++++++++---------- app/scripts/controllers/transactions/index.js | 1 + .../controllers/transactions/nonce-tracker.js | 18 +--- app/scripts/metamask-controller.js | 7 +- 8 files changed, 217 insertions(+), 70 deletions(-) create mode 100644 app/scripts/controllers/network/createInfuraClient.js create mode 100644 app/scripts/controllers/network/createJsonRpcClient.js create mode 100644 app/scripts/controllers/network/createLocalhostClient.js create mode 100644 app/scripts/controllers/network/createMetamaskMiddleware.js (limited to 'app') diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js new file mode 100644 index 000000000..e346f4bcb --- /dev/null +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -0,0 +1,34 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const BlockTracker = require('eth-block-tracker') + +module.exports = createInfuraClient + +function createInfuraClient({ network }) { + const infuraMiddleware = createInfuraMiddleware({ network }) + const blockProvider = providerFromMiddleware(infuraMiddleware) + const blockTracker = new BlockTracker({ provider: blockProvider }) + + const networkMiddleware = mergeMiddleware([ + createBlockRefMiddleware({ blockTracker }), + createBlockCacheMiddleware({ blockTracker }), + createInflightMiddleware(), + createBlockTrackerInspectorMiddleware({ blockTracker }), + infuraMiddleware, + ]) + return { networkMiddleware, blockTracker } +} + +// inspect if response contains a block ref higher than our latest block +const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] +function createBlockTrackerInspectorMiddleware ({ blockTracker }) { + return createAsyncMiddleware(async (req, res, next) => { + if (!futureBlockRefRequests.includes(req.method)) return next() + await next() + const blockNumber = Number.parseInt(res.result.blockNumber, 16) + const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) + if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() + }) +} diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js new file mode 100644 index 000000000..5a8e85c23 --- /dev/null +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -0,0 +1,35 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const BlockTracker = require('eth-block-tracker') + +module.exports = createJsonRpcClient + +function createJsonRpcClient({ rpcUrl }) { + const fetchMiddleware = createFetchMiddleware({ rpcUrl }) + const blockProvider = providerFromMiddleware(fetchMiddleware) + const blockTracker = new BlockTracker({ provider: blockProvider }) + + const networkMiddleware = mergeMiddleware([ + createBlockRefMiddleware({ blockTracker }), + createBlockCacheMiddleware({ blockTracker }), + createInflightMiddleware(), + createBlockTrackerInspectorMiddleware({ blockTracker }), + fetchMiddleware, + ]) + return { networkMiddleware, blockTracker } +} + +// inspect if response contains a block ref higher than our latest block +const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] +function createBlockTrackerInspectorMiddleware ({ blockTracker }) { + return createAsyncMiddleware(async (req, res, next) => { + if (!futureBlockRefRequests.includes(req.method)) return next() + await next() + const blockNumber = Number.parseInt(res.result.blockNumber, 16) + const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) + if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() + }) +} diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js new file mode 100644 index 000000000..404415532 --- /dev/null +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -0,0 +1,33 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const BlockTracker = require('eth-block-tracker') + +module.exports = createLocalhostClient + +function createLocalhostClient() { + const fetchMiddleware = createFetchMiddleware({ rpcUrl: 'http://localhost:8545/' }) + const blockProvider = providerFromMiddleware(fetchMiddleware) + const blockTracker = new BlockTracker({ provider: blockProvider, pollingInterval: 1000 }) + + const networkMiddleware = mergeMiddleware([ + createBlockRefMiddleware({ blockTracker }), + createBlockTrackerInspectorMiddleware({ blockTracker }), + fetchMiddleware, + ]) + return { networkMiddleware, blockTracker } +} + +// inspect if response contains a block ref higher than our latest block +const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] +function createBlockTrackerInspectorMiddleware ({ blockTracker }) { + return createAsyncMiddleware(async (req, res, next) => { + if (!futureBlockRefRequests.includes(req.method)) return next() + await next() + const blockNumber = Number.parseInt(res.result.blockNumber, 16) + const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) + if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() + }) +} diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js new file mode 100644 index 000000000..1974c231d --- /dev/null +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -0,0 +1,43 @@ +const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') +const createScaffoldMiddleware = require('json-rpc-engine/src/scaffold') +const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') +const createWalletSubprovider = require('eth-json-rpc-middleware/wallet') + +module.exports = createMetamaskMiddleware + +function createMetamaskMiddleware({ + version, + getAccounts, + processTransaction, + processEthSignMessage, + processTypedMessage, + processPersonalMessage, + getPendingNonce +}) { + const metamaskMiddleware = mergeMiddleware([ + createScaffoldMiddleware({ + // staticSubprovider + eth_syncing: false, + web3_clientVersion: `MetaMask/v${version}`, + }), + createWalletSubprovider({ + getAccounts, + processTransaction, + processEthSignMessage, + processTypedMessage, + processPersonalMessage, + }), + createPendingNonceMiddleware({ getPendingNonce }), + }) + return metamaskMiddleware +} + +function createPendingNonceMiddleware ({ getPendingNonce }) { + return createAsyncMiddleware(async (req, res, next) => { + if (req.method !== 'eth_getTransactionCount') return next() + const address = req.params[0] + const blockRef = req.params[1] + if (blockRef !== 'pending') return next() + req.result = await getPendingNonce(address) + }) +} diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 93fde7c57..c882c7d75 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -1,14 +1,17 @@ const assert = require('assert') const EventEmitter = require('events') -const createMetamaskProvider = require('web3-provider-engine/zero.js') -const SubproviderFromProvider = require('web3-provider-engine/subproviders/provider.js') -const createInfuraProvider = require('eth-json-rpc-infura/src/createProvider') const ObservableStore = require('obs-store') const ComposedStore = require('obs-store/lib/composed') const extend = require('xtend') const EthQuery = require('eth-query') -const createEventEmitterProxy = require('../../lib/events-proxy.js') const log = require('loglevel') +const createMetamaskMiddleware = require('./createMetamaskMiddleware') +const createInfuraClient = require('./createInfuraClient') +const createJsonRpcClient = require('./createJsonRpcClient') +const createLocalhostClient = require('./createLocalhostClient') +// const createEventEmitterProxy = require('../../lib/events-proxy.js') +const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') + const { ROPSTEN, RINKEBY, @@ -38,21 +41,27 @@ module.exports = class NetworkController extends EventEmitter { this.providerStore = new ObservableStore(providerConfig) this.networkStore = new ObservableStore('loading') this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore }) - // create event emitter proxy - this._proxy = createEventEmitterProxy() - this.on('networkDidChange', this.lookupNetwork) + // provider and block tracker + this._provider = null + this._blockTracker = null + // provider and block tracker proxies - because the network changes + this._providerProxy = null + this._blockTrackerProxy = null } - initializeProvider (_providerParams) { - this._baseProviderParams = _providerParams + initializeProvider (providerParams) { + this._baseProviderParams = providerParams const { type, rpcTarget } = this.providerStore.getState() this._configureProvider({ type, rpcTarget }) - this._proxy.on('block', this._logBlock.bind(this)) - this._proxy.on('error', this.verifyNetwork.bind(this)) - this.ethQuery = new EthQuery(this._proxy) this.lookupNetwork() - return this._proxy + } + + // return the proxies so the references will always be good + getProviderAndBlockTracker() { + const provider = this._providerProxy + const blockTracker = this._blockTracker + return { provider, blockTracker } } verifyNetwork () { @@ -74,10 +83,11 @@ module.exports = class NetworkController extends EventEmitter { lookupNetwork () { // Prevent firing when provider is not defined. - if (!this.ethQuery || !this.ethQuery.sendAsync) { - return log.warn('NetworkController - lookupNetwork aborted due to missing ethQuery') + if (!this._provider) { + return log.warn('NetworkController - lookupNetwork aborted due to missing provider') } - this.ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { + const ethQuery = new EthQuery(this._provider) + ethQuery.sendAsync({ method: 'net_version' }, (err, network) => { if (err) return this.setNetworkState('loading') log.info('web3.getNetwork returned ' + network) this.setNetworkState(network) @@ -123,7 +133,7 @@ module.exports = class NetworkController extends EventEmitter { this._configureInfuraProvider(opts) // other type-based rpc endpoints } else if (type === LOCALHOST) { - this._configureStandardProvider({ rpcUrl: LOCALHOST_RPC_URL }) + this._configureLocalhostProvider() // url-based rpc endpoints } else if (type === 'rpc'){ this._configureStandardProvider({ rpcUrl: rpcTarget }) @@ -133,47 +143,47 @@ module.exports = class NetworkController extends EventEmitter { } _configureInfuraProvider ({ type }) { - log.info('_configureInfuraProvider', type) - const infuraProvider = createInfuraProvider({ network: type }) - const infuraSubprovider = new SubproviderFromProvider(infuraProvider) - const providerParams = extend(this._baseProviderParams, { - engineParams: { - pollingInterval: 8000, - blockTrackerProvider: infuraProvider, - }, - dataSubprovider: infuraSubprovider, - }) - const provider = createMetamaskProvider(providerParams) - this._setProvider(provider) + log.info('NetworkController - configureInfuraProvider', type) + const networkClient = createInfuraClient({ network: type }) + this._setNetworkClient(networkClient) + } + + _configureLocalhostProvider () { + log.info('NetworkController - configureLocalhostProvider') + const networkClient = createLocalhostClient() + this._setNetworkClient(networkClient) } _configureStandardProvider ({ rpcUrl }) { - const providerParams = extend(this._baseProviderParams, { - rpcUrl, - engineParams: { - pollingInterval: 8000, - }, - }) - const provider = createMetamaskProvider(providerParams) - this._setProvider(provider) - } - - _setProvider (provider) { - // collect old block tracker events - const oldProvider = this._provider - let blockTrackerHandlers - if (oldProvider) { - // capture old block handlers - blockTrackerHandlers = oldProvider._blockTracker.proxyEventHandlers - // tear down - oldProvider.removeAllListeners() - oldProvider.stop() + log.info('NetworkController - configureStandardProvider', rpcUrl) + const networkClient = createJsonRpcClient({ rpcUrl }) + this._setNetworkClient(networkClient) + } + + _setNetworkClient ({ networkMiddleware, blockTracker }) { + const metamaskMiddleware = createMetamaskMiddleware(this._baseProviderParams) + const engine = new JsonRpcEngine() + engine.push(metamaskMiddleware) + engine.push(networkMiddleware) + const provider = providerFromEngine(engine) + this._setProviderAndBlockTracker({ provider, blockTracker }) + } + + _setProviderAndBlockTracker ({ provider, blockTracker }) { + // update or intialize proxies + if (this._providerProxy) { + this._providerProxy.setTarget(provider) + } else { + this._providerProxy = createSwappableProxy(provider) + } + if (this._blockTrackerProxy) { + this._blockTrackerProxy.setTarget(blockTracker) + } else { + this._blockTrackerProxy = createEventEmitterProxy(blockTracker) } - // override block tracler - provider._blockTracker = createEventEmitterProxy(provider._blockTracker, blockTrackerHandlers) - // set as new provider + // set new provider and blockTracker this._provider = provider - this._proxy.setTarget(provider) + this._blockTracker = blockTracker } _logBlock (block) { diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 3886db104..cb3d28f1d 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -63,6 +63,7 @@ class TransactionController extends EventEmitter { this.store = this.txStateManager.store this.nonceTracker = new NonceTracker({ provider: this.provider, + blockTracker: this.blockTracker, getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager), getConfirmedTransactions: this.txStateManager.getConfirmedTransactions.bind(this.txStateManager), }) diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js index f8cdc5523..490118c89 100644 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ b/app/scripts/controllers/transactions/nonce-tracker.js @@ -12,8 +12,9 @@ const Mutex = require('await-semaphore').Mutex */ class NonceTracker { - constructor ({ provider, getPendingTransactions, getConfirmedTransactions }) { + constructor ({ provider, blockTracker, getPendingTransactions, getConfirmedTransactions }) { this.provider = provider + this.blockTracker = blockTracker this.ethQuery = new EthQuery(provider) this.getPendingTransactions = getPendingTransactions this.getConfirmedTransactions = getConfirmedTransactions @@ -75,11 +76,10 @@ class NonceTracker { } async _getCurrentBlock () { - const blockTracker = this._getBlockTracker() - const currentBlock = blockTracker.getCurrentBlock() + const currentBlock = this.blockTracker.getCurrentBlock() if (currentBlock) return currentBlock return await new Promise((reject, resolve) => { - blockTracker.once('latest', resolve) + this.blockTracker.once('latest', resolve) }) } @@ -171,16 +171,6 @@ class NonceTracker { return { name: 'local', nonce: highest, details: { startPoint, highest } } } - - // this is a hotfix for the fact that the blockTracker will - // change when the network changes - - /** - @returns {Object} the current blockTracker - */ - _getBlockTracker () { - return this.provider._blockTracker - } } module.exports = NonceTracker diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index a6b5d3453..7f4f2fc9b 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -103,8 +103,9 @@ module.exports = class MetamaskController extends EventEmitter { this.blacklistController.scheduleUpdates() // rpc provider - this.provider = this.initializeProvider() - this.blockTracker = this.provider._blockTracker + this.initializeProvider() + this.provider = this.networkController.getProviderAndBlockTracker().provider + this.blockTracker = this.networkController.getProviderAndBlockTracker().blockTracker // token exchange rate tracker this.tokenRatesController = new TokenRatesController({ @@ -1033,7 +1034,7 @@ module.exports = class MetamaskController extends EventEmitter { // create filter polyfill middleware const filterMiddleware = createFilterMiddleware({ provider: this.provider, - blockTracker: this.provider._blockTracker, + blockTracker: this.blockTracker, }) engine.push(createOriginMiddleware({ origin })) -- cgit v1.2.3 From b6eff15bd25ca30ba8a746eff2beec1c820b8855 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:08:19 -0700 Subject: lint fix --- app/scripts/controllers/network/createInfuraClient.js | 7 +++++-- app/scripts/controllers/network/createJsonRpcClient.js | 6 ++++-- app/scripts/controllers/network/createLocalhostClient.js | 4 ++-- app/scripts/controllers/network/createMetamaskMiddleware.js | 6 +++--- app/scripts/controllers/network/network.js | 8 ++++---- 5 files changed, 18 insertions(+), 13 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index e346f4bcb..528be80ce 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,12 +1,15 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') +const createInfuraMiddleware = require('eth-json-rpc-infura') const BlockTracker = require('eth-block-tracker') module.exports = createInfuraClient -function createInfuraClient({ network }) { +function createInfuraClient ({ network }) { const infuraMiddleware = createInfuraMiddleware({ network }) const blockProvider = providerFromMiddleware(infuraMiddleware) const blockTracker = new BlockTracker({ provider: blockProvider }) diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index 5a8e85c23..f8b67aa26 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -2,12 +2,14 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') module.exports = createJsonRpcClient -function createJsonRpcClient({ rpcUrl }) { +function createJsonRpcClient ({ rpcUrl }) { const fetchMiddleware = createFetchMiddleware({ rpcUrl }) const blockProvider = providerFromMiddleware(fetchMiddleware) const blockTracker = new BlockTracker({ provider: blockProvider }) diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js index 404415532..990dc6a95 100644 --- a/app/scripts/controllers/network/createLocalhostClient.js +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -2,12 +2,12 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-cache') +const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') module.exports = createLocalhostClient -function createLocalhostClient() { +function createLocalhostClient () { const fetchMiddleware = createFetchMiddleware({ rpcUrl: 'http://localhost:8545/' }) const blockProvider = providerFromMiddleware(fetchMiddleware) const blockTracker = new BlockTracker({ provider: blockProvider, pollingInterval: 1000 }) diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index 1974c231d..7dbd90d7f 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -5,14 +5,14 @@ const createWalletSubprovider = require('eth-json-rpc-middleware/wallet') module.exports = createMetamaskMiddleware -function createMetamaskMiddleware({ +function createMetamaskMiddleware ({ version, getAccounts, processTransaction, processEthSignMessage, processTypedMessage, processPersonalMessage, - getPendingNonce + getPendingNonce, }) { const metamaskMiddleware = mergeMiddleware([ createScaffoldMiddleware({ @@ -28,7 +28,7 @@ function createMetamaskMiddleware({ processPersonalMessage, }), createPendingNonceMiddleware({ getPendingNonce }), - }) + ]) return metamaskMiddleware } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index c882c7d75..a8c45a79c 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -2,8 +2,9 @@ const assert = require('assert') const EventEmitter = require('events') const ObservableStore = require('obs-store') const ComposedStore = require('obs-store/lib/composed') -const extend = require('xtend') const EthQuery = require('eth-query') +const JsonRpcEngine = require('json-rpc-engine') +const providerFromEngine = require('eth-json-rpc-middle/providerFromEngine') const log = require('loglevel') const createMetamaskMiddleware = require('./createMetamaskMiddleware') const createInfuraClient = require('./createInfuraClient') @@ -19,7 +20,6 @@ const { MAINNET, LOCALHOST, } = require('./enums') -const LOCALHOST_RPC_URL = 'http://localhost:8545' const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET] const env = process.env.METAMASK_ENV @@ -58,7 +58,7 @@ module.exports = class NetworkController extends EventEmitter { } // return the proxies so the references will always be good - getProviderAndBlockTracker() { + getProviderAndBlockTracker () { const provider = this._providerProxy const blockTracker = this._blockTracker return { provider, blockTracker } @@ -135,7 +135,7 @@ module.exports = class NetworkController extends EventEmitter { } else if (type === LOCALHOST) { this._configureLocalhostProvider() // url-based rpc endpoints - } else if (type === 'rpc'){ + } else if (type === 'rpc') { this._configureStandardProvider({ rpcUrl: rpcTarget }) } else { throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`) -- cgit v1.2.3 From 3e04840a7104849e9329b8faa4730554b2438217 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:10:41 -0700 Subject: remove unused events-proxy, was replaced with module swappable-obj-proxy --- app/scripts/controllers/network/network.js | 1 - app/scripts/lib/events-proxy.js | 42 ------------------------------ 2 files changed, 43 deletions(-) delete mode 100644 app/scripts/lib/events-proxy.js (limited to 'app') diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index a8c45a79c..213013cca 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -10,7 +10,6 @@ const createMetamaskMiddleware = require('./createMetamaskMiddleware') const createInfuraClient = require('./createInfuraClient') const createJsonRpcClient = require('./createJsonRpcClient') const createLocalhostClient = require('./createLocalhostClient') -// const createEventEmitterProxy = require('../../lib/events-proxy.js') const { createSwappableProxy, createEventEmitterProxy } = require('swappable-obj-proxy') const { diff --git a/app/scripts/lib/events-proxy.js b/app/scripts/lib/events-proxy.js deleted file mode 100644 index f83773ccc..000000000 --- a/app/scripts/lib/events-proxy.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Returns an EventEmitter that proxies events from the given event emitter - * @param {any} eventEmitter - * @param {object} listeners - The listeners to proxy to - * @returns {any} - */ -module.exports = function createEventEmitterProxy (eventEmitter, listeners) { - let target = eventEmitter - const eventHandlers = listeners || {} - const proxy = /** @type {any} */ (new Proxy({}, { - get: (_, name) => { - // intercept listeners - if (name === 'on') return addListener - if (name === 'setTarget') return setTarget - if (name === 'proxyEventHandlers') return eventHandlers - return (/** @type {any} */ (target))[name] - }, - set: (_, name, value) => { - target[name] = value - return true - }, - })) - function setTarget (/** @type {EventEmitter} */ eventEmitter) { - target = eventEmitter - // migrate listeners - Object.keys(eventHandlers).forEach((name) => { - /** @type {Array} */ (eventHandlers[name]).forEach((handler) => target.on(name, handler)) - }) - } - /** - * Attaches a function to be called whenever the specified event is emitted - * @param {string} name - * @param {Function} handler - */ - function addListener (name, handler) { - if (!eventHandlers[name]) eventHandlers[name] = [] - eventHandlers[name].push(handler) - target.on(name, handler) - } - if (listeners) proxy.setTarget(eventEmitter) - return proxy -} -- cgit v1.2.3 From 623533ab1508c93f0c347f0c4a1002ce93ff1ae2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:13:53 -0700 Subject: recent-blocks - update for eth-block-tracker@4 --- app/scripts/controllers/recent-blocks.js | 41 +++++++++++--------------------- 1 file changed, 14 insertions(+), 27 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 1377c1ba9..4101814eb 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -3,6 +3,8 @@ const extend = require('xtend') const BN = require('ethereumjs-util').BN const EthQuery = require('eth-query') const log = require('loglevel') +const pify = require('pify') +const timeout = (duration) => new Promise(resolve => setTimeout(duration, resolve)) class RecentBlocksController { @@ -34,7 +36,7 @@ class RecentBlocksController { }, opts.initState) this.store = new ObservableStore(initState) - this.blockTracker.on('block', this.processBlock.bind(this)) + this.blockTracker.on('latest', this.processBlock.bind(this)) this.backfill() } @@ -55,7 +57,10 @@ class RecentBlocksController { * @param {object} newBlock The new block to modify and add to the recentBlocks array * */ - processBlock (newBlock) { + async processBlock (newBlockNumberHex) { + const newBlockNumber = Number.parseInt(newBlockNumberHex, 16) + const newBlock = await this.getBlockByNumber(newBlockNumber) + const block = this.mapTransactionsToPrices(newBlock) const state = this.store.getState() @@ -118,17 +123,16 @@ class RecentBlocksController { * @returns {Promise} Promises undefined */ async backfill() { - this.blockTracker.once('block', async (block) => { - let blockNum = block.number + this.blockTracker.once('latest', async (blockNumberHex) => { let recentBlocks + const blockNumber = Number.parseInt(blockNumberHex, 16) let state = this.store.getState() recentBlocks = state.recentBlocks while (recentBlocks.length < this.historyLength) { try { - let blockNumBn = new BN(blockNum.substr(2), 16) - const newNum = blockNumBn.subn(1).toString(10) - const newBlock = await this.getBlockByNumber(newNum) + const prevBlockNumber = blockNumber - 1 + const newBlock = await this.getBlockByNumber(prevBlockNumber) if (newBlock) { this.backfillBlock(newBlock) @@ -140,23 +144,11 @@ class RecentBlocksController { } catch (e) { log.error(e) } - await this.wait() + await timeout(100) } }) } - /** - * A helper for this.backfill. Provides an easy way to ensure a 100 millisecond delay using await - * - * @returns {Promise} Promises undefined - * - */ - async wait () { - return new Promise((resolve) => { - setTimeout(resolve, 100) - }) - } - /** * Uses EthQuery to get a block that has a given block number. * @@ -165,13 +157,8 @@ class RecentBlocksController { * */ async getBlockByNumber (number) { - const bn = new BN(number) - return new Promise((resolve, reject) => { - this.ethQuery.getBlockByNumber('0x' + bn.toString(16), true, (err, block) => { - if (err) reject(err) - resolve(block) - }) - }) + const blockNumberHex = '0x' + number.toString(16) + return await pify(this.ethQuery.getBlockByNumber).call(this.ethQuery, blockNumberHex, true) } } -- cgit v1.2.3 From 32b3b8f2a76b4a67fde2a3af2ddd239998c5dfcd Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 21:16:05 -0700 Subject: controllers - balance - update for eth-block-tracker@4 --- app/scripts/controllers/balance.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/balance.js b/app/scripts/controllers/balance.js index 86619fce1..465751e61 100644 --- a/app/scripts/controllers/balance.js +++ b/app/scripts/controllers/balance.js @@ -60,7 +60,7 @@ class BalanceController { * Sets up listeners and subscriptions which should trigger an update of ethBalance. These updates include: * - when a transaction changes state to 'submitted', 'confirmed' or 'failed' * - when the current account changes (i.e. a new account is selected) - * - when there is a block update + * - when there is a block update * * @private * @@ -80,7 +80,7 @@ class BalanceController { } }) this.accountTracker.store.subscribe(update) - this.blockTracker.on('block', update) + this.blockTracker.on('latest', update) } /** @@ -100,7 +100,7 @@ class BalanceController { /** * Gets the pending transactions (i.e. those with a 'submitted' status). These are accessed from the - * TransactionController passed to this BalanceController during construction. + * TransactionController passed to this BalanceController during construction. * * @private * @returns {Promise} Promises an array of transaction objects. -- cgit v1.2.3 From 08dc238c9fdb23997a7fbdf57de5305455d1d930 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 22:46:11 -0700 Subject: deps - fix incorrect dep paths and versions --- app/scripts/controllers/network/createInfuraClient.js | 2 +- app/scripts/controllers/network/createJsonRpcClient.js | 2 +- app/scripts/controllers/network/createMetamaskMiddleware.js | 2 +- app/scripts/controllers/network/network.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 528be80ce..adbf4c001 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -2,7 +2,7 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') -const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const createInfuraMiddleware = require('eth-json-rpc-infura') const BlockTracker = require('eth-block-tracker') diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index f8b67aa26..d712ed135 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -3,7 +3,7 @@ const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') -const createInflightMiddleware = require('eth-json-rpc-middleware/inflight') +const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') diff --git a/app/scripts/controllers/network/createMetamaskMiddleware.js b/app/scripts/controllers/network/createMetamaskMiddleware.js index 7dbd90d7f..8b17829b7 100644 --- a/app/scripts/controllers/network/createMetamaskMiddleware.js +++ b/app/scripts/controllers/network/createMetamaskMiddleware.js @@ -1,5 +1,5 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createScaffoldMiddleware = require('json-rpc-engine/src/scaffold') +const createScaffoldMiddleware = require('json-rpc-engine/src/createScaffoldMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createWalletSubprovider = require('eth-json-rpc-middleware/wallet') diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 213013cca..9e622981b 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -4,7 +4,7 @@ const ObservableStore = require('obs-store') const ComposedStore = require('obs-store/lib/composed') const EthQuery = require('eth-query') const JsonRpcEngine = require('json-rpc-engine') -const providerFromEngine = require('eth-json-rpc-middle/providerFromEngine') +const providerFromEngine = require('eth-json-rpc-middleware/providerFromEngine') const log = require('loglevel') const createMetamaskMiddleware = require('./createMetamaskMiddleware') const createInfuraClient = require('./createInfuraClient') -- cgit v1.2.3 From 41c04ef7219eafeca71bcd577abe6bca3a637a89 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 16 May 2018 23:13:25 -0700 Subject: controllers - recent-blocks - fix pifyd setTimeout args --- app/scripts/controllers/recent-blocks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 4101814eb..28eba0f26 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -4,7 +4,7 @@ const BN = require('ethereumjs-util').BN const EthQuery = require('eth-query') const log = require('loglevel') const pify = require('pify') -const timeout = (duration) => new Promise(resolve => setTimeout(duration, resolve)) +const timeout = (duration) => new Promise(resolve => setTimeout(resolve, duration)) class RecentBlocksController { -- cgit v1.2.3 From 3084dc47d10e3e455c924e5aad0b0961c500ec8d Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 17 May 2018 00:13:20 -0700 Subject: recent-blocks - fix backfill blockNumber tracking --- app/scripts/controllers/recent-blocks.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 28eba0f26..9a215d0e5 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -1,6 +1,5 @@ const ObservableStore = require('obs-store') const extend = require('xtend') -const BN = require('ethereumjs-util').BN const EthQuery = require('eth-query') const log = require('loglevel') const pify = require('pify') @@ -125,7 +124,7 @@ class RecentBlocksController { async backfill() { this.blockTracker.once('latest', async (blockNumberHex) => { let recentBlocks - const blockNumber = Number.parseInt(blockNumberHex, 16) + let blockNumber = Number.parseInt(blockNumberHex, 16) let state = this.store.getState() recentBlocks = state.recentBlocks @@ -136,7 +135,7 @@ class RecentBlocksController { if (newBlock) { this.backfillBlock(newBlock) - blockNum = newBlock.number + blockNumber = Number.parseInt(newBlock.number, 16) } state = this.store.getState() -- cgit v1.2.3 From 10aecf49227098fb7fdbd7db193a9dcc6fecf5af Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 22 May 2018 16:40:01 -0700 Subject: remove dependance on the even tx:confirmed --- app/scripts/controllers/transactions/index.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index cb3d28f1d..313b20675 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -57,6 +57,7 @@ class TransactionController extends EventEmitter { initState: opts.initState, txHistoryLimit: opts.txHistoryLimit, getNetwork: this.getNetwork.bind(this), + confirmTransaction: this.confirmTransaction.bind(this), }) this._onBootCleanUp() @@ -316,6 +317,11 @@ class TransactionController extends EventEmitter { this.txStateManager.setTxStatusSubmitted(txId) } + confirmTransaction (txId) { + this.txStateManager.setTxStatusConfirmed(txId) + this._markNonceDuplicatesDropped(txId) + } + /** Convenience method for the ui thats sets the transaction to rejected @param txId {number} - the tx's Id @@ -396,8 +402,6 @@ class TransactionController extends EventEmitter { this.pendingTxTracker.on('tx:warning', (txMeta) => { this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') }) - this.pendingTxTracker.on('tx:confirmed', (txId) => this.txStateManager.setTxStatusConfirmed(txId)) - this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId)) this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => { if (!txMeta.firstRetryBlockNumber) { -- cgit v1.2.3 From c4b09da34e9950ea485dfecb810726e49b683dcd Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 22 May 2018 16:41:00 -0700 Subject: transactions - update pending-tx-tracker to use the new block tracker --- .../controllers/transactions/pending-tx-tracker.js | 25 ++++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 6e2fcb40b..bd26a72d9 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -27,6 +27,7 @@ class PendingTransactionTracker extends EventEmitter { this.getPendingTransactions = config.getPendingTransactions this.getCompletedTransactions = config.getCompletedTransactions this.publishTransaction = config.publishTransaction + this.confirmTransaction = config.confirmTransaction this._checkPendingTxs() } @@ -37,7 +38,8 @@ class PendingTransactionTracker extends EventEmitter { @emits tx:confirmed @emits tx:failed */ - checkForTxInBlock (block) { + async checkForTxInBlock (blockNumber) { + const block = await this._getBlock(blockNumber) const signedTxList = this.getPendingTransactions() if (!signedTxList.length) return signedTxList.forEach((txMeta) => { @@ -51,9 +53,12 @@ class PendingTransactionTracker extends EventEmitter { return } + if (!block.transactions.length) return - block.transactions.forEach((tx) => { - if (tx.hash === txHash) this.emit('tx:confirmed', txId) + block.transactions.forEach((hash) => { + if (hash === txHash) { + this.confirmTransaction(txId) + } }) }) } @@ -70,7 +75,7 @@ class PendingTransactionTracker extends EventEmitter { return } // if we synced by more than one block, check for missed pending transactions - const diff = Number.parseInt(newBlock.number, 16) - Number.parseInt(oldBlock.number, 16) + const diff = Number.parseInt(newBlock, 16) - Number.parseInt(oldBlock, 16) if (diff > 1) this._checkPendingTxs() } @@ -79,11 +84,11 @@ class PendingTransactionTracker extends EventEmitter { @param block {object} - a block object @emits tx:warning */ - resubmitPendingTxs (block) { + resubmitPendingTxs (blockNumber) { const pending = this.getPendingTransactions() // only try resubmitting if their are transactions to resubmit if (!pending.length) return - pending.forEach((txMeta) => this._resubmitTx(txMeta, block.number).catch((err) => { + pending.forEach((txMeta) => this._resubmitTx(txMeta, blockNumber).catch((err) => { /* Dont marked as failed if the error is a "known" transaction warning "there is already a transaction with the same sender-nonce @@ -179,7 +184,7 @@ class PendingTransactionTracker extends EventEmitter { txParams = await this.query.getTransactionByHash(txHash) if (!txParams) return if (txParams.blockNumber) { - this.emit('tx:confirmed', txId) + this.confirmTransaction(txId) } } catch (err) { txMeta.warning = { @@ -206,11 +211,17 @@ class PendingTransactionTracker extends EventEmitter { nonceGlobalLock.releaseLock() } + async _getBlock (blockNumber) { + return await this.query.getBlockByNumber(blockNumber, false) + } + /** checks to see if a confirmed txMeta has the same nonce @param txMeta {Object} - txMeta object @returns {boolean} */ + + async _checkIfNonceIsTaken (txMeta) { const address = txMeta.txParams.from const completed = this.getCompletedTransactions(address) -- cgit v1.2.3 From 53b946362a59fbaea1a3ae3a7e7af97f427afed4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 16:20:35 -0700 Subject: controllers - recent-blocks - doc update --- app/scripts/controllers/recent-blocks.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index a6208b89c..e0b5551dd 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -8,7 +8,7 @@ class RecentBlocksController { /** * Controller responsible for storing, updating and managing the recent history of blocks. Blocks are back filled - * upon the controller's construction and then the list is updated when the given block tracker gets a 'block' event + * upon the controller's construction and then the list is updated when the given block tracker gets a 'latest' event * (indicating that there is a new block to process). * * @typedef {Object} RecentBlocksController @@ -16,7 +16,7 @@ class RecentBlocksController { * @param {BlockTracker} opts.blockTracker Contains objects necessary for tracking blocks and querying the blockchain * @param {BlockTracker} opts.provider The provider used to create a new EthQuery instance. * @property {BlockTracker} blockTracker Points to the passed BlockTracker. On RecentBlocksController construction, - * listens for 'block' events so that new blocks can be processed and added to storage. + * listens for 'latest' events so that new blocks can be processed and added to storage. * @property {EthQuery} ethQuery Points to the EthQuery instance created with the passed provider * @property {number} historyLength The maximum length of blocks to track * @property {object} store Stores the recentBlocks @@ -111,9 +111,9 @@ class RecentBlocksController { } /** - * On this.blockTracker's first 'block' event after this RecentBlocksController's instantiation, the store.recentBlocks + * On this.blockTracker's first 'latest' event after this RecentBlocksController's instantiation, the store.recentBlocks * array is populated with this.historyLength number of blocks. The block number of the this.blockTracker's first - * 'block' event is used to iteratively generate all the numbers of the previous blocks, which are obtained by querying + * 'latest' event is used to iteratively generate all the numbers of the previous blocks, which are obtained by querying * the blockchain. These blocks are backfilled so that the recentBlocks array is ordered from oldest to newest. * * Each iteration over the block numbers is delayed by 100 milliseconds. -- cgit v1.2.3 From eb2423799d472863b5a74443ac32b5c1d59ce9fc Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 16:22:40 -0700 Subject: controllers - account-tracker - refactor + update for eth-block-tracker@4 --- app/scripts/lib/account-tracker.js | 123 +++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 67 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index 0f7b3d865..c9db65710 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -7,14 +7,13 @@ * on each new block. */ -const async = require('async') const EthQuery = require('eth-query') const ObservableStore = require('obs-store') -const EventEmitter = require('events').EventEmitter -function noop () {} +const log = require('loglevel') +const pify = require('pify') -class AccountTracker extends EventEmitter { +class AccountTracker { /** * This module is responsible for tracking any number of accounts and caching their current balances & transaction @@ -35,8 +34,6 @@ class AccountTracker extends EventEmitter { * */ constructor (opts = {}) { - super() - const initState = { accounts: {}, currentBlockGasLimit: '', @@ -44,12 +41,12 @@ class AccountTracker extends EventEmitter { this.store = new ObservableStore(initState) this._provider = opts.provider - this._query = new EthQuery(this._provider) + this._query = pify(new EthQuery(this._provider)) this._blockTracker = opts.blockTracker // subscribe to latest block - this._blockTracker.on('block', this._updateForBlock.bind(this)) + this._blockTracker.on('latest', this._updateForBlock.bind(this)) // blockTracker.currentBlock may be null - this._currentBlockNumber = this._blockTracker.currentBlock + this._currentBlockNumber = this._blockTracker.getCurrentBlock() } /** @@ -67,49 +64,57 @@ class AccountTracker extends EventEmitter { const accounts = this.store.getState().accounts const locals = Object.keys(accounts) - const toAdd = [] + const accountsToAdd = [] addresses.forEach((upstream) => { if (!locals.includes(upstream)) { - toAdd.push(upstream) + accountsToAdd.push(upstream) } }) - const toRemove = [] + const accountsToRemove = [] locals.forEach((local) => { if (!addresses.includes(local)) { - toRemove.push(local) + accountsToRemove.push(local) } }) - toAdd.forEach(upstream => this.addAccount(upstream)) - toRemove.forEach(local => this.removeAccount(local)) - this._updateAccounts() + this.addAccounts(accountsToAdd) + this.removeAccounts(accountsToRemove) } /** - * Adds a new address to this AccountTracker's accounts object, which points to an empty object. This object will be + * Adds new addresses to track the balances of * given a balance as long this._currentBlockNumber is defined. * - * @param {string} address A hex address of a new account to store in this AccountTracker's accounts object + * @param {array} addresses An array of hex addresses of new accounts to track * */ - addAccount (address) { + addAccounts (addresses) { const accounts = this.store.getState().accounts - accounts[address] = {} + // add initial state for addresses + addresses.forEach(address => { + accounts[address] = {} + }) + // save accounts state this.store.updateState({ accounts }) + // fetch balances for the accounts if there is block number ready if (!this._currentBlockNumber) return - this._updateAccount(address) + addresses.forEach(address => this._updateAccount(address)) } /** - * Removes an account from this AccountTracker's accounts object + * Removes accounts from being tracked * - * @param {string} address A hex address of a the account to remove + * @param {array} an array of hex addresses to stop tracking * */ - removeAccount (address) { + removeAccounts (addresses) { const accounts = this.store.getState().accounts - delete accounts[address] + // remove each state object + addresses.forEach(address => { + delete accounts[address] + }) + // save accounts state this.store.updateState({ accounts }) } @@ -118,71 +123,55 @@ class AccountTracker extends EventEmitter { * via EthQuery * * @private - * @param {object} block Data about the block that contains the data to update to. + * @param {number} blockNumber the block number to update to. * @fires 'block' The updated state, if all account updates are successful * */ - _updateForBlock (block) { - this._currentBlockNumber = block.number - const currentBlockGasLimit = block.gasLimit + async _updateForBlock (blockNumber) { + this._currentBlockNumber = blockNumber + // this shouldn't be here... + const currentBlock = await this._query.getBlockByNumber(blockNumber, false) + const currentBlockGasLimit = currentBlock.gasLimit this.store.updateState({ currentBlockGasLimit }) - async.parallel([ - this._updateAccounts.bind(this), - ], (err) => { - if (err) return console.error(err) - this.emit('block', this.store.getState()) - }) + try { + await this._updateAccounts() + } catch (err) { + log.error(err) + } } /** * Calls this._updateAccount for each account in this.store * - * @param {Function} cb A callback to pass to this._updateAccount, called after each account is successfully updated + * @returns {Promise} after all account balances updated * */ - _updateAccounts (cb = noop) { + async _updateAccounts () { const accounts = this.store.getState().accounts const addresses = Object.keys(accounts) - async.each(addresses, this._updateAccount.bind(this), cb) + await Promise.all(addresses.map(this._updateAccount.bind(this))) } /** - * Updates the current balance of an account. Gets an updated balance via this._getAccount. + * Updates the current balance of an account. * * @private * @param {string} address A hex address of a the account to be updated - * @param {Function} cb A callback to call once the account at address is successfully update + * @returns {Promise} after the account balance is updated * */ - _updateAccount (address, cb = noop) { - this._getAccount(address, (err, result) => { - if (err) return cb(err) - result.address = address - const accounts = this.store.getState().accounts - // only populate if the entry is still present - if (accounts[address]) { - accounts[address] = result - this.store.updateState({ accounts }) - } - cb(null, result) - }) - } - - /** - * Gets the current balance of an account via EthQuery. - * - * @private - * @param {string} address A hex address of a the account to query - * @param {Function} cb A callback to call once the account at address is successfully update - * - */ - _getAccount (address, cb = noop) { - const query = this._query - async.parallel({ - balance: query.getBalance.bind(query, address), - }, cb) + async _updateAccount (address) { + // query balance + const balance = await this._query.getBalance(address) + const result = { address, balance } + // update accounts state + const { accounts } = this.store.getState() + // only populate if the entry is still present + if (!accounts[address]) return + accounts[address] = result + this.store.updateState({ accounts }) } } -- cgit v1.2.3 From 22e59af741a43ab9a9dc8e96415788f681a8efda Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 22:32:33 -0700 Subject: controllers - recent-blocks - ensure full blocks --- app/scripts/controllers/recent-blocks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index e0b5551dd..215638666 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -57,7 +57,7 @@ class RecentBlocksController { */ async processBlock (newBlockNumberHex) { const newBlockNumber = Number.parseInt(newBlockNumberHex, 16) - const newBlock = await this.getBlockByNumber(newBlockNumber) + const newBlock = await this.getBlockByNumber(newBlockNumber, true) const block = this.mapTransactionsToPrices(newBlock) @@ -128,7 +128,7 @@ class RecentBlocksController { const targetBlockNumbers = Array(blocksToFetch).fill().map((_, index) => prevBlockNumber - index) await Promise.all(targetBlockNumbers.map(async (targetBlockNumber) => { try { - const newBlock = await this.getBlockByNumber(targetBlockNumber) + const newBlock = await this.getBlockByNumber(targetBlockNumber, true) if (newBlock) { this.backfillBlock(newBlock) -- cgit v1.2.3 From f41198fbb6f4e72e331bb4e3d326534f90000ce9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 22:33:02 -0700 Subject: sentry - setupRaven - ensure message is truthy --- app/scripts/lib/setupRaven.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index d164827ab..30d0a3680 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -66,11 +66,11 @@ function simplifyErrorMessages(report) { function rewriteErrorMessages(report, rewriteFn) { // rewrite top level message - report.message = rewriteFn(report.message) + if (typeof report.message === 'string') report.message = rewriteFn(report.message) // rewrite each exception message if (report.exception && report.exception.values) { report.exception.values.forEach(item => { - item.value = rewriteFn(item.value) + if (typeof item.value === 'string') item.value = rewriteFn(item.value) }) } } -- cgit v1.2.3 From ee800de025397af7958d8e8e382b31b1d09c338c Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 23 May 2018 22:46:20 -0700 Subject: controllers - recent-blocks - wrap block-tracker event in try-catch --- app/scripts/controllers/recent-blocks.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index 215638666..e256c62e0 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -34,7 +34,13 @@ class RecentBlocksController { }, opts.initState) this.store = new ObservableStore(initState) - this.blockTracker.on('latest', this.processBlock.bind(this)) + this.blockTracker.on('latest', async (newBlockNumberHex) => { + try { + await this.processBlock(newBlockNumberHex) + } catch (err) { + log.error(err) + } + }) this.backfill() } -- cgit v1.2.3 From 49ef93b99158b9fae21d841828d7e7d105f837df Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 13:43:16 -0700 Subject: controllers - recent-blocks - guard against empty block --- app/scripts/controllers/recent-blocks.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js index e256c62e0..4009c35ae 100644 --- a/app/scripts/controllers/recent-blocks.js +++ b/app/scripts/controllers/recent-blocks.js @@ -64,6 +64,7 @@ class RecentBlocksController { async processBlock (newBlockNumberHex) { const newBlockNumber = Number.parseInt(newBlockNumberHex, 16) const newBlock = await this.getBlockByNumber(newBlockNumber, true) + if (!newBlock) return const block = this.mapTransactionsToPrices(newBlock) @@ -135,10 +136,9 @@ class RecentBlocksController { await Promise.all(targetBlockNumbers.map(async (targetBlockNumber) => { try { const newBlock = await this.getBlockByNumber(targetBlockNumber, true) + if (!newBlock) return - if (newBlock) { - this.backfillBlock(newBlock) - } + this.backfillBlock(newBlock) } catch (e) { log.error(e) } -- cgit v1.2.3 From 91accee2c65e2b9c9e278451f1d6794f74b27c24 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 13:43:36 -0700 Subject: account-tracker - guard against empty block --- app/scripts/lib/account-tracker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index c9db65710..1a2354463 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -130,8 +130,9 @@ class AccountTracker { async _updateForBlock (blockNumber) { this._currentBlockNumber = blockNumber - // this shouldn't be here... + // block gasLimit polling shouldn't be in account-tracker shouldn't be here... const currentBlock = await this._query.getBlockByNumber(blockNumber, false) + if (!currentBlock) return const currentBlockGasLimit = currentBlock.gasLimit this.store.updateState({ currentBlockGasLimit }) -- cgit v1.2.3 From 66a62dfd0c2efbb9596bdc4b4befe03b25fbd7e9 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 13:44:33 -0700 Subject: metamask-controller - fix account lookup hook --- app/scripts/metamask-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 14eb749e7..152ad13a0 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -241,7 +241,7 @@ module.exports = class MetamaskController extends EventEmitter { }, }, // account mgmt - getAccounts: (cb) => { + getAccounts: async () => { const isUnlocked = this.keyringController.memStore.getState().isUnlocked const result = [] const selectedAddress = this.preferencesController.getSelectedAddress() @@ -250,7 +250,7 @@ module.exports = class MetamaskController extends EventEmitter { if (isUnlocked && selectedAddress) { result.push(selectedAddress) } - cb(null, result) + return result }, // tx signing // old style msg signing -- cgit v1.2.3 From aab9691c42184b81cdf7086d389bb74279e867bf Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 15:51:46 -0700 Subject: provider - update wallet hooks for new wallet middleware --- app/scripts/lib/message-manager.js | 31 +++++++++++- app/scripts/lib/personal-message-manager.js | 35 ++++++++++++- app/scripts/lib/typed-message-manager.js | 31 +++++++++++- app/scripts/metamask-controller.js | 77 +++++++---------------------- 4 files changed, 110 insertions(+), 64 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index 901367f04..47925b94b 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -69,10 +69,39 @@ module.exports = class MessageManager extends EventEmitter { * new Message to this.messages, and to save the unapproved Messages from that list to this.memStore. * * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin + * @returns {promise} after signature has been + * + */ + addUnapprovedMessageAsync (msgParams, req) { + return new Promise((resolve, reject) => { + const msgId = this.addUnapprovedMessage(msgParams, req) + // await finished + this.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return resolve(data.rawSig) + case 'rejected': + return reject(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + }) + } + + /** + * Creates a new Message with an 'unapproved' status using the passed msgParams. this.addMsg is called to add the + * new Message to this.messages, and to save the unapproved Messages from that list to this.memStore. + * + * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object where the origin may be specificied * @returns {number} The id of the newly created message. * */ - addUnapprovedMessage (msgParams) { + addUnapprovedMessage (msgParams, req) { + // add origin from request + if (req) msgParams.origin = req.origin msgParams.data = normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data var time = (new Date()).getTime() diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index e96ced1f2..fc2cccdf1 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -73,11 +73,43 @@ module.exports = class PersonalMessageManager extends EventEmitter { * this.memStore. * * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin + * @returns {promise} When the message has been signed or rejected + * + */ + addUnapprovedMessageAsync (msgParams, req) { + return new Promise((resolve, reject) => { + if (!msgParams.from) { + reject(new Error('MetaMask Message Signature: from field is required.')) + } + const msgId = this.addUnapprovedMessage(msgParams, req) + this.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return resolve(data.rawSig) + case 'rejected': + return reject(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + }) + } + + /** + * Creates a new PersonalMessage with an 'unapproved' status using the passed msgParams. this.addMsg is called to add + * the new PersonalMessage to this.messages, and to save the unapproved PersonalMessages from that list to + * this.memStore. + * + * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin * @returns {number} The id of the newly created PersonalMessage. * */ - addUnapprovedMessage (msgParams) { + addUnapprovedMessage (msgParams, req) { log.debug(`PersonalMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) + // add origin from request + if (req) msgParams.origin = req.origin msgParams.data = this.normalizeMsgData(msgParams.data) // create txData obj with parameters and meta data var time = (new Date()).getTime() @@ -257,4 +289,3 @@ module.exports = class PersonalMessageManager extends EventEmitter { } } - diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index c58921610..e5e1c94b3 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -72,11 +72,40 @@ module.exports = class TypedMessageManager extends EventEmitter { * this.memStore. Before any of this is done, msgParams are validated * * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin + * @returns {promise} When the message has been signed or rejected + * + */ + addUnapprovedMessageAsync (msgParams, req) { + return new Promise((resolve, reject) => { + const msgId = this.addUnapprovedMessage(msgParams, req) + this.once(`${msgId}:finished`, (data) => { + switch (data.status) { + case 'signed': + return resolve(data.rawSig) + case 'rejected': + return reject(new Error('MetaMask Message Signature: User denied message signature.')) + default: + return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) + } + }) + }) + } + + /** + * Creates a new TypedMessage with an 'unapproved' status using the passed msgParams. this.addMsg is called to add + * the new TypedMessage to this.messages, and to save the unapproved TypedMessages from that list to + * this.memStore. Before any of this is done, msgParams are validated + * + * @param {Object} msgParams The params for the eth_sign call to be made after the message is approved. + * @param {Object} req (optional) The original request object possibly containing the origin * @returns {number} The id of the newly created TypedMessage. * */ - addUnapprovedMessage (msgParams) { + addUnapprovedMessage (msgParams, req) { this.validateParams(msgParams) + // add origin from request + if (req) msgParams.origin = req.origin log.debug(`TypedMessageManager addUnapprovedMessage: ${JSON.stringify(msgParams)}`) // create txData obj with parameters and meta data diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 152ad13a0..8c3c70c5c 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -234,28 +234,22 @@ module.exports = class MetamaskController extends EventEmitter { static: { eth_syncing: false, web3_clientVersion: `MetaMask/v${version}`, - eth_sendTransaction: (payload, next, end) => { - const origin = payload.origin - const txParams = payload.params[0] - nodeify(this.txController.newUnapprovedTransaction, this.txController)(txParams, { origin }, end) - }, }, // account mgmt getAccounts: async () => { const isUnlocked = this.keyringController.memStore.getState().isUnlocked - const result = [] const selectedAddress = this.preferencesController.getSelectedAddress() - // only show address if account is unlocked if (isUnlocked && selectedAddress) { - result.push(selectedAddress) + return [selectedAddress] + } else { + return [] } - return result }, // tx signing - // old style msg signing - processMessage: this.newUnsignedMessage.bind(this), - // personal_sign msg signing + processTransaction: this.txController.newUnapprovedTransaction.bind(this.txController), + // msg signing + processEthSignMessage: this.newUnsignedMessage.bind(this), processPersonalMessage: this.newUnsignedPersonalMessage.bind(this), processTypedMessage: this.newUnsignedTypedMessage.bind(this), } @@ -634,20 +628,11 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_sign. * @param {Function} cb = The callback function called with the signature. */ - newUnsignedMessage (msgParams, cb) { - const msgId = this.messageManager.addUnapprovedMessage(msgParams) + newUnsignedMessage (msgParams, req) { + const promise = this.messageManager.addUnapprovedMessageAsync(msgParams, req) this.sendUpdate() this.opts.showUnconfirmedMessage() - this.messageManager.once(`${msgId}:finished`, (data) => { - switch (data.status) { - case 'signed': - return cb(null, data.rawSig) - case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) - default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) - } - }) + return promise } /** @@ -701,24 +686,11 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Function} cb - The callback function called with the signature. * Passed back to the requesting Dapp. */ - newUnsignedPersonalMessage (msgParams, cb) { - if (!msgParams.from) { - return cb(new Error('MetaMask Message Signature: from field is required.')) - } - - const msgId = this.personalMessageManager.addUnapprovedMessage(msgParams) + async newUnsignedPersonalMessage (msgParams, req) { + const promise = this.personalMessageManager.addUnapprovedMessageAsync(msgParams, req) this.sendUpdate() this.opts.showUnconfirmedMessage() - this.personalMessageManager.once(`${msgId}:finished`, (data) => { - switch (data.status) { - case 'signed': - return cb(null, data.rawSig) - case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) - default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) - } - }) + return promise } /** @@ -767,26 +739,11 @@ module.exports = class MetamaskController extends EventEmitter { * @param {Object} msgParams - The params passed to eth_signTypedData. * @param {Function} cb - The callback function, called with the signature. */ - newUnsignedTypedMessage (msgParams, cb) { - let msgId - try { - msgId = this.typedMessageManager.addUnapprovedMessage(msgParams) - this.sendUpdate() - this.opts.showUnconfirmedMessage() - } catch (e) { - return cb(e) - } - - this.typedMessageManager.once(`${msgId}:finished`, (data) => { - switch (data.status) { - case 'signed': - return cb(null, data.rawSig) - case 'rejected': - return cb(new Error('MetaMask Message Signature: User denied message signature.')) - default: - return cb(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) - } - }) + newUnsignedTypedMessage (msgParams, req) { + const promise = this.typedMessageManager.addUnapprovedMessageAsync(msgParams, req) + this.sendUpdate() + this.opts.showUnconfirmedMessage() + return promise } /** -- cgit v1.2.3 From 76cfb10864364d53efcdfa5f646f9947c83b6fb2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 24 May 2018 16:05:07 -0700 Subject: metamask-controller - wrap txController.addUnapprovedTx for wallet middleware reference before txController is instantiated --- app/scripts/metamask-controller.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 8c3c70c5c..796c9385a 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -247,7 +247,7 @@ module.exports = class MetamaskController extends EventEmitter { } }, // tx signing - processTransaction: this.txController.newUnapprovedTransaction.bind(this.txController), + processTransaction: this.newUnapprovedTransaction.bind(this), // msg signing processEthSignMessage: this.newUnsignedMessage.bind(this), processPersonalMessage: this.newUnsignedPersonalMessage.bind(this), @@ -617,6 +617,18 @@ module.exports = class MetamaskController extends EventEmitter { // --------------------------------------------------------------------------- // Identity Management (signature operations) + /** + * Called when a Dapp suggests a new tx to be signed. + * this wrapper needs to exist so we can provide a reference to + * "newUnapprovedTransaction" before "txController" is instantiated + * + * @param {Object} msgParams - The params passed to eth_sign. + * @param {Object} req - (optional) the original request, containing the origin + */ + async newUnapprovedTransaction(txParams, req) { + return await this.txController.newUnapprovedTransaction(txParams, req) + } + // eth_sign methods: /** -- cgit v1.2.3 From 61ef4f1f29169c553b6a8fc36803e6f7596fc9ad Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 25 May 2018 13:21:42 -0700 Subject: tx-gas-utils - query for block without tx bodies --- app/scripts/controllers/transactions/tx-gas-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 36b5cdbc9..9bf2ae1e2 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -25,7 +25,7 @@ class TxGasUtil { @returns {object} the txMeta object with the gas written to the txParams */ async analyzeGasUsage (txMeta) { - const block = await this.query.getBlockByNumber('latest', true) + const block = await this.query.getBlockByNumber('latest', false) let estimatedGasHex try { estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit) @@ -126,4 +126,4 @@ class TxGasUtil { } } -module.exports = TxGasUtil \ No newline at end of file +module.exports = TxGasUtil -- cgit v1.2.3 From 9f8d5f05470d68a7a9a5474a5b1f4587398e94a3 Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 25 May 2018 13:30:26 -0700 Subject: controllers - transactions - pending-tx-tracker - _getBlock - poll until block is truthy --- app/scripts/controllers/transactions/pending-tx-tracker.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index bd26a72d9..e1bb67c90 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -1,6 +1,7 @@ const EventEmitter = require('events') const log = require('loglevel') const EthQuery = require('ethjs-query') +const timeout = (duration) => new Promise(resolve => setTimeout(resolve, duration)) /** Event emitter utility class for tracking the transactions as they
@@ -212,7 +213,15 @@ class PendingTransactionTracker extends EventEmitter { } async _getBlock (blockNumber) { - return await this.query.getBlockByNumber(blockNumber, false) + let block + while (!block) { + // block requests will sometimes return null due do the infura api + // being backed by multiple out-of-sync clients + block = await this.query.getBlockByNumber(blockNumber, false) + // if block is null, wait 1 sec then try again + if (!block) await timeout(1000) + } + return block } /** -- cgit v1.2.3 From 5be154ea2035810462ff0e7051e537870bfc1afb Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 14:29:31 -0700 Subject: controllers - transactions - merge @frankiebee's work with mine --- app/scripts/controllers/transactions/index.js | 46 ++++++++--- .../controllers/transactions/nonce-tracker.js | 16 +--- .../controllers/transactions/pending-tx-tracker.js | 89 ++++------------------ app/scripts/lib/util.js | 14 ++++ 4 files changed, 69 insertions(+), 96 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 7cb8af3a8..f84fd95ff 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -78,7 +78,7 @@ class TransactionController extends EventEmitter { }) this.txStateManager.store.subscribe(() => this.emit('update:badge')) - this._setupListners() + this._setupListeners() // memstore is computed from a few different stores this._updateMemstore() this.txStateManager.store.subscribe(() => this._updateMemstore()) @@ -382,8 +382,9 @@ class TransactionController extends EventEmitter { is called in constructor applies the listeners for pendingTxTracker txStateManager and blockTracker */ - _setupListners () { + _setupListeners () { this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update')) + this._setupBlockTrackerListener() this.pendingTxTracker.on('tx:warning', (txMeta) => { this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') }) @@ -399,13 +400,6 @@ class TransactionController extends EventEmitter { txMeta.retryCount++ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') }) - - this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker)) - // this is a little messy but until ethstore has been either - // removed or redone this is to guard against the race condition - this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker)) - this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker)) - } /** @@ -429,6 +423,40 @@ class TransactionController extends EventEmitter { }) } + _setupBlockTrackerListener () { + let listenersAreActive = false + const latestBlockHandler = this._onLatestBlock.bind(this) + const blockTracker = this.blockTracker + const txStateManager = this.txStateManager + + txStateManager.on('tx:status-update', updateSubscription) + updateSubscription() + + function updateSubscription() { + const pendingTxs = txStateManager.getPendingTransactions() + if (!listenersAreActive && pendingTxs.length > 0) { + blockTracker.on('latest', latestBlockHandler) + listenersAreActive = true + } else if (listenersAreActive && !pendingTxs.length) { + blockTracker.removeListener('latest', latestBlockHandler) + listenersAreActive = false + } + } + } + + async _onLatestBlock (blockNumber) { + try { + await this.pendingTxTracker.updatePendingTxs() + } catch (err) { + log.error(err) + } + try { + await this.pendingTxTracker.resubmitPendingTxs(blockNumber) + } catch (err) { + log.error(err) + } + } + /** Updates the memStore in transaction controller */ diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js index 490118c89..fe2d25fca 100644 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ b/app/scripts/controllers/transactions/nonce-tracker.js @@ -35,7 +35,7 @@ class NonceTracker { * @typedef NonceDetails * @property {number} highestLocallyConfirmed - A hex string of the highest nonce on a confirmed transaction. * @property {number} nextNetworkNonce - The next nonce suggested by the eth_getTransactionCount method. - * @property {number} highetSuggested - The maximum between the other two, the number returned. + * @property {number} highestSuggested - The maximum between the other two, the number returned. */ /** @@ -75,14 +75,6 @@ class NonceTracker { return { nextNonce, nonceDetails, releaseLock } } - async _getCurrentBlock () { - const currentBlock = this.blockTracker.getCurrentBlock() - if (currentBlock) return currentBlock - return await new Promise((reject, resolve) => { - this.blockTracker.once('latest', resolve) - }) - } - async _globalMutexFree () { const globalMutex = this._lookupMutex('global') const release = await globalMutex.acquire() @@ -108,9 +100,8 @@ class NonceTracker { // calculate next nonce // we need to make sure our base count // and pending count are from the same block - const currentBlock = await this._getCurrentBlock() - const blockNumber = currentBlock.blockNumber - const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber || 'latest') + const blockNumber = await this.blockTracker.getLatestBlock() + const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber) const baseCount = baseCountBN.toNumber() assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`) const nonceDetails = { blockNumber, baseCount } @@ -171,6 +162,7 @@ class NonceTracker { return { name: 'local', nonce: highest, details: { startPoint, highest } } } + } module.exports = NonceTracker diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index e1bb67c90..e981e2991 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -24,60 +24,27 @@ class PendingTransactionTracker extends EventEmitter { super() this.query = new EthQuery(config.provider) this.nonceTracker = config.nonceTracker - // default is one day this.getPendingTransactions = config.getPendingTransactions this.getCompletedTransactions = config.getCompletedTransactions this.publishTransaction = config.publishTransaction this.confirmTransaction = config.confirmTransaction - this._checkPendingTxs() + this.updatePendingTxs() } /** - checks if a signed tx is in a block and - if it is included emits tx status as 'confirmed' - @param block {object}, a full block - @emits tx:confirmed - @emits tx:failed - */ - async checkForTxInBlock (blockNumber) { - const block = await this._getBlock(blockNumber) - const signedTxList = this.getPendingTransactions() - if (!signedTxList.length) return - signedTxList.forEach((txMeta) => { - const txHash = txMeta.hash - const txId = txMeta.id - - if (!txHash) { - const noTxHashErr = new Error('We had an error while submitting this transaction, please try again.') - noTxHashErr.name = 'NoTxHashError' - this.emit('tx:failed', txId, noTxHashErr) - return - } - - if (!block.transactions.length) return - - block.transactions.forEach((hash) => { - if (hash === txHash) { - this.confirmTransaction(txId) - } - }) - }) - } - - /** - asks the network for the transaction to see if a block number is included on it - if we have skipped/missed blocks - @param object - oldBlock newBlock + checks the network for signed txs and releases the nonce global lock if it is */ - queryPendingTxs ({ oldBlock, newBlock }) { - // check pending transactions on start - if (!oldBlock) { - this._checkPendingTxs() - return + async updatePendingTxs () { + const pendingTxs = this.getPendingTransactions() + // in order to keep the nonceTracker accurate we block it while updating pending transactions + const nonceGlobalLock = await this.nonceTracker.getGlobalLock() + try { + await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta))) + } catch (err) { + log.error('PendingTransactionTracker - Error updating pending transactions') + log.error(err) } - // if we synced by more than one block, check for missed pending transactions - const diff = Number.parseInt(newBlock, 16) - Number.parseInt(oldBlock, 16) - if (diff > 1) this._checkPendingTxs() + nonceGlobalLock.releaseLock() } /** @@ -151,6 +118,7 @@ class PendingTransactionTracker extends EventEmitter { this.emit('tx:retry', txMeta) return txHash } + /** Ask the network for the transaction to see if it has been include in a block @param txMeta {Object} - the txMeta object @@ -180,9 +148,8 @@ class PendingTransactionTracker extends EventEmitter { } // get latest transaction status - let txParams try { - txParams = await this.query.getTransactionByHash(txHash) + const txParams = await this.query.getTransactionByHash(txHash) if (!txParams) return if (txParams.blockNumber) { this.confirmTransaction(txId) @@ -196,34 +163,6 @@ class PendingTransactionTracker extends EventEmitter { } } - /** - checks the network for signed txs and releases the nonce global lock if it is - */ - async _checkPendingTxs () { - const signedTxList = this.getPendingTransactions() - // in order to keep the nonceTracker accurate we block it while updating pending transactions - const nonceGlobalLock = await this.nonceTracker.getGlobalLock() - try { - await Promise.all(signedTxList.map((txMeta) => this._checkPendingTx(txMeta))) - } catch (err) { - log.error('PendingTransactionWatcher - Error updating pending transactions') - log.error(err) - } - nonceGlobalLock.releaseLock() - } - - async _getBlock (blockNumber) { - let block - while (!block) { - // block requests will sometimes return null due do the infura api - // being backed by multiple out-of-sync clients - block = await this.query.getBlockByNumber(blockNumber, false) - // if block is null, wait 1 sec then try again - if (!block) await timeout(1000) - } - return block - } - /** checks to see if a confirmed txMeta has the same nonce @param txMeta {Object} - txMeta object diff --git a/app/scripts/lib/util.js b/app/scripts/lib/util.js index 431d1e59c..7ceb9da3c 100644 --- a/app/scripts/lib/util.js +++ b/app/scripts/lib/util.js @@ -99,7 +99,21 @@ function BnMultiplyByFraction (targetBN, numerator, denominator) { return targetBN.mul(numBN).div(denomBN) } +function applyListeners (listeners, emitter) { + Object.keys(listeners).forEach((key) => { + emitter.on(key, listeners[key]) + }) +} + +function removeListeners (listeners, emitter) { + Object.keys(listeners).forEach((key) => { + emitter.removeListener(key, listeners[key]) + }) +} + module.exports = { + removeListeners, + applyListeners, getStack, getEnvironmentType, sufficientBalance, -- cgit v1.2.3 From 1b3fedd10d6209fe4c7dfcdc9e90a23c3972bf16 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 15:54:47 -0700 Subject: controllers - transaction - pending-tx-tracker - lint fix --- app/scripts/controllers/transactions/pending-tx-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index e981e2991..68f016d79 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -1,7 +1,7 @@ const EventEmitter = require('events') const log = require('loglevel') const EthQuery = require('ethjs-query') -const timeout = (duration) => new Promise(resolve => setTimeout(resolve, duration)) + /** Event emitter utility class for tracking the transactions as they
-- cgit v1.2.3 From fe42de46422c89156e91fb08ee06f50511c8601f Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 22:58:14 -0700 Subject: metamask-controller - update preferences controller addresses after import account --- app/scripts/metamask-controller.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'app') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 796c9385a..ed606d4ab 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -345,7 +345,7 @@ module.exports = class MetamaskController extends EventEmitter { verifySeedPhrase: nodeify(this.verifySeedPhrase, this), clearSeedWordCache: this.clearSeedWordCache.bind(this), resetAccount: nodeify(this.resetAccount, this), - importAccountWithStrategy: this.importAccountWithStrategy.bind(this), + importAccountWithStrategy: nodeify(this.importAccountWithStrategy, this), // vault management submitPassword: nodeify(keyringController.submitPassword, keyringController), @@ -603,15 +603,15 @@ module.exports = class MetamaskController extends EventEmitter { * @param {any} args - The data required by that strategy to import an account. * @param {Function} cb - A callback function called with a state update on success. */ - importAccountWithStrategy (strategy, args, cb) { - accountImporter.importAccount(strategy, args) - .then((privateKey) => { - return this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) - }) - .then(keyring => keyring.getAccounts()) - .then((accounts) => this.preferencesController.setSelectedAddress(accounts[0])) - .then(() => { cb(null, this.keyringController.fullUpdate()) }) - .catch((reason) => { cb(reason) }) + async importAccountWithStrategy (strategy, args) { + const privateKey = await accountImporter.importAccount(strategy, args) + const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) + const accounts = await keyring.getAccounts() + // update accounts in preferences controller + const allAccounts = await keyringController.getAccounts() + this.preferencesController.setAddresses(allAccounts) + // set new account as selected + await this.preferencesController.setSelectedAddress(accounts[0]) } // --------------------------------------------------------------------------- -- cgit v1.2.3 From c9f3404ca5b04df859f765f9f8e90f21737142c1 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 28 May 2018 23:14:38 -0700 Subject: metamask-controller - lint fix --- app/scripts/metamask-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index ed606d4ab..2e74b3a20 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -608,7 +608,7 @@ module.exports = class MetamaskController extends EventEmitter { const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ]) const accounts = await keyring.getAccounts() // update accounts in preferences controller - const allAccounts = await keyringController.getAccounts() + const allAccounts = await this.keyringController.getAccounts() this.preferencesController.setAddresses(allAccounts) // set new account as selected await this.preferencesController.setSelectedAddress(accounts[0]) -- cgit v1.2.3 From 16d0db15e05ec97adfcb050901d84a5130e88892 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 29 May 2018 00:41:28 -0700 Subject: controllers - transactions - fix tx confirmation --- app/scripts/controllers/transactions/index.js | 2 +- app/scripts/controllers/transactions/pending-tx-tracker.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index f84fd95ff..6266fea16 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -57,7 +57,6 @@ class TransactionController extends EventEmitter { initState: opts.initState, txHistoryLimit: opts.txHistoryLimit, getNetwork: this.getNetwork.bind(this), - confirmTransaction: this.confirmTransaction.bind(this), }) this._onBootCleanUp() @@ -389,6 +388,7 @@ class TransactionController extends EventEmitter { this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') }) this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) + this.pendingTxTracker.on('tx:confirmed', (txId) => this.confirmTransaction(txId)) this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => { if (!txMeta.firstRetryBlockNumber) { txMeta.firstRetryBlockNumber = latestBlockNumber diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 68f016d79..9a764b962 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -28,7 +28,6 @@ class PendingTransactionTracker extends EventEmitter { this.getCompletedTransactions = config.getCompletedTransactions this.publishTransaction = config.publishTransaction this.confirmTransaction = config.confirmTransaction - this.updatePendingTxs() } /** @@ -37,6 +36,7 @@ class PendingTransactionTracker extends EventEmitter { async updatePendingTxs () { const pendingTxs = this.getPendingTransactions() // in order to keep the nonceTracker accurate we block it while updating pending transactions + console.log('updating pending txs....', pendingTxs) const nonceGlobalLock = await this.nonceTracker.getGlobalLock() try { await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta))) @@ -152,7 +152,7 @@ class PendingTransactionTracker extends EventEmitter { const txParams = await this.query.getTransactionByHash(txHash) if (!txParams) return if (txParams.blockNumber) { - this.confirmTransaction(txId) + this.emit('tx:confirmed', txId) } } catch (err) { txMeta.warning = { -- cgit v1.2.3 From 58de5671cc26a8848b9e0e02bcd6d18bdfcd3ea8 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 29 May 2018 00:53:44 -0700 Subject: controllers - transactions - fix tx status update on boot --- app/scripts/controllers/transactions/index.js | 12 ++++++++++++ app/scripts/controllers/transactions/pending-tx-tracker.js | 3 +-- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 6266fea16..71e7ea920 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -83,7 +83,11 @@ class TransactionController extends EventEmitter { this.txStateManager.store.subscribe(() => this._updateMemstore()) this.networkStore.subscribe(() => this._updateMemstore()) this.preferencesStore.subscribe(() => this._updateMemstore()) + + // request state update to finalize initialization + this._updatePendingTxsAfterFirstBlock() } + /** @returns {number} the chainId*/ getChainId () { const networkState = this.networkStore.getState() @@ -349,6 +353,14 @@ class TransactionController extends EventEmitter { this.getFilteredTxList = (opts) => this.txStateManager.getFilteredTxList(opts) } + // called once on startup + async _updatePendingTxsAfterFirstBlock () { + // wait for first block so we know we're ready + await this.blockTracker.getLatestBlock() + // get status update for all pending transactions (for the current network) + await this.pendingTxTracker.updatePendingTxs() + } + /** If transaction controller was rebooted with transactions that are uncompleted in steps of the transaction signing or user confirmation process it will either diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index 9a764b962..70cac096b 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -34,11 +34,10 @@ class PendingTransactionTracker extends EventEmitter { checks the network for signed txs and releases the nonce global lock if it is */ async updatePendingTxs () { - const pendingTxs = this.getPendingTransactions() // in order to keep the nonceTracker accurate we block it while updating pending transactions - console.log('updating pending txs....', pendingTxs) const nonceGlobalLock = await this.nonceTracker.getGlobalLock() try { + const pendingTxs = this.getPendingTransactions() await Promise.all(pendingTxs.map((txMeta) => this._checkPendingTx(txMeta))) } catch (err) { log.error('PendingTransactionTracker - Error updating pending transactions') -- cgit v1.2.3 From ffb8fa16497d0c4a48e3bd4b918dde1ac3adcd5d Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 6 Jun 2018 11:17:52 -0700 Subject: lint - remove unused require --- app/scripts/metamask-controller.js | 1 - 1 file changed, 1 deletion(-) (limited to 'app') diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index b206c6b67..b1d0217fd 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -45,7 +45,6 @@ const BN = require('ethereumjs-util').BN const GWEI_BN = new BN('1000000000') const percentile = require('percentile') const seedPhraseVerifier = require('./lib/seed-phrase-verifier') -const cleanErrorStack = require('./lib/cleanErrorStack') const DiagnosticsReporter = require('./lib/diagnostics-reporter') const log = require('loglevel') -- cgit v1.2.3 From 3ce83570ee336524e1ab0da50a9f47744cddb193 Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 7 Jun 2018 12:26:37 -0700 Subject: network - provider - infura - use block-reemit middleware --- app/scripts/controllers/network/createInfuraClient.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index adbf4c001..663a2595a 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,6 +1,6 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') -const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockReEmitMiddleware = require('eth-json-rpc-middleware/block-reemit') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') @@ -15,7 +15,7 @@ function createInfuraClient ({ network }) { const blockTracker = new BlockTracker({ provider: blockProvider }) const networkMiddleware = mergeMiddleware([ - createBlockRefMiddleware({ blockTracker }), + createBlockReEmitMiddleware({ blockTracker, provider: blockProvider }), createBlockCacheMiddleware({ blockTracker }), createInflightMiddleware(), createBlockTrackerInspectorMiddleware({ blockTracker }), -- cgit v1.2.3 From 0db776c3cc58e817d108d38ca389893cb13e3f92 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 10:17:09 -0700 Subject: lint - controllers - whitepace fix --- app/scripts/controllers/currency.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index 480c08b1c..d5bc5fe2b 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -1,4 +1,4 @@ - const ObservableStore = require('obs-store') +const ObservableStore = require('obs-store') const extend = require('xtend') const log = require('loglevel') @@ -16,9 +16,9 @@ class CurrencyController { * currentCurrency, conversionRate and conversionDate properties * @property {string} currentCurrency A 2-4 character shorthand that describes a specific currency, currently * selected by the user - * @property {number} conversionRate The conversion rate from ETH to the selected currency. + * @property {number} conversionRate The conversion rate from ETH to the selected currency. * @property {string} conversionDate The date at which the conversion rate was set. Expressed in in milliseconds - * since midnight of January 1, 1970 + * since midnight of January 1, 1970 * @property {number} conversionInterval The id of the interval created by the scheduleConversionInterval method. * Used to clear an existing interval on subsequent calls of that method. * @@ -59,7 +59,7 @@ class CurrencyController { /** * A getter for the conversionRate property * - * @returns {string} The conversion rate from ETH to the selected currency. + * @returns {string} The conversion rate from ETH to the selected currency. * */ getConversionRate () { @@ -80,7 +80,7 @@ class CurrencyController { * A getter for the conversionDate property * * @returns {string} The date at which the conversion rate was set. Expressed in milliseconds since midnight of - * January 1, 1970 + * January 1, 1970 * */ getConversionDate () { -- cgit v1.2.3 From 02f5502e16fefc8d92392e614861e3f672c4f909 Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 11:04:28 -0700 Subject: test - e2e - inject metamask config to point at localhost --- app/scripts/background.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 56e190f97..41fd89016 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -18,7 +18,7 @@ const migrations = require('./migrations/') const PortStream = require('./lib/port-stream.js') const NotificationManager = require('./lib/notification-manager.js') const MetamaskController = require('./metamask-controller') -const firstTimeState = require('./first-time-state') +const rawFirstTimeState = require('./first-time-state') const setupRaven = require('./lib/setupRaven') const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') @@ -31,6 +31,8 @@ const { ENVIRONMENT_TYPE_FULLSCREEN, } = require('./lib/enums') +const firstTimeState = Object.assign({}, rawFirstTimeState, global.METAMASK_CONFIG) + const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = process.env.METAMASK_DEBUG -- cgit v1.2.3 From ebb9447593a877cd299e701ddfcb217070068fac Mon Sep 17 00:00:00 2001 From: kumavis Date: Mon, 11 Jun 2018 14:25:49 -0700 Subject: test - e2e - factor out setup phase + rename METAMASK_CONFIG to METAMASK_TEST_CONFIG --- app/scripts/background.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index 41fd89016..9866ff0b0 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -31,7 +31,8 @@ const { ENVIRONMENT_TYPE_FULLSCREEN, } = require('./lib/enums') -const firstTimeState = Object.assign({}, rawFirstTimeState, global.METAMASK_CONFIG) +// METAMASK_TEST_CONFIG is used in e2e tests to set the default network to localhost +const firstTimeState = Object.assign({}, rawFirstTimeState, global.METAMASK_TEST_CONFIG) const STORAGE_KEY = 'metamask-config' const METAMASK_DEBUG = process.env.METAMASK_DEBUG -- cgit v1.2.3 From c86f93588965291837ae905632ba9a8855f496f2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 10:55:54 -0700 Subject: nonce-tracker - wrap nonce calculations in try-catch and release lock on error --- .../controllers/transactions/nonce-tracker.js | 50 ++++++++++++---------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js index fe2d25fca..14581c998 100644 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ b/app/scripts/controllers/transactions/nonce-tracker.js @@ -50,29 +50,35 @@ class NonceTracker { await this._globalMutexFree() // await lock free, then take lock const releaseLock = await this._takeMutex(address) - // evaluate multiple nextNonce strategies - const nonceDetails = {} - const networkNonceResult = await this._getNetworkNextNonce(address) - const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address) - const nextNetworkNonce = networkNonceResult.nonce - const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed) - - const pendingTxs = this.getPendingTransactions(address) - const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0 - - nonceDetails.params = { - highestLocallyConfirmed, - highestSuggested, - nextNetworkNonce, + try { + // evaluate multiple nextNonce strategies + const nonceDetails = {} + const networkNonceResult = await this._getNetworkNextNonce(address) + const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address) + const nextNetworkNonce = networkNonceResult.nonce + const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed) + + const pendingTxs = this.getPendingTransactions(address) + const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0 + + nonceDetails.params = { + highestLocallyConfirmed, + highestSuggested, + nextNetworkNonce, + } + nonceDetails.local = localNonceResult + nonceDetails.network = networkNonceResult + + const nextNonce = Math.max(networkNonceResult.nonce, localNonceResult.nonce) + assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`) + + // return nonce and release cb + return { nextNonce, nonceDetails, releaseLock } + } catch (err) { + // release lock if we encounter an error + releaseLock() + throw err } - nonceDetails.local = localNonceResult - nonceDetails.network = networkNonceResult - - const nextNonce = Math.max(networkNonceResult.nonce, localNonceResult.nonce) - assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`) - - // return nonce and release cb - return { nextNonce, nonceDetails, releaseLock } } async _globalMutexFree () { -- cgit v1.2.3 From 6a2649a90f5147b505ebc33b97a75d2e90956fca Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 11:12:32 -0700 Subject: network - import createBlockTrackerInspectorMiddleware and rearrange cache middleware order --- app/scripts/controllers/network/createInfuraClient.js | 15 ++------------- app/scripts/controllers/network/createJsonRpcClient.js | 13 +------------ app/scripts/controllers/network/createLocalhostClient.js | 13 +------------ 3 files changed, 4 insertions(+), 37 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 663a2595a..6976e6022 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -3,6 +3,7 @@ const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware const createBlockReEmitMiddleware = require('eth-json-rpc-middleware/block-reemit') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') +const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const createInfuraMiddleware = require('eth-json-rpc-infura') const BlockTracker = require('eth-block-tracker') @@ -15,23 +16,11 @@ function createInfuraClient ({ network }) { const blockTracker = new BlockTracker({ provider: blockProvider }) const networkMiddleware = mergeMiddleware([ - createBlockReEmitMiddleware({ blockTracker, provider: blockProvider }), createBlockCacheMiddleware({ blockTracker }), createInflightMiddleware(), + createBlockReEmitMiddleware({ blockTracker, provider: blockProvider }), createBlockTrackerInspectorMiddleware({ blockTracker }), infuraMiddleware, ]) return { networkMiddleware, blockTracker } } - -// inspect if response contains a block ref higher than our latest block -const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] -function createBlockTrackerInspectorMiddleware ({ blockTracker }) { - return createAsyncMiddleware(async (req, res, next) => { - if (!futureBlockRefRequests.includes(req.method)) return next() - await next() - const blockNumber = Number.parseInt(res.result.blockNumber, 16) - const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) - if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() - }) -} diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index d712ed135..b9aca0bcf 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -4,6 +4,7 @@ const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') +const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') @@ -23,15 +24,3 @@ function createJsonRpcClient ({ rpcUrl }) { ]) return { networkMiddleware, blockTracker } } - -// inspect if response contains a block ref higher than our latest block -const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] -function createBlockTrackerInspectorMiddleware ({ blockTracker }) { - return createAsyncMiddleware(async (req, res, next) => { - if (!futureBlockRefRequests.includes(req.method)) return next() - await next() - const blockNumber = Number.parseInt(res.result.blockNumber, 16) - const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) - if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() - }) -} diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js index 990dc6a95..ae42ac48b 100644 --- a/app/scripts/controllers/network/createLocalhostClient.js +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -2,6 +2,7 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') +const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') const providerFromMiddleware = require('eth-json-rpc-middleware/providerFromMiddleware') const BlockTracker = require('eth-block-tracker') @@ -19,15 +20,3 @@ function createLocalhostClient () { ]) return { networkMiddleware, blockTracker } } - -// inspect if response contains a block ref higher than our latest block -const futureBlockRefRequests = ['eth_getTransactionByHash', 'eth_getTransactionReceipt'] -function createBlockTrackerInspectorMiddleware ({ blockTracker }) { - return createAsyncMiddleware(async (req, res, next) => { - if (!futureBlockRefRequests.includes(req.method)) return next() - await next() - const blockNumber = Number.parseInt(res.result.blockNumber, 16) - const currentBlockNumber = Number.parseInt(blockTracker.getCurrentBlock(), 16) - if (blockNumber > currentBlockNumber) await blockTracker.checkForLatestBlock() - }) -} -- cgit v1.2.3 From 055346843bc90a5168151ba2adc9deacedf8afd4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 12 Jun 2018 11:27:32 -0700 Subject: lint - fix lint for network --- app/scripts/controllers/network/createInfuraClient.js | 1 - app/scripts/controllers/network/createJsonRpcClient.js | 1 - app/scripts/controllers/network/createLocalhostClient.js | 1 - 3 files changed, 3 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/network/createInfuraClient.js b/app/scripts/controllers/network/createInfuraClient.js index 6976e6022..41af4d9f9 100644 --- a/app/scripts/controllers/network/createInfuraClient.js +++ b/app/scripts/controllers/network/createInfuraClient.js @@ -1,5 +1,4 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createBlockReEmitMiddleware = require('eth-json-rpc-middleware/block-reemit') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') const createInflightMiddleware = require('eth-json-rpc-middleware/inflight-cache') diff --git a/app/scripts/controllers/network/createJsonRpcClient.js b/app/scripts/controllers/network/createJsonRpcClient.js index b9aca0bcf..40c353f7f 100644 --- a/app/scripts/controllers/network/createJsonRpcClient.js +++ b/app/scripts/controllers/network/createJsonRpcClient.js @@ -1,5 +1,4 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockCacheMiddleware = require('eth-json-rpc-middleware/block-cache') diff --git a/app/scripts/controllers/network/createLocalhostClient.js b/app/scripts/controllers/network/createLocalhostClient.js index ae42ac48b..fecc512e8 100644 --- a/app/scripts/controllers/network/createLocalhostClient.js +++ b/app/scripts/controllers/network/createLocalhostClient.js @@ -1,5 +1,4 @@ const mergeMiddleware = require('json-rpc-engine/src/mergeMiddleware') -const createAsyncMiddleware = require('json-rpc-engine/src/createAsyncMiddleware') const createFetchMiddleware = require('eth-json-rpc-middleware/fetch') const createBlockRefMiddleware = require('eth-json-rpc-middleware/block-ref') const createBlockTrackerInspectorMiddleware = require('eth-json-rpc-middleware/block-tracker-inspector') -- cgit v1.2.3 From c2d4b237ebef45ff19ddcec5f364a251cd7662bf Mon Sep 17 00:00:00 2001 From: frankiebee Date: Tue, 7 Aug 2018 01:35:30 -0700 Subject: network - fix blockTracker reference to return the blockTrackerProxy instead of the direct blockTracker reference --- app/scripts/controllers/network/network.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 628e32fa4..76fdc3391 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -59,7 +59,7 @@ module.exports = class NetworkController extends EventEmitter { // return the proxies so the references will always be good getProviderAndBlockTracker () { const provider = this._providerProxy - const blockTracker = this._blockTracker + const blockTracker = this._blockTrackerProxy return { provider, blockTracker } } -- cgit v1.2.3