This repository has been archived by the owner on Jul 19, 2024. It is now read-only.
forked from bitcoinjs/indexd
-
Notifications
You must be signed in to change notification settings - Fork 6
/
adapter.js
158 lines (125 loc) · 5.05 KB
/
adapter.js
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
let dbwrapper = require('./dbwrapper')
let { EventEmitter } = require('events')
let parallel = require('run-parallel')
let Blockchain = require('./blockchain')
let Mempool = require('./mempool')
function Adapter (db, rpc) {
this.db = dbwrapper(db)
this.emitter = new EventEmitter()
this.emitter.setMaxListeners(Infinity)
this.blockchain = new Blockchain(this.emitter, this.db, rpc)
this.mempool = new Mempool(this.emitter, rpc)
}
Adapter.prototype.connect = function (blockId, height, callback) {
this.blockchain.connect(blockId, height, callback)
}
Adapter.prototype.disconnect = function (blockId, callback) {
this.blockchain.disconnect(blockId, callback)
}
// QUERIES
Adapter.prototype.blockIdByTransactionId = function (txId, callback) {
this.blockchain.blockIdByTransactionId(txId, callback)
}
Adapter.prototype.fees = function (n, callback) {
this.blockchain.fees(n, callback)
}
// returns whether (true/false) the script id (SHA256(script)) has even been seen
Adapter.prototype.seenScriptId = function (scId, callback) {
this.blockchain.seenScriptId(scId, (err, result) => {
if (err) return callback(err)
callback(null, result || this.mempool.seenScriptId(scId))
})
}
// returns list of inputs that spends {txo}, array length is guaranteed to be 1 if confirmed [on the blockchain]
Adapter.prototype.spentsFromTxo = function (txo, callback) {
this.blockchain.spentFromTxo(txo, (err, spent) => {
if (err) return callback(err)
// if in blockchain, ignore the mempool
if (spent) return callback(null, [spent])
// otherwise, could be multiple spents in the mempool
callback(null, this.mempool.spentsFromTxo(txo))
})
}
// returns blockchain chain tip id
Adapter.prototype.tip = function (callback) {
this.blockchain.tip(callback)
}
// returns blockchain chain tip height
Adapter.prototype.tipHeight = function (callback) {
this.blockchain.tipHeight(callback)
}
// returns set of transactions associated with script id (SHA256(script))
// minimum height can be provided if many transaction associations exist
Adapter.prototype.transactionIdsByScriptId = function (scId, height, callback, dbLimit) {
this.blockchain.transactionIdsByScriptId(scId, height, (err, txIds, position) => {
if (err) return callback(err)
Object.assign(txIds, this.mempool.transactionIdsByScriptId(scId))
callback(null, txIds, position)
}, dbLimit)
}
Adapter.prototype.transactionIdListFromScriptId = function (scId, height, callback, dbLimit) {
this.blockchain.transactionIdsByScriptId(scId, height, (err, txIdSet, position) => {
if (err) return callback(err)
let txIds = []
for (let txId in txIdSet) txIds.push(txId)
let txIdSet2 = this.mempool.transactionIdsByScriptId(scId)
for (let txId in txIdSet2) {
if (txIdSet[txId]) continue // prevent [impossible?] duplicates
txIds.push(txId)
}
callback(null, txIds, position)
}, dbLimit)
}
// returns a mapping of txos (`txid:vout`) for script id, mapping guarantees no duplicates
// the format `txid:vout`: { .., scId }, supports streamline merging with other queries
Adapter.prototype.txosByScriptId = function (scId, height, callback, dbLimit) {
let resultMap = {}
this.blockchain.txosByScriptId(scId, height, (err, txosMap) => {
if (err) return callback(err)
Object.assign(resultMap, txosMap, this.mempool.txosByScriptId(scId))
callback(null, resultMap)
}, dbLimit)
}
// returns a list of { txId, vout, scId, height }, height is undefined if from the mempool
// has a weak guarantee of no duplicates, enforced by mempool.clear in resync
Adapter.prototype.txosListByScriptId = function (scId, height, callback, dbLimit) {
this.blockchain.__txosListByScriptId(scId, height, (err, txos) => {
if (err) return callback(err)
callback(null, txos.concat(this.mempool.__txosListByScriptId(scId)))
}, dbLimit)
}
// returns extra txo information ({ txId, vout, value }) for the provided txo
// TODO: see #15
Adapter.prototype.txoByTxo = function (txId, vout, callback) {
this.blockchain.txoByTxo(txId, vout, (err, txo) => {
if (err) return callback(err)
// if in blockchain, ignore the mempool
if (txo) return callback(null, txo)
callback(null, this.mempool.txoByTxo(txId, vout))
})
}
// returns a list of unspent txos
Adapter.prototype.utxosByScriptId = function (scId, height, callback, limit) {
this.txosByScriptId(scId, height, (err, txos) => {
if (err) return callback(err)
txos = Object.keys(txos).map(x => txos[x])
let tasks = txos.map((txo) => {
return (next) => this.spentsFromTxo(txo, (err, spents) => {
if (err) return next(err)
if (spents.length !== 0) return next()
this.txoByTxo(txo.txId, txo.vout, (err, txoExtra) => {
if (err) return next(err)
next(null, Object.assign(txo, txoExtra))
})
})
})
parallel(tasks, (err, txos) => {
if (err) return callback(err, txos)
// filter empty txos
callback(err, txos.filter(txo => txo !== undefined))
})
}, limit)
}
module.exports = function makeAdapter (db, rpc) {
return new Adapter(db, rpc)
}