hypercore 10.31.4 → 10.31.6
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 +2 -3
- package/lib/bitfield.js +11 -3
- package/lib/compat.js +2 -1
- package/lib/core.js +1 -1
- package/lib/remote-bitfield.js +53 -3
- package/lib/replicator.js +116 -61
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -658,7 +658,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
658
658
|
const appended = (status & 0b0001) !== 0
|
|
659
659
|
|
|
660
660
|
if (truncated) {
|
|
661
|
-
this.replicator.ontruncate(bitfield.start)
|
|
661
|
+
this.replicator.ontruncate(bitfield.start, bitfield.length)
|
|
662
662
|
}
|
|
663
663
|
|
|
664
664
|
if ((status & 0b10011) !== 0) {
|
|
@@ -985,8 +985,7 @@ module.exports = class Hypercore extends EventEmitter {
|
|
|
985
985
|
} = typeof opts === 'number' ? { fork: opts } : opts
|
|
986
986
|
|
|
987
987
|
const writable = !this._readonly && !!(signature || (keyPair && keyPair.secretKey))
|
|
988
|
-
|
|
989
|
-
if (writable === false) throw SESSION_NOT_WRITABLE()
|
|
988
|
+
if (writable === false && (newLength > 0 || fork !== this.core.tree.fork)) throw SESSION_NOT_WRITABLE()
|
|
990
989
|
|
|
991
990
|
await this.core.truncate(newLength, fork, { keyPair, signature })
|
|
992
991
|
|
package/lib/bitfield.js
CHANGED
|
@@ -40,10 +40,10 @@ class BitfieldPage {
|
|
|
40
40
|
setRange (start, length, val) {
|
|
41
41
|
quickbit.fill(this.bitfield, val, start, start + length)
|
|
42
42
|
|
|
43
|
-
let i = Math.floor(start /
|
|
44
|
-
const n = i + Math.ceil(length /
|
|
43
|
+
let i = Math.floor(start / 128)
|
|
44
|
+
const n = i + Math.ceil(length / 128)
|
|
45
45
|
|
|
46
|
-
while (i < n) this.tree.update(this.offset * 8 + i++ *
|
|
46
|
+
while (i < n) this.tree.update(this.offset * 8 + i++ * 128)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
findFirst (val, position) {
|
|
@@ -213,6 +213,14 @@ module.exports = class Bitfield {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
getBitfield (index, length) {
|
|
217
|
+
const j = index & (BITS_PER_PAGE - 1)
|
|
218
|
+
const i = (index - j) / BITS_PER_PAGE
|
|
219
|
+
|
|
220
|
+
const p = this._pages.get(i)
|
|
221
|
+
return p || null
|
|
222
|
+
}
|
|
223
|
+
|
|
216
224
|
get (index) {
|
|
217
225
|
const j = index & (BITS_PER_PAGE - 1)
|
|
218
226
|
const i = (index - j) / BITS_PER_PAGE
|
package/lib/compat.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
let quickbit = require('quickbit-universal')
|
|
4
4
|
if (
|
|
5
5
|
typeof quickbit.findFirst !== 'function' ||
|
|
6
|
-
typeof quickbit.findLast !== 'function'
|
|
6
|
+
typeof quickbit.findLast !== 'function' ||
|
|
7
|
+
typeof quickbit.clear !== 'function'
|
|
7
8
|
) {
|
|
8
9
|
// This should always load the fallback from the locally installed version
|
|
9
10
|
quickbit = require('quickbit-universal/fallback')
|
package/lib/core.js
CHANGED
|
@@ -375,7 +375,7 @@ module.exports = class Core {
|
|
|
375
375
|
|
|
376
376
|
try {
|
|
377
377
|
const batch = await this.tree.truncate(length, fork)
|
|
378
|
-
batch.signature = signature || this.verifier.sign(batch, keyPair)
|
|
378
|
+
if (length > 0) batch.signature = signature || this.verifier.sign(batch, keyPair)
|
|
379
379
|
await this._truncate(batch, null)
|
|
380
380
|
} finally {
|
|
381
381
|
this.truncating--
|
package/lib/remote-bitfield.js
CHANGED
|
@@ -35,10 +35,10 @@ class RemoteBitfieldPage {
|
|
|
35
35
|
setRange (start, length, val) {
|
|
36
36
|
quickbit.fill(this.bitfield, val, start, start + length)
|
|
37
37
|
|
|
38
|
-
let i = Math.floor(start /
|
|
39
|
-
const n = i + Math.ceil(length /
|
|
38
|
+
let i = Math.floor(start / 128)
|
|
39
|
+
const n = i + Math.ceil(length / 128)
|
|
40
40
|
|
|
41
|
-
while (i < n) this.tree.update(this.offset * 8 + i++ *
|
|
41
|
+
while (i < n) this.tree.update(this.offset * 8 + i++ * 128)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
findFirst (val, position) {
|
|
@@ -51,6 +51,11 @@ class RemoteBitfieldPage {
|
|
|
51
51
|
|
|
52
52
|
insert (start, bitfield) {
|
|
53
53
|
this.bitfield.set(bitfield, start / 32)
|
|
54
|
+
this.segment.refresh()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
clear (start, bitfield) {
|
|
58
|
+
quickbit.clear(this.bitfield, { field: bitfield, offset: start })
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
61
|
|
|
@@ -66,6 +71,10 @@ class RemoteBitfieldSegment {
|
|
|
66
71
|
return this.tree.chunks
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
refresh () {
|
|
75
|
+
this.tree = quickbit.Index.from(this.tree.chunks, BYTES_PER_SEGMENT)
|
|
76
|
+
}
|
|
77
|
+
|
|
69
78
|
add (page) {
|
|
70
79
|
this.pages[page.index - this.index * PAGES_PER_SEGMENT] = page
|
|
71
80
|
|
|
@@ -138,6 +147,14 @@ module.exports = class RemoteBitfield {
|
|
|
138
147
|
this._segments = new BigSparseArray()
|
|
139
148
|
}
|
|
140
149
|
|
|
150
|
+
getBitfield (index) {
|
|
151
|
+
const j = index & (BITS_PER_PAGE - 1)
|
|
152
|
+
const i = (index - j) / BITS_PER_PAGE
|
|
153
|
+
|
|
154
|
+
const p = this._pages.get(i)
|
|
155
|
+
return p || null
|
|
156
|
+
}
|
|
157
|
+
|
|
141
158
|
get (index) {
|
|
142
159
|
const j = index & (BITS_PER_PAGE - 1)
|
|
143
160
|
const i = (index - j) / BITS_PER_PAGE
|
|
@@ -278,4 +295,37 @@ module.exports = class RemoteBitfield {
|
|
|
278
295
|
|
|
279
296
|
return true
|
|
280
297
|
}
|
|
298
|
+
|
|
299
|
+
clear (start, bitfield) {
|
|
300
|
+
if (start % 32 !== 0) return false
|
|
301
|
+
|
|
302
|
+
let length = bitfield.byteLength * 8
|
|
303
|
+
|
|
304
|
+
let j = start & (BITS_PER_PAGE - 1)
|
|
305
|
+
let i = (start - j) / BITS_PER_PAGE
|
|
306
|
+
|
|
307
|
+
while (length > 0) {
|
|
308
|
+
let p = this._pages.get(i)
|
|
309
|
+
|
|
310
|
+
if (!p) {
|
|
311
|
+
const k = Math.floor(i / PAGES_PER_SEGMENT)
|
|
312
|
+
const s = this._segments.get(k) || this._segments.set(k, new RemoteBitfieldSegment(k))
|
|
313
|
+
|
|
314
|
+
p = this._pages.set(i, new RemoteBitfieldPage(i, new Uint32Array(WORDS_PER_PAGE), s))
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const end = Math.min(j + length, BITS_PER_PAGE)
|
|
318
|
+
const range = end - j
|
|
319
|
+
|
|
320
|
+
p.clear(j, bitfield.subarray(0, range / 32))
|
|
321
|
+
|
|
322
|
+
bitfield = bitfield.subarray(range / 32)
|
|
323
|
+
|
|
324
|
+
j = 0
|
|
325
|
+
i++
|
|
326
|
+
length -= range
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return true
|
|
330
|
+
}
|
|
281
331
|
}
|
package/lib/replicator.js
CHANGED
|
@@ -310,7 +310,7 @@ class Peer {
|
|
|
310
310
|
|
|
311
311
|
this.remoteOpened = false
|
|
312
312
|
this.remoteBitfield = new RemoteBitfield()
|
|
313
|
-
this.
|
|
313
|
+
this.missingBlocks = new RemoteBitfield()
|
|
314
314
|
|
|
315
315
|
this.remoteFork = 0
|
|
316
316
|
this.remoteLength = 0
|
|
@@ -350,7 +350,9 @@ class Peer {
|
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
broadcastRange (start, length, drop) {
|
|
353
|
-
if (drop) this.
|
|
353
|
+
if (drop) this._unclearLocalRange(start, length)
|
|
354
|
+
else this._clearLocalRange(start, length)
|
|
355
|
+
|
|
354
356
|
this.wireRange.send({
|
|
355
357
|
drop,
|
|
356
358
|
start,
|
|
@@ -699,6 +701,7 @@ class Peer {
|
|
|
699
701
|
// might be a fork, verify
|
|
700
702
|
this._checkIfConflict()
|
|
701
703
|
}
|
|
704
|
+
|
|
702
705
|
this.replicator._onnodata(this, req)
|
|
703
706
|
this.replicator.oninvalid(err, req, data, this)
|
|
704
707
|
return
|
|
@@ -732,10 +735,60 @@ class Peer {
|
|
|
732
735
|
}
|
|
733
736
|
|
|
734
737
|
onbitfield ({ start, bitfield }) {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
+
this.remoteBitfield.insert(start, bitfield)
|
|
739
|
+
this.missingBlocks.insert(start, bitfield)
|
|
740
|
+
this._clearLocalRange(start, bitfield.byteLength * 8)
|
|
741
|
+
this._update()
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
_clearLocalRange (start, length) {
|
|
745
|
+
if (length === 1) {
|
|
746
|
+
this.missingBlocks.set(start, false)
|
|
747
|
+
return
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const contig = Math.min(this.core.tree.length, this.core.header.hints.contiguousLength)
|
|
751
|
+
|
|
752
|
+
if (start < contig) {
|
|
753
|
+
const delta = contig - start
|
|
754
|
+
this.missingBlocks.setRange(start, delta)
|
|
755
|
+
start = contig
|
|
756
|
+
length -= delta
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
if ((start & 31) > 0) start -= (start & 31)
|
|
760
|
+
|
|
761
|
+
const end = start + Math.min(length, this.core.tree.length)
|
|
762
|
+
while (start < end) {
|
|
763
|
+
const local = this.core.bitfield.getBitfield(start)
|
|
764
|
+
|
|
765
|
+
if (local && local.bitfield) {
|
|
766
|
+
this.missingBlocks.clear(start, local.bitfield)
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
start += 32768
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
_unclearLocalRange (start, length) {
|
|
774
|
+
if (length === 1) {
|
|
775
|
+
this.missingBlocks.set(start, this.remoteBitfield.get(start))
|
|
776
|
+
return
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if ((start & 31) > 0) start -= (start & 31)
|
|
780
|
+
|
|
781
|
+
const end = start + Math.min(length, this.remoteLength)
|
|
782
|
+
while (start < end) {
|
|
783
|
+
const remote = this.remoteBitfield.getBitfield(start)
|
|
784
|
+
if (remote && remote.bitfield) {
|
|
785
|
+
this.missingBlocks.insert(start, remote.bitfield)
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
start += 2097152
|
|
738
789
|
}
|
|
790
|
+
|
|
791
|
+
this._clearLocalRange(start, length)
|
|
739
792
|
}
|
|
740
793
|
|
|
741
794
|
onrange ({ drop, start, length }) {
|
|
@@ -743,14 +796,15 @@ class Peer {
|
|
|
743
796
|
|
|
744
797
|
if (length === 1) {
|
|
745
798
|
this.remoteBitfield.setRange(start, length, has)
|
|
746
|
-
this.
|
|
799
|
+
this.missingBlocks.set(start, has && !this.core.bitfield.get(start))
|
|
747
800
|
} else {
|
|
748
801
|
const rangeStart = this.remoteBitfield.findFirst(!has, start)
|
|
749
802
|
const rangeLength = length - (rangeStart - start)
|
|
750
803
|
|
|
751
804
|
if (rangeLength > 0) {
|
|
752
805
|
this.remoteBitfield.setRange(rangeStart, rangeLength, has)
|
|
753
|
-
this.
|
|
806
|
+
this.missingBlocks.setRange(rangeStart, rangeLength, has)
|
|
807
|
+
if (has) this._clearLocalRange(rangeStart, rangeLength)
|
|
754
808
|
}
|
|
755
809
|
}
|
|
756
810
|
|
|
@@ -942,74 +996,73 @@ class Peer {
|
|
|
942
996
|
return true
|
|
943
997
|
}
|
|
944
998
|
|
|
945
|
-
|
|
946
|
-
|
|
999
|
+
_requestRangeBlock (index, length) {
|
|
1000
|
+
if (this.core.bitfield.get(index) === true || !this._hasTreeParent(index)) return false
|
|
947
1001
|
|
|
948
|
-
const
|
|
949
|
-
if (
|
|
1002
|
+
const b = this.replicator._blocks.add(index, PRIORITY.NORMAL)
|
|
1003
|
+
if (b.inflight.length > 0) return false
|
|
950
1004
|
|
|
951
|
-
const
|
|
952
|
-
const off = r.start + (r.linear ? 0 : Math.floor(Math.random() * len))
|
|
1005
|
+
const req = this._makeRequest(index >= length, b.priority)
|
|
953
1006
|
|
|
954
|
-
//
|
|
955
|
-
|
|
956
|
-
|
|
1007
|
+
// If the request cannot be satisfied, dealloc the block request if no one is subscribed to it
|
|
1008
|
+
if (req === null) {
|
|
1009
|
+
b.gc()
|
|
1010
|
+
return false
|
|
1011
|
+
}
|
|
957
1012
|
|
|
958
|
-
|
|
1013
|
+
req.block = { index, nodes: 0 }
|
|
959
1014
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
if (index >= end) index -= len
|
|
1015
|
+
b.inflight.push(req)
|
|
1016
|
+
this._send(req)
|
|
963
1017
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
wrapped++
|
|
970
|
-
index = this.skipList.findFirst(false, r.start)
|
|
971
|
-
if (index === -1 || index >= end) {
|
|
972
|
-
return false
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
}
|
|
1018
|
+
// Don't think this will ever happen, as the pending queue is drained before the range queue
|
|
1019
|
+
// but doesn't hurt to check this explicitly here also.
|
|
1020
|
+
if (b.queued) b.queued = false
|
|
1021
|
+
return true
|
|
1022
|
+
}
|
|
976
1023
|
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
continue
|
|
980
|
-
}
|
|
1024
|
+
_requestRange (r) {
|
|
1025
|
+
const { length, fork } = this.core.tree
|
|
981
1026
|
|
|
982
|
-
|
|
983
|
-
|
|
1027
|
+
if (r.blocks) {
|
|
1028
|
+
let min = -1
|
|
1029
|
+
let max = -1
|
|
1030
|
+
for (let i = r.start; i < r.end; i++) {
|
|
1031
|
+
const index = r.blocks[i]
|
|
1032
|
+
if (min === -1 || index < min) min = index
|
|
1033
|
+
if (max === -1 || index > max) max = index
|
|
1034
|
+
if (this.missingBlocks.get(index) === true && this._requestRangeBlock(index, length)) return true
|
|
984
1035
|
}
|
|
1036
|
+
if (min > -1) this._maybeWant(min, max - min)
|
|
1037
|
+
return false
|
|
1038
|
+
}
|
|
985
1039
|
|
|
986
|
-
|
|
1040
|
+
const end = Math.min(r.end === -1 ? this.remoteLength : r.end, this.remoteLength)
|
|
1041
|
+
if (end < r.start || fork !== this.remoteFork) return false
|
|
987
1042
|
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
continue
|
|
991
|
-
}
|
|
1043
|
+
const len = end - r.start
|
|
1044
|
+
const off = r.start + (r.linear ? 0 : Math.floor(Math.random() * len))
|
|
992
1045
|
|
|
993
|
-
|
|
1046
|
+
let i = off
|
|
994
1047
|
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
b.gc()
|
|
998
|
-
return false
|
|
999
|
-
}
|
|
1048
|
+
while (true) {
|
|
1049
|
+
i = this.missingBlocks.findFirst(true, i)
|
|
1000
1050
|
|
|
1001
|
-
|
|
1051
|
+
if (i === -1 || i >= end) break
|
|
1002
1052
|
|
|
1003
|
-
|
|
1053
|
+
if (this._requestRangeBlock(i, length)) return true
|
|
1054
|
+
i++
|
|
1055
|
+
}
|
|
1004
1056
|
|
|
1005
|
-
|
|
1006
|
-
this._send(req)
|
|
1057
|
+
i = r.start
|
|
1007
1058
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
if (b.queued) b.queued = false
|
|
1059
|
+
while (true) {
|
|
1060
|
+
i = this.missingBlocks.findFirst(true, i)
|
|
1011
1061
|
|
|
1012
|
-
|
|
1062
|
+
if (i === -1 || i >= off) break
|
|
1063
|
+
|
|
1064
|
+
if (this.core.bitfield.get(i) === false && this._hasTreeParent(i) && this._requestRangeBlock(i, length)) return true
|
|
1065
|
+
i++
|
|
1013
1066
|
}
|
|
1014
1067
|
|
|
1015
1068
|
this._maybeWant(r.start, len)
|
|
@@ -1197,7 +1250,7 @@ module.exports = class Replicator {
|
|
|
1197
1250
|
}
|
|
1198
1251
|
|
|
1199
1252
|
// Called externally when a truncation upgrade has been processed
|
|
1200
|
-
ontruncate (newLength) {
|
|
1253
|
+
ontruncate (newLength, truncated) {
|
|
1201
1254
|
const notify = []
|
|
1202
1255
|
|
|
1203
1256
|
for (const blk of this._blocks) {
|
|
@@ -1211,6 +1264,8 @@ module.exports = class Replicator {
|
|
|
1211
1264
|
blk.detach(r, SNAPSHOT_NOT_AVAILABLE())
|
|
1212
1265
|
}
|
|
1213
1266
|
}
|
|
1267
|
+
|
|
1268
|
+
for (const peer of this.peers) peer._unclearLocalRange(newLength, truncated)
|
|
1214
1269
|
}
|
|
1215
1270
|
|
|
1216
1271
|
// Called externally when a upgrade has been processed
|
|
@@ -1526,9 +1581,9 @@ module.exports = class Replicator {
|
|
|
1526
1581
|
|
|
1527
1582
|
if (b === null || removeInflight(b.inflight, req) === false) return
|
|
1528
1583
|
|
|
1529
|
-
if (isBlock && this.core.bitfield.get(index) === false) {
|
|
1530
|
-
|
|
1531
|
-
}
|
|
1584
|
+
// if (isBlock && this.core.bitfield.get(index) === false) {
|
|
1585
|
+
// for (const peer of this.peers) peer.skipList.set(index, false)
|
|
1586
|
+
// }
|
|
1532
1587
|
|
|
1533
1588
|
if (b.refs.length > 0 && isBlock === true) {
|
|
1534
1589
|
this._queueBlock(b)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore",
|
|
3
|
-
"version": "10.31.
|
|
3
|
+
"version": "10.31.6",
|
|
4
4
|
"description": "Hypercore is a secure, distributed append-only log",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"hypercore-id-encoding": "^1.2.0",
|
|
49
49
|
"is-options": "^1.0.1",
|
|
50
50
|
"protomux": "^3.5.0",
|
|
51
|
-
"quickbit-universal": "^2.
|
|
51
|
+
"quickbit-universal": "^2.2.0",
|
|
52
52
|
"random-access-file": "^4.0.0",
|
|
53
53
|
"random-array-iterator": "^1.0.0",
|
|
54
54
|
"safety-catch": "^1.0.1",
|