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(){}
|