hypercore 9.12.0 → 10.0.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/test-node.yml +3 -4
- package/README.md +131 -404
- package/__snapshots__/test/storage.js.snapshot.cjs +15 -0
- package/examples/announce.js +19 -0
- package/examples/basic.js +10 -0
- package/examples/http.js +123 -0
- package/examples/lookup.js +20 -0
- package/index.js +365 -1600
- package/lib/bitfield.js +113 -285
- package/lib/block-encryption.js +68 -0
- package/lib/block-store.js +58 -0
- package/lib/core.js +468 -0
- package/lib/extensions.js +76 -0
- package/lib/merkle-tree.js +1110 -0
- package/lib/messages.js +571 -0
- package/lib/mutex.js +39 -0
- package/lib/oplog.js +224 -0
- package/lib/protocol.js +525 -0
- package/lib/random-iterator.js +46 -0
- package/lib/remote-bitfield.js +24 -0
- package/lib/replicator.js +857 -0
- package/lib/streams.js +39 -0
- package/package.json +44 -45
- package/test/basic.js +59 -471
- package/test/bitfield.js +48 -133
- package/test/core.js +290 -0
- package/test/encodings.js +18 -0
- package/test/encryption.js +123 -0
- package/test/extension.js +71 -0
- package/test/helpers/index.js +23 -0
- package/test/merkle-tree.js +518 -0
- package/test/mutex.js +137 -0
- package/test/oplog.js +399 -0
- package/test/preload.js +72 -0
- package/test/replicate.js +227 -824
- package/test/sessions.js +173 -0
- package/test/storage.js +31 -0
- package/test/streams.js +39 -146
- package/test/user-data.js +47 -0
- package/bench/all.sh +0 -65
- package/bench/copy-64kb-blocks.js +0 -51
- package/bench/helpers/read-throttled.js +0 -27
- package/bench/helpers/read.js +0 -47
- package/bench/helpers/write.js +0 -29
- package/bench/read-16kb-blocks-proof-throttled.js +0 -1
- package/bench/read-16kb-blocks-proof.js +0 -1
- package/bench/read-16kb-blocks-throttled.js +0 -1
- package/bench/read-16kb-blocks.js +0 -1
- package/bench/read-512b-blocks.js +0 -1
- package/bench/read-64kb-blocks-linear-batch.js +0 -18
- package/bench/read-64kb-blocks-linear.js +0 -18
- package/bench/read-64kb-blocks-proof.js +0 -1
- package/bench/read-64kb-blocks.js +0 -1
- package/bench/replicate-16kb-blocks.js +0 -19
- package/bench/replicate-64kb-blocks.js +0 -19
- package/bench/write-16kb-blocks.js +0 -1
- package/bench/write-512b-blocks.js +0 -1
- package/bench/write-64kb-blocks-static.js +0 -1
- package/bench/write-64kb-blocks.js +0 -1
- package/example.js +0 -23
- package/lib/cache.js +0 -26
- package/lib/crypto.js +0 -5
- package/lib/replicate.js +0 -829
- package/lib/safe-buffer-equals.js +0 -6
- package/lib/storage.js +0 -421
- package/lib/tree-index.js +0 -183
- package/test/ack.js +0 -306
- package/test/audit.js +0 -36
- package/test/cache.js +0 -93
- package/test/compat.js +0 -209
- package/test/copy.js +0 -377
- package/test/default-storage.js +0 -51
- package/test/extensions.js +0 -137
- package/test/get.js +0 -64
- package/test/head.js +0 -65
- package/test/helpers/create-tracking-ram.js +0 -27
- package/test/helpers/create.js +0 -6
- package/test/helpers/replicate.js +0 -4
- package/test/seek.js +0 -234
- package/test/selections.js +0 -95
- package/test/set-uploading-downloading.js +0 -91
- package/test/stats.js +0 -77
- package/test/timeouts.js +0 -22
- package/test/tree-index.js +0 -841
- package/test/update.js +0 -156
- package/test/value-encoding.js +0 -52
package/lib/storage.js
DELETED
|
@@ -1,421 +0,0 @@
|
|
|
1
|
-
var uint64be = require('uint64be')
|
|
2
|
-
var flat = require('flat-tree')
|
|
3
|
-
var createCache = require('./cache')
|
|
4
|
-
|
|
5
|
-
module.exports = Storage
|
|
6
|
-
|
|
7
|
-
var noarr = []
|
|
8
|
-
|
|
9
|
-
function Storage (create, opts) {
|
|
10
|
-
if (!(this instanceof Storage)) return new Storage(create, opts)
|
|
11
|
-
|
|
12
|
-
const cache = createCache(opts)
|
|
13
|
-
|
|
14
|
-
this.treeCache = cache.tree || null
|
|
15
|
-
this.dataCache = cache.data || null
|
|
16
|
-
this.key = null
|
|
17
|
-
this.secretKey = null
|
|
18
|
-
this.tree = null
|
|
19
|
-
this.data = null
|
|
20
|
-
this.bitfield = null
|
|
21
|
-
this.signatures = null
|
|
22
|
-
this.create = create
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
Storage.prototype.putData = function (index, data, nodes, cb) {
|
|
26
|
-
if (!cb) cb = noop
|
|
27
|
-
var self = this
|
|
28
|
-
if (!data.length) return cb(null)
|
|
29
|
-
this.dataOffset(index, nodes, function (err, offset, size) {
|
|
30
|
-
if (err) return cb(err)
|
|
31
|
-
if (size !== data.length) return cb(new Error('Unexpected data size'))
|
|
32
|
-
self.data.write(offset, data, cb)
|
|
33
|
-
})
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
Storage.prototype.getData = function (index, cb) {
|
|
37
|
-
var self = this
|
|
38
|
-
var cached = this.dataCache && this.dataCache.get(index)
|
|
39
|
-
if (cached) return process.nextTick(cb, null, cached)
|
|
40
|
-
this.dataOffset(index, noarr, function (err, offset, size) {
|
|
41
|
-
if (err) return cb(err)
|
|
42
|
-
self.data.read(offset, size, (err, data) => {
|
|
43
|
-
if (err) return cb(err)
|
|
44
|
-
if (self.dataCache) self.dataCache.set(index, data)
|
|
45
|
-
return cb(null, data)
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
Storage.prototype.nextSignature = function (index, cb) {
|
|
51
|
-
var self = this
|
|
52
|
-
|
|
53
|
-
this._getSignature(index, function (err, signature) {
|
|
54
|
-
if (err) return cb(err)
|
|
55
|
-
if (isBlank(signature)) return self.nextSignature(index + 1, cb)
|
|
56
|
-
cb(null, { index: index, signature: signature })
|
|
57
|
-
})
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
Storage.prototype.getSignature = function (index, cb) {
|
|
61
|
-
this._getSignature(index, function (err, signature) {
|
|
62
|
-
if (err) return cb(err)
|
|
63
|
-
if (isBlank(signature)) return cb(new Error('No signature found'))
|
|
64
|
-
cb(null, signature)
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Caching not enabled for signatures because they are rarely reused.
|
|
69
|
-
Storage.prototype._getSignature = function (index, cb) {
|
|
70
|
-
this.signatures.read(32 + 64 * index, 64, cb)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
Storage.prototype.putSignature = function (index, signature, cb) {
|
|
74
|
-
this.signatures.write(32 + 64 * index, signature, cb)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
Storage.prototype.deleteSignatures = function (start, end, cb) {
|
|
78
|
-
this.signatures.del(32 + 64 * start, (end - start) * 64, cb)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
Storage.prototype.dataOffset = function (index, cachedNodes, cb) {
|
|
82
|
-
var roots = flat.fullRoots(2 * index)
|
|
83
|
-
var self = this
|
|
84
|
-
var offset = 0
|
|
85
|
-
var pending = roots.length
|
|
86
|
-
var error = null
|
|
87
|
-
var blk = 2 * index
|
|
88
|
-
|
|
89
|
-
if (!pending) {
|
|
90
|
-
pending = 1
|
|
91
|
-
onnode(null, null)
|
|
92
|
-
return
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
for (var i = 0; i < roots.length; i++) {
|
|
96
|
-
var node = findNode(cachedNodes, roots[i])
|
|
97
|
-
if (node) onnode(null, node)
|
|
98
|
-
else this.getNode(roots[i], onnode)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function onlast (err, node) {
|
|
102
|
-
if (err) return cb(err)
|
|
103
|
-
cb(null, offset, node.size)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function onnode (err, node) {
|
|
107
|
-
if (err) error = err
|
|
108
|
-
if (node) offset += node.size
|
|
109
|
-
if (--pending) return
|
|
110
|
-
|
|
111
|
-
if (error) return cb(error)
|
|
112
|
-
|
|
113
|
-
var last = findNode(cachedNodes, blk)
|
|
114
|
-
if (last) onlast(null, last)
|
|
115
|
-
else self.getNode(blk, onlast)
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Caching not enabled for batch reads because they'd be complicated to batch and they're rarely used.
|
|
120
|
-
Storage.prototype.getDataBatch = function (start, n, cb) {
|
|
121
|
-
var result = new Array(n)
|
|
122
|
-
var sizes = new Array(n)
|
|
123
|
-
var self = this
|
|
124
|
-
|
|
125
|
-
this.dataOffset(start, noarr, function (err, offset, size) {
|
|
126
|
-
if (err) return cb(err)
|
|
127
|
-
|
|
128
|
-
start++
|
|
129
|
-
n--
|
|
130
|
-
|
|
131
|
-
if (n <= 0) return ontree(null, null)
|
|
132
|
-
self.tree.read(32 + 80 * start, 80 * n - 40, ontree)
|
|
133
|
-
|
|
134
|
-
function ontree (err, buf) {
|
|
135
|
-
if (err) return cb(err)
|
|
136
|
-
|
|
137
|
-
var total = sizes[0] = size
|
|
138
|
-
|
|
139
|
-
if (buf) {
|
|
140
|
-
for (var i = 1; i < sizes.length; i++) {
|
|
141
|
-
sizes[i] = uint64be.decode(buf, 32 + (i - 1) * 80)
|
|
142
|
-
total += sizes[i]
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
self.data.read(offset, total, ondata)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
function ondata (err, buf) {
|
|
150
|
-
if (err) return cb(err)
|
|
151
|
-
var total = 0
|
|
152
|
-
for (var i = 0; i < result.length; i++) {
|
|
153
|
-
result[i] = buf.slice(total, total += sizes[i])
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
cb(null, result)
|
|
157
|
-
}
|
|
158
|
-
})
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
Storage.prototype.getNode = function (index, cb) {
|
|
162
|
-
if (this.treeCache) {
|
|
163
|
-
var cached = this.treeCache.get(index)
|
|
164
|
-
if (cached) return cb(null, cached)
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
var self = this
|
|
168
|
-
|
|
169
|
-
this.tree.read(32 + 40 * index, 40, function (err, buf) {
|
|
170
|
-
if (err) return cb(err)
|
|
171
|
-
|
|
172
|
-
var hash = buf.slice(0, 32)
|
|
173
|
-
var size = uint64be.decode(buf, 32)
|
|
174
|
-
|
|
175
|
-
if (!size && isBlank(hash)) return cb(new Error('No node found'))
|
|
176
|
-
|
|
177
|
-
var val = new Node(index, self.treeCache ? copyMaybe(hash, 40) : hash, size, null)
|
|
178
|
-
if (self.treeCache) self.treeCache.set(index, val)
|
|
179
|
-
cb(null, val)
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
Storage.prototype.putNodeBatch = function (index, nodes, cb) {
|
|
184
|
-
if (!cb) cb = noop
|
|
185
|
-
|
|
186
|
-
var buf = Buffer.alloc(nodes.length * 40)
|
|
187
|
-
|
|
188
|
-
for (var i = 0; i < nodes.length; i++) {
|
|
189
|
-
var offset = i * 40
|
|
190
|
-
var node = nodes[i]
|
|
191
|
-
if (!node) continue
|
|
192
|
-
node.hash.copy(buf, offset)
|
|
193
|
-
uint64be.encode(node.size, buf, 32 + offset)
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
this.tree.write(32 + 40 * index, buf, cb)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
Storage.prototype.putNode = function (index, node, cb) {
|
|
200
|
-
if (!cb) cb = noop
|
|
201
|
-
|
|
202
|
-
// TODO: re-enable put cache. currently this causes a memleak
|
|
203
|
-
// because node.hash is a slice of the big data buffer on replicate
|
|
204
|
-
// if (this.cache) this.cache.set(index, node)
|
|
205
|
-
|
|
206
|
-
var buf = Buffer.allocUnsafe(40)
|
|
207
|
-
|
|
208
|
-
node.hash.copy(buf, 0)
|
|
209
|
-
uint64be.encode(node.size, buf, 32)
|
|
210
|
-
this.tree.write(32 + 40 * index, buf, cb)
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
Storage.prototype.putBitfield = function (offset, data, cb) {
|
|
214
|
-
this.bitfield.write(32 + offset, data, cb)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
Storage.prototype.close = function (cb) {
|
|
218
|
-
if (!cb) cb = noop
|
|
219
|
-
var missing = 6
|
|
220
|
-
var error = null
|
|
221
|
-
|
|
222
|
-
close(this.bitfield, done)
|
|
223
|
-
close(this.tree, done)
|
|
224
|
-
close(this.data, done)
|
|
225
|
-
close(this.key, done)
|
|
226
|
-
close(this.secretKey, done)
|
|
227
|
-
close(this.signatures, done)
|
|
228
|
-
|
|
229
|
-
function done (err) {
|
|
230
|
-
if (err) error = err
|
|
231
|
-
if (--missing) return
|
|
232
|
-
cb(error)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
Storage.prototype.destroy = function (cb) {
|
|
237
|
-
if (!cb) cb = noop
|
|
238
|
-
var missing = 6
|
|
239
|
-
var error = null
|
|
240
|
-
|
|
241
|
-
destroy(this.bitfield, done)
|
|
242
|
-
destroy(this.tree, done)
|
|
243
|
-
destroy(this.data, done)
|
|
244
|
-
destroy(this.key, done)
|
|
245
|
-
destroy(this.secretKey, done)
|
|
246
|
-
destroy(this.signatures, done)
|
|
247
|
-
|
|
248
|
-
function done (err) {
|
|
249
|
-
if (err) error = err
|
|
250
|
-
if (--missing) return
|
|
251
|
-
cb(error)
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
Storage.prototype.openKey = function (opts, cb) {
|
|
256
|
-
if (typeof opts === 'function') return this.openKey({}, opts)
|
|
257
|
-
if (!this.key) this.key = this.create('key', opts)
|
|
258
|
-
this.key.read(0, 32, cb)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
Storage.prototype.open = function (opts, cb) {
|
|
262
|
-
if (typeof opts === 'function') return this.open({}, opts)
|
|
263
|
-
|
|
264
|
-
var self = this
|
|
265
|
-
var error = null
|
|
266
|
-
var missing = 5
|
|
267
|
-
|
|
268
|
-
if (!this.key) this.key = this.create('key', opts)
|
|
269
|
-
if (!this.secretKey) this.secretKey = this.create('secret_key', opts)
|
|
270
|
-
if (!this.tree) this.tree = this.create('tree', opts)
|
|
271
|
-
if (!this.data) this.data = this.create('data', opts)
|
|
272
|
-
if (!this.bitfield) this.bitfield = this.create('bitfield', opts)
|
|
273
|
-
if (!this.signatures) this.signatures = this.create('signatures', opts)
|
|
274
|
-
|
|
275
|
-
var result = {
|
|
276
|
-
bitfield: [],
|
|
277
|
-
bitfieldPageSize: 3584, // we upgraded the page size to fix a bug
|
|
278
|
-
secretKey: null,
|
|
279
|
-
key: null
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
this.bitfield.read(0, 32, function (err, h) {
|
|
283
|
-
if (err && err.code === 'ELOCKED') return cb(err)
|
|
284
|
-
if (h) result.bitfieldPageSize = h.readUInt16BE(5)
|
|
285
|
-
self.bitfield.write(0, header(0, result.bitfieldPageSize, null), function (err) {
|
|
286
|
-
if (err) return cb(err)
|
|
287
|
-
readAll(self.bitfield, 32, result.bitfieldPageSize, function (err, pages) {
|
|
288
|
-
if (pages) result.bitfield = pages
|
|
289
|
-
done(err)
|
|
290
|
-
})
|
|
291
|
-
})
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
this.signatures.write(0, header(1, 64, 'Ed25519'), done)
|
|
295
|
-
this.tree.write(0, header(2, 40, 'BLAKE2b'), done)
|
|
296
|
-
|
|
297
|
-
// TODO: Improve the error handling here.
|
|
298
|
-
// I.e. if secretKey length === 64 and it fails, error
|
|
299
|
-
|
|
300
|
-
this.secretKey.read(0, 64, function (_, data) {
|
|
301
|
-
if (data) result.secretKey = data
|
|
302
|
-
done(null)
|
|
303
|
-
})
|
|
304
|
-
|
|
305
|
-
this.key.read(0, 32, function (_, data) {
|
|
306
|
-
if (data) result.key = data
|
|
307
|
-
done(null)
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
function done (err) {
|
|
311
|
-
if (err) error = err
|
|
312
|
-
if (--missing) return
|
|
313
|
-
if (error) cb(error)
|
|
314
|
-
else cb(null, result)
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
Storage.Node = Node
|
|
319
|
-
|
|
320
|
-
function noop () {}
|
|
321
|
-
|
|
322
|
-
function copyMaybe (buf, maxSize) {
|
|
323
|
-
if (buf.buffer.byteLength <= maxSize) return buf
|
|
324
|
-
const cpy = Buffer.alloc(buf.byteLength)
|
|
325
|
-
buf.copy(cpy)
|
|
326
|
-
return cpy
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
function header (type, size, name) {
|
|
330
|
-
var buf = Buffer.alloc(32)
|
|
331
|
-
|
|
332
|
-
// magic number
|
|
333
|
-
buf[0] = 5
|
|
334
|
-
buf[1] = 2
|
|
335
|
-
buf[2] = 87
|
|
336
|
-
buf[3] = type
|
|
337
|
-
|
|
338
|
-
// version
|
|
339
|
-
buf[4] = 0
|
|
340
|
-
|
|
341
|
-
// block size
|
|
342
|
-
buf.writeUInt16BE(size, 5)
|
|
343
|
-
|
|
344
|
-
if (name) {
|
|
345
|
-
// algo name
|
|
346
|
-
buf[7] = name.length
|
|
347
|
-
buf.write(name, 8)
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
return buf
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function Node (index, hash, size) {
|
|
354
|
-
this.index = index
|
|
355
|
-
this.hash = hash
|
|
356
|
-
this.size = size
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function findNode (nodes, index) {
|
|
360
|
-
for (var i = 0; i < nodes.length; i++) {
|
|
361
|
-
if (nodes[i].index === index) return nodes[i]
|
|
362
|
-
}
|
|
363
|
-
return null
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function isBlank (buf) {
|
|
367
|
-
for (var i = 0; i < buf.length; i++) {
|
|
368
|
-
if (buf[i]) return false
|
|
369
|
-
}
|
|
370
|
-
return true
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function close (st, cb) {
|
|
374
|
-
if (st.close) st.close(cb)
|
|
375
|
-
else cb()
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
function destroy (st, cb) {
|
|
379
|
-
if (st.destroy) st.destroy(cb)
|
|
380
|
-
else cb()
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
function statAndReadAll (st, offset, pageSize, cb) {
|
|
384
|
-
st.stat(function (err, stat) {
|
|
385
|
-
if (err) return cb(null, [])
|
|
386
|
-
|
|
387
|
-
var result = []
|
|
388
|
-
|
|
389
|
-
loop(null, null)
|
|
390
|
-
|
|
391
|
-
function loop (err, batch) {
|
|
392
|
-
if (err) return cb(err)
|
|
393
|
-
|
|
394
|
-
if (batch) {
|
|
395
|
-
offset += batch.length
|
|
396
|
-
for (var i = 0; i < batch.length; i += pageSize) {
|
|
397
|
-
result.push(batch.slice(i, i + pageSize))
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
var next = Math.min(stat.size - offset, 32 * pageSize)
|
|
402
|
-
if (!next) return cb(null, result)
|
|
403
|
-
|
|
404
|
-
st.read(offset, next, loop)
|
|
405
|
-
}
|
|
406
|
-
})
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function readAll (st, offset, pageSize, cb) {
|
|
410
|
-
if (st.statable === true) return statAndReadAll(st, offset, pageSize, cb)
|
|
411
|
-
|
|
412
|
-
var bufs = []
|
|
413
|
-
|
|
414
|
-
st.read(offset, pageSize, loop)
|
|
415
|
-
|
|
416
|
-
function loop (err, buf) {
|
|
417
|
-
if (err) return cb(null, bufs)
|
|
418
|
-
bufs.push(buf)
|
|
419
|
-
st.read(offset + bufs.length * pageSize, pageSize, loop)
|
|
420
|
-
}
|
|
421
|
-
}
|
package/lib/tree-index.js
DELETED
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
var flat = require('flat-tree')
|
|
2
|
-
var bitfield = require('sparse-bitfield')
|
|
3
|
-
|
|
4
|
-
module.exports = TreeIndex
|
|
5
|
-
|
|
6
|
-
function TreeIndex (bits) {
|
|
7
|
-
if (!(this instanceof TreeIndex)) return new TreeIndex(bits)
|
|
8
|
-
this.bitfield = bits || bitfield()
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
TreeIndex.prototype.proof = function (index, opts) {
|
|
12
|
-
if (!opts) opts = {}
|
|
13
|
-
|
|
14
|
-
var nodes = []
|
|
15
|
-
var remoteTree = opts.tree || new TreeIndex()
|
|
16
|
-
var digest = opts.digest || 0
|
|
17
|
-
|
|
18
|
-
if (!this.get(index)) return null
|
|
19
|
-
if (opts.hash) nodes.push(index) // always return hash - no matter what the digest says
|
|
20
|
-
if (digest === 1) return { nodes: nodes, verifiedBy: 0 }
|
|
21
|
-
|
|
22
|
-
var roots = null
|
|
23
|
-
var sibling = index
|
|
24
|
-
var next = index
|
|
25
|
-
var hasRoot = digest & 1
|
|
26
|
-
digest = rightShift(digest)
|
|
27
|
-
|
|
28
|
-
while (digest) {
|
|
29
|
-
if (digest === 1 && hasRoot) {
|
|
30
|
-
if (this.get(next)) remoteTree.set(next)
|
|
31
|
-
|
|
32
|
-
// having a root implies having prev roots as well
|
|
33
|
-
// TODO: this can be optimized away be only sending "newer" roots,
|
|
34
|
-
// when sending roots
|
|
35
|
-
if (flat.sibling(next) < next) next = flat.sibling(next)
|
|
36
|
-
roots = flat.fullRoots(flat.rightSpan(next) + 2)
|
|
37
|
-
for (var i = 0; i < roots.length; i++) {
|
|
38
|
-
if (this.get(roots[i])) remoteTree.set(roots[i])
|
|
39
|
-
}
|
|
40
|
-
break
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
sibling = flat.sibling(next)
|
|
44
|
-
if (digest & 1) {
|
|
45
|
-
if (this.get(sibling)) remoteTree.set(sibling)
|
|
46
|
-
}
|
|
47
|
-
next = flat.parent(next)
|
|
48
|
-
digest = rightShift(digest)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
next = index
|
|
52
|
-
|
|
53
|
-
while (!remoteTree.get(next)) {
|
|
54
|
-
sibling = flat.sibling(next)
|
|
55
|
-
if (!this.get(sibling)) {
|
|
56
|
-
// next is a local root
|
|
57
|
-
var verifiedBy = this.verifiedBy(next)
|
|
58
|
-
addFullRoots(verifiedBy, nodes, next, remoteTree)
|
|
59
|
-
return { nodes: nodes, verifiedBy: verifiedBy }
|
|
60
|
-
} else {
|
|
61
|
-
if (!remoteTree.get(sibling)) nodes.push(sibling)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
next = flat.parent(next)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return { nodes: nodes, verifiedBy: 0 }
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
TreeIndex.prototype.digest = function (index) {
|
|
71
|
-
if (this.get(index)) return 1
|
|
72
|
-
|
|
73
|
-
var digest = 0
|
|
74
|
-
var next = flat.sibling(index)
|
|
75
|
-
var max = Math.max(next + 2, this.bitfield.length) // TODO: make this less ... hacky
|
|
76
|
-
|
|
77
|
-
var bit = 2
|
|
78
|
-
var depth = flat.depth(index)
|
|
79
|
-
var parent = flat.parent(next, depth++)
|
|
80
|
-
|
|
81
|
-
while (flat.rightSpan(next) < max || flat.leftSpan(parent) > 0) {
|
|
82
|
-
if (this.get(next)) {
|
|
83
|
-
digest += bit // + cause in this case it's the same as | but works for large nums
|
|
84
|
-
}
|
|
85
|
-
if (this.get(parent)) {
|
|
86
|
-
digest += 2 * bit
|
|
87
|
-
if (!(digest & 1)) digest += 1
|
|
88
|
-
if (digest + 1 === 4 * bit) return 1
|
|
89
|
-
return digest
|
|
90
|
-
}
|
|
91
|
-
next = flat.sibling(parent)
|
|
92
|
-
parent = flat.parent(next, depth++)
|
|
93
|
-
bit *= 2
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return digest
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
TreeIndex.prototype.blocks = function () {
|
|
100
|
-
var top = 0
|
|
101
|
-
var next = 0
|
|
102
|
-
var max = this.bitfield.length
|
|
103
|
-
|
|
104
|
-
while (flat.rightSpan(next) < max) {
|
|
105
|
-
next = flat.parent(next)
|
|
106
|
-
if (this.get(next)) top = next
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return (this.get(top) ? this.verifiedBy(top) : 0) / 2
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
TreeIndex.prototype.roots = function () {
|
|
113
|
-
return flat.fullRoots(2 * this.blocks())
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
TreeIndex.prototype.verifiedBy = function (index, nodes) {
|
|
117
|
-
var hasIndex = this.get(index)
|
|
118
|
-
if (!hasIndex) return 0
|
|
119
|
-
|
|
120
|
-
// find root of current tree
|
|
121
|
-
|
|
122
|
-
var depth = flat.depth(index)
|
|
123
|
-
var top = index
|
|
124
|
-
var parent = flat.parent(top, depth++)
|
|
125
|
-
while (this.get(parent) && this.get(flat.sibling(top))) {
|
|
126
|
-
top = parent
|
|
127
|
-
parent = flat.parent(top, depth++)
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// expand right down
|
|
131
|
-
|
|
132
|
-
depth--
|
|
133
|
-
while (depth) {
|
|
134
|
-
top = flat.leftChild(flat.index(depth, flat.offset(top, depth) + 1), depth)
|
|
135
|
-
depth--
|
|
136
|
-
|
|
137
|
-
while (!this.get(top) && depth) top = flat.leftChild(top, depth--)
|
|
138
|
-
if (nodes && this.get(top)) nodes.push(top)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
return this.get(top) ? top + 2 : top
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
TreeIndex.prototype.get = function (index) {
|
|
145
|
-
return this.bitfield.get(index)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
TreeIndex.prototype.truncate = function (len) {
|
|
149
|
-
const currentLen = 2 * this.blocks()
|
|
150
|
-
const roots = flat.fullRoots(len)
|
|
151
|
-
|
|
152
|
-
for (let i = len; i < currentLen; i++) {
|
|
153
|
-
this.bitfield.set(i, false)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
for (const root of roots) {
|
|
157
|
-
let p = flat.parent(root)
|
|
158
|
-
while (p < len) {
|
|
159
|
-
this.bitfield.set(p, false)
|
|
160
|
-
p = flat.parent(p)
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
TreeIndex.prototype.set = function (index) {
|
|
166
|
-
if (!this.bitfield.set(index, true)) return false
|
|
167
|
-
while (this.bitfield.get(flat.sibling(index))) {
|
|
168
|
-
index = flat.parent(index)
|
|
169
|
-
if (!this.bitfield.set(index, true)) break
|
|
170
|
-
}
|
|
171
|
-
return true
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function rightShift (n) {
|
|
175
|
-
return (n - (n & 1)) / 2
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
function addFullRoots (verifiedBy, nodes, root, remoteTree) {
|
|
179
|
-
var roots = flat.fullRoots(verifiedBy)
|
|
180
|
-
for (var i = 0; i < roots.length; i++) {
|
|
181
|
-
if (roots[i] !== root && !remoteTree.get(roots[i])) nodes.push(roots[i])
|
|
182
|
-
}
|
|
183
|
-
}
|