refactor retrytx with higher gas price:

- create a new tx instead of overwriting the tx hash
- add a new state 'dropped' to the txStateManager
- mark duplicate txs as dropped when one gets confirmed in a block
feature/default_network_editable
frankiebee 7 years ago
parent 33373b676f
commit 62febac876
  1. 43
      app/scripts/controllers/transactions.js
  2. 38
      app/scripts/lib/tx-state-manager.js

@ -6,7 +6,6 @@ const EthQuery = require('ethjs-query')
const TransactionStateManger = require('../lib/tx-state-manager') const TransactionStateManger = require('../lib/tx-state-manager')
const TxGasUtil = require('../lib/tx-gas-utils') const TxGasUtil = require('../lib/tx-gas-utils')
const PendingTransactionTracker = require('../lib/pending-tx-tracker') const PendingTransactionTracker = require('../lib/pending-tx-tracker')
const createId = require('../lib/random-id')
const NonceTracker = require('../lib/nonce-tracker') const NonceTracker = require('../lib/nonce-tracker')
/* /*
@ -92,8 +91,22 @@ module.exports = class TransactionController extends EventEmitter {
this.pendingTxTracker.on('tx:warning', (txMeta) => { this.pendingTxTracker.on('tx:warning', (txMeta) => {
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning') this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
}) })
this.pendingTxTracker.on('tx:confirmed', (txId) => {
this.txStateManager.setTxStatusConfirmed(txId)
// get the confirmed transactions nonce and from address
const txMeta = this.txStateManager.getTx(txId)
const { nonce, from } = txMeta.txParams
const sameNonceTxs = this.txStateManager.getFilteredTxList({nonce, from})
if (!sameNonceTxs.length) return
// mark all same nonce transactions as dropped and give i a replacedBy hash
sameNonceTxs.forEach((otherTxMeta) => {
if (otherTxMeta === txId) return
otherTxMeta.replacedBy = txMeta.hash
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce')
this.txStateManager.setTxStatusDropped(otherTxMeta.id)
})
})
this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) 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:block-update', (txMeta, latestBlockNumber) => { this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
if (!txMeta.firstRetryBlockNumber) { if (!txMeta.firstRetryBlockNumber) {
txMeta.firstRetryBlockNumber = latestBlockNumber txMeta.firstRetryBlockNumber = latestBlockNumber
@ -186,14 +199,7 @@ module.exports = class TransactionController extends EventEmitter {
// validate // validate
await this.txGasUtil.validateTxParams(txParams) await this.txGasUtil.validateTxParams(txParams)
// construct txMeta // construct txMeta
const txMeta = { const txMeta = this.txStateManager.generateTxMeta({txParams})
id: createId(),
time: (new Date()).getTime(),
status: 'unapproved',
metamaskNetworkId: this.getNetwork(),
txParams: txParams,
loadingDefaults: true,
}
this.addTx(txMeta) this.addTx(txMeta)
this.emit('newUnapprovedTx', txMeta) this.emit('newUnapprovedTx', txMeta)
// add default tx params // add default tx params
@ -215,7 +221,6 @@ module.exports = class TransactionController extends EventEmitter {
const txParams = txMeta.txParams const txParams = txMeta.txParams
// ensure value // ensure value
txMeta.gasPriceSpecified = Boolean(txParams.gasPrice) txMeta.gasPriceSpecified = Boolean(txParams.gasPrice)
txMeta.nonceSpecified = Boolean(txParams.nonce)
let gasPrice = txParams.gasPrice let gasPrice = txParams.gasPrice
if (!gasPrice) { if (!gasPrice) {
gasPrice = this.getGasPrice ? this.getGasPrice() : await this.query.gasPrice() gasPrice = this.getGasPrice ? this.getGasPrice() : await this.query.gasPrice()
@ -226,11 +231,17 @@ module.exports = class TransactionController extends EventEmitter {
return await this.txGasUtil.analyzeGasUsage(txMeta) return await this.txGasUtil.analyzeGasUsage(txMeta)
} }
async retryTransaction (txId) { async retryTransaction (originalTxId) {
this.txStateManager.setTxStatusUnapproved(txId) const originalTxMeta = this.txStateManager.getTx(originalTxId)
const txMeta = this.txStateManager.getTx(txId) const lastGasPrice = originalTxMeta.txParams.gasPrice
txMeta.lastGasPrice = txMeta.txParams.gasPrice const txMeta = this.txStateManager.generateTxMeta({
this.txStateManager.updateTx(txMeta, 'retryTransaction: manual retry') txParams: originalTxMeta.txParams,
lastGasPrice,
loadingDefaults: false,
nonceSpecified: true,
})
this.addTx(txMeta)
this.emit('newUnapprovedTx', txMeta)
} }
async updateTransaction (txMeta) { async updateTransaction (txMeta) {

@ -1,9 +1,21 @@
const extend = require('xtend') const extend = require('xtend')
const EventEmitter = require('events') const EventEmitter = require('events')
const ObservableStore = require('obs-store') const ObservableStore = require('obs-store')
const createId = require('./random-id')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const txStateHistoryHelper = require('./tx-state-history-helper') const txStateHistoryHelper = require('./tx-state-history-helper')
// STATUS METHODS
// statuses:
// - `'unapproved'` the user has not responded
// - `'rejected'` the user has responded no!
// - `'approved'` the user has approved the tx
// - `'signed'` the tx is signed
// - `'submitted'` the tx is sent to a server
// - `'confirmed'` the tx has been included in a block.
// - `'failed'` the tx failed for some reason, included on tx data.
// - `'dropped'` the tx nonce was already used
module.exports = class TransactionStateManger extends EventEmitter { module.exports = class TransactionStateManger extends EventEmitter {
constructor ({ initState, txHistoryLimit, getNetwork }) { constructor ({ initState, txHistoryLimit, getNetwork }) {
super() super()
@ -16,6 +28,16 @@ module.exports = class TransactionStateManger extends EventEmitter {
this.getNetwork = getNetwork this.getNetwork = getNetwork
} }
generateTxMeta (opts) {
return extend({
id: createId(),
time: (new Date()).getTime(),
status: 'unapproved',
metamaskNetworkId: this.getNetwork(),
loadingDefaults: true,
}, opts)
}
// Returns the number of txs for the current network. // Returns the number of txs for the current network.
getTxCount () { getTxCount () {
return this.getTxList().length return this.getTxList().length
@ -164,16 +186,6 @@ module.exports = class TransactionStateManger extends EventEmitter {
}) })
} }
// STATUS METHODS
// statuses:
// - `'unapproved'` the user has not responded
// - `'rejected'` the user has responded no!
// - `'approved'` the user has approved the tx
// - `'signed'` the tx is signed
// - `'submitted'` the tx is sent to a server
// - `'confirmed'` the tx has been included in a block.
// - `'failed'` the tx failed for some reason, included on tx data.
// get::set status // get::set status
// should return the status of the tx. // should return the status of the tx.
@ -211,6 +223,12 @@ module.exports = class TransactionStateManger extends EventEmitter {
this._setTxStatus(txId, 'confirmed') this._setTxStatus(txId, 'confirmed')
} }
// should update the status dropped
setTxStatusDropped (txId) {
this._setTxStatus(txId, 'dropped')
}
setTxStatusFailed (txId, err) { setTxStatusFailed (txId, err) {
const txMeta = this.getTx(txId) const txMeta = this.getTx(txId)
txMeta.err = { txMeta.err = {

Loading…
Cancel
Save