From 8ffce8b59dc95ffa1af72293f40c21f78fd103bb Mon Sep 17 00:00:00 2001 From: frankiebee Date: Wed, 25 Apr 2018 11:13:51 -0700 Subject: transactions - more docs and clean ups --- app/scripts/controllers/transactions/index.js | 70 ++++++++++++++-------- .../transactions/lib/tx-state-history-helper.js | 2 +- .../controllers/transactions/nonce-tracker.js | 25 ++++++-- .../controllers/transactions/pending-tx-tracker.js | 14 ++--- .../controllers/transactions/tx-gas-utils.js | 33 ++++++++-- .../controllers/transactions/tx-state-manager.js | 27 +++++---- 6 files changed, 116 insertions(+), 55 deletions(-) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 321438598..541f1db73 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -26,17 +26,16 @@ const log = require('loglevel') @class - @param {Object} opts - @property {Object} opts.initState initial transaction list default is an empty array - @property {Object} opts.networkStore an observable store for network number - @param {Object} opts.blockTracker - An instance of eth-blocktracker - @property {Object} opts.provider - @param {Object} opts.provider - A network provider. - @property {Object} opts.signTransaction function the signs an ethereumjs-tx - @property {function} opts.getGasPrice optional gas price calculator - @property {function} opts.signTransaction ethTx signer that returns a rawTx - @property {number} opts.txHistoryLimit number *optional* for limiting how many transactions are in state - @property {Object} opts.preferencesStore + @param {object} - opts + @param {object} opts.initState - initial transaction list default is an empty array + @param {Object} opts.networkStore - an observable store for network number + @param {Object} opts.blockTracker - An instance of eth-blocktracker + @param {Object} opts.provider - A network provider. + @param {Function} opts.signTransaction - function the signs an ethereumjs-tx + @param {Function} [opts.getGasPrice] - optional gas price calculator + @param {Function} opts.signTransaction - ethTx signer that returns a rawTx + @param {Number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state + @param {Object} opts.preferencesStore */ 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 */ wipeTransactions (address) { @@ -115,9 +114,9 @@ class TransactionController extends EventEmitter { /** add a new unapproved transaction to the pipeline - @returns {promise} - @param txParams {Object} - txParams for the transaction - @param opts {Object} - with the key origin to put the origin on the txMeta + @returns {Promise} the hash of the transaction after being submitted to the network + @param txParams {object} - txParams for the transaction + @param opts {object} - with the key origin to put the origin on the txMeta */ async newUnapprovedTransaction (txParams, opts = {}) { 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 @returns {txMeta} @@ -173,7 +172,7 @@ class TransactionController extends EventEmitter { /** adds the tx gas defaults: gas && gasPrice @param txMeta {Object} - the txMeta object - @returns {promise} resolves with txMeta + @returns {Promise} resolves with txMeta */ async addTxGasDefaults (txMeta) { 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 @param originalTxId {number} - the id of the txMeta that you want to attempt to retry @@ -290,6 +289,7 @@ class TransactionController extends EventEmitter { publishes the raw tx and sets the txMeta to submitted @param txId {number} - the tx's Id @param rawTx {string} - the hex string of the serialized signed transaction + @returns {Promise} */ async publishTransaction (txId, rawTx) { 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 + @returns {Promise} */ async cancelTransaction (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 txHash {string} - the hash for the txMeta */ @@ -325,20 +326,29 @@ class TransactionController extends EventEmitter { // /** maps methods for convenience*/ _mapMethods () { - /** Returns the state in transaction controller */ + /** @returns the state in transaction controller */ this.getState = () => this.memStore.getState() - /** Returns the network number stored in networkStore */ + /** @returns the network number stored in networkStore */ this.getNetwork = () => this.networkStore.getState() - /** Returns the user selected address */ + /** @returns the user selected address */ this.getSelectedAddress = () => this.preferencesStore.getState().selectedAddress /** Returns an array of transactions whos status is unapproved */ 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 /** see txStateManager */ 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 () { this.txStateManager.getFilteredTxList({ status: 'unapproved', @@ -364,13 +374,13 @@ class TransactionController extends EventEmitter { /** is called in constructor applies the listeners for pendingTxTracker txStateManager and blockTracker -
*/ _setupListners () { this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update')) this.pendingTxTracker.on('tx:warning', (txMeta) => { 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:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager)) 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) { - this.txStateManager.setTxStatusConfirmed(txId) // get the confirmed transactions nonce and from address const txMeta = this.txStateManager.getTx(txId) const { nonce, from } = txMeta.txParams @@ -409,6 +424,9 @@ class TransactionController extends EventEmitter { }) } + /** + Updates the memStore in transaction controller + */ _updateMemstore () { const unapprovedTxs = this.txStateManager.getUnapprovedTxList() const selectedAddressTxList = this.txStateManager.getFilteredTxList({ diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js index 7a57e3cb5..59a4b562c 100644 --- a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js +++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js @@ -52,7 +52,7 @@ function replayHistory (_shortHistory) { } /** - @param txMeta {object} + @param txMeta {Object} @returns {object} a clone object of the txMeta with out history */ function snapshotFromTxMeta (txMeta) { diff --git a/app/scripts/controllers/transactions/nonce-tracker.js b/app/scripts/controllers/transactions/nonce-tracker.js index e2c5dadef..f8cdc5523 100644 --- a/app/scripts/controllers/transactions/nonce-tracker.js +++ b/app/scripts/controllers/transactions/nonce-tracker.js @@ -2,11 +2,11 @@ const EthQuery = require('ethjs-query') const assert = require('assert') const Mutex = require('await-semaphore').Mutex /** - @param opts {Object} - - @property {Object} opts.provider a ethereum provider - @property {Function} opts.getPendingTransactions a function that returns an array of txMeta + @param opts {Object} + @param {Object} opts.provider a ethereum provider + @param {Function} opts.getPendingTransactions a function that returns an array of txMeta 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` @class */ @@ -42,7 +42,7 @@ class NonceTracker { 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 - @returns {Promise} + @returns {Promise} */ async getNonceLock (address) { // await global mutex free @@ -146,6 +146,17 @@ class NonceTracker { 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) { const nonces = txList.map((txMeta) => { const nonce = txMeta.txParams.nonce @@ -163,6 +174,10 @@ class NonceTracker { // this is a hotfix for the fact that the blockTracker will // change when the network changes + + /** + @returns {Object} the current blockTracker + */ _getBlockTracker () { return this.provider._blockTracker } diff --git a/app/scripts/controllers/transactions/pending-tx-tracker.js b/app/scripts/controllers/transactions/pending-tx-tracker.js index f7c9993b3..6e2fcb40b 100644 --- a/app/scripts/controllers/transactions/pending-tx-tracker.js +++ b/app/scripts/controllers/transactions/pending-tx-tracker.js @@ -9,10 +9,10 @@ const EthQuery = require('ethjs-query') As well as continues broadcast while in the pending state
@param config {object} - non optional configuration object consists of: - @property {Object} config.provider - @property {Object} config.nonceTracker see nonce tracker - @property {function} config.getPendingTransactions a function for getting an array of transactions, - @property {function} config.publishTransaction a async function for publishing raw transactions, + @param {Object} config.provider - A network provider. + @param {Object} config.nonceTracker see nonce tracker + @param {function} config.getPendingTransactions a function for getting an array of transactions, + @param {function} config.publishTransaction a async function for publishing raw transactions, @class @@ -117,7 +117,7 @@ class PendingTransactionTracker extends EventEmitter { /** 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 @emits tx:retry @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 - @param txMeta {object} - the txMeta object + @param txMeta {Object} - the txMeta object @emits tx:failed @emits tx:confirmed @emits tx:warning @@ -208,7 +208,7 @@ class PendingTransactionTracker extends EventEmitter { /** checks to see if a confirmed txMeta has the same nonce - @param txMeta {object} - txMeta object + @param txMeta {Object} - txMeta object @returns {boolean} */ async _checkIfNonceIsTaken (txMeta) { diff --git a/app/scripts/controllers/transactions/tx-gas-utils.js b/app/scripts/controllers/transactions/tx-gas-utils.js index 31a5bfcf4..36b5cdbc9 100644 --- a/app/scripts/controllers/transactions/tx-gas-utils.js +++ b/app/scripts/controllers/transactions/tx-gas-utils.js @@ -7,19 +7,23 @@ const { const { addHexPrefix } = require('ethereumjs-util') 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 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) { 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) { const block = await this.query.getBlockByNumber('latest', true) let estimatedGasHex @@ -39,6 +43,12 @@ module.exports = class TxGasUtil { 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) { const txParams = txMeta.txParams @@ -71,6 +81,12 @@ module.exports = class TxGasUtil { 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) { txMeta.estimatedGas = addHexPrefix(estimatedGasHex) const txParams = txMeta.txParams @@ -88,6 +104,13 @@ module.exports = class TxGasUtil { 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) { const initialGasLimitBn = hexToBn(initialGasLimitHex) const blockGasLimitBn = hexToBn(blockGasLimitHex) @@ -102,3 +125,5 @@ module.exports = class TxGasUtil { return bnToHex(upperGasLimitBn) } } + +module.exports = TxGasUtil \ No newline at end of file diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js index 328024925..53428c333 100644 --- a/app/scripts/controllers/transactions/tx-state-manager.js +++ b/app/scripts/controllers/transactions/tx-state-manager.js @@ -20,11 +20,11 @@ const { getFinalStates } = require('./lib/util')
- `'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 - @param opts {object} - - @property {object} opts.initState with the key transaction {array} - @property {number} opts.txHistoryLimit limit for how many finished + @param opts {object} + @param {object} [opts.initState={ transactions: [] }] initial transactions list with the key transaction {array} + @param {number} [opts.txHistoryLimit] limit for how many finished transactions can hang around in state - @property {function} opts.getNetwork return network number + @param {function} opts.getNetwork return network number @class */ class TransactionStateManager extends EventEmitter { @@ -81,8 +81,9 @@ class TransactionStateManager extends EventEmitter { } /** - @param address {string} - hex prefixed address to sort the txMetas for [optional] - @returns {array} the tx list whos status is submitted + @param [address] {string} - hex prefixed address to sort the txMetas for [optional] + @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) { const opts = { status: 'submitted' } @@ -91,8 +92,9 @@ class TransactionStateManager extends EventEmitter { } /** - @param address {string} - hex prefixed address to sort the txMetas for [optional] - @returns {array} the tx list whos status is confirmed + @param [address] {string} - hex prefixed address to sort the txMetas for [optional] + @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) { const opts = { status: 'confirmed' } @@ -106,7 +108,7 @@ class TransactionStateManager extends EventEmitter { is in its final state it will allso add the key `history` to the txMeta with the snap shot of the original object - @param txMeta {object} + @param txMeta {Object} @returns {object} the txMeta */ addTx (txMeta) { @@ -155,8 +157,8 @@ class TransactionStateManager extends EventEmitter { /** updates the txMeta in the list and adds a history entry - @param txMeta {object} - the txMeta to update - @param note {string} - a not about the update for history + @param txMeta {Object} - the txMeta to update + @param [note] {string} - a not about the update for history */ updateTx (txMeta, note) { // validate txParams @@ -225,6 +227,7 @@ class TransactionStateManager extends EventEmitter { status: 'signed',
err: undefined,
}
+ @param [initialList=this.getTxList()] @returns a {array} of txMeta with all options matching */ @@ -253,7 +256,7 @@ class TransactionStateManager extends EventEmitter { @param key {string} - the key to check @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 @returns {array} a list of txMetas who matches the search params */ -- cgit v1.2.3