hypercore 10.24.3 → 10.24.5

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
@@ -629,7 +629,7 @@ module.exports = class Hypercore extends EventEmitter {
629
629
  this.replicator.ontruncate(bitfield.start)
630
630
  }
631
631
 
632
- if ((status & 0b0011) !== 0) {
632
+ if ((status & 0b10011) !== 0) {
633
633
  this.replicator.onupgrade()
634
634
  }
635
635
 
package/lib/batch.js CHANGED
@@ -272,13 +272,15 @@ module.exports = class HypercoreBatch extends EventEmitter {
272
272
  }
273
273
  }
274
274
 
275
- const offset = this._sessionLength + this._appends.length - this.core.tree.length
276
- for (let i = 0; i < offset; i++) this._byteLength -= this._appends[i]
275
+ const offset = this.core.tree.length - this._sessionLength
276
+ for (let i = 0; i < offset; i++) this._byteLength -= this._appends[i].byteLength
277
+
278
+ await this.core.insertValuesUnsafe(this._appends.slice(0, offset), this._sessionLength, this._sessionByteLength, b.nodes)
277
279
 
278
280
  this._sessionLength = this.session.length
279
281
  this._sessionByteLength = this.session.byteLength
280
282
  this._sessionBatch = this.session.createTreeBatch()
281
- this._appends = this._appends.slice(this._appends.length - offset)
283
+ this._appends = this._appends.slice(offset)
282
284
 
283
285
  return true
284
286
  }
package/lib/core.js CHANGED
@@ -218,7 +218,7 @@ module.exports = class Core {
218
218
  }
219
219
 
220
220
  async copyFrom (src, signature) {
221
- this._mutex.lock()
221
+ await this._mutex.lock()
222
222
 
223
223
  try {
224
224
  let pos = src.bitfield.firstSet(0)
@@ -432,6 +432,33 @@ module.exports = class Core {
432
432
  })
433
433
  }
434
434
 
435
+ // assumes mutex is already acquried
436
+ async insertValuesUnsafe (values, offset, byteOffset, treeNodes) {
437
+ if (!values.length) return
438
+
439
+ const bitfield = {
440
+ drop: false,
441
+ start: offset,
442
+ end: offset + values.length
443
+ }
444
+
445
+ await this.blocks.putBatch(offset, values, byteOffset)
446
+ await this.oplog.append({
447
+ userData: null,
448
+ treeNodes,
449
+ treeUpgrade: null,
450
+ bitfield
451
+ }, false)
452
+
453
+ this.bitfield.setRange(bitfield.start, values.length, true)
454
+ for (const node of treeNodes) this.tree.unflushed.set(node.index, node)
455
+
456
+ const status = updateContig(this.header, bitfield, this.bitfield)
457
+ this.onupdate(status, bitfield, null, null)
458
+
459
+ if (this._shouldFlush()) await this._flushOplog()
460
+ }
461
+
435
462
  async append (values, { lock, signature, keyPair = this.header.keyPair, preappend } = {}) {
436
463
  if (lock) await this._mutex.lock()
437
464
 
@@ -1188,6 +1188,12 @@ async function generateProof (tree, block, hash, seek, upgrade) {
1188
1188
  const from = upgrade ? upgrade.start * 2 : 0
1189
1189
  const to = upgrade ? from + upgrade.length * 2 : head
1190
1190
  const node = normalizeIndexed(block, hash)
1191
+
1192
+ const result = { fork, block: null, hash: null, seek: null, upgrade: null, manifest: null }
1193
+
1194
+ // can't do anything as we have no data...
1195
+ if (head === 0) return result
1196
+
1191
1197
  if (from >= to || to > head) {
1192
1198
  throw INVALID_OPERATION('Invalid upgrade')
1193
1199
  }
@@ -1218,7 +1224,6 @@ async function generateProof (tree, block, hash, seek, upgrade) {
1218
1224
  }
1219
1225
 
1220
1226
  const [pNode, pSeek, pUpgrade, pAdditional] = await settleProof(p)
1221
- const result = { fork, block: null, hash: null, seek: null, upgrade: null, manifest: null }
1222
1227
 
1223
1228
  if (block) {
1224
1229
  result.block = {
package/lib/mutex.js CHANGED
@@ -10,7 +10,7 @@ module.exports = class Mutex {
10
10
  }
11
11
 
12
12
  lock () {
13
- if (this.destroyed) return Promise.reject(this._destroyError)
13
+ if (this.destroyed) return Promise.reject(this._destroyError || new Error('Mutex has been destroyed'))
14
14
  if (this.locked) return new Promise(this._enqueue)
15
15
  this.locked = true
16
16
  return Promise.resolve()
@@ -28,7 +28,7 @@ module.exports = class Mutex {
28
28
  if (!this._destroying) this._destroying = this.locked ? this.lock().catch(() => {}) : Promise.resolve()
29
29
 
30
30
  this.destroyed = true
31
- this._destroyError = err || new Error('Mutex has been destroyed')
31
+ if (err) this._destroyError = err
32
32
 
33
33
  if (err) {
34
34
  while (this._queue.length) this._queue.shift()[1](err)
package/lib/replicator.js CHANGED
@@ -384,7 +384,7 @@ class Peer {
384
384
  remoteLength: this.core.tree.fork === this.remoteFork ? this.remoteLength : 0,
385
385
  canUpgrade: this.canUpgrade,
386
386
  uploading: true,
387
- downloading: this.replicator.downloading,
387
+ downloading: this.replicator.isDownloading(),
388
388
  hasManifest: !!this.core.header.manifest && this.core.compat === false
389
389
  })
390
390
  }
@@ -582,9 +582,9 @@ class Peer {
582
582
  if (msg.fork === this.core.tree.fork) {
583
583
  try {
584
584
  proof = await this._getProof(msg)
585
- } catch (err) { // TODO: better error handling here, ie custom errors
585
+ } catch (err) {
586
586
  safetyCatch(err)
587
- if (this.replicator.core.closed) throw err // just an extra safety check...
587
+ if (isCriticalError(err)) throw err
588
588
  }
589
589
  }
590
590
 
@@ -619,7 +619,7 @@ class Peer {
619
619
  if (!exists) return
620
620
 
621
621
  this.inflight--
622
- this.replicator._inflight.remove(id)
622
+ this.replicator._removeInflight(id)
623
623
 
624
624
  this.wireCancel.send({ request: id })
625
625
  }
@@ -660,7 +660,7 @@ class Peer {
660
660
  if (req !== null) {
661
661
  if (req.peer !== this) return
662
662
  this.inflight--
663
- this.replicator._inflight.remove(req.id)
663
+ this.replicator._removeInflight(req.id)
664
664
  }
665
665
 
666
666
  if (reorg === true) return this.replicator._onreorgdata(this, req, data)
@@ -674,6 +674,8 @@ class Peer {
674
674
  }
675
675
  } catch (err) {
676
676
  safetyCatch(err)
677
+ if (this.core.closed && !isCriticalError(err)) return
678
+
677
679
  // might be a fork, verify
678
680
  this._checkIfConflict(err)
679
681
  this.replicator._onnodata(this, req)
@@ -695,7 +697,7 @@ class Peer {
695
697
  if (req === null || req.peer !== this) return
696
698
 
697
699
  this.inflight--
698
- this.replicator._inflight.remove(req.id)
700
+ this.replicator._removeInflight(req.id)
699
701
  this.replicator._onnodata(this, req)
700
702
  }
701
703
 
@@ -1072,10 +1074,15 @@ module.exports = class Replicator {
1072
1074
  }
1073
1075
  }
1074
1076
 
1077
+ isDownloading () {
1078
+ return this.downloading || !this._inflight.idle
1079
+ }
1080
+
1075
1081
  setDownloading (downloading) {
1076
1082
  if (this.downloading === downloading) return
1077
1083
  this.downloading = downloading
1078
- for (const peer of this.peers) peer.sendSync()
1084
+ if (!downloading && this.isDownloading()) return
1085
+ for (const peer of this.peers) peer.signalUpgrade()
1079
1086
  }
1080
1087
 
1081
1088
  cork () {
@@ -1319,6 +1326,13 @@ module.exports = class Replicator {
1319
1326
  this.onpeerupdate(true, peer)
1320
1327
  }
1321
1328
 
1329
+ _removeInflight (id) {
1330
+ this._inflight.remove(id)
1331
+ if (this.isDownloading() === false) {
1332
+ for (const peer of this.peers) peer.signalUpgrade()
1333
+ }
1334
+ }
1335
+
1322
1336
  _removePeer (peer) {
1323
1337
  this.peers.splice(this.peers.indexOf(peer), 1)
1324
1338
 
@@ -1904,6 +1918,11 @@ function destroyRequestTimeout (req) {
1904
1918
  }
1905
1919
  }
1906
1920
 
1921
+ function isCriticalError (err) {
1922
+ // TODO: expose .critical or similar on the hypercore errors that are critical (if all not are)
1923
+ return err.name === 'HypercoreError'
1924
+ }
1925
+
1907
1926
  function onwireopen (m, c) {
1908
1927
  return c.userData.onopen(m)
1909
1928
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.24.3",
3
+ "version": "10.24.5",
4
4
  "description": "Hypercore is a secure, distributed append-only log",
5
5
  "main": "index.js",
6
6
  "scripts": {