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.
- package/index.js +145 -79
- package/lib/bitfield.js +6 -3
- package/lib/caps.js +34 -0
- package/lib/core.js +26 -10
- package/lib/merkle-tree.js +114 -81
- package/lib/messages.js +246 -177
- package/lib/replicator.js +1253 -592
- package/package.json +5 -3
- package/lib/extensions.js +0 -76
- package/lib/protocol.js +0 -606
- package/lib/random-iterator.js +0 -46
package/lib/merkle-tree.js
CHANGED
|
@@ -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
|
|
61
|
+
return caps.treeSignable(hash, this.length, this.fork)
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
return
|
|
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 =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 &&
|
|
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
|
-
|
|
619
|
+
node: null,
|
|
622
620
|
seek: null,
|
|
623
621
|
upgrade: null,
|
|
624
622
|
additionalUpgrade: null
|
|
625
623
|
}
|
|
626
624
|
|
|
627
|
-
if (
|
|
628
|
-
subTree = nodesToRoot(
|
|
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,
|
|
631
|
-
} else if ((
|
|
632
|
-
subTree = seek ? await seekFromHead(this, to, seek.bytes) :
|
|
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,
|
|
634
|
+
upgradeProof(this, node, seek, from, to, subTree, p)
|
|
637
635
|
if (head > to) additionalUpgradeProof(this, to, head, p)
|
|
638
636
|
}
|
|
639
637
|
|
|
640
|
-
|
|
641
|
-
|
|
638
|
+
const [pNode, pSeek, pUpgrade, pAdditional] = await settleProof(p)
|
|
639
|
+
const result = { fork, block: null, hash: null, seek: null, upgrade: null }
|
|
642
640
|
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
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
|
-
|
|
653
|
-
|
|
647
|
+
} else if (hash) {
|
|
648
|
+
result.hash = {
|
|
649
|
+
index: hash.index,
|
|
650
|
+
nodes: pNode
|
|
651
|
+
}
|
|
652
|
+
}
|
|
654
653
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
654
|
+
if (seek && pSeek !== null) {
|
|
655
|
+
result.seek = {
|
|
656
|
+
bytes: seek.bytes,
|
|
657
|
+
nodes: pSeek
|
|
659
658
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
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
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
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
|
|
759
|
-
|
|
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 (
|
|
795
|
+
if (untrustedNode === null) return root
|
|
780
796
|
|
|
781
|
-
const ite = flat.iterator(
|
|
782
|
-
const blockHash =
|
|
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(
|
|
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,
|
|
934
|
-
if (!
|
|
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(
|
|
952
|
+
const ite = flat.iterator(node.index)
|
|
937
953
|
|
|
938
|
-
p.
|
|
939
|
-
if (!
|
|
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.
|
|
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,
|
|
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.
|
|
974
|
-
blockAndSeekProof(tree,
|
|
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.
|
|
992
|
-
blockAndSeekProof(tree,
|
|
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
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
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
|
}
|