From 7854321faeeb8184b3171e3b214f57d6e61c0814 Mon Sep 17 00:00:00 2001 From: vicnaum Date: Wed, 6 Dec 2017 22:49:24 +0100 Subject: [PATCH 1/6] Fix for #2644 - Specified Nonce isn't used Added nonceSpecified. And a check if nonce was specified - then we should use the specified nonce instead of generating a new one. --- app/scripts/controllers/transactions.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index ce709bd28..060484b87 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -177,6 +177,7 @@ module.exports = class TransactionController extends EventEmitter { const txParams = txMeta.txParams // ensure value txMeta.gasPriceSpecified = Boolean(txParams.gasPrice) + txMeta.nonceSpecified = Boolean(txParams.nonce) const gasPrice = txParams.gasPrice || await this.query.gasPrice() txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' @@ -200,7 +201,11 @@ module.exports = class TransactionController extends EventEmitter { // wait for a nonce nonceLock = await this.nonceTracker.getNonceLock(fromAddress) // add nonce to txParams - txMeta.txParams.nonce = ethUtil.addHexPrefix(nonceLock.nextNonce.toString(16)) + if (txMeta.nonceSpecified) { + txMeta.txParams.nonce = ethUtil.addHexPrefix(txMeta.txParams.nonce.toString(16)) + } else { + txMeta.txParams.nonce = ethUtil.addHexPrefix(nonceLock.nextNonce.toString(16)) + } // add nonce debugging information to txMeta txMeta.nonceDetails = nonceLock.nonceDetails this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction') From 553d713636d317b74d819d62b5b931bdf2d112d8 Mon Sep 17 00:00:00 2001 From: vicnaum Date: Thu, 7 Dec 2017 15:30:05 +0100 Subject: [PATCH 2/6] A more expressive way replaced ifs with ? : --- app/scripts/controllers/transactions.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 060484b87..6bdbd2cfc 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -201,11 +201,8 @@ module.exports = class TransactionController extends EventEmitter { // wait for a nonce nonceLock = await this.nonceTracker.getNonceLock(fromAddress) // add nonce to txParams - if (txMeta.nonceSpecified) { - txMeta.txParams.nonce = ethUtil.addHexPrefix(txMeta.txParams.nonce.toString(16)) - } else { - txMeta.txParams.nonce = ethUtil.addHexPrefix(nonceLock.nextNonce.toString(16)) - } + const nonce = txMeta.nonceSpecified ? txMeta.txParams.nonce : nonceLock.nextNonce + txMeta.txParams.nonce = ethUtil.addHexPrefix(nonce.toString(16)) // add nonce debugging information to txMeta txMeta.nonceDetails = nonceLock.nonceDetails this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction') From 950ec9596c931055c3e0f2212f2733c9ca07739d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 7 Dec 2017 16:13:38 -0500 Subject: [PATCH 3/6] Do not allow nonces larger than the next valid nonce To avoid situations where a user signs a transaction that will become surprisingly valid in the future. --- app/scripts/controllers/transactions.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index bb408d445..6110b9c75 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -209,6 +209,10 @@ module.exports = class TransactionController extends EventEmitter { nonceLock = await this.nonceTracker.getNonceLock(fromAddress) // add nonce to txParams const nonce = txMeta.nonceSpecified ? txMeta.txParams.nonce : nonceLock.nextNonce + if (nonce > nonceLock.nextNonce) { + const message = `Specified nonce may not be larger than account's next valid nonce.` + throw new Error(message) + } txMeta.txParams.nonce = ethUtil.addHexPrefix(nonce.toString(16)) // add nonce debugging information to txMeta txMeta.nonceDetails = nonceLock.nonceDetails From 9bb4df46ec8a2cd90aa50546799e9cf5ef738632 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 7 Dec 2017 16:16:47 -0500 Subject: [PATCH 4/6] Bump changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index faffb8a2d..f3979fbbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +- Allow Dapps to specify a transaction nonce, allowing dapps to propose resubmit and force-cancel transactions. + ## 3.13.0 2017-12-7 - Allow resubmitting transactions that are taking long to complete. From dc4e3ef24185f3f4dae1fedc5840e36b703617d2 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 7 Dec 2017 16:17:33 -0500 Subject: [PATCH 5/6] Version 3.13.1 --- CHANGELOG.md | 2 ++ app/manifest.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3979fbbb..ea7e1cc8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Current Master +## 3.13.1 2017-12-7 + - Allow Dapps to specify a transaction nonce, allowing dapps to propose resubmit and force-cancel transactions. ## 3.13.0 2017-12-7 diff --git a/app/manifest.json b/app/manifest.json index aa23f85ff..e95e75f6d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "3.13.0", + "version": "3.13.1", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", From a91200fd08b429c81d4096de17cdd9066a632ade Mon Sep 17 00:00:00 2001 From: kumavis Date: Thu, 7 Dec 2017 18:04:14 -0500 Subject: [PATCH 6/6] tx-controller - failed state is a finished state --- app/scripts/controllers/transactions.js | 14 ++++++++------ app/scripts/lib/tx-state-manager.js | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 6110b9c75..f95b5e39a 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -138,18 +138,20 @@ module.exports = class TransactionController extends EventEmitter { async newUnapprovedTransaction (txParams) { log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) - const txMeta = await this.addUnapprovedTransaction(txParams) - this.emit('newUnapprovedTx', txMeta) + const initialTxMeta = await this.addUnapprovedTransaction(txParams) + this.emit('newUnapprovedTx', initialTxMeta) // listen for tx completion (success, fail) return new Promise((resolve, reject) => { - this.txStateManager.once(`${txMeta.id}:finished`, (completedTx) => { - switch (completedTx.status) { + this.txStateManager.once(`${initialTxMeta.id}:finished`, (finishedTxMeta) => { + switch (finishedTxMeta.status) { case 'submitted': - return resolve(completedTx.hash) + return resolve(finishedTxMeta.hash) case 'rejected': return reject(new Error('MetaMask Tx Signature: User denied transaction signature.')) + case 'failed': + return reject(new Error(finishedTxMeta.err.message)) default: - return reject(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(completedTx.txParams)}`)) + return reject(new Error(`MetaMask Tx Signature: Unknown problem: ${JSON.stringify(finishedTxMeta.txParams)}`)) } }) }) diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index cc441c584..a8ef39891 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -240,7 +240,7 @@ module.exports = class TransactionStateManger extends EventEmitter { txMeta.status = status this.emit(`${txMeta.id}:${status}`, txId) this.emit(`tx:status-update`, txId, status) - if (status === 'submitted' || status === 'rejected') { + if (['submitted', 'rejected', 'failed'].includes(status)) { this.emit(`${txMeta.id}:finished`, txMeta) } this.updateTx(txMeta, `txStateManager: setting status to ${status}`)