diff options
author | pldespaigne <pl.despaigne@gmail.com> | 2019-05-31 00:22:55 +0800 |
---|---|---|
committer | pldespaigne <pl.despaigne@gmail.com> | 2019-05-31 00:22:55 +0800 |
commit | 9a658ee53d1f75ce07c33581ac1189fa8c4fd173 (patch) | |
tree | ea92ef1971ffaa72c29bf16904906bc1841654c7 /app/scripts/controllers/transactions/nonce-tracker.js | |
parent | 9b87aaae1907eb04ca0a4055b5bb2c863e56aa39 (diff) | |
parent | 681f3f67b89b64fc837df1103198b641c7e7b2d6 (diff) | |
download | tangerine-wallet-browser-9a658ee53d1f75ce07c33581ac1189fa8c4fd173.tar tangerine-wallet-browser-9a658ee53d1f75ce07c33581ac1189fa8c4fd173.tar.gz tangerine-wallet-browser-9a658ee53d1f75ce07c33581ac1189fa8c4fd173.tar.bz2 tangerine-wallet-browser-9a658ee53d1f75ce07c33581ac1189fa8c4fd173.tar.lz tangerine-wallet-browser-9a658ee53d1f75ce07c33581ac1189fa8c4fd173.tar.xz tangerine-wallet-browser-9a658ee53d1f75ce07c33581ac1189fa8c4fd173.tar.zst tangerine-wallet-browser-9a658ee53d1f75ce07c33581ac1189fa8c4fd173.zip |
merge
Diffstat (limited to 'app/scripts/controllers/transactions/nonce-tracker.js')
-rw-r--r-- | app/scripts/controllers/transactions/nonce-tracker.js | 161 |
1 files changed, 0 insertions, 161 deletions
diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js deleted file mode 100644 index 421036368..000000000 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ /dev/null @@ -1,161 +0,0 @@ -const EthQuery = require('ethjs-query') -const assert = require('assert') -const Mutex = require('await-semaphore').Mutex -/** - @param opts {Object} - @param {Object} opts.provider a ethereum provider - @param {Function} opts.getPendingTransactions a function that returns an array of txMeta - whosee status is `submitted` - @param {Function} opts.getConfirmedTransactions a function that returns an array of txMeta - whose status is `confirmed` - @class -*/ -class NonceTracker { - - constructor ({ provider, blockTracker, getPendingTransactions, getConfirmedTransactions }) { - this.provider = provider - this.blockTracker = blockTracker - this.ethQuery = new EthQuery(provider) - this.getPendingTransactions = getPendingTransactions - this.getConfirmedTransactions = getConfirmedTransactions - this.lockMap = {} - } - - /** - @returns {Promise<Object>} with the key releaseLock (the gloabl mutex) - */ - async getGlobalLock () { - const globalMutex = this._lookupMutex('global') - // await global mutex free - const releaseLock = await globalMutex.acquire() - return { releaseLock } - } - - /** - * @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} highestSuggested - The maximum between the other two, the number returned. - */ - - /** - this will return an object with the `nextNonce` `nonceDetails` of type NonceDetails, and the releaseLock - Note: releaseLock must be called after adding a signed tx to pending transactions (or discarding). - - @param address {string} the hex string for the address whose nonce we are calculating - @returns {Promise<NonceDetails>} - */ - async getNonceLock (address) { - // await global mutex free - await this._globalMutexFree() - // await lock free, then take lock - const releaseLock = await this._takeMutex(address) - 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 - } - } - - async _globalMutexFree () { - const globalMutex = this._lookupMutex('global') - const releaseLock = await globalMutex.acquire() - releaseLock() - } - - async _takeMutex (lockId) { - const mutex = this._lookupMutex(lockId) - const releaseLock = await mutex.acquire() - return releaseLock - } - - _lookupMutex (lockId) { - let mutex = this.lockMap[lockId] - if (!mutex) { - mutex = new Mutex() - this.lockMap[lockId] = mutex - } - return mutex - } - - async _getNetworkNextNonce (address) { - // calculate next nonce - // we need to make sure our base count - // and pending count are from the same block - 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 } - return { name: 'network', nonce: baseCount, details: nonceDetails } - } - - _getHighestLocallyConfirmed (address) { - const confirmedTransactions = this.getConfirmedTransactions(address) - const highest = this._getHighestNonce(confirmedTransactions) - return Number.isInteger(highest) ? highest + 1 : 0 - } - - _getHighestNonce (txList) { - const nonces = txList.map((txMeta) => { - const nonce = txMeta.txParams.nonce - assert(typeof nonce, 'string', 'nonces should be hex strings') - return parseInt(nonce, 16) - }) - const highestNonce = Math.max.apply(null, nonces) - return highestNonce - } - - /** - @typedef {object} highestContinuousFrom - @property {string} - name the name for how the nonce was calculated based on the data used - @property {number} - nonce the next suggested nonce - @property {object} - details the provided starting nonce that was used (for debugging) - */ - /** - @param txList {array} - list of txMeta's - @param startPoint {number} - the highest known locally confirmed nonce - @returns {highestContinuousFrom} - */ - _getHighestContinuousFrom (txList, startPoint) { - const nonces = txList.map((txMeta) => { - const nonce = txMeta.txParams.nonce - assert(typeof nonce, 'string', 'nonces should be hex strings') - return parseInt(nonce, 16) - }) - - let highest = startPoint - while (nonces.includes(highest)) { - highest++ - } - - return { name: 'local', nonce: highest, details: { startPoint, highest } } - } - -} - -module.exports = NonceTracker |