aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/controllers/transactions/nonce-tracker.js
diff options
context:
space:
mode:
authorFrankie <frankie.diamond@gmail.com>2019-05-21 23:17:09 +0800
committerGitHub <noreply@github.com>2019-05-21 23:17:09 +0800
commit2b5c7b82a95dea4ddb50917daa52fae07715e210 (patch)
tree7d92aaadd6a19681393b68624f6289b3f6516fbb /app/scripts/controllers/transactions/nonce-tracker.js
parente0c11371a9d5f419d91a6d30d2cfda1743d2a967 (diff)
downloadtangerine-wallet-browser-2b5c7b82a95dea4ddb50917daa52fae07715e210.tar
tangerine-wallet-browser-2b5c7b82a95dea4ddb50917daa52fae07715e210.tar.gz
tangerine-wallet-browser-2b5c7b82a95dea4ddb50917daa52fae07715e210.tar.bz2
tangerine-wallet-browser-2b5c7b82a95dea4ddb50917daa52fae07715e210.tar.lz
tangerine-wallet-browser-2b5c7b82a95dea4ddb50917daa52fae07715e210.tar.xz
tangerine-wallet-browser-2b5c7b82a95dea4ddb50917daa52fae07715e210.tar.zst
tangerine-wallet-browser-2b5c7b82a95dea4ddb50917daa52fae07715e210.zip
transactions/deps - use broken out nonce-tracker module (#6555)
Diffstat (limited to 'app/scripts/controllers/transactions/nonce-tracker.js')
-rw-r--r--app/scripts/controllers/transactions/nonce-tracker.js161
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