diff options
-rw-r--r-- | app/manifest.json | 3 | ||||
-rw-r--r-- | app/scripts/controllers/transactions.js | 16 | ||||
-rw-r--r-- | app/scripts/lib/pending-tx-tracker.js | 12 | ||||
-rw-r--r-- | app/scripts/lib/tx-state-history-helper.js | 10 | ||||
-rw-r--r-- | app/scripts/lib/tx-state-manager.js | 10 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | test/unit/pending-tx-test.js | 17 | ||||
-rw-r--r-- | test/unit/tx-state-history-helper.js | 23 | ||||
-rw-r--r-- | ui/app/components/transaction-list-item.js | 34 |
9 files changed, 88 insertions, 39 deletions
diff --git a/app/manifest.json b/app/manifest.json index e71018211..0fc43c7d4 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -57,7 +57,8 @@ "permissions": [ "storage", "clipboardWrite", - "http://localhost:8545/" + "http://localhost:8545/", + "https://*.infura.io/" ], "web_accessible_resources": [ "scripts/inpage.js" diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 9fdec1ead..94e04c429 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -66,13 +66,15 @@ module.exports = class TransactionController extends EventEmitter { this.txStateManager.store.subscribe(() => this.emit('update:badge')) - this.pendingTxTracker.on('tx:warning', this.txStateManager.updateTx.bind(this.txStateManager)) + this.pendingTxTracker.on('tx:warning', (txMeta) => { + this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') + }) this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) this.pendingTxTracker.on('tx:confirmed', this.txStateManager.setTxStatusConfirmed.bind(this.txStateManager)) this.pendingTxTracker.on('tx:retry', (txMeta) => { if (!('retryCount' in txMeta)) txMeta.retryCount = 0 txMeta.retryCount++ - this.txStateManager.updateTx(txMeta) + this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry') }) this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker)) @@ -168,14 +170,14 @@ module.exports = class TransactionController extends EventEmitter { const txParams = txMeta.txParams // ensure value const gasPrice = txParams.gasPrice || await this.query.gasPrice() - txParams.value = txParams.value || '0x0' txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) + txParams.value = txParams.value || '0x0' // set gasLimit return await this.txGasUtil.analyzeGasUsage(txMeta) } async updateAndApproveTransaction (txMeta) { - this.txStateManager.updateTx(txMeta) + this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction') await this.approveTransaction(txMeta.id) } @@ -193,7 +195,7 @@ module.exports = class TransactionController extends EventEmitter { txMeta.txParams.nonce = ethUtil.addHexPrefix(nonceLock.nextNonce.toString(16)) // add nonce debugging information to txMeta txMeta.nonceDetails = nonceLock.nonceDetails - this.txStateManager.updateTx(txMeta) + this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction') // sign transaction const rawTx = await this.signTransaction(txId) await this.publishTransaction(txId, rawTx) @@ -224,7 +226,7 @@ module.exports = class TransactionController extends EventEmitter { async publishTransaction (txId, rawTx) { const txMeta = this.txStateManager.getTx(txId) txMeta.rawTx = rawTx - this.txStateManager.updateTx(txMeta) + this.txStateManager.updateTx(txMeta, 'transactions#publishTransaction') const txHash = await this.query.sendRawTransaction(rawTx) this.setTxHash(txId, txHash) this.txStateManager.setTxStatusSubmitted(txId) @@ -239,7 +241,7 @@ module.exports = class TransactionController extends EventEmitter { // Add the tx hash to the persisted meta-tx object const txMeta = this.txStateManager.getTx(txId) txMeta.hash = txHash - this.txStateManager.updateTx(txMeta) + this.txStateManager.updateTx(txMeta, 'transactions#setTxHash') } // diff --git a/app/scripts/lib/pending-tx-tracker.js b/app/scripts/lib/pending-tx-tracker.js index 3d358b00e..6f1601586 100644 --- a/app/scripts/lib/pending-tx-tracker.js +++ b/app/scripts/lib/pending-tx-tracker.js @@ -86,12 +86,15 @@ module.exports = class PendingTransactionTracker extends EventEmitter { // other || errorMessage.includes('gateway timeout') || errorMessage.includes('nonce too low') - || txMeta.retryCount > 1 ) // ignore resubmit warnings, return early if (isKnownTx) return // encountered real error - transition to error state - this.emit('tx:failed', txMeta.id, err) + txMeta.warning = { + error: errorMessage, + message: 'There was an error when resubmitting this transaction.', + } + this.emit('tx:warning', txMeta, err) })) } @@ -133,11 +136,10 @@ module.exports = class PendingTransactionTracker extends EventEmitter { } } catch (err) { txMeta.warning = { - error: err, + error: err.message, message: 'There was a problem loading this transaction.', } - this.emit('tx:warning', txMeta) - throw err + this.emit('tx:warning', txMeta, err) } } diff --git a/app/scripts/lib/tx-state-history-helper.js b/app/scripts/lib/tx-state-history-helper.js index 304069d57..db6e3bc9f 100644 --- a/app/scripts/lib/tx-state-history-helper.js +++ b/app/scripts/lib/tx-state-history-helper.js @@ -20,11 +20,15 @@ function migrateFromSnapshotsToDiffs(longHistory) { ) } -function generateHistoryEntry(previousState, newState) { - return jsonDiffer.compare(previousState, newState) +function generateHistoryEntry(previousState, newState, note) { + const entry = jsonDiffer.compare(previousState, newState) + // Add a note to the first op, since it breaks if we append it to the entry + if (note && entry[0]) entry[0].note = note + return entry } -function replayHistory(shortHistory) { +function replayHistory(_shortHistory) { + const shortHistory = clone(_shortHistory) return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument) } diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index abb9d7910..cf8117864 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -82,7 +82,7 @@ module.exports = class TransactionStateManger extends EventEmitter { return txMeta } - updateTx (txMeta) { + updateTx (txMeta, note) { if (txMeta.txParams) { Object.keys(txMeta.txParams).forEach((key) => { let value = txMeta.txParams[key] @@ -96,8 +96,8 @@ module.exports = class TransactionStateManger extends EventEmitter { // recover previous tx state obj const previousState = txStateHistoryHelper.replayHistory(txMeta.history) // generate history entry and add to history - const entry = txStateHistoryHelper.generateHistoryEntry(previousState, currentState) - txMeta.history.push(entry) + const entry = txStateHistoryHelper.generateHistoryEntry(previousState, currentState, note) + txMeta.history.push(entry) // commit txMeta to state const txId = txMeta.id @@ -113,7 +113,7 @@ module.exports = class TransactionStateManger extends EventEmitter { updateTxParams (txId, txParams) { const txMeta = this.getTx(txId) txMeta.txParams = extend(txMeta.txParams, txParams) - this.updateTx(txMeta) + this.updateTx(txMeta, `txStateManager#updateTxParams`) } /* @@ -233,7 +233,7 @@ module.exports = class TransactionStateManger extends EventEmitter { if (status === 'submitted' || status === 'rejected') { this.emit(`${txMeta.id}:finished`, txMeta) } - this.updateTx(txMeta) + this.updateTx(txMeta, `txStateManager: setting status to ${status}`) this.emit('update:badge') } diff --git a/package.json b/package.json index b9a38ac71..918531f15 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "valid-url": "^1.0.9", "vreme": "^3.0.2", "web3": "^0.20.1", - "web3-provider-engine": "^13.2.12", + "web3-provider-engine": "^13.3.1", "web3-stream-provider": "^3.0.1", "xtend": "^4.0.1" }, diff --git a/test/unit/pending-tx-test.js b/test/unit/pending-tx-test.js index 4da0eff5d..6b62bb5b1 100644 --- a/test/unit/pending-tx-test.js +++ b/test/unit/pending-tx-test.js @@ -57,7 +57,7 @@ describe('PendingTransactionTracker', function () { const block = Proxy.revocable({}, {}).revoke() pendingTxTracker.checkForTxInBlock(block) }) - it('should emit \'txFailed\' if the txMeta does not have a hash', function (done) { + it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { const block = Proxy.revocable({}, {}).revoke() pendingTxTracker.getPendingTransactions = () => [txMetaNoHash] pendingTxTracker.once('tx:failed', (txId, err) => { @@ -105,7 +105,7 @@ describe('PendingTransactionTracker', function () { }) describe('#_checkPendingTx', function () { - it('should emit \'txFailed\' if the txMeta does not have a hash', function (done) { + it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) { pendingTxTracker.once('tx:failed', (txId, err) => { assert(txId, txMetaNoHash.id, 'should pass txId') done() @@ -172,7 +172,7 @@ describe('PendingTransactionTracker', function () { .catch(done) pendingTxTracker.resubmitPendingTxs() }) - it('should not emit \'txFailed\' if the txMeta throws a known txError', function (done) { + it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) { knownErrors =[ // geth ' Replacement transaction Underpriced ', @@ -199,8 +199,15 @@ describe('PendingTransactionTracker', function () { pendingTxTracker.resubmitPendingTxs() }) - it('should emit \'txFailed\' if it encountered a real error', function (done) { - pendingTxTracker.once('tx:failed', (id, err) => err.message === 'im some real error' ? txList[id - 1].resolve() : done(err)) + it('should emit \'tx:warning\' if it encountered a real error', function (done) { + pendingTxTracker.once('tx:warning', (txMeta, err) => { + if (err.message === 'im some real error') { + const matchingTx = txList.find(tx => tx.id === txMeta.id) + matchingTx.resolve() + } else { + done(err) + } + }) pendingTxTracker.getPendingTransactions = () => txList pendingTxTracker._resubmitTx = async (tx) => { throw new TypeError('im some real error') } diff --git a/test/unit/tx-state-history-helper.js b/test/unit/tx-state-history-helper.js index 5bb6c9bee..79ee26d6e 100644 --- a/test/unit/tx-state-history-helper.js +++ b/test/unit/tx-state-history-helper.js @@ -20,4 +20,27 @@ describe('tx-state-history-helper', function () { }) }) }) + + it('replaying history does not mutate the original obj', function () { + const initialState = { test: true, message: 'hello', value: 1 } + const diff1 = [{ + "op": "replace", + "path": "/message", + "value": "haay", + }] + const diff2 = [{ + "op": "replace", + "path": "/value", + "value": 2, + }] + const history = [initialState, diff1, diff2] + + const beforeStateSnapshot = JSON.stringify(initialState) + const latestState = txStateHistoryHelper.replayHistory(history) + const afterStateSnapshot = JSON.stringify(initialState) + + assert.notEqual(initialState, latestState, 'initial state is not the same obj as the latest state') + assert.equal(beforeStateSnapshot, afterStateSnapshot, 'initial state is not modified during run') + }) + }) diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 0e5c0b5a3..a9961f47c 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -133,7 +133,7 @@ function recipientField (txParams, transaction, isTx, isMsg) { }, }, [ message, - failIfFailed(transaction), + renderErrorOrWarning(transaction), ]) } @@ -141,25 +141,35 @@ function formatDate (date) { return vreme.format(new Date(date), 'March 16 2014 14:30') } -function failIfFailed (transaction) { - if (transaction.status === 'rejected') { +function renderErrorOrWarning (transaction) { + const { status, err, warning } = transaction + + // show rejected + if (status === 'rejected') { return h('span.error', ' (Rejected)') } - if (transaction.err || transaction.warning) { - const { err, warning = {} } = transaction - const errFirst = !!(( err && warning ) || err) - const message = errFirst ? err.message : warning.message - - errFirst ? err.message : warning.message + // show error + if (err) { + const message = err.message || '' + return ( + h(Tooltip, { + title: message, + position: 'bottom', + }, [ + h(`span.error`, ` (Failed)`), + ]) + ) + } + // show warning + if (warning) { + const message = warning.message return h(Tooltip, { title: message, position: 'bottom', }, [ - h(`span.${errFirst ? 'error' : 'warning'}`, - ` (${errFirst ? 'Failed' : 'Warning'})` - ), + h(`span.warning`, ` (Warning)`), ]) } } |