mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-03 14:44:27 +01:00
43b1cb9100
Fixed warnings: ```md app/scripts/controllers/computed-balances.js + 35:27 warning Missing space before function parentheses space-before-function-paren + 41:14 warning 'address' is never reassigned. Use 'const' instead prefer-const + 61:9 warning 'updater' is never reassigned. Use 'const' instead prefer-const + 68:11 warning 'newState' is never reassigned. Use 'const' instead prefer-const app/scripts/controllers/network.js + 104:29 warning Missing space before function parentheses space-before-function-paren app/scripts/lib/createLoggerMiddleware.js + 4:32 warning Missing space before function parentheses space-before-function-paren + 15:2 warning Newline required at end of file but not found eol-last app/scripts/lib/createOriginMiddleware.js + 4:32 warning Missing space before function parentheses space-before-function-paren + 9:2 warning Newline required at end of file but not found eol-last app/scripts/lib/createProviderMiddleware.js + 5:34 warning Missing space before function parentheses space-before-function-paren + 13:2 warning Newline required at end of file but not found eol-last app/scripts/lib/events-proxy.js + 1:50 warning Missing space before function parentheses space-before-function-paren + 31:2 warning Newline required at end of file but not found eol-last app/scripts/lib/nodeify.js + 2:22 warning Missing space before function parentheses space-before-function-paren + 2:24 warning Missing space before opening brace space-before-blocks + 5:18 warning Missing space before function parentheses space-before-function-paren + 5:20 warning Missing space before opening brace space-before-blocks app/scripts/lib/pending-balance-calculator.js + 16:19 warning Missing space before function parentheses space-before-function-paren app/scripts/lib/pending-tx-tracker.js + 85:11 warning '||' should be placed at the end of the line operator-linebreak + 87:11 warning '||' should be placed at the end of the line operator-linebreak + 88:11 warning '||' should be placed at the end of the line operator-linebreak + 90:11 warning '||' should be placed at the end of the line operator-linebreak + 91:11 warning '||' should be placed at the end of the line operator-linebreak app/scripts/lib/port-stream.js + 3:22 warning Missing space before function parentheses space-before-function-paren + 3:24 warning Missing space before opening brace space-before-blocks app/scripts/lib/tx-gas-utils.js + 84:2 warning Newline required at end of file but not found eol-last app/scripts/lib/tx-state-history-helper.js + 12:37 warning Missing space before function parentheses space-before-function-paren + 23:30 warning Missing space before function parentheses space-before-function-paren + 30:23 warning Missing space before function parentheses space-before-function-paren + 35:28 warning Missing space before function parentheses space-before-function-paren + 41:2 warning Newline required at end of file but not found eol-last app/scripts/lib/tx-state-manager.js + 94:13 warning 'value' is never reassigned. Use 'const' instead prefer-const ui/app/reducers.js + 45:7 warning 'state' is never reassigned. Use 'const' instead prefer-const + 53:7 warning 'stateString' is never reassigned. Use 'const' instead prefer-const ui/lib/tx-helper.js + 27:2 warning Newline required at end of file but not found eol-last ui/app/components/account-dropdowns.js + 163:1 warning More than 2 blank lines not allowed no-multiple-empty-lines ui/app/components/menu-droppo.js + 22:7 warning 'style' is never reassigned. Use 'const' instead prefer-const ui/app/components/shapeshift-form.js + 135:11 warning '&&' should be placed at the end of the line operator-linebreak ui/app/components/typed-message-renderer.js + 35:25 warning Missing space before function parentheses space-before-function-paren + 42:2 warning Newline required at end of file but not found eol-last mascara/server/index.js + 11:42 warning Use path.join() or path.resolve() instead of + to create paths no-path-concat + 12:36 warning Use path.join() or path.resolve() instead of + to create paths no-path-concat + 13:33 warning Use path.join() or path.resolve() instead of + to create paths no-path-concat + 14:40 warning Use path.join() or path.resolve() instead of + to create paths no-path-concat + 20:29 warning Use path.join() or path.resolve() instead of + to create paths no-path-concat + 21:29 warning Use path.join() or path.resolve() instead of + to create paths no-path-concat + 26:40 warning Use path.join() or path.resolve() instead of + to create paths no-path-concat ```
184 lines
6.1 KiB
JavaScript
184 lines
6.1 KiB
JavaScript
const EventEmitter = require('events')
|
|
const EthQuery = require('ethjs-query')
|
|
/*
|
|
|
|
Utility class for tracking the transactions as they
|
|
go from a pending state to a confirmed (mined in a block) state
|
|
|
|
As well as continues broadcast while in the pending state
|
|
|
|
~config is not optional~
|
|
requires a: {
|
|
provider: //,
|
|
nonceTracker: //see nonce tracker,
|
|
getPendingTransactions: //() a function for getting an array of transactions,
|
|
publishTransaction: //(rawTx) a async function for publishing raw transactions,
|
|
}
|
|
|
|
*/
|
|
|
|
module.exports = class PendingTransactionTracker extends EventEmitter {
|
|
constructor (config) {
|
|
super()
|
|
this.query = new EthQuery(config.provider)
|
|
this.nonceTracker = config.nonceTracker
|
|
// default is one day
|
|
this.retryTimePeriod = config.retryTimePeriod || 86400000
|
|
this.getPendingTransactions = config.getPendingTransactions
|
|
this.getCompletedTransactions = config.getCompletedTransactions
|
|
this.publishTransaction = config.publishTransaction
|
|
this._checkPendingTxs()
|
|
}
|
|
|
|
// checks if a signed tx is in a block and
|
|
// if included sets the tx status as 'confirmed'
|
|
checkForTxInBlock (block) {
|
|
const signedTxList = this.getPendingTransactions()
|
|
if (!signedTxList.length) return
|
|
signedTxList.forEach((txMeta) => {
|
|
const txHash = txMeta.hash
|
|
const txId = txMeta.id
|
|
|
|
if (!txHash) {
|
|
const noTxHashErr = new Error('We had an error while submitting this transaction, please try again.')
|
|
noTxHashErr.name = 'NoTxHashError'
|
|
this.emit('tx:failed', txId, noTxHashErr)
|
|
return
|
|
}
|
|
|
|
|
|
block.transactions.forEach((tx) => {
|
|
if (tx.hash === txHash) this.emit('tx:confirmed', 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, 16) - Number.parseInt(oldBlock.number, 16)
|
|
if (diff > 1) this._checkPendingTxs()
|
|
}
|
|
|
|
|
|
resubmitPendingTxs () {
|
|
const pending = this.getPendingTransactions()
|
|
// only try resubmitting if their are transactions to resubmit
|
|
if (!pending.length) return
|
|
pending.forEach((txMeta) => this._resubmitTx(txMeta).catch((err) => {
|
|
/*
|
|
Dont marked as failed if the error is a "known" transaction warning
|
|
"there is already a transaction with the same sender-nonce
|
|
but higher/same gas price"
|
|
|
|
Also don't mark as failed if it has ever been broadcast successfully.
|
|
A successful broadcast means it may still be mined.
|
|
*/
|
|
const errorMessage = err.message.toLowerCase()
|
|
const isKnownTx = (
|
|
// geth
|
|
errorMessage.includes('replacement transaction underpriced') ||
|
|
errorMessage.includes('known transaction') ||
|
|
// parity
|
|
errorMessage.includes('gas price too low to replace') ||
|
|
errorMessage.includes('transaction with the same hash was already imported') ||
|
|
// other
|
|
errorMessage.includes('gateway timeout') ||
|
|
errorMessage.includes('nonce too low')
|
|
)
|
|
// ignore resubmit warnings, return early
|
|
if (isKnownTx) return
|
|
// encountered real error - transition to error state
|
|
txMeta.warning = {
|
|
error: errorMessage,
|
|
message: 'There was an error when resubmitting this transaction.',
|
|
}
|
|
this.emit('tx:warning', txMeta, err)
|
|
}))
|
|
}
|
|
|
|
async _resubmitTx (txMeta) {
|
|
if (Date.now() > txMeta.time + this.retryTimePeriod) {
|
|
const hours = (this.retryTimePeriod / 3.6e+6).toFixed(1)
|
|
const err = new Error(`Gave up submitting after ${hours} hours.`)
|
|
return this.emit('tx:failed', txMeta.id, err)
|
|
}
|
|
|
|
// Only auto-submit already-signed txs:
|
|
if (!('rawTx' in txMeta)) return
|
|
|
|
const rawTx = txMeta.rawTx
|
|
const txHash = await this.publishTransaction(rawTx)
|
|
|
|
// Increment successful tries:
|
|
this.emit('tx:retry', txMeta)
|
|
return txHash
|
|
}
|
|
|
|
async _checkPendingTx (txMeta) {
|
|
const txHash = txMeta.hash
|
|
const txId = txMeta.id
|
|
|
|
// extra check in case there was an uncaught error during the
|
|
// signature and submission process
|
|
if (!txHash) {
|
|
const noTxHashErr = new Error('We had an error while submitting this transaction, please try again.')
|
|
noTxHashErr.name = 'NoTxHashError'
|
|
this.emit('tx:failed', txId, noTxHashErr)
|
|
return
|
|
}
|
|
|
|
// If another tx with the same nonce is mined, set as failed.
|
|
const taken = await this._checkIfNonceIsTaken(txMeta)
|
|
if (taken) {
|
|
const nonceTakenErr = new Error('Another transaction with this nonce has been mined.')
|
|
nonceTakenErr.name = 'NonceTakenErr'
|
|
return this.emit('tx:failed', txId, nonceTakenErr)
|
|
}
|
|
|
|
// get latest transaction status
|
|
let txParams
|
|
try {
|
|
txParams = await this.query.getTransactionByHash(txHash)
|
|
if (!txParams) return
|
|
if (txParams.blockNumber) {
|
|
this.emit('tx:confirmed', txId)
|
|
}
|
|
} catch (err) {
|
|
txMeta.warning = {
|
|
error: err.message,
|
|
message: 'There was a problem loading this transaction.',
|
|
}
|
|
this.emit('tx:warning', txMeta, err)
|
|
}
|
|
}
|
|
|
|
// checks the network for signed txs and
|
|
// if confirmed sets the tx status as 'confirmed'
|
|
async _checkPendingTxs () {
|
|
const signedTxList = this.getPendingTransactions()
|
|
// in order to keep the nonceTracker accurate we block it while updating pending transactions
|
|
const nonceGlobalLock = await this.nonceTracker.getGlobalLock()
|
|
try {
|
|
await Promise.all(signedTxList.map((txMeta) => this._checkPendingTx(txMeta)))
|
|
} catch (err) {
|
|
console.error('PendingTransactionWatcher - Error updating pending transactions')
|
|
console.error(err)
|
|
}
|
|
nonceGlobalLock.releaseLock()
|
|
}
|
|
|
|
async _checkIfNonceIsTaken (txMeta) {
|
|
const completed = this.getCompletedTransactions()
|
|
const sameNonce = completed.filter((otherMeta) => {
|
|
return otherMeta.txParams.nonce === txMeta.txParams.nonce
|
|
})
|
|
return sameNonce.length > 0
|
|
}
|
|
|
|
}
|