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.
Files changed (86) hide show
  1. package/.github/workflows/test-node.yml +3 -4
  2. package/README.md +131 -404
  3. package/__snapshots__/test/storage.js.snapshot.cjs +15 -0
  4. package/examples/announce.js +19 -0
  5. package/examples/basic.js +10 -0
  6. package/examples/http.js +123 -0
  7. package/examples/lookup.js +20 -0
  8. package/index.js +365 -1600
  9. package/lib/bitfield.js +113 -285
  10. package/lib/block-encryption.js +68 -0
  11. package/lib/block-store.js +58 -0
  12. package/lib/core.js +468 -0
  13. package/lib/extensions.js +76 -0
  14. package/lib/merkle-tree.js +1110 -0
  15. package/lib/messages.js +571 -0
  16. package/lib/mutex.js +39 -0
  17. package/lib/oplog.js +224 -0
  18. package/lib/protocol.js +525 -0
  19. package/lib/random-iterator.js +46 -0
  20. package/lib/remote-bitfield.js +24 -0
  21. package/lib/replicator.js +857 -0
  22. package/lib/streams.js +39 -0
  23. package/package.json +44 -45
  24. package/test/basic.js +59 -471
  25. package/test/bitfield.js +48 -133
  26. package/test/core.js +290 -0
  27. package/test/encodings.js +18 -0
  28. package/test/encryption.js +123 -0
  29. package/test/extension.js +71 -0
  30. package/test/helpers/index.js +23 -0
  31. package/test/merkle-tree.js +518 -0
  32. package/test/mutex.js +137 -0
  33. package/test/oplog.js +399 -0
  34. package/test/preload.js +72 -0
  35. package/test/replicate.js +227 -824
  36. package/test/sessions.js +173 -0
  37. package/test/storage.js +31 -0
  38. package/test/streams.js +39 -146
  39. package/test/user-data.js +47 -0
  40. package/bench/all.sh +0 -65
  41. package/bench/copy-64kb-blocks.js +0 -51
  42. package/bench/helpers/read-throttled.js +0 -27
  43. package/bench/helpers/read.js +0 -47
  44. package/bench/helpers/write.js +0 -29
  45. package/bench/read-16kb-blocks-proof-throttled.js +0 -1
  46. package/bench/read-16kb-blocks-proof.js +0 -1
  47. package/bench/read-16kb-blocks-throttled.js +0 -1
  48. package/bench/read-16kb-blocks.js +0 -1
  49. package/bench/read-512b-blocks.js +0 -1
  50. package/bench/read-64kb-blocks-linear-batch.js +0 -18
  51. package/bench/read-64kb-blocks-linear.js +0 -18
  52. package/bench/read-64kb-blocks-proof.js +0 -1
  53. package/bench/read-64kb-blocks.js +0 -1
  54. package/bench/replicate-16kb-blocks.js +0 -19
  55. package/bench/replicate-64kb-blocks.js +0 -19
  56. package/bench/write-16kb-blocks.js +0 -1
  57. package/bench/write-512b-blocks.js +0 -1
  58. package/bench/write-64kb-blocks-static.js +0 -1
  59. package/bench/write-64kb-blocks.js +0 -1
  60. package/example.js +0 -23
  61. package/lib/cache.js +0 -26
  62. package/lib/crypto.js +0 -5
  63. package/lib/replicate.js +0 -829
  64. package/lib/safe-buffer-equals.js +0 -6
  65. package/lib/storage.js +0 -421
  66. package/lib/tree-index.js +0 -183
  67. package/test/ack.js +0 -306
  68. package/test/audit.js +0 -36
  69. package/test/cache.js +0 -93
  70. package/test/compat.js +0 -209
  71. package/test/copy.js +0 -377
  72. package/test/default-storage.js +0 -51
  73. package/test/extensions.js +0 -137
  74. package/test/get.js +0 -64
  75. package/test/head.js +0 -65
  76. package/test/helpers/create-tracking-ram.js +0 -27
  77. package/test/helpers/create.js +0 -6
  78. package/test/helpers/replicate.js +0 -4
  79. package/test/seek.js +0 -234
  80. package/test/selections.js +0 -95
  81. package/test/set-uploading-downloading.js +0 -91
  82. package/test/stats.js +0 -77
  83. package/test/timeouts.js +0 -22
  84. package/test/tree-index.js +0 -841
  85. package/test/update.js +0 -156
  86. package/test/value-encoding.js +0 -52
@@ -0,0 +1,1110 @@
1
+ const flat = require('flat-tree')
2
+ const crypto = require('hypercore-crypto')
3
+ const c = require('compact-encoding')
4
+ const b4a = require('b4a')
5
+
6
+ const BLANK_HASH = b4a.alloc(32)
7
+ const OLD_TREE = b4a.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
8
+
9
+ class NodeQueue {
10
+ constructor (nodes, extra = null) {
11
+ this.i = 0
12
+ this.nodes = nodes
13
+ this.extra = extra
14
+ this.length = nodes.length + (this.extra === null ? 0 : 1)
15
+ }
16
+
17
+ shift (index) {
18
+ if (this.extra !== null && this.extra.index === index) {
19
+ const node = this.extra
20
+ this.extra = null
21
+ this.length--
22
+ return node
23
+ }
24
+
25
+ if (this.i >= this.nodes.length) {
26
+ throw new Error('Expected node ' + index + ', got (nil)')
27
+ }
28
+
29
+ const node = this.nodes[this.i++]
30
+ if (node.index !== index) {
31
+ throw new Error('Expected node ' + index + ', got node ' + node.index)
32
+ }
33
+
34
+ this.length--
35
+ return node
36
+ }
37
+ }
38
+
39
+ class MerkleTreeBatch {
40
+ constructor (tree) {
41
+ this.fork = tree.fork
42
+ this.roots = [...tree.roots]
43
+ this.length = tree.length
44
+ this.ancestors = tree.length
45
+ this.byteLength = tree.byteLength
46
+ this.signature = null
47
+
48
+ this.treeLength = tree.length
49
+ this.treeFork = tree.fork
50
+ this.tree = tree
51
+ this.nodes = []
52
+ this.upgraded = false
53
+ }
54
+
55
+ hash () {
56
+ return this.tree.crypto.tree(this.roots)
57
+ }
58
+
59
+ signable (hash = this.hash()) {
60
+ return signable(hash, this.length, this.fork)
61
+ }
62
+
63
+ signedBy (key) {
64
+ return this.signature !== null && this.tree.crypto.verify(this.signable(), this.signature, key)
65
+ }
66
+
67
+ append (buf) {
68
+ const head = this.length * 2
69
+ const ite = flat.iterator(head)
70
+ const node = blockNode(this.tree.crypto, head, buf)
71
+
72
+ this.appendRoot(node, ite)
73
+ }
74
+
75
+ appendRoot (node, ite) {
76
+ this.upgraded = true
77
+ this.length += ite.factor / 2
78
+ this.byteLength += node.size
79
+ this.roots.push(node)
80
+ this.nodes.push(node)
81
+
82
+ while (this.roots.length > 1) {
83
+ const a = this.roots[this.roots.length - 1]
84
+ const b = this.roots[this.roots.length - 2]
85
+
86
+ // TODO: just have a peek sibling instead? (pretty sure it's always the left sib as well)
87
+ if (ite.sibling() !== b.index) {
88
+ ite.sibling() // unset so it always points to last root
89
+ break
90
+ }
91
+
92
+ const node = parentNode(this.tree.crypto, ite.parent(), a, b)
93
+ this.nodes.push(node)
94
+ this.roots.pop()
95
+ this.roots.pop()
96
+ this.roots.push(node)
97
+ }
98
+ }
99
+
100
+ commitable () {
101
+ return this.treeFork === this.tree.fork && (
102
+ this.upgraded
103
+ ? this.treeLength === this.tree.length
104
+ : this.treeLength <= this.tree.length
105
+ )
106
+ }
107
+
108
+ commit () {
109
+ if (!this.commitable()) throw new Error('Tree was modified during batch, refusing to commit')
110
+
111
+ if (this.upgraded) this._commitUpgrade()
112
+
113
+ for (let i = 0; i < this.nodes.length; i++) {
114
+ const node = this.nodes[i]
115
+ this.tree.unflushed.set(node.index, node)
116
+ }
117
+ }
118
+
119
+ _commitUpgrade () {
120
+ // TODO: If easy to detect, we should refuse an trunc+append here without a fork id
121
+ // change. Will only happen on user error so mostly to prevent that.
122
+
123
+ if (this.ancestors < this.treeLength) {
124
+ if (this.ancestors > 0) {
125
+ const head = 2 * this.ancestors
126
+ const ite = flat.iterator(head - 2)
127
+
128
+ while (true) {
129
+ if (ite.contains(head) && ite.index < head) {
130
+ this.tree.unflushed.set(ite.index, blankNode(ite.index))
131
+ }
132
+ if (ite.offset === 0) break
133
+ ite.parent()
134
+ }
135
+ }
136
+
137
+ this.tree.truncateTo = this.tree.truncated
138
+ ? Math.min(this.tree.truncateTo, this.ancestors)
139
+ : this.ancestors
140
+
141
+ this.tree.truncated = true
142
+ truncateMap(this.tree.unflushed, this.ancestors)
143
+ if (this.tree.flushing !== null) truncateMap(this.tree.flushing, this.ancestors)
144
+ }
145
+
146
+ this.tree.roots = this.roots
147
+ this.tree.length = this.length
148
+ this.tree.byteLength = this.byteLength
149
+ this.tree.fork = this.fork
150
+ this.tree.signature = this.signature
151
+ }
152
+
153
+ // TODO: this is the only async method on the batch, so unsure if it should go here
154
+ // this is important so you know where to right data without committing the batch
155
+ // so we'll keep it here for now.
156
+
157
+ async byteOffset (index) {
158
+ if (2 * this.tree.length === index) return this.tree.byteLength
159
+
160
+ const ite = flat.iterator(index)
161
+
162
+ let treeOffset = 0
163
+ let isRight = false
164
+ let parent = null
165
+
166
+ for (const node of this.nodes) {
167
+ if (node.index === ite.index) {
168
+ if (isRight && parent) treeOffset += node.size - parent.size
169
+ parent = node
170
+ isRight = ite.isRight()
171
+ ite.parent()
172
+ }
173
+ }
174
+
175
+ const r = this.roots.indexOf(parent)
176
+ if (r > -1) {
177
+ for (let i = 0; i < r; i++) {
178
+ treeOffset += this.roots[i].size
179
+ }
180
+
181
+ return treeOffset
182
+ }
183
+
184
+ const byteOffset = await this.tree.byteOffset(parent ? parent.index : index)
185
+
186
+ return byteOffset + treeOffset
187
+ }
188
+ }
189
+
190
+ class ReorgBatch extends MerkleTreeBatch {
191
+ constructor (tree) {
192
+ super(tree)
193
+ this.roots = []
194
+ this.length = 0
195
+ this.byteLength = 0
196
+ this.diff = null
197
+ this.ancestors = 0
198
+ // We set upgraded because reorgs are signed so hit will
199
+ // hit the same code paths (like the treeLength check in commit)
200
+ this.upgraded = true
201
+ this.want = {
202
+ nodes: 0,
203
+ start: 0,
204
+ end: 0
205
+ }
206
+ }
207
+
208
+ get finished () {
209
+ return this.want === null
210
+ }
211
+
212
+ update (proof) {
213
+ if (this.want === null) return true
214
+
215
+ const nodes = []
216
+ const root = verifyBlock(proof, this.tree.crypto, nodes)
217
+
218
+ if (root === null || !root.hash.equals(this.diff.hash)) return false
219
+
220
+ this.nodes.push(...nodes)
221
+ return this._update(nodes)
222
+ }
223
+
224
+ async _update (nodes) {
225
+ const n = new Map()
226
+ for (const node of nodes) n.set(node.index, node)
227
+
228
+ let diff = null
229
+ const ite = flat.iterator(this.diff.index)
230
+
231
+ while ((ite.index & 1) !== 0) {
232
+ const left = n.get(ite.leftChild())
233
+ if (!left) break
234
+
235
+ const existing = await this.tree.get(left.index, false)
236
+ if (!existing || !existing.hash.equals(left.hash)) {
237
+ diff = left
238
+ } else {
239
+ diff = n.get(ite.sibling())
240
+ }
241
+ }
242
+
243
+ if ((this.diff.index & 1) === 0) return true
244
+ if (diff === null) return false
245
+
246
+ return this._updateDiffRoot(diff)
247
+ }
248
+
249
+ _updateDiffRoot (diff) {
250
+ const spans = flat.spans(diff.index)
251
+ const start = spans[0] / 2
252
+ const end = Math.min(this.treeLength, spans[1] / 2 + 1)
253
+ const len = end - start
254
+
255
+ if (this.diff !== null && len >= this.want.end - this.want.start) {
256
+ return false
257
+ }
258
+
259
+ this.ancestors = start
260
+ this.diff = diff
261
+
262
+ if ((diff.index & 1) === 0 || this.want.start >= this.treeLength || len <= 0) {
263
+ this.want = null
264
+ return true
265
+ }
266
+
267
+ this.want.start = start
268
+ this.want.end = end
269
+ this.want.nodes = log2(spans[1] - spans[0] + 2) - 1
270
+
271
+ return false
272
+ }
273
+ }
274
+
275
+ class ByteSeeker {
276
+ constructor (tree, bytes, padding = 0) {
277
+ this.tree = tree
278
+ this.bytes = bytes
279
+ this.padding = padding
280
+
281
+ const size = tree.byteLength - (tree.length * padding)
282
+
283
+ this.start = bytes >= size ? tree.length : 0
284
+ this.end = bytes < size ? tree.length : 0
285
+ }
286
+
287
+ nodes () {
288
+ return this.tree.nodes(this.start * 2)
289
+ }
290
+
291
+ async _seek (bytes) {
292
+ if (!bytes) return [0, 0]
293
+
294
+ for (const node of this.tree.roots) { // all async ticks happen once we find the root so safe
295
+ let size = node.size
296
+ if (this.padding > 0) size -= this.padding * flat.countLeaves(node.index)
297
+
298
+ if (bytes === size) return [flat.rightSpan(node.index) + 2, 0]
299
+ if (bytes > size) {
300
+ bytes -= size
301
+ continue
302
+ }
303
+
304
+ const ite = flat.iterator(node.index)
305
+
306
+ while ((ite.index & 1) !== 0) {
307
+ const l = await this.tree.get(ite.leftChild(), false)
308
+ if (l) {
309
+ let size = l.size
310
+ if (this.padding > 0) size -= this.padding * ite.countLeaves()
311
+
312
+ if (size === bytes) return [ite.rightSpan() + 2, 0]
313
+ if (size > bytes) continue
314
+ bytes -= size
315
+ ite.sibling()
316
+ } else {
317
+ ite.parent()
318
+ return [ite.index, bytes]
319
+ }
320
+ }
321
+
322
+ return [ite.index, bytes]
323
+ }
324
+
325
+ return null
326
+ }
327
+
328
+ async update () { // TODO: combine _seek and this, much simpler
329
+ const res = await this._seek(this.bytes)
330
+ if (!res) return null
331
+ if ((res[0] & 1) === 0) return [res[0] / 2, res[1]]
332
+
333
+ const span = flat.spans(res[0])
334
+ this.start = span[0] / 2
335
+ this.end = span[1] / 2 + 1
336
+
337
+ return null
338
+ }
339
+ }
340
+
341
+ module.exports = class MerkleTree {
342
+ constructor (storage, roots, fork, signature) {
343
+ this.crypto = crypto
344
+ this.fork = fork
345
+ this.roots = roots
346
+ this.length = roots.length ? totalSpan(roots) / 2 : 0
347
+ this.byteLength = totalSize(roots)
348
+ this.signature = signature
349
+
350
+ this.storage = storage
351
+ this.unflushed = new Map()
352
+ this.flushing = null
353
+ this.truncated = false
354
+ this.truncateTo = 0
355
+ }
356
+
357
+ addNode (node) {
358
+ if (node.size === 0 && node.hash.equals(BLANK_HASH)) node = blankNode(node.index)
359
+ this.unflushed.set(node.index, node)
360
+ }
361
+
362
+ batch () {
363
+ return new MerkleTreeBatch(this)
364
+ }
365
+
366
+ seek (bytes, padding) {
367
+ return new ByteSeeker(this, bytes, padding)
368
+ }
369
+
370
+ hash () {
371
+ return this.crypto.tree(this.roots)
372
+ }
373
+
374
+ signable (hash = this.hash()) {
375
+ return signable(hash, this.length, this.fork)
376
+ }
377
+
378
+ signedBy (key) {
379
+ return this.signature !== null && this.crypto.verify(this.signable(), this.signature, key)
380
+ }
381
+
382
+ get (index, error = true) {
383
+ let node = this.unflushed.get(index)
384
+
385
+ if (this.flushing !== null && node === undefined) {
386
+ node = this.flushing.get(index)
387
+ }
388
+
389
+ // TODO: test this
390
+ if (this.truncated && node !== undefined && node.index >= 2 * this.truncateTo) {
391
+ node = blankNode(index)
392
+ }
393
+
394
+ if (node !== undefined) {
395
+ if (node.hash === BLANK_HASH) {
396
+ if (error) throw new Error('Could not load node: ' + index)
397
+ return Promise.resolve(null)
398
+ }
399
+ return Promise.resolve(node)
400
+ }
401
+
402
+ return getStoredNode(this.storage, index, error)
403
+ }
404
+
405
+ async flush () {
406
+ this.flushing = this.unflushed
407
+ this.unflushed = new Map()
408
+
409
+ try {
410
+ if (this.truncated) await this._flushTruncation()
411
+ await this._flushNodes()
412
+ } catch (err) {
413
+ for (const node of this.flushing.values()) {
414
+ if (!this.unflushed.has(node.index)) this.unflushed.set(node.index, node)
415
+ }
416
+ throw err
417
+ } finally {
418
+ this.flushing = null
419
+ }
420
+ }
421
+
422
+ _flushTruncation () {
423
+ return new Promise((resolve, reject) => {
424
+ const t = this.truncateTo
425
+ const offset = t === 0 ? 0 : (t - 1) * 80 + 40
426
+
427
+ this.storage.del(offset, Infinity, (err) => {
428
+ if (err) return reject(err)
429
+
430
+ if (this.truncateTo === t) {
431
+ this.truncateTo = 0
432
+ this.truncated = false
433
+ }
434
+
435
+ resolve()
436
+ })
437
+ })
438
+ }
439
+
440
+ _flushNodes () {
441
+ // TODO: write neighbors together etc etc
442
+ // TODO: bench loading a full disk page and copy to that instead
443
+ return new Promise((resolve, reject) => {
444
+ const slab = b4a.allocUnsafe(40 * this.flushing.size)
445
+
446
+ let error = null
447
+ let missing = this.flushing.size + 1
448
+ let offset = 0
449
+
450
+ for (const node of this.flushing.values()) {
451
+ const state = {
452
+ start: 0,
453
+ end: 40,
454
+ buffer: slab.subarray(offset, offset += 40)
455
+ }
456
+
457
+ c.uint64.encode(state, node.size)
458
+ c.raw.encode(state, node.hash)
459
+
460
+ this.storage.write(node.index * 40, state.buffer, done)
461
+ }
462
+
463
+ done(null)
464
+
465
+ function done (err) {
466
+ if (err) error = err
467
+ if (--missing > 0) return
468
+ if (error) reject(error)
469
+ else resolve()
470
+ }
471
+ })
472
+ }
473
+
474
+ clear () {
475
+ this.truncated = true
476
+ this.truncateTo = 0
477
+ this.roots = []
478
+ this.length = 0
479
+ this.byteLength = 0
480
+ this.fork = 0
481
+ this.signature = null
482
+ if (this.flushing !== null) this.flushing.clear()
483
+ this.unflushed.clear()
484
+ return this.flush()
485
+ }
486
+
487
+ close () {
488
+ return new Promise((resolve, reject) => {
489
+ this.storage.close(err => {
490
+ if (err) reject(err)
491
+ else resolve()
492
+ })
493
+ })
494
+ }
495
+
496
+ async truncate (length, fork = this.fork) {
497
+ const head = length * 2
498
+ const batch = new MerkleTreeBatch(this)
499
+ const fullRoots = flat.fullRoots(head)
500
+
501
+ for (let i = 0; i < fullRoots.length; i++) {
502
+ const root = fullRoots[i]
503
+ if (i < batch.roots.length && batch.roots[i].index === root) continue
504
+
505
+ while (batch.roots.length > i) batch.roots.pop()
506
+ batch.roots.push(await this.get(root))
507
+ }
508
+
509
+ while (batch.roots.length > fullRoots.length) {
510
+ batch.roots.pop()
511
+ }
512
+
513
+ batch.fork = fork
514
+ batch.length = length
515
+ batch.ancestors = length
516
+ batch.byteLength = totalSize(batch.roots)
517
+ batch.upgraded = true
518
+
519
+ return batch
520
+ }
521
+
522
+ async reorg (proof) {
523
+ const batch = new ReorgBatch(this)
524
+
525
+ let unverified = null
526
+
527
+ if (proof.block || proof.seek) {
528
+ unverified = verifyBlock(proof, this.crypto, batch.nodes)
529
+ }
530
+
531
+ if (!verifyUpgrade(proof, unverified, batch)) {
532
+ throw new Error('Fork proof not verifiable')
533
+ }
534
+
535
+ for (const root of batch.roots) {
536
+ const existing = await this.get(root.index, false)
537
+ if (existing && existing.hash.equals(root.hash)) continue
538
+ batch._updateDiffRoot(root)
539
+ break
540
+ }
541
+
542
+ if (batch.diff !== null) {
543
+ await batch._update(batch.nodes)
544
+ } else {
545
+ batch.want = null
546
+ batch.ancestors = batch.length
547
+ }
548
+
549
+ return batch
550
+ }
551
+
552
+ async verify (proof) {
553
+ const batch = new MerkleTreeBatch(this)
554
+
555
+ let unverified = verifyBlock(proof, this.crypto, batch.nodes)
556
+
557
+ if (proof.upgrade) {
558
+ if (verifyUpgrade(proof, unverified, batch)) {
559
+ unverified = null
560
+ }
561
+ }
562
+
563
+ if (unverified) {
564
+ const verified = await this.get(unverified.index)
565
+ if (!verified.hash.equals(unverified.hash)) {
566
+ throw new Error('Invalid checksum at node ' + unverified.index)
567
+ }
568
+ }
569
+
570
+ return batch
571
+ }
572
+
573
+ async proof ({ block, seek, upgrade }) {
574
+ // Important that this does not throw inbetween making the promise arrays
575
+ // and finalise being called, otherwise there will be lingering promises in the background
576
+
577
+ const signature = this.signature
578
+ const fork = this.fork
579
+ const head = 2 * this.length
580
+ const from = upgrade ? upgrade.start * 2 : 0
581
+ const to = upgrade ? from + upgrade.length * 2 : head
582
+
583
+ if (from >= to || to > head) {
584
+ throw new Error('Invalid upgrade')
585
+ }
586
+ if (seek && block && upgrade && block.index * 2 >= from) {
587
+ throw new Error('Cannot both do a seek and block request when upgrading')
588
+ }
589
+
590
+ let subTree = head
591
+
592
+ const p = {
593
+ block: null,
594
+ seek: null,
595
+ upgrade: null,
596
+ additionalUpgrade: null
597
+ }
598
+
599
+ if (block && (!upgrade || block.index < upgrade.start)) {
600
+ subTree = nodesToRoot(2 * block.index, block.nodes, to)
601
+ const seekRoot = seek ? await seekUntrustedTree(this, subTree, seek.bytes) : head
602
+ blockAndSeekProof(this, block, seek, seekRoot, subTree, p)
603
+ } else if ((block || seek) && upgrade) {
604
+ subTree = seek ? await seekFromHead(this, to, seek.bytes) : 2 * block.index
605
+ }
606
+
607
+ if (upgrade) {
608
+ upgradeProof(this, block, seek, from, to, subTree, p)
609
+ if (head > to) additionalUpgradeProof(this, to, head, p)
610
+ }
611
+
612
+ try {
613
+ const result = { fork, block: null, seek: null, upgrade: null }
614
+
615
+ if (block) {
616
+ const nodes = await Promise.all(p.block)
617
+
618
+ result.block = {
619
+ index: block.index,
620
+ value: null,
621
+ nodes
622
+ }
623
+ }
624
+ if (seek && p.seek !== null) {
625
+ const nodes = await Promise.all(p.seek)
626
+
627
+ result.seek = {
628
+ bytes: seek.bytes,
629
+ nodes
630
+ }
631
+ }
632
+ if (upgrade) {
633
+ const nodes = await Promise.all(p.upgrade)
634
+ const additionalNodes = await Promise.all(p.additionalUpgrade || [])
635
+
636
+ result.upgrade = {
637
+ start: upgrade.start,
638
+ length: upgrade.length,
639
+ nodes,
640
+ additionalNodes,
641
+ signature
642
+ }
643
+ }
644
+
645
+ return result
646
+ } catch (err) {
647
+ // Make sure we await all pending p so don't have background async state...
648
+ if (p.seek !== null) await Promise.allSettled(p.seek)
649
+ if (p.block !== null) await Promise.allSettled(p.block)
650
+ if (p.upgrade !== null) await Promise.allSettled(p.upgrade)
651
+ if (p.additionalUpgrade !== null) await Promise.allSettled(p.additionalUpgrade)
652
+ throw err
653
+ }
654
+ }
655
+
656
+ async nodes (index) {
657
+ const head = 2 * this.length
658
+ const ite = flat.iterator(index)
659
+
660
+ let cnt = 0
661
+ while (!ite.contains(head) && (await this.get(ite.index, false)) === null) {
662
+ cnt++
663
+ ite.parent()
664
+ }
665
+
666
+ return cnt
667
+ }
668
+
669
+ async byteRange (index) {
670
+ const head = 2 * this.length
671
+ if (((index & 1) === 0 ? index : flat.rightSpan(index)) >= head) {
672
+ throw new Error('Index is out of bounds')
673
+ }
674
+ return [await this.byteOffset(index), (await this.get(index)).size]
675
+ }
676
+
677
+ async byteOffset (index) {
678
+ if ((index & 1) === 1) index = flat.leftSpan(index)
679
+
680
+ let head = 0
681
+ let offset = 0
682
+
683
+ for (const node of this.roots) { // all async ticks happen once we find the root so safe
684
+ head += 2 * ((node.index - head) + 1)
685
+
686
+ if (index >= head) {
687
+ offset += node.size
688
+ continue
689
+ }
690
+
691
+ const ite = flat.iterator(node.index)
692
+
693
+ while (ite.index !== index) {
694
+ if (index < ite.index) {
695
+ ite.leftChild()
696
+ } else {
697
+ offset += (await this.get(ite.leftChild())).size
698
+ ite.sibling()
699
+ }
700
+ }
701
+
702
+ return offset
703
+ }
704
+ }
705
+
706
+ static async open (storage, opts = {}) {
707
+ await new Promise((resolve, reject) => {
708
+ storage.read(0, OLD_TREE.length, (err, buf) => {
709
+ if (err) return resolve()
710
+ if (buf.equals(OLD_TREE)) return reject(new Error('Storage contains an incompatible merkle tree'))
711
+ resolve()
712
+ })
713
+ })
714
+
715
+ const length = typeof opts.length === 'number'
716
+ ? opts.length
717
+ : await autoLength(storage)
718
+
719
+ const roots = []
720
+ for (const index of flat.fullRoots(2 * length)) {
721
+ roots.push(await getStoredNode(storage, index, true))
722
+ }
723
+
724
+ return new MerkleTree(storage, roots, opts.fork || 0, opts.signature || null)
725
+ }
726
+ }
727
+
728
+ // All the methods needed for proof verification
729
+
730
+ function verifyBlock ({ block, seek }, crypto, nodes) {
731
+ if (!block && (!seek || !seek.nodes.length)) return null
732
+
733
+ let root = null
734
+
735
+ if (seek && seek.nodes.length) {
736
+ const ite = flat.iterator(seek.nodes[0].index)
737
+ const q = new NodeQueue(seek.nodes)
738
+
739
+ root = q.shift(ite.index)
740
+ nodes.push(root)
741
+
742
+ while (q.length > 0) {
743
+ const node = q.shift(ite.sibling())
744
+
745
+ root = parentNode(crypto, ite.parent(), root, node)
746
+ nodes.push(node)
747
+ nodes.push(root)
748
+ }
749
+ }
750
+
751
+ if (!block) return root
752
+
753
+ const ite = flat.iterator(2 * block.index)
754
+ const blockHash = block.value && blockNode(crypto, ite.index, block.value)
755
+
756
+ const q = new NodeQueue(block.nodes, root)
757
+
758
+ root = blockHash || q.shift(ite.index)
759
+ nodes.push(root)
760
+
761
+ while (q.length > 0) {
762
+ const node = q.shift(ite.sibling())
763
+
764
+ root = parentNode(crypto, ite.parent(), root, node)
765
+ nodes.push(node)
766
+ nodes.push(root)
767
+ }
768
+
769
+ return root
770
+ }
771
+
772
+ function verifyUpgrade ({ fork, upgrade }, blockRoot, batch) {
773
+ const q = new NodeQueue(upgrade.nodes, blockRoot)
774
+
775
+ let grow = batch.roots.length > 0
776
+ let i = 0
777
+
778
+ const to = 2 * (upgrade.start + upgrade.length)
779
+ const ite = flat.iterator(0)
780
+
781
+ for (; ite.fullRoot(to); ite.nextTree()) {
782
+ if (i < batch.roots.length && batch.roots[i].index === ite.index) {
783
+ i++
784
+ continue
785
+ }
786
+
787
+ if (grow) {
788
+ grow = false
789
+ const root = ite.index
790
+ if (i < batch.roots.length) {
791
+ ite.seek(batch.roots[batch.roots.length - 1].index)
792
+ while (ite.index !== root) {
793
+ batch.appendRoot(q.shift(ite.sibling()), ite)
794
+ }
795
+ continue
796
+ }
797
+ }
798
+
799
+ batch.appendRoot(q.shift(ite.index), ite)
800
+ }
801
+
802
+ const extra = upgrade.additionalNodes
803
+
804
+ ite.seek(batch.roots[batch.roots.length - 1].index)
805
+ i = 0
806
+
807
+ while (i < extra.length && extra[i].index === ite.sibling()) {
808
+ batch.appendRoot(extra[i++], ite)
809
+ }
810
+
811
+ while (i < extra.length) {
812
+ const node = extra[i++]
813
+
814
+ while (node.index !== ite.index) {
815
+ if (ite.factor === 2) throw new Error('Unexpected node: ' + node.index)
816
+ ite.leftChild()
817
+ }
818
+
819
+ batch.appendRoot(node, ite)
820
+ ite.sibling()
821
+ }
822
+
823
+ batch.signature = upgrade.signature
824
+ batch.fork = fork
825
+
826
+ return q.extra === null
827
+ }
828
+
829
+ async function seekFromHead (tree, head, bytes) {
830
+ const roots = flat.fullRoots(head)
831
+
832
+ for (let i = 0; i < roots.length; i++) {
833
+ const root = roots[i]
834
+ const node = await tree.get(root)
835
+
836
+ if (bytes === node.size) return root
837
+ if (bytes > node.size) {
838
+ bytes -= node.size
839
+ continue
840
+ }
841
+
842
+ return seekTrustedTree(tree, root, bytes)
843
+ }
844
+
845
+ return head
846
+ }
847
+
848
+ // trust that bytes are within the root tree and find the block at bytes
849
+
850
+ async function seekTrustedTree (tree, root, bytes) {
851
+ if (!bytes) return root
852
+
853
+ const ite = flat.iterator(root)
854
+
855
+ while ((ite.index & 1) !== 0) {
856
+ const l = await tree.get(ite.leftChild(), false)
857
+ if (l) {
858
+ if (l.size === bytes) return ite.index
859
+ if (l.size > bytes) continue
860
+ bytes -= l.size
861
+ ite.sibling()
862
+ } else {
863
+ ite.parent()
864
+ return ite.index
865
+ }
866
+ }
867
+
868
+ return ite.index
869
+ }
870
+
871
+ // try to find the block at bytes without trusting that is *is* within the root passed
872
+
873
+ async function seekUntrustedTree (tree, root, bytes) {
874
+ const offset = await tree.byteOffset(root)
875
+
876
+ if (offset > bytes) throw new Error('Invalid seek')
877
+ if (offset === bytes) return root
878
+
879
+ bytes -= offset
880
+
881
+ const node = await tree.get(root)
882
+
883
+ if (node.size <= bytes) throw new Error('Invalid seek')
884
+
885
+ return seekTrustedTree(tree, root, bytes)
886
+ }
887
+
888
+ // Below is proof production, ie, construct proofs to verify a request
889
+ // Note, that all these methods are sync as we can statically infer which nodes
890
+ // are needed for the remote to verify given they arguments they passed us
891
+
892
+ function seekProof (tree, seekRoot, root, p) {
893
+ const ite = flat.iterator(seekRoot)
894
+
895
+ p.seek = []
896
+ p.seek.push(tree.get(ite.index))
897
+
898
+ while (ite.index !== root) {
899
+ ite.sibling()
900
+ p.seek.push(tree.get(ite.index))
901
+ ite.parent()
902
+ }
903
+ }
904
+
905
+ function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
906
+ if (!block) return seekProof(tree, seekRoot, root, p)
907
+
908
+ const ite = flat.iterator(2 * block.index)
909
+
910
+ p.block = []
911
+ if (!block.value) p.block.push(tree.get(ite.index))
912
+
913
+ while (ite.index !== root) {
914
+ ite.sibling()
915
+
916
+ if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
917
+ seekProof(tree, seekRoot, ite.index, p)
918
+ } else {
919
+ p.block.push(tree.get(ite.index))
920
+ }
921
+
922
+ ite.parent()
923
+ }
924
+ }
925
+
926
+ function upgradeProof (tree, block, seek, from, to, subTree, p) {
927
+ if (from === 0) p.upgrade = []
928
+
929
+ for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
930
+ // check if they already have the node
931
+ if (ite.index + ite.factor / 2 < from) continue
932
+
933
+ // connect existing tree
934
+ if (p.upgrade === null && ite.contains(from - 2)) {
935
+ p.upgrade = []
936
+
937
+ const root = ite.index
938
+ const target = from - 2
939
+
940
+ ite.seek(target)
941
+
942
+ while (ite.index !== root) {
943
+ ite.sibling()
944
+ if (ite.index > target) {
945
+ if (p.block === null && p.seek === null && ite.contains(subTree)) {
946
+ blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
947
+ } else {
948
+ p.upgrade.push(tree.get(ite.index))
949
+ }
950
+ }
951
+ ite.parent()
952
+ }
953
+
954
+ continue
955
+ }
956
+
957
+ if (p.upgrade === null) {
958
+ p.upgrade = []
959
+ }
960
+
961
+ // if the subtree included is a child of this tree, include that one
962
+ // instead of a dup node
963
+ if (p.block === null && p.seek === null && ite.contains(subTree)) {
964
+ blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
965
+ continue
966
+ }
967
+
968
+ // add root (can be optimised since the root might be in tree.roots)
969
+ p.upgrade.push(tree.get(ite.index))
970
+ }
971
+ }
972
+
973
+ function additionalUpgradeProof (tree, from, to, p) {
974
+ if (from === 0) p.additionalUpgrade = []
975
+
976
+ for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
977
+ // check if they already have the node
978
+ if (ite.index + ite.factor / 2 < from) continue
979
+
980
+ // connect existing tree
981
+ if (p.additionalUpgrade === null && ite.contains(from - 2)) {
982
+ p.additionalUpgrade = []
983
+
984
+ const root = ite.index
985
+ const target = from - 2
986
+
987
+ ite.seek(target)
988
+
989
+ while (ite.index !== root) {
990
+ ite.sibling()
991
+ if (ite.index > target) {
992
+ p.additionalUpgrade.push(tree.get(ite.index))
993
+ }
994
+ ite.parent()
995
+ }
996
+
997
+ continue
998
+ }
999
+
1000
+ if (p.additionalUpgrade === null) {
1001
+ p.additionalUpgrade = []
1002
+ }
1003
+
1004
+ // add root (can be optimised since the root is in tree.roots)
1005
+ p.additionalUpgrade.push(tree.get(ite.index))
1006
+ }
1007
+ }
1008
+
1009
+ function nodesToRoot (index, nodes, head) {
1010
+ const ite = flat.iterator(index)
1011
+
1012
+ for (let i = 0; i < nodes; i++) {
1013
+ ite.parent()
1014
+ if (ite.contains(head)) throw new Error('Nodes is out of bounds')
1015
+ }
1016
+
1017
+ return ite.index
1018
+ }
1019
+
1020
+ function totalSize (nodes) {
1021
+ let s = 0
1022
+ for (const node of nodes) s += node.size
1023
+ return s
1024
+ }
1025
+
1026
+ function totalSpan (nodes) {
1027
+ let s = 0
1028
+ for (const node of nodes) s += 2 * ((node.index - s) + 1)
1029
+ return s
1030
+ }
1031
+
1032
+ function blockNode (crypto, index, value) {
1033
+ return { index, size: value.byteLength, hash: crypto.data(value) }
1034
+ }
1035
+
1036
+ function parentNode (crypto, index, a, b) {
1037
+ return { index, size: a.size + b.size, hash: crypto.parent(a, b) }
1038
+ }
1039
+
1040
+ function blankNode (index) {
1041
+ return { index, size: 0, hash: BLANK_HASH }
1042
+ }
1043
+
1044
+ // Storage methods
1045
+
1046
+ function getStoredNode (storage, index, error) {
1047
+ return new Promise((resolve, reject) => {
1048
+ storage.read(40 * index, 40, (err, data) => {
1049
+ if (err) {
1050
+ if (error) return reject(err)
1051
+ else resolve(null)
1052
+ return
1053
+ }
1054
+
1055
+ const hash = data.subarray(8)
1056
+ const size = c.decode(c.uint64, data)
1057
+
1058
+ if (size === 0 && b4a.compare(hash, BLANK_HASH) === 0) {
1059
+ if (error) reject(new Error('Could not load node: ' + index))
1060
+ else resolve(null)
1061
+ return
1062
+ }
1063
+
1064
+ resolve({ index, size, hash })
1065
+ })
1066
+ })
1067
+ }
1068
+
1069
+ function storedNodes (storage) {
1070
+ return new Promise((resolve) => {
1071
+ storage.stat((_, st) => {
1072
+ if (!st) return resolve(0)
1073
+ resolve((st.size - (st.size % 40)) / 40)
1074
+ })
1075
+ })
1076
+ }
1077
+
1078
+ async function autoLength (storage) {
1079
+ const nodes = await storedNodes(storage)
1080
+ if (!nodes) return 0
1081
+ const ite = flat.iterator(nodes - 1)
1082
+ let index = nodes - 1
1083
+ while (await getStoredNode(storage, ite.parent(), false)) index = ite.index
1084
+ return flat.rightSpan(index) / 2 + 1
1085
+ }
1086
+
1087
+ function truncateMap (map, len) {
1088
+ for (const node of map.values()) {
1089
+ if (node.index >= 2 * len) map.delete(node.index)
1090
+ }
1091
+ }
1092
+
1093
+ function log2 (n) {
1094
+ let res = 1
1095
+
1096
+ while (n > 2) {
1097
+ n /= 2
1098
+ res++
1099
+ }
1100
+
1101
+ return res
1102
+ }
1103
+
1104
+ function signable (hash, length, fork) {
1105
+ const state = { start: 0, end: 48, buffer: b4a.alloc(48) }
1106
+ c.raw.encode(state, hash)
1107
+ c.uint64.encode(state, length)
1108
+ c.uint64.encode(state, fork)
1109
+ return state.buffer
1110
+ }