1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-24 02:58:09 +01:00
metamask-extension/app/scripts/lib/eth-store.js

147 lines
3.8 KiB
JavaScript
Raw Normal View History

2017-01-04 23:07:08 +01:00
/* 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.
*/
2017-01-04 22:56:21 +01:00
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
//
2017-01-04 23:05:00 +01:00
EthereumStore.prototype.getState = function () {
2017-01-04 22:56:21 +01:00
const self = this
return clone(self._currentState)
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype.addAccount = function (address) {
2017-01-04 22:56:21 +01:00
const self = this
self._currentState.accounts[address] = {}
self._didUpdate()
if (!self.currentBlockNumber) return
self._updateAccount(address, () => {
self._didUpdate()
})
2017-01-04 22:56:21 +01:00
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype.removeAccount = function (address) {
2017-01-04 22:56:21 +01:00
const self = this
delete self._currentState.accounts[address]
self._didUpdate()
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype.addTransaction = function (txHash) {
2017-01-04 22:56:21 +01:00
const self = this
self._currentState.transactions[txHash] = {}
self._didUpdate()
if (!self.currentBlockNumber) return
self._updateTransaction(self.currentBlockNumber, txHash, noop)
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype.removeTransaction = function (address) {
2017-01-04 22:56:21 +01:00
const self = this
delete self._currentState.transactions[address]
self._didUpdate()
}
//
// private
//
2017-01-04 23:05:00 +01:00
EthereumStore.prototype._didUpdate = function () {
2017-01-04 22:56:21 +01:00
const self = this
var state = self.getState()
self.emit('update', state)
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype._updateForBlock = function (block) {
2017-01-04 22:56:21 +01:00
const self = this
2017-01-04 23:14:45 +01:00
var blockNumber = '0x' + block.number.toString('hex')
2017-01-04 22:56:21 +01:00
self.currentBlockNumber = blockNumber
async.parallel([
self._updateAccounts.bind(self),
2017-01-04 22:56:21 +01:00
self._updateTransactions.bind(self, blockNumber),
2017-01-04 23:05:00 +01:00
], function (err) {
2017-01-04 22:56:21 +01:00
if (err) return console.error(err)
self.emit('block', self.getState())
self._didUpdate()
2017-01-04 22:56:21 +01:00
})
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype._updateAccounts = function (cb) {
var accountsState = this._currentState.accounts
2017-01-04 22:56:21 +01:00
var addresses = Object.keys(accountsState)
async.each(addresses, this._updateAccount.bind(this), cb)
2017-01-04 22:56:21 +01:00
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype._updateAccount = function (address, cb) {
var accountsState = this._currentState.accounts
this.getAccount(address, function (err, result) {
2017-01-04 22:56:21 +01:00
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)
})
}
2017-01-04 23:05:00 +01:00
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)
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype._updateTransactions = function (block, cb) {
2017-01-04 22:56:21 +01:00
const self = this
var transactionsState = self._currentState.transactions
var txHashes = Object.keys(transactionsState)
async.each(txHashes, self._updateTransaction.bind(self, block), cb)
}
2017-01-04 23:05:00 +01:00
EthereumStore.prototype._updateTransaction = function (block, txHash, cb) {
2017-01-04 22:56:21 +01:00
const self = this
// would use the block here to determine how many confirmations the tx has
var transactionsState = self._currentState.transactions
2017-01-04 23:05:00 +01:00
self._query.getTransaction(txHash, function (err, result) {
2017-01-04 22:56:21 +01:00
if (err) return cb(err)
2017-01-04 23:14:45 +01:00
// only populate if the entry is still present
if (transactionsState[txHash]) {
2017-01-04 22:56:21 +01:00
transactionsState[txHash] = result
self._didUpdate()
}
cb(null, result)
})
}
2017-01-04 23:05:00 +01:00
function noop() {}