hypercore 10.0.0-alpha.1 → 10.0.0-alpha.10

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
@@ -3,6 +3,8 @@ const raf = require('random-access-file')
3
3
  const isOptions = require('is-options')
4
4
  const hypercoreCrypto = require('hypercore-crypto')
5
5
  const c = require('compact-encoding')
6
+ const b4a = require('b4a')
7
+ const Xache = require('xache')
6
8
  const NoiseSecretStream = require('@hyperswarm/secret-stream')
7
9
  const codecs = require('codecs')
8
10
 
@@ -11,6 +13,7 @@ const fsctl = requireMaybe('fsctl') || { lock: noop, sparse: noop }
11
13
  const Replicator = require('./lib/replicator')
12
14
  const Extensions = require('./lib/extensions')
13
15
  const Core = require('./lib/core')
16
+ const BlockEncryption = require('./lib/block-encryption')
14
17
 
15
18
  const promises = Symbol.for('hypercore.promises')
16
19
  const inspect = Symbol.for('nodejs.util.inspect.custom')
@@ -27,14 +30,17 @@ module.exports = class Hypercore extends EventEmitter {
27
30
  opts = key
28
31
  key = null
29
32
  }
33
+
30
34
  if (key && typeof key === 'string') {
31
- key = Buffer.from(key, 'hex')
35
+ key = b4a.from(key, 'hex')
32
36
  }
33
- if (key && key.byteLength !== 32) {
37
+
38
+ if (!opts) opts = {}
39
+
40
+ if (!opts.crypto && key && key.byteLength !== 32) {
34
41
  throw new Error('Hypercore key should be 32 bytes')
35
42
  }
36
43
 
37
- if (!opts) opts = {}
38
44
  if (!storage) storage = opts.storage
39
45
 
40
46
  this[promises] = true
@@ -43,7 +49,9 @@ module.exports = class Hypercore extends EventEmitter {
43
49
  this.crypto = opts.crypto || hypercoreCrypto
44
50
  this.core = null
45
51
  this.replicator = null
52
+ this.encryption = null
46
53
  this.extensions = opts.extensions || new Extensions()
54
+ this.cache = opts.cache === true ? new Xache({ maxSize: 65536, maxAge: 0 }) : (opts.cache || null)
47
55
 
48
56
  this.valueEncoding = null
49
57
  this.key = key || null
@@ -59,6 +67,8 @@ module.exports = class Hypercore extends EventEmitter {
59
67
  this.closing = null
60
68
  this.opening = opts._opening || this._open(key, storage, opts)
61
69
  this.opening.catch(noop)
70
+
71
+ this._preappend = preappend.bind(this)
62
72
  }
63
73
 
64
74
  [inspect] (depth, opts) {
@@ -89,8 +99,9 @@ module.exports = class Hypercore extends EventEmitter {
89
99
  const directory = storage
90
100
  const toLock = opts.lock || 'oplog'
91
101
  return function createFile (name) {
92
- const lock = name === toLock ? fsctl.lock : null
93
- const sparse = name !== toLock ? fsctl.sparse : null
102
+ const locked = name === toLock || name.endsWith('/' + toLock)
103
+ const lock = locked ? fsctl.lock : null
104
+ const sparse = locked ? null : null // fsctl.sparse, disable sparse on windows - seems to fail for some people. TODO: investigate
94
105
  return raf(name, { directory, lock, sparse })
95
106
  }
96
107
  }
@@ -132,6 +143,7 @@ module.exports = class Hypercore extends EventEmitter {
132
143
  this.discoveryKey = o.discoveryKey
133
144
  this.core = o.core
134
145
  this.replicator = o.replicator
146
+ this.encryption = o.encryption
135
147
  this.writable = !!this.sign
136
148
  this.autoClose = o.autoClose
137
149
  }
@@ -201,7 +213,7 @@ module.exports = class Hypercore extends EventEmitter {
201
213
  }
202
214
 
203
215
  get byteLength () {
204
- return this.core === null ? 0 : this.core.tree.byteLength
216
+ return this.core === null ? 0 : this.core.tree.byteLength - (this.core.tree.length * this.padding)
205
217
  }
206
218
 
207
219
  get fork () {
@@ -212,6 +224,14 @@ module.exports = class Hypercore extends EventEmitter {
212
224
  return this.replicator === null ? [] : this.replicator.peers
213
225
  }
214
226
 
227
+ get encryptionKey () {
228
+ return this.encryption && this.encryption.key
229
+ }
230
+
231
+ get padding () {
232
+ return this.encryption === null ? 0 : this.encryption.padding
233
+ }
234
+
215
235
  ready () {
216
236
  return this.opening
217
237
  }
@@ -265,6 +285,10 @@ module.exports = class Hypercore extends EventEmitter {
265
285
  this.key = this.core.header.signer.publicKey
266
286
  this.writable = !!this.sign
267
287
 
288
+ if (!this.encryption && opts.encryptionKey) {
289
+ this.encryption = new BlockEncryption(opts.encryptionKey, this.key)
290
+ }
291
+
268
292
  this.extensions.attach(this.replicator)
269
293
  this.opened = true
270
294
 
@@ -280,8 +304,13 @@ module.exports = class Hypercore extends EventEmitter {
280
304
  _oncoreupdate (status, bitfield, value, from) {
281
305
  if (status !== 0) {
282
306
  for (let i = 0; i < this.sessions.length; i++) {
283
- if ((status & 0b10) !== 0) this.sessions[i].emit('truncate', this.core.tree.fork)
284
- if ((status & 0b01) !== 0) this.sessions[i].emit('append')
307
+ if ((status & 0b10) !== 0) {
308
+ if (this.cache) this.cache.clear()
309
+ this.sessions[i].emit('truncate', this.core.tree.fork)
310
+ }
311
+ if ((status & 0b01) !== 0) {
312
+ this.sessions[i].emit('append')
313
+ }
285
314
  }
286
315
 
287
316
  this.replicator.broadcastInfo()
@@ -294,8 +323,10 @@ module.exports = class Hypercore extends EventEmitter {
294
323
  }
295
324
 
296
325
  if (value) {
326
+ const byteLength = value.byteLength - this.padding
327
+
297
328
  for (let i = 0; i < this.sessions.length; i++) {
298
- this.sessions[i].emit('download', bitfield.start, value, from)
329
+ this.sessions[i].emit('download', bitfield.start, byteLength, from)
299
330
  }
300
331
  }
301
332
  }
@@ -332,7 +363,7 @@ module.exports = class Hypercore extends EventEmitter {
332
363
  async seek (bytes) {
333
364
  if (this.opened === false) await this.opening
334
365
 
335
- const s = this.core.tree.seek(bytes)
366
+ const s = this.core.tree.seek(bytes, this.padding)
336
367
 
337
368
  return (await s.update()) || this.replicator.requestSeek(s)
338
369
  }
@@ -345,22 +376,52 @@ module.exports = class Hypercore extends EventEmitter {
345
376
 
346
377
  async get (index, opts) {
347
378
  if (this.opened === false) await this.opening
379
+ const c = this.cache && this.cache.get(index)
380
+ if (c) return c
381
+ const fork = this.core.tree.fork
382
+ const b = await this._get(index, opts)
383
+ if (this.cache && fork === this.core.tree.fork && b) this.cache.set(index, b)
384
+ return b
385
+ }
386
+
387
+ async _get (index, opts) {
348
388
  const encoding = (opts && opts.valueEncoding && c.from(codecs(opts.valueEncoding))) || this.valueEncoding
349
389
 
350
- if (this.core.bitfield.get(index)) return decode(encoding, await this.core.blocks.get(index))
351
- if (opts && opts.onwait) opts.onwait(index)
390
+ let block
391
+
392
+ if (this.core.bitfield.get(index)) {
393
+ block = await this.core.blocks.get(index)
394
+ } else {
395
+ if (opts && opts.onwait) opts.onwait(index)
396
+ block = await this.replicator.requestBlock(index)
397
+ }
352
398
 
353
- return decode(encoding, await this.replicator.requestBlock(index))
399
+ if (this.encryption) this.encryption.decrypt(index, block)
400
+ return this._decode(encoding, block)
354
401
  }
355
402
 
356
403
  download (range) {
357
- const start = (range && range.start) || 0
358
- const end = typeof (range && range.end) === 'number' ? range.end : -1 // download all
359
404
  const linear = !!(range && range.linear)
360
405
 
361
- // TODO: support range.blocks
406
+ let start
407
+ let end
408
+ let filter
409
+
410
+ if (range && range.blocks) {
411
+ const blocks = range.blocks instanceof Set
412
+ ? range.blocks
413
+ : new Set(range.blocks)
414
+
415
+ start = range.start || (blocks.size ? min(range.blocks) : 0)
416
+ end = range.end || (blocks.size ? max(range.blocks) + 1 : 0)
417
+
418
+ filter = (i) => blocks.has(i)
419
+ } else {
420
+ start = (range && range.start) || 0
421
+ end = typeof (range && range.end) === 'number' ? range.end : -1 // download all
422
+ }
362
423
 
363
- const r = Replicator.createRange(start, end, linear)
424
+ const r = Replicator.createRange(start, end, filter, linear)
364
425
 
365
426
  if (this.opened) this.replicator.addRange(r)
366
427
  else this.opening.then(() => this.replicator.addRange(r), noop)
@@ -393,22 +454,16 @@ module.exports = class Hypercore extends EventEmitter {
393
454
  if (this.opened === false) await this.opening
394
455
  if (this.writable === false) throw new Error('Core is not writable')
395
456
 
396
- const blks = Array.isArray(blocks) ? blocks : [blocks]
397
- const buffers = new Array(blks.length)
457
+ blocks = Array.isArray(blocks) ? blocks : [blocks]
398
458
 
399
- for (let i = 0; i < blks.length; i++) {
400
- const blk = blks[i]
459
+ const preappend = this.encryption && this._preappend
460
+ const buffers = new Array(blocks.length)
401
461
 
402
- const buf = Buffer.isBuffer(blk)
403
- ? blk
404
- : this.valueEncoding
405
- ? c.encode(this.valueEncoding, blk)
406
- : Buffer.from(blk)
407
-
408
- buffers[i] = buf
462
+ for (let i = 0; i < blocks.length; i++) {
463
+ buffers[i] = this._encode(this.valueEncoding, blocks[i])
409
464
  }
410
465
 
411
- return await this.core.append(buffers, this.sign)
466
+ return await this.core.append(buffers, this.sign, { preappend })
412
467
  }
413
468
 
414
469
  registerExtension (name, handlers) {
@@ -419,14 +474,38 @@ module.exports = class Hypercore extends EventEmitter {
419
474
  onextensionupdate () {
420
475
  if (this.replicator !== null) this.replicator.broadcastOptions()
421
476
  }
422
- }
423
477
 
424
- function noop () {}
478
+ _encode (enc, val) {
479
+ const state = { start: this.padding, end: this.padding, buffer: null }
480
+
481
+ if (b4a.isBuffer(val)) {
482
+ if (state.start === 0) return val
483
+ state.end += val.byteLength
484
+ } else if (enc) {
485
+ enc.preencode(state, val)
486
+ } else {
487
+ val = b4a.from(val)
488
+ if (state.start === 0) return val
489
+ state.end += val.byteLength
490
+ }
425
491
 
426
- function decode (enc, buf) {
427
- return enc ? c.decode(enc, buf) : buf
492
+ state.buffer = b4a.allocUnsafe(state.end)
493
+
494
+ if (enc) enc.encode(state, val)
495
+ else state.buffer.set(val, state.start)
496
+
497
+ return state.buffer
498
+ }
499
+
500
+ _decode (enc, block) {
501
+ block = block.subarray(this.padding)
502
+ if (enc) return c.decode(enc, block)
503
+ return block
504
+ }
428
505
  }
429
506
 
507
+ function noop () {}
508
+
430
509
  function isStream (s) {
431
510
  return typeof s === 'object' && s && typeof s.pipe === 'function'
432
511
  }
@@ -440,5 +519,27 @@ function requireMaybe (name) {
440
519
  }
441
520
 
442
521
  function toHex (buf) {
443
- return buf && buf.toString('hex')
522
+ return buf && b4a.toString(buf, 'hex')
523
+ }
524
+
525
+ function reduce (iter, fn, acc) {
526
+ for (const item of iter) acc = fn(acc, item)
527
+ return acc
528
+ }
529
+
530
+ function min (arr) {
531
+ return reduce(arr, (a, b) => Math.min(a, b), Infinity)
532
+ }
533
+
534
+ function max (arr) {
535
+ return reduce(arr, (a, b) => Math.max(a, b), -Infinity)
536
+ }
537
+
538
+ function preappend (blocks) {
539
+ const offset = this.core.tree.length
540
+ const fork = this.core.tree.fork
541
+
542
+ for (let i = 0; i < blocks.length; i++) {
543
+ this.encryption.encrypt(offset + i, blocks[i], fork)
544
+ }
444
545
  }
package/lib/bitfield.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // TODO: needs massive improvements obvs
2
2
 
3
3
  const BigSparseArray = require('big-sparse-array')
4
+ const b4a = require('b4a')
4
5
 
5
6
  class FixedBitfield {
6
7
  constructor (index, bitfield) {
@@ -116,9 +117,9 @@ module.exports = class Bitfield {
116
117
  let error = null
117
118
 
118
119
  for (const page of this.unflushed) {
119
- const b = Buffer.from(page.bitfield.buffer, page.bitfield.byteOffset, page.bitfield.byteLength)
120
+ const buf = b4a.from(page.bitfield.buffer, page.bitfield.byteOffset, page.bitfield.byteLength)
120
121
  page.dirty = false
121
- this.storage.write(page.index * 4096, b, done)
122
+ this.storage.write(page.index * 4096, buf, done)
122
123
  }
123
124
 
124
125
  function done (err) {
@@ -0,0 +1,68 @@
1
+ const sodium = require('sodium-universal')
2
+ const c = require('compact-encoding')
3
+ const b4a = require('b4a')
4
+
5
+ const nonce = b4a.alloc(sodium.crypto_stream_NONCEBYTES)
6
+
7
+ module.exports = class BlockEncryption {
8
+ constructor (encryptionKey, hypercoreKey) {
9
+ const subKeys = b4a.alloc(2 * sodium.crypto_stream_KEYBYTES)
10
+
11
+ this.key = encryptionKey
12
+ this.blockKey = subKeys.subarray(0, sodium.crypto_stream_KEYBYTES)
13
+ this.blindingKey = subKeys.subarray(sodium.crypto_stream_KEYBYTES)
14
+ this.padding = 8
15
+
16
+ sodium.crypto_generichash(this.blockKey, encryptionKey, hypercoreKey)
17
+ sodium.crypto_generichash(this.blindingKey, this.blockKey)
18
+ }
19
+
20
+ encrypt (index, block, fork) {
21
+ const padding = block.subarray(0, this.padding)
22
+ block = block.subarray(this.padding)
23
+
24
+ c.uint64.encode({ start: 0, end: 8, buffer: padding }, fork)
25
+ c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
26
+
27
+ // Zero out any previous padding.
28
+ nonce.fill(0, 8, 8 + padding.byteLength)
29
+
30
+ // Blind the fork ID, possibly risking reusing the nonce on a reorg of the
31
+ // Hypercore. This is fine as the blinding is best-effort and the latest
32
+ // fork ID shared on replication anyway.
33
+ sodium.crypto_stream_xor(
34
+ padding,
35
+ padding,
36
+ nonce,
37
+ this.blindingKey
38
+ )
39
+
40
+ nonce.set(padding, 8)
41
+
42
+ // The combination of a (blinded) fork ID and a block index is unique for a
43
+ // given Hypercore and is therefore a valid nonce for encrypting the block.
44
+ sodium.crypto_stream_xor(
45
+ block,
46
+ block,
47
+ nonce,
48
+ this.blockKey
49
+ )
50
+ }
51
+
52
+ decrypt (index, block) {
53
+ const padding = block.subarray(0, this.padding)
54
+ block = block.subarray(this.padding)
55
+
56
+ c.uint64.encode({ start: 0, end: 8, buffer: nonce }, index)
57
+
58
+ nonce.set(padding, 8)
59
+
60
+ // Decrypt the block using the blinded fork ID.
61
+ sodium.crypto_stream_xor(
62
+ block,
63
+ block,
64
+ nonce,
65
+ this.blockKey
66
+ )
67
+ }
68
+ }
@@ -1,3 +1,5 @@
1
+ const b4a = require('b4a')
2
+
1
3
  module.exports = class BlockStore {
2
4
  constructor (storage, tree) {
3
5
  this.storage = storage
@@ -15,7 +17,7 @@ module.exports = class BlockStore {
15
17
 
16
18
  putBatch (i, batch, offset) {
17
19
  if (batch.length === 0) return Promise.resolve()
18
- return this.put(i, batch.length === 1 ? batch[0] : Buffer.concat(batch), offset)
20
+ return this.put(i, batch.length === 1 ? batch[0] : b4a.concat(batch), offset)
19
21
  }
20
22
 
21
23
  clear () {
package/lib/core.js CHANGED
@@ -214,10 +214,12 @@ module.exports = class Core {
214
214
  }
215
215
  }
216
216
 
217
- async append (values, sign = this.defaultSign) {
217
+ async append (values, sign = this.defaultSign, hooks = {}) {
218
218
  await this._mutex.lock()
219
219
 
220
220
  try {
221
+ if (hooks.preappend) await hooks.preappend(values)
222
+
221
223
  if (!values.length) return this.tree.length
222
224
 
223
225
  const batch = this.tree.batch()
@@ -1,9 +1,10 @@
1
1
  const flat = require('flat-tree')
2
2
  const crypto = require('hypercore-crypto')
3
- const uint64le = require('uint64le')
3
+ const c = require('compact-encoding')
4
+ const b4a = require('b4a')
4
5
 
5
- const BLANK_HASH = Buffer.alloc(32)
6
- const OLD_TREE = Buffer.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
6
+ const BLANK_HASH = b4a.alloc(32)
7
+ const OLD_TREE = b4a.from([5, 2, 87, 2, 0, 0, 40, 7, 66, 76, 65, 75, 69, 50, 98])
7
8
 
8
9
  class NodeQueue {
9
10
  constructor (nodes, extra = null) {
@@ -272,11 +273,15 @@ class ReorgBatch extends MerkleTreeBatch {
272
273
  }
273
274
 
274
275
  class ByteSeeker {
275
- constructor (tree, bytes) {
276
+ constructor (tree, bytes, padding = 0) {
276
277
  this.tree = tree
277
278
  this.bytes = bytes
278
- this.start = bytes >= tree.byteLength ? tree.length : 0
279
- this.end = bytes < tree.byteLength ? tree.length : 0
279
+ this.padding = padding
280
+
281
+ const size = tree.byteLength - (tree.length * padding)
282
+
283
+ this.start = bytes >= size ? tree.length : 0
284
+ this.end = bytes < size ? tree.length : 0
280
285
  }
281
286
 
282
287
  nodes () {
@@ -287,12 +292,12 @@ class ByteSeeker {
287
292
  if (!bytes) return [0, 0]
288
293
 
289
294
  for (const node of this.tree.roots) { // all async ticks happen once we find the root so safe
290
- if (bytes === node.size) {
291
- return [flat.rightSpan(node.index) + 2, 0]
292
- }
295
+ let size = node.size
296
+ if (this.padding > 0) size -= this.padding * flat.countLeaves(node.index)
293
297
 
294
- if (bytes > node.size) {
295
- bytes -= node.size
298
+ if (bytes === size) return [flat.rightSpan(node.index) + 2, 0]
299
+ if (bytes > size) {
300
+ bytes -= size
296
301
  continue
297
302
  }
298
303
 
@@ -301,9 +306,12 @@ class ByteSeeker {
301
306
  while ((ite.index & 1) !== 0) {
302
307
  const l = await this.tree.get(ite.leftChild(), false)
303
308
  if (l) {
304
- if (l.size === bytes) return [ite.rightSpan() + 2, 0]
305
- if (l.size > bytes) continue
306
- bytes -= l.size
309
+ let size = l.size
310
+ if (this.padding > 0) size -= this.padding * ite.countLeaves()
311
+
312
+ if (size === bytes) return [ite.rightSpan() + 2, 0]
313
+ if (size > bytes) continue
314
+ bytes -= size
307
315
  ite.sibling()
308
316
  } else {
309
317
  ite.parent()
@@ -355,8 +363,8 @@ module.exports = class MerkleTree {
355
363
  return new MerkleTreeBatch(this)
356
364
  }
357
365
 
358
- seek (bytes) {
359
- return new ByteSeeker(this, bytes)
366
+ seek (bytes, padding) {
367
+ return new ByteSeeker(this, bytes, padding)
360
368
  }
361
369
 
362
370
  hash () {
@@ -433,17 +441,23 @@ module.exports = class MerkleTree {
433
441
  // TODO: write neighbors together etc etc
434
442
  // TODO: bench loading a full disk page and copy to that instead
435
443
  return new Promise((resolve, reject) => {
436
- const slab = Buffer.allocUnsafe(40 * this.flushing.size)
444
+ const slab = b4a.allocUnsafe(40 * this.flushing.size)
437
445
 
438
446
  let error = null
439
447
  let missing = this.flushing.size + 1
440
448
  let offset = 0
441
449
 
442
450
  for (const node of this.flushing.values()) {
443
- const b = slab.slice(offset, offset += 40)
444
- uint64le.encode(node.size, b, 0)
445
- node.hash.copy(b, 8)
446
- this.storage.write(node.index * 40, b, done)
451
+ const state = {
452
+ start: 0,
453
+ end: 40,
454
+ buffer: slab.subarray(offset, offset += 40)
455
+ }
456
+
457
+ c.uint64.encode(state, node.size)
458
+ c.raw.encode(state, node.hash)
459
+
460
+ this.storage.write(node.index * 40, state.buffer, done)
447
461
  }
448
462
 
449
463
  done(null)
@@ -1038,10 +1052,10 @@ function getStoredNode (storage, index, error) {
1038
1052
  return
1039
1053
  }
1040
1054
 
1041
- const hash = data.slice(8)
1042
- const size = uint64le.decode(data, 0)
1055
+ const hash = data.subarray(8)
1056
+ const size = c.decode(c.uint64, data)
1043
1057
 
1044
- if (size === 0 && Buffer.compare(hash, BLANK_HASH) === 0) {
1058
+ if (size === 0 && b4a.compare(hash, BLANK_HASH) === 0) {
1045
1059
  if (error) reject(new Error('Could not load node: ' + index))
1046
1060
  else resolve(null)
1047
1061
  return
@@ -1088,9 +1102,9 @@ function log2 (n) {
1088
1102
  }
1089
1103
 
1090
1104
  function signable (hash, length, fork) {
1091
- const buf = Buffer.alloc(48)
1092
- hash.copy(buf)
1093
- uint64le.encode(length, buf, 32)
1094
- uint64le.encode(fork, buf, 40)
1095
- return buf
1105
+ const state = { start: 0, end: 48, buffer: b4a.alloc(48) }
1106
+ c.raw.encode(state, hash)
1107
+ c.uint64.encode(state, length)
1108
+ c.uint64.encode(state, fork)
1109
+ return state.buffer
1096
1110
  }
package/lib/oplog.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const cenc = require('compact-encoding')
2
+ const b4a = require('b4a')
2
3
  const crc32 = require('crc32-universal')
3
4
 
4
5
  module.exports = class Oplog {
@@ -133,7 +134,7 @@ module.exports = class Oplog {
133
134
  return new Promise((resolve, reject) => {
134
135
  this.storage.open(err => {
135
136
  if (err && err.code !== 'ENOENT') return reject(err)
136
- if (err) return resolve(Buffer.alloc(0))
137
+ if (err) return resolve(b4a.alloc(0))
137
138
  this.storage.stat((err, stat) => {
138
139
  if (err && err.code !== 'ENOENT') return reject(err)
139
140
  this.storage.read(0, stat.size, (err, buf) => {
@@ -151,7 +152,7 @@ module.exports = class Oplog {
151
152
  const bit = (this._headers[i] + 1) & 1
152
153
 
153
154
  this.headerEncoding.preencode(state, header)
154
- state.buffer = Buffer.allocUnsafe(state.end)
155
+ state.buffer = b4a.allocUnsafe(state.end)
155
156
  this.headerEncoding.encode(state, header)
156
157
  this._addHeader(state, state.end - 8, bit, 0)
157
158
 
@@ -187,7 +188,7 @@ module.exports = class Oplog {
187
188
  this.entryEncoding.preencode(state, batch[i])
188
189
  }
189
190
 
190
- state.buffer = Buffer.allocUnsafe(state.end)
191
+ state.buffer = b4a.allocUnsafe(state.end)
191
192
 
192
193
  for (let i = 0; i < batch.length; i++) {
193
194
  const start = state.start += 8 // space for header
package/lib/protocol.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const { uint, from: fromEncoding } = require('compact-encoding')
2
+ const b4a = require('b4a')
2
3
  const safetyCatch = require('safety-catch')
3
4
  const codecs = require('codecs')
4
5
 
@@ -125,6 +126,7 @@ class Peer {
125
126
  this.resend = false
126
127
  this.state = state
127
128
  this.extensions = new Map()
129
+ this.destroyed = false
128
130
 
129
131
  this._destroyer = this._safeDestroy.bind(this)
130
132
  }
@@ -229,6 +231,7 @@ class Peer {
229
231
  }
230
232
 
231
233
  destroy (err) {
234
+ this.destroyed = true
232
235
  return this.protocol.unregisterPeer(this, err)
233
236
  }
234
237
  }
@@ -283,20 +286,20 @@ module.exports = class Protocol {
283
286
 
284
287
  registerPeer (key, discoveryKey, handlers = {}, state = null) {
285
288
  const peer = new Peer(this, this._localAliases++, key, discoveryKey, handlers, state)
286
- this._peers.set(discoveryKey.toString('hex'), peer)
289
+ this._peers.set(b4a.toString(discoveryKey, 'hex'), peer)
287
290
  this._announceCore(peer.alias, key, discoveryKey)
288
291
  return peer
289
292
  }
290
293
 
291
294
  unregisterPeer (peer, err) {
292
- this._peers.delete(peer.discoveryKey.toString('hex'))
295
+ this._peers.delete(b4a.toString(peer.discoveryKey, 'hex'))
293
296
 
294
297
  if (peer.remoteAlias > -1) {
295
298
  this._remoteAliases[peer.remoteAlias] = null
296
299
  peer.remoteAlias = -1
297
300
  }
298
301
 
299
- peer.handlers.onunregister(this, err)
302
+ peer.handlers.onunregister(peer, err)
300
303
 
301
304
  if (err) this.noiseStream.destroy(err)
302
305
  }
@@ -372,7 +375,7 @@ module.exports = class Protocol {
372
375
  this.send(2, messages.core, -1, {
373
376
  alias: alias,
374
377
  discoveryKey: discoveryKey,
375
- capability: Buffer.alloc(32) // TODO
378
+ capability: b4a.alloc(32) // TODO
376
379
  })
377
380
  }
378
381
 
@@ -441,7 +444,7 @@ module.exports = class Protocol {
441
444
  }
442
445
 
443
446
  _oncore (m) {
444
- const hex = m.discoveryKey.toString('hex')
447
+ const hex = b4a.toString(m.discoveryKey, 'hex')
445
448
  const peer = this._peers.get(hex)
446
449
 
447
450
  // allow one alloc
@@ -477,7 +480,7 @@ module.exports = class Protocol {
477
480
  }
478
481
 
479
482
  _onunknowncore (m) {
480
- const peer = this._peers.get(m.discoveryKey.toString('hex'))
483
+ const peer = this._peers.get(b4a.toString(m.discoveryKey, 'hex'))
481
484
  if (!peer) return
482
485
 
483
486
  peer.resend = true