hypercore 11.26.0 → 11.27.1

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
@@ -1057,22 +1057,27 @@ class Hypercore extends EventEmitter {
1057
1057
  async recoverFromRemoteProof(remoteProof) {
1058
1058
  this.core.replicator.setPushOnly(true)
1059
1059
  this.core._repairMode = true
1060
+
1060
1061
  await this.core.state.mutex.lock()
1061
- const p = await verify(this.core.db, remoteProof)
1062
- if (!p) return false
1063
1062
 
1064
- const tx = this.core.storage.write()
1065
- for (const node of p.proof.upgrade.nodes) {
1066
- tx.putTreeNode(node)
1067
- }
1068
- await tx.flush()
1063
+ try {
1064
+ const p = await verify(this.core.db, remoteProof)
1065
+ if (!p) return false
1069
1066
 
1070
- this.core.state.mutex.unlock()
1071
- const succeed = p.proof.upgrade.nodes.length !== 0
1072
- if (succeed) {
1073
- this.core.replicator.setPushOnly(false)
1067
+ const tx = this.core.storage.write()
1068
+ for (const node of p.proof.upgrade.nodes) {
1069
+ tx.putTreeNode(node)
1070
+ }
1071
+ await tx.flush()
1072
+
1073
+ const succeed = p.proof.upgrade.nodes.length !== 0
1074
+ if (succeed) {
1075
+ this.core.replicator.setPushOnly(false)
1076
+ }
1077
+ return succeed
1078
+ } finally {
1079
+ this.core.state.mutex.unlock()
1074
1080
  }
1075
- return succeed
1076
1081
  }
1077
1082
 
1078
1083
  recoverTreeNodeFromPeers() {
package/lib/core.js CHANGED
@@ -204,7 +204,8 @@ module.exports = class Core {
204
204
  hints: {
205
205
  reorgs: [],
206
206
  contiguousLength: 0,
207
- remoteContiguousLength: 0
207
+ remoteContiguousLength: 0,
208
+ recovering: 0
208
209
  }
209
210
  }
210
211
 
@@ -553,7 +554,8 @@ module.exports = class Core {
553
554
 
554
555
  tx.setHints({
555
556
  contiguousLength: this.header.hints.contiguousLength,
556
- remoteContiguousLength: this.header.hints.remoteContiguousLength
557
+ remoteContiguousLength: this.header.hints.remoteContiguousLength,
558
+ recovering: this.header.hints.recovering
557
559
  })
558
560
 
559
561
  await tx.flush()
@@ -963,7 +965,8 @@ function parseHeader(info) {
963
965
  hints: {
964
966
  reorgs: [],
965
967
  contiguousLength: info.hints ? info.hints.contiguousLength : 0,
966
- remoteContiguousLength: info.hints ? info.hints.remoteContiguousLength : 0
968
+ remoteContiguousLength: info.hints ? info.hints.remoteContiguousLength : 0,
969
+ recovering: info.hints ? info.hints.recovering : 0
967
970
  }
968
971
  }
969
972
  }
package/lib/replicator.js CHANGED
@@ -987,6 +987,7 @@ class Peer {
987
987
  async push(index) {
988
988
  if (!this.remoteAllowPush) return
989
989
  if (!this.remoteDownloading) return
990
+ if (this.core.state.length <= index) return
990
991
  if (this.core.state.fork !== this.remoteFork) return
991
992
  if (this.remoteBitfield.get(index)) return
992
993
 
@@ -4,7 +4,13 @@ const assert = require('nanoassert')
4
4
  const flat = require('flat-tree')
5
5
  const quickbit = require('quickbit-universal')
6
6
 
7
- const { INVALID_OPERATION, INVALID_SIGNATURE, ASSERTION } = require('hypercore-errors')
7
+ const {
8
+ INVALID_OPERATION,
9
+ INVALID_SIGNATURE,
10
+ ASSERTION,
11
+ SESSION_CLOSED,
12
+ SESSION_NOT_WRITABLE
13
+ } = require('hypercore-errors')
8
14
 
9
15
  const Mutex = require('./mutex')
10
16
  const Bitfield = require('./bitfield')
@@ -562,9 +568,47 @@ module.exports = class SessionState {
562
568
  }
563
569
  }
564
570
 
571
+ // simple tool to wait for other peers to catch us up
572
+ async _waitForRecovery() {
573
+ const length = this.length
574
+ const replicator = this.core.replicator
575
+
576
+ while (!this.closing) {
577
+ if (replicator.peers.length < 1) {
578
+ await new Promise((resolve) => setTimeout(resolve, 5000))
579
+ continue
580
+ }
581
+
582
+ await new Promise((resolve) => setTimeout(resolve, 5000))
583
+
584
+ const peers = replicator.peers
585
+
586
+ if (peers.length < 1 || this.closing) continue
587
+ if (peers[0].remoteLength > this.length) continue
588
+
589
+ if (this.length !== length) {
590
+ throw SESSION_NOT_WRITABLE('core recovered during append')
591
+ }
592
+
593
+ this.core.header.hints.recovering = 0
594
+
595
+ await this.mutex.lock()
596
+ try {
597
+ await this.core.flushHints()
598
+ return
599
+ } finally {
600
+ this.mutex.unlock()
601
+ }
602
+ }
603
+
604
+ throw SESSION_CLOSED('Cannot recover a closed session', this.discoveryKey)
605
+ }
606
+
565
607
  async append(values, { signature, keyPair, preappend, postappend, maxLength = -1 } = {}) {
566
608
  if (!keyPair && this.isDefault()) keyPair = this.core.header.keyPair
567
609
 
610
+ if (this.isDefault() && this.core.header.hints.recovering) await this._waitForRecovery()
611
+
568
612
  await this.mutex.lock()
569
613
 
570
614
  try {
@@ -921,6 +965,8 @@ module.exports = class SessionState {
921
965
  throw ASSERTION('Cannot commit while repair mode is on')
922
966
  }
923
967
 
968
+ if (this.core.header.hints.recovering) await this._waitForRecovery()
969
+
924
970
  let srcLocked = false
925
971
  await this.mutex.lock()
926
972
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "11.26.0",
3
+ "version": "11.27.1",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {