hypercore 10.0.0-alpha.24 → 10.0.0-alpha.27

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.
@@ -2,6 +2,7 @@ const flat = require('flat-tree')
2
2
  const crypto = require('hypercore-crypto')
3
3
  const c = require('compact-encoding')
4
4
  const b4a = require('b4a')
5
+ const caps = require('./caps')
5
6
 
6
7
  const BLANK_HASH = b4a.alloc(32)
7
8
  const OLD_TREE = b4a.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
@@ -57,11 +58,11 @@ class MerkleTreeBatch {
57
58
  }
58
59
 
59
60
  signable (hash = this.hash()) {
60
- return signable(hash, this.length, this.fork)
61
+ return caps.treeSignable(hash, this.length, this.fork)
61
62
  }
62
63
 
63
- signedBy (key) {
64
- 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)
65
66
  }
66
67
 
67
68
  append (buf) {
@@ -213,7 +214,7 @@ class ReorgBatch extends MerkleTreeBatch {
213
214
  if (this.want === null) return true
214
215
 
215
216
  const nodes = []
216
- const root = verifyBlock(proof, this.tree.crypto, nodes)
217
+ const root = verifyTree(proof, this.tree.crypto, nodes)
217
218
 
218
219
  if (root === null || !b4a.equals(root.hash, this.diff.hash)) return false
219
220
 
@@ -374,11 +375,7 @@ module.exports = class MerkleTree {
374
375
  }
375
376
 
376
377
  signable (hash = this.hash()) {
377
- return signable(hash, this.length, this.fork)
378
- }
379
-
380
- signedBy (key) {
381
- return this.signature !== null && this.crypto.verify(this.signable(), this.signature, key)
378
+ return caps.treeSignable(hash, this.length, this.fork)
382
379
  }
383
380
 
384
381
  getRoots (length) {
@@ -392,6 +389,21 @@ module.exports = class MerkleTree {
392
389
  return Promise.all(roots)
393
390
  }
394
391
 
392
+ async upgradeable (length) {
393
+ const indexes = flat.fullRoots(2 * length)
394
+ const roots = new Array(indexes.length)
395
+
396
+ for (let i = 0; i < indexes.length; i++) {
397
+ roots[i] = this.get(indexes[i], false)
398
+ }
399
+
400
+ for (const node of await Promise.all(roots)) {
401
+ if (node === null) return false
402
+ }
403
+
404
+ return true
405
+ }
406
+
395
407
  get (index, error = true) {
396
408
  let node = this.unflushed.get(index)
397
409
 
@@ -537,8 +549,8 @@ module.exports = class MerkleTree {
537
549
 
538
550
  let unverified = null
539
551
 
540
- if (proof.block || proof.seek) {
541
- unverified = verifyBlock(proof, this.crypto, batch.nodes)
552
+ if (proof.block || proof.hash || proof.seek) {
553
+ unverified = verifyTree(proof, this.crypto, batch.nodes)
542
554
  }
543
555
 
544
556
  if (!verifyUpgrade(proof, unverified, batch)) {
@@ -565,7 +577,7 @@ module.exports = class MerkleTree {
565
577
  async verify (proof) {
566
578
  const batch = new MerkleTreeBatch(this)
567
579
 
568
- let unverified = verifyBlock(proof, this.crypto, batch.nodes)
580
+ let unverified = verifyTree(proof, this.crypto, batch.nodes)
569
581
 
570
582
  if (proof.upgrade) {
571
583
  if (verifyUpgrade(proof, unverified, batch)) {
@@ -583,89 +595,102 @@ module.exports = class MerkleTree {
583
595
  return batch
584
596
  }
585
597
 
586
- async proof ({ block, seek, upgrade }) {
598
+ async proof ({ block, hash, seek, upgrade }) {
587
599
  // Important that this does not throw inbetween making the promise arrays
588
600
  // and finalise being called, otherwise there will be lingering promises in the background
589
601
 
590
- const signature = this.signature
591
602
  const fork = this.fork
603
+ const signature = this.signature
592
604
  const head = 2 * this.length
593
605
  const from = upgrade ? upgrade.start * 2 : 0
594
606
  const to = upgrade ? from + upgrade.length * 2 : head
607
+ const node = normalizeIndexed(block, hash)
595
608
 
596
609
  if (from >= to || to > head) {
597
610
  throw new Error('Invalid upgrade')
598
611
  }
599
- if (seek && block && upgrade && block.index * 2 >= from) {
600
- throw new Error('Cannot both do a seek and block request when upgrading')
612
+ if (seek && upgrade && node !== null && node.index >= from) {
613
+ throw new Error('Cannot both do a seek and block/hash request when upgrading')
601
614
  }
602
615
 
603
616
  let subTree = head
604
617
 
605
618
  const p = {
606
- block: null,
619
+ node: null,
607
620
  seek: null,
608
621
  upgrade: null,
609
622
  additionalUpgrade: null
610
623
  }
611
624
 
612
- if (block && (!upgrade || block.index < upgrade.start)) {
613
- subTree = nodesToRoot(2 * block.index, block.nodes, to)
625
+ if (node !== null && (!upgrade || node.lastIndex < upgrade.start)) {
626
+ subTree = nodesToRoot(node.index, node.nodes, to)
614
627
  const seekRoot = seek ? await seekUntrustedTree(this, subTree, seek.bytes) : head
615
- blockAndSeekProof(this, block, seek, seekRoot, subTree, p)
616
- } else if ((block || seek) && upgrade) {
617
- subTree = seek ? await seekFromHead(this, to, seek.bytes) : 2 * block.index
628
+ blockAndSeekProof(this, node, seek, seekRoot, subTree, p)
629
+ } else if ((node || seek) && upgrade) {
630
+ subTree = seek ? await seekFromHead(this, to, seek.bytes) : node.index
618
631
  }
619
632
 
620
633
  if (upgrade) {
621
- upgradeProof(this, block, seek, from, to, subTree, p)
634
+ upgradeProof(this, node, seek, from, to, subTree, p)
622
635
  if (head > to) additionalUpgradeProof(this, to, head, p)
623
636
  }
624
637
 
625
- try {
626
- const result = { fork, block: null, seek: null, upgrade: null }
627
-
628
- if (block) {
629
- const nodes = await Promise.all(p.block)
638
+ const [pNode, pSeek, pUpgrade, pAdditional] = await settleProof(p)
639
+ const result = { fork, block: null, hash: null, seek: null, upgrade: null }
630
640
 
631
- result.block = {
632
- index: block.index,
633
- value: null,
634
- nodes
635
- }
641
+ if (block) {
642
+ result.block = {
643
+ index: block.index,
644
+ value: null, // populated upstream, alloc it here for simplicity
645
+ nodes: pNode
636
646
  }
637
- if (seek && p.seek !== null) {
638
- const nodes = await Promise.all(p.seek)
647
+ } else if (hash) {
648
+ result.hash = {
649
+ index: hash.index,
650
+ nodes: pNode
651
+ }
652
+ }
639
653
 
640
- result.seek = {
641
- bytes: seek.bytes,
642
- nodes
643
- }
654
+ if (seek && pSeek !== null) {
655
+ result.seek = {
656
+ bytes: seek.bytes,
657
+ nodes: pSeek
644
658
  }
645
- if (upgrade) {
646
- const nodes = await Promise.all(p.upgrade)
647
- const additionalNodes = await Promise.all(p.additionalUpgrade || [])
648
-
649
- result.upgrade = {
650
- start: upgrade.start,
651
- length: upgrade.length,
652
- nodes,
653
- additionalNodes,
654
- signature
655
- }
659
+ }
660
+
661
+ if (upgrade) {
662
+ result.upgrade = {
663
+ start: upgrade.start,
664
+ length: upgrade.length,
665
+ nodes: pUpgrade,
666
+ additionalNodes: pAdditional || [],
667
+ signature
656
668
  }
669
+ }
657
670
 
658
- return result
659
- } catch (err) {
660
- // Make sure we await all pending p so don't have background async state...
661
- if (p.seek !== null) await Promise.allSettled(p.seek)
662
- if (p.block !== null) await Promise.allSettled(p.block)
663
- if (p.upgrade !== null) await Promise.allSettled(p.upgrade)
664
- if (p.additionalUpgrade !== null) await Promise.allSettled(p.additionalUpgrade)
665
- throw err
671
+ return result
672
+ }
673
+
674
+ // Successor to .nodes()
675
+ async missingNodes (index) {
676
+ const head = 2 * this.length
677
+ const ite = flat.iterator(index)
678
+
679
+ // See iterator.rightSpan()
680
+ const iteRightSpan = ite.index + ite.factor / 2 - 1
681
+ // If the index is not in the current tree, we do not know how many missing nodes there are...
682
+ if (iteRightSpan >= head) return 0
683
+
684
+ let cnt = 0
685
+ while (!ite.contains(head) && (await this.get(ite.index, false)) === null) {
686
+ cnt++
687
+ ite.parent()
666
688
  }
689
+
690
+ return cnt
667
691
  }
668
692
 
693
+ // Deprecated
669
694
  async nodes (index) {
670
695
  const head = 2 * this.length
671
696
  const ite = flat.iterator(index)
@@ -740,8 +765,14 @@ module.exports = class MerkleTree {
740
765
 
741
766
  // All the methods needed for proof verification
742
767
 
743
- function verifyBlock ({ block, seek }, crypto, nodes) {
744
- if (!block && (!seek || !seek.nodes.length)) return null
768
+ function verifyTree ({ block, hash, seek }, crypto, nodes) {
769
+ const untrustedNode = block
770
+ ? { index: 2 * block.index, value: block.value, nodes: block.nodes }
771
+ : hash
772
+ ? { index: hash.index, value: null, nodes: hash.nodes }
773
+ : null
774
+
775
+ if (untrustedNode === null && (!seek || !seek.nodes.length)) return null
745
776
 
746
777
  let root = null
747
778
 
@@ -761,12 +792,12 @@ function verifyBlock ({ block, seek }, crypto, nodes) {
761
792
  }
762
793
  }
763
794
 
764
- if (!block) return root
795
+ if (untrustedNode === null) return root
765
796
 
766
- const ite = flat.iterator(2 * block.index)
767
- const blockHash = block.value && blockNode(crypto, ite.index, block.value)
797
+ const ite = flat.iterator(untrustedNode.index)
798
+ const blockHash = untrustedNode.value && blockNode(crypto, ite.index, untrustedNode.value)
768
799
 
769
- const q = new NodeQueue(block.nodes, root)
800
+ const q = new NodeQueue(untrustedNode.nodes, root)
770
801
 
771
802
  root = blockHash || q.shift(ite.index)
772
803
  nodes.push(root)
@@ -915,13 +946,13 @@ function seekProof (tree, seekRoot, root, p) {
915
946
  }
916
947
  }
917
948
 
918
- function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
919
- if (!block) return seekProof(tree, seekRoot, root, p)
949
+ function blockAndSeekProof (tree, node, seek, seekRoot, root, p) {
950
+ if (!node) return seekProof(tree, seekRoot, root, p)
920
951
 
921
- const ite = flat.iterator(2 * block.index)
952
+ const ite = flat.iterator(node.index)
922
953
 
923
- p.block = []
924
- if (!block.value) p.block.push(tree.get(ite.index))
954
+ p.node = []
955
+ if (!node.value) p.node.push(tree.get(ite.index))
925
956
 
926
957
  while (ite.index !== root) {
927
958
  ite.sibling()
@@ -929,14 +960,14 @@ function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
929
960
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
930
961
  seekProof(tree, seekRoot, ite.index, p)
931
962
  } else {
932
- p.block.push(tree.get(ite.index))
963
+ p.node.push(tree.get(ite.index))
933
964
  }
934
965
 
935
966
  ite.parent()
936
967
  }
937
968
  }
938
969
 
939
- function upgradeProof (tree, block, seek, from, to, subTree, p) {
970
+ function upgradeProof (tree, node, seek, from, to, subTree, p) {
940
971
  if (from === 0) p.upgrade = []
941
972
 
942
973
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -955,8 +986,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
955
986
  while (ite.index !== root) {
956
987
  ite.sibling()
957
988
  if (ite.index > target) {
958
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
959
- blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
989
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
990
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
960
991
  } else {
961
992
  p.upgrade.push(tree.get(ite.index))
962
993
  }
@@ -973,8 +1004,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
973
1004
 
974
1005
  // if the subtree included is a child of this tree, include that one
975
1006
  // instead of a dup node
976
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
977
- blockAndSeekProof(tree, block, seek, subTree, ite.index, p)
1007
+ if (p.node === null && p.seek === null && ite.contains(subTree)) {
1008
+ blockAndSeekProof(tree, node, seek, subTree, ite.index, p)
978
1009
  continue
979
1010
  }
980
1011
 
@@ -1114,10 +1145,27 @@ function log2 (n) {
1114
1145
  return res
1115
1146
  }
1116
1147
 
1117
- function signable (hash, length, fork) {
1118
- const state = { start: 0, end: 48, buffer: b4a.alloc(48) }
1119
- c.raw.encode(state, hash)
1120
- c.uint64.encode(state, length)
1121
- c.uint64.encode(state, fork)
1122
- return state.buffer
1148
+ function normalizeIndexed (block, hash) {
1149
+ if (block) return { value: true, index: block.index * 2, nodes: block.nodes, lastIndex: block.index }
1150
+ if (hash) return { value: false, index: hash.index, nodes: hash.nodes, lastIndex: flat.rightSpan(hash.index) / 2 }
1151
+ return null
1152
+ }
1153
+
1154
+ async function settleProof (p) {
1155
+ const result = [
1156
+ p.node && Promise.all(p.node),
1157
+ p.seek && Promise.all(p.seek),
1158
+ p.upgrade && Promise.all(p.upgrade),
1159
+ p.additionalUpgrade && Promise.all(p.additionalUpgrade)
1160
+ ]
1161
+
1162
+ try {
1163
+ return await Promise.all(result)
1164
+ } catch (err) {
1165
+ if (p.node) await Promise.allSettled(p.node)
1166
+ if (p.seek) await Promise.allSettled(p.seek)
1167
+ if (p.upgrade) await Promise.allSettled(p.upgrade)
1168
+ if (p.additionalUpgrade) await Promise.allSettled(p.additionalUpgrade)
1169
+ throw err
1170
+ }
1123
1171
  }