aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md1
-rw-r--r--ISSUE_TEMPLATE15
-rw-r--r--app/scripts/controllers/transactions.js103
-rw-r--r--app/scripts/metamask-controller.js7
-rw-r--r--package.json8
-rw-r--r--test/unit/linting_test.js9
-rw-r--r--test/unit/tx-controller-test.js1
7 files changed, 95 insertions, 49 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6d22da332..a60e1d93a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@
- Add ability to add Tokens to token list.
- Add a warning to JSON file import.
- Add "send" link to token list, which goes to TokenFactory.
+- Fix bug where slowly mined txs would sometimes be incorrectly marked as failed.
## 3.7.8 2017-6-12
diff --git a/ISSUE_TEMPLATE b/ISSUE_TEMPLATE
new file mode 100644
index 000000000..d0ff3c08e
--- /dev/null
+++ b/ISSUE_TEMPLATE
@@ -0,0 +1,15 @@
+<!--
+FAQ:
+ BEFORE SUBMITTING, please make sure your question hasn't been answered in our FAQ: https://github.com/MetaMask/faq
+ Common questions such as "Where is my ether?" or "Where did my tokens go?" are answered in the FAQ.
+
+Bug Reports:
+
+ Briefly describe the issue you've encountered
+ * Expected Behavior
+ * Actual Behavior
+ * Browser Used
+ * Operating System Used
+
+ Screenshots are very helpful and will expedite your issue being resolved!
+-->
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js
index 07fe2bb26..f6dea34e7 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions.js
@@ -24,11 +24,12 @@ module.exports = class TransactionController extends EventEmitter {
this.blockTracker = opts.blockTracker
this.query = opts.ethQuery
this.txProviderUtils = new TxProviderUtil(this.query)
- this.blockTracker.on('block', this.checkForTxInBlock.bind(this))
- this.blockTracker.on('block', this.resubmitPendingTxs.bind(this))
+ this.blockTracker.on('rawBlock', this.checkForTxInBlock.bind(this))
+ this.blockTracker.on('latest', this.resubmitPendingTxs.bind(this))
+ this.blockTracker.on('sync', this.queryPendingTxs.bind(this))
this.signEthTx = opts.signTransaction
this.nonceLock = Semaphore(1)
-
+ this.ethStore = opts.ethStore
// memstore is computed from a few different stores
this._updateMemstore()
this.store.subscribe(() => this._updateMemstore())
@@ -338,12 +339,13 @@ module.exports = class TransactionController extends EventEmitter {
// checks if a signed tx is in a block and
// if included sets the tx status as 'confirmed'
- checkForTxInBlock () {
+ checkForTxInBlock (block) {
var signedTxList = this.getFilteredTxList({status: 'submitted'})
if (!signedTxList.length) return
signedTxList.forEach((txMeta) => {
var txHash = txMeta.hash
var txId = txMeta.id
+
if (!txHash) {
const errReason = {
errCode: 'No hash was provided',
@@ -351,24 +353,24 @@ module.exports = class TransactionController extends EventEmitter {
}
return this.setTxStatusFailed(txId, errReason)
}
- this.query.getTransactionByHash(txHash, (err, txParams) => {
- if (err || !txParams) {
- if (!txParams) return
- txMeta.err = {
- isWarning: true,
- errorCode: err,
- message: 'There was a problem loading this transaction.',
- }
- this.updateTx(txMeta)
- return log.error(err)
- }
- if (txParams.blockNumber) {
- this.setTxStatusConfirmed(txId)
- }
+
+ block.transactions.forEach((tx) => {
+ if (tx.hash === txHash) this.setTxStatusConfirmed(txId)
})
})
}
+ queryPendingTxs ({oldBlock, newBlock}) {
+ // check pending transactions on start
+ if (!oldBlock) {
+ this._checkPendingTxs()
+ return
+ }
+ // if we synced by more than one block, check for missed pending transactions
+ const diff = Number.parseInt(newBlock.number) - Number.parseInt(oldBlock.number)
+ if (diff > 1) this._checkPendingTxs()
+ }
+
// PRIVATE METHODS
// Should find the tx in the tx list and
@@ -411,38 +413,69 @@ module.exports = class TransactionController extends EventEmitter {
const pending = this.getTxsByMetaData('status', 'submitted')
// only try resubmitting if their are transactions to resubmit
if (!pending.length) return
- const resubmit = denodeify(this.resubmitTx.bind(this))
+ const resubmit = denodeify(this._resubmitTx.bind(this))
Promise.all(pending.map(txMeta => resubmit(txMeta)))
.catch((reason) => {
log.info('Problem resubmitting tx', reason)
})
}
- resubmitTx (txMeta, cb) {
- // Increment a try counter.
- if (!('retryCount' in txMeta)) {
- txMeta.retryCount = 0
- }
+ _resubmitTx (txMeta, cb) {
+ const address = txMeta.txParams.from
+ const balance = this.ethStore.getState().accounts[address].balance
+ const nonce = Number.parseInt(this.ethStore.getState().accounts[address].nonce)
+ const txNonce = Number.parseInt(txMeta.txParams.nonce)
+ const gtBalance = Number.parseInt(txMeta.txParams.value) > Number.parseInt(balance)
+ if (!('retryCount' in txMeta)) txMeta.retryCount = 0
+ // if the value of the transaction is greater then the balance
+ // or the nonce of the transaction is lower then the accounts nonce
+ // dont resubmit the tx
+ if (gtBalance || txNonce < nonce) return cb()
// Only auto-submit already-signed txs:
- if (!('rawTx' in txMeta)) {
- return cb()
- }
+ if (!('rawTx' in txMeta)) return cb()
- if (txMeta.retryCount > RETRY_LIMIT) {
- txMeta.err = {
- isWarning: true,
- message: 'Gave up submitting tx.',
- }
- this.updateTx(txMeta)
- return log.error(txMeta.err.message)
- }
+ if (txMeta.retryCount > RETRY_LIMIT) return
+ // Increment a try counter.
txMeta.retryCount++
const rawTx = txMeta.rawTx
this.txProviderUtils.publishTransaction(rawTx, cb)
}
+ // checks the network for signed txs and
+ // if confirmed sets the tx status as 'confirmed'
+ _checkPendingTxs () {
+ var signedTxList = this.getFilteredTxList({status: 'submitted'})
+ if (!signedTxList.length) return
+ signedTxList.forEach((txMeta) => {
+ var txHash = txMeta.hash
+ var txId = txMeta.id
+ if (!txHash) {
+ const errReason = {
+ errCode: 'No hash was provided',
+ message: 'We had an error while submitting this transaction, please try again.',
+ }
+ return this.setTxStatusFailed(txId, errReason)
+ }
+ this.query.getTransactionByHash(txHash, (err, txParams) => {
+ if (err || !txParams) {
+ if (!txParams) return
+ txMeta.err = {
+ isWarning: true,
+ errorCode: err,
+ message: 'There was a problem loading this transaction.',
+ }
+ this.updateTx(txMeta)
+ return log.error(err)
+ }
+ if (txParams.blockNumber) {
+ this.setTxStatusConfirmed(txId)
+ }
+ })
+ })
+ }
+
}
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index e4267381d..39d22f278 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -23,6 +23,7 @@ const autoFaucet = require('./lib/auto-faucet')
const nodeify = require('./lib/nodeify')
const accountImporter = require('./account-import-strategies')
const getBuyEthUrl = require('./lib/buy-eth-url')
+const debounce = require('debounce')
const version = require('../manifest.json').version
@@ -30,6 +31,9 @@ module.exports = class MetamaskController extends EventEmitter {
constructor (opts) {
super()
+
+ this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200)
+
this.opts = opts
const initState = opts.initState || {}
@@ -98,6 +102,7 @@ module.exports = class MetamaskController extends EventEmitter {
provider: this.provider,
blockTracker: this.provider,
ethQuery: this.ethQuery,
+ ethStore: this.ethStore,
})
// notices
@@ -356,7 +361,7 @@ module.exports = class MetamaskController extends EventEmitter {
)
}
- sendUpdate () {
+ privateSendUpdate () {
this.emit('update', this.getState())
}
diff --git a/package.json b/package.json
index 7f0089d8a..01c256ef3 100644
--- a/package.json
+++ b/package.json
@@ -62,12 +62,12 @@
"end-of-stream": "^1.1.0",
"ensnare": "^1.0.0",
"eth-bin-to-ops": "^1.0.1",
- "eth-contract-metadata": "^1.1.1",
+ "eth-contract-metadata": "^1.1.3",
"eth-hd-keyring": "^1.1.1",
- "eth-query": "^2.1.1",
+ "eth-query": "^2.1.2",
"eth-sig-util": "^1.1.1",
"eth-simple-keyring": "^1.1.1",
- "eth-token-tracker": "^1.0.8",
+ "eth-token-tracker": "^1.0.9",
"ethereumjs-tx": "^1.3.0",
"ethereumjs-util": "ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
"ethereumjs-wallet": "^0.6.0",
@@ -124,7 +124,7 @@
"valid-url": "^1.0.9",
"vreme": "^3.0.2",
"web3": "0.18.2",
- "web3-provider-engine": "^12.2.4",
+ "web3-provider-engine": "^13.0.3",
"web3-stream-provider": "^2.0.6",
"xtend": "^4.0.1"
},
diff --git a/test/unit/linting_test.js b/test/unit/linting_test.js
deleted file mode 100644
index 45578fc36..000000000
--- a/test/unit/linting_test.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// LINTING:
-const lint = require('mocha-eslint')
-const lintPaths = ['app/**/*.js', 'ui/**/*.js', 'test/**/*.js', '!node_modules/**', '!dist/**', '!docs/**', '!app/scripts/chromereload.js']
-
-const lintOptions = {
- strict: false,
-}
-
-lint(lintPaths, lintOptions)
diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js
index f0d8a706e..0d35cd62c 100644
--- a/test/unit/tx-controller-test.js
+++ b/test/unit/tx-controller-test.js
@@ -19,6 +19,7 @@ describe('Transaction Controller', function () {
txController = new TransactionController({
networkStore: new ObservableStore(currentNetworkId),
txHistoryLimit: 10,
+ provider: { _blockTracker: new EventEmitter()},
blockTracker: new EventEmitter(),
ethQuery: new EthQuery(new EventEmitter()),
signTransaction: (ethTx) => new Promise((resolve) => {