hypercore 11.19.1 → 11.20.0

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/README.md CHANGED
@@ -594,7 +594,13 @@ Populated after `ready` has been emitted. Will be `0` before the event.
594
594
 
595
595
  #### `core.contiguousLength`
596
596
 
597
- How many blocks are contiguously available starting from the first block of this core?
597
+ How many blocks are contiguously available starting from the first block of this core.
598
+
599
+ Populated after `ready` has been emitted. Will be `0` before the event.
600
+
601
+ #### `core.remoteContiguousLength`
602
+
603
+ How many blocks are contiguously available starting from the first block of this core on any known remote. This is only updated when a remote thinks it is fully contiguous such that they have all known blocks.
598
604
 
599
605
  Populated after `ready` has been emitted. Will be `0` before the event.
600
606
 
@@ -708,6 +714,10 @@ Emitted when a block is uploaded to a peer.
708
714
 
709
715
  Emitted when a block is downloaded from a peer.
710
716
 
717
+ #### `core.on('remote-contiguous-length', length)`
718
+
719
+ Emitted when the max known contiguous `length` from a remote, ie `core.remoteContiguousLength`, is updated. Note this is not emitted when core is truncated.
720
+
711
721
  #### `Hypercore.MAX_SUGGESTED_BLOCK_SIZE`
712
722
 
713
723
  The constant for max size (15MB) for blocks appended to Hypercore. This max ensures blocks are replicated smoothly.
package/index.js CHANGED
@@ -564,6 +564,11 @@ class Hypercore extends EventEmitter {
564
564
  return this.state.byteLength - this.state.length * this.padding
565
565
  }
566
566
 
567
+ get remoteContiguousLength() {
568
+ if (this.opened === false) return 0
569
+ return Math.min(this.core.state.length, this.core.header.hints.remoteContiguousLength)
570
+ }
571
+
567
572
  get contiguousLength() {
568
573
  if (this.opened === false) return 0
569
574
  return Math.min(this.core.state.length, this.core.header.hints.contiguousLength)
package/lib/core.js CHANGED
@@ -200,7 +200,8 @@ module.exports = class Core {
200
200
  },
201
201
  hints: {
202
202
  reorgs: [],
203
- contiguousLength: 0
203
+ contiguousLength: 0,
204
+ remoteContiguousLength: 0
204
205
  }
205
206
  }
206
207
 
@@ -284,7 +285,7 @@ module.exports = class Core {
284
285
  if (header.hints.contiguousLength !== len) {
285
286
  header.hints.contiguousLength = len
286
287
  const tx = storage.write()
287
- tx.setHints({ contiguousLength: len })
288
+ tx.setHints(header.hints)
288
289
  await tx.flush()
289
290
  }
290
291
 
@@ -718,6 +719,16 @@ module.exports = class Core {
718
719
  }
719
720
  }
720
721
 
722
+ async updateRemoteContiguousLength(length) {
723
+ this.header.hints.remoteContiguousLength = length
724
+ await this.state.flushHints()
725
+ if (this.header.hints.remoteContiguousLength !== length) return
726
+
727
+ for (let i = this.monitors.length - 1; i >= 0; i--) {
728
+ this.monitors[i].emit('remote-contiguous-length', length)
729
+ }
730
+ }
731
+
721
732
  onappend(tree, bitfield) {
722
733
  this.header.tree = tree
723
734
 
@@ -860,7 +871,8 @@ function parseHeader(info) {
860
871
  tree: info.head || getDefaultTree(),
861
872
  hints: {
862
873
  reorgs: [],
863
- contiguousLength: info.hints ? info.hints.contiguousLength : 0
874
+ contiguousLength: info.hints ? info.hints.contiguousLength : 0,
875
+ remoteContiguousLength: info.hints ? info.hints.remoteContiguousLength : 0
864
876
  }
865
877
  }
866
878
  }
package/lib/replicator.js CHANGED
@@ -514,19 +514,19 @@ class Peer {
514
514
  else this._clearLocalRange(start, length)
515
515
 
516
516
  const i = Math.floor(start / DEFAULT_SEGMENT_SIZE)
517
- const contig = this.core.header.hints.contiguousLength === this.core.state.length
517
+ const fullyContig = this.core.header.hints.contiguousLength === this.core.state.length
518
518
 
519
519
  if (
520
520
  start + LAST_BLOCKS < this.core.state.length &&
521
521
  !this.remoteSegmentsWanted.has(i) &&
522
522
  !drop &&
523
- !contig
523
+ !fullyContig
524
524
  ) {
525
525
  return
526
526
  }
527
527
 
528
528
  let force = false
529
- if (contig && !drop) {
529
+ if (fullyContig && !drop) {
530
530
  start = 0
531
531
  length = this.core.state.length
532
532
 
@@ -1152,7 +1152,7 @@ class Peer {
1152
1152
  this._clearLocalRange(fixedStart, length)
1153
1153
  }
1154
1154
 
1155
- onrange({ drop, start, length }) {
1155
+ async onrange({ drop, start, length }) {
1156
1156
  const has = drop === false
1157
1157
 
1158
1158
  if (drop === true && start < this._remoteContiguousLength) {
@@ -1160,7 +1160,15 @@ class Peer {
1160
1160
  }
1161
1161
 
1162
1162
  if (start === 0 && drop === false) {
1163
- if (length > this._remoteContiguousLength) this._remoteContiguousLength = length
1163
+ if (length > this._remoteContiguousLength) {
1164
+ this._remoteContiguousLength = length
1165
+ if (
1166
+ this.remoteFork === this.core.state.fork &&
1167
+ length > this.core.header.hints.remoteContiguousLength
1168
+ ) {
1169
+ await this.core.updateRemoteContiguousLength(length)
1170
+ }
1171
+ }
1164
1172
  } else if (length === 1) {
1165
1173
  const bitfield = this.core.skipBitfield === null ? this.core.bitfield : this.core.skipBitfield
1166
1174
  this.remoteBitfield.set(start, has)
@@ -473,13 +473,37 @@ module.exports = class SessionState {
473
473
  if (this.isDefault()) {
474
474
  await storeBitfieldRange(this.storage, storage, batch.ancestors, batch.treeLength, false)
475
475
  if (batch.ancestors < this.core.header.hints.contiguousLength) {
476
- storage.setHints({ contiguousLength: batch.ancestors })
476
+ this.core.header.hints.remoteContiguousLength = Math.min(
477
+ batch.length,
478
+ this.core.header.hints.remoteContiguousLength
479
+ )
480
+ storage.setHints({
481
+ contiguousLength: batch.ancestors,
482
+ remoteContiguousLength: this.core.header.hints.remoteContiguousLength
483
+ })
477
484
  }
478
485
  }
479
486
 
480
487
  return { dependency, tree, roots: batch.roots }
481
488
  }
482
489
 
490
+ async flushHints() {
491
+ await this.mutex.lock()
492
+
493
+ try {
494
+ const tx = this.createWriteBatch()
495
+
496
+ tx.setHints({
497
+ contiguousLength: this.core.header.hints.contiguousLength,
498
+ remoteContiguousLength: this.core.header.hints.remoteContiguousLength
499
+ })
500
+
501
+ await tx.flush()
502
+ } finally {
503
+ this._unlock()
504
+ }
505
+ }
506
+
483
507
  async clear(start, end, cleared) {
484
508
  await this.mutex.lock()
485
509
 
@@ -505,7 +529,10 @@ module.exports = class SessionState {
505
529
  if (this.isDefault()) {
506
530
  await storeBitfieldRange(this.storage, tx, start, end, false)
507
531
  if (start < this.core.header.hints.contiguousLength) {
508
- tx.setHints({ contiguousLength: start })
532
+ tx.setHints({
533
+ contiguousLength: start,
534
+ remoteContiguousLength: this.core.header.hints.remoteContiguousLength
535
+ })
509
536
  }
510
537
  }
511
538
 
@@ -577,7 +604,10 @@ module.exports = class SessionState {
577
604
  if (this.isDefault()) {
578
605
  await storeBitfieldRange(this.storage, tx, batch.ancestors, batch.length, true)
579
606
  if (this.length === this.core.header.hints.contiguousLength) {
580
- tx.setHints({ contiguousLength: this.length + values.length })
607
+ tx.setHints({
608
+ contiguousLength: this.length + values.length,
609
+ remoteContiguousLength: this.core.header.hints.remoteContiguousLength
610
+ })
581
611
  }
582
612
  }
583
613
 
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.19.1",
3
+ "version": "11.20.0",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "format": "prettier --write .",
8
- "lint": "prettier --check .",
8
+ "lint": "prettier --check . && lunte",
9
9
  "test": "brittle test/all.js",
10
10
  "test:bare": "bare test/all.js",
11
11
  "test:generate": "brittle -r test/all.js test/*.js"
@@ -70,7 +70,7 @@
70
70
  "brittle": "^3.0.0",
71
71
  "debugging-stream": "^3.1.0",
72
72
  "hyperswarm": "^4.3.6",
73
- "lunte": "^1.2.0",
73
+ "lunte": "^1.3.0",
74
74
  "prettier": "^3.6.2",
75
75
  "prettier-config-holepunch": "^2.0.0",
76
76
  "rache": "^1.0.0",