hypercore 10.0.0-alpha.25 → 10.0.0-alpha.26

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) {
@@ -552,8 +549,8 @@ module.exports = class MerkleTree {
552
549
 
553
550
  let unverified = null
554
551
 
555
- if (proof.block || proof.seek) {
556
- unverified = verifyBlock(proof, this.crypto, batch.nodes)
552
+ if (proof.block || proof.hash || proof.seek) {
553
+ unverified = verifyTree(proof, this.crypto, batch.nodes)
557
554
  }
558
555
 
559
556
  if (!verifyUpgrade(proof, unverified, batch)) {
@@ -580,7 +577,7 @@ module.exports = class MerkleTree {
580
577
  async verify (proof) {
581
578
  const batch = new MerkleTreeBatch(this)
582
579
 
583
- let unverified = verifyBlock(proof, this.crypto, batch.nodes)
580
+ let unverified = verifyTree(proof, this.crypto, batch.nodes)
584
581
 
585
582
  if (proof.upgrade) {
586
583
  if (verifyUpgrade(proof, unverified, batch)) {
@@ -598,89 +595,102 @@ module.exports = class MerkleTree {
598
595
  return batch
599
596
  }
600
597
 
601
- async proof ({ block, seek, upgrade }) {
598
+ async proof ({ block, hash, seek, upgrade }) {
602
599
  // Important that this does not throw inbetween making the promise arrays
603
600
  // and finalise being called, otherwise there will be lingering promises in the background
604
601
 
605
- const signature = this.signature
606
602
  const fork = this.fork
603
+ const signature = this.signature
607
604
  const head = 2 * this.length
608
605
  const from = upgrade ? upgrade.start * 2 : 0
609
606
  const to = upgrade ? from + upgrade.length * 2 : head
607
+ const node = normalizeIndexed(block, hash)
610
608
 
611
609
  if (from >= to || to > head) {
612
610
  throw new Error('Invalid upgrade')
613
611
  }
614
- if (seek && block && upgrade && block.index * 2 >= from) {
615
- 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')
616
614
  }
617
615
 
618
616
  let subTree = head
619
617
 
620
618
  const p = {
621
- block: null,
619
+ node: null,
622
620
  seek: null,
623
621
  upgrade: null,
624
622
  additionalUpgrade: null
625
623
  }
626
624
 
627
- if (block && (!upgrade || block.index < upgrade.start)) {
628
- 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)
629
627
  const seekRoot = seek ? await seekUntrustedTree(this, subTree, seek.bytes) : head
630
- blockAndSeekProof(this, block, seek, seekRoot, subTree, p)
631
- } else if ((block || seek) && upgrade) {
632
- 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
633
631
  }
634
632
 
635
633
  if (upgrade) {
636
- upgradeProof(this, block, seek, from, to, subTree, p)
634
+ upgradeProof(this, node, seek, from, to, subTree, p)
637
635
  if (head > to) additionalUpgradeProof(this, to, head, p)
638
636
  }
639
637
 
640
- try {
641
- const result = { fork, block: null, seek: null, upgrade: null }
638
+ const [pNode, pSeek, pUpgrade, pAdditional] = await settleProof(p)
639
+ const result = { fork, block: null, hash: null, seek: null, upgrade: null }
642
640
 
643
- if (block) {
644
- const nodes = await Promise.all(p.block)
645
-
646
- result.block = {
647
- index: block.index,
648
- value: null,
649
- nodes
650
- }
641
+ if (block) {
642
+ result.block = {
643
+ index: block.index,
644
+ value: null, // populated upstream, alloc it here for simplicity
645
+ nodes: pNode
651
646
  }
652
- if (seek && p.seek !== null) {
653
- const nodes = await Promise.all(p.seek)
647
+ } else if (hash) {
648
+ result.hash = {
649
+ index: hash.index,
650
+ nodes: pNode
651
+ }
652
+ }
654
653
 
655
- result.seek = {
656
- bytes: seek.bytes,
657
- nodes
658
- }
654
+ if (seek && pSeek !== null) {
655
+ result.seek = {
656
+ bytes: seek.bytes,
657
+ nodes: pSeek
659
658
  }
660
- if (upgrade) {
661
- const nodes = await Promise.all(p.upgrade)
662
- const additionalNodes = await Promise.all(p.additionalUpgrade || [])
663
-
664
- result.upgrade = {
665
- start: upgrade.start,
666
- length: upgrade.length,
667
- nodes,
668
- additionalNodes,
669
- signature
670
- }
659
+ }
660
+
661
+ if (upgrade) {
662
+ result.upgrade = {
663
+ start: upgrade.start,
664
+ length: upgrade.length,
665
+ nodes: pUpgrade,
666
+ additionalNodes: pAdditional || [],
667
+ signature
671
668
  }
669
+ }
672
670
 
673
- return result
674
- } catch (err) {
675
- // Make sure we await all pending p so don't have background async state...
676
- if (p.seek !== null) await Promise.allSettled(p.seek)
677
- if (p.block !== null) await Promise.allSettled(p.block)
678
- if (p.upgrade !== null) await Promise.allSettled(p.upgrade)
679
- if (p.additionalUpgrade !== null) await Promise.allSettled(p.additionalUpgrade)
680
- 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()
681
688
  }
689
+
690
+ return cnt
682
691
  }
683
692
 
693
+ // Deprecated
684
694
  async nodes (index) {
685
695
  const head = 2 * this.length
686
696
  const ite = flat.iterator(index)
@@ -755,8 +765,14 @@ module.exports = class MerkleTree {
755
765
 
756
766
  // All the methods needed for proof verification
757
767
 
758
- function verifyBlock ({ block, seek }, crypto, nodes) {
759
- 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
760
776
 
761
777
  let root = null
762
778
 
@@ -776,12 +792,12 @@ function verifyBlock ({ block, seek }, crypto, nodes) {
776
792
  }
777
793
  }
778
794
 
779
- if (!block) return root
795
+ if (untrustedNode === null) return root
780
796
 
781
- const ite = flat.iterator(2 * block.index)
782
- 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)
783
799
 
784
- const q = new NodeQueue(block.nodes, root)
800
+ const q = new NodeQueue(untrustedNode.nodes, root)
785
801
 
786
802
  root = blockHash || q.shift(ite.index)
787
803
  nodes.push(root)
@@ -930,13 +946,13 @@ function seekProof (tree, seekRoot, root, p) {
930
946
  }
931
947
  }
932
948
 
933
- function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
934
- 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)
935
951
 
936
- const ite = flat.iterator(2 * block.index)
952
+ const ite = flat.iterator(node.index)
937
953
 
938
- p.block = []
939
- if (!block.value) p.block.push(tree.get(ite.index))
954
+ p.node = []
955
+ if (!node.value) p.node.push(tree.get(ite.index))
940
956
 
941
957
  while (ite.index !== root) {
942
958
  ite.sibling()
@@ -944,14 +960,14 @@ function blockAndSeekProof (tree, block, seek, seekRoot, root, p) {
944
960
  if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
945
961
  seekProof(tree, seekRoot, ite.index, p)
946
962
  } else {
947
- p.block.push(tree.get(ite.index))
963
+ p.node.push(tree.get(ite.index))
948
964
  }
949
965
 
950
966
  ite.parent()
951
967
  }
952
968
  }
953
969
 
954
- function upgradeProof (tree, block, seek, from, to, subTree, p) {
970
+ function upgradeProof (tree, node, seek, from, to, subTree, p) {
955
971
  if (from === 0) p.upgrade = []
956
972
 
957
973
  for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
@@ -970,8 +986,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
970
986
  while (ite.index !== root) {
971
987
  ite.sibling()
972
988
  if (ite.index > target) {
973
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
974
- 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)
975
991
  } else {
976
992
  p.upgrade.push(tree.get(ite.index))
977
993
  }
@@ -988,8 +1004,8 @@ function upgradeProof (tree, block, seek, from, to, subTree, p) {
988
1004
 
989
1005
  // if the subtree included is a child of this tree, include that one
990
1006
  // instead of a dup node
991
- if (p.block === null && p.seek === null && ite.contains(subTree)) {
992
- 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)
993
1009
  continue
994
1010
  }
995
1011
 
@@ -1129,10 +1145,27 @@ function log2 (n) {
1129
1145
  return res
1130
1146
  }
1131
1147
 
1132
- function signable (hash, length, fork) {
1133
- const state = { start: 0, end: 48, buffer: b4a.alloc(48) }
1134
- c.raw.encode(state, hash)
1135
- c.uint64.encode(state, length)
1136
- c.uint64.encode(state, fork)
1137
- 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
+ }
1138
1171
  }