diff options
Diffstat (limited to 'app/scripts')
-rw-r--r-- | app/scripts/lib/eth-store.js | 144 | ||||
-rw-r--r-- | app/scripts/metamask-controller.js | 2 |
2 files changed, 145 insertions, 1 deletions
diff --git a/app/scripts/lib/eth-store.js b/app/scripts/lib/eth-store.js new file mode 100644 index 000000000..a42b2417f --- /dev/null +++ b/app/scripts/lib/eth-store.js @@ -0,0 +1,144 @@ +/* Ethereum Store + * + * This module is responsible for tracking any number of accounts + * and caching their current balances & transaction counts. + * + * It also tracks transaction hashes, and checks their inclusion status + * on each new block. + */ + +const EventEmitter = require('events').EventEmitter +const inherits = require('util').inherits +const async = require('async') +const clone = require('clone') +const EthQuery = require('eth-query') + +module.exports = EthereumStore + + +inherits(EthereumStore, EventEmitter) +function EthereumStore(engine) { + const self = this + EventEmitter.call(self) + self._currentState = { + accounts: {}, + transactions: {}, + } + self._query = new EthQuery(engine) + + engine.on('block', self._updateForBlock.bind(self)) +} + +// +// public +// + +EthereumStore.prototype.getState = function () { + const self = this + return clone(self._currentState) +} + +EthereumStore.prototype.addAccount = function (address) { + const self = this + self._currentState.accounts[address] = {} + self._didUpdate() + if (!self.currentBlockNumber) return + self._updateAccount(address, noop) +} + +EthereumStore.prototype.removeAccount = function (address) { + const self = this + delete self._currentState.accounts[address] + self._didUpdate() +} + +EthereumStore.prototype.addTransaction = function (txHash) { + const self = this + self._currentState.transactions[txHash] = {} + self._didUpdate() + if (!self.currentBlockNumber) return + self._updateTransaction(self.currentBlockNumber, txHash, noop) +} + +EthereumStore.prototype.removeTransaction = function (address) { + const self = this + delete self._currentState.transactions[address] + self._didUpdate() +} + + +// +// private +// + +EthereumStore.prototype._didUpdate = function () { + const self = this + var state = self.getState() + self.emit('update', state) +} + +EthereumStore.prototype._updateForBlock = function (block) { + const self = this + var blockNumber = '0x' + block.number.toString('hex') + self.currentBlockNumber = blockNumber + async.parallel([ + self._updateAccounts.bind(self), + self._updateTransactions.bind(self, blockNumber), + ], function (err) { + if (err) return console.error(err) + self.emit('block', self.getState()) + self._didUpdate() + }) +} + +EthereumStore.prototype._updateAccounts = function (cb) { + var accountsState = this._currentState.accounts + var addresses = Object.keys(accountsState) + async.each(addresses, this._updateAccount.bind(this), cb) +} + +EthereumStore.prototype._updateAccount = function (address, cb) { + var accountsState = this._currentState.accounts + this.getAccount(address, function (err, result) { + if (err) return cb(err) + result.address = address + // only populate if the entry is still present + if (accountsState[address]) { + accountsState[address] = result + } + cb(null, result) + }) +} + +EthereumStore.prototype.getAccount = function (address, cb) { + const query = this._query + async.parallel({ + balance: query.getBalance.bind(query, address), + nonce: query.getTransactionCount.bind(query, address), + code: query.getCode.bind(query, address), + }, cb) +} + +EthereumStore.prototype._updateTransactions = function (block, cb) { + const self = this + var transactionsState = self._currentState.transactions + var txHashes = Object.keys(transactionsState) + async.each(txHashes, self._updateTransaction.bind(self, block), cb) +} + +EthereumStore.prototype._updateTransaction = function (block, txHash, cb) { + const self = this + // would use the block here to determine how many confirmations the tx has + var transactionsState = self._currentState.transactions + self._query.getTransaction(txHash, function (err, result) { + if (err) return cb(err) + // only populate if the entry is still present + if (transactionsState[txHash]) { + transactionsState[txHash] = result + self._didUpdate() + } + cb(null, result) + }) +} + +function noop() {} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index c0d2f3b4c..8bfb85370 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -1,5 +1,5 @@ const extend = require('xtend') -const EthStore = require('eth-store') +const EthStore = require('./lib/eth-store') const MetaMaskProvider = require('web3-provider-engine/zero.js') const KeyringController = require('./keyring-controller') const NoticeController = require('./notice-controller') |