hypercore 11.0.43 → 11.0.45
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 +3 -0
- package/lib/core.js +48 -8
- package/lib/merkle-tree.js +79 -94
- package/lib/replicator.js +9 -1
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -370,6 +370,9 @@ class Hypercore extends EventEmitter {
|
|
|
370
370
|
if (this.state && checkout !== -1) {
|
|
371
371
|
if (!opts.name && !opts.atom) throw ASSERTION('Checkouts must be named or atomized')
|
|
372
372
|
if (checkout > this.state.length) throw ASSERTION('Invalid checkout ' + checkout + ' for ' + opts.name + ', length is ' + this.state.length)
|
|
373
|
+
if (this.state.prologue && checkout < this.state.prologue.length) {
|
|
374
|
+
throw ASSERTION('Invalid checkout ' + checkout + ' for ' + opts.name + ', prologue length is ' + this.state.prologue.length)
|
|
375
|
+
}
|
|
373
376
|
if (checkout < this.state.length) await this.state.truncate(checkout, this.fork)
|
|
374
377
|
}
|
|
375
378
|
|
package/lib/core.js
CHANGED
|
@@ -171,6 +171,7 @@ module.exports = class Core {
|
|
|
171
171
|
key: opts.key || (compat ? manifest.signers[0].publicKey : Verifier.manifestHash(manifest)),
|
|
172
172
|
manifest,
|
|
173
173
|
keyPair: keyPair ? { publicKey: keyPair.publicKey, secretKey: keyPair.secretKey || null } : null,
|
|
174
|
+
frozen: false,
|
|
174
175
|
userData: [],
|
|
175
176
|
tree: {
|
|
176
177
|
fork: 0,
|
|
@@ -190,6 +191,7 @@ module.exports = class Core {
|
|
|
190
191
|
key: header.key,
|
|
191
192
|
manifest,
|
|
192
193
|
keyPair,
|
|
194
|
+
frozen: false,
|
|
193
195
|
discoveryKey,
|
|
194
196
|
userData: opts.userData || [],
|
|
195
197
|
alias: opts.alias || null
|
|
@@ -494,6 +496,11 @@ module.exports = class Core {
|
|
|
494
496
|
return false
|
|
495
497
|
}
|
|
496
498
|
|
|
499
|
+
// sanity check -> no manifest, no way to verify
|
|
500
|
+
if (!this.header.manifest) {
|
|
501
|
+
return false
|
|
502
|
+
}
|
|
503
|
+
|
|
497
504
|
const batch = MerkleTree.verifyFullyRemote(this.state, proof)
|
|
498
505
|
|
|
499
506
|
try {
|
|
@@ -502,24 +509,57 @@ module.exports = class Core {
|
|
|
502
509
|
return true
|
|
503
510
|
}
|
|
504
511
|
|
|
512
|
+
const roots = await MerkleTree.getRootsFromStorage(this.storage, proof.upgrade.length)
|
|
513
|
+
const remoteTreeHash = crypto.tree(proof.upgrade.nodes)
|
|
514
|
+
const localTreeHash = crypto.tree(roots)
|
|
515
|
+
|
|
516
|
+
try {
|
|
517
|
+
const rx = this.state.storage.read()
|
|
518
|
+
const treeProofPromise = MerkleTree.proof(this.state, rx, {
|
|
519
|
+
block: null,
|
|
520
|
+
hash: null,
|
|
521
|
+
seek: null,
|
|
522
|
+
upgrade: {
|
|
523
|
+
start: 0,
|
|
524
|
+
length: proof.upgrade.length
|
|
525
|
+
}
|
|
526
|
+
})
|
|
527
|
+
|
|
528
|
+
rx.tryFlush()
|
|
529
|
+
|
|
530
|
+
const treeProof = await treeProofPromise
|
|
531
|
+
|
|
532
|
+
const verifyBatch = MerkleTree.verifyFullyRemote(this.state, await treeProof.settle())
|
|
533
|
+
this._verifyBatchUpgrade(verifyBatch, this.header.manifest)
|
|
534
|
+
} catch {
|
|
535
|
+
return true
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// both proofs are valid, now check if they forked
|
|
539
|
+
if (b4a.equals(localTreeHash, remoteTreeHash)) return false
|
|
540
|
+
|
|
505
541
|
await this.state.mutex.lock()
|
|
506
542
|
|
|
507
543
|
try {
|
|
508
544
|
const tx = this.state.createWriteBatch()
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
545
|
+
|
|
546
|
+
this.header.frozen = true
|
|
547
|
+
|
|
548
|
+
tx.setAuth({
|
|
549
|
+
key: this.header.key,
|
|
550
|
+
discoveryKey: this.discoveryKey,
|
|
551
|
+
manifest: this.header.manifest,
|
|
552
|
+
keyPair: this.header.keyPair,
|
|
553
|
+
frozen: true
|
|
554
|
+
})
|
|
512
555
|
|
|
513
556
|
await this.state.flush()
|
|
514
557
|
} finally {
|
|
515
558
|
this.state.mutex.unlock()
|
|
516
559
|
}
|
|
517
560
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
if (b4a.equals(localTreeHash, remoteTreeHash)) return false
|
|
522
|
-
|
|
561
|
+
// tmp log so we can see these
|
|
562
|
+
console.log('[hypercore] conflict detected in ' + this.id + ' (writable=' + !!this.header.keyPair + ',quorum=' + this.header.manifest.quorum + ')')
|
|
523
563
|
await this._onconflict(proof)
|
|
524
564
|
return true
|
|
525
565
|
}
|
package/lib/merkle-tree.js
CHANGED
|
@@ -148,7 +148,7 @@ class MerkleTreeBatch {
|
|
|
148
148
|
return caps.treeSignableCompat(this.hash(), this.length, this.fork, noHeader)
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
get (index
|
|
151
|
+
get (index) {
|
|
152
152
|
if (index >= this.length * 2) {
|
|
153
153
|
return null
|
|
154
154
|
}
|
|
@@ -157,7 +157,7 @@ class MerkleTreeBatch {
|
|
|
157
157
|
if (n.index === index) return n
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
return
|
|
160
|
+
return getTreeNodeFromStorage(this.session.storage, index)
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// deprecated, use sssion proof instead
|
|
@@ -267,9 +267,9 @@ class MerkleTreeBatch {
|
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
byteRange (index) {
|
|
270
|
-
const
|
|
271
|
-
const range = getByteRange(this, index,
|
|
272
|
-
|
|
270
|
+
const rx = this.storage.read()
|
|
271
|
+
const range = getByteRange(this, index, rx)
|
|
272
|
+
rx.tryFlush()
|
|
273
273
|
|
|
274
274
|
return range
|
|
275
275
|
}
|
|
@@ -277,9 +277,9 @@ class MerkleTreeBatch {
|
|
|
277
277
|
byteOffset (index) {
|
|
278
278
|
if (index === 2 * this.length) return this.byteLength
|
|
279
279
|
|
|
280
|
-
const
|
|
281
|
-
const offset = getByteOffset(this, index,
|
|
282
|
-
|
|
280
|
+
const rx = this.storage.read()
|
|
281
|
+
const offset = getByteOffset(this, index, rx)
|
|
282
|
+
rx.tryFlush()
|
|
283
283
|
|
|
284
284
|
return offset
|
|
285
285
|
}
|
|
@@ -347,7 +347,7 @@ class ReorgBatch extends MerkleTreeBatch {
|
|
|
347
347
|
const left = n.get(ite.leftChild())
|
|
348
348
|
if (!left) break
|
|
349
349
|
|
|
350
|
-
const existing = await
|
|
350
|
+
const existing = await getTreeNodeFromStorage(this.session.storage, left.index)
|
|
351
351
|
if (!existing || !b4a.equals(existing.hash, left.hash)) {
|
|
352
352
|
diff = left
|
|
353
353
|
} else {
|
|
@@ -413,7 +413,7 @@ class ByteSeeker {
|
|
|
413
413
|
const ite = flat.iterator(node.index)
|
|
414
414
|
|
|
415
415
|
while ((ite.index & 1) !== 0) {
|
|
416
|
-
const l = await
|
|
416
|
+
const l = await getTreeNodeFromStorage(this.session.storage, ite.leftChild())
|
|
417
417
|
|
|
418
418
|
if (l) {
|
|
419
419
|
const size = getUnpaddedSize(l, this.padding, ite)
|
|
@@ -530,51 +530,27 @@ class MerkleTree {
|
|
|
530
530
|
static getRootsFromStorage (storage, length) {
|
|
531
531
|
const indexes = flat.fullRoots(2 * length)
|
|
532
532
|
const roots = new Array(indexes.length)
|
|
533
|
-
const
|
|
533
|
+
const rx = storage.read()
|
|
534
534
|
|
|
535
535
|
for (let i = 0; i < indexes.length; i++) {
|
|
536
|
-
roots[i] =
|
|
536
|
+
roots[i] = getTreeNodeOrError(rx, indexes[i])
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
-
|
|
539
|
+
rx.tryFlush()
|
|
540
540
|
|
|
541
541
|
return Promise.all(roots)
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
-
static getNeededNodes (session, length, start, end) {
|
|
545
|
-
const nodes = new Map()
|
|
546
|
-
const head = length * 2
|
|
547
|
-
|
|
548
|
-
for (let i = start; i < end; i++) {
|
|
549
|
-
const ite = flat.iterator(i * 2)
|
|
550
|
-
|
|
551
|
-
while (true) {
|
|
552
|
-
if (nodes.has(ite.index)) break
|
|
553
|
-
nodes.set(ite.index, this.get(session, ite.index, true))
|
|
554
|
-
|
|
555
|
-
const sibling = ite.sibling()
|
|
556
|
-
|
|
557
|
-
ite.parent()
|
|
558
|
-
if (ite.contains(head)) break
|
|
559
|
-
|
|
560
|
-
if (nodes.has(sibling)) break
|
|
561
|
-
nodes.set(sibling, this.get(session, sibling, true))
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
return Promise.all([...nodes.values()])
|
|
566
|
-
}
|
|
567
|
-
|
|
568
544
|
static async upgradeable (session, length) {
|
|
569
545
|
const indexes = flat.fullRoots(2 * length)
|
|
570
546
|
const roots = new Array(indexes.length)
|
|
571
|
-
const
|
|
547
|
+
const rx = session.storage.read()
|
|
572
548
|
|
|
573
549
|
for (let i = 0; i < indexes.length; i++) {
|
|
574
|
-
roots[i] =
|
|
550
|
+
roots[i] = rx.getTreeNode(indexes[i])
|
|
575
551
|
}
|
|
576
552
|
|
|
577
|
-
|
|
553
|
+
rx.tryFlush()
|
|
578
554
|
|
|
579
555
|
for (const node of await Promise.all(roots)) {
|
|
580
556
|
if (node === null) return false
|
|
@@ -587,10 +563,8 @@ class MerkleTree {
|
|
|
587
563
|
return new ByteSeeker(session, bytes, padding)
|
|
588
564
|
}
|
|
589
565
|
|
|
590
|
-
static get (session, index
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
return getTreeNode(session.storage, index, error)
|
|
566
|
+
static get (session, index) {
|
|
567
|
+
return getTreeNodeFromStorage(session.storage, index)
|
|
594
568
|
}
|
|
595
569
|
|
|
596
570
|
static async truncate (session, length, batch, fork = batch.fork) {
|
|
@@ -602,7 +576,7 @@ class MerkleTree {
|
|
|
602
576
|
if (i < batch.roots.length && batch.roots[i].index === root) continue
|
|
603
577
|
|
|
604
578
|
while (batch.roots.length > i) batch.roots.pop()
|
|
605
|
-
batch.roots.push(unslabNode(await
|
|
579
|
+
batch.roots.push(unslabNode(await getTreeNodeFromStorageOrError(session.storage, root)))
|
|
606
580
|
}
|
|
607
581
|
|
|
608
582
|
while (batch.roots.length > fullRoots.length) {
|
|
@@ -630,7 +604,7 @@ class MerkleTree {
|
|
|
630
604
|
}
|
|
631
605
|
|
|
632
606
|
for (const root of batch.roots) {
|
|
633
|
-
const existing = await
|
|
607
|
+
const existing = await getTreeNodeFromStorage(session.storage, root.index)
|
|
634
608
|
if (existing && b4a.equals(existing.hash, root.hash)) continue
|
|
635
609
|
batch._updateDiffRoot(root)
|
|
636
610
|
break
|
|
@@ -679,7 +653,7 @@ class MerkleTree {
|
|
|
679
653
|
}
|
|
680
654
|
|
|
681
655
|
if (unverified) {
|
|
682
|
-
const verified = await
|
|
656
|
+
const verified = await getTreeNodeFromStorageOrError(session.storage, unverified.index)
|
|
683
657
|
if (!b4a.equals(verified.hash, unverified.hash)) {
|
|
684
658
|
throw INVALID_CHECKSUM('Invalid checksum at node ' + unverified.index)
|
|
685
659
|
}
|
|
@@ -730,16 +704,16 @@ module.exports = {
|
|
|
730
704
|
MerkleTree
|
|
731
705
|
}
|
|
732
706
|
|
|
733
|
-
async function getNodeSize (index,
|
|
734
|
-
return (await
|
|
707
|
+
async function getNodeSize (index, rx) {
|
|
708
|
+
return (await getTreeNodeOrError(rx, index)).size
|
|
735
709
|
}
|
|
736
710
|
|
|
737
|
-
async function getByteOffsetSession (session, index,
|
|
711
|
+
async function getByteOffsetSession (session, index, rx) {
|
|
738
712
|
if (index === 2 * session.length) return session.byteLength
|
|
739
713
|
|
|
740
|
-
const treeNodes =
|
|
714
|
+
const treeNodes = rx === null
|
|
741
715
|
? await getByteOffsetBatchFlush(session.roots, index, session.storage.read())
|
|
742
|
-
: await getByteOffsetBatch(session.roots, index,
|
|
716
|
+
: await getByteOffsetBatch(session.roots, index, rx)
|
|
743
717
|
|
|
744
718
|
let offset = 0
|
|
745
719
|
for (const node of treeNodes) offset += node.size
|
|
@@ -747,10 +721,10 @@ async function getByteOffsetSession (session, index, readBatch) {
|
|
|
747
721
|
return offset
|
|
748
722
|
}
|
|
749
723
|
|
|
750
|
-
async function getByteOffset (tree, index,
|
|
724
|
+
async function getByteOffset (tree, index, rx) {
|
|
751
725
|
if (index === 2 * tree.length) return tree.byteLength
|
|
752
726
|
|
|
753
|
-
const treeNodes = await getByteOffsetBatch(tree.roots, index,
|
|
727
|
+
const treeNodes = await getByteOffsetBatch(tree.roots, index, rx)
|
|
754
728
|
|
|
755
729
|
let offset = 0
|
|
756
730
|
for (const node of treeNodes) offset += node.size
|
|
@@ -758,13 +732,13 @@ async function getByteOffset (tree, index, readBatch) {
|
|
|
758
732
|
return offset
|
|
759
733
|
}
|
|
760
734
|
|
|
761
|
-
function getByteOffsetBatchFlush (roots, index,
|
|
762
|
-
const treeNodes = getByteOffsetBatch(roots, index,
|
|
763
|
-
|
|
735
|
+
function getByteOffsetBatchFlush (roots, index, rx) {
|
|
736
|
+
const treeNodes = getByteOffsetBatch(roots, index, rx)
|
|
737
|
+
rx.tryFlush()
|
|
764
738
|
return treeNodes
|
|
765
739
|
}
|
|
766
740
|
|
|
767
|
-
function getByteOffsetBatch (roots, index,
|
|
741
|
+
function getByteOffsetBatch (roots, index, rx) {
|
|
768
742
|
if ((index & 1) === 1) index = flat.leftSpan(index)
|
|
769
743
|
|
|
770
744
|
let head = 0
|
|
@@ -785,7 +759,7 @@ function getByteOffsetBatch (roots, index, readBatch) {
|
|
|
785
759
|
if (index < ite.index) {
|
|
786
760
|
ite.leftChild()
|
|
787
761
|
} else {
|
|
788
|
-
promises.push(
|
|
762
|
+
promises.push(getTreeNodeOrError(rx, ite.leftChild()))
|
|
789
763
|
ite.sibling()
|
|
790
764
|
}
|
|
791
765
|
}
|
|
@@ -796,14 +770,14 @@ function getByteOffsetBatch (roots, index, readBatch) {
|
|
|
796
770
|
throw ASSERTION('Failed to find offset')
|
|
797
771
|
}
|
|
798
772
|
|
|
799
|
-
function getByteRange (tree, index,
|
|
773
|
+
function getByteRange (tree, index, rx) {
|
|
800
774
|
const head = 2 * tree.length
|
|
801
775
|
if (((index & 1) === 0 ? index : flat.rightSpan(index)) >= head) {
|
|
802
776
|
throw BAD_ARGUMENT('Index is out of bounds')
|
|
803
777
|
}
|
|
804
778
|
|
|
805
|
-
const offset = getByteOffset(tree, index,
|
|
806
|
-
const size = getNodeSize(index,
|
|
779
|
+
const offset = getByteOffset(tree, index, rx)
|
|
780
|
+
const size = getNodeSize(index, rx)
|
|
807
781
|
|
|
808
782
|
return Promise.all([offset, size])
|
|
809
783
|
}
|
|
@@ -935,8 +909,7 @@ async function seekFromHead (session, head, bytes, padding) {
|
|
|
935
909
|
|
|
936
910
|
for (let i = 0; i < roots.length; i++) {
|
|
937
911
|
const root = roots[i]
|
|
938
|
-
const node = await
|
|
939
|
-
if (node === null) throw new Error('Tree node missing')
|
|
912
|
+
const node = await getTreeNodeFromStorage(session.storage, root)
|
|
940
913
|
const size = getUnpaddedSize(node, padding, null)
|
|
941
914
|
|
|
942
915
|
if (bytes === size) return root
|
|
@@ -959,7 +932,7 @@ async function seekTrustedTree (session, root, bytes, padding) {
|
|
|
959
932
|
const ite = flat.iterator(root)
|
|
960
933
|
|
|
961
934
|
while ((ite.index & 1) !== 0) {
|
|
962
|
-
const l = await
|
|
935
|
+
const l = await getTreeNodeFromStorage(session.storage, ite.leftChild())
|
|
963
936
|
|
|
964
937
|
if (l) {
|
|
965
938
|
const size = getUnpaddedSize(l, padding, ite)
|
|
@@ -986,8 +959,7 @@ async function seekUntrustedTree (session, root, bytes, padding) {
|
|
|
986
959
|
|
|
987
960
|
bytes -= offset
|
|
988
961
|
|
|
989
|
-
const node = await
|
|
990
|
-
if (node === null) throw new Error('Tree node missing')
|
|
962
|
+
const node = await getTreeNodeFromStorageOrError(session.storage, root)
|
|
991
963
|
|
|
992
964
|
if (getUnpaddedSize(node, padding, null) <= bytes) throw INVALID_OPERATION('Invalid seek')
|
|
993
965
|
|
|
@@ -998,41 +970,41 @@ async function seekUntrustedTree (session, root, bytes, padding) {
|
|
|
998
970
|
// Note, that all these methods are sync as we can statically infer which nodes
|
|
999
971
|
// are needed for the remote to verify given they arguments they passed us
|
|
1000
972
|
|
|
1001
|
-
function seekProof (session,
|
|
973
|
+
function seekProof (session, rx, seekRoot, root, p) {
|
|
1002
974
|
const ite = flat.iterator(seekRoot)
|
|
1003
975
|
|
|
1004
976
|
p.seek = []
|
|
1005
|
-
p.seek.push(
|
|
977
|
+
p.seek.push(getTreeNodeOrError(rx, ite.index))
|
|
1006
978
|
|
|
1007
979
|
while (ite.index !== root) {
|
|
1008
980
|
ite.sibling()
|
|
1009
|
-
p.seek.push(
|
|
981
|
+
p.seek.push(getTreeNodeOrError(rx, ite.index))
|
|
1010
982
|
ite.parent()
|
|
1011
983
|
}
|
|
1012
984
|
}
|
|
1013
985
|
|
|
1014
|
-
function blockAndSeekProof (session,
|
|
1015
|
-
if (!node) return seekProof(session,
|
|
986
|
+
function blockAndSeekProof (session, rx, node, seek, seekRoot, root, p) {
|
|
987
|
+
if (!node) return seekProof(session, rx, seekRoot, root, p)
|
|
1016
988
|
|
|
1017
989
|
const ite = flat.iterator(node.index)
|
|
1018
990
|
|
|
1019
991
|
p.node = []
|
|
1020
|
-
if (!node.value) p.node.push(
|
|
992
|
+
if (!node.value) p.node.push(getTreeNodeOrError(rx, ite.index))
|
|
1021
993
|
|
|
1022
994
|
while (ite.index !== root) {
|
|
1023
995
|
ite.sibling()
|
|
1024
996
|
|
|
1025
997
|
if (seek && ite.contains(seekRoot) && ite.index !== seekRoot) {
|
|
1026
|
-
seekProof(session,
|
|
998
|
+
seekProof(session, rx, seekRoot, ite.index, p)
|
|
1027
999
|
} else {
|
|
1028
|
-
p.node.push(
|
|
1000
|
+
p.node.push(getTreeNodeOrError(rx, ite.index))
|
|
1029
1001
|
}
|
|
1030
1002
|
|
|
1031
1003
|
ite.parent()
|
|
1032
1004
|
}
|
|
1033
1005
|
}
|
|
1034
1006
|
|
|
1035
|
-
function upgradeProof (session,
|
|
1007
|
+
function upgradeProof (session, rx, node, seek, from, to, subTree, p) {
|
|
1036
1008
|
if (from === 0) p.upgrade = []
|
|
1037
1009
|
|
|
1038
1010
|
for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
|
|
@@ -1052,9 +1024,9 @@ function upgradeProof (session, batch, node, seek, from, to, subTree, p) {
|
|
|
1052
1024
|
ite.sibling()
|
|
1053
1025
|
if (ite.index > target) {
|
|
1054
1026
|
if (p.node === null && p.seek === null && ite.contains(subTree)) {
|
|
1055
|
-
blockAndSeekProof(session,
|
|
1027
|
+
blockAndSeekProof(session, rx, node, seek, subTree, ite.index, p)
|
|
1056
1028
|
} else {
|
|
1057
|
-
p.upgrade.push(
|
|
1029
|
+
p.upgrade.push(getTreeNodeOrError(rx, ite.index))
|
|
1058
1030
|
}
|
|
1059
1031
|
}
|
|
1060
1032
|
ite.parent()
|
|
@@ -1070,16 +1042,16 @@ function upgradeProof (session, batch, node, seek, from, to, subTree, p) {
|
|
|
1070
1042
|
// if the subtree included is a child of this tree, include that one
|
|
1071
1043
|
// instead of a dup node
|
|
1072
1044
|
if (p.node === null && p.seek === null && ite.contains(subTree)) {
|
|
1073
|
-
blockAndSeekProof(session,
|
|
1045
|
+
blockAndSeekProof(session, rx, node, seek, subTree, ite.index, p)
|
|
1074
1046
|
continue
|
|
1075
1047
|
}
|
|
1076
1048
|
|
|
1077
1049
|
// add root (can be optimised since the root might be in tree.roots)
|
|
1078
|
-
p.upgrade.push(
|
|
1050
|
+
p.upgrade.push(getTreeNodeOrError(rx, ite.index))
|
|
1079
1051
|
}
|
|
1080
1052
|
}
|
|
1081
1053
|
|
|
1082
|
-
function additionalUpgradeProof (session,
|
|
1054
|
+
function additionalUpgradeProof (session, rx, from, to, p) {
|
|
1083
1055
|
if (from === 0) p.additionalUpgrade = []
|
|
1084
1056
|
|
|
1085
1057
|
for (const ite = flat.iterator(0); ite.fullRoot(to); ite.nextTree()) {
|
|
@@ -1098,7 +1070,7 @@ function additionalUpgradeProof (session, batch, from, to, p) {
|
|
|
1098
1070
|
while (ite.index !== root) {
|
|
1099
1071
|
ite.sibling()
|
|
1100
1072
|
if (ite.index > target) {
|
|
1101
|
-
p.additionalUpgrade.push(
|
|
1073
|
+
p.additionalUpgrade.push(getTreeNodeOrError(rx, ite.index))
|
|
1102
1074
|
}
|
|
1103
1075
|
ite.parent()
|
|
1104
1076
|
}
|
|
@@ -1111,7 +1083,7 @@ function additionalUpgradeProof (session, batch, from, to, p) {
|
|
|
1111
1083
|
}
|
|
1112
1084
|
|
|
1113
1085
|
// add root (can be optimised since the root is in tree.roots)
|
|
1114
|
-
p.additionalUpgrade.push(
|
|
1086
|
+
p.additionalUpgrade.push(getTreeNodeOrError(rx, ite.index))
|
|
1115
1087
|
}
|
|
1116
1088
|
}
|
|
1117
1089
|
|
|
@@ -1163,17 +1135,30 @@ function normalizeIndexed (block, hash) {
|
|
|
1163
1135
|
return null
|
|
1164
1136
|
}
|
|
1165
1137
|
|
|
1166
|
-
function
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1138
|
+
async function getTreeNodeOrError (rx, index) {
|
|
1139
|
+
const node = await rx.getTreeNode(index)
|
|
1140
|
+
if (node === null) throw INVALID_OPERATION('Expected tree node ' + index + ' from storage, got (nil)')
|
|
1141
|
+
return node
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
function getTreeNodeFromStorageOrError (storage, index) {
|
|
1145
|
+
const rx = storage.read()
|
|
1146
|
+
const p = getTreeNodeOrError(rx, index)
|
|
1147
|
+
rx.tryFlush()
|
|
1148
|
+
return p
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
function getTreeNodeFromStorage (storage, index) {
|
|
1152
|
+
const rx = storage.read()
|
|
1153
|
+
const node = rx.getTreeNode(index)
|
|
1154
|
+
rx.tryFlush()
|
|
1170
1155
|
return node
|
|
1171
1156
|
}
|
|
1172
1157
|
|
|
1173
1158
|
function hasTreeNode (storage, index) {
|
|
1174
|
-
const
|
|
1175
|
-
const has =
|
|
1176
|
-
|
|
1159
|
+
const rx = storage.read()
|
|
1160
|
+
const has = rx.hasTreeNode(index)
|
|
1161
|
+
rx.tryFlush()
|
|
1177
1162
|
return has
|
|
1178
1163
|
}
|
|
1179
1164
|
|
|
@@ -1197,7 +1182,7 @@ async function settleProof (p) {
|
|
|
1197
1182
|
}
|
|
1198
1183
|
|
|
1199
1184
|
// tree can be either the merkle tree or a merkle tree batch
|
|
1200
|
-
async function generateProof (session,
|
|
1185
|
+
async function generateProof (session, rx, block, hash, seek, upgrade) {
|
|
1201
1186
|
// Important that this does not throw inbetween making the promise arrays
|
|
1202
1187
|
// and finalise being called, otherwise there will be lingering promises in the background
|
|
1203
1188
|
|
|
@@ -1228,14 +1213,14 @@ async function generateProof (session, readBatch, block, hash, seek, upgrade) {
|
|
|
1228
1213
|
if (node !== null && (!upgrade || node.lastIndex < upgrade.start)) {
|
|
1229
1214
|
subTree = nodesToRoot(node.index, node.nodes, to)
|
|
1230
1215
|
const seekRoot = seek ? await seekUntrustedTree(session, subTree, seek.bytes, seek.padding) : head
|
|
1231
|
-
blockAndSeekProof(session,
|
|
1216
|
+
blockAndSeekProof(session, rx, node, seek, seekRoot, subTree, p.pending)
|
|
1232
1217
|
} else if ((node || seek) && upgrade) {
|
|
1233
1218
|
subTree = seek ? await seekFromHead(session, to, seek.bytes, seek.padding) : node.index
|
|
1234
1219
|
}
|
|
1235
1220
|
|
|
1236
1221
|
if (upgrade) {
|
|
1237
|
-
upgradeProof(session,
|
|
1238
|
-
if (head > to) additionalUpgradeProof(session,
|
|
1222
|
+
upgradeProof(session, rx, node, seek, from, to, subTree, p.pending)
|
|
1223
|
+
if (head > to) additionalUpgradeProof(session, rx, to, head, p.pending)
|
|
1239
1224
|
}
|
|
1240
1225
|
|
|
1241
1226
|
return p
|
package/lib/replicator.js
CHANGED
|
@@ -475,6 +475,8 @@ class Peer {
|
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
broadcastRange (start, length, drop) {
|
|
478
|
+
if (!this.isActive()) return
|
|
479
|
+
|
|
478
480
|
if (drop) this._unclearLocalRange(start, length)
|
|
479
481
|
else this._clearLocalRange(start, length)
|
|
480
482
|
|
|
@@ -779,6 +781,10 @@ class Peer {
|
|
|
779
781
|
// sync from now on, so safe to delete from the map
|
|
780
782
|
this.remoteRequests.delete(req.msg.id)
|
|
781
783
|
|
|
784
|
+
if (!this.isActive() && proof.block !== null) {
|
|
785
|
+
return
|
|
786
|
+
}
|
|
787
|
+
|
|
782
788
|
if (proof === null) {
|
|
783
789
|
if (req.msg.manifest && this.core.header.manifest) {
|
|
784
790
|
const manifest = this.core.header.manifest
|
|
@@ -1389,7 +1395,7 @@ class Peer {
|
|
|
1389
1395
|
}
|
|
1390
1396
|
|
|
1391
1397
|
isActive () {
|
|
1392
|
-
if (this.paused || this.removed) return false
|
|
1398
|
+
if (this.paused || this.removed || this.core.header.frozen) return false
|
|
1393
1399
|
return true
|
|
1394
1400
|
}
|
|
1395
1401
|
|
|
@@ -2120,6 +2126,8 @@ module.exports = class Replicator {
|
|
|
2120
2126
|
}
|
|
2121
2127
|
|
|
2122
2128
|
_onwant (peer, start, length) {
|
|
2129
|
+
if (!peer.isActive()) return
|
|
2130
|
+
|
|
2123
2131
|
const contig = Math.min(this.core.state.length, this.core.header.hints.contiguousLength)
|
|
2124
2132
|
|
|
2125
2133
|
if (start + length < contig || (this.core.state.length === contig)) {
|