hypercore 10.35.1 → 10.35.3

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 CHANGED
@@ -60,7 +60,6 @@ module.exports = class Hypercore extends EventEmitter {
60
60
  this.crypto = opts.crypto || hypercoreCrypto
61
61
  this.core = null
62
62
  this.replicator = null
63
- this.inflightRange = opts.inflightRange || null
64
63
  this.encryption = null
65
64
  this.extensions = new Map()
66
65
  this.cache = createCache(opts.cache)
@@ -405,7 +404,7 @@ module.exports = class Hypercore extends EventEmitter {
405
404
  eagerUpgrade: true,
406
405
  notDownloadingLinger: opts.notDownloadingLinger,
407
406
  allowFork: opts.allowFork !== false,
408
- inflightRange: this.inflightRange,
407
+ inflightRange: opts.inflightRange,
409
408
  onpeerupdate: this._onpeerupdate.bind(this),
410
409
  onupload: this._onupload.bind(this),
411
410
  oninvalid: this._oninvalid.bind(this)
package/lib/bitfield.js CHANGED
@@ -213,6 +213,30 @@ module.exports = class Bitfield {
213
213
  }
214
214
  }
215
215
 
216
+ toBuffer (length) {
217
+ const pages = Math.ceil(length / BITS_PER_PAGE)
218
+ const buffer = b4a.allocUnsafe(pages * BYTES_PER_PAGE)
219
+
220
+ for (let i = 0; i < pages; i++) {
221
+ const page = this._pages.get(i)
222
+ const offset = i * BYTES_PER_PAGE
223
+
224
+ if (page) {
225
+ const buf = b4a.from(
226
+ page.bitfield.buffer,
227
+ page.bitfield.byteOffset,
228
+ page.bitfield.byteLength
229
+ )
230
+
231
+ buffer.set(buf, offset)
232
+ } else {
233
+ buffer.fill(0, offset, offset + BYTES_PER_PAGE)
234
+ }
235
+ }
236
+
237
+ return buffer
238
+ }
239
+
216
240
  getBitfield (index, length) {
217
241
  const j = index & (BITS_PER_PAGE - 1)
218
242
  const i = (index - j) / BITS_PER_PAGE
@@ -303,7 +327,7 @@ module.exports = class Bitfield {
303
327
  i++
304
328
  }
305
329
 
306
- return val ? -1 : position
330
+ return val ? -1 : this._segments.maxLength * BITS_PER_SEGMENT
307
331
  }
308
332
 
309
333
  firstSet (position) {
package/lib/core.js CHANGED
@@ -6,6 +6,7 @@ const Mutex = require('./mutex')
6
6
  const MerkleTree = require('./merkle-tree')
7
7
  const BlockStore = require('./block-store')
8
8
  const Bitfield = require('./bitfield')
9
+ const RemoteBitfield = require('./remote-bitfield')
9
10
  const Info = require('./info')
10
11
  const { BAD_ARGUMENT, STORAGE_EMPTY, STORAGE_CONFLICT, INVALID_OPERATION, INVALID_SIGNATURE, INVALID_CHECKSUM } = require('hypercore-errors')
11
12
  const m = require('./messages')
@@ -30,6 +31,7 @@ module.exports = class Core {
30
31
  this.truncating = 0
31
32
  this.updating = false
32
33
  this.closed = false
34
+ this.skipBitfield = null
33
35
 
34
36
  this._manifestFlushed = !!header.manifest
35
37
  this._maxOplogSize = 65536
@@ -142,7 +144,7 @@ module.exports = class Core {
142
144
  const prologue = header.manifest ? header.manifest.prologue : null
143
145
 
144
146
  const tree = await MerkleTree.open(treeFile, { crypto, prologue, ...header.tree })
145
- const bitfield = await Bitfield.open(bitfieldFile, tree)
147
+ const bitfield = await Bitfield.open(bitfieldFile)
146
148
  const blocks = new BlockStore(dataFile, tree)
147
149
 
148
150
  if (overwrite) {
@@ -258,7 +260,7 @@ module.exports = class Core {
258
260
  const [offset] = await src.tree.byteRange(2 * segmentStart)
259
261
  await this.blocks.putBatch(segmentStart, segment, offset)
260
262
 
261
- this.bitfield.setRange(segmentStart, segmentEnd - segmentStart, true)
263
+ this._setBitfieldRange(segmentStart, segmentEnd - segmentStart, true)
262
264
 
263
265
  pos = segmentEnd + 1
264
266
 
@@ -300,7 +302,7 @@ module.exports = class Core {
300
302
  const blocks = additional.length === missing ? additional : additional.slice(offset, offset + missing)
301
303
 
302
304
  await this.blocks.putBatch(source.length, blocks, source.byteLength)
303
- this.bitfield.setRange(source.length, missing, true)
305
+ this._setBitfieldRange(source.length, missing, true)
304
306
 
305
307
  updates.push({
306
308
  drop: false,
@@ -464,7 +466,7 @@ module.exports = class Core {
464
466
 
465
467
  await this.oplog.append([entry], false)
466
468
 
467
- this.bitfield.setRange(batch.ancestors, len - batch.ancestors, false)
469
+ this._setBitfieldRange(batch.ancestors, len - batch.ancestors, false)
468
470
  batch.commit()
469
471
 
470
472
  // TODO: (see below todo)
@@ -491,7 +493,7 @@ module.exports = class Core {
491
493
 
492
494
  await this.oplog.append([entry], false)
493
495
 
494
- this.bitfield.setRange(start, end - start, false)
496
+ this._setBitfieldRange(start, end - start, false)
495
497
 
496
498
  if (start < this.header.hints.contiguousLength) {
497
499
  this.header.hints.contiguousLength = start
@@ -588,7 +590,7 @@ module.exports = class Core {
588
590
  await this.blocks.putBatch(treeLength, adding > values.length ? values.slice(0, adding) : values, byteOffset)
589
591
  await this.oplog.append([entry], false)
590
592
 
591
- this.bitfield.setRange(entry.bitfield.start, entry.bitfield.length, true)
593
+ this._setBitfieldRange(entry.bitfield.start, entry.bitfield.length, true)
592
594
  batch.commit()
593
595
 
594
596
  if (batch.upgraded) {
@@ -654,7 +656,7 @@ module.exports = class Core {
654
656
 
655
657
  await this.oplog.append([entry], false)
656
658
 
657
- this.bitfield.setRange(batch.ancestors, batch.length - batch.ancestors, true)
659
+ this._setBitfieldRange(batch.ancestors, batch.length - batch.ancestors, true)
658
660
  batch.commit()
659
661
 
660
662
  this.header.tree.length = batch.length
@@ -719,7 +721,7 @@ module.exports = class Core {
719
721
  let status = 0b0001
720
722
 
721
723
  if (bitfield) {
722
- this.bitfield.set(bitfield.start, true)
724
+ this._setBitfield(bitfield.start, true)
723
725
  status |= updateContig(this.header, bitfield, this.bitfield)
724
726
  }
725
727
 
@@ -781,7 +783,7 @@ module.exports = class Core {
781
783
  let status = 0
782
784
 
783
785
  if (bitfield) {
784
- this.bitfield.set(bitfield.start, true)
786
+ this._setBitfield(bitfield.start, true)
785
787
  status = updateContig(this.header, bitfield, this.bitfield)
786
788
  }
787
789
 
@@ -898,7 +900,7 @@ module.exports = class Core {
898
900
 
899
901
  await this.oplog.append([entry], false)
900
902
 
901
- this.bitfield.setRange(batch.ancestors, this.tree.length - batch.ancestors, false)
903
+ this._setBitfieldRange(batch.ancestors, this.tree.length - batch.ancestors, false)
902
904
  addReorgHint(this.header.hints.reorgs, this.tree, batch)
903
905
  batch.commit()
904
906
 
@@ -920,6 +922,23 @@ module.exports = class Core {
920
922
  await this._flushOplog()
921
923
  }
922
924
 
925
+ openSkipBitfield () {
926
+ if (this.skipBitfield !== null) return this.skipBitfield
927
+ this.skipBitfield = new RemoteBitfield()
928
+ this.skipBitfield.insert(0, this.bitfield.toBuffer(this.tree.length))
929
+ return this.skipBitfield
930
+ }
931
+
932
+ _setBitfield (index, value) {
933
+ this.bitfield.set(index, value)
934
+ if (this.skipBitfield !== null) this.skipBitfield.set(index, value)
935
+ }
936
+
937
+ _setBitfieldRange (start, length, value) {
938
+ this.bitfield.setRange(start, length, value)
939
+ if (this.skipBitfield !== null) this.skipBitfield.setRange(start, length, value)
940
+ }
941
+
923
942
  async close () {
924
943
  this.closed = true
925
944
  await this._mutex.destroy()
@@ -116,7 +116,7 @@ class RemoteBitfieldSegment {
116
116
  i++
117
117
  }
118
118
 
119
- return -1
119
+ return (val || this.pagesLength === PAGES_PER_SEGMENT) ? -1 : this.pagesLength * BITS_PER_PAGE
120
120
  }
121
121
 
122
122
  findLast (val, position) {
@@ -230,7 +230,7 @@ module.exports = class RemoteBitfield {
230
230
  i++
231
231
  }
232
232
 
233
- return val ? -1 : position
233
+ return val ? -1 : this._maxSegments * BITS_PER_SEGMENT
234
234
  }
235
235
 
236
236
  firstSet (position) {
package/lib/replicator.js CHANGED
@@ -33,7 +33,7 @@ const m = require('./messages')
33
33
  const caps = require('./caps')
34
34
  const { createTracer } = require('hypertrace')
35
35
 
36
- const DEFAULT_MAX_INFLIGHT = [32, 512]
36
+ const DEFAULT_MAX_INFLIGHT = [16, 512]
37
37
  const SCALE_LATENCY = 50
38
38
  const DEFAULT_SEGMENT_SIZE = 256 * 1024 * 8 // 256 KiB in bits
39
39
  const NOT_DOWNLOADING_SLACK = 20000 + (Math.random() * 20000) | 0
@@ -369,8 +369,8 @@ class Peer {
369
369
  const stream = this.stream.rawStream
370
370
  if (!stream.udx) return Math.min(this.inflightRange[1], this.inflightRange[0] * 3)
371
371
 
372
- const scale = stream.rtt <= SCALE_LATENCY ? 1 : stream.rtt / SCALE_LATENCY
373
- return Math.round(Math.min(this.inflightRange[1], this.inflightRange[0] * scale))
372
+ const scale = stream.rtt <= SCALE_LATENCY ? 1 : stream.rtt / SCALE_LATENCY * Math.min(1, 2 / this.replicator.peers.length)
373
+ return Math.max(this.inflightRange[0], Math.round(Math.min(this.inflightRange[1], this.inflightRange[0] * scale)))
374
374
  }
375
375
 
376
376
  signalUpgrade () {
@@ -378,6 +378,10 @@ class Peer {
378
378
  else this.sendSync()
379
379
  }
380
380
 
381
+ _markInflight (index) {
382
+ this.missingBlocks.set(index, false)
383
+ }
384
+
381
385
  broadcastRange (start, length, drop) {
382
386
  if (drop) this._unclearLocalRange(start, length)
383
387
  else this._clearLocalRange(start, length)
@@ -662,11 +666,12 @@ class Peer {
662
666
  }
663
667
 
664
668
  _cancelRequest (id) {
665
- const exists = this.replicator._inflight.get(id)
666
- if (!exists) return
669
+ const req = this.replicator._inflight.get(id)
670
+ if (!req) return
667
671
 
668
672
  this.inflight--
669
673
  this.replicator._removeInflight(id)
674
+ if (isBlockRequest(req)) this.replicator._unmarkInflight(req.block.index)
670
675
 
671
676
  this.wireCancel.send({ request: id })
672
677
  }
@@ -716,6 +721,8 @@ class Peer {
716
721
  if (reorg === true) return await this.replicator._onreorgdata(this, req, data)
717
722
  } catch (err) {
718
723
  safetyCatch(err)
724
+ if (isBlockRequest(req)) this.replicator._unmarkInflight(req.block.index)
725
+
719
726
  this.paused = true
720
727
  this.replicator.oninvalid(err, req, data, this)
721
728
  return
@@ -730,6 +737,7 @@ class Peer {
730
737
  }
731
738
  } catch (err) {
732
739
  safetyCatch(err)
740
+ if (isBlockRequest(req)) this.replicator._unmarkInflight(req.block.index)
733
741
 
734
742
  if (err.code === 'WRITE_FAILED') {
735
743
  // For example, we don't want to keep pulling data when storage is full
@@ -788,8 +796,10 @@ class Peer {
788
796
  }
789
797
 
790
798
  _clearLocalRange (start, length) {
799
+ const bitfield = this.core.skipBitfield === null ? this.core.bitfield : this.core.skipBitfield
800
+
791
801
  if (length === 1) {
792
- this.missingBlocks.set(start, this._remoteHasBlock(start) && !this.core.bitfield.get(start))
802
+ this.missingBlocks.set(start, this._remoteHasBlock(start) && !bitfield.get(start))
793
803
  return
794
804
  }
795
805
 
@@ -809,7 +819,7 @@ class Peer {
809
819
 
810
820
  const end = start + Math.min(length, this.core.tree.length)
811
821
  while (start < end) {
812
- const local = this.core.bitfield.getBitfield(start)
822
+ const local = bitfield.getBitfield(start)
813
823
 
814
824
  if (local && local.bitfield) {
815
825
  this.missingBlocks.clear(start, local.bitfield)
@@ -819,9 +829,14 @@ class Peer {
819
829
  }
820
830
  }
821
831
 
832
+ _resetMissingBlock (index) {
833
+ const bitfield = this.core.skipBitfield === null ? this.core.bitfield : this.core.skipBitfield
834
+ this.missingBlocks.set(index, this._remoteHasBlock(index) && !bitfield.get(index))
835
+ }
836
+
822
837
  _unclearLocalRange (start, length) {
823
838
  if (length === 1) {
824
- this.missingBlocks.set(start, this._remoteHasBlock(start) && !this.core.bitfield.get(start))
839
+ this._resetMissingBlock(start)
825
840
  return
826
841
  }
827
842
 
@@ -856,8 +871,9 @@ class Peer {
856
871
  if (start === 0 && drop === false && length > this._remoteContiguousLength) {
857
872
  this._remoteContiguousLength = length
858
873
  } else if (length === 1) {
874
+ const bitfield = this.core.skipBitfield === null ? this.core.bitfield : this.core.skipBitfield
859
875
  this.remoteBitfield.set(start, has)
860
- this.missingBlocks.set(start, has && !this.core.bitfield.get(start))
876
+ this.missingBlocks.set(start, has && !bitfield.get(start))
861
877
  } else {
862
878
  const rangeStart = this.remoteBitfield.findFirst(!has, start)
863
879
  const rangeLength = length - (rangeStart - start)
@@ -1034,6 +1050,14 @@ class Peer {
1034
1050
  return index < this._remoteContiguousLength || this.remoteBitfield.get(index) === true
1035
1051
  }
1036
1052
 
1053
+ _sendBlockRequest (req, b) {
1054
+ req.block = { index: b.index, nodes: 0 }
1055
+ this.replicator._markInflight(b.index)
1056
+
1057
+ b.inflight.push(req)
1058
+ this._send(req)
1059
+ }
1060
+
1037
1061
  _requestBlock (b) {
1038
1062
  const { length, fork } = this.core.tree
1039
1063
 
@@ -1049,10 +1073,7 @@ class Peer {
1049
1073
  const req = this._makeRequest(b.index >= length, b.priority)
1050
1074
  if (req === null) return false
1051
1075
 
1052
- req.block = { index: b.index, nodes: 0 }
1053
-
1054
- b.inflight.push(req)
1055
- this._send(req)
1076
+ this._sendBlockRequest(req, b)
1056
1077
 
1057
1078
  return true
1058
1079
  }
@@ -1061,7 +1082,10 @@ class Peer {
1061
1082
  if (this.core.bitfield.get(index) === true || !this._hasTreeParent(index)) return false
1062
1083
 
1063
1084
  const b = this.replicator._blocks.add(index, PRIORITY.NORMAL)
1064
- if (b.inflight.length > 0) return false
1085
+ if (b.inflight.length > 0) {
1086
+ this.missingBlocks.set(index, false) // in case we missed some states just set them ondemand, nbd
1087
+ return false
1088
+ }
1065
1089
 
1066
1090
  const req = this._makeRequest(index >= length, b.priority)
1067
1091
 
@@ -1071,10 +1095,7 @@ class Peer {
1071
1095
  return false
1072
1096
  }
1073
1097
 
1074
- req.block = { index, nodes: 0 }
1075
-
1076
- b.inflight.push(req)
1077
- this._send(req)
1098
+ this._sendBlockRequest(req, b)
1078
1099
 
1079
1100
  // Don't think this will ever happen, as the pending queue is drained before the range queue
1080
1101
  // but doesn't hurt to check this explicitly here also.
@@ -1084,7 +1105,8 @@ class Peer {
1084
1105
 
1085
1106
  _findNext (i) {
1086
1107
  if (i < this._remoteContiguousLength) {
1087
- i = this.core.bitfield.findFirst(false, i)
1108
+ if (this.core.skipBitfield === null) this.replicator._openSkipBitfield()
1109
+ i = this.core.skipBitfield.findFirst(false, i)
1088
1110
  if (i < this._remoteContiguousLength && i > -1) return i
1089
1111
  i = this._remoteContiguousLength
1090
1112
  }
@@ -1583,9 +1605,8 @@ module.exports = class Replicator {
1583
1605
 
1584
1606
  _removeInflight (id) {
1585
1607
  this._inflight.remove(id)
1586
- if (this.isDownloading() === false) {
1587
- for (const peer of this.peers) peer.signalUpgrade()
1588
- }
1608
+ if (this.isDownloading() === true) return
1609
+ for (const peer of this.peers) peer.signalUpgrade()
1589
1610
  }
1590
1611
 
1591
1612
  _removePeer (peer) {
@@ -1788,6 +1809,7 @@ module.exports = class Replicator {
1788
1809
  _clearRequest (peer, req) {
1789
1810
  if (req.block !== null) {
1790
1811
  this._clearInflightBlock(this._blocks, req)
1812
+ this._unmarkInflight(req.block.index)
1791
1813
  }
1792
1814
 
1793
1815
  if (req.hash !== null) {
@@ -1812,6 +1834,28 @@ module.exports = class Replicator {
1812
1834
  this.updateAll()
1813
1835
  }
1814
1836
 
1837
+ _openSkipBitfield () {
1838
+ // technically the skip bitfield gets bits cleared if .clear() is called
1839
+ // also which might be in inflight also, but that just results in that section being overcalled shortly
1840
+ // worst case, so ok for now
1841
+
1842
+ const bitfield = this.core.openSkipBitfield()
1843
+
1844
+ for (const req of this._inflight) {
1845
+ if (req.block) bitfield.set(req.block.index, true) // skip
1846
+ }
1847
+ }
1848
+
1849
+ _markInflight (index) {
1850
+ if (this.core.skipBitfield !== null) this.core.skipBitfield.set(index, true)
1851
+ for (const peer of this.peers) peer._markInflight(index)
1852
+ }
1853
+
1854
+ _unmarkInflight (index) {
1855
+ if (this.core.skipBitfield !== null) this.core.skipBitfield.set(index, this.core.bitfield.get(index))
1856
+ for (const peer of this.peers) peer._resetMissingBlock(index)
1857
+ }
1858
+
1815
1859
  _ondata (peer, req, data) {
1816
1860
  if (data.block !== null) {
1817
1861
  this._resolveBlockRequest(this._blocks, data.block.index, data.block.value, req)
@@ -2247,3 +2291,7 @@ function onwireextension (m, c) {
2247
2291
  function setDownloadingLater (repl, downloading, session) {
2248
2292
  repl.setDownloadingNow(downloading, session)
2249
2293
  }
2294
+
2295
+ function isBlockRequest (req) {
2296
+ return req !== null && req.block !== null
2297
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.35.1",
3
+ "version": "10.35.3",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {