aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/lib/eth-store.js
blob: aeb5667e58593442d4f381f346a86d29508bff7d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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(){}