diff options
-rw-r--r-- | app/scripts/lib/eth-store.js | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/app/scripts/lib/eth-store.js b/app/scripts/lib/eth-store.js new file mode 100644 index 000000000..aeb5667e5 --- /dev/null +++ b/app/scripts/lib/eth-store.js @@ -0,0 +1,132 @@ +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._updateAccountForBlock(self.currentBlockNumber, 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._updateAccountsForBlock.bind(self, blockNumber), + self._updateTransactions.bind(self, blockNumber), + ], function(err){ + if (err) return console.error(err) + self.emit('block', self.getState()) + }) +} + +EthereumStore.prototype._updateAccountsForBlock = function(block, cb) { + const self = this + var accountsState = self._currentState.accounts + var addresses = Object.keys(accountsState) + async.each(addresses, self._updateAccountForBlock.bind(self, block), cb) +} + +EthereumStore.prototype._updateAccountForBlock = function(block, address, cb) { + const self = this + var accountsState = self._currentState.accounts + self._query.getAccount(address, block, 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 + self._didUpdate() + } + cb(null, result) + }) +} + +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 valuesFor(obj){ + return Object.keys(obj).map(function(key){ return obj[key] }) +} + +function noop(){} |