hypercore 10.0.0-alpha.31 → 10.0.0-alpha.34

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
@@ -280,6 +280,13 @@ const socket = net.connect(...)
280
280
  socket.pipe(localCore.replicate(true)).pipe(socket)
281
281
  ```
282
282
 
283
+ #### `const done = core.findingPeers()`
284
+
285
+ Create a hook that tells Hypercore you are finding peers for this core in the background. Call `done` when your current discovery iteration is done.
286
+ If you're using Hyperswarm, you'd normally call this after a `swarm.flush()` finishes.
287
+
288
+ This allows `core.update` to wait for either the `findingPeers` hook to finish or one peer to appear before deciding whether it should wait for a merkle tree update before returning.
289
+
283
290
  #### `core.on('append')`
284
291
 
285
292
  Emitted when the core has been appended to (i.e. has a new length / byteLength), either locally or remotely.
package/index.js CHANGED
@@ -65,7 +65,7 @@ module.exports = class Hypercore extends EventEmitter {
65
65
  this.opened = false
66
66
  this.closed = false
67
67
  this.sessions = opts._sessions || [this]
68
- this.sign = opts.sign || null
68
+ this.auth = opts.auth || null
69
69
  this.autoClose = !!opts.autoClose
70
70
 
71
71
  this.closing = null
@@ -74,6 +74,7 @@ module.exports = class Hypercore extends EventEmitter {
74
74
 
75
75
  this._preappend = preappend.bind(this)
76
76
  this._snapshot = opts.snapshot || null
77
+ this._findingPeers = 0
77
78
  }
78
79
 
79
80
  [inspect] (depth, opts) {
@@ -168,13 +169,13 @@ module.exports = class Hypercore extends EventEmitter {
168
169
  }
169
170
 
170
171
  _passCapabilities (o) {
171
- if (!this.sign) this.sign = o.sign
172
+ if (!this.auth) this.auth = o.auth
172
173
  this.crypto = o.crypto
173
174
  this.key = o.key
174
175
  this.core = o.core
175
176
  this.replicator = o.replicator
176
177
  this.encryption = o.encryption
177
- this.writable = !!this.sign
178
+ this.writable = !!(this.auth && this.auth.sign)
178
179
  this.autoClose = o.autoClose
179
180
  }
180
181
 
@@ -184,6 +185,7 @@ module.exports = class Hypercore extends EventEmitter {
184
185
  this._passCapabilities(from)
185
186
  this.sessions = from.sessions
186
187
  this.storage = from.storage
188
+ this.replicator.findingPeers += this._findingPeers
187
189
 
188
190
  this.sessions.push(this)
189
191
  }
@@ -204,10 +206,12 @@ module.exports = class Hypercore extends EventEmitter {
204
206
  // but we only do this to validate the keypair to help catch bugs so yolo
205
207
  if (this.key && keyPair) keyPair.publicKey = this.key
206
208
 
207
- if (opts.sign) {
208
- this.sign = opts.sign
209
+ if (opts.auth) {
210
+ this.auth = opts.auth
211
+ } else if (opts.sign) {
212
+ this.auth = Core.createAuth(this.crypto, keyPair, opts)
209
213
  } else if (keyPair && keyPair.secretKey) {
210
- this.sign = Core.createSigner(this.crypto, keyPair)
214
+ this.auth = Core.createAuth(this.crypto, keyPair)
211
215
  }
212
216
 
213
217
  if (isFirst) {
@@ -219,8 +223,8 @@ module.exports = class Hypercore extends EventEmitter {
219
223
  }
220
224
  }
221
225
 
222
- if (!this.sign) this.sign = this.core.defaultSign
223
- this.writable = !!this.sign
226
+ if (!this.auth) this.auth = this.core.defaultAuth
227
+ this.writable = !!this.auth.sign
224
228
 
225
229
  if (opts.valueEncoding) {
226
230
  this.valueEncoding = c.from(codecs(opts.valueEncoding))
@@ -249,6 +253,7 @@ module.exports = class Hypercore extends EventEmitter {
249
253
  keyPair,
250
254
  crypto: this.crypto,
251
255
  legacy: opts.legacy,
256
+ auth: opts.auth,
252
257
  onupdate: this._oncoreupdate.bind(this)
253
258
  })
254
259
 
@@ -268,6 +273,8 @@ module.exports = class Hypercore extends EventEmitter {
268
273
  onupload: this._onupload.bind(this)
269
274
  })
270
275
 
276
+ this.replicator.findingPeers += this._findingPeers
277
+
271
278
  if (!this.encryption && opts.encryptionKey) {
272
279
  this.encryption = new BlockEncryption(opts.encryptionKey, this.key)
273
280
  }
@@ -298,9 +305,12 @@ module.exports = class Hypercore extends EventEmitter {
298
305
  for (const ext of gc) ext.destroy()
299
306
 
300
307
  if (this.replicator !== null) {
308
+ this.replicator.findingPeers -= this._findingPeers
301
309
  this.replicator.clearRequests(this.activeRequests)
302
310
  }
303
311
 
312
+ this._findingPeers = 0
313
+
304
314
  if (this.sessions.length) {
305
315
  // if this is the last session and we are auto closing, trigger that first to enforce error handling
306
316
  if (this.sessions.length === 1 && this.autoClose) await this.sessions[0].close()
@@ -429,6 +439,22 @@ module.exports = class Hypercore extends EventEmitter {
429
439
  return null
430
440
  }
431
441
 
442
+ findingPeers () {
443
+ this._findingPeers++
444
+ if (this.replicator !== null && !this.closing) this.replicator.findingPeers++
445
+
446
+ let once = true
447
+
448
+ return () => {
449
+ if (this.closing || !once) return
450
+ once = false
451
+ this._findingPeers--
452
+ if (this.replicator !== null && --this.replicator.findingPeers === 0) {
453
+ this.replicator.updateAll()
454
+ }
455
+ }
456
+ }
457
+
432
458
  async update (opts) {
433
459
  if (this.opened === false) await this.opening
434
460
 
@@ -438,6 +464,7 @@ module.exports = class Hypercore extends EventEmitter {
438
464
  const activeRequests = (opts && opts.activeRequests) || this.activeRequests
439
465
  const req = this.replicator.addUpgrade(activeRequests)
440
466
 
467
+ // TODO: if snapshot, also update the length/byteLength to latest
441
468
  return req.promise
442
469
  }
443
470
 
@@ -543,7 +570,7 @@ module.exports = class Hypercore extends EventEmitter {
543
570
  if (this.writable === false) throw new Error('Core is not writable')
544
571
 
545
572
  if (fork === -1) fork = this.core.tree.fork + 1
546
- await this.core.truncate(newLength, fork, this.sign)
573
+ await this.core.truncate(newLength, fork, this.auth)
547
574
 
548
575
  // TODO: Should propagate from an event triggered by the oplog
549
576
  this.replicator.updateAll()
@@ -565,7 +592,7 @@ module.exports = class Hypercore extends EventEmitter {
565
592
  }
566
593
  }
567
594
 
568
- return await this.core.append(buffers, this.sign, { preappend })
595
+ return await this.core.append(buffers, this.auth, { preappend })
569
596
  }
570
597
 
571
598
  async treeHash (length) {
package/lib/core.js CHANGED
@@ -8,7 +8,7 @@ const Bitfield = require('./bitfield')
8
8
  const m = require('./messages')
9
9
 
10
10
  module.exports = class Core {
11
- constructor (header, crypto, oplog, tree, blocks, bitfield, sign, legacy, onupdate) {
11
+ constructor (header, crypto, oplog, tree, blocks, bitfield, auth, legacy, onupdate) {
12
12
  this.onupdate = onupdate
13
13
  this.header = header
14
14
  this.crypto = crypto
@@ -16,7 +16,7 @@ module.exports = class Core {
16
16
  this.tree = tree
17
17
  this.blocks = blocks
18
18
  this.bitfield = bitfield
19
- this.defaultSign = sign
19
+ this.defaultAuth = auth
20
20
  this.truncating = 0
21
21
 
22
22
  this._maxOplogSize = 65536
@@ -51,10 +51,21 @@ module.exports = class Core {
51
51
  }
52
52
  }
53
53
 
54
- // TODO: we should prob have a general "auth" abstraction instead somewhere?
55
- static createSigner (crypto, { publicKey, secretKey }) {
56
- if (!crypto.validateKeyPair({ publicKey, secretKey })) throw new Error('Invalid key pair')
57
- return signable => crypto.sign(signable, secretKey)
54
+ static createAuth (crypto, { publicKey, secretKey }, opts = {}) {
55
+ if (secretKey && !crypto.validateKeyPair({ publicKey, secretKey })) throw new Error('Invalid key pair')
56
+
57
+ const sign = opts.sign
58
+ ? opts.sign
59
+ : secretKey
60
+ ? (signable) => crypto.sign(signable, secretKey)
61
+ : undefined
62
+
63
+ return {
64
+ sign,
65
+ verify (signable, signature) {
66
+ return crypto.verify(signable, signature, publicKey)
67
+ }
68
+ }
58
69
  }
59
70
 
60
71
  static async resume (oplogFile, treeFile, bitfieldFile, dataFile, opts) {
@@ -116,7 +127,7 @@ module.exports = class Core {
116
127
  await bitfield.clear()
117
128
  }
118
129
 
119
- const sign = opts.sign || (header.signer.secretKey ? this.createSigner(crypto, header.signer) : null)
130
+ const auth = opts.auth || this.createAuth(crypto, header.signer)
120
131
 
121
132
  for (const e of entries) {
122
133
  if (e.userData) {
@@ -147,7 +158,7 @@ module.exports = class Core {
147
158
  }
148
159
  }
149
160
 
150
- return new this(header, crypto, oplog, tree, blocks, bitfield, sign, !!opts.legacy, opts.onupdate || noop)
161
+ return new this(header, crypto, oplog, tree, blocks, bitfield, auth, !!opts.legacy, opts.onupdate || noop)
151
162
  }
152
163
 
153
164
  _shouldFlush () {
@@ -212,13 +223,13 @@ module.exports = class Core {
212
223
  }
213
224
  }
214
225
 
215
- async truncate (length, fork, sign = this.defaultSign) {
226
+ async truncate (length, fork, auth = this.defaultAuth) {
216
227
  this.truncating++
217
228
  await this._mutex.lock()
218
229
 
219
230
  try {
220
231
  const batch = await this.tree.truncate(length, fork)
221
- batch.signature = await sign(batch.signable())
232
+ batch.signature = await auth.sign(batch.signable())
222
233
  await this._truncate(batch, null)
223
234
  } finally {
224
235
  this.truncating--
@@ -226,7 +237,7 @@ module.exports = class Core {
226
237
  }
227
238
  }
228
239
 
229
- async append (values, sign = this.defaultSign, hooks = {}) {
240
+ async append (values, auth = this.defaultAuth, hooks = {}) {
230
241
  await this._mutex.lock()
231
242
 
232
243
  try {
@@ -238,7 +249,7 @@ module.exports = class Core {
238
249
  for (const val of values) batch.append(val)
239
250
 
240
251
  const hash = batch.hash()
241
- batch.signature = await sign(this._legacy ? batch.signableLegacy(hash) : batch.signable(hash))
252
+ batch.signature = await auth.sign(this._legacy ? batch.signableLegacy(hash) : batch.signable(hash))
242
253
 
243
254
  const entry = {
244
255
  userData: null,
@@ -270,9 +281,9 @@ module.exports = class Core {
270
281
  }
271
282
  }
272
283
 
273
- _signed (batch, hash) {
284
+ _signed (batch, hash, auth = this.defaultAuth) {
274
285
  const signable = this._legacy ? batch.signableLegacy(hash) : batch.signable(hash)
275
- return this.crypto.verify(signable, batch.signature, this.header.signer.publicKey)
286
+ return auth.verify(signable, batch.signature)
276
287
  }
277
288
 
278
289
  async _verifyExclusive ({ batch, bitfield, value, from }) {
package/lib/replicator.js CHANGED
@@ -842,6 +842,7 @@ module.exports = class Replicator {
842
842
  this.onpeerupdate = onpeerupdate
843
843
  this.onupload = onupload
844
844
  this.peers = []
845
+ this.findingPeers = 0 // updateable from the outside
845
846
 
846
847
  this._inflight = new InflightTracker()
847
848
  this._blocks = new BlockTracker(core)
@@ -854,6 +855,7 @@ module.exports = class Replicator {
854
855
  this._reorgs = []
855
856
  this._ranges = []
856
857
 
858
+ this._hadPeers = false
857
859
  this._ifAvailable = 0
858
860
  this._updatesPending = 0
859
861
  this._applyingReorg = false
@@ -959,6 +961,7 @@ module.exports = class Replicator {
959
961
  // Do this when we have more tests.
960
962
  _checkUpgradeIfAvailable () {
961
963
  if (this._ifAvailable > 0 || this._upgrade === null || this._upgrade.refs.length === 0) return
964
+ if (this._hadPeers === false && this.findingPeers > 0) return
962
965
 
963
966
  // check if a peer can upgrade us
964
967
 
@@ -1047,6 +1050,7 @@ module.exports = class Replicator {
1047
1050
  }
1048
1051
 
1049
1052
  _addPeer (peer) {
1053
+ this._hadPeers = true
1050
1054
  this.peers.push(peer)
1051
1055
  this.updatePeer(peer)
1052
1056
  this.onpeerupdate(true, peer)
@@ -1382,6 +1386,10 @@ module.exports = class Replicator {
1382
1386
  }
1383
1387
 
1384
1388
  _updatePeerNonPrimary (peer) {
1389
+ if (peer.inflight >= peer.maxInflight) {
1390
+ return false
1391
+ }
1392
+
1385
1393
  const ranges = new RandomIterator(this._ranges)
1386
1394
 
1387
1395
  for (const r of ranges) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore",
3
- "version": "10.0.0-alpha.31",
3
+ "version": "10.0.0-alpha.34",
4
4
  "description": "Hypercore 10",
5
5
  "main": "index.js",
6
6
  "scripts": {