hypercore 10.0.0-alpha.5 → 10.0.0-alpha.50

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.
@@ -1,9 +1,11 @@
1
1
  const flat = require('flat-tree')
2
2
  const crypto = require('hypercore-crypto')
3
- const uint64le = require('uint64le')
3
+ const c = require('compact-encoding')
4
+ const b4a = require('b4a')
5
+ const caps = require('./caps')
4
6
 
5
- const BLANK_HASH = Buffer.alloc(32)
6
- const OLD_TREE = Buffer.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
7
+ const BLANK_HASH = b4a.alloc(32)
8
+ const OLD_TREE = b4a.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
7
9
 
8
10
  class NodeQueue {
9
11
  constructor (nodes, extra = null) {
@@ -56,11 +58,11 @@ class MerkleTreeBatch {
56
58
  }
57
59
 
58
60
  signable (hash = this.hash()) {
59
- return signable(hash, this.length, this.fork)
61
+ return caps.treeSignable(hash, this.length, this.fork)
60
62
  }
61
63
 
62
- signedBy (key) {
63
- return this.signature !== null && this.tree.crypto.verify(this.signable(), this.signature, key)
64
+ signableLegacy (hash = this.hash()) {
65
+ return caps.treeSignableLegacy(hash, this.length, this.fork)
64
66
  }
65
67
 
66
68
  append (buf) {
@@ -212,9 +214,9 @@ class ReorgBatch extends MerkleTreeBatch {
212
214
  if (this.want === null) return true
213
215
 
214
216
  const nodes = []
215
- const root = verifyBlock(proof, this.tree.crypto, nodes)
217
+ const root = verifyTree(proof, this.tree.crypto, nodes)
216
218
 
217
- if (root === null || !root.hash.equals(this.diff.hash)) return false
219
+ if (root === null || !b4a.equals(root.hash, this.diff.hash)) return false
218
220
 
219
221
  this.nodes.push(...nodes)
220
222
  return this._update(nodes)
@@ -226,13 +228,14 @@ class ReorgBatch extends MerkleTreeBatch {
226
228
 
227
229
  let diff = null
228
230
  const ite = flat.iterator(this.diff.index)
231
+ const startingDiff = this.diff
229
232
 
230
233
  while ((ite.index & 1) !== 0) {
231
234
  const left = n.get(ite.leftChild())
232
235
  if (!left) break
233
236
 
234
237
  const existing = await this.tree.get(left.index, false)
235
- if (!existing || !existing.hash.equals(left.hash)) {
238
+ if (!existing || !b4a.equals(existing.hash, left.hash)) {
236
239
  diff = left
237
240
  } else {
238
241
  diff = n.get(ite.sibling())
@@ -241,20 +244,19 @@ class ReorgBatch extends MerkleTreeBatch {
241
244
 
242
245
  if ((this.diff.index & 1) === 0) return true
243
246
  if (diff === null) return false
247
+ if (startingDiff !== this.diff) return false
244
248
 
245
249
  return this._updateDiffRoot(diff)
246
250
  }
247
251
 
248
252
  _updateDiffRoot (diff) {
253
+ if (this.want === null) return true
254
+
249
255
  const spans = flat.spans(diff.index)
250
256
  const start = spans[0] / 2
251
257
  const end = Math.min(this.treeLength, spans[1] / 2 + 1)
252
258
  const len = end - start
253
259
 
254
- if (this.diff !== null && len >= this.want.end - this.want.start) {
255
- return false
256
- }
257
-
258
260
  this.ancestors = start
259
261
  this.diff = diff
260
262
 
@@ -272,11 +274,15 @@ class ReorgBatch extends MerkleTreeBatch {
272
274
  }
273
275
 
274
276
  class ByteSeeker {
275
- constructor (tree, bytes) {
277
+ constructor (tree, bytes, padding = 0) {
276
278
  this.tree = tree
277
279
  this.bytes = bytes
278
- this.start = bytes >= tree.byteLength ? tree.length : 0
279
- this.end = bytes < tree.byteLength ? tree.length : 0
280
+ this.padding = padding
281
+
282
+ const size = tree.byteLength - (tree.length * padding)
283
+
284
+ this.start = bytes >= size ? tree.length : 0
285
+ this.end = bytes < size ? tree.length : 0
280
286
  }
281
287
 
282
288
  nodes () {
@@ -287,12 +293,12 @@ class ByteSeeker {
287
293
  if (!bytes) return [0, 0]
288
294
 
289
295
  for (const node of this.tree.roots) { // all async ticks happen once we find the root so safe
290
- if (bytes === node.size) {
291
- return [flat.rightSpan(node.index) + 2, 0]
292
- }
296
+ let size = node.size
297
+ if (this.padding > 0) size -= this.padding * flat.countLeaves(node.index)
293
298
 
294
- if (bytes > node.size) {
295
- bytes -= node.size
299
+ if (bytes === size) return [flat.rightSpan(node.index) + 2, 0]
300
+ if (bytes > size) {
301
+ bytes -= size
296
302
  continue
297
303
  }
298
304
 
@@ -301,9 +307,12 @@ class ByteSeeker {
301
307
  while ((ite.index & 1) !== 0) {
302
308
  const l = await this.tree.get(ite.leftChild(), false)
303
309
  if (l) {
304
- if (l.size === bytes) return [ite.rightSpan() + 2, 0]
305
- if (l.size > bytes) continue
306
- bytes -= l.size
310
+ let size = l.size
311
+ if (this.padding > 0) size -= this.padding * ite.countLeaves()
312
+
313
+ if (size === bytes) return [ite.rightSpan() + 2, 0]
314
+ if (size > bytes) continue
315
+ bytes -= size
307
316
  ite.sibling()
308
317
  } else {
309
318
  ite.parent()
@@ -347,7 +356,7 @@ module.exports = class MerkleTree {
347
356
  }
348
357
 
349
358
  addNode (node) {
350
- if (node.size === 0 && node.hash.equals(BLANK_HASH)) node = blankNode(node.index)
359
+ if (node.size === 0 && b4a.equals(node.hash, BLANK_HASH)) node = blankNode(node.index)
351
360
  this.unflushed.set(node.index, node)
352
361
  }
353
362
 
@@ -355,8 +364,8 @@ module.exports = class MerkleTree {
355
364
  return new MerkleTreeBatch(this)
356
365
  }
357
366
 
358
- seek (bytes) {
359
- return new ByteSeeker(this, bytes)
367
+ seek (bytes, padding) {
368
+ return new ByteSeeker(this, bytes, padding)
360
369
  }
361
370
 
362
371
  hash () {
@@ -364,11 +373,33 @@ module.exports = class MerkleTree {
364
373
  }
365
374
 
366
375
  signable (hash = this.hash()) {
367
- return signable(hash, this.length, this.fork)
376
+ return caps.treeSignable(hash, this.length, this.fork)
377
+ }
378
+
379
+ getRoots (length) {
380
+ const indexes = flat.fullRoots(2 * length)
381
+ const roots = new Array(indexes.length)
382
+
383
+ for (let i = 0; i < indexes.length; i++) {
384
+ roots[i] = this.get(indexes[i], true)
385
+ }
386
+
387
+ return Promise.all(roots)
368
388
  }
369
389
 
370
- signedBy (key) {
371
- return this.signature !== null && this.crypto.verify(this.signable(), this.signature, key)
390
+ async upgradeable (length) {
391
+ const indexes = flat.fullRoots(2 * length)
392
+ const roots = new Array(indexes.length)
393
+
394
+ for (let i = 0; i < indexes.length; i++) {
395
+ roots[i] = this.get(indexes[i], false)
396
+ }
397
+
398
+ for (const node of await Promise.all(roots)) {
399
+ if (node === null) return false
400
+ }
401
+
402
+ return true
372
403
  }
373
404
 
374
405
  get (index, error = true) {
@@ -433,17 +464,23 @@ module.exports = class MerkleTree {
433
464
  // TODO: write neighbors together etc etc
434
465
  // TODO: bench loading a full disk page and copy to that instead
435
466
  return new Promise((resolve, reject) => {
436
- const slab = Buffer.allocUnsafe(40 * this.flushing.size)
467
+ const slab = b4a.allocUnsafe(40 * this.flushing.size)
437
468
 
438
469
  let error = null
439
470
  let missing = this.flushing.size + 1
440
471
  let offset = 0
441
472
 
442
473
  for (const node of this.flushing.values()) {
443
- const b = slab.slice(offset, offset += 40)
444
- uint64le.encode(node.size, b, 0)
445
- node.hash.copy(b, 8)
446
- this.storage.write(node.index * 40, b, done)
474
+ const state = {
475
+ start: 0,
476
+ end: 40,
477
+ buffer: slab.subarray(offset, offset += 40)
478
+ }
479
+
480
+ c.uint64.encode(state, node.size)
481
+ c.raw.encode(state, node.hash)
482
+
483
+ this.storage.write(node.index * 40, state.buffer, done)
447
484
  }
448
485
 
449
486
  done(null)
@@ -510,8 +547,8 @@ module.exports = class MerkleTree {
510
547
 
511
548
  let unverified = null
512
549
 
513
- if (proof.block || proof.seek) {
514
- unverified = verifyBlock(proof, this.crypto, batch.nodes)
550
+ if (proof.block || proof.hash || proof.seek) {
551
+ unverified = verifyTree(proof, this.crypto, batch.nodes)
515
552
  }
516
553
 
517
554
  if (!verifyUpgrade(proof, unverified, batch)) {
@@ -520,7 +557,7 @@ module.exports = class MerkleTree {
520
557
 
521
558
  for (const root of batch.roots) {
522
559
  const existing = await this.get(root.index, false)
523
- if (existing && existing.hash.equals(root.hash)) continue
560
+ if (existing && b4a.equals(existing.hash, root.hash)) continue
524
561
  batch._updateDiffRoot(root)
525
562
  break
526
563
  }
@@ -538,7 +575,7 @@ module.exports = class MerkleTree {
538
575
  async verify (proof) {
539
576
  const batch = new MerkleTreeBatch(this)
540
577
 
541
- let unverified = verifyBlock(proof, this.crypto, batch.nodes)
578
+ let unverified = verifyTree(proof, this.crypto, batch.nodes)
542
579
 
543
580
  if (proof.upgrade) {
544
581
  if (verifyUpgrade(proof, unverified, batch)) {
@@ -548,7 +585,7 @@ module.exports = class MerkleTree {
548
585
 
549
586
  if (unverified) {
550
587
  const verified = await this.get(unverified.index)
551
- if (!verified.hash.equals(unverified.hash)) {
588
+ if (!b4a.equals(verified.hash, unverified.hash)) {
552
589
  throw new Error('Invalid checksum at node ' + unverified.index)
553
590
  }
554
591
  }
@@ -556,89 +593,102 @@ module.exports = class MerkleTree {
556
593
  return batch
557
594
  }
558
595
 
559
- async proof ({ block, seek, upgrade }) {
596
+ async proof ({ block, hash, seek, upgrade }) {
560
597
  // Important that this does not throw inbetween making the promise arrays
561
598
  // and finalise being called, otherwise there will be lingering promises in the background
562
599
 
563
- const signature = this.signature
564
600
  const fork = this.fork
601
+ const signature = this.signature
565
602
  const head = 2 * this.length
566
603
  const from = upgrade ? upgrade.start * 2 : 0
567
604
  const to = upgrade ? from + upgrade.length * 2 : head
605
+ const node = normalizeIndexed(block, hash)
568
606
 
569
607
  if (from >= to || to > head) {
570
608
  throw new Error('Invalid upgrade')
571
609
  }
572
- if (seek && block && upgrade && block.index * 2 >= from) {
573
- throw new Error('Cannot both do a seek and block request when upgrading')
610
+ if (seek && upgrade && node !== null && node.index >= from) {
611
+ throw new Error('Cannot both do a seek and block/hash request when upgrading')
574
612
  }
575
613
 
576
614
  let subTree = head
577
615
 
578
616
  const p = {
579
- block: null,
617
+ node: null,
580
618
  seek: null,
581
619
  upgrade: null,
582
620
  additionalUpgrade: null
583
621
  }
584
622
 
585
- if (block && (!upgrade || block.index < upgrade.start)) {
586
- subTree = nodesToRoot(2 * block.index, block.nodes, to)
623
+ if (node !== null && (!upgrade || node.lastIndex < upgrade.start)) {
624
+ subTree = nodesToRoot(node.index, node.nodes, to)
587
625
  const seekRoot = seek ? await seekUntrustedTree(this, subTree, seek.bytes) : head
588
- blockAndSeekProof(this, block, seek, seekRoot, subTree, p)
589
- } else if ((block || seek) && upgrade) {
590
- subTree = seek ? await seekFromHead(this, to, seek.bytes) : 2 * block.index
626
+ blockAndSeekProof(this, node, seek, seekRoot, subTree, p)
627
+ } else if ((node || seek) && upgrade) {
628
+ subTree = seek ? await seekFromHead(this, to, seek.bytes) : node.index
591
629
  }
592
630
 
593
631
  if (upgrade) {
594
- upgradeProof(this, block, seek, from, to, subTree, p)
632
+ upgradeProof(this, node, seek, from, to, subTree, p)
595
633
  if (head > to) additionalUpgradeProof(this, to, head, p)
596
634
  }
597
635
 
598
- try {
599
- const result = { fork, block: null, seek: null, upgrade: null }
600
-
601
- if (block) {
602
- const nodes = await Promise.all(p.block)
636
+ const [pNode, pSeek, pUpgrade, pAdditional] = await settleProof(p)
637
+ const result = { fork, block: null, hash: null, seek: null, upgrade: null }
603
638
 
604
- result.block = {
605
- index: block.index,
606
- value: null,
607
- nodes
608
- }
639
+ if (block) {
640
+ result.block = {
641
+ index: block.index,
642
+ value: null, // populated upstream, alloc it here for simplicity
643
+ nodes: pNode
609
644
  }
610
- if (seek && p.seek !== null) {
611
- const nodes = await Promise.all(p.seek)
645
+ } else if (hash) {
646
+ result.hash = {
647
+ index: hash.index,
648
+ nodes: pNode
649
+ }
650
+ }
612
651
 
613
- result.seek = {
614
- bytes: seek.bytes,
615
- nodes
616
- }
652
+ if (seek && pSeek !== null) {
653
+ result.seek = {
654
+ bytes: seek.bytes,
655
+ nodes: pSeek
617
656
  }
618
- if (upgrade) {
619
- const nodes = await Promise.all(p.upgrade)
620
- const additionalNodes = await Promise.all(p.additionalUpgrade || [])
621
-
622
- result.upgrade = {
623
- start: upgrade.start,
624
- length: upgrade.length,
625
- nodes,
626
- additionalNodes,
627
- signature
628
- }
657
+ }
658
+
659
+ if (upgrade) {
660
+ result.upgrade = {
661
+ start: upgrade.start,
662
+ length: upgrade.length,
663
+ nodes: pUpgrade,
664
+ additionalNodes: pAdditional || [],
665
+ signature
629
666
  }
667
+ }
630
668
 
631
- return result
632
- } catch (err) {
633
- // Make sure we await all pending p so don't have background async state...
634
- if (p.seek !== null) await Promise.allSettled(p.seek)
635
- if (p.block !== null) await Promise.allSettled(p.block)
636
- if (p.upgrade !== null) await Promise.allSettled(p.upgrade)
637
- if (p.additionalUpgrade !== null) await Promise.allSettled(p.additionalUpgrade)
638
- throw err
669
+ return result
670
+ }
671
+
672
+ // Successor to .nodes()
673
+ async missingNodes (index) {
674
+ const head = 2 * this.length
675
+ const ite = flat.iterator(index)
676
+
677
+ // See iterator.rightSpan()
678
+ const iteRightSpan = ite.index + ite.factor / 2 - 1
679
+ // If the index is not in the current tree, we do not know how many missing nodes there are...
680
+ if (iteRightSpan >= head) return 0
681
+
682
+ let cnt = 0
683
+ while (!ite.contains(head) && (await this.get(ite.index, false)) === null) {
684
+ cnt++
685
+ ite.parent()
639
686
  }
687
+
688
+ return cnt
640
689
  }
641
690
 
691
+ // Deprecated
642
692
  async nodes (index) {
643
693
  const head = 2 * this.length
644
694
  const ite = flat.iterator(index)
@@ -693,7 +743,7 @@ module.exports = class MerkleTree {
693
743
  await new Promise((resolve, reject) => {
694
744
  storage.read(0, OLD_TREE.length, (err, buf) => {
695
745
  if (err) return resolve()
696
- if (buf.equals(OLD_TREE)) return reject(new Error('Storage contains an incompatible merkle tree'))
746
+ if (b4a.equals(buf, OLD_TREE)) return reject(new Error('Storage contains an incompatible merkle tree'))
697
747
  resolve()
698
748
  })
699
749
  })
@@ -713,8 +763,14 @@ module.exports = class MerkleTree {
713
763
 
714
764
  // All the methods needed for proof verification
715
765
 
716
- function verifyBlock ({ block, seek }, crypto, nodes) {
717
- if (!block && (!seek || !seek.nodes.length)) return null
766
+ function verifyTree ({ block, hash, seek }, crypto, nodes) {
767
+ const untrustedNode = block
768
+ ? { index: 2 * block.index, value: block.value, nodes: block.nodes }
769
+ : hash
770
+ ? { index: hash.index, value: null, nodes: hash.nodes }
771
+ : null
772
+
773
+ if (untrustedNode === null && (!seek || !seek.nodes.length)) return null
718
774
 
719
775
  let root = null
720
776
 
@@ -734,12 +790,12 @@ function verifyBlock ({ block, seek }, crypto, nodes) {
734
790
  }
735
791
  }
736
792
 
737
- if (!block) return root
793
+ if (untrustedNode === null) return root
738
794
 
739
- const ite = flat.iterator(2 * block.index)
740
- const blockHash = block.value && blockNode(crypto, ite.index, block.value)
795
+ const ite = flat.iterator(untrustedNode.index)
796
+ const blockHash = untrustedNode.value && blockNode(crypto, ite.index, untrustedNode.value)
741
797
 
742
- const q = new NodeQueue(block.nodes, root)
798
+ const q = new NodeQueue(untrustedNode.nodes, root)
743
799
 
744
800
  root = blockHash || q.shift(ite.index)
745
801
  nodes.push(root)
@@ -888,13 +944,13 @@ function seekProof (tree, seekRoot, root, p) {
888
944
  }
889
945
  }
890
946
 
891
- function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
892
- if (!block) return seekProof(tree, seekRoot, root, p)
947
+ function blockAndSeekProof (tree, node, seek, seekRoot, root, p) {
948
+ if (!node) return seekProof(tree, seekRoot, root, p)
893
949
 
894
- const ite = flat.iterator(2 * block.index)
950
+ const ite = flat.iterator(node.index)
895
951
 
896
- p.block = []
897
- if (!block.value) p.block.push(tree.get(ite.index))
952
+ p.node = []
953
+ if (!node.value) p.node.push(tree.get(ite.index))
898
954
 
899
955
  while (ite.index !== root) {
900
956
  ite.sibling()
@@ -902,14 +958,14 @@ function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
902
958
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
903
959
  seekProof(tree, seekRoot, ite.index, p)
904
960
  } else {
905
- p.block.push(tree.get(ite.index))
961
+ p.node.push(tree.get(ite.index))
906
962
  }
907
963
 
908
964
  ite.parent()
909
965
  }
910
966
  }
911
967
 
912
- function upgradeProof (tree, block, seek, from, to, subTree, p) {
968
+ function upgradeProof (tree, node, seek, from, to, subTree, p) {
913
969
  if (from === 0) p.upgrade = []
914
970
 
915
971
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -928,8 +984,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
928
984
  while (ite.index !== root) {
929
985
  ite.sibling()
930
986
  if (ite.index > target) {
931
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
932
- blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
987
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
988
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
933
989
  } else {
934
990
  p.upgrade.push(tree.get(ite.index))
935
991
  }
@@ -946,8 +1002,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
946
1002
 
947
1003
  // if the subtree included is a child of this tree, include that one
948
1004
  // instead of a dup node
949
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
950
- blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
1005
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
1006
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
951
1007
  continue
952
1008
  }
953
1009
 
@@ -1038,10 +1094,10 @@ function getStoredNode (storage, index, error) {
1038
1094
  return
1039
1095
  }
1040
1096
 
1041
- const hash = data.slice(8)
1042
- const size = uint64le.decode(data, 0)
1097
+ const hash = data.subarray(8)
1098
+ const size = c.decode(c.uint64, data)
1043
1099
 
1044
- if (size === 0 && Buffer.compare(hash, BLANK_HASH) === 0) {
1100
+ if (size === 0 && b4a.compare(hash, BLANK_HASH) === 0) {
1045
1101
  if (error) reject(new Error('Could not load node: ' + index))
1046
1102
  else resolve(null)
1047
1103
  return
@@ -1087,10 +1143,27 @@ function log2 (n) {
1087
1143
  return res
1088
1144
  }
1089
1145
 
1090
- function signable (hash, length, fork) {
1091
- const buf = Buffer.alloc(48)
1092
- hash.copy(buf)
1093
- uint64le.encode(length, buf, 32)
1094
- uint64le.encode(fork, buf, 40)
1095
- return buf
1146
+ function normalizeIndexed (block, hash) {
1147
+ if (block) return { value: true, index: block.index * 2, nodes: block.nodes, lastIndex: block.index }
1148
+ if (hash) return { value: false, index: hash.index, nodes: hash.nodes, lastIndex: flat.rightSpan(hash.index) / 2 }
1149
+ return null
1150
+ }
1151
+
1152
+ async function settleProof (p) {
1153
+ const result = [
1154
+ p.node && Promise.all(p.node),
1155
+ p.seek && Promise.all(p.seek),
1156
+ p.upgrade && Promise.all(p.upgrade),
1157
+ p.additionalUpgrade && Promise.all(p.additionalUpgrade)
1158
+ ]
1159
+
1160
+ try {
1161
+ return await Promise.all(result)
1162
+ } catch (err) {
1163
+ if (p.node) await Promise.allSettled(p.node)
1164
+ if (p.seek) await Promise.allSettled(p.seek)
1165
+ if (p.upgrade) await Promise.allSettled(p.upgrade)
1166
+ if (p.additionalUpgrade) await Promise.allSettled(p.additionalUpgrade)
1167
+ throw err
1168
+ }
1096
1169
  }