From dadee1ed79715c7dcdfe1d208e2bd554a1d4da8b Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 23 Aug 2017 22:48:19 -0700 Subject: [PATCH 1/5] hotfix - fail submitted txs whos nonce is out of bound --- app/scripts/migrations/019.js | 60 +++++++++++++++++++++++++++++++++ app/scripts/migrations/index.js | 1 + 2 files changed, 61 insertions(+) create mode 100644 app/scripts/migrations/019.js diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js new file mode 100644 index 000000000..e6e8f1f01 --- /dev/null +++ b/app/scripts/migrations/019.js @@ -0,0 +1,60 @@ + +const version = 19 + +/* + +This migration sets transactions with the 'Gave up submitting tx.' err message +to a 'failed' stated + +*/ + +const clone = require('clone') + +module.exports = { + version, + + migrate: function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + try { + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + } catch (err) { + console.warn(`MetaMask Migration #${version}` + err.stack) + } + return Promise.resolve(versionedData) + }, +} + +function transformState (state) { + const newState = state + const transactions = newState.TransactionController.transactions + newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { + if (txMeta.status !== 'submitted') return txMeta + + const confirmedTxs = txList.filter((tx) => tx.status === 'confirmed') + .filter((tx) => tx.txParams.from === txMeta.txParams.from) + .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) + const highestConfirmedNonce = getHighestNonce(confirmedTxs) + + if (parseInt(txMeta.txParams.nonce, 16) > highestConfirmedNonce + 1) { + txMeta.status = 'failed' + txMeta.err = { + message: 'nonce too high', + note: 'migration 019 custom error', + } + } + return txMeta + }) + return newState +} + +function getHighestNonce (txList) { + const nonces = txList.map((txMeta) => { + const nonce = txMeta.txParams.nonce + return parseInt(nonce || '0x0', 16) + }) + const highestNonce = Math.max.apply(null, nonces) + return highestNonce +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index 6bfc622f7..e9cbd7b98 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -29,4 +29,5 @@ module.exports = [ require('./016'), require('./017'), require('./018'), + require('./019'), ] From f42687d25f844efd3be915e077cddcb4ccd458cf Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 23 Aug 2017 22:53:29 -0700 Subject: [PATCH 2/5] fix description --- app/scripts/migrations/019.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js index e6e8f1f01..9dfe96050 100644 --- a/app/scripts/migrations/019.js +++ b/app/scripts/migrations/019.js @@ -3,8 +3,8 @@ const version = 19 /* -This migration sets transactions with the 'Gave up submitting tx.' err message -to a 'failed' stated +This migration sets transactions as failed +whos nonce is too high */ From 17a71a9b4cb5cc23cbedfc52ba35c562dffdc02e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 23 Aug 2017 23:09:57 -0700 Subject: [PATCH 3/5] Only cancel pending txs with non continuously high nonces --- app/scripts/migrations/019.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js index 9dfe96050..d41b39d1c 100644 --- a/app/scripts/migrations/019.js +++ b/app/scripts/migrations/019.js @@ -30,6 +30,7 @@ module.exports = { function transformState (state) { const newState = state const transactions = newState.TransactionController.transactions + newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => { if (txMeta.status !== 'submitted') return txMeta @@ -38,7 +39,14 @@ function transformState (state) { .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) const highestConfirmedNonce = getHighestNonce(confirmedTxs) - if (parseInt(txMeta.txParams.nonce, 16) > highestConfirmedNonce + 1) { + const pendingTxs = txList.filter((tx) => tx.status === 'submitted') + .filter((tx) => tx.txParams.from === txMeta.txParams.from) + .filter((tx) => tx.metamaskNetworkId.from === txMeta.metamaskNetworkId.from) + const highestContinuousNonce = getHighestContinuousFrom(pendingTxs, highestConfirmedNonce) + + const maxNonce = Math.max(highestContinuousNonce, highestConfirmedNonce) + + if (parseInt(txMeta.txParams.nonce, 16) > maxNonce + 1) { txMeta.status = 'failed' txMeta.err = { message: 'nonce too high', @@ -50,6 +58,20 @@ function transformState (state) { return newState } +function getHighestContinuousFrom (txList, startPoint) { + const nonces = txList.map((txMeta) => { + const nonce = txMeta.txParams.nonce + return parseInt(nonce, 16) + }) + + let highest = startPoint + while (nonces.includes(highest)) { + highest++ + } + + return { name: 'local', nonce: highest, details: { startPoint, highest } } +} + function getHighestNonce (txList) { const nonces = txList.map((txMeta) => { const nonce = txMeta.txParams.nonce @@ -58,3 +80,4 @@ function getHighestNonce (txList) { const highestNonce = Math.max.apply(null, nonces) return highestNonce } + From 803e696cdc2a2f60d6097f1ff1efa8202d8e4320 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 23 Aug 2017 23:24:01 -0700 Subject: [PATCH 4/5] Make method return a number --- app/scripts/migrations/019.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/migrations/019.js b/app/scripts/migrations/019.js index d41b39d1c..072c96370 100644 --- a/app/scripts/migrations/019.js +++ b/app/scripts/migrations/019.js @@ -69,7 +69,7 @@ function getHighestContinuousFrom (txList, startPoint) { highest++ } - return { name: 'local', nonce: highest, details: { startPoint, highest } } + return highest } function getHighestNonce (txList) { From c2624dd1a071ea4388df23400f4319e863d061c6 Mon Sep 17 00:00:00 2001 From: frankiebee Date: Thu, 24 Aug 2017 00:02:06 -0700 Subject: [PATCH 5/5] fall back to `latest` if blockNumber is null --- app/scripts/lib/nonce-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index 08f1e1e86..0029ac953 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -88,7 +88,7 @@ class NonceTracker { // 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) + const baseCountBN = await this.ethQuery.getTransactionCount(address, blockNumber || 'latest') const baseCount = baseCountBN.toNumber() assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`) const nonceDetails = { blockNumber, baseCount }