transactions - more docs and clean ups

feature/default_network_editable
frankiebee 7 years ago
parent 621e9334bc
commit 8ffce8b59d
  1. 66
      app/scripts/controllers/transactions/index.js
  2. 2
      app/scripts/controllers/transactions/lib/tx-state-history-helper.js
  3. 25
      app/scripts/controllers/transactions/nonce-tracker.js
  4. 14
      app/scripts/controllers/transactions/pending-tx-tracker.js
  5. 33
      app/scripts/controllers/transactions/tx-gas-utils.js
  6. 27
      app/scripts/controllers/transactions/tx-state-manager.js

@ -26,17 +26,16 @@ const log = require('loglevel')
@class @class
@param {Object} opts @param {object} - opts
@property {Object} opts.initState initial transaction list default is an empty array @param {object} opts.initState - initial transaction list default is an empty array
@property {Object} opts.networkStore an observable store for network number @param {Object} opts.networkStore - an observable store for network number
@param {Object} opts.blockTracker - An instance of eth-blocktracker @param {Object} opts.blockTracker - An instance of eth-blocktracker
@property {Object} opts.provider
@param {Object} opts.provider - A network provider. @param {Object} opts.provider - A network provider.
@property {Object} opts.signTransaction function the signs an ethereumjs-tx @param {Function} opts.signTransaction - function the signs an ethereumjs-tx
@property {function} opts.getGasPrice optional gas price calculator @param {Function} [opts.getGasPrice] - optional gas price calculator
@property {function} opts.signTransaction ethTx signer that returns a rawTx @param {Function} opts.signTransaction - ethTx signer that returns a rawTx
@property {number} opts.txHistoryLimit number *optional* for limiting how many transactions are in state @param {Number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state
@property {Object} opts.preferencesStore @param {Object} opts.preferencesStore
*/ */
class TransactionController extends EventEmitter { class TransactionController extends EventEmitter {
@ -105,7 +104,7 @@ class TransactionController extends EventEmitter {
} }
/** /**
wipes the transactions for a given account Wipes the transactions for a given account
@param {string} address - hex string of the from address for txs being removed @param {string} address - hex string of the from address for txs being removed
*/ */
wipeTransactions (address) { wipeTransactions (address) {
@ -115,9 +114,9 @@ class TransactionController extends EventEmitter {
/** /**
add a new unapproved transaction to the pipeline add a new unapproved transaction to the pipeline
@returns {promise} @returns {Promise<string>} the hash of the transaction after being submitted to the network
@param txParams {Object} - txParams for the transaction @param txParams {object} - txParams for the transaction
@param opts {Object} - with the key origin to put the origin on the txMeta @param opts {object} - with the key origin to put the origin on the txMeta
*/ */
async newUnapprovedTransaction (txParams, opts = {}) { async newUnapprovedTransaction (txParams, opts = {}) {
log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`)
@ -142,7 +141,7 @@ class TransactionController extends EventEmitter {
} }
/** /**
validates and generates a txMeta with defaults and puts it in txStateManager Validates and generates a txMeta with defaults and puts it in txStateManager
store store
@returns {txMeta} @returns {txMeta}
@ -173,7 +172,7 @@ class TransactionController extends EventEmitter {
/** /**
adds the tx gas defaults: gas && gasPrice adds the tx gas defaults: gas && gasPrice
@param txMeta {Object} - the txMeta object @param txMeta {Object} - the txMeta object
@returns {promise} resolves with txMeta @returns {Promise<object>} resolves with txMeta
*/ */
async addTxGasDefaults (txMeta) { async addTxGasDefaults (txMeta) {
const txParams = txMeta.txParams const txParams = txMeta.txParams
@ -190,7 +189,7 @@ class TransactionController extends EventEmitter {
} }
/** /**
creates a new txMeta with the same txParams as the original Creates a new txMeta with the same txParams as the original
to allow the user to resign the transaction with a higher gas values to allow the user to resign the transaction with a higher gas values
@param originalTxId {number} - the id of the txMeta that @param originalTxId {number} - the id of the txMeta that
you want to attempt to retry you want to attempt to retry
@ -290,6 +289,7 @@ class TransactionController extends EventEmitter {
publishes the raw tx and sets the txMeta to submitted publishes the raw tx and sets the txMeta to submitted
@param txId {number} - the tx's Id @param txId {number} - the tx's Id
@param rawTx {string} - the hex string of the serialized signed transaction @param rawTx {string} - the hex string of the serialized signed transaction
@returns {Promise<void>}
*/ */
async publishTransaction (txId, rawTx) { async publishTransaction (txId, rawTx) {
const txMeta = this.txStateManager.getTx(txId) const txMeta = this.txStateManager.getTx(txId)
@ -301,15 +301,16 @@ class TransactionController extends EventEmitter {
} }
/** /**
convenience method for the ui thats sets the transaction to rejected Convenience method for the ui thats sets the transaction to rejected
@param txId {number} - the tx's Id @param txId {number} - the tx's Id
@returns {Promise<void>}
*/ */
async cancelTransaction (txId) { async cancelTransaction (txId) {
this.txStateManager.setTxStatusRejected(txId) this.txStateManager.setTxStatusRejected(txId)
} }
/** /**
sets the txHas on the txMeta Sets the txHas on the txMeta
@param txId {number} - the tx's Id @param txId {number} - the tx's Id
@param txHash {string} - the hash for the txMeta @param txHash {string} - the hash for the txMeta
*/ */
@ -325,20 +326,29 @@ class TransactionController extends EventEmitter {
// //
/** maps methods for convenience*/ /** maps methods for convenience*/
_mapMethods () { _mapMethods () {
/** Returns the state in transaction controller */ /** @returns the state in transaction controller */
this.getState = () => this.memStore.getState() this.getState = () => this.memStore.getState()
/** Returns the network number stored in networkStore */ /** @returns the network number stored in networkStore */
this.getNetwork = () => this.networkStore.getState() this.getNetwork = () => this.networkStore.getState()
/** Returns the user selected address */ /** @returns the user selected address */
this.getSelectedAddress = () => this.preferencesStore.getState().selectedAddress this.getSelectedAddress = () => this.preferencesStore.getState().selectedAddress
/** Returns an array of transactions whos status is unapproved */ /** Returns an array of transactions whos status is unapproved */
this.getUnapprovedTxCount = () => Object.keys(this.txStateManager.getUnapprovedTxList()).length this.getUnapprovedTxCount = () => Object.keys(this.txStateManager.getUnapprovedTxList()).length
/** Returns a number that represents how many transactions have the status submitted*/ /**
@returns a number that represents how many transactions have the status submitted
@param account {String} - hex prefixed account
*/
this.getPendingTxCount = (account) => this.txStateManager.getPendingTransactions(account).length this.getPendingTxCount = (account) => this.txStateManager.getPendingTransactions(account).length
/** see txStateManager */ /** see txStateManager */
this.getFilteredTxList = (opts) => this.txStateManager.getFilteredTxList(opts) this.getFilteredTxList = (opts) => this.txStateManager.getFilteredTxList(opts)
} }
/**
If transaction controller was rebooted with transactions that are uncompleted
in steps of the transaction signing or user confirmation process it will either
transition txMetas to a failed state or try to redo those tasks.
*/
_onBootCleanUp () { _onBootCleanUp () {
this.txStateManager.getFilteredTxList({ this.txStateManager.getFilteredTxList({
status: 'unapproved', status: 'unapproved',
@ -364,13 +374,13 @@ class TransactionController extends EventEmitter {
/** /**
is called in constructor applies the listeners for pendingTxTracker txStateManager is called in constructor applies the listeners for pendingTxTracker txStateManager
and blockTracker and blockTracker
<br>
*/ */
_setupListners () { _setupListners () {
this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update')) this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
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))
this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId)) this.pendingTxTracker.on('tx:confirmed', (txId) => this._markNonceDuplicatesDropped(txId))
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:block-update', (txMeta, latestBlockNumber) => { this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
@ -393,8 +403,13 @@ class TransactionController extends EventEmitter {
} }
/**
Sets other txMeta statuses to dropped if the txMeta that has been confirmed has other transactions
in the list have the same nonce
@param txId {Number} - the txId of the transaction that has been confirmed in a block
*/
_markNonceDuplicatesDropped (txId) { _markNonceDuplicatesDropped (txId) {
this.txStateManager.setTxStatusConfirmed(txId)
// get the confirmed transactions nonce and from address // get the confirmed transactions nonce and from address
const txMeta = this.txStateManager.getTx(txId) const txMeta = this.txStateManager.getTx(txId)
const { nonce, from } = txMeta.txParams const { nonce, from } = txMeta.txParams
@ -409,6 +424,9 @@ class TransactionController extends EventEmitter {
}) })
} }
/**
Updates the memStore in transaction controller
*/
_updateMemstore () { _updateMemstore () {
const unapprovedTxs = this.txStateManager.getUnapprovedTxList() const unapprovedTxs = this.txStateManager.getUnapprovedTxList()
const selectedAddressTxList = this.txStateManager.getFilteredTxList({ const selectedAddressTxList = this.txStateManager.getFilteredTxList({

@ -52,7 +52,7 @@ function replayHistory (_shortHistory) {
} }
/** /**
@param txMeta {object} @param txMeta {Object}
@returns {object} a clone object of the txMeta with out history @returns {object} a clone object of the txMeta with out history
*/ */
function snapshotFromTxMeta (txMeta) { function snapshotFromTxMeta (txMeta) {

@ -2,11 +2,11 @@ const EthQuery = require('ethjs-query')
const assert = require('assert') const assert = require('assert')
const Mutex = require('await-semaphore').Mutex const Mutex = require('await-semaphore').Mutex
/** /**
@param opts {Object} - @param opts {Object}
@property {Object} opts.provider a ethereum provider @param {Object} opts.provider a ethereum provider
@property {Function} opts.getPendingTransactions a function that returns an array of txMeta @param {Function} opts.getPendingTransactions a function that returns an array of txMeta
whosee status is `submitted` whosee status is `submitted`
@property {Function} opts.getConfirmedTransactions a function that returns an array of txMeta @param {Function} opts.getConfirmedTransactions a function that returns an array of txMeta
whose status is `confirmed` whose status is `confirmed`
@class @class
*/ */
@ -42,7 +42,7 @@ class NonceTracker {
Note: releaseLock must be called after adding a signed tx to pending transactions (or discarding). Note: releaseLock must be called after adding a signed tx to pending transactions (or discarding).
@param address {string} the hex string for the address whose nonce we are calculating @param address {string} the hex string for the address whose nonce we are calculating
@returns {Promise<Object>} @returns {Promise<NonceDetails>}
*/ */
async getNonceLock (address) { async getNonceLock (address) {
// await global mutex free // await global mutex free
@ -146,6 +146,17 @@ class NonceTracker {
return highestNonce return highestNonce
} }
/**
@typedef {object} highestContinuousFrom
@property {string} - name the name for how the nonce was calculated based on the data used
@property {number} - nonce the next suggested nonce
@property {object} - details the provided starting nonce that was used (for debugging)
*/
/**
@param txList {array} - list of txMeta's
@param startPoint {number} - the highest known locally confirmed nonce
@returns {highestContinuousFrom}
*/
_getHighestContinuousFrom (txList, startPoint) { _getHighestContinuousFrom (txList, startPoint) {
const nonces = txList.map((txMeta) => { const nonces = txList.map((txMeta) => {
const nonce = txMeta.txParams.nonce const nonce = txMeta.txParams.nonce
@ -163,6 +174,10 @@ class NonceTracker {
// this is a hotfix for the fact that the blockTracker will // this is a hotfix for the fact that the blockTracker will
// change when the network changes // change when the network changes
/**
@returns {Object} the current blockTracker
*/
_getBlockTracker () { _getBlockTracker () {
return this.provider._blockTracker return this.provider._blockTracker
} }

@ -9,10 +9,10 @@ const EthQuery = require('ethjs-query')
As well as continues broadcast while in the pending state As well as continues broadcast while in the pending state
<br> <br>
@param config {object} - non optional configuration object consists of: @param config {object} - non optional configuration object consists of:
@property {Object} config.provider @param {Object} config.provider - A network provider.
@property {Object} config.nonceTracker see nonce tracker @param {Object} config.nonceTracker see nonce tracker
@property {function} config.getPendingTransactions a function for getting an array of transactions, @param {function} config.getPendingTransactions a function for getting an array of transactions,
@property {function} config.publishTransaction a async function for publishing raw transactions, @param {function} config.publishTransaction a async function for publishing raw transactions,
@class @class
@ -117,7 +117,7 @@ class PendingTransactionTracker extends EventEmitter {
/** /**
resubmits the individual txMeta used in resubmitPendingTxs resubmits the individual txMeta used in resubmitPendingTxs
@param txMeta {object} - txMeta object @param txMeta {Object} - txMeta object
@param latestBlockNumber {string} - hex string for the latest block number @param latestBlockNumber {string} - hex string for the latest block number
@emits tx:retry @emits tx:retry
@returns txHash {string} @returns txHash {string}
@ -147,7 +147,7 @@ class PendingTransactionTracker extends EventEmitter {
} }
/** /**
Ask the network for the transaction to see if it has been include in a block Ask the network for the transaction to see if it has been include in a block
@param txMeta {object} - the txMeta object @param txMeta {Object} - the txMeta object
@emits tx:failed @emits tx:failed
@emits tx:confirmed @emits tx:confirmed
@emits tx:warning @emits tx:warning
@ -208,7 +208,7 @@ class PendingTransactionTracker extends EventEmitter {
/** /**
checks to see if a confirmed txMeta has the same nonce checks to see if a confirmed txMeta has the same nonce
@param txMeta {object} - txMeta object @param txMeta {Object} - txMeta object
@returns {boolean} @returns {boolean}
*/ */
async _checkIfNonceIsTaken (txMeta) { async _checkIfNonceIsTaken (txMeta) {

@ -7,19 +7,23 @@ const {
const { addHexPrefix } = require('ethereumjs-util') const { addHexPrefix } = require('ethereumjs-util')
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send. const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
/* /**
tx-utils are utility methods for Transaction manager tx-gas-utils are gas utility methods for Transaction manager
its passed ethquery its passed ethquery
and used to do things like calculate gas of a tx. and used to do things like calculate gas of a tx.
@param provider {object} @param {Object} provider - A network provider.
*/ */
module.exports = class TxGasUtil { class TxGasUtil {
constructor (provider) { constructor (provider) {
this.query = new EthQuery(provider) this.query = new EthQuery(provider)
} }
/**
@param txMeta {Object} - the txMeta object
@returns {object} the txMeta object with the gas written to the txParams
*/
async analyzeGasUsage (txMeta) { async analyzeGasUsage (txMeta) {
const block = await this.query.getBlockByNumber('latest', true) const block = await this.query.getBlockByNumber('latest', true)
let estimatedGasHex let estimatedGasHex
@ -39,6 +43,12 @@ module.exports = class TxGasUtil {
return txMeta return txMeta
} }
/**
Estimates the tx's gas usage
@param txMeta {Object} - the txMeta object
@param blockGasLimitHex {string} - hex string of the block's gas limit
@returns {string} the estimated gas limit as a hex string
*/
async estimateTxGas (txMeta, blockGasLimitHex) { async estimateTxGas (txMeta, blockGasLimitHex) {
const txParams = txMeta.txParams const txParams = txMeta.txParams
@ -71,6 +81,12 @@ module.exports = class TxGasUtil {
return await this.query.estimateGas(txParams) return await this.query.estimateGas(txParams)
} }
/**
Writes the gas on the txParams in the txMeta
@param txMeta {Object} - the txMeta object to write to
@param blockGasLimitHex {string} - the block gas limit hex
@param estimatedGasHex {string} - the estimated gas hex
*/
setTxGas (txMeta, blockGasLimitHex, estimatedGasHex) { setTxGas (txMeta, blockGasLimitHex, estimatedGasHex) {
txMeta.estimatedGas = addHexPrefix(estimatedGasHex) txMeta.estimatedGas = addHexPrefix(estimatedGasHex)
const txParams = txMeta.txParams const txParams = txMeta.txParams
@ -88,6 +104,13 @@ module.exports = class TxGasUtil {
return return
} }
/**
Adds a gas buffer with out exceeding the block gas limit
@param initialGasLimitHex {string} - the initial gas limit to add the buffer too
@param blockGasLimitHex {string} - the block gas limit
@returns {string} the buffered gas limit as a hex string
*/
addGasBuffer (initialGasLimitHex, blockGasLimitHex) { addGasBuffer (initialGasLimitHex, blockGasLimitHex) {
const initialGasLimitBn = hexToBn(initialGasLimitHex) const initialGasLimitBn = hexToBn(initialGasLimitHex)
const blockGasLimitBn = hexToBn(blockGasLimitHex) const blockGasLimitBn = hexToBn(blockGasLimitHex)
@ -102,3 +125,5 @@ module.exports = class TxGasUtil {
return bnToHex(upperGasLimitBn) return bnToHex(upperGasLimitBn)
} }
} }
module.exports = TxGasUtil

@ -20,11 +20,11 @@ const { getFinalStates } = require('./lib/util')
<br> - `'confirmed'` the tx has been included in a block. <br> - `'confirmed'` the tx has been included in a block.
<br> - `'failed'` the tx failed for some reason, included on tx data. <br> - `'failed'` the tx failed for some reason, included on tx data.
<br> - `'dropped'` the tx nonce was already used <br> - `'dropped'` the tx nonce was already used
@param opts {object} - @param opts {object}
@property {object} opts.initState with the key transaction {array} @param {object} [opts.initState={ transactions: [] }] initial transactions list with the key transaction {array}
@property {number} opts.txHistoryLimit limit for how many finished @param {number} [opts.txHistoryLimit] limit for how many finished
transactions can hang around in state transactions can hang around in state
@property {function} opts.getNetwork return network number @param {function} opts.getNetwork return network number
@class @class
*/ */
class TransactionStateManager extends EventEmitter { class TransactionStateManager extends EventEmitter {
@ -81,8 +81,9 @@ class TransactionStateManager extends EventEmitter {
} }
/** /**
@param address {string} - hex prefixed address to sort the txMetas for [optional] @param [address] {string} - hex prefixed address to sort the txMetas for [optional]
@returns {array} the tx list whos status is submitted @returns {array} the tx list whos status is submitted if no address is provide
returns all txMetas who's status is submitted for the current network
*/ */
getPendingTransactions (address) { getPendingTransactions (address) {
const opts = { status: 'submitted' } const opts = { status: 'submitted' }
@ -91,8 +92,9 @@ class TransactionStateManager extends EventEmitter {
} }
/** /**
@param address {string} - hex prefixed address to sort the txMetas for [optional] @param [address] {string} - hex prefixed address to sort the txMetas for [optional]
@returns {array} the tx list whos status is confirmed @returns {array} the tx list whos status is confirmed if no address is provide
returns all txMetas who's status is confirmed for the current network
*/ */
getConfirmedTransactions (address) { getConfirmedTransactions (address) {
const opts = { status: 'confirmed' } const opts = { status: 'confirmed' }
@ -106,7 +108,7 @@ class TransactionStateManager extends EventEmitter {
is in its final state is in its final state
it will allso add the key `history` to the txMeta with the snap shot of the original it will allso add the key `history` to the txMeta with the snap shot of the original
object object
@param txMeta {object} @param txMeta {Object}
@returns {object} the txMeta @returns {object} the txMeta
*/ */
addTx (txMeta) { addTx (txMeta) {
@ -155,8 +157,8 @@ class TransactionStateManager extends EventEmitter {
/** /**
updates the txMeta in the list and adds a history entry updates the txMeta in the list and adds a history entry
@param txMeta {object} - the txMeta to update @param txMeta {Object} - the txMeta to update
@param note {string} - a not about the update for history @param [note] {string} - a not about the update for history
*/ */
updateTx (txMeta, note) { updateTx (txMeta, note) {
// validate txParams // validate txParams
@ -225,6 +227,7 @@ class TransactionStateManager extends EventEmitter {
status: 'signed',<br> status: 'signed',<br>
err: undefined,<br> err: undefined,<br>
}<br></code> }<br></code>
@param [initialList=this.getTxList()]
@returns a {array} of txMeta with all @returns a {array} of txMeta with all
options matching options matching
*/ */
@ -253,7 +256,7 @@ class TransactionStateManager extends EventEmitter {
@param key {string} - the key to check @param key {string} - the key to check
@param value - the value your looking for @param value - the value your looking for
@param txList {array} - [optional] the list to search. default is the txList @param [txList=this.getTxList()] {array} - the list to search. default is the txList
from txStateManager#getTxList from txStateManager#getTxList
@returns {array} a list of txMetas who matches the search params @returns {array} a list of txMetas who matches the search params
*/ */

Loading…
Cancel
Save