aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/controllers
diff options
context:
space:
mode:
authorkumavis <aaron@kumavis.me>2018-05-17 11:46:34 +0800
committerkumavis <aaron@kumavis.me>2018-05-17 11:46:34 +0800
commit088d7930e0895ef1802823c5fc843dd1c19b9661 (patch)
treea2aed8b980fa44254121021d0529169369d77992 /app/scripts/controllers
parent708422432c634ffbd4c73388f980c43f766b3355 (diff)
downloadtangerine-wallet-browser-088d7930e0895ef1802823c5fc843dd1c19b9661.tar
tangerine-wallet-browser-088d7930e0895ef1802823c5fc843dd1c19b9661.tar.gz
tangerine-wallet-browser-088d7930e0895ef1802823c5fc843dd1c19b9661.tar.bz2
tangerine-wallet-browser-088d7930e0895ef1802823c5fc843dd1c19b9661.tar.lz
tangerine-wallet-browser-088d7930e0895ef1802823c5fc843dd1c19b9661.tar.xz
tangerine-wallet-browser-088d7930e0895ef1802823c5fc843dd1c19b9661.tar.zst
tangerine-wallet-browser-088d7930e0895ef1802823c5fc843dd1c19b9661.zip
network - create provider and block-tracker via json-rpc-engine
Diffstat (limited to 'app/scripts/controllers')
-rw-r--r--app/scripts/controllers/network/createInfuraClient.js34
-rw-r--r--app/scripts/controllers/network/createJsonRpcClient.js35
-rw-r--r--app/scripts/controllers/network/createLocalhostClient.js33
-rw-r--r--app/scripts/controllers/network/createMetamaskMiddleware.js43
-rw-r--r--app/scripts/controllers/network/network.js116
-rw-r--r--app/scripts/controllers/transactions/index.js1
-rw-r--r--app/scripts/controllers/transactions/nonce-tracker.js18
7 files changed, 213 insertions, 67 deletions
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